UART and DMA

ChibiOS public support forum for topics related to the Atmel AT91SAM7x family of micro-controllers.
FlorianS
Posts: 22
Joined: Thu Jan 26, 2012 12:29 pm

UART and DMA

Postby FlorianS » Wed Oct 16, 2013 12:36 pm

Hi,
within our project we need a continous receive of data via the UART. For that case the DMA Controller of the AT91SAM7 provides two Receive (and two transmit) Buffer. Even with a lot of thinking we did not find a solution how we implement that in the lowlevel driver with the given highlevel driver.

We would like to modify the highlevel driver in the following way (see attachment).
We want do add some defines so that it is still possible to use the current lowlevel drivers. This define should enable (in high-/lowlevel Driver) a functionality like uartStartReceiveQueued().
With that function the next uart receive operation can be stored wich will be performed immediatelly after the first one is done. For that we would like to add a new state called ACTIVE_QUEUED (because the next task is already queued).

Our usecase is the following: We receive a continuous datastream consisting of 8 Byte Dataframes. At an "random" point we start listening to the stream. So we read twice 8 Byte. After we got the first 8 Byte we decide how many Bytes we need to read such that the startbyte of the next 8-Byte-Receive is in Byte 1 of the Rx buffer. After that we want to receive the 8 Byte continuously.
So we maybe read: 8 Byte - 8 Byte - 3 Byte - 8 Byte - 8 Byte - 8 Byte - 8 Byte ...

Regards,
Florian
Attachments
UART_RX_QUEUED_Statediagram.png
UART_RX_QUEUED_Statediagram.png (64.1 KiB) Viewed 10564 times

User avatar
Giovanni
Site Admin
Posts: 14444
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1074 times
Been thanked: 921 times
Contact:

Re: UART and DMA

Postby Giovanni » Wed Oct 16, 2013 1:13 pm

You may use the uc_rxchar callback in order to synchronize with the packets flow (no need to start a read, just process one byte at time until you reach your delimiter), then start doing uartStartReceive() when synchronized.

I think there is no need for such complex solution.

Giovanni

FlorianS
Posts: 22
Joined: Thu Jan 26, 2012 12:29 pm

Re: UART and DMA

Postby FlorianS » Wed Oct 16, 2013 1:18 pm

Hi,
while i'm in callback i maybe miss the start of the next frame.

Regards,
Florian

User avatar
Giovanni
Site Admin
Posts: 14444
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1074 times
Been thanked: 921 times
Contact:

Re: UART and DMA

Postby Giovanni » Wed Oct 16, 2013 2:55 pm

How long do you plan to stay in the callback? it should be a very short code there.

Giovanni

andre
Posts: 1
Joined: Thu Oct 17, 2013 9:43 am

Re: UART and DMA

Postby andre » Thu Oct 17, 2013 9:58 am

Hi Giovanni,

I'm working with Florian in Aachen. We actually do not plan to stay long in the interrupt-callback. But there is always the chance to hit a missed byte with the interrupt in between. Since the Atmel Hardware we use (AT91SAM7) offers the construct of an USART with DMA and a so called "next" registers for configuration which gently take care of these problems, we wanted to add support for this hardware-feature.

The "next" registers are fed with input. As soon as the actual configuration registers get empty due to a completed transmission the hardware transfers the content of the next registers to the actual configuration in the background. This means we could avoid any loss of data. In order to model this in the software (and be able to utilize this feature) we would need a 2nd RX-State (--> RX_ACTIVE_QUEUED). This is what we wanted to introduce.

To be fully compatible with the existing code the idea was to introduce a define, which tells the system that there are next registers or say better the possibility of queuing is available. If this define is not set we would stay with the old drivers behavior.

From my point of view this would be a sound solution to our problem and supporting the full hardware possibilities of the SAM7. We do not see any chance to use the next registers with the current high-level-driver and on the other hand we have good experience with the hardware queuing for USART.

Best regards,

Andre

User avatar
Giovanni
Site Admin
Posts: 14444
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1074 times
Been thanked: 921 times
Contact:

Re: UART and DMA

Postby Giovanni » Thu Oct 17, 2013 12:39 pm

Hi Florian and Andre,

I see your point but the purpose of the HAL is to expose a common set of features, what you are asking is very specific of that family and will make an already complex driver even harder to understand.

I think you have several alternative options:
1) You implement your protocol using the current API, I believe it is worth a serious try.
2) You make a driver extension that lives exclusively in the low level driver. This is allowed by the architecture, you can add new APIs using this convention <driver><platform><name><class>(), for example uartAT91StartReadQueuedI()). Some STM32 drivers do this for STM32-exclusive features. This makes clear that the functionality is architecture dependent.
3) You create a whole different driver model forking off the UART driver.

