2020-02-26 09:23 AM
In a noisy media, I need to receive 10bytes with DMA (about 1Mb). I have set the DMA and its interrupt as shown below:
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel3);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART3->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = sizeof(Buffer) - 1;
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_Mode_Circular
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel3, &DMA_InitStructure);
USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);
/* Enable DMA Stream Transfer Complete interrupt */
DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA1_Channel3, ENABLE);
}
void DMA1_Channel3_IRQHandler(void) // USART1_RX
{
if (DMA_GetITStatus(DMA1_IT_TC3))
{
SendTest=Buffer[2];
DMA1_Channel3->CNDTR = 0;DMA1_Channel3->CMAR = 0;
DMA_ClearITPendingBit(DMA1_IT_TC3);
}
}
My buffer receives 10bytes. In a noisy media, some noises can deceive my receiver. I implement another pin for telling the receiver I need to send:
void EXTI15_10_IRQHandler(void){
if (EXTI_GetITStatus(EXTI_Line10) != RESET) {
if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_10)==0 ){DMA_Configuration();GPIO_ResetBits(GPIOA,GPIO_Pin_5);}
else
{ //USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);
GPIO_SetBits(GPIOA,GPIO_Pin_5);
DMA_DeInit(DMA1_Channel3);
//USART_DMACmd(USART3, USART_DMAReq_Rx, DISABLE);
}
EXTI_ClearITPendingBit(EXTI_Line10);
}
}
But I can't Enable and Disable DMA correctly(for example by getting 1-10 bytes it stop working in receiving mode).
I disabled my DMA with different ways:
Disabling: DMA_DeInit(DMA1_Channel3); USART_DMACmd(USART3, USART_DMAReq_Rx, DISABLE); DMA_Cmd(DMA1_Channel3, DISABLE);
Enabling: Calling DMA_Configuration(); USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE); DMA_Cmd(DMA1_Channel3, ENABLE);
I will be thankful if you could help me.
2020-02-26 09:15 PM
Hard to say. I take it that the data is sent in a burst - one byte right after another, but how long is the gap between bursts (transfers)? What are the GPIOs used for an how - what is the GPIOA pin 5, and when does the EXTI_Line10 change state? Can data be dropped (DMA TC doesn't occur)?
2020-02-29 01:15 AM
I really appreciate your help.
1)PC10 is used for realizing that the data is ready to send (when it goes to zero it means the transmitter wants to start sending). The receiver change the state of PA.5 to inform the transmitter I am ready to get the Data. I changed the mode of DMA to circular but it works for one time and never happens again( I count the execution of DMA TC interrupt)
2020-02-29 04:07 AM
First, I hope the environment is not so noisy that it could cause EXTI_Line10 to change state in the middle of transmission.
And if you use circular DMA, it might be better to leave the DMA ON and use transfer half complete interrupt too.
When the next message should arrive, have you checked the DMAC status and USART status? That might give you an idea about what's wrong.
Note, that if the sender changes the state of EXTI_Line10 right after the data is put to USART data register, it might stop the receive DMA before the message gets completely received. Then the interrupt won't take place. TC usually takes plece when the DMA is done. The USART still keeps on ticking the data out. Check the USART TC, and maybe even add a short delay after that. The TXE is usually given when data is moved from DR to the shift register (such that new data can be written).
2020-02-29 04:51 AM
This seems to be broken on so many levels. Maybe "noisy environment" actually is multiple EXTI events from buttons, ground loops and flawed USART code? Anyway, if noise is the real problem, one must choose appropriate hardware transmission line implementation and use checksums on messages. Messages can also include addresses and eliminate EXTI lines.
For a typical command and data usage DMA is not required and interrupt mode is easier to implement. And proper USART implementation is shown there: https://github.com/MaJerle/stm32-usart-uart-dma-rx-tx
2020-02-29 06:42 AM
I really thank you for your explanation and your help.
I've added these lines to DMA interrupt:
USART_Cmd(USART3,DISABLE);
USART_ITConfig(USART3,USART_IT_RXNE,DISABLE);
DMA_Cmd(DMA1_Channel3, DISABLE);
and these lines instead of "DMA_Configuration();GPIO_ResetBits(GPIOA,GPIO_Pin_5);"
USART_Cmd(USART3,ENABLE);USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);DMA_Cmd(DMA1_Channel3, ENABLE);
it works fine when the transmitter changes its Ready -to-send pin and the receiver changes the states of PA.5. But when I've added the mentioned lines to "EXTI15_10_IRQHandler" "else sentence" it stop working. what is the mistake?
2020-02-29 08:07 AM
The biggest problem is in not listening and not reading documentation. Make basic USART on interrupts working like in a Tilen's example, then learn EXTI. You don't need DMA for your 10 bytes. And probably this usage of EXTI is also the result of the same level of flawed design and is not actually needed.
2020-02-29 09:01 AM
I appreciate your comment. Yes, I have implemented USART/EXTI before but now I need to learn more about DMA and why this code doesn't work( I need to send more than 500Kbyte/S data and I need to do small amount of samples byte(10 bytes).
2020-02-29 09:52 AM
That's 5 Mbps. For such a speeds with USART, especially in noisy environments, you'll need a proper transmission line with proper impedances - RS-485 or something like that. And you'll need a real correct asynchronous code with buffering, not this "cobbled something together, sometimes seems to work" style code. Well, I can only repeat the third time - start learning the reference manual and Tilen's example!
2020-03-02 09:39 AM
I think the sender asserts the EXTI_15_10 as soon as it gets tha last data put in the DR register. The last data hasn't been transfered yet.
There should not be interrupt for the rising edge, because the sender really doesn't know when the receiver is done - or rather, it shouldn't stop the receiving.
The receiving is done when the DMAC says so. The transmission is done when the USART says so (TC). After the transmitter writes the last byte into the DR, there can be 2 bytes in the "hardware pipeline" being transmitted out. One in the shift register, another in the DR.
I f you can't affect the sender's EXTI_15_10-behaviour, you should receive, until DMAC gives TC. Then toggle PA5 and wait until EXTI_15_10 is "inactive" - in that order.
That is, after received all, then let the transmitter know the the receiver is no more listening - until next round.