41 Star 204 Fork 53

张明亮 / harmony-raspberry

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
2.3、串口分析移植.md 6.51 KB
一键复制 编辑 原始数据 按行查看 历史
张明亮 提交于 2021-01-25 11:27 . _

1、鸿蒙串口驱动

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;
}
1
https://gitee.com/liangzili/harmony-raspberry.git
git@gitee.com:liangzili/harmony-raspberry.git
liangzili
harmony-raspberry
harmony-raspberry
master

搜索帮助