Giovanni

inmarket
Posts: 89
Joined: Fri Jul 27, 2012 1:37 pm
Location: Brisbane, Australia

Re: UART and DMA

Postby inmarket » Sat Oct 26, 2013 8:03 am

This concept of a string of buffers/operations to be performed is actually something that would abstract very well to higher level code and would be a very useful ChibiOS feature.

I struck this when dealing with the ADC. Already ChibiOS splits the buffer in two and allows a half-completion. Unfortunately using this feature to chain operations is not easy, obvious or without pitfalls. You would think that a split buffer like this would fit nicely into the SAM7's NEXT register capability but unfortunately it doesn't.

To overcome these problems for streaming from an ADC device, I wrote a special layer in uGFX called GADC which does exactly this sort of buffer management using the ChibiOS model. The only real implementation for this layer is currently for the SAM7 processor. To make real streaming work it has to ignore the "half-completion" callbacks that ChibiOS generates - they just don't work properly in a real streaming situation.
Note that GADC (in uGFX) also has a number of other aims like the ability to mix high speed and low speed ADC conversions on the one processor ADC unit but that is not relevant this discussion.

Another place where this would be useful is in things like the i2c interface. Currently all bytes in one i2c transaction must be supplied in a single buffer. To be able to specify multiple buffers of bytes that make up the single i2c transaction would be VERY useful and prevent lots of data copying. As an example see the SSD1306 driver in uGFX (i2c implementation). A workaround as been developed for uGFX v2.0 (soon to be released) but the current version this is a significant problem.

In conclusion,
The general ability in ChibiOS to be able to specify a string of buffers (or queue of buffers) to be processed would be very useful for many high speed devices across many device architectures. For those processors that have something similar to the SAM7's NEXT registers it would enable the processor to stay one step ahead but on every other platform the next item in the queue can be started automatically from the interrupt handler.

inmarket.

FlorianS
Posts: 22
Joined: Thu Jan 26, 2012 12:29 pm

Re: UART and DMA

Postby FlorianS » Mon Dec 16, 2013 6:24 pm

Hi,
I got a little bit stuck with my implementation of the "uartAT91StartReadQueuedI".

In the interrupt of the USART0 i call a callbackfunction. This will call the function "uartAT91StartReadQueuedI" be able to receive. But while calling that i will write over the bounds of the stack in "chSemWaitTimeoutS". So that one function call will be broken.

To enter chSemWaitTimeoutS this will be executed: push {r4, r5, r11, lr} (Addr 0x0020FF5A will be overritten)

While returning from ChThdSleep "pop {r4, r11, pc}" will be ececuted and the program counter will use the wrong value of Adress 0x0020FF5A. This causes an unhandled_exception.

My stack-trace:
7 chSemWaitTimeoutS() chsem.c:243 0x001013f4
6 dma_RxStart() dma.c:835 0x001027d4
5 uartAT91StartReadQueuedI() uart_lld.c:404 0x00103f2c
4 mdl_processEndOfReceiveInterrupt() uarttest.c:82 0x001054d8
3 uart_us_rxend() uart_lld.c:131 0x00103bf8
2 serve_dma_us0_interrupt() dma.c:158 0x00102428
1 us0_IrqHandler() dma.c:580 0x001024cc

How can I solve the problem? Do I need to increase the Stackpointer of the interrupt? (Increasing PORT_INT_REQUIRED_STACK does not fix the problem)

Regards,
Florian

User avatar
Giovanni
Site Admin
Posts: 14444
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1074 times
Been thanked: 921 times
Contact:

Re: UART and DMA

Postby Giovanni » Mon Dec 16, 2013 7:03 pm

Hi,

There is a limitation with ARM7 ISRs, the ISR is assumed to not use the function-preserved registers. The safest way to ensure this is to just call another function from the ISR.

It is possible your problem is related to this.

Giovanni

FlorianS
Posts: 22
Joined: Thu Jan 26, 2012 12:29 pm

Re: UART and DMA

Postby FlorianS » Tue Dec 17, 2013 4:18 pm

Hi,
actually we don't use the preserved register. I just had a look at the diassembly to find the cause of my error. We still think the problem is that the stacksize of the irq is too small.
After we increased the __irq_stack_size__ in AT91SAM7X256.ld it seems like i solved the problem.

So the __irq_stack_size__ is for increasing the stacksize of the irq such that i can have more nested functions?

Regards,
Florian


Return to “AT91SAM7x Support”

Who is online

Users browsing this forum: No registered users and 7 guests