[研电赛技术支持] GD32H759 UART DMA接收问题

[复制链接]
 楼主| ryan_jiang 发表于 2025-4-23 14:32 | 显示全部楼层 |阅读模式
GD32H759 UART开启DMA接收+空闲中断;开启了cache。第一次接收的数据是正确的,后面接收的数据,只要接收的数据长度大于上一次接收的数据才能正确接收;小于上一次的长度,接收不到数据,DMA读取的数据长度和数据还是保持上次的数据,没有更新,但是回正常进入空闲中断,读取DMA的接收数据长度还是上次的。比如第一次发送数据123456789这9个数据是正常接收的;后面我发送123456789abc,这样也是正常接收的;但是我发qwe这三个数据,会正常进入空闲中断,但是读取DMA接收数据长度还是上次123456789abc的数据长度,缓存的数据也是上次的123456789abc。很奇怪,不知道问题出在哪?

  1. #define USART1_RDATA_ADDRESS      (&USART_RDATA(USART1))
  2. #define USART1_TDATA_ADDRESS      (&USART_TDATA(USART1))

  3. #define UART1_BUADRATE                115200

  4. //Uart1_Com_Type  Uart1_Com={0};

  5. __attribute__ ((aligned(32))) uint8_t uart1_tx_buf[64];
  6. __attribute__ ((aligned(32))) uint8_t uart1_rx_buf[64];
  7. uint8_t TransmitDone = 0;
  8. void gd32h7_uart1_config(void)
  9. {
  10.         /* enable GPIO clock */
  11.     rcu_periph_clock_enable(RCU_GPIOA);
  12.     /* enable USART clock */
  13.     rcu_periph_clock_enable(RCU_USART1);
  14.         /* connect port to USART TX */
  15.     gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_2);
  16.     /* connect port to USART RX */
  17.     gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_3);
  18.         /* configure USART TX as alternate function push-pull */
  19.     gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2);
  20.     gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_2);
  21.     /* configure USART RX as alternate function push-pull */
  22.     gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_3);
  23.     gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_3);
  24.        
  25.         nvic_irq_enable(USART1_IRQn, 1, 0);
  26.         /* USART configure */
  27.     usart_deinit(USART1);
  28.         usart_oversample_config(USART1,USART_OVSMOD_16);
  29.         usart_word_length_set(USART1,USART_WL_8BIT);
  30.         usart_parity_config(USART1,USART_PM_NONE);
  31.         usart_sample_bit_config(USART1,USART_OSB_1BIT);
  32.         usart_baudrate_set(USART1, UART1_BUADRATE);
  33.     usart_receive_config(USART1, USART_RECEIVE_ENABLE);
  34.     usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);
  35.     usart_dma_receive_config(USART1, USART_RECEIVE_DMA_ENABLE);
  36.         usart_dma_transmit_config(USART1, USART_TRANSMIT_DMA_ENABLE);
  37.         usart_interrupt_enable(USART1,USART_INT_IDLE);
  38.         usart_interrupt_flag_clear(USART1, USART_INT_FLAG_IDLE);
  39.     usart_enable(USART1);
  40.        
  41. }

  42. #ifdef USE_PRINTF
  43. /* retarget the C library printf function to the USART */
  44. int fputc(int ch, FILE *f)
  45. {
  46.     usart_data_transmit(USART1, (uint8_t)ch);
  47.     while(RESET == usart_flag_get(USART1, USART_FLAG_TBE));

  48.     return ch;
  49. }
  50. #endif
  51. void gd32h7_uart1_dma_config(void)
  52. {
  53.         dma_single_data_parameter_struct dma_init_struct;
  54.         /* enable DMA clock */
  55.     rcu_periph_clock_enable(RCU_DMA1);
  56.     /* enable DMAMUX clock */
  57.     rcu_periph_clock_enable(RCU_DMAMUX);
  58. #ifndef USE_PRINTF
  59.     /* initialize the com */
  60.         nvic_irq_enable(DMA1_Channel0_IRQn, 5, 0);
  61.        
  62.        
  63.        
  64.     /* initialize DMA channel 0 --> UART1_TX*/
  65.     dma_deinit(DMA1, DMA_CH0);
  66.     dma_single_data_para_struct_init(&dma_init_struct);
  67.     dma_init_struct.request      = DMA_REQUEST_USART1_TX;
  68.     dma_init_struct.direction    = DMA_MEMORY_TO_PERIPH;
  69. //    dma_init_struct.memory0_addr  = (uint32_t)txbuffer;
  70.     dma_init_struct.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
  71.     dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
  72. //    dma_init_struct.number       = ARRAYNUM(txbuffer);
  73.     dma_init_struct.periph_addr  = (uint32_t)USART1_TDATA_ADDRESS;
  74.     dma_init_struct.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
  75.     dma_init_struct.priority     = DMA_PRIORITY_ULTRA_HIGH;
  76.     dma_single_data_mode_init(DMA1, DMA_CH0, &dma_init_struct);

  77.     /* configure DMA mode */
  78.     dma_circulation_disable(DMA1, DMA_CH0);
  79.     /* USART DMA enable for transmission and reception */
  80.     usart_dma_transmit_config(USART1, USART_TRANSMIT_DMA_ENABLE);
  81.     /* enable DMA channel 0 transfer complete interrupt */
  82.     dma_interrupt_enable(DMA1, DMA_CH0, DMA_CHXCTL_FTFIE);
  83.     /* enable DMA channel 0 */
  84. //    dma_channel_enable(DMA1, DMA_CH0);
  85. #endif
  86.     /* initialize DMA channel 1 --> UART1_RX*/
  87.     dma_deinit(DMA1, DMA_CH1);
  88.     dma_single_data_para_struct_init(&dma_init_struct);
  89.     dma_init_struct.request      = DMA_REQUEST_USART1_RX;
  90.     dma_init_struct.direction    = DMA_PERIPH_TO_MEMORY;
  91. //    dma_init_struct.memory0_addr  = (uint32_t)rxbuffer;
  92.     dma_init_struct.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
  93.     dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
  94. //    dma_init_struct.number       = 32;
  95.     dma_init_struct.periph_addr  = (uint32_t)USART1_RDATA_ADDRESS;
  96.     dma_init_struct.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
  97.     dma_init_struct.priority     = DMA_PRIORITY_ULTRA_HIGH;
  98.     dma_single_data_mode_init(DMA1, DMA_CH1, &dma_init_struct);

  99.     /* configure DMA mode */
  100.     dma_circulation_disable(DMA1, DMA_CH1);
  101.     /* USART DMA enable for reception */
  102.     usart_dma_receive_config(USART1, USART_RECEIVE_DMA_ENABLE);
  103.     /* disable DMA channel 1 transfer complete interrupt */
  104.     dma_interrupt_disable(DMA1, DMA_CH1, DMA_CHXCTL_FTFIE);
  105.     /* enable DMA channel 1 */
  106. //    dma_channel_enable(DMA1, DMA_CH1);
  107. }

  108. void bspUsart1_DMA_Transmit(uint8_t *txd, uint32_t Size)
  109. {
  110.         dma_channel_disable(DMA1, DMA_CH0);
  111.         dma_memory_address_config(DMA1,DMA_CH0,DMA_MEMORY_0,(uint32_t)txd);
  112.         dma_transfer_number_config(DMA1,DMA_CH0,Size);
  113.         usart_dma_transmit_config(USART1, USART_TRANSMIT_DMA_ENABLE);
  114.         dma_channel_enable(DMA1, DMA_CH0);
  115.        
  116. }

  117. void bspUsart1_DMA_Receive(uint8_t *rxd, uint32_t Size)
  118. {
  119.         dma_channel_disable(DMA1, DMA_CH1);
  120.         dma_memory_address_config(DMA1,DMA_CH1,DMA_MEMORY_0,(uint32_t)rxd);
  121.         dma_transfer_number_config(DMA1,DMA_CH1,Size);
  122.         usart_dma_receive_config(USART1, USART_RECEIVE_DMA_ENABLE);
  123.         dma_channel_enable(DMA1, DMA_CH1);
  124. }

  125. void bsp_uart_init(void)
  126. {
  127.         gd32h7_uart1_dma_config();
  128.         gd32h7_uart1_config();
  129.         bspUsart1_DMA_Receive(uart1_rx_buf,UART1_RECV_SIZE);
  130. }



  131. /*!
  132.     \brief      this function handles USART interrupt exception
  133.     \param[in]  none
  134.     \param[out] none
  135.     \retval     none
  136. */

  137. void USART1_IRQHandler(void)
  138. {
  139.         uint16_t recv_len=0;
  140.        
  141.     if(RESET != usart_interrupt_flag_get(USART1, USART_INT_FLAG_IDLE))
  142.         {
  143.         usart_interrupt_flag_clear(USART1, USART_INT_FLAG_IDLE);

  144.                 dma_channel_disable(DMA1, DMA_CH1);
  145.                 dma_interrupt_flag_clear(DMA1, DMA_CH1, DMA_INT_FLAG_FTF);
  146.                 dma_interrupt_flag_clear(DMA1, DMA_CH1, DMA_INT_FLAG_HTF);
  147.                 dma_interrupt_flag_clear(DMA1, DMA_CH1, DMA_INT_FLAG_TAE);
  148.                 dma_interrupt_flag_clear(DMA1, DMA_CH1, DMA_INT_FLAG_FEE);
  149.                 dma_interrupt_flag_clear(DMA1, DMA_CH1, DMA_INT_FLAG_FEE);
  150.                 SCB_InvalidateDCache_by_Addr(uart1_rx_buf,UART1_RECV_SIZE);
  151.         /* number of data received */
  152.         recv_len = UART1_RECV_SIZE - (dma_transfer_number_get(DMA1, DMA_CH1));
  153.                
  154.                
  155.                

  156.                
  157.                

  158.                
  159.     }
  160. }

  161. /*!
  162.     \brief      this function handles DMA_Channel0_IRQHandler exception
  163.     \param[in]  none
  164.     \param[out] none
  165.     \retval     none
  166. */
  167. void DMA1_Channel0_IRQHandler(void)
  168. {
  169.     if(RESET != dma_interrupt_flag_get(DMA1, DMA_CH0, DMA_INT_FLAG_FTF))
  170.         {
  171.         dma_interrupt_flag_clear(DMA1, DMA_CH0, DMA_INT_FLAG_FTF);
  172.                 dma_interrupt_flag_clear(DMA1, DMA_CH0, DMA_INT_FLAG_HTF);
  173.                 dma_interrupt_flag_clear(DMA1, DMA_CH0, DMA_INT_FLAG_TAE);
  174.                 dma_interrupt_flag_clear(DMA1, DMA_CH0, DMA_INT_FLAG_FEE);
  175.                 dma_interrupt_flag_clear(DMA1, DMA_CH0, DMA_INT_FLAG_FEE);
  176.                 TransmitDone = 1;
  177.                
  178.     }
  179. }

  180. /*!
  181.     \brief      this function handles DMA_Channel1_IRQHandler exception
  182.     \param[in]  none
  183.     \param[out] none
  184.     \retval     none
  185. */
  186. void DMA1_Channel1_IRQHandler(void)
  187. {
  188.     if(RESET != dma_interrupt_flag_get(DMA1, DMA_CH1, DMA_INT_FLAG_FTF))
  189.         {
  190.         dma_interrupt_flag_clear(DMA1, DMA_CH1, DMA_INT_FLAG_FTF);
  191.                 dma_interrupt_flag_clear(DMA1, DMA_CH1, DMA_INT_FLAG_HTF);
  192.                 dma_interrupt_flag_clear(DMA1, DMA_CH1, DMA_INT_FLAG_TAE);
  193.                 dma_interrupt_flag_clear(DMA1, DMA_CH1, DMA_INT_FLAG_FEE);
  194.                 dma_interrupt_flag_clear(DMA1, DMA_CH1, DMA_INT_FLAG_FEE);
  195.                

  196.     }
  197. }


