瑞萨其实两版串口驱动都已经适配了,但是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配置的默认参数是什么,那最后使用时就是什么。
我要赚赏金
