当前位置:网站首页>【RT-Thread】nxp rt10xx 设备驱动框架之--uart搭建和使用
【RT-Thread】nxp rt10xx 设备驱动框架之--uart搭建和使用
2022-07-16 03:18:00 【L_17】
UART全称:Universal Asynchronous Receiver-Transmitter, 通用异步收发器。与IIC、SPI 等接口一样,都属于串行通信接口,但是UART只有数据线收和发,无时钟线,故为异步串行通信接口,可以实现全双工通信;在嵌入式系统中,常用与控制系统与外设通信,包括控制器与控制器,控制器与终端设备。线路简单,成本低,传输距离远,但传输速度慢。需要深入了解,网上资料很多,本章不做扩展。
开发前准备
- 硬件平台:nxp rt10xx单片机
- IDE: Keil
1.Kconfig 修改和menuconfig配置
在Env环境menuconfig中 RT-Thread Components->Device Drivers 设备驱动默认为y,毕竟最常用的外设之一,在RT-Thread系统中会用到MSH所以,基本都会用到串口。

先在Kconfig中添加如下语句,然后在Env环境menuconfig中 Hardware Drivers Config->On-Chip Peripheral Drivers 使能UART,本章使用UART1/2 其中,UART1用于MSH,UART2 为本章测试内容。

MSH 配置如下:
/* 开启 FinSH */
#define RT_USING_FINSH
/* 将线程名称定义为 tshell */
#define FINSH_THREAD_NAME "tshell"
/* 开启历史命令 */
#define FINSH_USING_HISTORY
/* 记录 5 行历史命令 */
#define FINSH_HISTORY_LINES 5
/* 开启使用 Tab 键 */
#define FINSH_USING_SYMTAB
/* 开启描述功能 */
#define FINSH_USING_DESCRIPTION
/* 定义 FinSH 线程优先级为 20 */
#define FINSH_THREAD_PRIORITY 20
/* 定义 FinSH 线程的栈大小为 4KB */
#define FINSH_THREAD_STACK_SIZE 4096
/* 定义命令字符长度为 80 字节 */
#define FINSH_CMD_SIZE 80
/* 开启 msh 功能 */
#define FINSH_USING_MSH
/* 默认使用 msh 功能 */
#define FINSH_USING_MSH_DEFAULT
/* 最大输入参数数量为 10 个 */
#define FINSH_ARG_MAX 10

2.工程添加UART驱动框架和BSP驱动接口
设备驱动框架:serial.c BSP接口:drv_uart.c fsl_lpuart.c

