当前位置: 首页 > 科技观察

鸿蒙移植RaspberryPi(下)修改源码

时间:2023-03-23 11:44:29 科技观察

更多内容请访问:https://harmonyos.51cto.com/#zz与华为官方共建的鸿蒙技术社区最新更新,你可以查看代码仓库https://gitee.com/liangzili/harmony-raspberry1,切换启动方式树莓派默认以HYP模式启动,我们需要在内核启动前改为SVC模式kernel\liteos_a\arch\arm\arm\src\startup\reset_vector_up.S在第115行附近,reset_vector:在mrsr0,cpsr下面添加//读取CPU模式寄存器bicr0,r0,#0x1F//清除CPU模式位(如果处于催眠模式,则为1A)keepallothersorrr0,r0,#0x13//将CPU_MODE设置为SVC_MODE(0x13),而ORR仍保留所有其他位msrsspsr_cxsf,r0//将其写入spsr_cxsf寄存器,以便在调用开关时加载它。addr0,pc,#4//计算从pc进入SVC_MODE的地址(下面两个操作码很长)msrELR_hyp,r0//将地址值写入ELR_hyp寄存器eret//执行回车指令2、修改串口驱动2.1。为了调试方便,先设置一个字符打印函数kernel\liteos_a\platform\uart\amba_pl011\amba_pl011.c,在第46行左右添加如下代码,uart_putc_phy使用物理地址打印字符,uart_putc_virt使用虚拟地址打印.内核代码启动MMU后,需要使用uart_putc_virt打印字符。/*--------自定义义数----------*/#defineRPI_BASE_UART_REGISTER(0x3f201000)//HI3516:0x120A0000rpi2:0x3F201000#defineAMBA_UART_DR(*(volatile+unsignedchar*)(RPI_REBASE_UART_UART_REGISTER(0x3f201000)))#defineAMBA_UART_FR(*(volatileunsignedchar*)(RPI_BASE_UART_REGISTER+0x18))?#defineRPI_BASE_UART_REGISTER1IO_DEVICE_ADDR(0x3F201000)//HI3516:0x120A0000rpi2:0x3F201000#defineAMBA_UART_DR1(*(volatileunsignedchar*)(RPI_BASE_UART_REGISTER1+0x00))#defineAMBA_UART_FR1(*(volatileunsignedchar*)(RPI_BASE_UART_REGISTER1+0x18))/*----------------------------*/voiduart_putc_phy(unsignedcharc){//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;}voiduart_putc_virt(unsignedcharc){//UART_Type*uartRegs=(UART_Type*)UART_REG_BASE;//while((uartRegs->USART_ISR&(1<<5))==0);//uartRegs->USART_TDR=c;而(AMBA_UART_FR1&(1<<5));AMBA_UART_DR1=c;}例如:kernel\liteos_a\arch\arm\arm\src\startup\reset_vector_up.Sldrsp,=0x00000000+0x5000000//调用C函数前,必须先设置栈,树莓派物理内存从0x0开始movr0,#'m'bluart_putc_phy//在MMU启动前使用物理地址打印blmmu_setup/*setupthemmu*/movr0,#'M'bluart_putc_virt//在MMU启动后使用虚拟地址打印2.2,增加串口中断,串口输入代码vendor\broadcom\BCM2836\driver\uart\uart_hardware.c2.2.1,串口中断函数,当中断发生时,该函数调用staticirqreturn_tBCM2836_uart_irq(intirq,void*data){charbuf[FIFO_SIZE];unsignedintcount=0;structBCM2836_port*port=NULL;structuart_driver_data*udd=(structuart_driver_data*)data;UART_Type*uartRegs;uint32_tstatus;if(udd==NULL){uart_error("uddisnull!\n");returnIRQ_HANDLED;}port=(structBCM2836_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);//*(volatileUINT32*)((UINTPTR)(UART_REG_BASE+UART_DR));//读取硬件获取数据if(udd->num!=CONSOLE_UART){continue;}if(CheckMagicKey(buf[count-1])){//数据放在buf中gotoend;}if(buf[count-1]=='\r')//回车换行的处理在windows和liteos中buf[count-1]='\n';}while(UARTREG(UART_REG_BASE,UART_DR));udd->recv(udd,buf,count);//调用udd中的recv函数发送}UARTREG(UART_REG_BASE,UART_ICR)=0x3ff;end:/*clearallinterrupt*/return0;}2.2.2、串口初始化函数staticintBCM2836_startup(structuart_driver_data*udd){intret=0;structBCM2836_port*port=NULL;if(udd==NULL){uart_error("uddisnull!\n");return-EFAULT;}port=(structBCM2836_port*)udd->private;//*private是指向struct{enable,phys_base,irq_num,*udd}if(!port){uart_error("portisnull!");return-EFAULT;}/*enabletheclock*/LOS_TaskLock();LOS_TaskUnlock();ret=request_irq(port->irq_num,(irq_handler_t)BCM2836_uart_irq,0,"uart_dw",udd);//注册串口接收中断函数/*1.uartinterruptpriorityshouldbethehighestininterruptpreemptionmode*///ret=LOS_HwiCreate(NUM_HAL_INTERRUPT_UART,0,0,(HWI_PROC_FUNC)uart_handler,NULL);/*2.clearallirqs*/UARTREG(UART_REG_BASE,UART_ICR)=0x3ff;//*(volatileUINT32*)((UINTPTR)IO_DEVICE_ADDR(0x3F201044))=0x3ff;/*禁用FIFO模式*///uartRegs->USART_CR1&=~(1<<29);//*(volatileUINT32*)((UINTPTR)IO_DEVICE_ADDR(0x3F20102C))=0x60;UARTREG(UART_REG_BASE,UART_LCR_H)=(1<<6|1<<5|1<<4);/*3.setfifotriggerlevel*///*(volatileUINT32*)((UINTPTR)IO_DEVICE_ADDR(0x3F201034))=0x0;UARTREG(UART_REG_BASE,UART_IFLS)=0;/*4.enablerxinterrupt使能串口接收中断,bit4*/UARTREG(UART_REG_BASE,UART_IMSC)=(1<<4|1<<6);//*(volatileUINT32*)((UINTPTR)IO_DEVICE_ADDR(0x3F201038))=0x10;/*5.enablereceive*/UARTREG(UART_REG_BASE,UART_CR)|=(1<<9);//*(volatileUINT32*)((UINTPTR)IO_DEVICE_ADDR(0x3F201030))=0x301;//HalIrqUnmask(NUM_HAL_INTERRUPT_UART);//6.*(volatileUINT32*)((UINTPTR)IO_DEVICE_ADDR(0x3F00B214))=0x02000000;//Unmask收到25号中断BCM2836_config_in(udd);returnret;}2.2.3、串口写函数staticintBCM2836_start_tx(structuart_driver_data*udd,constchar*buf,size_tcount){unsignedinttx_len=count;structBCM2836_port*port=NULL;charvalue;unsignedinti;intret=0;if(udd==NULL){uart_error("uddisnull!\n");返回-EFAULT;}port=(structBCM2836_port*)udd->private;if(!port){uart_error("portisnull!");return-EFAULT;}/*UART_WITH_LOCK:thereisaspinlockinthefunctiontowritereginorder.*/for(i=0;iphys_base,&value,1,UART_WITH_LOCK);}returncount;}2.系统时钟初始化2.1.main函数的各种调用,验证参数kernel\liteos_a\platform\main.c->main()kernel\liteos_a\kernel\common\los_config.c->OsMain()kernel\liteos_a\arch\arm\arm\src\los_hw_tick.c->OsTickInit()systemClock//vendor中设置为50000000tickPerSecond//鸿蒙默认设置为100LITE_OS_SEC_TEXT_INITUINT32OsTickInit(UINT32systemClock)tick,UINT3{//只是验证了传入的两个参数,并没有使用HalClockInit();returnLOS_OK;}2.2、首先获取当前时钟频率,注册中断kernel\liteos_a\platform\hw\arm\timer\arm_generic\arm_generic_timer.cOS_TICK_INT_NUM//中断号,定义在vendor\***\***\board\include\asm\hal_platform_ints.h下,查看手册确定MIN_INTERRUPT_PRIORITY//优先级OsTickEntry//中断函数LITE_OS_SEC_TEXT_INITVOIDHalClockInit(VOID){...g_sysClock=HalClockFreqRead();//先获取当前时钟频率//调用LOS_HwiCreate函数创建新中断,系统中断由其注册ret=LOS_HwiCreate(OS_TICK_INT_NUM,MIN_INTERRUPT_PRIORITY,0,OsTickEntry,0);//参数1:中断号,参数4:执行函数//这个函数就不深究了,一般把中断号和对应的执行函数放到一个array//比如这里是,当OS_TICK_INT_NUM中断发生时,执行OsTickEntry()函数...}2.3、时钟中断执行函数OsTickEntry()kernel\liteos_a\platform\hw\arm\timer\arm_generic\arm_generic_timer.c但是这个此时注册了这个函数,时钟还没有启动,就得执行(3.在调用此函数之前启动时钟LITE_OS_SEC_TEXTVOIDOsTickEntry(VOID){TimerCtlWrite(0);OsTickHandler();TimerCvalWrite(TimerCvalRead()+OS_CYCLE_PER_TICK);TimerCtlWrite(1);//使用最后一个cval生成下一个滴答时间绝对准确。不要使用tval来驱动一般时间,这样tick会更慢。}2.3、启动时钟main()=>OsStart(VOID)=>OsTickStart()=>HalClockStart(VOID)kernel\liteos_a\platform\hw\arm\timer\arm_generic\arm_generic_timer.c=>HalClockStart(VOID)//树莓派2没有GIC,所以这个函数需要改成LITE_OS_SEC_TEXT_INITVOIDHalClockStart(VOID){HalIrqUnmask(OS_TICK_INT_NUM);//OS_TICK_INT_NUM=29TimerCtlWrite(0);TimerTvalWrite(OS_CYCLE_PER_TICK);TimerCtl;Write(3.1)定义在WendorHalIrqUnmask;//接收中断(通过设置寄存器,让CPU响应中断)HalIrqUnmask(OS_TICK_INT_NUM);HalIrqUnmask(29);GIC_REG_32(GICD_ISENABER(29>>5))=1U<<(29%32);(GICD_ISENABLER(29>>5))反汇编GIC_REG_32(GICD_OFFSET+0x100+(29>>5)*4)=1U<<(29%32);/*中断使能寄存器*/GIC_REG_32反汇编,(29%32)=1DGIC_BASE_ADDR+(GICD_OFFSET+0x100+(29>>5)*4)=1U<<(29%32)#defineGIC_BASE_ADDRIO_DEVICE_ADDR(0x3F00A100)#defineGICD_OFFSET0x1000/*interruptdistributoroffset*/2.3.2,TimerCtlWrite//close(0);定时器参考:ARMArchitectureReferenceManualARMv7-AandARMv7-Redition.pdf《B3.17 Organization of the CP15 registers in a VMSA implementation》WRITE_TIMER_REG32(TIMER_REG_CTL,0);ARM_SYSREG_WRITE(TIMER_REG_CTL,0)ARM_SYSREG_WRITE(TIMER_REG(_CTL),0)ARM_SYSREG_WRITE(CP15_REG(c14,0,c2,1)),0)"mcr"(CP15_REG(c14,0,c2,1):::"r"(val)disassemblyr80mcrp15,#0,r8,c14,c2,#1CNTP_CTL,PL1物理定时器控制寄存器2.3.3,TimerTvalWrite(OS_CYCLE_PER_TICK);//设置Tval反汇编r0192000mcrp15,#0,r0,c14,c2,#0CNTP_TVAL,PL1物理时间值寄存器2.3.4,TimerCtlWrite(1);//RestartTimer反汇编r51mcrp15,#0,r5,c14,c2,#1CNTP_CTL,PL1物理定时器控制寄存器2.4,代码移植Z:\bright\harmony-100ask\kernel\liteos_a\platform\hw\arm\interrupt\gic\gic_v2.cVOIDHalIrqUnmask(UINT32vector){if((vector>OS_USER_HWI_MAX)||(vector>5))=1U<<(vector%32);//替换*(volatileUINT32*)((UINTPTR)IO_DEVICE_ADDR(0x3F00B218))=1;//使能ARMTimerIRQ}Z:\bright\harmony-100ask\kernel\liteos_a\platform\hw\arm\timer\arm_generic\arm_generic_timer.cSTATIC_INLINEVOIDTimerCtlWrite(UINT32cntpCtl){//WRITE_TIMER_REG32(TIMER_REG_CTL,cntp/Ctl(ctl)替换)tl==0){*(volatileUINT32*)((UINTPTR)IO_DEVICE_ADDR(0x3F00B408))=0x003E0000;}else{*(volatileUINT32*)((UINTPTR)IO_DEVICE_ADDR(0x3F00B408))=0x003E00A2;}}2STATIC_INvalINTUtTimerT(er){//WRITE_TIMER_REG32(TIMER_REG_TVAL,tval);//替换*(volatileUINT32*)((UINTPTR)IO_DEVICE_ADDR(0x3F00B400))=tval;//设置倒计时时间,鸿蒙为10ms}=======完整内容======#2020收藏-开发板#鸿蒙移植树莓派(上)搭建环境源码下载#2020求文-开发板#鸿蒙移植树莓派(中)添加单板#2020收藏-开发板#鸿蒙移植树莓派(下)并修改源码?版权归作者及鸿蒙技术社区所有。如需转载请注明出处,否则将追究法律责任。更多信息请访问:与华为官方共建鸿蒙技术社区https://harmonyos.51cto.com/#zz

最新推荐
猜你喜欢