cancel
Showing results for 
Search instead for 
Did you mean: 

stm32 serial port DMA RX problem

masekp
Associate II
Posted on July 15, 2008 at 06:04

stm32 serial port DMA RX problem

7 REPLIES 7
masekp
Associate II
Posted on May 17, 2011 at 12:28

Greetings to everybody,

I'm connecting strm32 to Bluetooth module via serial port and I've probably found a huge design flaw in serial port peripheral. I'd like to ask you, if I'm missing something (and I hope so) or if someone make terrible mistake designing USART peripheral for stm32.

I'd like to use fast communication (>115200bps) with the module and it is obvious that I have to use DMA for this, because stm32 has only one byte FIFO for serial port (unlike str711, which has 16bytes and which I used in previous project).

But the problem is, that RX data on serial port comes irregularly and I can't predict it's length. I can setup RX DMA channel into circular mode (let's say with buffer about 64bytes), but how can I determine, when command with smaller length (let's say 40 bytes) arrives?

STR711 has logical solution: I could setup interrupt TimeoutNotEmpty, which gives me an interrupt, when there are no RX data during defined time period and I could start processing data already received. But I can see no such behaviour in stm32's USART.

Is it really true? Is there no mechanism how to solve this? Because if it is, the greatness of this USART+DMA+HW FLOW CONTROL is totally useless. From my opinion, 99% application of serial port cannot predict, how many data are going to be received and I can't imagine, how could anyone do such terrible flaw.

All I hope now is, I'm wrong and I'm missing something.

Thank you very much for response

Petr Masek

giles
Associate II
Posted on May 17, 2011 at 12:28

Yeah i'm having similar problems @1.5Mb, mines made worse from needing to watch for framing errors.

With regards yours could you set up the the dma in a circular mode and use the rx pin as an EXTI as well as a buffer not empty trigger?

Its just a thought and a bit of a dirty hack at that and i haven't tested it.

masekp
Associate II
Posted on May 17, 2011 at 12:28

Hello Gilles,

thank you for an idea. You are right, it is not quite clear workaround, but could do the job. Thank you,I will try it. It is shame of st engineers to not include this basic thing. It spoils whole USART part :(

regards

Petr

giles
Associate II
Posted on May 17, 2011 at 12:28

Dirty Hack2 that i use now - do your own sw fifo:

set usart Rx as highest priority.

set EXTI 1 not triggering off rising or falling but with interrupt and pending mask enabled, (at a lower priority to usart Rx)

have global items:

unsigned short UsartDR[256];

unsigned short UsartSR[256];

unsigned short UsartFI, UsartFO;

unsigned short Us1Size;

void US1init(void)

{

UsartFI = 0;

UsartFO = 0;

Us1Size = 0;

};

void EXTI0_IRQHandler(void)

{

EXTI->PR |= 1;

NotEmptyFn();

};

//should take about 2us at 70mhz

void USART1_IRQHandler(void)

{

UsartSR[UsartFI] = USART1->SR;

UsartDR[UsartFI++] = USART1->DR;

UsartFI &= 0xFF;

Us1Size ++;

//pend software interrupt on exti

EXTI->SWIER |= 1;

}

void NotEmptyFn(void)

{

unsigned char MyDR, MySR;

MyDR=UsartDR[UsartFO];

MySR=UsartSR[UsartFO];

//Code Here

//remvove char for fifo

UsartFO = (UsartFO +1) & 0xFF;

Us1Size --;

};

ericvanolden9
Associate II
Posted on May 17, 2011 at 12:28

Stm32 Uart include an idle line detect. I don't test this but it seems that you can have an interrupt when line is idle for a duration of one character. With bit IDLIE, you can have an interrupt when this condition occur.

Another medoth is by polling. When character are received with DMA, register CNDTR in Dma decrement after each receive. So you can see how many character waits in Dma buffer before end of Dma transfer. I use a method without circular mode : I poll periodically CNDTR and I read received character, I have an interrupt at end of Dma buffer, in this interrupt I prepare a new Dma with the size free because I have read character at the beginning of the buffer.

andy239955_stm1
Associate II
Posted on May 17, 2011 at 12:28

I am successfully using interrupts and the (very misnamed) hardware handshake pins to read from a Roving Networks RN41 (BC04 based) bluetooth module at 460kbaud. I use dma for transmit.

What brand module are you using?

I make sure that I check the 'read data is available' bit first in the isr, before checking for errors or transmit data. It is hard to get more than around 300kbaud effective throughput so I haven't tried bumping the baudrate up any higher.

If I had time I would experiment with the IDLE line detect ...

ereikes
Associate
Posted on May 17, 2011 at 12:28

The way I plan to handle this with the STM32 is to not use interrupts in the USART at all (except for error handling). The DMA transfer is the producer and some foreground task is the consumer.

Something like this (remember to calculate index wrap if you use a buffer smaller than 256 bytes):

#define BUFLEN 256;

UI8 dma_buf[BUFLEN];

UI8 consumer_index=0;

main()

{

setup_uart_dma(dma_buf, 256, CIRCULAR_MODE);

while(1)

{

//UART task

if (consumer_index != (BUFLEN - CNDTR)) //bytes available

{

parse_byte(dma_buf[consumer_index++]); //pass a byte to the parser

}

//task1

//task2

//.... etc.

}

}

HTH