pgix
Posts: 40
Joined: Wed Jan 25, 2012 3:53 pm
Contact: Website

Flushing UART Tx and Rx FIFO

Mon Mar 23, 2015 6:28 pm

Hi All,

Having fixed my ELF relocation issue, I've now got my basic kernel running quite well on the RPi - it seems that the "architecture independent" heap manager I wrote on x86 seems to work quite nicely on ARM.

I'm working on my UART debug interface now, and have got quite a lot of useful information, but there's an annoyance. I'm at 115200 baud and can see my console output. Data is being passed through an Arduino DUE which is transparent - passing data direct from one UART to another (and has been tested with other serial devices to test this - including my CubieTruck).

The problem is that the last 16-17 characters are not appearing on my terminal, when sent with my putc() function. If I send additional dummy characters to the UART transmit buffer at the end of transmission, I can see all the "real" output. Also, if I spin on a getc() function, this seems to cause the transmit to complete correctly. My code:

Code: Select all

      inline char getc( void )
		{
			while ( (volatile uint32_t)readRegister(UartRegister::FR) & (1 << 4) ); // bit 4 == Rx Fifo Empty Flag
			return (char)(readRegister(UartRegister::DR) && 0xFF);
		}

		inline void putc(uint8_t c)
		{
			while ( ((volatile uint32_t)readRegister(UartRegister::FR)) & (1 << 5) ) ; // bit 5 == Tx Fifo Full flag
			writeRegister(UartRegister::DR, c);
		}
I call the above code from a C++ function (arch::Arm.initialise();):

Code: Select all

... // UART initialisation and write barrier
for(int i = 0; i < 4; ++i) uart0.puts("UART TEST");
uart0.puts("UART0 has been initialised.");
... // write barrier and GPIO initialisation
My console output for the above is as follows:

Code: Select all

UART TESTUART TESTUART TESTUART TESTUART0 has
And if I spin on a call to getc():

Code: Select all

UART TESTUART TESTUART TESTUART TESTUART0 has been initialised.
Is there some sort of buffer flush that I should be regularly calling in order to flush the Tx buffer? I'm using the memory barriers shown here: http://www.raspberrypi.org/forums/viewt ... 6&p=582004 on a RPi Model B (version 1).

Many thanks for any help,
Adam

EDIT: In fact, calling uart0.getc() *twice* seems to be enough to cause the tx to happen correctly. There must be some timing issue here that Ive missed...

PlutoniumBob
Posts: 16
Joined: Sun Feb 17, 2013 1:24 pm
Location: 1313 Mockingbird Lane

Re: Flushing UART Tx and Rx FIFO

Mon Mar 23, 2015 9:39 pm

Hi Adam,

I also had problems with flushing the UART's internal pipe (although I was using the mini UART at the time).
Try spinning on the BUSY bit of the FR register and see if that gets you where you want to go.

Regards
Bill

Code: Select all

      inline void flush()
      {
         while ( ((volatile uint32_t)readRegister(UartRegister::FR)) & (1 << 3) ) ; // bit 3 == Tx Fifo BUSY flag
      }

pgix
Posts: 40
Joined: Wed Jan 25, 2012 3:53 pm
Contact: Website

Re: Flushing UART Tx and Rx FIFO

Tue Mar 24, 2015 7:22 am

Hi!

Yes - that makes sense. Any read of FR seems to do the job and rather than guessing the number of required reads, testing the busy flag should allow me to know exactly how long to wait.

I'm thinking of implementing this as a separate flush() routine and calling from puts rather than putc, so that I can make proper use of the FIFO.

Thanks,
Adam

PlutoniumBob
Posts: 16
Joined: Sun Feb 17, 2013 1:24 pm
Location: 1313 Mockingbird Lane

Re: Flushing UART Tx and Rx FIFO

Tue Mar 24, 2015 12:46 pm

Hi Adam,

in my stuff I usually expose a whole bunch of functions getc(), putc(), puts(), and flush()
(even been known to do printf() from time to time).

I call flush() when the app needs it rather than intrinsically when I call puts(),
this allows me to do several puts()'es and then a flush().

e.g.
puts("Hello World\n");
... and some other code and stuff
puts("What a nice day it is\n");
... and some more code and stuff
puts("well i'll be off now\n");
... and finally...
flush();

(oh and I also (usually) expand lf to crlf in my putc() routine)

Regards
Bill

pgix
Posts: 40
Joined: Wed Jan 25, 2012 3:53 pm
Contact: Website

Re: Flushing UART Tx and Rx FIFO

Tue Mar 24, 2015 1:30 pm

Hi Bill,

I'll probably do that eventually. I have three classes "DebugConsole", "DebugInput" and "DebugOutput". The kernel calls an early architecture initialisation routine that registers a "DebugOutput" class (in this case, Uart inherits from DebugOutput - in my x86-64 port, Vga inherits from DebugOutput). This is an early boot-time feature and is designed to allow me to display debug information correctly in the first part of the boot process, before dynamic memory allocation is online.

My x86-64 port has got beyond this stage and once the VFS is online console input and output are handled in a more traditional way with the normal C/C++ filesystem calls. Everything can be written to cout and cerr as appropriate and is then sent via a VFS and driver pipeline to the VESA linear frame buffer. My ARM port has not yet got to this stage, and I'm simply wanting anything sent to UART to be instantly flushed.

I've implemented the suggestion of flushing by spinning on the busy flag and it works like a dream. I'm pleased to say my hex/oct/binary/decimal -to-ascii functions work well on the ARM port and now I can get the debug console running, I should have my heap manager up and running in no time (once I get my head around the differences between the x86 and ARM MMU!). I find that stage of the kernel quite an exciting part to develop, because once I have dynamic memory allocation I feel like anything else becomes possible!

Thanks again for your help and it was nice to know that someone else hit the same issue!

Adam

PlutoniumBob
Posts: 16
Joined: Sun Feb 17, 2013 1:24 pm
Location: 1313 Mockingbird Lane

Re: Flushing UART Tx and Rx FIFO

Tue Mar 24, 2015 3:19 pm

Awesome... Viva-La Bare-Metal... :lol:

Return to “Bare metal, Assembly language”