uart串口的驱动分为,transmit发送、receive接收两部分,transmit比较简单,而receive需要中断触发,相对比较麻烦一些。前期为了方便调试可以使用一个简单的字符打印函数,查看程序运行情况。
默认情况下鸿蒙使用的串口驱动是这个文件,kernel\liteos_a\platform\uart\amba_pl011\amba_pl011.c
而uart的驱动文件在kernel\liteos_a\platform\bsp.mk进行了设置,这段代码也是之前添加单板时添加的。
########################## LOSCFG_PLATFORM_RASPBERRYPI2B Options##############################
else ifeq ($(LOSCFG_PLATFORM_RASPBERRYPI2B), y)
HWI_TYPE := arm/interrupt/gic
TIMER_TYPE := arm/timer/arm_generic
HRTIMER_TYPE := BCM2836/hrtimer
#UART_TYPE := amba_pl011
endif
由于注释掉了默认的串口驱动,所以在vender文件夹里需要提供串口的驱动程序。
2.1、为了方便调试,先设置一个字符打印函数
kernel\liteos_a\platform\uart\amba_pl011\amba_pl011.c在46行左右处添加下面的代码,uart_putc_phy使用物理地址打印字符,uart_putc_virt使用虚拟地址打印。当内核代码启动MMU之后,需用使用uart_putc_virt来打印字符。
/*---------自定义函数----------*/
#define RPI_BASE_UART_REGISTER (0x3f201000) //HI3516:0x120A0000 rpi2b:0x3F201000
#define AMBA_UART_DR (*(volatile unsigned char *)(RPI_BASE_UART_REGISTER + 0x00))
#define AMBA_UART_FR (*(volatile unsigned char *)(RPI_BASE_UART_REGISTER + 0x18))
#define RPI_BASE_UART_REGISTER1 IO_DEVICE_ADDR(0x3F201000) //HI3516:0x120A0000 rpi2b:0x3F201000
#define AMBA_UART_DR1 (*(volatile unsigned char *)(RPI_BASE_UART_REGISTER1 + 0x00))
#define AMBA_UART_FR1 (*(volatile unsigned char *)(RPI_BASE_UART_REGISTER1 + 0x18))
/*---------------------------*/
void uart_putc_phy(unsigned char c)
{
//UART_Type *uartRegs = (UART_Type *)UART4_REG_PBASE;
//while ((uartRegs->USART_ISR & (1<<5)) == 0);
//uartRegs->USART_TDR = c;
while (AMBA_UART_FR & (1 << 5));
AMBA_UART_DR = c;
}
void uart_putc_virt(unsigned char c)
{
//UART_Type *uartRegs = (UART_Type *)UART_REG_BASE;
//while ((uartRegs->USART_ISR & (1<<5)) == 0);
//uartRegs->USART_TDR = c;
while (AMBA_UART_FR1 & (1 << 5));
AMBA_UART_DR1 = c;
}
例如:kernel\liteos_a\arch\arm\arm\src\startup\reset_vector_up.S
ldr sp, =0x00000000 + 0x5000000 //调用C函数前,得先设置栈,树莓派物理内存从0x0开始
mov r0, #'m'
bl uart_putc_phy //在MMU启动之前使用的是物理地址打印
bl mmu_setup /* set up the mmu */
mov r0, #'M'
bl uart_putc_virt //在MMU启动之后使用的是虚拟地址打印
2.2、添加串口中断,串口输入代码
vendor\broadcom\BCM2836\driver\uart\uart_hardware.c
2.2.1、 串口的中断函数,产生中断时,这个函数调用
static irqreturn_t BCM2836_uart_irq(int irq, void *data)
{
char buf[FIFO_SIZE];
unsigned int count = 0;
struct BCM2836_port *port = NULL;
struct uart_driver_data *udd = (struct uart_driver_data *)data;
UART_Type *uartRegs;
uint32_t status;
if (udd == NULL) {
uart_error("udd is null!\n");
return IRQ_HANDLED;
}
port = (struct BCM2836_port *)udd->private;
uartRegs = (UART_Type *)port->phys_base;
READ_UINT32(status, UART_REG_BASE + UART_FR);
if ((UARTREG(UART_REG_BASE,UART_FR)&(1<<4)) == 0) {
do {
buf[count++] = UARTREG(UART_REG_BASE,UART_DR);//*(volatile UINT32 *)((UINTPTR)(UART_REG_BASE + UART_DR)); //去读取硬件得到数据
if (udd->num != CONSOLE_UART) {
continue;
}
if (CheckMagicKey(buf[count - 1])) { //数据放在buf里
goto end;
}
if (buf[count-1] == '\r') //对windows和liteos回车换行的处理
buf[count-1] = '\n';
} while ((UARTREG(UART_REG_BASE,UART_FR)&(1<<4)) == 0);
udd->recv(udd, buf, count); //调用udd里的recv函数把数据发送给上一级
}
UARTREG(UART_REG_BASE, UART_ICR) = 0x3ff;
end:
/* clear all interrupt */
return 0;
}
2.2.2、串口的初始化函数
static int BCM2836_startup(struct uart_driver_data *udd)
{
int ret = 0;
struct BCM2836_port *port = NULL;
if (udd == NULL) {
uart_error("udd is null!\n");
return -EFAULT;
}
port = (struct BCM2836_port *)udd->private;//*private是一个指针,指向 struct {enable,phys_base,irq_num,*udd}
if (!port) {
uart_error("port is null!");
return -EFAULT;
}
/* enable the clock */
LOS_TaskLock();
LOS_TaskUnlock();
ret = request_irq(port->irq_num, (irq_handler_t)BCM2836_uart_irq,0, "uart_dw", udd); //去注册一个串口的接收中断函数
/* 1.uart interrupt priority should be the highest in interrupt preemption mode */
//ret = LOS_HwiCreate(NUM_HAL_INTERRUPT_UART, 0, 0, (HWI_PROC_FUNC)uart_handler, NULL);
/* 2.clear all irqs */
UARTREG(UART_REG_BASE, UART_ICR) = 0x3ff;
//*(volatile UINT32 *)((UINTPTR)IO_DEVICE_ADDR(0x3F201044)) = 0x3ff;
/* disable FIFO mode */
//uartRegs->USART_CR1 &= ~(1<<29);
//*(volatile UINT32 *)((UINTPTR)IO_DEVICE_ADDR(0x3F20102C)) = 0x60;
UARTREG(UART_REG_BASE, UART_LCR_H) = (1 << 6 | 1 << 5| 1 << 4);
/* 3.set fifo trigger level */
//*(volatile UINT32 *)((UINTPTR)IO_DEVICE_ADDR(0x3F201034)) = 0x0;
UARTREG(UART_REG_BASE, UART_IFLS) = 0;
/* 4.enable rx interrupt 开启串口接收中断,第4位*/
UARTREG(UART_REG_BASE, UART_IMSC) = (1 << 4 | 1 << 6); //*(volatile UINT32 *)((UINTPTR)IO_DEVICE_ADDR(0x3F201038)) = 0x10;
/* 5.enable receive */
UARTREG(UART_REG_BASE, UART_CR) |= (1 << 9); //*(volatile UINT32 *)((UINTPTR)IO_DEVICE_ADDR(0x3F201030)) = 0x301;
//HalIrqUnmask(NUM_HAL_INTERRUPT_UART);//6.
*(volatile UINT32 *)((UINTPTR)IO_DEVICE_ADDR(0x3F00B214)) = 0x02000000;//Unmask接收25号中断
BCM2836_config_in(udd);
return ret;
}
2.2.3、串口写函数
static int BCM2836_start_tx(struct uart_driver_data *udd, const char *buf, size_t count)
{
unsigned int tx_len = count;
struct BCM2836_port *port = NULL;
char value;
unsigned int i;
int ret = 0;
if (udd == NULL) {
uart_error("udd is null!\n");
return -EFAULT;
}
port = (struct BCM2836_port *)udd->private;
if (!port) {
uart_error("port is null!");
return -EFAULT;
}
/* UART_WITH_LOCK: there is a spinlock in the function to write reg in order. */
for (i = 0; i < tx_len; i++ ){
ret = LOS_CopyToKernel((void *)&value, sizeof(char),(void *)(buf++), sizeof(char));
if (ret) {
return i;
}
(void)UartPutsReg(port->phys_base, &value, 1, UART_WITH_LOCK);
}
return count;
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。