3.添加或修改drv_uart.c
串口设备驱动基本是不用改动的,因为上rt-thread系统必定会用到,不过设备驱动底层还是需要了解的
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 bit_order :1;
rt_uint32_t invert :1;
rt_uint32_t bufsz :16;
rt_uint32_t flowcontrol :1;
rt_uint32_t reserved :5;
};
/** * 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);
rt_size_t (*dma_transmit)(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction);
};
struct rt_serial_device
{
struct rt_device parent;
const struct rt_uart_ops *ops;
struct serial_configure config;
void *serial_rx;
void *serial_tx;
};
int rt_hw_uart_init(void)
{
int i;
rt_uint32_t flag;
rt_err_t ret = RT_EOK;
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
flag = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX;
uart_get_dma_config();
for (i = 0; i < sizeof(uarts) / sizeof(uarts[0]); i++)
{
uarts[i].serial.ops = &imxrt_uart_ops;
uarts[i].serial.config = config;
ret = rt_hw_serial_register(&uarts[i].serial, uarts[i].name, flag | uarts[i].dma_flag, NULL);
}
return ret;
}
INIT_BOARD_EXPORT(rt_hw_uart_init);
uint32_t GetUartSrcFreq(void)
{
uint32_t freq;
/* To make it simple, we assume default PLL and divider settings, and the only variable from application is use PLL3 source or OSC source */
if (CLOCK_GetMux(kCLOCK_UartMux) == 0) /* PLL3 div6 80M */
{
freq = (CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 6U) / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
}
else
{
freq = CLOCK_GetOscFreq() / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
}
return freq;
}
static rt_err_t imxrt_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
struct imxrt_uart *uart;
lpuart_config_t config;
RT_ASSERT(serial != RT_NULL);
RT_ASSERT(cfg != RT_NULL);
uart = rt_container_of(serial, struct imxrt_uart, serial);
LPUART_GetDefaultConfig(&config);
config.baudRate_Bps = cfg->baud_rate;
switch (cfg->data_bits)
{
case DATA_BITS_7:
config.dataBitsCount = kLPUART_SevenDataBits;
break;
default:
config.dataBitsCount = kLPUART_EightDataBits;
break;
}
switch (cfg->stop_bits)
{
case STOP_BITS_2:
config.stopBitCount = kLPUART_TwoStopBit;
break;
default:
config.stopBitCount = kLPUART_OneStopBit;
break;
}
switch (cfg->parity)
{
case PARITY_ODD:
config.parityMode = kLPUART_ParityOdd;
break;
case PARITY_EVEN:
config.parityMode = kLPUART_ParityEven;
break;
default:
config.parityMode = kLPUART_ParityDisabled;
break;
}
config.enableTx = true;
config.enableRx = true;
LPUART_Init(uart->uart_base, &config, GetUartSrcFreq());
return RT_EOK;
}
static rt_err_t imxrt_control(struct rt_serial_device *serial, int cmd, void *arg)
{
struct imxrt_uart *uart;
RT_ASSERT(serial != RT_NULL);
uart = rt_container_of(serial, struct imxrt_uart, serial);
#if defined(RT_SERIAL_USING_DMA) && defined(BSP_USING_DMA)
rt_ubase_t ctrl_arg = (rt_ubase_t)arg;
#endif
switch (cmd)
{
case RT_DEVICE_CTRL_CLR_INT:
DisableIRQ(uart->irqn);
break;
case RT_DEVICE_CTRL_SET_INT:
LPUART_EnableInterrupts(uart->uart_base, kLPUART_RxDataRegFullInterruptEnable);
NVIC_SetPriority(uart->irqn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 4, 0));
EnableIRQ(uart->irqn);
break;
#if defined(RT_SERIAL_USING_DMA) && defined(BSP_USING_DMA)
case RT_DEVICE_CTRL_CONFIG:
if (RT_DEVICE_FLAG_DMA_RX == ctrl_arg)
{
imxrt_dma_rx_config(uart);
}
else if (RT_DEVICE_FLAG_DMA_TX == ctrl_arg)
{
imxrt_dma_tx_config(uart);
}
break;
#endif
}
return RT_EOK;
}
static int imxrt_putc(struct rt_serial_device *serial, char ch)
{
struct imxrt_uart *uart;
RT_ASSERT(serial != RT_NULL);
uart = rt_container_of(serial, struct imxrt_uart, serial);
LPUART_WriteByte(uart->uart_base, ch);
while (!(LPUART_GetStatusFlags(uart->uart_base) & kLPUART_TxDataRegEmptyFlag));
return 1;
}
static int imxrt_getc(struct rt_serial_device *serial)
{
int ch;
struct imxrt_uart *uart;
RT_ASSERT(serial != RT_NULL);
uart = rt_container_of(serial, struct imxrt_uart, serial);
ch = -1;
if (LPUART_GetStatusFlags(uart->uart_base) & kLPUART_RxDataRegFullFlag)
{
ch = LPUART_ReadByte(uart->uart_base);
}
return ch;
}
4.搭建应用层demo
底层IO初始化,本章初始化UART1和UART2
#ifdef BSP_USING_LPUART1
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_12_LPUART1_TX, 0U);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_13_LPUART1_RX, 0U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_12_LPUART1_TX, 0x10B0U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_13_LPUART1_RX, 0x10B0U);
#endif
#ifdef BSP_USING_LPUART2
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_02_LPUART2_TX, 0U);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_03_LPUART2_RX, 0U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_02_LPUART2_TX, 0x10B0u);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_03_LPUART2_RX, 0x10B0u);
#endif
串口默认基础配置,详见serial.h
/* Default config for serial_configure structure */
#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 */ \ RT_SERIAL_FLOWCONTROL_NONE, /* Off flowcontrol */ \ 0 \ }
/**************************************************START OF FILE*****************************************************/
/*------------------------------------------------------------------------------------------------------------------ Includes */
#include <rtthread.h>
#include <rtdevice.h>
//#include "serial.h"
/*------------------------------------------------------------------------------------------------------------------ Macros */
#define SAMPLE_UART_NAME "uart2" /* 串口设备名称 */
/*------------------------------------------------------------------------------------------------------------------ Variables */
static rt_device_t serial; /* 串口设备句柄 */
struct serial_configure uart2config = RT_SERIAL_CONFIG_DEFAULT; /* 初始化配置参数 */
char sendStr[] = "hello uart2!\r\n";
/*------------------------------------------------------------------------------------------------------------------ Functions */
void uart_sample(void)
{
/* step1:查找串口设备 */
serial = rt_device_find(SAMPLE_UART_NAME);
/* step2:修改串口配置参数 */
uart2config.data_bits = DATA_BITS_8; //数据位 8
uart2config.stop_bits = STOP_BITS_1; //停止位 1
uart2config.bufsz = 128; //修改缓冲区 buff size 为 128
uart2config.parity = PARITY_NONE; //无奇偶校验位
/* step3:控制串口设备。通过控制接口传入命令控制字,与控制参数 */
rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &uart2config);
/* step4:打开串口设备。以中断接收及轮询发送模式打开串口设备 */
rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
/* 发送字符串 */
rt_device_write(serial, 0, sendStr, (sizeof(sendStr) - 1)); //uart2 发送参数
rt_kprintf("hello uart1!\n");
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(uart_sample, uart sample);
/****************************************************END OF FILE*****************************************************/
将两个串口外接到终端上(笔者使用的是MobaXterm,极力推荐这个多功能终端神器),打开两个窗口。复位MCU,输入uart_sample,在两个窗口上将分别看到:hello uart1 和 hello uart2


