2015-07-27 02:09 AM
I am using an STM32L1 on a Nucleo-L152RE board. I have to devices I control through serial running at rather high baudrates, so I am trying to enable DMA on the USART. With the code below I can launch one Rx DMA, but the second one, which I start from the ISR never completes:
void uart_receive_dma() { DMA_InitTypeDef DMA_InitStructure; DMA_DeInit(DMA1_Channel5); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &USART1->DR; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) buffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = UART_PACKET_SIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_Init(DMA1_Channel5, &DMA_InitStructure); /* RX */ DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE); DMA_Cmd(DMA1_Channel5, ENABLE); USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE); } void DMA1_Channel5_IRQHandler(void){
if (DMA_GetITStatus(DMA1_IT_TC5) != RESET) {
DMA_ClearITPendingBit(DMA1_IT_TC5);
DMA_ClearFlag(DMA1_FLAG_TC5);
uart_receive_dma(); } int main(void) { RCC_Configuration(); GPIO_Configuration(); NVIC_Configuration(); USART_Configuration(); /* First Rx, works and MA1_Channel5_IRQHandler gets called */ uart_receive_dma(); while(1); }
The first DMA transfer works well, so I guess I am not clearing something before starting the second one, but I can't figure out what it is.
Depending on some external conditions, the real code doesn't always restart the DMA transfer from DMA1_Channel5_IRQHandler but restarts it from somewhere else, that's why I can't use the DMA in circular mode.
EDIT: I removed the line numbers, fixed an error when calling DMA_Init and checked the source of the interrupt, as suggested. Still, the interrupt is called only once.
#usart #dma #stm32l1
2015-07-27 03:52 AM
Pro Tip : When your simple example runs 80 lines, don't post 40 of them, and don't enable line numbering.
Make sure you've fully filled the DMA Init structure, and qualify the source of your interrupt. Don't use a variable to select the DMA if you've hard coded a value *everywhere* else.2015-07-27 07:41 AM
Thanks for the suggestions. I 'm now checking the source of the interrupt, but still no luck. The USART seems to work well in Tx mode using DMA and interrupts.
2015-07-27 07:54 AM
Unfortunately there are limits to static analysis.
How are you telling that the interrupt is not occurring? If you're sitting in a debugger is it probable you might cause the USART to overrun? Are the USART or DMA indicating an error conditions? Consider toggling a GPIO/LED.2015-07-28 03:40 AM
You were right. I was using either breakpoints on the interrupt routing or calling printf from there. After I stopped doing that, the DMA seems to work well.
Thanks a lot for your support.2015-07-28 09:16 AM
In another sort of things, if I configure the UART with RTS/CTS flow contol, does the DMA controller set/check the CTS and RTS pins or do I need to handle them myself?
2015-07-28 09:24 AM
That's all managed by you and the USART. The DMA just recognizes the TXE and RXNE from the USART and services it.
I've covered RTS/CTS on the forum several times, in my opinion it's something you have to manage at a ''system'' level. And you'll have to read the reference manual to understand what the hardware does.