【GD32L233C-START评测】4、USART用空闲中断和DMA实现不定长数据的接收
[复制链接]
对于串口的数据接收,很多的场合都需要接收不定长的数据。如果只是通过接收中断的方式来实现接收不定长数据会非常麻烦。
还好,GD32的这款L233 MCU的USART提供了idle中断功能。
idle中断结合DMA接收是接收不定长数据非常经典的方法,也是非常基础和常用的方法。
基本思路:
1.通过idle中断保证一帧数据接收完成
2.通过DMA获取接收到的数据的长度。
3.从buffer里获取指定长度的数据供应用程序处理
关于DMA,可能跟之前我们使用的有点区别,我没有找到外设和DMA通道的对应表。
直接使用DMA通道1作为USART的接收通道,发现可以正常使用。
例程里也提供了一个idle中的结合DMA的例子,例程使用的是USART1.
稍加改动,就可以改动到其它USART上面去。
本次我将使用USART0来实现idle中的和DMA接收功能。
USART0在开发板硬件上是直接通过uart转USB接口引出的,只需要一根usb线就可以实现与PC的通讯。
引脚用的是PA9(TX),PA10(RX)
如下:
程序上主要分为几个部分:
1.usart0的初始化:引脚配置,使能发送和接收,使能idle中断等;
2.接收DMA配置
3.idle中断的相关配置
4.usart0的中断处理函数实现
具体如下:
1.usart0的初始化:
void uart0_init(void)
{
nvic_irq_enable(USART0_IRQn, 0);
/* enable GPIO clock */
rcu_periph_clock_enable(RCU_GPIOA);
/* enable USART clock */
rcu_periph_clock_enable(RCU_USART0);
/* connect port to USART TX */
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9);
/* connect port to USART RX */
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_10);
/* configure USART TX as alternate function push-pull */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_9);
/* configure USART RX as alternate function push-pull */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_10);
/* USART configure */
usart_deinit(USART0);
usart_baudrate_set(USART0, 115200U);
usart_receive_config(USART0, USART_RECEIVE_ENABLE);
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
usart_dma_receive_config(USART0, USART_DENR_ENABLE);
//usart_dma_transmit_config(USART1, USART_DENT_ENABLE);
usart_enable(USART0);
}
2.接收DMA配置:
void uart0_dma_init(void)
{
dma_parameter_struct dma_init_struct;
/* enable DMA clock */
rcu_periph_clock_enable(RCU_DMA);
/* initialize DMA channel 1 */
dma_deinit(DMA_CH1);
dma_struct_para_init(&dma_init_struct);
dma_init_struct.request = DMA_REQUEST_USART0_RX;
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
dma_init_struct.memory_addr = (uint32_t)usart0_rec_buf;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
dma_init_struct.number = UART0_DMA_REC_LEN;
dma_init_struct.periph_addr = (uint32_t)&USART_RDATA(USART0);
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA_CH1, &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA_CH1);
dma_memory_to_memory_disable(DMA_CH1);
/* disable the DMAMUX_MUXCH1 synchronization mode */
dmamux_synchronization_disable(DMAMUX_MUXCH1);
/* enable DMA channel 1 */
dma_channel_enable(DMA_CH1);
}
3.idle中断的相关配置:
void uart0_idle_init(void)
{
/*wait IDLEF set and clear it*/
while(RESET == usart_flag_get(USART0, USART_FLAG_IDLE)) {
}
usart_flag_clear(USART0, USART_FLAG_IDLE);
usart_interrupt_enable(USART0, USART_INT_IDLE);
}
4.usart0的中断处理函数实现:
void USART0_IRQHandler(void)
{
if(RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE)){
usart_interrupt_flag_clear(USART0, USART_INT_FLAG_IDLE);
/* number of data received */
Usart0RecLen = UART0_DMA_REC_LEN - (dma_transfer_number_get(DMA_CH1));
memcpy(usart0_rec_pro_buf,usart0_rec_buf,Usart0RecLen);
usart0_rec_comp_flag = 1;
/* disable DMA and reconfigure */
dma_channel_disable(DMA_CH1);
dma_transfer_number_config(DMA_CH1, UART0_DMA_REC_LEN);
dma_channel_enable(DMA_CH1);
}
}
编译,下载,调试:
串口助手发送1234:
以上测试达到了预期的效果!
源代码如下:
gd_finger.zip
(606.14 KB, 下载次数: 81)
|