串口驱动学习
0.串口驱动的使用方法
//定义一个时间
struct rt_event system_event;
#define SYS_EVENT_UART_RX_FINISH 0x00000001 /* UART receive data finish event *//*串口接收回调函数 Receive data callback function */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{//有数据到来,通知读取数据rt_event_send(&system_event, SYS_EVENT_UART_RX_FINISH);return RT_EOK;
}static void test1_thread_entry(void* parameter)
{rt_device_t uart_dev;uint8_t data[30] = {0};uint8_t data1[30] = {0};uint16_t i = 0;uint16_t data_length = 0;rt_uint32_t sys_event_recv = 0;rt_err_t result = rt_event_init(&system_event, "event", RT_IPC_FLAG_FIFO);//查找设备uart_dev = rt_device_find("usart3");//打开设备rt_device_open(uart_dev, RT_DEVICE_FLAG_INT_RX);//打开接收/* 注册一个数据接收回调函数*/rt_device_set_rx_indicate(uart_dev, uart_input);for(i=0;i<sizeof(data);i++){data[i]=i+1;}if(RT_EOK == rt_device_open(uart_dev, RT_DEVICE_FLAG_INT_RX))//打开中断{//串口发送数据rt_device_write(uart_dev, RT_NULL, data, sizeof(data)); }while(1){rt_thread_delay(50);/* 等待数据到来事件 */if(RT_EOK == rt_event_recv(&system_event, SYS_EVENT_UART_RX_FINISH, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 10, &sys_event_recv)){data_length = rt_device_read(uart_dev, RT_NULL, data1, RT_SERIAL_RB_BUFSZ);rt_device_write(uart_dev, RT_NULL, data1, data_length); } }
}
串口驱动抽象层
1.串口配置
struct serial_configure
{rt_uint32_t baud_rate;rt_uint32_t data_bits :4;rt_uint32_t stop_bits :2;rt_uint32_t parity :2;rt_uint32_t hardwareflow_control :2;rt_uint32_t mode :2;rt_uint32_t bufsz :16;rt_uint32_t reserved :6;
};
2.串口抽象操作
/*** uart operators*/
struct rt_uart_ops
{ //配置函数rt_err_t (*configure)(struct rt_serial_device *serial, struct serial_configure *cfg);//控制函数rt_err_t (*control)(struct rt_serial_device *serial, int cmd, void *arg);//发送一个字符int (*putc)(struct rt_serial_device *serial, char c);//接收一个字符int (*getc)(struct rt_serial_device *serial);//dma数据发送rt_size_t (*dma_transmit)(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction);
};
3.串口驱动抽象
struct rt_serial_device
{struct rt_device parent;//RTT设备驱动抽象const struct rt_uart_ops *ops;//串口抽象层操作函数struct serial_configure config;//串口配置void *serial_rx;void *serial_tx;
};
typedef struct rt_serial_device rt_serial_t;
串口驱动硬件层
这个结构体封装N32L40x相关的串口硬件参数
struct n32l40x_uart
{USART_Module* uart_periph; // Todo: 3bits串口号IRQn_Type irqn; // Todo: 7bits 串口中断号 uint32_t per_clk; // Todo: 5bits串口时钟uint32_t tx_gpio_clk; // Todo: 5bits发送引脚时钟uint32_t rx_gpio_clk; // Todo: 5bits接收引脚时钟GPIO_Module* tx_port; // Todo: 4bits发送引脚分gpio分组uint32_t tx_af; // Todo: 4bits发送引脚的复用uint16_t tx_pin; // Todo: 4bits发送引脚pinGPIO_Module* rx_port; // Todo: 4bits接收引脚分gpio分组uint32_t rx_af; // Todo: 4bits接收引脚的复用uint16_t rx_pin; // Todo: 4bits接收引脚pinstruct rt_serial_device * serial; //串口驱动抽象父类char *device_name; //串口名字
};
分析已经有的串口设备驱动程序
- 定义一个串口配置函数
- 定义一个串口控制函数
- 定义一个串口的单字符发送函数
- 定义一个串口的单字符接收函数
- 定义一个统一的串口中断处理函数
- 在同一的串口处理函数内部,清楚中断标志后,调用父类的中断处理函数 rt_hw_serial_isr
- 定义一个struct rt_uart_ops 对象分别赋值内部的,configure,control,putc,getc,dma_transmit(dma发送非必须)
- 注册串口设备对象 rt_hw_serial_register
如何自己添加或更改一个串口设备
文件在drv_usart.c 文件中修改