This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
I referred to the Firmware upgrade over USB as a reference and I am currently trying to perform the firmware upgrade over Ethernet with the help of a HTTP server. The scheme which we are trying to implement is to split the flash into three sections Bootloader, Application and Binary section.
1. The the user uploads the bin file through the web page hosted and we store the uploaded file into the address of binary section.
2. Get into custom boot loader and perform erase of Application section and flash the firmware in binary section to application section.
3. Then load application.
Is this a possible method to implement and what will be the changes which needs to be made for this.
HI Mohammed,
I hope you have already gone through the Ethernet bootloader examples in the TivaWare library. How will the application be programmed in the first place? Will the application be programmed to the flash via the JTAG or like the binary to be uploaded via the Ethernet as well?
If both the application and the binary are to be uploaded via the Ethernet, then you will need to add some intelligence into the bootloader. The bootloader needs to know when to load the application section and when to load the binary section and when to reprogram the application from the binary section. If the application was already loaded via the JTAG like the bootloader itself then it will be slightly easier. The bootloader needs to first upload the binary from your http server to the binary section in the flash. Somehow your application will receive some type of command or just pin pressed and it will transfer control to the bootloader. The bootloader in this case will just erase the application and program the application section again based on the binary stored in the binary section. The erase and program can just use the TivaWare API such as FlashErase() and FlashProgram(). Please refer to the TivaWare Peripheral Driver Library user's guide.
With that said, I'm just curious why you want to split into three sections instead of just two - the bootloader and the application sections. The flash will initially contain just the bootloader. The bootloader will first send BOOTP request to the server. The server will then upload the application via the Ethernet. The application will just run like normal. If the server wants to update the application again, it can just do so. The server will send some magic packet to the application. Upon receiving the magic packet the application will transfer the control to the bootloader again. Once transferred to the bootloader, the bootloader will upload a new application code from the server. This is basically what the TivaWare Ethernet bootloader example does.
Hi Charles,
Thanks a lot for your reply, Please find the replies for your concerns.
1. The firmware is downloaded to the binary section by the user from the hosted HTTP server by the controller itself. After the upload is done from the web page we switch to the boot loader mode.
2. No, we are not planning on using the JTAG or any program like LM flash. That is the reason we want to load the new firmware on demand from the HTTP server.
3. I guess the bootloader doesn't have capabilities to host a http server and perform the operations of download from the server. Hence we download from the application code and then switch to boot loader.
4. Point 3 explains the reason why we need a binary section, as the firmware is not loaded lively over TFTP like the LM Flash programmer, but it is rather flashed from another location from the flash itself.
I hope I have made clear of the requirements and the reasons why we opted for this method. Please confirm the feasibility of this and any challenges we might face.
Hi,
Ok, thanks for the clarification. I think I understand why you are trying to achieve. Your application will need to program the binary section. In the TivaWare bootloader example it will upload the firmware via the TFTP and program/update the application section. In your case, your application will need to handle this like the bootloader does and will update the binary section instead. So I will suggest your application reference how it is done in the TivaWare bootloader example to update the firmware. Once your application updates the binary section you will jump to the bootloader. Your bootloader will need to be modified to perform just the FlashErase() and FlashProgram() to the application section from the binary section.
There is a difference in the firmware download approach in the TivaWare bootloader example and the upload via the HTTP server
Current boot loader example:
We will need the LM flash programmer to load the file to the device via TFTP. But the way in which I am trying to do is to send the file through the HTTP server hosted by the controller itself.
Method trying to implement:
To load the file via the hosted HTTP server, The binary bin file I am generating is around 160 KB and the upload is failing due to the heap memory allocation. The whole file is sent as a text string to the device, therefore taking the allocation on heap memory.
typedef struct { char *Name; /* NULL terminated "name" */ char *Filename; /* NULL terminated "filename" or NULL if not a file */ char *Type; /* NULL terminated "Content-Type" or NULL if no type */ char *Data; /* Pointer to item data (NULL terminated on strings) */ int DataSize; /* Length of data (also valid on strings) */ } CGIPARSEREC;
On increasing the heap memory size I am able to upload up to 130 KB. This is after changing the BIOS.heapSize to a very large value. Please let me know a way in which we should be able to upload the file as a whole to the device.
So these would be queries on this,
1. Is it acceptable to send the binary file as a character string to the device via the HTTP server?
2. Shall we make the full binary file into separate chunks and upload in separate instance?
3. After receiving the whole file, how to copy it to the binary section (specific address location) in our flash, we have any specific API's for this?
Hi,
On number 1, I think character should be fine but I'm not certainly sure. I will suggest you start with a small binary first and get everything working and proven out before you attempt with your final binary image. Breaking into separate chucks if you still have the heapsize issue. Please reference the bl_flash.c in the TviaWare bootloader file to copy (program/erase) the image to its destination address.
Hi Charles,
Thanks a lot for confirming this, let me try the implementation part for this.
I will reference the bl_flash.c for programming and erasing the application section.
Could you please help me with number 3, the method to store the firmware binary in the binary section. How to perform the storage to a specific location in flash.
Hi,
I thought you were going to reference the bl_flash.c for programming and erasing the application section. To program and erase the binary section you would have used the similar method. Please see below bootloader code in the bl_emac.c file where the TFTP data is parsed and then the data is programmed to the application section by calling both the BL_FLASH_ERASE_FN_HOOK and BL_FLASH_PROGRAM_FN_HOOK functions. The data is programmed to the beginning at APP_START_ADDRESS. The BL_FLASH_ERASE_FN_HOOK and BL_FLASH_PROGRAM_FN_HOOK are defined in the bl_flash.c. What I was suggesting was that you can reference how it is done in the TivaWare bootloader. Your application will need to parse the received HTTP data and program to the binary section.
//***************************************************************************** // //! Parses a packet checking for a TFTP data packet. //! //! This function parses a packet to determine if it is a TFTP data packet for //! out current TFTP transfer. If a valid packet is found, the contents of the //! packet are programmed into flash. //! //! \return Returns 1 if this packet was the last packet of the TFTP data //! transfer and 0 otherwise. // //***************************************************************************** static uint32_t ParseTFTPData(void) { uint8_t *pui8Packet = (uint8_t *)uip_appdata; uint32_t ui32FlashAddr; uint32_t ui32Idx; // // See if this is a TFTP data packet. // if((pui8Packet[0] != ((TFTP_DATA >> 8) && 0xff)) || (pui8Packet[1] != (TFTP_DATA & 0xff))) { return(0); } // // If the remote port on our connection is still the TFTP server port (i.e. // this is the first data packet), then copy the transaction ID for the // TFTP data connection into our connection. This will ensure that our // response will be sent to the correct port. // if(g_pConn->rport == HTONS(TFTP_PORT)) { g_pConn->rport = ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])->srcport; } // // See if this is the correct data packet. // if((pui8Packet[2] != ((g_ui32TFTPBlock >> 8) & 0xff)) || (pui8Packet[3] != (g_ui32TFTPBlock & 0xff))) { // // Since the wrong data packet was sent, resend the ACK for it since // we've already processed it. // pui8Packet[0] = (TFTP_ACK >> 8) & 0xff; pui8Packet[1] = TFTP_ACK & 0xff; uip_udp_send(4); // // Ignore this packet. // return(0); } // // What address are we about to program to? // ui32FlashAddr = ((g_ui32TFTPBlock - 1) * TFTP_BLOCK_SIZE) + APP_START_ADDRESS; // // Do not program this data into flash if it is beyond the end of flash. // if(ui32FlashAddr < g_ui32FlashEnd) { // // If this is the first block and we have been provided with a start // hook function, call it here to indicate that we are about to begin // flashing a new image. // #ifdef BL_START_FN_HOOK if(g_ui32TFTPBlock == 1) { BL_START_FN_HOOK(); } #endif // // Clear any flash error indicator. // BL_FLASH_CL_ERR_FN_HOOK(); // // If this is the first data packet and code protection is enabled, // then erase the entire flash. // #ifdef FLASH_CODE_PROTECTION if(g_ui32TFTPBlock == 1) { // // Loop through the pages in the flash, excluding the pages that // contain the boot loader and the optional reserved space. // for(ui32Idx = APP_START_ADDRESS; ui32Idx < g_ui32FlashEnd; ui32Idx += FLASH_PAGE_SIZE) { // // Erase this block of the flash. // BL_FLASH_ERASE_FN_HOOK((ui32Idx); } } #else // // Flash code protection is not enabled, so see if the data in this // packet will be programmed to the beginning of a flash block. We // assume that the flash block size is always a multiple of 1KB so, // since each TFTP packet is 512 bytes and that the start must always // be on a flash page boundary, we can be sure that we will hit the // start of each page as we receive packets. // if(!(ui32FlashAddr & (FLASH_PAGE_SIZE - 1))) { // // Erase this block of the flash. // BL_FLASH_ERASE_FN_HOOK(ui32FlashAddr); } #endif // // Decrypt the data if required. // #ifdef BL_DECRYPT_FN_HOOK BL_DECRYPT_FN_HOOK(pui8Packet + 4, uip_len - 4); #endif // // Program this block of data into flash. // BL_FLASH_PROGRAM_FN_HOOK(ui32FlashAddr, (pui8Packet + 4), (uip_len - 4)); // // If a progress reporting hook function has been provided, call it // here. The TFTP protocol doesn't let us know how large the image is // before it starts the transfer so we pass 0 as the ui32Total // parameter to indicate this. // #ifdef BL_PROGRESS_FN_HOOK BL_PROGRESS_FN_HOOK(((ui32FlashAddr - APP_START_ADDRESS) + (uip_len - 4)), 0); #endif } // // Increment to the next block. // g_ui32TFTPBlock++; // // Save the packet length. // ui32Idx = uip_len; // // Did we see any error? // if(BL_FLASH_ERROR_FN_HOOK()) { // // Yes - send back an error packet. // SendTFTPError(2, "Error programming flash."); } else { // // No errors reported so construct an ACK packet. The block number // field is already correct, so it does not need to be set. // pui8Packet[0] = (TFTP_ACK >> 8) & 0xff; pui8Packet[1] = TFTP_ACK & 0xff; // // Send the ACK packet to the TFTP server. // uip_udp_send(4); } // // If the packet was shorter than TFTP_BLOCK_SIZE bytes then this was the // last packet in the file. // if(ui32Idx != (TFTP_BLOCK_SIZE + 4)) { // // If an end signal hook function has been provided, call it here. // #ifdef BL_END_FN_HOOK BL_END_FN_HOOK(); #endif return(1); } // // There is more data to be read. // return(0); }
Hi Charles,
Thanks again, Those function calls helped me flash the new blinky.bin(a very basic binary-2 KB) file in the new location. I'm thinking two things now,
1. To boot my device from the binary section itslef (new programmed location) and alternate back to the first section if another firmware upgrade command is received.
2. Or copy the new binary to the APP_BASE from the boot loader.
What method would you suggest?
and correct me if I am wrong,I am guessing PC, Vector table and memory mapping would play a role and I should give boot loader the intelligence for that? Let me know the things to be taken care of.
Hi Mohammed,
Glad that you make great progress.
You have proven the second method and therefore, it may be easier for you to continue your development. I thought that you originally discarded the first method because the bootloader will not be able to support HTTP as you wanted to keep it simple and compact. If this is no longer the requirement - make the bootloader supporting http, I will even consider a third option - which is to bootload the same section instead of alternating between the application and binary sections. In another word, you will only have the bootloader and the application section similar to the TivaWare example but the difference is that your bootloader will support http. The benefit of doing so is that you can grow your application in size only limited by the flash size instead of only one half of the flash size.
If you look at the TivaWare bootloader, the vector table is fist copied to the RAM. When CPU receives an exception/interrupt it will jump to the vector table in the RAM. I think you should be fine if you are referencing the same method.
Hi Mohammed
I have not heard back from you. I hope you are making good progress with your project. I will close the thread for now. If you have new questions please open new thread. If your current issue is not resolved you can reply back here to reopen the thread.
Hi Charles,
Sorry that I couldn't reply, I am currently on implementing the proposed scheme. On using the boot_demo_emac_flash project as demo for pushing the device from Application to Bootloader. I took reference of the SoftwareUpdateBegin function, I am getting the following error on calling it from a task. What should be the way to proceed on this, is it because I am calling this function from a task.
SoftwareUpdateBegin(g_ui32SysClockFreq);
void SoftwareUpdateBegin(uint32_t ui32SysClock) { // // Disable all processor interrupts. Instead of disabling them // one at a time (and possibly missing an interrupt if new sources // are added), a direct write to NVIC is done to disable all // peripheral interrupts. // HWREG(NVIC_DIS0) = 0xffffffff; HWREG(NVIC_DIS1) = 0xffffffff; HWREG(NVIC_DIS2) = 0xffffffff; HWREG(NVIC_DIS3) = 0xffffffff; HWREG(NVIC_DIS4) = 0xffffffff; // // Also disable the SysTick interrupt. // SysTickIntDisable(); SysTickDisable(); // // Return control to the boot loader. This is a call to the SVC // handler in the flashed-based boot loader, or to the ROM if configured. // #if ((defined ROM_UpdateEMAC) && !(defined USE_FLASH_BOOT_LOADER)) ROM_UpdateEMAC(ui32SysClock); #else (*((void (*)(void))(*(uint32_t *)0x2c)))(); #endif }
00008.400 TcpTimeoutRexmt: Retransmit Timeout ti.sysbios.family.arm.m3.Hwi: line 1095: E_hardFault: FORCED ti.sysbios.family.arm.m3.Hwi: line 1140: E_memFault: IACCVIOL: Instruction Access Violation, address: e000ed34 Exception occurred in background thread at PC = 0xfffffffe. Core 0: Exception occurred in ThreadType_Task. Task name: {unknown-instance-name}, handle: 0x2002aa10. Task stack base: 0x20028120. Task stack size: 0x800. R0 = 0xffffffff R8 = 0xffffffff R1 = 0x00000000 R9 = 0xffffffff R2 = 0x00000000 R10 = 0xffffffff R3 = 0x2002b5bc R11 = 0xffffffff R4 = 0x0000028f R12 = 0x2002aec8 R5 = 0x0000ffff SP(R13) = 0x200287b8 R6 = 0xffffffff LR(R14) = 0x0001e643 R7 = 0xffffffff PC(R15) = 0xfffffffe PSR = 0x21000000 ICSR = 0x00400803 MMFSR = 0x01 BFSR = 0x00 UFSR = 0x0000 HFSR = 0x40000000 DFSR = 0x0000000b MMAR = 0xe000ed34 BFAR = 0xe000ed38 AFSR = 0x00000000 Terminating execution...