From 4085ae3ddfbbf10c8ccbd3dccd43452c40a1fe40 Mon Sep 17 00:00:00 2001 From: Yuval Adam Date: Fri, 13 Mar 2015 12:24:52 +0200 Subject: Add bootloader, nfclib and sensorlib --- boot_loader/bl_main.c | 913 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 913 insertions(+) create mode 100644 boot_loader/bl_main.c (limited to 'boot_loader/bl_main.c') diff --git a/boot_loader/bl_main.c b/boot_loader/bl_main.c new file mode 100644 index 0000000..fbb7275 --- /dev/null +++ b/boot_loader/bl_main.c @@ -0,0 +1,913 @@ +//***************************************************************************** +// +// bl_main.c - The file holds the main control loop of the boot loader. +// +// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved. +// Software License Agreement +// +// Texas Instruments (TI) is supplying this software for use solely and +// exclusively on TI's microcontroller products. The software is owned by +// TI and/or its suppliers, and is protected under applicable copyright +// laws. You may not combine this software with "viral" open-source +// software in order to form a larger program. +// +// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. +// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT +// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY +// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL +// DAMAGES, FOR ANY REASON WHATSOEVER. +// +// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package. +// +//***************************************************************************** + +#include +#include +#include "inc/hw_gpio.h" +#include "inc/hw_flash.h" +#include "inc/hw_i2c.h" +#include "inc/hw_memmap.h" +#include "inc/hw_nvic.h" +#include "inc/hw_ssi.h" +#include "inc/hw_sysctl.h" +#include "inc/hw_types.h" +#include "inc/hw_uart.h" +#include "bl_config.h" +#include "boot_loader/bl_commands.h" +#include "boot_loader/bl_decrypt.h" +#include "boot_loader/bl_flash.h" +#include "boot_loader/bl_hooks.h" +#include "boot_loader/bl_i2c.h" +#include "boot_loader/bl_packet.h" +#include "boot_loader/bl_ssi.h" +#include "boot_loader/bl_uart.h" +#ifdef CHECK_CRC +#include "boot_loader/bl_crc32.h" +#endif + +//***************************************************************************** +// +// Make sure that the application start address falls on a flash page boundary +// +//***************************************************************************** +#if (APP_START_ADDRESS & (FLASH_PAGE_SIZE - 1)) +#error ERROR: APP_START_ADDRESS must be a multiple of FLASH_PAGE_SIZE bytes! +#endif + +//***************************************************************************** +// +// Make sure that the flash reserved space is a multiple of flash pages. +// +//***************************************************************************** +#if (FLASH_RSVD_SPACE & (FLASH_PAGE_SIZE - 1)) +#error ERROR: FLASH_RSVD_SPACE must be a multiple of FLASH_PAGE_SIZE bytes! +#endif + +//***************************************************************************** +// +//! \addtogroup bl_main_api +//! @{ +// +//***************************************************************************** +#if defined(I2C_ENABLE_UPDATE) || defined(SSI_ENABLE_UPDATE) || \ + defined(UART_ENABLE_UPDATE) || defined(DOXYGEN) + +//***************************************************************************** +// +// A prototype for the function (in the startup code) for calling the +// application. +// +//***************************************************************************** +extern void CallApplication(uint32_t ui32Base); + +//***************************************************************************** +// +// A prototype for the function (in the startup code) for a predictable length +// delay. +// +//***************************************************************************** +extern void Delay(uint32_t ui32Count); + +//***************************************************************************** +// +// Holds the current status of the last command that was issued to the boot +// loader. +// +//***************************************************************************** +uint8_t g_ui8Status; + +//***************************************************************************** +// +// This holds the current remaining size in bytes to be downloaded. +// +//***************************************************************************** +uint32_t g_ui32TransferSize; + +//***************************************************************************** +// +// This holds the total size of the firmware image being downloaded (if the +// protocol in use provides this). +// +//***************************************************************************** +#if (defined BL_PROGRESS_FN_HOOK) || (defined CHECK_CRC) +uint32_t g_ui32ImageSize; +#endif + +//***************************************************************************** +// +// This holds the current address that is being written to during a download +// command. +// +//***************************************************************************** +uint32_t g_ui32TransferAddress; +#ifdef CHECK_CRC +uint32_t g_ui32ImageAddress; +#endif + +//***************************************************************************** +// +// This is the data buffer used during transfers to the boot loader. +// +//***************************************************************************** +uint32_t g_pui32DataBuffer[BUFFER_SIZE]; + +//***************************************************************************** +// +// This is an specially aligned buffer pointer to g_pui32DataBuffer to make +// copying to the buffer simpler. It must be offset to end on an address that +// ends with 3. +// +//***************************************************************************** +uint8_t *g_pui8DataBuffer; + +//***************************************************************************** +// +// Converts a word from big endian to little endian. This macro uses compiler- +// specific constructs to perform an inline insertion of the "rev" instruction, +// which performs the byte swap directly. +// +//***************************************************************************** +#if defined(ewarm) +#include +#define SwapWord(x) __REV(x) +#endif +#if defined(codered) || defined(gcc) || defined(sourcerygxx) +#define SwapWord(x) __extension__ \ + ({ \ + register uint32_t __ret, __inp = x; \ + __asm__("rev %0, %1" : "=r" (__ret) : "r" (__inp)); \ + __ret; \ + }) +#endif +#if defined(rvmdk) || defined(__ARMCC_VERSION) +#define SwapWord(x) __rev(x) +#endif +#if defined(ccs) +uint32_t +SwapWord(uint32_t x) +{ + __asm(" rev r0, r0\n" + " bx lr\n"); // need this to make sure r0 is returned + return(x + 1); // return makes compiler happy - ignored +} +#endif + +//***************************************************************************** +// +//! Configures the microcontroller. +//! +//! This function configures the peripherals and GPIOs of the microcontroller, +//! preparing it for use by the boot loader. The interface that has been +//! selected as the update port will be configured, and auto-baud will be +//! performed if required. +//! +//! \return None. +// +//***************************************************************************** +void +ConfigureDevice(void) +{ +#ifdef UART_ENABLE_UPDATE + uint32_t ui32ProcRatio; +#endif + +#ifdef CRYSTAL_FREQ + // + // Since the crystal frequency was specified, enable the main oscillator + // and clock the processor from it. + // + HWREG(SYSCTL_RCC) &= ~(SYSCTL_RCC_MOSCDIS); + Delay(524288); + HWREG(SYSCTL_RCC) = ((HWREG(SYSCTL_RCC) & ~(SYSCTL_RCC_OSCSRC_M)) | + SYSCTL_RCC_OSCSRC_MAIN); +#endif + +#ifdef I2C_ENABLE_UPDATE + // + // Enable the clocks to the I2C and GPIO modules. + // + HWREG(SYSCTL_RCGC2) |= SYSCTL_RCGC2_GPIOB; + HWREG(SYSCTL_RCGC1) |= SYSCTL_RCGC1_I2C0; + + // + // Configure the GPIO pins for hardware control, open drain with pull-up, + // and enable them. + // + HWREG(GPIO_PORTB_BASE + GPIO_O_AFSEL) |= (1 << 7) | I2C_PINS; + HWREG(GPIO_PORTB_BASE + GPIO_O_DEN) |= (1 << 7) | I2C_PINS; + HWREG(GPIO_PORTB_BASE + GPIO_O_ODR) |= I2C_PINS; + + // + // Enable the I2C Slave Mode. + // + HWREG(I2C0_BASE + I2C_O_MCR) = I2C_MCR_MFE | I2C_MCR_SFE; + + // + // Setup the I2C Slave Address. + // + HWREG(I2C0_BASE + I2C_O_SOAR) = I2C_SLAVE_ADDR; + + // + // Enable the I2C Slave Device on the I2C bus. + // + HWREG(I2C0_BASE + I2C_O_SCSR) = I2C_SCSR_DA; +#endif + +#ifdef SSI_ENABLE_UPDATE + // + // Enable the clocks to the SSI and GPIO modules. + // + HWREG(SYSCTL_RCGC2) |= SYSCTL_RCGC2_GPIOA; + HWREG(SYSCTL_RCGC1) |= SYSCTL_RCGC1_SSI0; + + // + // Make the pin be peripheral controlled. + // + HWREG(GPIO_PORTA_BASE + GPIO_O_AFSEL) |= SSI_PINS; + HWREG(GPIO_PORTA_BASE + GPIO_O_DEN) |= SSI_PINS; + + // + // Set the SSI protocol to Motorola with default clock high and data + // valid on the rising edge. + // + HWREG(SSI0_BASE + SSI_O_CR0) = (SSI_CR0_SPH | SSI_CR0_SPO | + (DATA_BITS_SSI - 1)); + + // + // Enable the SSI interface in slave mode. + // + HWREG(SSI0_BASE + SSI_O_CR1) = SSI_CR1_MS | SSI_CR1_SSE; +#endif + +#ifdef UART_ENABLE_UPDATE + // + // Enable the the clocks to the UART and GPIO modules. + // + HWREG(SYSCTL_RCGC2) |= SYSCTL_RCGC2_GPIOA; + HWREG(SYSCTL_RCGC1) |= SYSCTL_RCGC1_UART0; + + // + // Keep attempting to sync until we are successful. + // +#ifdef UART_AUTOBAUD + while(UARTAutoBaud(&ui32ProcRatio) < 0) + { + } +#else + ui32ProcRatio = UART_BAUD_RATIO(UART_FIXED_BAUDRATE); +#endif + + // + // Set GPIO A0 and A1 as UART pins. + // + HWREG(GPIO_PORTA_BASE + GPIO_O_AFSEL) |= UART_PINS; + + // + // Set the pin type. + // + HWREG(GPIO_PORTA_BASE + GPIO_O_DEN) |= UART_PINS; + + // + // Set the baud rate. + // + HWREG(UART0_BASE + UART_O_IBRD) = ui32ProcRatio >> 6; + HWREG(UART0_BASE + UART_O_FBRD) = ui32ProcRatio & UART_FBRD_DIVFRAC_M; + + // + // Set data length, parity, and number of stop bits to 8-N-1. + // + HWREG(UART0_BASE + UART_O_LCRH) = UART_LCRH_WLEN_8 | UART_LCRH_FEN; + + // + // Enable RX, TX, and the UART. + // + HWREG(UART0_BASE + UART_O_CTL) = (UART_CTL_UARTEN | UART_CTL_TXE | + UART_CTL_RXE); + +#ifdef UART_AUTOBAUD + // + // Need to ack in the UART case to hold it up while we get things set up. + // + AckPacket(); +#endif +#endif +} + +//***************************************************************************** +// +//! This function performs the update on the selected port. +//! +//! This function is called directly by the boot loader or it is called as a +//! result of an update request from the application. +//! +//! \return Never returns. +// +//***************************************************************************** +void +Updater(void) +{ + uint32_t ui32Size, ui32Temp, ui32FlashSize; +#ifdef CHECK_CRC + uint32_t ui32Retcode; +#endif + + // + // This ensures proper alignment of the global buffer so that the one byte + // size parameter used by the packetized format is easily skipped for data + // transfers. + // + g_pui8DataBuffer = ((uint8_t *)g_pui32DataBuffer) + 3; + + // + // Insure that the COMMAND_SEND_DATA cannot be sent to erase the boot + // loader before the application is erased. + // + g_ui32TransferAddress = 0xffffffff; + + // + // Read any data from the serial port in use. + // + while(1) + { + // + // Receive a packet from the port in use. + // + ui32Size = sizeof(g_pui32DataBuffer) - 3; + if(ReceivePacket(g_pui8DataBuffer, &ui32Size) != 0) + { + continue; + } + + // + // The first byte of the data buffer has the command and determines + // the format of the rest of the bytes. + // + switch(g_pui8DataBuffer[0]) + { + // + // This was a simple ping command. + // + case COMMAND_PING: + { + // + // This command always sets the status to COMMAND_RET_SUCCESS. + // + g_ui8Status = COMMAND_RET_SUCCESS; + + // + // Just acknowledge that the command was received. + // + AckPacket(); + + // + // Go back and wait for a new command. + // + break; + } + + // + // This command indicates the start of a download sequence. + // + case COMMAND_DOWNLOAD: + { + // + // Until determined otherwise, the command status is success. + // + g_ui8Status = COMMAND_RET_SUCCESS; + + // + // A simple do/while(0) control loop to make error exits + // easier. + // + do + { + // + // See if a full packet was received. + // + if(ui32Size != 9) + { + // + // Indicate that an invalid command was received. + // + g_ui8Status = COMMAND_RET_INVALID_CMD; + + // + // This packet has been handled. + // + break; + } + + // + // Get the address and size from the command. + // + g_ui32TransferAddress = SwapWord(g_pui32DataBuffer[1]); + g_ui32TransferSize = SwapWord(g_pui32DataBuffer[2]); + + // + // Depending upon the build options set, keep a copy of + // the original size and start address because we will need + // these later. + // +#if (defined BL_PROGRESS_FN_HOOK) || (defined CHECK_CRC) + g_ui32ImageSize = g_ui32TransferSize; +#endif +#ifdef CHECK_CRC + g_ui32ImageAddress = g_ui32TransferAddress; +#endif + + // + // Check for a valid starting address and image size. + // + if(!BL_FLASH_AD_CHECK_FN_HOOK(g_ui32TransferAddress, + g_ui32TransferSize)) + { + // + // Set the code to an error to indicate that the last + // command failed. This informs the updater program + // that the download command failed. + // + g_ui8Status = COMMAND_RET_INVALID_ADR; + + // + // This packet has been handled. + // + break; + } + + + // + // Only erase the space that we need if we are not + // protecting the code, otherwise erase the entire flash. + // +#ifdef FLASH_CODE_PROTECTION + ui32FlashSize = BL_FLASH_SIZE_FN_HOOK(); +#ifdef FLASH_RSVD_SPACE + if((ui32FlashSize - FLASH_RSVD_SPACE) != + g_ui32TransferAddress) + { + ui32FlashSize -= FLASH_RSVD_SPACE; + } +#endif +#else + ui32FlashSize = g_ui32TransferAddress + g_ui32TransferSize; +#endif + + // + // Clear the flash access interrupt. + // + BL_FLASH_CL_ERR_FN_HOOK(); + + // + // Leave the boot loader present until we start getting an + // image. + // + for(ui32Temp = g_ui32TransferAddress; + ui32Temp < ui32FlashSize; ui32Temp += FLASH_PAGE_SIZE) + { + // + // Erase this block. + // + BL_FLASH_ERASE_FN_HOOK(ui32Temp); + } + + // + // Return an error if an access violation occurred. + // + if(BL_FLASH_ERROR_FN_HOOK()) + { + g_ui8Status = COMMAND_RET_FLASH_FAIL; + } + } + while(0); + + // + // See if the command was successful. + // + if(g_ui8Status != COMMAND_RET_SUCCESS) + { + // + // Setting g_ui32TransferSize to zero makes + // COMMAND_SEND_DATA fail to accept any data. + // + g_ui32TransferSize = 0; + } + + // + // Acknowledge that this command was received correctly. This + // does not indicate success, just that the command was + // received. + // + AckPacket(); + + // + // If we have a start notification hook function, call it + // now if everything is OK. + // +#ifdef BL_START_FN_HOOK + if(g_ui32TransferSize) + { + BL_START_FN_HOOK(); + } +#endif + + // + // Go back and wait for a new command. + // + break; + } + + // + // This command indicates that control should be transferred to + // the specified address. + // + case COMMAND_RUN: + { + // + // Acknowledge that this command was received correctly. This + // does not indicate success, just that the command was + // received. + // + AckPacket(); + + // + // See if a full packet was received. + // + if(ui32Size != 5) + { + // + // Indicate that an invalid command was received. + // + g_ui8Status = COMMAND_RET_INVALID_CMD; + + // + // This packet has been handled. + // + break; + } + + // + // Get the address to which control should be transferred. + // + g_ui32TransferAddress = SwapWord(g_pui32DataBuffer[1]); + + // + // This determines the size of the flash available on the + // device in use. + // + ui32FlashSize = BL_FLASH_SIZE_FN_HOOK(); + + // + // Test if the transfer address is valid for this device. + // + if(g_ui32TransferAddress >= ui32FlashSize) + { + // + // Indicate that an invalid address was specified. + // + g_ui8Status = COMMAND_RET_INVALID_ADR; + + // + // This packet has been handled. + // + break; + } + + // + // Make sure that the ACK packet has been sent. + // + FlushData(); + + // + // Reset and disable the peripherals used by the boot loader. + // +#ifdef I2C_ENABLE_UPDATE + HWREG(SYSCTL_RCGC1) &= ~SYSCTL_RCGC1_I2C0; + HWREG(SYSCTL_SRCR1) = SYSCTL_SRCR1_I2C0; +#endif +#ifdef UART_ENABLE_UPDATE + HWREG(SYSCTL_RCGC1) &= ~SYSCTL_RCGC1_UART0; + HWREG(SYSCTL_SRCR1) = SYSCTL_SRCR1_UART0; +#endif +#ifdef SSI_ENABLE_UPDATE + HWREG(SYSCTL_RCGC1) &= ~SYSCTL_RCGC1_SSI0; + HWREG(SYSCTL_SRCR1) = SYSCTL_SRCR1_SSI0; +#endif + HWREG(SYSCTL_SRCR1) = 0; + + // + // Branch to the specified address. This should never return. + // If it does, very bad things will likely happen since it is + // likely that the copy of the boot loader in SRAM will have + // been overwritten. + // + ((void (*)(void))g_ui32TransferAddress)(); + + // + // In case this ever does return and the boot loader is still + // intact, simply reset the device. + // + HWREG(NVIC_APINT) = (NVIC_APINT_VECTKEY | + NVIC_APINT_SYSRESETREQ); + + // + // The microcontroller should have reset, so this should + // never be reached. Just in case, loop forever. + // + while(1) + { + } + } + + // + // This command just returns the status of the last command that + // was sent. + // + case COMMAND_GET_STATUS: + { + // + // Acknowledge that this command was received correctly. This + // does not indicate success, just that the command was + // received. + // + AckPacket(); + + // + // Return the status to the updater. + // + SendPacket(&g_ui8Status, 1); + + // + // Go back and wait for a new command. + // + break; + } + + // + // This command is sent to transfer data to the device following + // a download command. + // + case COMMAND_SEND_DATA: + { + // + // Until determined otherwise, the command status is success. + // + g_ui8Status = COMMAND_RET_SUCCESS; + + // + // If this is overwriting the boot loader then the application + // has already been erased so now erase the boot loader. + // + if(g_ui32TransferAddress == 0) + { + // + // Clear the flash access interrupt. + // + BL_FLASH_CL_ERR_FN_HOOK(); + + // + // Erase the boot loader. + // + for(ui32Temp = 0; ui32Temp < APP_START_ADDRESS; + ui32Temp += FLASH_PAGE_SIZE) + { + // + // Erase this block. + // + BL_FLASH_ERASE_FN_HOOK(ui32Temp); + } + + // + // Return an error if an access violation occurred. + // + if(BL_FLASH_ERROR_FN_HOOK()) + { + // + // Setting g_ui32TransferSize to zero makes + // COMMAND_SEND_DATA fail to accept any more data. + // + g_ui32TransferSize = 0; + + // + // Indicate that the flash erase failed. + // + g_ui8Status = COMMAND_RET_FLASH_FAIL; + } + } + + // + // Take one byte off for the command. + // + ui32Size = ui32Size - 1; + + // + // Check if there are any more bytes to receive. + // + if(g_ui32TransferSize >= ui32Size) + { + // + // If we have been provided with a decryption hook function + // call it here. + // +#ifdef BL_DECRYPT_FN_HOOK + BL_DECRYPT_FN_HOOK(g_pui8DataBuffer + 1, ui32Size); +#endif + + // + // Write this block of data to the flash + // + BL_FLASH_PROGRAM_FN_HOOK(g_ui32TransferAddress, + (uint8_t *) &g_pui32DataBuffer[1], + ((ui32Size + 3) & ~3)); + + // + // Return an error if an access violation occurred. + // + if(BL_FLASH_ERROR_FN_HOOK()) + { + // + // Indicate that the flash programming failed. + // + g_ui8Status = COMMAND_RET_FLASH_FAIL; + } + else + { + // + // Now update the address to program. + // + g_ui32TransferSize -= ui32Size; + g_ui32TransferAddress += ui32Size; + + // + // If a progress hook function has been provided, call + // it here. + // +#ifdef BL_PROGRESS_FN_HOOK + BL_PROGRESS_FN_HOOK(g_ui32ImageSize - + g_ui32TransferSize, + g_ui32ImageSize); +#endif + +#ifdef CHECK_CRC + // + // If we've reached the end, check the CRC in the + // image to determine whether or not we report an error + // back to the host. + // + if(g_ui32TransferSize == 0) + { + InitCRC32Table(); + ui32Retcode = CheckImageCRC32( + (uint32_t *)g_ui32ImageAddress); + + // + // Was the CRC good? We consider the CRC good if + // the header is found and the embedded CRC matches + // the calculated value or, if ENFORCE_CRC is not + // defined, if the header exists but is unpopulated. + // +#ifdef ENFORCE_CRC + if(ui32Retcode == CHECK_CRC_OK) +#else + if((ui32Retcode == CHECK_CRC_OK) || + (ui32Retcode == CHECK_CRC_NO_LENGTH)) +#endif + { + // + // The calculated CRC didn't match the expected + // value or the image didn't contain an embedded + // CRC. + // + g_ui8Status = COMMAND_RET_SUCCESS; + } + else + { + // + // The calculated CRC agreed with the embedded + // value. + // + g_ui8Status = COMMAND_RET_CRC_FAIL; + } + } +#endif + } + } + else + { + // + // This indicates that too much data is being sent to the + // device. + // + g_ui8Status = COMMAND_RET_INVALID_ADR; + } + + // + // Acknowledge that this command was received correctly. This + // does not indicate success, just that the command was + // received. + // + AckPacket(); + + // + // If we have an end notification hook function, and we've + // reached the end, call it now. + // +#ifdef BL_END_FN_HOOK + if(g_ui32TransferSize == 0) + { + BL_END_FN_HOOK(); + } +#endif + + // + // Go back and wait for a new command. + // + break; + } + + // + // This command is used to reset the device. + // + case COMMAND_RESET: + { + // + // Send out a one-byte ACK to ensure the byte goes back to the + // host before we reset everything. + // + AckPacket(); + + // + // Make sure that the ACK packet has been sent. + // + FlushData(); + + // + // Perform a software reset request. This will cause the + // microcontroller to reset; no further code will be executed. + // + HWREG(NVIC_APINT) = (NVIC_APINT_VECTKEY | + NVIC_APINT_SYSRESETREQ); + + // + // The microcontroller should have reset, so this should never + // be reached. Just in case, loop forever. + // + while(1) + { + } + } + + // + // Just acknowledge the command and set the error to indicate that + // a bad command was sent. + // + default: + { + // + // Acknowledge that this command was received correctly. This + // does not indicate success, just that the command was + // received. + // + AckPacket(); + + // + // Indicate that a bad comand was sent. + // + g_ui8Status = COMMAND_RET_UNKNOWN_CMD; + + // + // Go back and wait for a new command. + // + break; + } + } + } +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** +#endif -- cgit v1.3.1