鴻蒙移植樹(shù)莓派(下)修改源碼
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
https://harmonyos.51cto.com/#zz
項(xiàng)目最新更新,可以查看碼倉(cāng) https://gitee.com/liangzili/harmony-raspberry
1、切換啟動(dòng)模式
樹(shù)莓派默認(rèn)啟動(dòng)在HYP模式,我們需要在內(nèi)核啟動(dòng)前改為SVC模式
kernel\liteos_a\arch\arm\arm\src\startup\reset_vector_up.S 在115行左右,reset_vector:下面添加
- mrs r0,cpsr //讀取CPU模式寄存器
- bic r0,r0,#0x1F //清除CPU模式位(如果處于催眠模式,它將是1A)保留所有其他
- orr r0,r0,#0x13 //設(shè)置CPU_MODE為SVC_MODE (0x13),而ORR仍然保留所有其他位
- msr spsr_cxsf,r0 //將其寫(xiě)入spsr_cxsf寄存器,以便在調(diào)用交換機(jī)時(shí)加載該寄存器。
- add r0,pc,#4 //從pc計(jì)算要進(jìn)入SVC_MODE的地址(后面的兩個(gè)操作碼很長(zhǎng))
- msr ELR_hyp,r0 //將地址值寫(xiě)入ELR_hyp寄存器
- eret //執(zhí)行了回車(chē)指令
2、修改串口驅(qū)動(dòng)
2.1、為了方便調(diào)試,先設(shè)置一個(gè)字符打印函數(shù)
kernel\liteos_a\platform\uart\amba_pl011\amba_pl011.c在46行左右處添加下面的代碼,uart_putc_phy使用物理地址打印字符,uart_putc_virt使用虛擬地址打印。當(dāng)內(nèi)核代碼啟動(dòng)MMU之后,需用使用uart_putc_virt來(lái)打印字符。
- /*---------自定義函數(shù)----------*/
- #define RPI_BASE_UART_REGISTER (0x3f201000) //HI3516:0x120A0000 rpi2: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 rpi2: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 //調(diào)用C函數(shù)前,得先設(shè)置棧,樹(shù)莓派物理內(nèi)存從0x0開(kāi)始
- mov r0, #'m'
- bl uart_putc_phy //在MMU啟動(dòng)之前使用的是物理地址打印
- bl mmu_setup /* set up the mmu */
- mov r0, #'M'
- bl uart_putc_virt //在MMU啟動(dòng)之后使用的是虛擬地址打印
2.2、添加串口中斷,串口輸入代碼
- vendor\broadcom\BCM2836\driver\uart\uart_hardware.c
2.2.1、 串口的中斷函數(shù),產(chǎn)生中斷時(shí),這個(gè)函數(shù)調(diào)用
- 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)); //去讀取硬件得到數(shù)據(jù)
- if (udd->num != CONSOLE_UART) {
- continue;
- }
- if (CheckMagicKey(buf[count - 1])) { //數(shù)據(jù)放在buf里
- goto end;
- }
-
- if (buf[count-1] == '\r') //對(duì)windows和liteos回車(chē)換行的處理
- buf[count-1] = '\n';
- } while (UARTREG(UART_REG_BASE,UART_DR));
- udd->recv(udd, buf, count); //調(diào)用udd里的recv函數(shù)把數(shù)據(jù)發(fā)送給上一級(jí)
- }
- UARTREG(UART_REG_BASE, UART_ICR) = 0x3ff;
- end:
- /* clear all interrupt */
- return 0;
- }
2.2.2、串口的初始化函數(shù)
- 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是一個(gè)指針,指向 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); //去注冊(cè)一個(gè)串口的接收中斷函數(shù)
- /* 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 開(kāi)啟串口接收中斷,第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號(hào)中斷
-
- BCM2836_config_in(udd);
-
- return ret;
- }
2.2.3、串口寫(xiě)函數(shù)
- 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;
- }
2、系統(tǒng)時(shí)鐘初始化
2.1、main函數(shù)的各種調(diào)用,驗(yàn)證參數(shù)
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里設(shè)置的是50000000
- tickPerSecond //鴻蒙默認(rèn)設(shè)置的是100
- LITE_OS_SEC_TEXT_INIT UINT32 OsTickInit(UINT32 systemClock, UINT32 tickPerSecond)
- { //只是驗(yàn)證了下傳入的這兩個(gè)參數(shù),并未使用
- HalClockInit();
- return LOS_OK;
- }
2.2、先獲取當(dāng)前時(shí)鐘頻率,注冊(cè)中斷
kernel\liteos_a\platform\hw\arm\timer\arm_generic\arm_generic_timer.c
- OS_TICK_INT_NUM//中斷號(hào),在vendor\***\***\board\include\asm\hal_platform_ints.h下定義,查手冊(cè)確定
- MIN_INTERRUPT_PRIORITY//優(yōu)先級(jí)
- OsTickEntry//中斷函數(shù)
- LITE_OS_SEC_TEXT_INIT VOID HalClockInit(VOID)
- { ...
- g_sysClock = HalClockFreqRead(); //先獲取當(dāng)前時(shí)鐘頻率
- //調(diào)用LOS_HwiCreate函數(shù)新建中斷,系統(tǒng)中斷由它注冊(cè)
- ret = LOS_HwiCreate(OS_TICK_INT_NUM, MIN_INTERRUPT_PRIORITY, 0, OsTickEntry, 0);//參數(shù)1:中斷號(hào)、參數(shù)4:執(zhí)行函數(shù)
- //這個(gè)函數(shù)就不深入了,大體就是將中斷號(hào)好和對(duì)應(yīng)的執(zhí)行函數(shù)放到一個(gè)數(shù)組
- //比如這里就是,當(dāng)發(fā)生OS_TICK_INT_NUM這個(gè)中斷時(shí),執(zhí)行OsTickEntry()函數(shù)
- ...
- }
2.3、時(shí)鐘中斷的執(zhí)行函數(shù)OsTickEntry()
kernel\liteos_a\platform\hw\arm\timer\arm_generic\arm_generic_timer.c
- 不過(guò)此時(shí)這是注冊(cè)了這個(gè)函數(shù),時(shí)鐘并未啟動(dòng),得執(zhí)行了(三.啟動(dòng)時(shí)鐘)之后才會(huì)調(diào)用這個(gè)函數(shù)
- LITE_OS_SEC_TEXT VOID OsTickEntry(VOID)
- {
- TimerCtlWrite(0);
- OsTickHandler();
- TimerCvalWrite(TimerCvalRead() + OS_CYCLE_PER_TICK);
- TimerCtlWrite(1);
- //使用最后一個(gè)cval生成下一個(gè)tick的時(shí)間是絕對(duì)和準(zhǔn)確的。不要使用tval來(lái)驅(qū)動(dòng)一般時(shí)間,在這種情況下tick會(huì)變慢。
- }
2.3、啟動(dòng)時(shí)鐘
main() => OsStart(VOID) => OsTickStart() => HalClockStart(VOID)
kernel\liteos_a\platform\hw\arm\timer\arm_generic\arm_generic_timer.c => HalClockStart(VOID)
- //樹(shù)莓派2沒(méi)有GIC所以這個(gè)函數(shù)要爆改
- LITE_OS_SEC_TEXT_INIT VOID HalClockStart(VOID)
- {
- HalIrqUnmask(OS_TICK_INT_NUM); //wendor里定義的 OS_TICK_INT_NUM = 29
- TimerCtlWrite(0);
- TimerTvalWrite(OS_CYCLE_PER_TICK);
- TimerCtlWrite(1);
- }
2.3.1、HalIrqUnmask; //接收中斷(通過(guò)設(shè)置寄存器,允許CPU響應(yīng)該中斷)
- HalIrqUnmask(OS_TICK_INT_NUM);
- HalIrqUnmask(29);
- GIC_REG_32(GICD_ISENABLER(29 >> 5)) = 1U << (29 % 32);
-
- (GICD_ISENABLER(29 >> 5))拆開(kāi)
- GIC_REG_32(GICD_OFFSET + 0x100 + (29 >> 5) * 4) = 1U << (29 % 32);/* 中斷使能 Registers */
-
- GIC_REG_32拆開(kāi),(29 % 32)=1D
- GIC_BASE_ADDR + (GICD_OFFSET + 0x100 + (29 >> 5) * 4) = 1U << (29 % 32)
-
- #define GIC_BASE_ADDR IO_DEVICE_ADDR(0x3F00A100)
- #define GICD_OFFSET 0x1000 /* interrupt distributor offset */
2.3.2、TimerCtlWrite(0); //關(guān)閉Timer
參考:ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.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)
- 反匯編
- r8 0
- mcr p15, #0, r8, c14, c2, #1 CNTP_CTL,PL1物理定時(shí)器控制寄存器
2.3.3、TimerTvalWrite(OS_CYCLE_PER_TICK); //設(shè)置Tval
- 反匯編
- r0 192000
- mcr p15, #0, r0, c14, c2, #0 CNTP_TVAL,PL1物理時(shí)間值寄存器
2.3.4、TimerCtlWrite(1); //再開(kāi)啟Timer
- 反匯編
- r5 1
- mcr p15, #0, r5, c14, c2, #1 CNTP_CTL,PL1物理定時(shí)器控制寄存器
2.4、代碼移植
Z:\bright\harmony-100ask\kernel\liteos_a\platform\hw\arm\interrupt\gic\gic_v2.c
- VOID HalIrqUnmask(UINT32 vector)
- {
- if ((vector > OS_USER_HWI_MAX) || (vector < OS_USER_HWI_MIN)) {
- return;
- }
- //GIC_REG_32(GICD_ISENABLER(vector >> 5)) = 1U << (vector % 32); //替換
- *(volatile UINT32 *)((UINTPTR)IO_DEVICE_ADDR(0x3F00B218)) = 1; //使能ARM Timer IRQ
- }
Z:\bright\harmony-100ask\kernel\liteos_a\platform\hw\arm\timer\arm_generic\arm_generic_timer.c
- STATIC_INLINE VOID TimerCtlWrite(UINT32 cntpCtl)
- {
- //WRITE_TIMER_REG32(TIMER_REG_CTL, cntpCtl);//替換
- if(cntpCtl == 0){
- *(volatile UINT32 *)((UINTPTR)IO_DEVICE_ADDR(0x3F00B408)) = 0x003E0000;
- }
- else
- {
- *(volatile UINT32 *)((UINTPTR)IO_DEVICE_ADDR(0x3F00B408)) = 0x003E00A2;
- }
- }
- STATIC_INLINE VOID TimerTvalWrite(UINT32 tval)
- {
- //WRITE_TIMER_REG32(TIMER_REG_TVAL, tval);//替換
- *(volatile UINT32 *)((UINTPTR)IO_DEVICE_ADDR(0x3F00B400)) = tval; //設(shè)置倒計(jì)時(shí)時(shí)間,鴻蒙是10ms
- }
=======完整內(nèi)容======
#2020征文-開(kāi)發(fā)板# 鴻蒙 移植 樹(shù)莓派(上)搭建環(huán)境下載源碼
#2020征文-開(kāi)發(fā)板# 鴻蒙 移植 樹(shù)莓派(中)添加單板
#2020征文-開(kāi)發(fā)板# 鴻蒙 移植 樹(shù)莓派(下)修改源碼
©著作權(quán)歸作者和HarmonyOS技術(shù)社區(qū)共同所有,如需轉(zhuǎn)載,請(qǐng)注明出處,否則將追究法律責(zé)任.
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
https://harmonyos.51cto.com/#zz