int SBL_Execute() { int retVal = NPI_LNX_SUCCESS; LOG_INFO("[SBL] Executing Serial Bootloader\n"); if (!sblImageBuf || (sblImageLen <= 0)) { LOG_ERROR("[SBL] No binary file found\n"); retVal = NPI_LNX_FAILURE; } else { int sbResult = 0; sblState = SBL_STATE_SERIAL_BOOT; sbResult = sbExec(sblImageBuf, sblImageLen); if (sbResult != 0) { npiMsgData_t pMsg; LOG_WARN("[SBL] Serial boot loader failed. Attempting hard reset\n"); // Trying again after a hard reset pMsg.len = 0; pMsg.subSys = RPC_SYS_SRV_CTRL | RPC_CMD_AREQ; pMsg.cmdId = NPI_LNX_CMD_ID_RESET_DEVICE; // Send command NPI_SendAsynchData( &pMsg ); // After a very short delay attempt again LOG_INFO("[SBL] Send Handshake command\n"); retVal = BOOT_HandshakeReq(); if (retVal != NPI_LNX_SUCCESS) { LOG_FATAL("[SBL] Serial boot loader failed. Please restart application.\n"); } else { // Try again retVal = sbExec(sblImageBuf, sblImageLen); } } } return retVal; }
/************************************************************************************************** * @fn sblExec * * @brief Infinite SBL execute loop that jumps upon receiving a code enable. * * input parameters * * None. * * output parameters * * None. * * @return None. ************************************************************************************************** */ static void sblExec(void) { uint32 dlyCnt = 0; while (1) { HalUARTPollUSB(); if (sbExec() && sbImgValid()) { SB_TURN_ON_LED1(); SB_TURN_ON_LED2(); // Delay to allow the SB_ENABLE_CMD response to be flushed. for (dlyCnt = 0; dlyCnt < 0x40000; dlyCnt++) { HalUARTPollUSB(); } sblJump(); } else if (dlyCnt++ & 0x4000) { SB_TOGGLE_LED1(); } } }
/************************************************************************************************** * @fn sblExec * * @brief Infinite SBL execute loop that returns upon receiving a code enable. * * input parameters * * None. * * output parameters * * None. * * @return None. ************************************************************************************************** */ static void sblExec(void) { uint32 dlyCnt = 0; uint8 sbExec_rc; sbReportState(SB_STATE_BOOTLOADER_ACTIVE); while (1) { sbUartPoll(); sbExec_rc = sbExec(); if (sbExec_rc == SB_CMND_ENABLE_STATE_REPORTING) { sbReportState(SB_STATE_BOOTLOADER_ACTIVE); } else if (sbExec_rc == SB_CMND_ENABLED_CMD_OK) { // Delay to allow the SB_ENABLE_CMD response to be flushed. for (dlyCnt = 0; dlyCnt < 0x40000; dlyCnt++) { sbUartPoll(); } break; } } }
/************************************************************************************************** * @fn sblExec * * @brief Infinite SBL execute loop that returns upon receiving a code enable. * * input parameters * * None. * * output parameters * * None. * * @return None. ************************************************************************************************** */ static void sblExec(void) { uint32 dlyCnt = 0; vddWait(VDD_MIN_NV); HAL_ENABLE_INTERRUPTS(); while (1) { if (dlyCnt++ & 0x4000) { SB_TOGGLE_LED1(); } HalUARTPollUSB(); if (sbExec()) { break; } } SB_TURN_ON_LED1(); SB_TURN_ON_LED2(); // Delay to allow the SB_ENABLE_CMD response to be flushed. for (dlyCnt = 0; dlyCnt < 0x40000; dlyCnt++) { HalUARTPollUSB(); } }
/************************************************************************************************** * @fn sblExec * * @brief Infinite SBL execute loop that returns upon receiving a code enable. * * input parameters * * None. * * output parameters * * None. * * @return None. ************************************************************************************************** */ static void sblExec(void) { uint32 dlyCnt = 0; uint8 sbExec_rc; if (znpCfg1 == ZNP_CFG1_UART) { URX0IE = 1; HAL_ENABLE_INTERRUPTS(); sbReportState(SB_STATE_BOOTLOADER_ACTIVE); } else { /* For preventing an unknown delay after sending SB_FORCE_BOOT and before being able to send SB_HANDSHAKE_CMD, this call was moved to the processing of SB_HANDSHAKE_CMD, which has an associated response (SB_FORCE_BOOT does not have any response). This change was required for the bootloader to work on the Alektrona gateway reference board. It was verified only with UART, so at the moment the behavior for SPI is left unchanged. */ vddWait(VDD_MIN_NV); } while (1) { if (znpCfg1 == ZNP_CFG1_UART) { sbUartPoll(); } sbExec_rc = sbExec(); if (sbExec_rc == SB_CMND_ENABLE_STATE_REPORTING) { sbReportState(SB_STATE_BOOTLOADER_ACTIVE); } else if (sbExec_rc == SB_CMND_ENABLED_CMD_OK) { // Delay to allow the SB_ENABLE_CMD response to be flushed. if (znpCfg1 == ZNP_CFG1_UART) { for (dlyCnt = 0; dlyCnt < 0x40000; dlyCnt++) { sbUartPoll(); } URX0IE = 0; } break; } } }
/************************************************************************************************** * @fn sblWait * * @brief A timed-out wait loop that exits early upon receiving a force code/sbl byte. * * input parameters * * None. * * output parameters * * None. * * @return TRUE to run the code image, FALSE to run the SBL. ************************************************************************************************** */ static uint8 sblWait(uint16 sbl_wait_time) { uint32 dlyCnt; uint8 rtrn = FALSE; uint8 sbExec_rc; dlyCnt = (uint32)0x7332 * sbl_wait_time; //0x7332 gives about 1 second sbReportState(SB_STATE_WAITING); while (1) { sbUartPoll(); sbExec_rc = sbExec(); if (sbExec_rc == SB_CMND_ENABLE_STATE_REPORTING) { sbReportState(SB_STATE_WAITING); } else if ((sbExec_rc == SB_CMND_FORCE_RUN) || (SB2_PRESS)) { dlyCnt = 0; } else if (((sbExec_rc != SB_CMND_IDLE) && (sbExec_rc != SB_CMND_UNSUPPORTED)) || (SB1_PRESS)) { break; } if (dlyCnt-- == 0) { rtrn = TRUE; break; } } return rtrn; }
/************************************************************************************************** * @fn sblWait * * @brief A timed-out wait loop that exits early upon receiving a force code/sbl byte. * * input parameters * * None. * * output parameters * * None. * * @return TRUE to run the code image, FALSE to run the SBL. ************************************************************************************************** */ static uint8 sblWait(uint16 sbl_wait_time) { uint32 dlyCnt; uint8 rtrn = FALSE; uint8 sbExec_rc; uint8 ch; if (znpCfg1 == ZNP_CFG1_SPI) { // Slave signals ready for read by setting its ready flag first. SRDY_SET(); // Flag to sbRx() to poll for 1 Rx byte instead of blocking read until MRDY_CLR. spiPoll = TRUE; dlyCnt = 0x38; // About 50 msecs. } else { URX0IE = 1; HAL_ENABLE_INTERRUPTS(); dlyCnt = (uint32)0x7332 * sbl_wait_time; //0x7332 gives about 1 second sbReportState(SB_STATE_WAITING); } while (1) { if (znpCfg1 == ZNP_CFG1_UART) { sbUartPoll(); sbExec_rc = sbExec(); if (sbExec_rc == SB_CMND_ENABLE_STATE_REPORTING) { sbReportState(SB_STATE_WAITING); } else if (sbExec_rc == SB_CMND_FORCE_RUN) { dlyCnt = 0; } else if ((sbExec_rc != SB_CMND_IDLE) && (sbExec_rc != SB_CMND_UNSUPPORTED)) { break; } } else // Note: the SPI implementation was left unchanged, since the new implementation // (as implemented for the UART) was not tested with SPI at this time. { if (sbRx(&ch, 1)) { if (ch == SB_FORCE_BOOT) { break; } else if (ch == SB_FORCE_RUN) { dlyCnt = 0; } } } if (dlyCnt-- == 0) { rtrn = TRUE; break; } } if (znpCfg1 == ZNP_CFG1_SPI) { // Master blocks waiting for slave to clear its ready flag before continuing. SRDY_CLR(); // Flag to sbRx() to now block while reading Rx bytes until MRDY_CLR. spiPoll = FALSE; } else { HAL_DISABLE_INTERRUPTS(); URX0IE = 0; } return rtrn; }