边栏推荐
- Share the operation steps of postman connecting to MySQL database from the beginning of installation
- IO Language Guide
- hcip动态路由实验(RIP)
- viewpager冲突解决
- [swoole series 2.4] websocket service
- List of ICP license application process in 2022
- 东方甄选爆火背后的流量密码
- Dongfang selects the traffic password behind the explosion
- 花生壳内网穿透实践指南
- IIC read / write EEPROM
猜你喜欢

03_案例搭建【RestTemplate 调用微服务】

今日份工作感悟

Comment systématiser gratuitement l'introduction à la science des données?

ReversingKr-wp(4)

解决pycharm无法输入中文的方法:

The development of digital collection system helps enterprises' meta universe scene marketing

Radio and television 5g officially entered the arena: there is no four nation scuffle, but a two-line confrontation

Network protocol -- concept and function analysis of seven layer, five layer and four layer protocols

Reduce debugging costs by 50%. Xiaojiang IOT pushes a remote serial port debugging assistant

hcip第六天笔记
随机推荐
hcip第五天笔记
论文阅读:U-Net: Convolutional Networks for Biomedical Image Segmentation
Hcip day 6 notes
Golang empty interface
Word -- set tab width
金仓数据库 KingbaseES SQL 语言参考手册 (3.1.1.9. 网络地址类型)
JS small effect jump according to the corresponding item name
SSH Remote port forwarding
Use of resttemplate
iptables 端口转发
[golang | GRC] GRC bidirectional streaming two-way flow practice
【HBZ分享】TCP协议讲解
Google Earth Engine APP(GEE)—加载一个可查询的Spector
This week's investment and finance report: many venture capital institutions have completed fund-raising, and Web3.0 track continues to attract money
One side is Wangwang's childlike innocence, and the other is an energy drink that can't be put down
金仓数据库 KingbaseES SQL 语言参考手册 (3.1.1.13. JSON 类型)
一个优秀的智慧展厅应该具备哪些能力
示波器的带宽介绍
ReversingKr-wp(4)
Outil de transfert de port rinetd