[En-Nut-Discussion] Timing problems with UART
ulrich.prinz at googlemail.com
Sun Nov 6 18:55:30 CET 2011
On 06.11.2011 07:30, Klaus Kloos wrote:
> Hello Ulrich
>> 1st) I remember that SAM7 might support interrupt priorities. So if a
>> same level interrupt is already active, it is finished before the next
>> interrupt of same or lower level is served. AFAIK in Nut/OS all
>> interrupts are on same level.
> Is it NUT_IRQPRI_UART0 in ih_at91uart0.c? ive changed it to 7 but there is not much change.
> (Ive change the code directly in the nut-directory. How to add such defines to the makefile?)
In your local Makefile add
CFLAGS += -DNUT_IRQPRI_UART0=xyz
Mind the += as you otherwise loose all predefinitions of the flags.
>> 2nd) NutEnterCritical disables all interrupts until NutExitCritical is
>> called. And therefore yes: It might influence your USART timing.
> Is it a way (for me) to modify NutEnterCritical/NutExitCritical for leaving the USART-IRQ unchanged?
The problem with atomic operations is that who comes first, serves
first. So if someone already entered atomic mode your atomic code cannot
be executed until the first one left it.
Second, it will not fix you problem. USART normally is interrupt driven.
So a simple
NutEnterCritical(); printf("MyCommand"); NutExitCritical;
Does just nothing to the timing. It might break the timing even more as
as long you are keeping the atomic mode on (IRQs switched off) as long
the USART functions will not role.
>> Only way out might be usage of DMA. I do not remember if DMA is
>> supported for USARTs in SAM9. In Cortex they are.
>> I wrote the DMA unit for the SPI in SAM7 so you might take look there
>> and copy the needed things over to USART.
>> It is not difficult especially if you're needing DMA for only one component.
> Ive found a very detailed description on USART-DMA here
> So i might be able to get this run (with some help :-).
> Where to find the DMA SPI code? Ive searched in ethernut-4.10\nut\arch\arm\dev\atmel.
Just out of my human harddrive... The USART works like this:
Some function puts data into the USARTs buffer.
You might know that the USARTs have two TX Interrupts. One is rised when
the USART TX Buffer can be filled with the next character. Behind this
buffer there is the FIFO register that actually transmits the character
that was written to the buffer before.
For this the TX-Empty IRQ is available.
Then the first USART function is called that starts the TX by just
enabling the TX-Buffer IRQ. As there is no char present in the TX
buffer, this immediately rises the first TX Interrupt.
This TX Buffer Empty IRQ fetches the first character from the buffer and
transmits it. Then many TX-Buffer IRQs are called until the last byte is
put into the USARTs TY buffer.
At that point the TX Buffer routine switches interrupts to call the
TX-Empty IRQ routine to finish and clean up the transfer.
Just for information, this TX Buffer IRQ und TX Empty IRQ are important
to divide! If you need handshake signals via GPIO, like RS485 direction
switching, it makes big difference if you switch the direction on TX
Buffer or TX Empty IRQ. If you switch on the first one, you cut the last
transmitted byte into nonsense as it is interrupted while it is transmitted.
To use DMA you just have to modify the first routine to collect the
buffer pointers and sizes and program the DMA controller with them.
Then you can directly enable TX-Empty Interrupt to tell you software
that the transmission is over.
As you like to transmit packet oriented data which you already prepared
in your own part of the software, you can and should use your own sender
You do not know how the printf background really works, you cannot tell
when the watermarks have reached their levels and the USART likes to
transmit something. So this function set works fine for command line
interfaces but not for packet oriented and timing critical things.
So write a function that throws out your packets with your features.
It is no tricky thing. You can reregister the interrupts from the USARTs
in your own piece of code without a problem. If you don't call the code
that Nut/OS provides it will either not compiled in or it stays silently
in the background.
The packet thing you need is a pretty easy one, as you only prepare your
packet in a memory, put address and size into DMA registers. Enable the
empty-Interrupt and start the DMA transmission via USART control register.
I guess about 8 lines of code and the data rolls out.
The spi code is in at91_spi.c. AFAIK I implemented it as I had to drive
a larger OLED display and a radio chipset on the same bus. And with both
of them using DMA gave real big performance boosts.
If you could tell me some more details of how you need to use the USARTs
for your application, I re reactivate my AT91SAM7X-EK and test or
support a bit. If it's company secret, use my PM.
More information about the En-Nut-Discussion