1
\$\begingroup\$

I'm trying to set up UART communication with DMA using the STM32F103C8 controller. I'm trying to receive data with DMA, but I can't receive data continuously. Can anyone correct me if I made a mistake? I'm using STM32f103C8 registers to code.

Communication: USART3
Pins: PB10-TX, PB11-RX
DMA channels: DMA1_channel1 for TX, DMA1_channel3 for RX

#include<stm32f10x.h>
uint8_t rx_data[20];
    
void USART3_config(void)
{
  RCC->APB1ENR |= RCC_APB1ENR_USART3EN;
  RCC->AHBENR |= RCC_AHBENR_DMA1EN;
            
  USART3->BRR = 0x0EA6; // for 9600 baurd rate
  USART3->CR1 |= USART_CR1_TE | USART_CR1_RXNEIE | USART_CR1_RE;
  USART3->CR3 |= USART_CR3_DMAT | USART_CR3_DMAR;
  USART3->CR1 |= USART_CR1_UE;

  NVIC_EnableIRQ(USART3_IRQn);
}
    
void USART_DMA_RX_init(void)
{
  RCC->AHBENR |= RCC_AHBENR_DMA1EN;

  DMA1_Channel3->CPAR = (uint32_t)&USART3->DR;
  DMA1_Channel3->CMAR = (uint32_t)rx_data;
  DMA1_Channel3->CNDTR = 20;
  DMA1_Channel3->CCR |= DMA_CCR3_MINC | DMA_CCR3_TCIE | DMA_CCR3_HTIE;
  DMA1_Channel3->CCR |= DMA_CCR3_EN;

  NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}

int main(void)
{
  RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;
  GPIOB->CRH = 0x00008B00;
  USART_DMA_RX_init();
  USART3_config();
      
  while(1)
  {}
}
    
void DMA1_Channel3_IRQHandler(void)
{
  if ((DMA1->ISR & DMA_ISR_HTIF3) == DMA_ISR_HTIF3)
  {
    DMA1->IFCR = DMA_IFCR_CHTIF3;
  }
  else if ((DMA1->ISR & DMA_ISR_TCIF3) == DMA_ISR_TCIF3)
  {
    DMA1->IFCR = DMA_IFCR_CGIF3 | DMA_IFCR_CTCIF3;
  }
}

void USART3_IRQHandler(void)
{
  if ((USART3->SR & USART_SR_RXNE) == USART_SR_RXNE)
  {
    USART3->SR &= ~ USART_SR_RXNE;
  }
}
\$\endgroup\$
10
  • 1
    \$\begingroup\$ What do you mean with "I can't receive data continuously"? What do you expect to happen, and what happens instead? \$\endgroup\$
    – Codo
    Jan 24, 2023 at 10:08
  • 2
    \$\begingroup\$ That's how you have configured it. CNDTR is set to 20. After 20 bytes, DMA is complete and stops. It must be restarted to process further data. And since DMA is used, the USART IRQ isn't needed. \$\endgroup\$
    – Codo
    Jan 24, 2023 at 11:35
  • 2
    \$\begingroup\$ The code configures DMA to process 20 bytes. It does not configure DMA to run continuously. You have two options: Either restart DMA after the DMA interrupt (with TCIF3 bit set) has occurred, or configure DMA for circular mode. \$\endgroup\$
    – Codo
    Jan 24, 2023 at 12:52
  • 2
    \$\begingroup\$ Please add the code that didn't work to your question. Then we can have a look at it. \$\endgroup\$
    – Codo
    Jan 24, 2023 at 14:14
  • 1
    \$\begingroup\$ Also you should always declare DMA buffers volatile, or the compiler might decide to generate nonsense during optimization. \$\endgroup\$
    – Lundin
    Jan 24, 2023 at 15:07

1 Answer 1

0
\$\begingroup\$

Couple of pointers:

  1. There's no need for this callback as it's not needed void USART3_IRQHandler(void)
  2. You've set only 20 bytes to be transferred. So it'll stop after 20 bytes. When it comes to DMA reception, you need to specify the length of the incoming bytes.
  3. Also as @Lundin said, declare buffer to be volatile
\$\endgroup\$
1
  • 1
    \$\begingroup\$ EmbeddedAlpha - Hi, (a) As you're new here, please see the tour & help center as the site rules differ from typical forums. (b) We do not allow links unless they have a very specific reason why they are useful for this answer. Therefore your GitHub link has been removed. You can edit your site profile and add it there, if you want people to know about it. (c) Don't ask questions in an answer. If you need to ask clarification questions to an OP, that should be done in a comment when you have 50 points. \$\endgroup\$
    – SamGibson
    Feb 19 at 22:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.