rtthread 串口dma接收_RT-Thread 设备驱动UART浅析

OS版本:RT-Thread 4.0.0

芯片:STM32F407

RT-Thread的串口驱动框架与Linux相识,分成 I/O设备框架 + 设备底层驱动;

1. serial设备初始化及使用

将配置使能的 uart_obj[ ] 进行设备注册

rtthread_startup --> rt_hw_usart_init() --> rt_hw_serial_register --> rt_device_register

设备注册之后就可使用设备操作方式来使用串口

rt_device_find("uart3") -->  rt_device_open(serial, RT_DEVICE_FLAG_DMA_RX) -->  rt_device_set_rx_indicate(serial, uart_dma_rx_handle)

2. serial设备

设备层 rt_device 注册及 ops 实现

const static struct rt_device_ops serial_ops ={

rt_serial_init,

rt_serial_open,

rt_serial_close,

rt_serial_read,

rt_serial_write,

rt_serial_control

};

而serial设备 rt_serial_device 为 rt_device 的一个子类

structrt_serial_device

{structrt_device parent;const struct rt_uart_ops *ops;structserial_configure config;void *serial_rx;void *serial_tx;

};

其中 rt_serial_device 中的 ops 通过 stm32_uart_ops 实现,这样 rt_device、rt_serial_device 和 uart底层就都关联起来了

硬件驱动层文件

drv_usart.c

drv_usart.h

stm32f4xx_hal_msp.c

主要内容 ops 实现,中断处理

static const struct rt_uart_ops stm32_uart_ops ={

.configure=stm32_configure, //默认配置

.control=stm32_control,

.putc=stm32_putc,

.getc=stm32_getc,

};

串口硬件初始化  HAL_UART_MspInit  对串口引脚和时钟的初始化 在 stm32f4xx_hal_msp.c 中,通过配置CubeMX生成;

3. 驱动分析

serial 的 control 操作 设计成 不能设置中断,即缺少 RT_DEVICE_CTRL_SET_INT 和 RT_DEVICE_CTRL_CLR_INT 操作, 这样可以避免误设置;

同时也是由于串口接收已经设计成三选一方式:中断、DMA、轮询;

说一下DMA,因为这也是我们最常用的串口数据接收处理方式;

RTT的 serial 的DMA接收,采用的 IDLE 中断来控制DMA接收数据的,

在 drv_usart.c 中

static void stm32_dma_config(struct rt_serial_device *serial)

{

....../*enable interrupt*/__HAL_UART_ENABLE_IT(&(uart->handle), UART_IT_IDLE); //使能了空闲中断和DMA中断/*enable rx irq*/HAL_NVIC_SetPriority(uart->config->dma_rx->dma_irq, 0, 0);

HAL_NVIC_EnableIRQ(uart->config->dma_rx->dma_irq);

HAL_NVIC_SetPriority(uart->config->irq_type, 1, 0);

HAL_NVIC_EnableIRQ(uart->config->irq_type);

....

}

在中断处理函数 uart_isr 中 实现了

static void uart_isr(struct rt_serial_device *serial)

{

....

#ifdef RT_SERIAL_USING_DMAelse if ((uart->uart_dma_flag) && (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_IDLE) != RESET) &&(__HAL_UART_GET_IT_SOURCE(&(uart->handle), UART_IT_IDLE) !=RESET)) //IDLE空闲中断

{

level=rt_hw_interrupt_disable();

recv_total_index= serial->config.bufsz - __HAL_DMA_GET_COUNTER(&(uart->dma.handle));

recv_len= recv_total_index - uart->dma.last_index;

uart->dma.last_index =recv_total_index;

rt_hw_interrupt_enable(level);if(recv_len)

{

rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE| (recv_len << 8));

}

__HAL_UART_CLEAR_IDLEFLAG(&uart->handle);

}#endif.....

}

void rt_hw_serial_isr(struct rt_serial_device *serial, int event)

{caseRT_SERIAL_EVENT_RX_DMADONE:

{intlength;

rt_base_t level;/*get DMA rx length*/length= (event & (~0xff)) >> 8;if (serial->config.bufsz == 0)

{struct rt_serial_rx_dma*rx_dma;

rx_dma= (struct rt_serial_rx_dma*) serial->serial_rx;

RT_ASSERT(rx_dma!=RT_NULL);

RT_ASSERT(serial->parent.rx_indicate !=RT_NULL);

serial->parent.rx_indicate(&(serial->parent), length);

rx_dma->activated =RT_FALSE;

}else{/*disable interrupt*/level=rt_hw_interrupt_disable();/*update fifo put index*/rt_dma_recv_update_put_index(serial, length);/*calculate received total length*/length=rt_dma_calc_recved_len(serial);/*enable interrupt*/rt_hw_interrupt_enable(level);/*invoke callback*/

if (serial->parent.rx_indicate !=RT_NULL)

{

serial->parent.rx_indicate(&(serial->parent), length); //应用回调接收处理函数

}

}break;

}

}

如果进行大数据传输,发现默认缓存(64字节)不够用 可修改 RT_SERIAL_RB_BUFSZ 值

#define RT_SERIAL_CONFIG_DEFAULT \{ \

BAUD_RATE_115200,/*115200 bits/s*/\

DATA_BITS_8,/*8 databits*/\

STOP_BITS_1,/*1 stopbit*/\

PARITY_NONE,/*No parity*/\

BIT_ORDER_LSB,/*LSB first sent*/\

NRZ_NORMAL,/*Normal mode*/\

RT_SERIAL_RB_BUFSZ,/*Buffer size*/\0\

}

#define RT_SERIAL_RB_BUFSZ              64


版权声明:本文为weixin_39955700原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。