lbbook 发表于 2022-4-17 21:52

(3)UART之DMA加IDLE中断不定长字节接收

<p style="text-indent:21.0pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;"><em><span style="font-family:宋体"><span style="font-style:normal">雷达应用接收的数据量比较大,因此需要用到DMA来提高速度,降低MCU负载。之前的项目已经在STM32F103芯片上使用了DMA+IDLE中断的方式实现了不定长的UART数据接收,这里也想在GD32L233C实现。</span></span></em></span></span></p>

<p style="text-indent:21.0pt; text-align:justify">&nbsp;</p>

<p style="text-indent:21.0pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;"><em><span lang="EN-US" style="font-family:宋体"><span style="font-style:normal">GD32L233C-START</span></span></em><em><span style="font-family:宋体"><span style="font-style:normal">开发板配套的例程GD32L233K_START_Demo_Suites只有6个例程。关于UART接口的只有04_USART_HyperTerminal_Interrupt这一个例程。也不是我想要的DMA。但是我看到</span></span></em><i><span lang="EN-US" style="font-family:宋体">GD32L23x_Demo_Suites_V1.1.0</span></i><span style="font-family:宋体">这个例程包里面还有另外一个开发板的配套例程GD32L233R_EVAL_Demo_Suites,里面有多达24个例程。光UART相关就有4个,特别是包含DMA的例程,真是柳暗花明又一村。</span></span></span></p>

<p style="text-indent:21.0pt; text-align:justify">&nbsp;</p>

<p style="text-indent:21.0pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;"><span style="font-family:宋体">例程是这样的:启</span><span style="font-family:宋体">动后,</span>USART<span style="font-family:宋体">将输出</span>&ldquo;USART DMA interrupt receive and transmit example, please input 10 bytes:&rdquo;<span style="font-family:宋体">并等待接收由超级终端发送</span>10<span style="font-family:宋体">个字节的数据。</span>MCU<span style="font-family:宋体">接收到数据后,串口将接收到的数据继续输出到超级终端。</span></span></span></p>

<p style="text-indent:21.0pt; text-align:justify">&nbsp;</p>

<p style="text-indent:21.0pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;"><span style="font-family:宋体">功能实在是太简单了,好在</span>DMA<span style="font-family:宋体">收发功能都已经初始化完毕,因此只需要进行简单修改就好了。</span></span></span></p>

<p style="text-indent:21.0pt; text-align:justify">&nbsp;</p>

<p style="text-indent:21.0pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;"><span style="font-family:宋体">首先是</span><em><span lang="EN-US" style="font-family:宋体"><span style="font-style:normal">GD32L233C-START</span></span></em><em><span style="font-family:宋体"><span style="font-style:normal">开发板使用的是USART0,对应的IO是PA9和PA10,因此需要修改所有相关代码。这里就不展开了。</span></span></em></span></span></p>

<p style="text-indent:21.0pt; text-align:justify">&nbsp;</p>

<p style="text-indent:21.0pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;"><em><span style="font-family:宋体"><span style="font-style:normal">其次是需要添加IDLE中断相关使能代码。</span></span></em></span></span></p>

<p style="text-indent:21.0pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;"><strong><em><span lang="EN-US" style="font-family:宋体"><span style="font-style:normal">main.c</span></span></em></strong><em><span style="font-family:宋体"><span style="font-style:normal">中系统初始化UART后面添加UART中断使能以及IDLE中断使能,</span></span></em></span></span></p>

<pre>
<code class="language-cpp">    /* USART interrupt configuration */
    nvic_irq_enable(USART0_IRQn, 0);
    /* enable USART1 IDLE interrupt */
    usart_interrupt_enable(USART0, USART_INT_IDLE);
</code></pre>

<p><span style="font-size:10.5pt"><span style="font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;"><em><span style="font-family:宋体"><span style="font-style:normal">&nbsp;&nbsp; 特别是前一句,如果未添加的话无法进入中断,也就没有IDLE中断了。我也是看了05_USART_HyperTerminal_Interrupt这个例程才找到原因的。</span></span></em></span></span></p>

<p style="text-indent:21.0pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;"><strong><em><span lang="EN-US" style="font-family:宋体"><span style="font-style:normal">gd32l23x_it.c</span></span></em></strong><em><span style="font-family:宋体"><span style="font-style:normal">中添加IDLE中断调用:</span></span></em></span></span></p>

<pre>
<code class="language-cpp">void USART0_IRQHandler(void)
{
    if(RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE)) {
      usart_interrupt_flag_clear(USART0, USART_INT_FLAG_IDLE);// 清标志
      dma_channel_disable(DMA_CH1);// 关闭DMA
      //DMA接收到数据后CHCNT是往下减的,因此已经接收到的数据长度=DMA总长-当前CHCNT
      g_receive_count = RX_NUM - DMA_CHCNT(DMA_CH1);
      /* configure the number of remaining data to be transferred */
      DMA_CHCNT(DMA_CH1) = RX_NUM;// 复位DMA计数
      dma_channel_enable(DMA_CH1);// 使能DMA
      g_receive_complete = SET;// 接收数据标志置高
    }
    // 这里可以添加各种通讯错误处理
}</code></pre>

<p><span style="font-size:10.5pt"><span style="font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;"><span style="font-family:宋体">&nbsp;&nbsp; 这里需要对DMA进行干预,因为发生了IDLE事件,即收到一个短于DMA设置长度的数据段,此时可将数据进行处理,然后重新复位DMA计数,否则DMA会将两个甚至多个数据段拼合,导致错误。当然,如果不是像我一样设置了较大的DMA缓存,主要通过IDLE中断来接收不定长数据的话,也可能正合适。</span></span></span></p>

<p style="text-indent:21.0pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;"><span style="font-family:宋体">下面通过串口软件发送不同长度的数据进行简单测试:</span></span></span><span style="font-size:10.5pt"><span style="font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;"><span style="font-family:宋体">都能正确接收回送。附:</span></span></span></p>

Jacktang 发表于 2022-4-18 07:11

<p>如果未添加的话无法进入中断,也就没有IDLE中断了,这个具体什么原因呢</p>

lugl4313820 发表于 2022-4-18 07:49

建议标题,咱加上是哪一款芯片,这样一看就明白。希望下次的文章有进步!谢谢

freebsder 发表于 2022-4-19 17:45

<p>DMA IDLE倒是一个不错的硬件机制,有些硬件没有,只能用硬件定时器来做</p>

秦天qintian0303 发表于 2022-4-19 22:26

lugl4313820 发表于 2022-4-18 07:49
建议标题,咱加上是哪一款芯片,这样一看就明白。希望下次的文章有进步!谢谢

<p>外边选择了主题,再加上芯片是不是太长了</p>

lbbook 发表于 2022-4-22 18:27

Jacktang 发表于 2022-4-18 07:11
如果未添加的话无法进入中断,也就没有IDLE中断了,这个具体什么原因呢

<p>就是必须先开USART中断,再开USART里面的IDLE中断</p>

dayuyuyuyu 发表于 2024-1-10 15:53

<p>为什么这样配置MCU一上电就进入空闲中断</p>
页: [1]
查看完整版本: (3)UART之DMA加IDLE中断不定长字节接收