一、复位
ARM启动中需要配置上电复位功能,因为这样才能确保上电之后程序处于初始状态而并非程序指针未知。通常启动代码编译器自带,而程序入口基本上都是以复位中断开始。
下面这一段启动代码会自动调用两个函数,分别是
SystemInit 系统上电初始化,主要进行时钟、锁相环等核心部分的配置
main 系统上电初始化之后,调用main函数,用户无需返回main函数
; Reset Handler Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT SystemInit IMPORT __main LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP
二、SystemInit系统上电初始化
SystemInit仅仅是一个函数名称,所以在不同的环境下可能名字不同。
//LPC175X-6X #if 1 void SystemInit(void){ //Flash Accelerator Configuration register LPC_SC->FLASHCFG = ((0x05ul << 12) & (~(0x003f))) | 0x003a; //Set system timers for each component #if (FPCLK / (FCCLK / 4)) == 1 LPC_SC->PCLKSEL0 = 0x00000000; /* PCLK is 1/4 CCLK */ LPC_SC->PCLKSEL1 = 0x00000000; #endif /* (FPCLK / (FCCLK / 4)) */ #if (FPCLK / (FCCLK / 4)) == 2 LPC_SC->PCLKSEL0 = 0xAAAAAAAA; /* PCLK is 1/2 CCLK */ LPC_SC->PCLKSEL1 = 0xAAAAAAAA; #endif /* (FPCLK / (FCCLK / 4)) */ #if (FPCLK / (FCCLK / 4)) == 4 LPC_SC->PCLKSEL0 = 0x55555555; /* PCLK is the same as CCLK */ LPC_SC->PCLKSEL1 = 0x55555555; #endif /* (FPCLK / (FCCLK / 4)) */ //Selects the CPU clock as the CLKOUT source LPC_SC->CLKOUTCFG = 0; /* Close PLL */ if ((LPC_SC->PLL0STAT >> 24) == 1) { LPC_SC->PLL0CON = 1; // Enable PLL, disconnected LPC_SC->PLL0FEED = 0xAA; LPC_SC->PLL0FEED = 0x55; } LPC_SC->PLL0CON = 0; // Disable PLL, disconnected LPC_SC->PLL0FEED = 0xAA; LPC_SC->PLL0FEED = 0x55; while(LPC_SC->PLL0STAT & (3 << 24)); /* PLL clock */ //Enable mainOSC,1MHz~20MHz LPC_SC->SCS = (LPC_SC->SCS) | 0x20; //wait for The main oscillator is ready while ((LPC_SC->SCS & (1ul << 6)) == 0) ; LPC_SC->CLKSRCSEL = 0x01;//select main OSC as the PLL clock source LPC_SC->PLL0CFG = (((PLL_NVALUE - 1) << 16) | (PLL_MVALUE - 1)); LPC_SC->PLL0FEED = 0xAA; /* Enable but disconnect PLL */ LPC_SC->PLL0FEED = 0x55; LPC_SC->PLL0CON = 1;//PLL0 Enable LPC_SC->PLL0FEED = 0xAA; // Enable but disconnect PLL LPC_SC->PLL0FEED = 0x55; while ((LPC_SC->PLL0STAT & (1ul << 26)) == 0); //CPU Clock Configuration register LPC_SC->CCLKCFG = (FCCO / FCCLK) - 1; while (((LPC_SC->PLL0STAT & (1ul << 26)) == 0)); /* Check lock bit status */ while (((LPC_SC->PLL0STAT & 0x00007FFF) != (PLL_MVALUE - 1)) && (((LPC_SC->PLL0STAT & 0x00FF0000) >> 16) != (PLL_NVALUE - 1))); LPC_SC->PLL0CON = 3; /* connect the PLL */ LPC_SC->PLL0FEED = 0xAA; LPC_SC->PLL0FEED = 0x55; //Wait until the PLL is connected while ((LPC_SC->PLL0STAT & (1ul << 25)) == 0); /* USB clock */ #if FUSBCLK_EN #if (FCCO % (FUSBCLK * 2)) == 0 LPC_SC->PLL1CON = 0; LPC_SC->PLL1FEED = 0xaa; LPC_SC->PLL1FEED = 0x55; LPC_SC->USBCLKCFG = (FCCO / (FUSBCLK)) - 1; #else LPC_SC->PLL1CON = 1; LPC_SC->PLL1CFG = ((FUSBCLK / FOSC) - 1) | (1 << 5); LPC_SC->PLL1FEED = 0xaa; LPC_SC->PLL1FEED = 0x55; while ((LPC_SC->PLL1STAT & (1 << 10)) == 0) { } LPC_SC->PLL1CON = 3; LPC_SC->PLL1FEED = 0xaa; LPC_SC->PLL1FEED = 0x55; #endif #endif /* flash accesses */ //Flash accesses use 1 CPU clock. Use for up to 20 MHz CPU clock. #if FCCLK <= 20000000 LPC_SC->FLASHCFG = ((0x01ul << 12) & (~(0x003f))) | 0x003a; #endif //Flash accesses use 2 CPU clocks. Use for up to 40 MHz CPU clock. #if FCCLK > 20000000 && FCCLK <= 40000000 LPC_SC->FLASHCFG = ((0x02ul << 12) & (~(0x003f))) | 0x003a; #endif //Flash accesses use 3 CPU clocks. Use for up to 60 MHz CPU clock. #if FCCLK > 40000000 && FCCLK <= 60000000 LPC_SC->FLASHCFG = ((0x03ul << 12) & (~(0x003f))) | 0x003a; #endif //Flash accesses use 4 CPU clocks. Use for up to 80 MHz CPU clock. #if FCCLK > 60000000 && FCCLK <= 80000000 LPC_SC->FLASHCFG = ((0x04ul << 12) & (~(0x003f))) | 0x003a; #endif //Flash accesses use 5 CPU clocks. Use for up to 100 MHz CPU clock #if FCCLK > 80000000 && FCCLK <= 100000000 LPC_SC->FLASHCFG = ((0x05ul << 12) & (~(0x003f))) | 0x003a; #endif IO_init(); NVIC_ICER0 = 0xffffffff; NVIC_ICER1 |= 0x00000007; Interrupt_Enable(); } #endif
三、main用户函数
main函数根据用户编程,一般执行步骤是初始化各个模块资源,然后进入后台循环任务。
//最简化的main函数,没有任何任务
int main(void)
{
while(1)
{
}
}
/************************************************************************************************ * * Description: * * Arguments : * Returns : ************************************************************************************************/ int main(void) { ErrType err; INT8U receive_buf[128],para_buf[128]; u_BusPacket pkt; TKIT_MSG Msg; //TKIT init #ifdef __APP_CODE__ SystemVectorRemap(0x00030000); TKIT_Init( TKITMODE_APP ); #else //BOOT code SystemVectorRemap(0x00000000); TKIT_Init( TKITMODE_BOOT ); #endif //__APP_CODE__ //检查文件系统以及升级文件 #if TKIT_FATFS_EN && KIT_SDCARD_EN while( SD_Exist ) { //建立系统文件夹 err = t_FatSysCheck(FAT_ROOT); if( TKIT_SUCCESS==err )err = t_fat_PathCheck(FAT_ROOT_PATH, TRUE); if( TKIT_SUCCESS==err )err = t_fat_PathCheck(FAT_PATH_DEVICE, TRUE); if( TKIT_SUCCESS==err )err = t_fat_PathCheck(FAT_PATH_SYS, TRUE); //检测升级文件 if( TRUE==b_FileFirmwareCheck(FAT_PATH_SYS,"AM-AM",FALSE,FALSE) ) { Printf("\tFind available app code in disk[%s]\r\n ",FAT_PATH_SYS); #ifndef __APP_CODE__ b_FileFirmwareCheck(FAT_PATH_SYS,"AM-AM10",TRUE,TRUE); #endif } else { Printf("\tCan't find available app code in disk[%s]\r\n ",FAT_PATH_SYS); } break; } #endif //TKIT_FATFS_EN //Bootloader检测是否需要跳转 #ifndef __APP_CODE__ Printf("\tBootloader check app code and jump...\r\n "); pkt.Alt.Port = BUS_PORT_ALL; TKIT_ErrUpdate( t_TKIT_AppCheck( TKIT_DLY_3S, &pkt ) ); #endif //__APP_CODE__ //启动所有前台任务 Printf("\tTKIT task init and start.\r\n "); TKIT_TaskStart(); Task_Init(); //创建一个任务,每隔1S执行一次 TKIT_TaskCreateTimer("Task isr",Task_Isr, NULL, TKIT_DLY_1S ); //创建一个消息,系统每隔1S自动触发 Msg = TKIT_MsgCreate( NULL,TKIT_DLY_1S); while( 1 ) { Task(); //LED if( TKIT_MsgPend(Msg,NULL,0) ) { TKIT_IO_SetBurstCnt(IO_LED_CORE,1);//Pend message success } //If terminal enable if( Terminal_EnableCheck() ) { if( ReadsExt(receive_buf,para_buf) ) { Terminal_Handler(receive_buf,para_buf); } } //选择通信接口 //接收一个帧 pkt.Alt.Port = BUS_PORT_USB | BUS_PORT_AT | BUS_PORT_TCP; if( FALSE==Terminal_EnableCheck() ) { pkt.Alt.Port |= BUS_PORT_UART; } if( i_ProBus_ReadPkt(&pkt,TKIT_DLY_10MS) ) { //Printf("\tReceived command:%04X, Data len=%d\r\n",pkt.Alt.Cmd.u16,pkt.Alt.DataSize.u32 ); t_ProBus_CmdHandler( &pkt ); //Printf("\tReceived command handler finished. Return len:%d\r\n\r\n",pkt.Alt.DataSize.u32 ); TKIT_IO_SetBurstCnt(IO_LED_CORE,1); } else if( BUS_PORT_UART&pkt.Alt.Port && i_ProBus_ReadPktBuffer() ) { if( 0==std_StringCmpExtLen("admin%ADMIN",(char*)pkt.byte,5 ) ) { Terminal_Enable(TRUE); PrintWelcome(); } } #if DHCP_EN do_dhcp(); //DHCP测试程序 #endif ////////END FOR ///////////////// }//end while }
四、启动流程串口演示
(演示了代码启动,然后用户程序执行了手动跳转)