RTT serial 设备的底层硬件驱动
一、需要用到的头文件
系统头文件
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
硬件相关头文件
#include "board.h"
#include "LPC177x_8x.h"
#include "lpc177x_8x_uart.h"
#include "lpc177x_8x_pinsel.h"
二、引脚配置
因为现在大部分的CPU的引脚功能是复用的,所以这一项必不可少。这里没有使用PIN设备,而使用的宏定义。当然,这部分的功能可以不在这里实现,在应用代码里通过PIN设备来配置。不过个人感觉没有必要。
#define pinConnectToTxduart0() PINSEL_ConfigPin(0, 2, 1)
#define pinConnectToRxduart0() PINSEL_ConfigPin(0, 3, 1)
...
#define pinConnectToTxduart4() PINSEL_ConfigPin(5, 4, 4)
#define pinConnectToRxduart4() PINSEL_ConfigPin(5, 3, 4)
#define configTxdPin(__num) pinConnectToTxd##__num()
#define configRxdPin(__num) pinConnectToRxd##__num()
用法如下:
configTxdPin(uart0);
configRxdPin(uart0);
三、串口配置
这个结构体和各个芯片供应商提供的驱动有关,也可以自己写。
typedef struct {
uint32_t Baud_rate; /**< UART baud rate */
UART_PARITY_Type Parity; /**< Parity selection, should be:
- UART_PARITY_NONE: No parity
- UART_PARITY_ODD: Odd parity
- UART_PARITY_EVEN: Even parity
- UART_PARITY_SP_1: Forced "1" stick parity
- UART_PARITY_SP_0: Forced "0" stick parity
*/
UART_DATABIT_Type Databits; /**< Number of data bits, should be:
- UART_DATABIT_5: UART 5 bit data mode
- UART_DATABIT_6: UART 6 bit data mode
- UART_DATABIT_7: UART 7 bit data mode
- UART_DATABIT_8: UART 8 bit data mode
*/
UART_STOPBIT_Type Stopbits; /**< Number of stop bits, should be:
- UART_STOPBIT_1: UART 1 Stop Bits Select
- UART_STOPBIT_2: UART 2 Stop Bits Select
*/
} UART_CFG_Type;
和芯片寄存器相关的用户自定义配置。用于指示当前对象所操作的目标硬件。
struct rt_uart_lpc
{
LPC_UART_TypeDef * UART;
IRQn_Type irq;
UART_CFG_Type UART_ConfigStruct;
};
定义操作对象:
以下是驱动需要知道的内容,用户不关心。
struct rt_uart_lpc lpc_uart0 =
{
.UART = LPC_UART0,
.irq = UART0_IRQn,
};
struct rt_serial_device uart0_device =
{
.ops = &uart_ops,
};
四、serial中需要的串口ops
static void uart_isr(struct rt_serial_device *serial) ;
rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg);
static rt_err_t uart_control (struct rt_serial_device *serial, int cmd, void *arg);
static int uart_putc (struct rt_serial_device *serial, char c);
static int uart_getc (struct rt_serial_device *serial);
rt_size_t uart_dma_transmit (struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction);
const struct rt_uart_ops uart_ops =
{
uart_configure,
uart_control,
uart_putc,
uart_getc,
uart_dma_transmit,
};
下面关注以上几个函数如何实现。
中断函数入口
void UART0_IRQHandler(void)
{
/* enter interrupt */
rt_interrupt_enter();
uart_isr(&uart0_device);
/* leave interrupt */
rt_interrupt_leave();
}
串口中断使用的公共函数
static void uart_isr(struct rt_serial_device *serial)
{
struct rt_uart_lpc *uart = (struct rt_uart_lpc *) serial->parent.user_data;
uint32_t iir;
RT_ASSERT(uart != RT_NULL);
iir = UART_GetIntId(uart->UART);
switch ( iir & 0x0E)
{
case UART_IIR_INTID_RDA:
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
break;
case UART_IIR_INTID_RLS:
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
break;
case UART_IIR_INTID_THRE:
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_TX_DONE);
break;
}
}
配置串口参数。
rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
struct rt_uart_lpc *lpc_uart;
RT_ASSERT(serial != RT_NULL);
RT_ASSERT(cfg != RT_NULL);
lpc_uart = (struct rt_uart_lpc *)serial->parent.user_data;
lpc_uart->UART_ConfigStruct = default_uart_cfg;
lpc_uart->UART_ConfigStruct.Baud_rate = cfg->baud_rate;
switch (cfg->data_bits)
{
case DATA_BITS_5:
lpc_uart->UART_ConfigStruct.Databits = UART_DATABIT_5;
break;
case DATA_BITS_6:
lpc_uart->UART_ConfigStruct.Databits = UART_DATABIT_6;
break;
case DATA_BITS_7:
lpc_uart->UART_ConfigStruct.Databits = UART_DATABIT_7;
break;
case DATA_BITS_8:
default:
lpc_uart->UART_ConfigStruct.Databits = UART_DATABIT_8;
break;
}
switch (cfg->stop_bits)
{
case STOP_BITS_1:
lpc_uart->UART_ConfigStruct.Stopbits = UART_STOPBIT_1;
break;
case STOP_BITS_2:
lpc_uart->UART_ConfigStruct.Stopbits = UART_STOPBIT_2;
break;
default:
lpc_uart->UART_ConfigStruct.Stopbits = UART_STOPBIT_1;
break;
}
switch (cfg->parity)
{
case PARITY_NONE:
lpc_uart->UART_ConfigStruct.Parity = UART_PARITY_NONE;
break;
case PARITY_ODD:
lpc_uart->UART_ConfigStruct.Parity = UART_PARITY_ODD;
break;
case PARITY_EVEN:
lpc_uart->UART_ConfigStruct.Parity = UART_PARITY_EVEN;
break;
default:
lpc_uart->UART_ConfigStruct.Parity = UART_PARITY_NONE;
break;
}
//if (HAL_UART_Init(&uart->UartHandle) != HAL_OK)
UART_Init(lpc_uart->UART, &lpc_uart->UART_ConfigStruct);
UART_TxCmd (lpc_uart->UART, ENABLE);
return RT_EOK;
}
控制串口收发模式:
static rt_err_t uart_control (struct rt_serial_device *serial, int cmd, void *arg)
{
struct rt_uart_lpc *uart;
RT_ASSERT(serial != RT_NULL);
uart = (struct rt_uart_lpc *)serial->parent.user_data;
switch (cmd)
{
case RT_DEVICE_CTRL_CLR_INT:
NVIC_DisableIRQ( uart->irq );
UART_IntConfig( uart->UART, UART_INTCFG_THRE, DISABLE);
UART_IntConfig( uart->UART, UART_INTCFG_RBR, DISABLE);
break;
case RT_SERIAL_RX_INT:
/* enable rx irq */
NVIC_EnableIRQ(uart->irq);
/* enable interrupt */
UART_IntConfig( uart->UART, UART_INTCFG_RBR, ENABLE);
break;
case RT_SERIAL_TX_INT:
/* enable rx irq */
NVIC_EnableIRQ(uart->irq);
/* enable interrupt */
UART_IntConfig( uart->UART, UART_INTCFG_THRE, ENABLE);
break;
case RT_DEVICE_CTRL_SET_INT:
/* enable rx irq */
NVIC_EnableIRQ(uart->irq);
/* enable interrupt */
UART_IntConfig( uart->UART, UART_INTCFG_RBR, ENABLE);
break;
case RT_DEVICE_CTRL_GET_INT:
break;
}
return RT_EOK;
}
发送一个字节数据
static int uart_putc (struct rt_serial_device *serial, char c)
{
struct rt_uart_lpc *uart;
RT_ASSERT(serial != RT_NULL);
uart = (struct rt_uart_lpc *)serial->parent.user_data;
while (!(uart->UART->LSR & UART_LSR_THRE));
UART_SendByte( uart->UART,c);
}
接收一个字节数据
static int uart_getc (struct rt_serial_device *serial)
{
struct rt_uart_lpc *uart;
RT_ASSERT(serial != RT_NULL);
uart = (struct rt_uart_lpc *)serial->parent.user_data;
if (!(uart->UART->LSR & UART_LSR_RDR)) return -1;
return uart->UART->RBR;
}
串口注册
void rt_hw_uart_init(void)
{
struct serial_configure cfg ;
cfg.baud_rate = boundRateUart0;
cfg.bit_order = BIT_ORDER_LSB;
cfg.bufsz = 32;
cfg.data_bits = DATA_BITS_8;
cfg.invert = NRZ_NORMAL;
cfg.parity = PARITY_NONE;
cfg.stop_bits = STOP_BITS_1;
#ifdef RT_USING_UART0
configTxdPin(uart0);
configRxdPin(uart0);
cfg.baud_rate = boundRateUart0;
uart0_device.config = cfg;
rt_hw_serial_register(&uart0_device,
"uart0",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
&lpc_uart0);
uart_configure (&uart0_device, &cfg); //注册的时候配置的目的是图省事儿,不改变rt_hw_board_init()函数的顺序及代码的同时不影响shell的使用
#endif
}
参考了stm32f429-disco相关部分代码的编写