classroom 发表于 2025-4-24 10:54 | 显示全部楼层
DMA缓存未正确更新?GD32H759启用了Cache,而DMA直接访问内存。若未正确处理Cache一致性,可能导致DMA读取到的是缓存中的旧数据,而非内存中的最新数据。
fxyc87 发表于 2025-4-24 11:47 | 显示全部楼层
arm cortex m7有一个概念叫缓存,如果你不懂,你可以将其禁用掉。牺牲一点性能。
flycamelaaa 发表于 2025-4-24 12:00 | 显示全部楼层
DMA的传输长度可能未正确重置或更新,导致DMA始终按照上一次的配置进行传输。
powerantone 发表于 2025-4-24 13:20 | 显示全部楼层
若未正确重置DMA传输长度,DMA可能继续使用旧长度,导致数据截断或错误。
stormwind123 发表于 2025-4-24 14:04 | 显示全部楼层
接收缓冲区未正确对齐?
probedog 发表于 2025-4-24 15:00 | 显示全部楼层
闲中断处理函数中,可能未正确读取DMA传输的数据长度或未更新接收状态。
classroom 发表于 2025-4-24 16:23 | 显示全部楼层
问题应该主要由Cache一致性和DMA配置不当引起。
喂什么玩意 发表于 2025-5-31 11:49 | 显示全部楼层
如果缓存数据长度不变,说明DMA计数器没有变化,DMA没有更新缓存指针。
wddvvsdf 发表于 2025-7-7 14:27 | 显示全部楼层
这个芯片的DMA映射表在哪里看的
您需要登录后才可以回帖 登录 | 注册

本版积分规则

8

主题

24

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部

8

主题

24

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部