瑞萨其实两版串口驱动都已经适配了,但是V1版的驱动的适配是放在drv_sci驱动中,个人理解sci是瑞萨专门的一个总线(个人猜测全名是serial control interface),这种总线可以配置成各类串行通信波形。而drv_sci里面适配了不同功能的驱动,内容会显得相对杂乱,不便于分析,且从分析上看,V2版的驱动框架明显比V1版的驱动框架有优势,因此跳过V1版的驱动框架分析实现V2版的驱动框架更加合适。
由V2版驱动框架整理出来的驱动参考模板
#include <rthw.h> #include <rtthread.h> #include <rtdevice.h> #ifdef RT_USING_SERIAL_V2 struct _uart_config { const char *name; // Other uart param }; struct _uart { struct rt_serial_device serial; struct _uart_config config; }; static struct _uart_config uart_config[] = { // Fill uart param }; static struct _uart uart_obj[sizeof(uart_config) / sizeof(uart_config[0])] = {0}; static rt_err_t _configure(struct rt_serial_device *serial, struct serial_configure *cfg) { // TODO: uart config return RT_EOK; } static rt_err_t _control(struct rt_serial_device *serial, int cmd, void *arg) { switch (cmd) { case RT_DEVICE_CTRL_CLR_INT: // TODO: Disable IRQ break; case RT_DEVICE_CTRL_CONFIG: // TODO: Uart config break; case RT_DEVICE_CHECK_OPTMODE: // TODO: Return dma mode or intterupt mode case RT_DEVICE_CTRL_CLOSE: // uart close break; } return RT_EOK; } static int _putc(struct rt_serial_device *serial, char c) { // TODO: process write one byte return 1; } static int _getc(struct rt_serial_device *serial) { // TODO: Read a Byte from uart register // return xxxx(); } static rt_ssize_t _transmit(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, rt_uint32_t tx_flag) { // TODO: Process Tx and Rx function // Return value is real read/write data num return size; } // TODO: Int function that call // rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8)); // rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); // rt_hw_serial_isr(serial, RT_SERIAL_EVENT_TX_DONE); // rt_hw_serial_isr(serial, RT_SERIAL_EVENT_TX_DMADONE); static const struct rt_uart_ops _uart_ops = { .configure = _configure, .control = _control, .putc = _putc, .getc = _getc, .transmit = _transmit }; int rt_hw_usart_init(void) { rt_err_t result = 0; rt_size_t obj_num = sizeof(uart_obj) / sizeof(struct _uart); for (int i = 0; i < obj_num; i++) { // TODO: uart config init uart_obj[i].serial.ops = &_uart_ops; result = rt_hw_serial_register(&uart_obj[i].serial, uart_obj[i].config->name, RT_DEVICE_FLAG_RDWR, NULL); RT_ASSERT(result == RT_EOK); } return result; } #endif /* RT_USING_SERIAL_V2 */
适配接口分析
源码路径
bsp\renesas\libraries\HAL_Drivers\drv_usart_v2.c
注册入口
// 此部分由RASC生成,并不需要改动 #if defined(BSP_USING_UART0) #ifndef UART0_CONFIG #define UART0_CONFIG \ { \ .name = "uart0", \ .p_api_ctrl = &g_uart0_ctrl, \ .p_cfg = &g_uart0_cfg, \ } #endif /* UART0_CONFIG */ #endif /* BSP_USING_UART0 */ #if defined(BSP_USING_UART1) #ifndef UART1_CONFIG #define UART1_CONFIG \ { \ .name = "uart1", \ .p_api_ctrl = &g_uart1_ctrl, \ .p_cfg = &g_uart1_cfg, \ } #endif /* UART1_CONFIG */ #endif /* BSP_USING_UART1 */ #if defined(BSP_USING_UART2) #ifndef UART2_CONFIG #define UART2_CONFIG \ { \ .name = "uart2", \ .p_api_ctrl = &g_uart2_ctrl, \ .p_cfg = &g_uart2_cfg, \ } #endif /* UART2_CONFIG */ #endif /* BSP_USING_UART2 */ #if defined(BSP_USING_UART3) #ifndef UART3_CONFIG #define UART3_CONFIG \ { \ .name = "uart3", \ .p_api_ctrl = &g_uart3_ctrl, \ .p_cfg = &g_uart3_cfg, \ } #endif /* UART3_CONFIG */ #endif /* BSP_USING_UART3 */ #if defined(BSP_USING_UART9) #ifndef UART9_CONFIG #define UART9_CONFIG \ { \ .name = "uart9", \ .p_api_ctrl = &g_uart9_ctrl, \ .p_cfg = &g_uart9_cfg, \ } #endif /* UART9_CONFIG */ #endif /* BSP_USING_UART9 */ static struct ra_uart_config uart_config[] = { #ifdef BSP_USING_UART0 UART0_CONFIG, #endif #ifdef BSP_USING_UART1 UART1_CONFIG, #endif #ifdef BSP_USING_UART2 UART2_CONFIG, #endif #ifdef BSP_USING_UART3 UART3_CONFIG, #endif #ifdef BSP_USING_UART4 UART4_CONFIG, #endif #ifdef BSP_USING_UART5 UART5_CONFIG, #endif #ifdef BSP_USING_UART6 UART6_CONFIG, #endif #ifdef BSP_USING_UART7 UART7_CONFIG, #endif #ifdef BSP_USING_UART8 UART8_CONFIG, #endif #ifdef BSP_USING_UART9 UART9_CONFIG, #endif }; enum { #ifdef BSP_USING_UART0 UART0_INDEX, #endif #ifdef BSP_USING_UART1 UART1_INDEX, #endif #ifdef BSP_USING_UART2 UART2_INDEX, #endif #ifdef BSP_USING_UART3 UART3_INDEX, #endif #ifdef BSP_USING_UART4 UART4_INDEX, #endif #ifdef BSP_USING_UART5 UART5_INDEX, #endif #ifdef BSP_USING_UART6 UART6_INDEX, #endif #ifdef BSP_USING_UART7 UART7_INDEX, #endif #ifdef BSP_USING_UART8 UART8_INDEX, #endif #ifdef BSP_USING_UART9 UART9_INDEX, #endif }; static struct ra_uart uart_obj[sizeof(uart_config) / sizeof(uart_config[0])] = {0}; static void ra_uart_get_config(void) { struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; #ifdef BSP_USING_UART0 uart_obj[UART0_INDEX].serial.config = config; uart_obj[UART0_INDEX].uart_dma_flag = 0; uart_obj[UART0_INDEX].serial.config.rx_bufsz = BSP_UART0_RX_BUFSIZE; uart_obj[UART0_INDEX].serial.config.tx_bufsz = BSP_UART0_TX_BUFSIZE; #endif #ifdef BSP_USING_UART1 uart_obj[UART1_INDEX].serial.config = config; uart_obj[UART1_INDEX].uart_dma_flag = 0; uart_obj[UART1_INDEX].serial.config.rx_bufsz = BSP_UART1_RX_BUFSIZE; uart_obj[UART1_INDEX].serial.config.tx_bufsz = BSP_UART1_TX_BUFSIZE; #endif #ifdef BSP_USING_UART2 uart_obj[UART2_INDEX].serial.config = config; uart_obj[UART2_INDEX].uart_dma_flag = 0; uart_obj[UART2_INDEX].serial.config.rx_bufsz = BSP_UART2_RX_BUFSIZE; uart_obj[UART2_INDEX].serial.config.tx_bufsz = BSP_UART2_TX_BUFSIZE; #endif #ifdef BSP_USING_UART3 uart_obj[UART3_INDEX].serial.config = config; uart_obj[UART3_INDEX].uart_dma_flag = 0; uart_obj[UART3_INDEX].serial.config.rx_bufsz = BSP_UART3_RX_BUFSIZE; uart_obj[UART3_INDEX].serial.config.tx_bufsz = BSP_UART3_TX_BUFSIZE; #endif #ifdef BSP_USING_UART4 uart_obj[UART4_INDEX].serial.config = config; uart_obj[UART4_INDEX].uart_dma_flag = 0; uart_obj[UART4_INDEX].serial.config.rx_bufsz = BSP_UART4_RX_BUFSIZE; uart_obj[UART4_INDEX].serial.config.tx_bufsz = BSP_UART4_TX_BUFSIZE; #endif #ifdef BSP_USING_UART5 uart_obj[UART5_INDEX].serial.config = config; uart_obj[UART5_INDEX].uart_dma_flag = 0; uart_obj[UART5_INDEX].serial.config.rx_bufsz = BSP_UART5_RX_BUFSIZE; uart_obj[UART5_INDEX].serial.config.tx_bufsz = BSP_UART5_TX_BUFSIZE; #endif #ifdef BSP_USING_UART6 uart_obj[UART6_INDEX].serial.config = config; uart_obj[UART6_INDEX].uart_dma_flag = 0; uart_obj[UART6_INDEX].serial.config.rx_bufsz = BSP_UART6_RX_BUFSIZE; uart_obj[UART6_INDEX].serial.config.tx_bufsz = BSP_UART6_TX_BUFSIZE; #endif #ifdef BSP_USING_UART7 uart_obj[UART7_INDEX].serial.config = config; uart_obj[UART7_INDEX].uart_dma_flag = 0; uart_obj[UART7_INDEX].serial.config.rx_bufsz = BSP_UART7_RX_BUFSIZE; uart_obj[UART7_INDEX].serial.config.tx_bufsz = BSP_UART7_TX_BUFSIZE; #endif #ifdef BSP_USING_UART8 uart_obj[UART8_INDEX].serial.config = config; uart_obj[UART8_INDEX].uart_dma_flag = 0; uart_obj[UART8_INDEX].serial.config.rx_bufsz = BSP_UART8_RX_BUFSIZE; uart_obj[UART8_INDEX].serial.config.tx_bufsz = BSP_UART8_TX_BUFSIZE; #endif #ifdef BSP_USING_UART9 uart_obj[UART9_INDEX].serial.config = config; uart_obj[UART9_INDEX].uart_dma_flag = 0; uart_obj[UART9_INDEX].serial.config.rx_bufsz = BSP_UART9_RX_BUFSIZE; uart_obj[UART9_INDEX].serial.config.tx_bufsz = BSP_UART9_TX_BUFSIZE; #endif } // 对接框架层的实现代码 static const struct rt_uart_ops ra_uart_ops = { .configure = ra_uart_configure, .control = ra_uart_control, .putc = ra_uart_putc, .getc = ra_uart_getc, .transmit = ra_uart_transmit }; int rt_hw_usart_init(void) { rt_err_t result = 0; rt_size_t obj_num = sizeof(uart_obj) / sizeof(struct ra_uart); // uart object默认参数初始化 ra_uart_get_config(); for (int i = 0; i < obj_num; i++) { /* 将uart配置和uart对应的操作函数交由object维护 */ uart_obj[i].config = &uart_config[i]; uart_obj[i].serial.ops = &ra_uart_ops; /* 向系统注册uart设备 */ result = rt_hw_serial_register(&uart_obj[i].serial, uart_obj[i].config->name, RT_DEVICE_FLAG_RDWR, NULL); RT_ASSERT(result == RT_EOK); } return result; }
注册入口基本上就是照着模板的样子实现的。
uart配置入口
static rt_err_t ra_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg) { struct ra_uart *uart; RT_ASSERT(serial != RT_NULL); RT_ASSERT(cfg != RT_NULL); fsp_err_t err = FSP_SUCCESS; uart = rt_container_of(serial, struct ra_uart, serial); RT_ASSERT(uart != RT_NULL); #ifdef SOC_SERIES_R7FA8M85 err = R_SCI_B_UART_Open(uart->config->p_api_ctrl, uart->config->p_cfg); #else err = R_SCI_UART_Open(uart->config->p_api_ctrl, uart->config->p_cfg); #endif if (FSP_SUCCESS != err) { return -RT_ERROR; } return RT_EOK; }
从配置入口我们可以看出,传入的cfg参数完全没有使用到,而使用到的仅仅是rasc生成的默认配置,也就是说,瑞萨目前适配的框架并不能做到动态设置串口参数的目的,而是直接在调用configure接口时,就已经打开串口了。
uart控制入口
static rt_err_t ra_uart_control(struct rt_serial_device *serial, int cmd, void *arg) { return RT_EOK; }
同上,由于目前瑞萨所做的并不是上层应用动态配置串口参数的方法,因此控制接口也一个功能都未实现,直接返回RT_EOK,以免上层不能执行下去。
uart输出字符入口
static int ra_uart_putc(struct rt_serial_device *serial, char c) { struct ra_uart *uart; RT_ASSERT(serial != RT_NULL); uart = rt_container_of(serial, struct ra_uart, serial); RT_ASSERT(uart != RT_NULL); #ifdef SOC_SERIES_R7FA8M85 sci_b_uart_instance_ctrl_t *p_ctrl = (sci_b_uart_instance_ctrl_t *)uart->config->p_api_ctrl; #else sci_uart_instance_ctrl_t *p_ctrl = (sci_uart_instance_ctrl_t *)uart->config->p_api_ctrl; #endif p_ctrl->p_reg->TDR = c; #if defined(SOC_SERIES_R7FA8M85) || defined(SOC_SERIES_R9A07G0) while ((p_ctrl->p_reg->CSR_b.TEND) == 0); #else while ((p_ctrl->p_reg->SSR_b.TEND) == 0); #endif return RT_EOK; }
轮询发送实现,其实轮询发送实现逻辑很简单,几乎所有方案都是往某个发送寄存器放一个字节的内容,然后等待发送完成标记置位,瑞萨也是这么操作的,只是不知道为何瑞萨这部分的实现并未封装到fsp层,而是直接将寄存器操作放置在驱动适配层。
uart读取字符入口
static int ra_uart_getc(struct rt_serial_device *serial) { return RT_EOK; }
此接口在轮询模式下会使用,而瑞萨未实现具体功能,代表目前瑞萨并未适配轮询方式的RX接口t。
uart传输入口
static rt_ssize_t ra_uart_transmit(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, rt_uint32_t tx_flag) { struct ra_uart *uart; RT_ASSERT(serial != RT_NULL); RT_ASSERT(buf != RT_NULL); uart = rt_container_of(serial, struct ra_uart, serial); RT_ASSERT(uart != RT_NULL); ra_uart_control(serial, RT_DEVICE_CTRL_SET_INT, (void *)tx_flag); return size; }
确切的说,这个函数不应该叫传输函数,因为对接的瑞萨框架的接口上表明了,这个函数实际上仅仅执行了发送功能,而且这个发送还是不带发送完成回调的,这就意味着,在我们使用瑞萨目前的驱动代码时,是默认认为串口数据发送成功的。
uart中断回调处理入口
#ifdef BSP_USING_UART0 void user_uart0_callback(uart_callback_args_t *p_args) { rt_interrupt_enter(); struct rt_serial_device *serial = &uart_obj[UART0_INDEX].serial; RT_ASSERT(serial != RT_NULL); if (UART_EVENT_RX_CHAR == p_args->event) { struct rt_serial_rx_fifo *rx_fifo; rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; RT_ASSERT(rx_fifo != RT_NULL); rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data); rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); } rt_interrupt_leave(); } #endif #ifdef BSP_USING_UART1 void user_uart1_callback(uart_callback_args_t *p_args) { rt_interrupt_enter(); struct rt_serial_device *serial = &uart_obj[UART1_INDEX].serial; RT_ASSERT(serial != RT_NULL); if (UART_EVENT_RX_CHAR == p_args->event) { struct rt_serial_rx_fifo *rx_fifo; rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; RT_ASSERT(rx_fifo != RT_NULL); rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data); rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); } rt_interrupt_leave(); } #endif #ifdef BSP_USING_UART2 void user_uart2_callback(uart_callback_args_t *p_args) { rt_interrupt_enter(); struct rt_serial_device *serial = &uart_obj[UART2_INDEX].serial; RT_ASSERT(serial != RT_NULL); if (UART_EVENT_RX_CHAR == p_args->event) { struct rt_serial_rx_fifo *rx_fifo; rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; RT_ASSERT(rx_fifo != RT_NULL); rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data); rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); } rt_interrupt_leave(); } #endif #ifdef BSP_USING_UART3 void user_uart3_callback(uart_callback_args_t *p_args) { rt_interrupt_enter(); struct rt_serial_device *serial = &uart_obj[UART3_INDEX].serial; RT_ASSERT(serial != RT_NULL); if (UART_EVENT_RX_CHAR == p_args->event) { struct rt_serial_rx_fifo *rx_fifo; rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; RT_ASSERT(rx_fifo != RT_NULL); rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data); rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); } rt_interrupt_leave(); } #endif #ifdef BSP_USING_UART4 void user_uart4_callback(uart_callback_args_t *p_args) { rt_interrupt_enter(); struct rt_serial_device *serial = &uart_obj[UART4_INDEX].serial; RT_ASSERT(serial != RT_NULL); if (UART_EVENT_RX_CHAR == p_args->event) { struct rt_serial_rx_fifo *rx_fifo; rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; RT_ASSERT(rx_fifo != RT_NULL); rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data); rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); } rt_interrupt_leave(); } #endif #ifdef BSP_USING_UART5 void user_uart5_callback(uart_callback_args_t *p_args) { rt_interrupt_enter(); struct rt_serial_device *serial = &uart_obj[UART5_INDEX].serial; RT_ASSERT(serial != RT_NULL); if (UART_EVENT_RX_CHAR == p_args->event) { struct rt_serial_rx_fifo *rx_fifo; rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; RT_ASSERT(rx_fifo != RT_NULL); rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data); rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); } rt_interrupt_leave(); } #endif #ifdef BSP_USING_UART6 void user_uart6_callback(uart_callback_args_t *p_args) { rt_interrupt_enter(); struct rt_serial_device *serial = &uart_obj[UART6_INDEX].serial; RT_ASSERT(serial != RT_NULL); if (UART_EVENT_RX_CHAR == p_args->event) { struct rt_serial_rx_fifo *rx_fifo; rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; RT_ASSERT(rx_fifo != RT_NULL); rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data); rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); } rt_interrupt_leave(); } #endif #ifdef BSP_USING_UART7 void user_uart7_callback(uart_callback_args_t *p_args) { rt_interrupt_enter(); struct rt_serial_device *serial = &uart_obj[UART7_INDEX].serial; RT_ASSERT(serial != RT_NULL); if (UART_EVENT_RX_CHAR == p_args->event) { struct rt_serial_rx_fifo *rx_fifo; rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; RT_ASSERT(rx_fifo != RT_NULL); rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data); rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); } rt_interrupt_leave(); } #endif #ifdef BSP_USING_UART8 void user_uart8_callback(uart_callback_args_t *p_args) { rt_interrupt_enter(); struct rt_serial_device *serial = &uart_obj[UART8_INDEX].serial; RT_ASSERT(serial != RT_NULL); if (UART_EVENT_RX_CHAR == p_args->event) { struct rt_serial_rx_fifo *rx_fifo; rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; RT_ASSERT(rx_fifo != RT_NULL); rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data); rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); } rt_interrupt_leave(); } #endif #ifdef BSP_USING_UART9 void user_uart9_callback(uart_callback_args_t *p_args) { rt_interrupt_enter(); struct rt_serial_device *serial = &uart_obj[UART9_INDEX].serial; RT_ASSERT(serial != RT_NULL); if (UART_EVENT_RX_CHAR == p_args->event) { struct rt_serial_rx_fifo *rx_fifo; rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; RT_ASSERT(rx_fifo != RT_NULL); rt_ringbuffer_putchar(&(rx_fifo->rb), (rt_uint8_t)p_args->data); rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); } rt_interrupt_leave(); } #endif
乍一看,会觉得代码非常多,但实际上看每个宏包裹的内容,会发现,实际上实现长一个样,这么写纯粹的让人误解,还不如把实现统一写成一个宏或者一个函数来降低阅读难度。从这中断回调处理,我们可以发现,瑞萨仅仅做了接收数据的中断回调处理,而发送数据的中断回调,瑞萨并未添加,若需要,则需要自行添加。
总结
通过对瑞萨适配的V2版串口驱动的分析,我们会发现,瑞萨仅仅适配了中断方式通信的串口,如果要使用轮询或DMA方式工作,还需要自行添加对应实现(轮询方式发送接口已经实现,但未实现轮询接收),否则在驱动这一层就会走不通。
另外,目前瑞萨适配的版本,并不支持动态配置串口参数,也就是说,RASC配置的默认参数是什么,那最后使用时就是什么。