硬件環境:NXP 1788
軟件環境:KEIL
實現過程:上面說了我準備了兩個程序,就用裸機版的代碼說一下實現流程。帶操作系統的原理都是一樣的。只是多創建幾個任務而已。USB_HOST實現IAP升級,總的思路就是:複製bin文件到U盤->目標板斷電,插上U盤->目標板上電,進入升級->運行升級程序。其實可以更具體,比如說設置升級標誌或者按鍵。
拿到一個程序先從main開始,直接貼代碼,說一大堆廢話有什麼用。
int main()
{
int32_t rc;
uint32_t numBlks,blkSize;
uint8_t inquiryResult[INQUIRY_LENGTH];
SystemInit();
UART_Init(57600);
Host_Init();
rc =Host_EnumDev();
if (rc ==OK) {
rc = MS_Init( &blkSize, &numBlks, inquiryResult );
if (rc == OK) {
rc = FAT_Init();
if (rc == OK) {
Bin_Read();
} else {
return (0);
}
} else {
return (0);
}
} else{
return (0);
}
while(1);
}
下面分模塊說一下, 前面的硬件初始化函數很簡單,USB設備枚舉和FAT文件系統NXP官網上都有,只需改硬件接口,Host_Init函數如下:
void Host_Init(void)
{
uint32_t HostBaseAddr;
LPC_SC->PCONP |=0x80000000;
LPC_USB->OTGClkCtrl =0x00000019;
while((LPC_USB->OTGClkSt & 0x00000019) != 0x19);
LPC_USB->StCtrl =0x1;
LPC_IOCON->P0_29 &= ~(0x07UL << 0);
LPC_IOCON->P0_30 &= ~(0x07UL << 0);
LPC_IOCON->P1_28 &= ~(0x07UL << 0);
LPC_IOCON->P1_29 &= ~(0x07UL << 0);
LPC_IOCON->P0_29 |= 0x01UL <<0;
LPC_IOCON->P0_30 |= 0x01UL <<0;
LPC_IOCON->P1_28 |= 0x01UL <<0;
LPC_IOCON->P1_29 |= 0x01UL <<0; // P1.29 --USB_SDA1
PRINT_Log("Initializing HostStack\n");
HostBaseAddr = HOST_BASE_ADDR;
Hcca = (volatile HCCA *)(HostBaseAddr+0x000);
TDHead = (volatile HCTD *)(HostBaseAddr+0x100);
TDTail = (volatile HCTD *)(HostBaseAddr+0x110);
EDCtrl = (volatile HCED *)(HostBaseAddr+0x120);
EDBulkIn =(volatile HCED *)(HostBaseAddr+0x130);
EDBulkOut = (volatile HCED *)(HostBaseAddr+0x140);
TDBuffer =(volatile uint8_t *)(HostBaseAddr+0x150);
FATBuffer = (volatile uint8_t*)(HostBaseAddr+0x1D0);
UserBuffer =(volatile uint8_t*)(HostBaseAddr+0x1000);
Host_EDInit(EDCtrl);
Host_EDInit(EDBulkIn);
Host_EDInit(EDBulkOut);
Host_TDInit(TDHead);
Host_TDInit(TDTail);
Host_HCCAInit(Hcca);
Host_DelayMS(50);
LPC_USB->Control = 0;
LPC_USB->ControlHeadED =0;
LPC_USB->BulkHeadED = 0;
LPC_USB->CommandStatus = OR_CMD_STATUS_HCR;
LPC_USB->FmInterval = DEFAULT_FMINTERVAL;
LPC_USB->Control = (LPC_USB->Control &(~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER;
LPC_USB->RhStatus =OR_RH_STATUS_LPSC;
LPC_USB->HCCA = (uint32_t)Hcca;
LPC_USB->InterruptStatus |=LPC_USB->InterruptStatus;
LPC_USB->InterruptEnable = OR_INTR_ENABLE_MIE|
OR_INTR_ENABLE_WDH |
OR_INTR_ENABLE_RHSC |
OR_INTR_ENABLE_UE;
NVIC_EnableIRQ(USB_IRQn);
NVIC_SetPriority (USB_IRQn,0);
PRINT_Log("Host Initialized\n");
}
這段主要是USB引腳配置和USB主機初始化。Bin_Read()函數如下:
void Bin_Read(void)
{
int32_t fdr;
uint32_t bytes_read,writelen;
uint32_t dstaddr;
SelSector(APP_START_SECTOR,APP_END_SECTOR); //選擇扇區
EraseSector(APP_START_SECTOR,APP_END_SECTOR);
BlankCHK(APP_START_SECTOR,APP_END_SECTOR);
SelSector(APP_START_SECTOR,APP_END_SECTOR);
PRINT_Log("\r\nstart file operations...\r\n");
fdr = FILE_Open(FILENAME_R, RDONLY);
if (fdr >0) {
PRINT_Log("Reading from %s...\n", FILENAME_R);
for(writelen=0;writelen<(APP_END_ADDR-APP_START_ADDR)/1024;writelen++)
{
bytes_read =FILE_Read(fdr, UserBuffer,MAX_BUFFER_SIZE);
dstaddr= (uint32_t)(APP_START_ADDR +(writelen)*1024);//dst address.
SelSector(APP_START_SECTOR,APP_END_SECTOR);
RamToFlash(dstaddr,(uint32_t)UserBuffer, 1024);
Compare(dstaddr, (uint32_t)UserBuffer, 1024);
}
// printf("%x",writelen);
PRINT_Log("\r\n write filesuccessful\r\n");
SCB->VTOR =APP_START_ADDR;
ExceuteApplication();
FILE_Close(fdr);
} else{
PRINT_Log("\r\n write file failed\r\n");
}
}
上面的代碼可以分爲兩部分:1.從U盤讀取bin文件2.IAP功能。先說IAP部分,IAP實現方法有UART,GPRS,USB等方式。要進行IAP設計,先劃分FLASH扇區。LPC1788的FLASH劃分如下:
#define IAP_LOCATION 0x1FFF1FF1
#defineAPP_START_ADDR 0x00A000 // 用戶程序起始地址
#defineAPP_END_ADDR 0x78000 //LPC1788 512KFlash
//#defineAPP_SIZE 0x10000
#defineAPP_START_SECTOR 10
#defineAPP_END_SECTOR 29 // LPC1788 512K Flash扇區
uint32_t paramout[8];
unsigned long command[5];
unsigned long result[5];
typedef void (*IAP) (unsigned int [ ] , unsigned int []);
{
paramin[0] =IAP_SELECTOR;
paramin[1] =sec1;
paramin[2] =sec2;
(*(void(*)())IAP_LOCATION)(paramin,paramout);
return(paramout[0]);
}
{
paramin[0] =IAP_ERASESECTOR;
paramin[1] =sec1;
paramin[2] =sec2;
paramin[3] =IAP_FCCLK;
(*(void(*)())IAP_LOCATION)(paramin,paramout);
return(paramout[0]);
}
{
paramin[0] =IAP_RAMTOFLASH;
paramin[1] =dst;
paramin[2] =src;
paramin[3] =no;
paramin[4] =IAP_FCCLK;
(*(void(*)())IAP_LOCATION)(paramin,paramout);
return(paramout[0]);
}
{
paramin[0] =IAP_COMPARE;
paramin[1] =dst;
paramin[2] =src;
paramin[3] =no;
(*(void(*)())IAP_LOCATION)(paramin,paramout);
return(paramout[0]);
}
__asm void ExceuteApplication(void)
{
ldr r0, =0x00A000
ldr r0, [r0]
mov sp, r0
ldr r0, =0x00A004
ldr r0, [r0]
BX r0
}
最後關閉文件系統,main裏面最主要讀取bin文件調用IAP功能的Bin_Read()函數說完了。最後說一下APP程序產生bin文件的配置。
KEIL中Target Options配置:
1.將程序入口定位到App即用戶程序的入口地址;2.User選項:Run#1填寫產生bin文件路徑:C:\Keil\ARM\ARMCC\bin\fromelf.exe--bin --outputoutput\FLASH\test.binoutput\FLASH\LPC177x_8x.axf;3.C/c++選項:Optimization選擇高優先級:Level3;4.Asm選項:Define填NO_CRP;不產生空文件夾5.Linker選項:勾選UseMemory layout from TargetDialog.整個工程就算建立起來了。附兩個版本的代碼,僅限參考:
裸機版:http://download.csdn.net/download/u012246376/8453395
帶操作系統UCOS版本:http://download.csdn.net/download/u012246376/8453349
更多技術文章瀏覽請關注:
百家號:
https://author.baidu.com/home?context=%7B%22app_id%22%3A%221646108714303504%22%7D&wfr=bjh
頭條號:
https://www.toutiao.com/c/user/8115738721/#mid=1646025109246987