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_autobaud.c | 279 +++++ boot_loader/bl_can.c | 1403 ++++++++++++++++++++++ boot_loader/bl_can.h | 64 + boot_loader/bl_can_timing.h | 241 ++++ boot_loader/bl_check.c | 266 +++++ boot_loader/bl_check.h | 39 + boot_loader/bl_commands.h | 242 ++++ boot_loader/bl_config.c | 164 +++ boot_loader/bl_config.h.tmpl | 950 +++++++++++++++ boot_loader/bl_crc32.c | 267 +++++ boot_loader/bl_crc32.h | 49 + boot_loader/bl_crystal.h | 79 ++ boot_loader/bl_decrypt.c | 64 + boot_loader/bl_decrypt.h | 35 + boot_loader/bl_emac.c | 1914 ++++++++++++++++++++++++++++++ boot_loader/bl_flash.c | 218 ++++ boot_loader/bl_flash.h | 127 ++ boot_loader/bl_hooks.h | 72 ++ boot_loader/bl_i2c.c | 149 +++ boot_loader/bl_i2c.h | 70 ++ boot_loader/bl_link.icf | 83 ++ boot_loader/bl_link.ld | 51 + boot_loader/bl_link.sct | 45 + boot_loader/bl_link_ccs.cmd | 63 + boot_loader/bl_main.c | 913 ++++++++++++++ boot_loader/bl_packet.c | 295 +++++ boot_loader/bl_packet.h | 37 + boot_loader/bl_ssi.c | 161 +++ boot_loader/bl_ssi.h | 92 ++ boot_loader/bl_startup_ccs.s | 645 ++++++++++ boot_loader/bl_startup_ewarm.S | 612 ++++++++++ boot_loader/bl_startup_gcc.S | 630 ++++++++++ boot_loader/bl_startup_rvmdk.S | 653 ++++++++++ boot_loader/bl_startup_sourcerygxx.S | 630 ++++++++++ boot_loader/bl_uart.c | 156 +++ boot_loader/bl_uart.h | 81 ++ boot_loader/bl_usb.c | 2166 ++++++++++++++++++++++++++++++++++ boot_loader/bl_usbfuncs.c | 1915 ++++++++++++++++++++++++++++++ boot_loader/bl_usbfuncs.h | 505 ++++++++ boot_loader/readme.txt | 28 + boot_loader/uip-conf.h | 108 ++ boot_loader/usbdfu.h | 420 +++++++ 42 files changed, 16981 insertions(+) create mode 100644 boot_loader/bl_autobaud.c create mode 100644 boot_loader/bl_can.c create mode 100644 boot_loader/bl_can.h create mode 100644 boot_loader/bl_can_timing.h create mode 100644 boot_loader/bl_check.c create mode 100644 boot_loader/bl_check.h create mode 100644 boot_loader/bl_commands.h create mode 100644 boot_loader/bl_config.c create mode 100644 boot_loader/bl_config.h.tmpl create mode 100644 boot_loader/bl_crc32.c create mode 100644 boot_loader/bl_crc32.h create mode 100644 boot_loader/bl_crystal.h create mode 100644 boot_loader/bl_decrypt.c create mode 100644 boot_loader/bl_decrypt.h create mode 100644 boot_loader/bl_emac.c create mode 100644 boot_loader/bl_flash.c create mode 100644 boot_loader/bl_flash.h create mode 100644 boot_loader/bl_hooks.h create mode 100644 boot_loader/bl_i2c.c create mode 100644 boot_loader/bl_i2c.h create mode 100644 boot_loader/bl_link.icf create mode 100644 boot_loader/bl_link.ld create mode 100644 boot_loader/bl_link.sct create mode 100644 boot_loader/bl_link_ccs.cmd create mode 100644 boot_loader/bl_main.c create mode 100644 boot_loader/bl_packet.c create mode 100644 boot_loader/bl_packet.h create mode 100644 boot_loader/bl_ssi.c create mode 100644 boot_loader/bl_ssi.h create mode 100644 boot_loader/bl_startup_ccs.s create mode 100644 boot_loader/bl_startup_ewarm.S create mode 100644 boot_loader/bl_startup_gcc.S create mode 100644 boot_loader/bl_startup_rvmdk.S create mode 100644 boot_loader/bl_startup_sourcerygxx.S create mode 100644 boot_loader/bl_uart.c create mode 100644 boot_loader/bl_uart.h create mode 100644 boot_loader/bl_usb.c create mode 100644 boot_loader/bl_usbfuncs.c create mode 100644 boot_loader/bl_usbfuncs.h create mode 100644 boot_loader/readme.txt create mode 100644 boot_loader/uip-conf.h create mode 100644 boot_loader/usbdfu.h (limited to 'boot_loader') diff --git a/boot_loader/bl_autobaud.c b/boot_loader/bl_autobaud.c new file mode 100644 index 0000000..1600c71 --- /dev/null +++ b/boot_loader/bl_autobaud.c @@ -0,0 +1,279 @@ +//***************************************************************************** +// +// bl_autobaud.c - Automatic baud rate detection code. +// +// 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 "inc/hw_gpio.h" +#include "inc/hw_memmap.h" +#include "inc/hw_nvic.h" +#include "inc/hw_types.h" +#include "bl_config.h" +#include "boot_loader/bl_uart.h" + +//***************************************************************************** +// +// If using auto-baud, make sure that the data buffer is large enough. +// +//***************************************************************************** +#if defined(UART_ENABLE_UPDATE) && defined(UART_AUTOBAUD) && (BUFFER_SIZE < 20) +#error ERROR: BUFFER_SIZE must be >= 20! +#endif + +//***************************************************************************** +// +//! \addtogroup bl_autobaud_api +//! @{ +// +//***************************************************************************** +#if defined(UART_ENABLE_UPDATE) && defined(UART_AUTOBAUD) || defined(DOXYGEN) + +//***************************************************************************** +// +// This define holds the multiplier for the pulse detection algorithm. The +// value is used to generate a fractional difference detection of +// 1 / PULSE_DETECTION_MULT. +// +//***************************************************************************** +#define PULSE_DETECTION_MULT 3 + +//***************************************************************************** +// +// This define holds the minimum number of edges to successfully sync to a +// pattern of 2 bytes. +// +//***************************************************************************** +#define MIN_EDGE_COUNT 18 + +//***************************************************************************** +// +// This global holds the number of edges that have been stored in the global +// buffer g_pui32DataBuffer. +// +//***************************************************************************** +static volatile uint32_t g_ui32TickIndex; + +//***************************************************************************** +// +// The data buffer that is used for receiving packets is used to hold the edge +// times during auto-baud. The buffer is not used for receiving packets while +// auto-baud is in progress, so this does not present problems. +// +//***************************************************************************** +extern uint32_t g_pui32DataBuffer[]; + +//***************************************************************************** +// +//! Handles the UART Rx GPIO interrupt. +//! +//! When an edge is detected on the UART Rx pin, this function is called to +//! save the time of the edge. These times are later used to determine the +//! ratio of the UART baud rate to the processor clock rate. +//! +//! \return None. +// +//***************************************************************************** +void +GPIOIntHandler(void) +{ + uint32_t ui32Temp; + + // + // Clear the GPIO interrupt source. + // + HWREG(GPIO_PORTA_BASE + GPIO_O_ICR) = UART_RX; + + // + // While we still have space in our buffer, store the current system tick + // count and return from interrupt. + // + if(g_ui32TickIndex < 20) + { + ui32Temp = HWREG(NVIC_ST_CURRENT); + g_pui32DataBuffer[g_ui32TickIndex++] = ui32Temp; + } +} + +//***************************************************************************** +// +//! Performs auto-baud on the UART port. +//! +//! \param pui32Ratio is the ratio of the processor's crystal frequency to the +//! baud rate being used by the UART port for communications. +//! +//! This function attempts to synchronize to the updater program that is trying +//! to communicate with the boot loader. The UART port is monitored for edges +//! using interrupts. Once enough edges are detected, the boot loader +//! determines the ratio of baud rate and crystal frequency needed to program +//! the UART. +//! +//! \return Returns a value of 0 to indicate that this call successfully +//! synchronized with the other device communicating over the UART, and a +//! negative value to indicate that this function did not successfully +//! synchronize with the other UART device. +// +//***************************************************************************** +int +UARTAutoBaud(uint32_t *pui32Ratio) +{ + int32_t i32Pulse, i32ValidPulses, i32Temp, i32Total; + volatile int32_t i32Delay; + + // + // Configure and enable SysTick. Set the reload value to the maximum; + // there are only 24 bits in the register but loading 32 bits of ones is + // more efficient. + // + HWREG(NVIC_ST_RELOAD) = 0xffffffff; + HWREG(NVIC_ST_CTRL) = NVIC_ST_CTRL_CLK_SRC | NVIC_ST_CTRL_ENABLE; + + // + // Reset the counters that control the pulse detection. + // + i32ValidPulses = 0; + i32Total = 0; + g_ui32TickIndex = 0; + + // + // Set the pad(s) for standard push-pull operation. + // + HWREG(GPIO_PORTA_BASE + GPIO_O_PUR) |= UART_RX; + HWREG(GPIO_PORTA_BASE + GPIO_O_DEN) |= UART_RX; + + // + // Interrupt on both edges. + // + HWREG(GPIO_PORTA_BASE + GPIO_O_IBE) = UART_RX; + + // + // Clear out all of the gpio interrupts in this register. + // + HWREG(GPIO_PORTA_BASE + GPIO_O_ICR) = UART_RX; + + // + // Enable the GPIO pin corresponding to the UART RX pin. + // + HWREG(GPIO_PORTA_BASE + GPIO_O_IM) = UART_RX; + + // + // Enable GPIOA Interrupt. + // + HWREG(NVIC_EN0) = 1; + + // + // Wait for MIN_EDGE_COUNT to pass to collect enough edges. + // + while(g_ui32TickIndex < MIN_EDGE_COUNT) + { + } + + // + // Disable GPIOA Interrupt. + // + HWREG(NVIC_DIS0) = 1; + + // + // Calculate the pulse widths from the array of tick times. + // + for(i32Pulse = 0; i32Pulse < (MIN_EDGE_COUNT - 1); i32Pulse++) + { + i32Temp = (((int32_t)g_pui32DataBuffer[i32Pulse] - + (int32_t)g_pui32DataBuffer[i32Pulse + 1]) & 0x00ffffff); + g_pui32DataBuffer[i32Pulse] = i32Temp; + } + + // + // This loops handles checking for consecutive pulses that have pulse + // widths that are within an acceptable margin. + // + for(i32Pulse = 0; i32Pulse < (MIN_EDGE_COUNT - 1); i32Pulse++) + { + // + // Calculate the absolute difference between two consecutive pulses. + // + i32Temp = (int32_t)g_pui32DataBuffer[i32Pulse]; + i32Temp -= (int32_t)g_pui32DataBuffer[i32Pulse + 1]; + if(i32Temp < 0) + { + i32Temp *= -1; + } + + // + // This pulse detection code uses the following algorithm: + // If the following is true then we have consecutive acceptable pulses + // abs(Pulse[n] - Pulse[n + 1]) < Pulse[n + 1] / PULSE_DETECTION_MULT + // or + // PULSE_DETECTION_MULT * abs(Pulse[n] - Pulse[n + 1]) < Pulse[n + 1] + // + if((i32Temp * PULSE_DETECTION_MULT) < + (int32_t)g_pui32DataBuffer[i32Pulse + 1]) + { + i32Total += (int32_t)g_pui32DataBuffer[i32Pulse]; + i32ValidPulses++; + } + else + { + i32ValidPulses = 0; + i32Total = 0; + } + + // + // Once we have 7 pulses calculate the ratio needed to program the + // UART. + // + if(i32ValidPulses == 7) + { + // + // Add in the last pulse and calculate the ratio. + // + i32Total += (int32_t)g_pui32DataBuffer[i32Pulse]; + *pui32Ratio = i32Total >> 1; + + // + // Wait for at least 2 UART clocks since we only wait for 18 of 20 + // that are coming from the host. If we don't wait, we can turn + // on the UART while the last two pulses come down. + // + for(i32Delay = i32Total; i32Delay; i32Delay--) + { + } + + // + // Indicate a successful auto baud operation. + // + return(0); + } + } + + // + // Automatic baud rate detection failed. + // + return(-1); +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** +#endif diff --git a/boot_loader/bl_can.c b/boot_loader/bl_can.c new file mode 100644 index 0000000..9cf5c0b --- /dev/null +++ b/boot_loader/bl_can.c @@ -0,0 +1,1403 @@ +//***************************************************************************** +// +// bl_can.c - Functions to transfer data via the CAN port. +// +// Copyright (c) 2008-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 "inc/hw_can.h" +#include "inc/hw_gpio.h" +#include "inc/hw_memmap.h" +#include "inc/hw_nvic.h" +#include "inc/hw_flash.h" +#include "inc/hw_sysctl.h" +#include "inc/hw_types.h" +#include "inc/hw_uart.h" +#include "bl_config.h" +#include "boot_loader/bl_can.h" +#include "boot_loader/bl_can_timing.h" +#include "boot_loader/bl_check.h" +#include "boot_loader/bl_crystal.h" +#include "boot_loader/bl_flash.h" +#include "boot_loader/bl_hooks.h" +#include "boot_loader/bl_uart.h" + +//***************************************************************************** +// +//! \addtogroup bl_can_api +//! @{ +// +//***************************************************************************** +#if defined(CAN_ENABLE_UPDATE) || defined(DOXYGEN) + +//***************************************************************************** +// +// The results that can be returned by the CAN APIs. +// +//***************************************************************************** +#define CAN_CMD_SUCCESS 0x00 +#define CAN_CMD_FAIL 0x01 + +//***************************************************************************** +// +// Macros used to generate correct pin definitions. +// +//***************************************************************************** +#define CAN_RX_PIN_M (1 << CAN_RX_PIN) +#define CAN_TX_PIN_M (1 << CAN_TX_PIN) + +//***************************************************************************** +// +// Convenience macros for accessing CAN registers. +// +//***************************************************************************** +#define CANRegWrite(ui32Address, ui32Value) \ + HWREG(ui32Address) = ui32Value + +#define CANRegRead(ui32Address) \ + HWREG(ui32Address) + +//***************************************************************************** +// +// The message object number and index to the local message object memory to +// use when accessing the messages. +// +//***************************************************************************** +#define MSG_OBJ_BCAST_RX_ID 1 +#define MSG_OBJ_BCAST_TX_ID 2 + +//***************************************************************************** +// +// A prototype for the function (in the startup code) for calling the +// application. +// +//***************************************************************************** +extern void StartApplication(void); + +//***************************************************************************** +// +// A prototype for the function (in the startup code) for a predictable length +// delay. +// +//***************************************************************************** +extern void Delay(uint32_t ui32Count); + +//***************************************************************************** +// +// Holds the current address to write to when data is received via the Send +// Data Command. +// +//***************************************************************************** +static uint32_t g_ui32TransferAddress; + +//***************************************************************************** +// +// Holds the remaining bytes expected to be received. +// +//***************************************************************************** +static uint32_t g_ui32TransferSize; + +//***************************************************************************** +// +// The buffer used to receive data from the update. +// +//***************************************************************************** +static uint8_t g_pui8CommandBuffer[8]; + +//***************************************************************************** +// +// These globals are used to store the first two words to prevent a partial +// image from being booted. +// +//***************************************************************************** +static uint32_t g_ui32StartValues[2]; +static uint32_t g_ui32StartSize; +static uint32_t g_ui32StartAddress; + +//***************************************************************************** +// +// The active interface when the UART bridge is enabled. +// +//***************************************************************************** +#ifdef CAN_UART_BRIDGE +static uint32_t g_ui32Interface; +#define IFACE_UNKNOWN 0 +#define IFACE_CAN 1 +#define IFACE_UART 2 +#endif + +//***************************************************************************** +// +//! Initializes the CAN controller after reset. +//! +//! After reset, the CAN controller is left in the disabled state. However, +//! the memory used for message objects contains undefined values and must be +//! cleared prior to enabling the CAN controller the first time. This prevents +//! unwanted transmission or reception of data before the message objects are +//! configured. This function must be called before enabling the controller +//! the first time. +//! +//! \return None. +// +//***************************************************************************** +static void +CANInit(void) +{ + int iMsg; + + // + // Place CAN controller in init state, regardless of previous state. This + // will put the controller in idle, and allow the message object RAM to be + // programmed. + // + CANRegWrite(CAN0_BASE + CAN_O_CTL, CAN_CTL_INIT | CAN_CTL_CCE); + + // + // Loop through to program all 32 message objects + // + for(iMsg = 1; iMsg <= 32; iMsg++) + { + // + // Wait for busy bit to clear. + // + while(CANRegRead(CAN0_BASE + CAN_O_IF1CRQ) & CAN_IF1CRQ_BUSY) + { + } + + // + // Clear the message value bit in the arbitration register. This + // indicates the message is not valid and is a "safe" condition to + // leave the message object. + // + CANRegWrite(CAN0_BASE + CAN_O_IF1CMSK, + CAN_IF1CMSK_WRNRD | CAN_IF1CMSK_ARB | CAN_IF1CMSK_CONTROL); + CANRegWrite(CAN0_BASE + CAN_O_IF1ARB2, 0); + CANRegWrite(CAN0_BASE + CAN_O_IF1MCTL, 0); + + // + // Initiate programming of the message object + // + CANRegWrite(CAN0_BASE + CAN_O_IF1CRQ, iMsg); + } + + // + // Acknowledge any pending status interrupts. + // + CANRegRead(CAN0_BASE + CAN_O_STS); +} + +//***************************************************************************** +// +//! This function configures the message object used to receive commands. +//! +//! This function configures the message object used to receive all firmware +//! update messages. This will not actually read the data from the message it +//! is used to prepare the message object to receive the data when it is sent. +//! +//! \return None. +// +//***************************************************************************** +static void +CANMessageSetRx(void) +{ + uint16_t ui16CmdMaskReg; + uint16_t ui16MaskReg[2]; + uint16_t ui16ArbReg[2]; + uint16_t ui16MsgCtrl; + + // + // Wait for busy bit to clear + // + while(CANRegRead(CAN0_BASE + CAN_O_IF1CRQ) & CAN_IF1CRQ_BUSY) + { + } + + // + // This is always a write to the Message object as this call is setting a + // message object. This call will also always set all size bits so it sets + // both data bits. The call will use the CONTROL register to set control + // bits so this bit needs to be set as well. + // + // Set the MASK bit so that this gets transferred to the Message Object. + // Set the Arb bit so that this gets transferred to the Message object. + // + ui16CmdMaskReg = (CAN_IF1CMSK_WRNRD | CAN_IF1CMSK_DATAA | + CAN_IF1CMSK_DATAB | CAN_IF1CMSK_CONTROL | + CAN_IF1CMSK_MASK | CAN_IF1CMSK_ARB); + + // + // Set the UMASK bit to enable using the mask register. + // Set the data length since this is set for all transfers. This is also a + // single transfer and not a FIFO transfer so set EOB bit. + // + ui16MsgCtrl = CAN_IF1MCTL_UMASK | CAN_IF1MCTL_EOB; + + // + // Configure the Mask Registers. + // + // + // Set the 29 bits of Identifier mask that were requested. + // + ui16MaskReg[0] = (uint16_t)LM_API_UPD; + + // + // If the caller wants to filter on the extended ID bit then set it. + // + ui16MaskReg[1] = + (uint16_t)(CAN_IF1MSK2_MXTD | (LM_API_UPD >> 16)); + + // + // Set the 29 bit version of the Identifier for this message object. + // Mark the message as valid and set the extended ID bit. + // + ui16ArbReg[0] = LM_API_UPD & CAN_IF1ARB1_ID_M; + ui16ArbReg[1] = (((LM_API_UPD >> 16) & CAN_IF1ARB2_ID_M) | + (CAN_IF1ARB2_MSGVAL | CAN_IF1ARB2_XTD)); + + // + // Write out the registers to program the message object. + // + CANRegWrite(CAN0_BASE + CAN_O_IF1CMSK, ui16CmdMaskReg); + CANRegWrite(CAN0_BASE + CAN_O_IF1MSK1, ui16MaskReg[0]); + CANRegWrite(CAN0_BASE + CAN_O_IF1MSK2, ui16MaskReg[1]); + CANRegWrite(CAN0_BASE + CAN_O_IF1ARB1, ui16ArbReg[0]); + CANRegWrite(CAN0_BASE + CAN_O_IF1ARB2, ui16ArbReg[1]); + CANRegWrite(CAN0_BASE + CAN_O_IF1MCTL, ui16MsgCtrl); + + // + // Transfer the message object to the message object specific by + // MSG_OBJ_BCAST_RX_ID. + // + CANRegWrite(CAN0_BASE + CAN_O_IF1CRQ, + MSG_OBJ_BCAST_RX_ID & CAN_IF1CRQ_MNUM_M); +} + +//***************************************************************************** +// +//! This function reads data from the receive message object. +//! +//! \param pui8Data is a pointer to the buffer to store the data read from the +//! CAN controller. +//! \param pui32MsgID is a pointer to the ID that was received with the data. +//! +//! This function will reads and acknowledges the data read from the message +//! object used to receive all CAN firmware update messages. It will also +//! return the message identifier as this holds the API number that was +//! attached to the data. This message identifier should be one of the +//! LM_API_UPD_* definitions. +//! +//! \return The number of valid bytes returned in the \e pui8Data buffer or +//! 0xffffffff if data was overwritten in the buffer. +// +//***************************************************************************** +static uint32_t +CANMessageGetRx(uint8_t *pui8Data, uint32_t *pui32MsgID) +{ + uint16_t ui16CmdMaskReg; + uint16_t ui16ArbReg0, ui16ArbReg1; + uint16_t ui16MsgCtrl; + uint32_t ui32Bytes; + uint16_t *pui16Data; + + // + // This is always a read to the Message object as this call is setting a + // message object. + // Clear a pending interrupt and new data in a message object. + // + ui16CmdMaskReg = (CAN_IF2CMSK_DATAA | CAN_IF2CMSK_DATAB | + CAN_IF1CMSK_CONTROL | CAN_IF2CMSK_CLRINTPND | + CAN_IF2CMSK_ARB); + + // + // Set up the request for data from the message object. + // + CANRegWrite(CAN0_BASE + CAN_O_IF2CMSK, ui16CmdMaskReg); + + // + // Transfer the message object to the message object specific by + // MSG_OBJ_BCAST_RX_ID. + // + CANRegWrite(CAN0_BASE + CAN_O_IF2CRQ, + MSG_OBJ_BCAST_RX_ID & CAN_IF1CRQ_MNUM_M); + + // + // Wait for busy bit to clear + // + while(CANRegRead(CAN0_BASE + CAN_O_IF2CRQ) & CAN_IF1CRQ_BUSY) + { + } + + // + // Read out the IF Registers. + // + ui16ArbReg0 = CANRegRead(CAN0_BASE + CAN_O_IF2ARB1); + ui16ArbReg1 = CANRegRead(CAN0_BASE + CAN_O_IF2ARB2); + ui16MsgCtrl = CANRegRead(CAN0_BASE + CAN_O_IF2MCTL); + + // + // Set the 29 bit version of the Identifier for this message object. + // + *pui32MsgID = ((ui16ArbReg1 & CAN_IF1ARB2_ID_M) << 16) | ui16ArbReg0; + + // + // See if there is new data available. + // + if((ui16MsgCtrl & (CAN_IF1MCTL_NEWDAT | CAN_IF1MCTL_MSGLST)) == + CAN_IF1MCTL_NEWDAT) + { + // + // Get the amount of data needed to be read. + // + ui32Bytes = ui16MsgCtrl & CAN_IF1MCTL_DLC_M; + + // + // Read out the data from the CAN registers 16 bits at a time. + // + pui16Data = (uint16_t *)pui8Data; + + pui16Data[0] = CANRegRead(CAN0_BASE + CAN_O_IF2DA1); + pui16Data[1] = CANRegRead(CAN0_BASE + CAN_O_IF2DA2); + pui16Data[2] = CANRegRead(CAN0_BASE + CAN_O_IF2DB1); + pui16Data[3] = CANRegRead(CAN0_BASE + CAN_O_IF2DB2); + + // + // Now clear out the new data flag. + // + CANRegWrite(CAN0_BASE + CAN_O_IF2CMSK, CAN_IF1CMSK_NEWDAT); + + // + // Transfer the message object to the message object specific by + // MSG_OBJ_BCAST_RX_ID. + // + CANRegWrite(CAN0_BASE + CAN_O_IF2CRQ, MSG_OBJ_BCAST_RX_ID); + + // + // Wait for busy bit to clear + // + while(CANRegRead(CAN0_BASE + CAN_O_IF2CRQ) & CAN_IF2CRQ_BUSY) + { + } + } + else + { + // + // Data was lost so inform the caller. + // + ui32Bytes = 0xffffffff; + } + return(ui32Bytes); +} + +//***************************************************************************** +// +//! This function sends data using the transmit message object. +//! +//! \param ui32Id is the ID to use with this message. +//! \param pui8Data is a pointer to the buffer with the data to be sent. +//! \param ui32Size is the number of bytes to send and should not be more than +//! 8 bytes. +//! +//! This function will reads and acknowledges the data read from the message +//! object used to receive all CAN firmware update messages. It will also +//! return the message identifier as this holds the API number that was +//! attached to the data. This message identifier should be one of the +//! LM_API_UPD_* definitions. +//! +//! \return None. +// +//***************************************************************************** +static void +CANMessageSetTx(uint32_t ui32Id, const uint8_t *pui8Data, uint32_t ui32Size) +{ + uint16_t ui16CmdMaskReg; + uint16_t ui16ArbReg0, ui16ArbReg1; + uint16_t ui16MsgCtrl; + uint16_t *pui16Data; + + // + // Wait for busy bit to clear + // + while(CANRegRead(CAN0_BASE + CAN_O_IF1CRQ) & CAN_IF1CRQ_BUSY) + { + } + + // + // This is always a write to the Message object as this call is setting a + // message object. This call will also always set all size bits so it sets + // both data bits. The call will use the CONTROL register to set control + // bits so this bit needs to be set as well. + // + ui16CmdMaskReg = (CAN_IF1CMSK_WRNRD | CAN_IF1CMSK_DATAA | + CAN_IF1CMSK_DATAB | CAN_IF1CMSK_CONTROL | + CAN_IF1CMSK_ARB); + + // + // Set the 29 bit version of the Identifier for this message object. + // + ui16ArbReg0 = ui32Id & CAN_IF1ARB1_ID_M; + + // + // Mark the message as valid and set the extended ID bit. + // + ui16ArbReg1 = (((ui32Id >> 16) & CAN_IF1ARB2_ID_M) | + (CAN_IF1ARB2_DIR | CAN_IF1ARB2_MSGVAL | CAN_IF1ARB2_XTD)); + + // + // Set the TXRQST bit and the reset the rest of the register. + // Set the data length since this is set for all transfers. This is also a + // single transfer and not a FIFO transfer so set EOB bit. + // + // + ui16MsgCtrl = (CAN_IF1MCTL_TXRQST | CAN_IF1MCTL_EOB | + (ui32Size & CAN_IF1MCTL_DLC_M)); + + pui16Data = (uint16_t *)pui8Data; + + // + // Write the data out to the CAN Data registers if needed. + // + CANRegWrite(CAN0_BASE + CAN_O_IF1DA1, pui16Data[0]); + CANRegWrite(CAN0_BASE + CAN_O_IF1DA2, pui16Data[1]); + CANRegWrite(CAN0_BASE + CAN_O_IF1DB1, pui16Data[2]); + CANRegWrite(CAN0_BASE + CAN_O_IF1DB2, pui16Data[3]); + + // + // Write out the registers to program the message object. + // + CANRegWrite(CAN0_BASE + CAN_O_IF1CMSK, ui16CmdMaskReg); + CANRegWrite(CAN0_BASE + CAN_O_IF1ARB1, ui16ArbReg0); + CANRegWrite(CAN0_BASE + CAN_O_IF1ARB2, ui16ArbReg1); + CANRegWrite(CAN0_BASE + CAN_O_IF1MCTL, ui16MsgCtrl); + + // + // Transfer the message object to the message object specifiec by + // MSG_OBJ_BCAST_RX_ID. + // + CANRegWrite(CAN0_BASE + CAN_O_IF1CRQ, + (MSG_OBJ_BCAST_TX_ID) & CAN_IF1CRQ_MNUM_M); +} + +//***************************************************************************** +// +//! Configures the CAN interface. +//! +//! \param ui32SetTiming determines if the CAN bit timing should be configured. +//! +//! This function configures the CAN controller, preparing it for use by +//! the boot loader. If the \e ui32SetTiming parameter is 0, the bit timing +//! for the CAN bus will be left alone. This occurs when the boot loader was +//! entered from a running application that already has configured the timing +//! for the system. When \e ui32SetTiming is non-zero the bit timing will be +//! set to the defaults defined in the bl_config.h file in the +//! project. +//! +//! \return None. +// +//***************************************************************************** +static void +ConfigureCANInterface(uint32_t ui32SetTiming) +{ + // + // Reset the state of all the message object and the state of the CAN + // module to a known state. + // + CANInit(); + + // + // If a device identifier was specified then this was due to an update from + // a running CAN application so don't change the CAN bit timing. + // + if(ui32SetTiming != 0) + { + // + // Set the bit fields of the bit timing register according to the + // parms. + // + CANRegWrite(CAN0_BASE + CAN_O_BIT, CAN_BIT_TIMING); + + // + // Set the divider upper bits in the extension register. + // + CANRegWrite(CAN0_BASE + CAN_O_BRPE, 0); + } + + // + // Take the CAN0 device out of INIT state. + // + CANRegWrite(CAN0_BASE + CAN_O_CTL, 0); + + // + // Configure the broadcast receive message object. + // + CANMessageSetRx(); +} + +//***************************************************************************** +// +// Reads the next packet that is sent to the boot loader. +// +//***************************************************************************** +static uint32_t +PacketRead(uint8_t *pui8Data, uint32_t *pui32Size) +{ + uint32_t ui32MsgID; + +#ifdef CAN_UART_BRIDGE + uint32_t ui32Size, ui32Length, ui32Mode, ui32Char; + uint8_t pui8Buffer[12]; + + // + // Initialize the size and length of the packet. + // + ui32Length = 0; + ui32Size = 0; + + // + // If no interface has been determined then wait for either CAN or UART + // data until either responds. + // + if(g_ui32Interface == IFACE_UNKNOWN) + { + // + // Wait for CAN or UART data. + // + while((CANRegRead(CAN0_BASE + CAN_O_NWDA1) == 0) && + ((HWREG(UART0_BASE + UART_O_FR) & UART_FR_RXFE) == UART_FR_RXFE)) + { + } + + // + // If the UART FIFO was empty then the loop exited due to a CAN + // message. + // + if((HWREG(UART0_BASE + UART_O_FR) & UART_FR_RXFE) == UART_FR_RXFE) + { + g_ui32Interface = IFACE_CAN; + } + else + { + // + // The UART FIFO was not empty so the UART interface was used. + // + g_ui32Interface = IFACE_UART; + } + } + + // + // Read a data packet from the CAN controller. + // + if(g_ui32Interface == IFACE_CAN) + { +#endif + // + // Wait until a packet has been received. + // + while(CANRegRead(CAN0_BASE + CAN_O_NWDA1) == 0) + { + } + + // + // Read the packet. + // + *pui32Size = CANMessageGetRx(pui8Data, &ui32MsgID); +#ifdef CAN_UART_BRIDGE + } + else + { + // + // Read a data packet from the UART controller. + // + ui32Mode = 0; + + while(1) + { + // + // Wait until a char is available. + // + while(HWREG(UART0_BASE + UART_O_FR) & UART_FR_RXFE) + { + } + + // + // Now get the char. + // + ui32Char = HWREG(UART0_BASE + UART_O_DR); + + if(ui32Char == 0xff) + { + ui32Mode = 1; + ui32Length = 0; + } + else if(ui32Mode == 1) + { + if(ui32Char > 12) + { + ui32Mode = 0; + } + else + { + ui32Size = ui32Char; + ui32Mode = 2; + } + } + else if(ui32Mode == 3) + { + if(ui32Char == 0xfe) + { + pui8Buffer[ui32Length++] = 0xff; + ui32Mode = 2; + } + else if(ui32Char == 0xfd) + { + pui8Buffer[ui32Length++] = 0xfe; + ui32Mode = 2; + } + else + { + ui32Mode = 0; + } + } + else if(ui32Mode == 2) + { + if(ui32Char == 0xfe) + { + ui32Mode = 3; + } + else + { + pui8Buffer[ui32Length++] = ui32Char; + } + } + + if((ui32Length == ui32Size) && (ui32Mode == 2)) + { + ui32MsgID = *(uint32_t *)pui8Buffer; + + if((ui32MsgID & (CAN_MSGID_MFR_M | CAN_MSGID_DTYPE_M)) == + LM_API_UPD) + { + *(uint32_t *)pui8Data = + *(uint32_t *)(pui8Buffer + 4); + *(uint32_t *)(pui8Data + 4) = + *(uint32_t *)(pui8Buffer + 8); + *pui32Size = ui32Size - 4; + break; + } + } + } + } +#endif + + // + // Return the message ID of the packet that was received. + // + return(ui32MsgID); +} + +//***************************************************************************** +// +// This function writes out an individual character over the UART and +// handles sending out special sequences for handling 0xff and 0xfe values. +// +//***************************************************************************** +#ifdef CAN_UART_BRIDGE +static void +UARTBridgeWrite(uint32_t ui32Char) +{ + // + // See if the character being sent is 0xff. + // + if(ui32Char == 0xff) + { + // + // Send 0xfe 0xfe, the escaped version of 0xff. A sign extended + // version of 0xfe is used to avoid the check below for 0xfe, thereby + // avoiding an infinite loop. Only the lower 8 bits are actually sent, + // so 0xfe is what is actually transmitted. + // + UARTBridgeWrite(0xfffffffe); + UARTBridgeWrite(0xfffffffe); + } + + // + // Otherwise, see if the character being sent is 0xfe. + // + else if(ui32Char == 0xfe) + { + // + // Send 0xfe 0xfd, the escaped version of 0xfe. A sign extended + // version of 0xfe is used to avoid the check above for 0xfe, thereby + // avoiding an infinite loop. Only the lower 8 bits are actually sent, + // so 0xfe is what is actually transmitted. + // + UARTBridgeWrite(0xfffffffe); + UARTBridgeWrite(0xfd); + } + + // + // Otherwise, simply send this character. + // + else + { + // + // Wait until space is available in the UART transmit FIFO. + // + while(HWREG(UART0_BASE + UART_O_FR) & UART_FR_TXFF) + { + } + + // + // Send the char. + // + HWREG(UART0_BASE + UART_O_DR) = ui32Char & 0xff; + } +} +#endif + +//***************************************************************************** +// +// Sends a packet to the controller that is communicating with the boot loader. +// +//***************************************************************************** +static void +PacketWrite(uint32_t ui32Id, const uint8_t *pui8Data, uint32_t ui32Size) +{ + uint32_t ui32Idx; + +#ifdef CAN_UART_BRIDGE + // + // Check if the boot loader is in CAN mode. + // + if(g_ui32Interface == IFACE_CAN) + { +#endif + // + // Wait until the previous packet has been sent, providing a time out so + // that the boot loader does not hang here. + // + for(ui32Idx = 1000; + (ui32Idx != 0) && (CANRegRead(CAN0_BASE + CAN_O_TXRQ1) != 0); + ui32Idx--) + { + } + + // + // If the previous packet was sent, then send this packet. + // + if(ui32Idx != 0) + { + CANMessageSetTx(ui32Id, pui8Data, ui32Size); + } +#ifdef CAN_UART_BRIDGE + } + else + { + // + // The boot loader is in UART modes so write the packet using the UART + // functions. Write the start pattern followed by the size, and the ID. + // + UARTBridgeWrite(0xffffffff); + UARTBridgeWrite(ui32Size + 4); + UARTBridgeWrite(ui32Id & 0xff); + UARTBridgeWrite((ui32Id >> 8) & 0xff); + UARTBridgeWrite((ui32Id >> 16) & 0xff); + UARTBridgeWrite((ui32Id >> 24) & 0xff); + + // + // Now write out the remaining data bytes. + // + while(ui32Size--) + { + UARTBridgeWrite(*pui8Data++); + } + } +#endif +} + +//***************************************************************************** +// +//! This is the main routine for handling updating over CAN. +//! +//! This function accepts boot loader commands over CAN to perform a firmware +//! update over the CAN bus. This function assumes that the CAN bus timing +//! and message objects have been configured elsewhere. +//! +//! \return None. +// +//***************************************************************************** +void +UpdaterCAN(void) +{ + uint32_t ui32Bytes; + uint32_t ui32Cmd; + uint32_t ui32FlashSize; + uint32_t ui32Temp; + uint8_t ui8Status; + +#ifdef ENABLE_UPDATE_CHECK + // + // Check the application is valid and check the pin to see if an update is + // being requested. + // + if(g_ui32Forced == 1) + { + // + // Send out the CAN request. + // +#ifdef CAN_UART_BRIDGE + g_ui32Interface = IFACE_CAN; +#endif + PacketWrite(LM_API_UPD_REQUEST, 0, 0); + + // + // Send out the UART request. + // +#ifdef CAN_UART_BRIDGE + g_ui32Interface = IFACE_UART; + PacketWrite(LM_API_UPD_REQUEST, 0, 0); + g_ui32Interface = IFACE_UNKNOWN; +#endif + + // + // Wait only 50ms for the response and move on otherwise. + // + Delay(CRYSTAL_FREQ / 20); + + // + // Wait until a packet has been received. + // +#ifdef CAN_UART_BRIDGE + if((CANRegRead(CAN0_BASE + CAN_O_NWDA1) == 0) && + ((HWREG(UART0_BASE + UART_O_FR) & UART_FR_RXFE) == UART_FR_RXFE)) +#else + if(CANRegRead(CAN0_BASE + CAN_O_NWDA1) == 0) +#endif + { + // + // Call the application. + // + StartApplication(); + } + } +#endif + + // + // Loop forever processing packets. + // + while(1) + { + // + // Read the next packet. + // + ui32Bytes = 0; + ui32Cmd = PacketRead(g_pui8CommandBuffer, &ui32Bytes); + + // + // Handle this packet. + // + ui8Status = CAN_CMD_SUCCESS; + switch(ui32Cmd) + { + // + // This is an update request packet. + // + case LM_API_UPD_REQUEST: + { + // + // This packet is ignored (other than generating an ACK). + // + break; + } + + // + // This is a ping packet. + // + case LM_API_UPD_PING: + { + // + // This packet is ignored (other than generating an ACK). + // + break; + } + + // + // This is a reset packet. + // + case LM_API_UPD_RESET: + { + // + // 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) + { + } + } + + // + // This is a data packet. + // + case LM_API_UPD_SEND_DATA: + { + // + // 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 application before 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. + // + ui8Status = CAN_CMD_FAIL; + } + } + + // + // Check if there are any more bytes to receive. + // + if(g_ui32TransferSize >= ui32Bytes) + { + // + // Decrypt the data if required. + // +#ifdef BL_DECRYPT_FN_HOOK + BL_DECRYPT_FN_HOOK(g_pui8CommandBuffer, ui32Bytes); +#endif + + // + // Clear the flash access interrupt. + // + BL_FLASH_CL_ERR_FN_HOOK(); + + // + // Skip the first transfer. + // + if(g_ui32StartSize == g_ui32TransferSize) + { + g_ui32StartValues[0] = + *((uint32_t *)&g_pui8CommandBuffer[0]); + g_ui32StartValues[1] = + *((uint32_t *)&g_pui8CommandBuffer[4]); + } + else + { + // + // Loop over the words to program. + // + BL_FLASH_PROGRAM_FN_HOOK(g_ui32TransferAddress, + g_pui8CommandBuffer, + ui32Bytes); + } + + // + // Return an error if an access violation occurred. + // + if(BL_FLASH_ERROR_FN_HOOK()) + { + // + // Indicate that the flash programming failed. + // + ui8Status = CAN_CMD_FAIL; + } + else + { + // + // Now update the address to program. + // + g_ui32TransferSize -= ui32Bytes; + g_ui32TransferAddress += ui32Bytes; + + // + // If a progress hook function has been provided, call + // it here. + // +#ifdef BL_PROGRESS_FN_HOOK + BL_PROGRESS_FN_HOOK(g_ui32StartSize - + g_ui32TransferSize, + g_ui32StartSize); +#endif + } + } + else + { + // + // This indicates that too much data is being sent to the + // device. + // + ui8Status = CAN_CMD_FAIL; + } + + // + // If the last expected bytes were received then write out the + // first two words of the image to allow it to boot. + // + if(g_ui32TransferSize == 0) + { + // + // Loop over the words to program. + // + BL_FLASH_PROGRAM_FN_HOOK(g_ui32StartAddress, + (uint8_t *)&g_ui32StartValues, + 8); + + // + // If an end signal hook function has been provided, call + // it here since we have finished a download. + // +#ifdef BL_END_FN_HOOK + BL_END_FN_HOOK(); +#endif + } + break; + } + + // + // This is a start download packet. + // + case LM_API_UPD_DOWNLOAD: + { + // + // Get the application address and size from the packet data. + // + g_ui32TransferAddress = + *((uint32_t *)&g_pui8CommandBuffer[0]); + g_ui32TransferSize = *((uint32_t *)&g_pui8CommandBuffer[4]); + g_ui32StartSize = g_ui32TransferSize; + g_ui32StartAddress = g_ui32TransferAddress; + + // + // 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. + // + ui8Status = CAN_CMD_FAIL; + + // + // 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()) + { + ui8Status = CAN_CMD_FAIL; + } + + // + // See if the command was successful. + // + if(ui8Status != CAN_CMD_SUCCESS) + { + // + // Setting g_ui32TransferSize to zero makes + // COMMAND_SEND_DATA fail to accept any data. + // + g_ui32TransferSize = 0; + } +#ifdef BL_START_FN_HOOK + else + { + // + // If a start signal hook function has been provided, call + // it here since we are about to start a new download. + // + BL_START_FN_HOOK(); + } +#endif + + break; + } + + // + // This is an unknown packet. + // + default: + { + // + // Set the status to indicate a failure. + // + ui8Status = CAN_CMD_FAIL; + break; + } + } + + // + // Send an ACK packet in response to indicate that the packet was + // received. The status in the ACK data indicates if the command was + // successfully processed. + // + PacketWrite(LM_API_UPD_ACK, &ui8Status, 1); + } +} + +//***************************************************************************** +// +// Configures the UART used for CAN traffic bridging. +// +//***************************************************************************** +#ifdef CAN_UART_BRIDGE +void +ConfigureBridge(void) +{ + // + // Enable the GPIO module if necessary. + // +#if (CAN_RX_PERIPH != SYSCTL_RCGC2_GPIOA) && \ + (CAN_TX_PERIPH != SYSCTL_RCGC2_GPIOA) + HWREG(SYSCTL_RCGC2) |= SYSCTL_RCGC2_GPIOA; +#endif + + // + // Enable the UART module. + // + HWREG(SYSCTL_RCGC1) |= SYSCTL_RCGC1_UART0; + + // + // Enable the GPIO pins used for the UART. + // + HWREG(GPIO_PORTA_BASE + GPIO_O_AFSEL) |= 0x3; + HWREG(GPIO_PORTA_BASE + GPIO_O_DEN) |= 0x03; + + // + // Configure the UART. + // + HWREG(UART0_BASE + UART_O_IBRD) = UART_BAUD_RATIO(115200) >> 6; + HWREG(UART0_BASE + UART_O_FBRD) = (UART_BAUD_RATIO(115200) & + UART_FBRD_DIVFRAC_M); + HWREG(UART0_BASE + UART_O_LCRH) = UART_LCRH_WLEN_8 | UART_LCRH_FEN; + HWREG(UART0_BASE + UART_O_CTL) = (UART_CTL_UARTEN | UART_CTL_TXE | + UART_CTL_RXE); +} +#endif + +//***************************************************************************** +// +//! This is the application entry point to the CAN updater. +//! +//! This function should only be entered from a running application and not +//! when running the boot loader with no application present. +//! +//! \return None. +// +//***************************************************************************** +void +AppUpdaterCAN(void) +{ + // + // If the boot loader is being called from the application the UART needs + // to be configured. + // +#ifdef CAN_UART_BRIDGE + ConfigureBridge(); +#endif + + // + // Configure the CAN controller but don't change the bit timing. + // + ConfigureCANInterface(0); + + // + // Call the main update routine. + // + UpdaterCAN(); +} + +//***************************************************************************** +// +//! Generic configuration is handled in this function. +//! +//! This function is called by the start up code to perform any configuration +//! necessary before calling the update routine. +//! +//! \return None. +// +//***************************************************************************** +void +ConfigureCAN(void) +{ +#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 while the main oscillator starts up. + // + Delay(524288); + + // + // Set the crystal frequency and switch to the main oscillator. + // + HWREG(SYSCTL_RCC) = ((HWREG(SYSCTL_RCC) & + ~(SYSCTL_RCC_XTAL_M | SYSCTL_RCC_OSCSRC_M)) | + XTAL_VALUE | SYSCTL_RCC_OSCSRC_MAIN); +#endif + + // + // Enable the CAN controller. + // + HWREG(SYSCTL_RCGC0) |= SYSCTL_RCGC0_CAN0; + +#if CAN_RX_PERIPH == CAN_TX_PERIPH + // + // Enable the GPIO associated with CAN0 + // + HWREG(SYSCTL_RCGC2) |= CAN_RX_PERIPH; + + // + // Wait a while before accessing the peripheral. + // + Delay(3); + + // + // Set the alternate function selects. + // + HWREG(CAN_RX_PORT + GPIO_O_AFSEL) |= CAN_RX_PIN_M | CAN_TX_PIN_M; + + // + // Set the pin type to it's digital function. + // + HWREG(CAN_RX_PORT + GPIO_O_DEN) |= CAN_RX_PIN_M | CAN_TX_PIN_M; + +#else + // + // Enable the GPIO associated with CAN0 + // + HWREG(SYSCTL_RCGC2) |= CAN_RX_PERIPH | CAN_TX_PERIPH; + + // + // Wait a while before accessing the peripheral. + // + Delay(3); + + // + // Set the alternate function selects. + // + HWREG(CAN_RX_PORT + GPIO_O_AFSEL) |= CAN_RX_PIN_M; + HWREG(CAN_TX_PORT + GPIO_O_AFSEL) |= CAN_TX_PIN_M; + + // + // Set the pin type to it's digital function. + // + HWREG(CAN_RX_PORT + GPIO_O_DEN) |= CAN_RX_PIN_M; + HWREG(CAN_TX_PORT + GPIO_O_DEN) |= CAN_TX_PIN_M; +#endif + + // + // Configure the UART used for bridging. + // +#ifdef CAN_UART_BRIDGE + ConfigureBridge(); +#endif + + // + // Configure the CAN interface. + // + ConfigureCANInterface(1); +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** +#endif diff --git a/boot_loader/bl_can.h b/boot_loader/bl_can.h new file mode 100644 index 0000000..504a410 --- /dev/null +++ b/boot_loader/bl_can.h @@ -0,0 +1,64 @@ +//***************************************************************************** +// +// bl_can.h - Definitions for the CAN transport functions. +// +// Copyright (c) 2008-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. +// +//***************************************************************************** + +#ifndef __BL_CAN_H__ +#define __BL_CAN_H__ + +//***************************************************************************** +// +// These defines are used to define the range of values that are used for +// the CAN update protocol. +// +//***************************************************************************** +#define CAN_MSGID_DTYPE_UPDATE 0x1f000000 +#define CAN_MSGID_MFR_LM 0x00020000 + +//***************************************************************************** +// +// The masks of the fields that are used in the message identifier. +// +//***************************************************************************** +#define CAN_MSGID_DEVNO_M 0x0000003f +#define CAN_MSGID_API_M 0x0000ffc0 +#define CAN_MSGID_MFR_M 0x00ff0000 +#define CAN_MSGID_DTYPE_M 0x1f000000 +#define CAN_MSGID_DEVNO_S 0 +#define CAN_MSGID_API_S 6 +#define CAN_MSGID_MFR_S 16 +#define CAN_MSGID_DTYPE_S 24 + +//***************************************************************************** +// +// Firmware Update API definitions. +// +//***************************************************************************** +#define LM_API_UPD (CAN_MSGID_MFR_LM | CAN_MSGID_DTYPE_UPDATE) +#define LM_API_UPD_PING (LM_API_UPD | (0 << CAN_MSGID_API_S)) +#define LM_API_UPD_DOWNLOAD (LM_API_UPD | (1 << CAN_MSGID_API_S)) +#define LM_API_UPD_SEND_DATA (LM_API_UPD | (2 << CAN_MSGID_API_S)) +#define LM_API_UPD_RESET (LM_API_UPD | (3 << CAN_MSGID_API_S)) +#define LM_API_UPD_ACK (LM_API_UPD | (4 << CAN_MSGID_API_S)) +#define LM_API_UPD_REQUEST (LM_API_UPD | (6 << CAN_MSGID_API_S)) + +#endif // __BL_CAN_H__ diff --git a/boot_loader/bl_can_timing.h b/boot_loader/bl_can_timing.h new file mode 100644 index 0000000..f0aaa0c --- /dev/null +++ b/boot_loader/bl_can_timing.h @@ -0,0 +1,241 @@ +//***************************************************************************** +// +// bl_can_timing.h - Timing definitions for the CAN controller. +// +// Copyright (c) 2008-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. +// +//***************************************************************************** + +#ifndef __BL_CAN_TIMING_H__ +#define __BL_CAN_TIMING_H__ + +#ifdef CAN_ENABLE_UPDATE + +//***************************************************************************** +// +// This macro is used to generate the proper value for CAN_BIT_TIMING. The +// values selected for each crystal/bit rate combination assumes a propagation +// delay of 300ns (which will always be rounded up to the next integer multiple +// of the CAN time quanta). +// +//***************************************************************************** +#define CAN_BIT_REG(seg1, seg2, sjw, brp) \ + ((((seg2 - 1) << CAN_BIT_TSEG2_S) & \ + CAN_BIT_TSEG2_M) | \ + (((seg1 - 1) << CAN_BIT_TSEG1_S) & \ + CAN_BIT_TSEG1_M) | \ + (((sjw - 1) << CAN_BIT_SJW_S) & \ + CAN_BIT_SJW_M) | \ + (((brp - 1) << CAN_BIT_BRP_S) & \ + CAN_BIT_BRP_M)) + +//***************************************************************************** +// +// The settings for a 16MHz crystal frequency. +// +//***************************************************************************** +#if CRYSTAL_FREQ == 16000000 +#if CAN_BIT_RATE == 1000000 +#define CAN_BIT_TIMING CAN_BIT_REG(10, 5, 4, 1) // tProp = 312ns +#elif CAN_BIT_RATE == 500000 +#define CAN_BIT_TIMING CAN_BIT_REG(9, 6, 4, 2) // tProp = 375ns +#elif CAN_BIT_RATE == 250000 +#define CAN_BIT_TIMING CAN_BIT_REG(4, 3, 3, 8) // tProp = 500ns +#elif CAN_BIT_RATE == 125000 +#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 8) // tProp = 500ns +#elif CAN_BIT_RATE == 50000 +#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 20) // tProp = 1250ns +#elif CAN_BIT_RATE == 20000 +#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 50) // tProp = 3125ns +#else +#error Invalid CAN_BIT_RATE value used with a 16MHz crystal. +#endif + +//***************************************************************************** +// +// The settings for a 12MHz crystal frequency. +// +//***************************************************************************** +#elif CRYSTAL_FREQ == 12000000 +#if CAN_BIT_RATE == 1000000 +#define CAN_BIT_TIMING CAN_BIT_REG(8, 3, 3, 1) // tProp = 416ns +#elif CAN_BIT_RATE == 500000 +#define CAN_BIT_TIMING CAN_BIT_REG(7, 4, 4, 2) // tProp = 500ns +#elif CAN_BIT_RATE == 250000 +#define CAN_BIT_TIMING CAN_BIT_REG(6, 5, 4, 4) // tProp = 333ns +#elif CAN_BIT_RATE == 125000 +#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 6) // tProp = 500ns +#elif CAN_BIT_RATE == 50000 +#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 15) // tProp = 1250ns +#elif CAN_BIT_RATE == 20000 +#define CAN_BIT_TIMING CAN_BIT_REG(6, 5, 4, 50) // tProp = 4166ns +#else +#error Invalid CAN_BIT_RATE value used with a 12MHz crystal. +#endif + +//***************************************************************************** +// +// The settings for a 10MHz crystal frequency. +// +//***************************************************************************** +#elif CRYSTAL_FREQ == 10000000 +#if CAN_BIT_RATE == 1000000 +#define CAN_BIT_TIMING CAN_BIT_REG(6, 3, 3, 1) // tProp = 300ns +#elif CAN_BIT_RATE == 500000 +#define CAN_BIT_TIMING CAN_BIT_REG(11, 8, 4, 1) // tProp = 300ns +#elif CAN_BIT_RATE == 250000 +#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 4) // tProp = 400ns +#elif CAN_BIT_RATE == 125000 +#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 5) // tProp = 500ns +#elif CAN_BIT_RATE == 50000 +#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 20) // tProp = 2000ns +#elif CAN_BIT_RATE == 20000 +#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 50) // tProp = 5000ns +#else +#error Invalid CAN_BIT_RATE value used with a 10MHz crystal. +#endif + +//***************************************************************************** +// +// The settings for a 8MHz crystal frequency. +// +//***************************************************************************** +#elif CRYSTAL_FREQ == 8000000 +#if CAN_BIT_RATE == 1000000 +#define CAN_BIT_TIMING CAN_BIT_REG(5, 2, 2, 1) // tProp = 375ns +#elif CAN_BIT_RATE == 500000 +#define CAN_BIT_TIMING CAN_BIT_REG(9, 6, 4, 1) // tProp = 375ns +#elif CAN_BIT_RATE == 250000 +#define CAN_BIT_TIMING CAN_BIT_REG(4, 3, 3, 4) // tProp = 500ns +#elif CAN_BIT_RATE == 125000 +#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 4) // tProp = 500ns +#elif CAN_BIT_RATE == 50000 +#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 10) // tProp = 1250ns +#elif CAN_BIT_RATE == 20000 +#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 25) // tProp = 3125ns +#else +#error Invalid CAN_BIT_RATE value used with a 8MHz crystal. +#endif + +//***************************************************************************** +// +// The settings for a 6MHz crystal frequency. +// +//***************************************************************************** +#elif CRYSTAL_FREQ == 6000000 +#if CAN_BIT_RATE == 500000 +#define CAN_BIT_TIMING CAN_BIT_REG(7, 4, 4, 1) // tProp = 500ns +#elif CAN_BIT_RATE == 250000 +#define CAN_BIT_TIMING CAN_BIT_REG(6, 5, 4, 2) // tProp = 333ns +#elif CAN_BIT_RATE == 125000 +#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 3) // tProp = 500ns +#elif CAN_BIT_RATE == 50000 +#define CAN_BIT_TIMING CAN_BIT_REG(6, 5, 4, 10) // tProp = 1666ns +#elif CAN_BIT_RATE == 20000 +#define CAN_BIT_TIMING CAN_BIT_REG(6, 5, 4, 25) // tProp = 4166ns +#else +#error Invalid CAN_BIT_RATE value used with a 6MHz crystal. +#endif + +//***************************************************************************** +// +// The settings for a 5MHz crystal frequency. +// +//***************************************************************************** +#elif CRYSTAL_FREQ == 5000000 +#if CAN_BIT_RATE == 500000 +#define CAN_BIT_TIMING CAN_BIT_REG(6, 3, 3, 1) // tProp = 600ns +#elif CAN_BIT_RATE == 250000 +#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 2) // tProp = 400ns +#elif CAN_BIT_RATE == 125000 +#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 4) // tProp = 800ns +#elif CAN_BIT_RATE == 50000 +#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 10) // tProp = 2000ns +#elif CAN_BIT_RATE == 20000 +#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 25) // tProp = 5000ns +#else +#error Invalid CAN_BIT_RATE value used with a 5MHz crystal. +#endif + +//***************************************************************************** +// +// The settings for a 4MHz crystal frequency. +// +//***************************************************************************** +#elif CRYSTAL_FREQ == 4000000 +#if CAN_BIT_RATE == 500000 +#define CAN_BIT_TIMING CAN_BIT_REG(5, 2, 2, 1) // tProp = 750ns +#elif CAN_BIT_RATE == 250000 +#define CAN_BIT_TIMING CAN_BIT_REG(4, 3, 3, 2) // tProp = 500ns +#elif CAN_BIT_RATE == 125000 +#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 2) // tProp = 500ns +#elif CAN_BIT_RATE == 50000 +#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 5) // tProp = 1250ns +#elif CAN_BIT_RATE == 20000 +#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 20) // tProp = 5000ns +#else +#error Invalid CAN_BIT_RATE value used with a 4MHz crystal. +#endif + +//***************************************************************************** +// +// The settings for a 2MHz crystal frequency. +// +//***************************************************************************** +#elif CRYSTAL_FREQ == 2000000 +#if CAN_BIT_RATE == 250000 +#define CAN_BIT_TIMING CAN_BIT_REG(4, 3, 3, 1) // tProp = 500ns +#elif CAN_BIT_RATE == 125000 +#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 1) // tProp = 500ns +#elif CAN_BIT_RATE == 50000 +#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 4) // tProp = 2000ns +#elif CAN_BIT_RATE == 20000 +#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 10) // tProp = 5000ns +#else +#error Invalid CAN_BIT_RATE value used with a 2MHz crystal. +#endif + +//***************************************************************************** +// +// The settings for a 1MHz crystal frequency. +// +//***************************************************************************** +#elif CRYSTAL_FREQ == 1000000 +#if CAN_BIT_RATE == 125000 +#define CAN_BIT_TIMING CAN_BIT_REG(4, 3, 3, 1) // tProp = 1000ns +#elif CAN_BIT_RATE == 50000 +#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 2) // tProp = 2000ns +#elif CAN_BIT_RATE == 20000 +#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 5) // tProp = 5000ns +#else +#error Invalid CAN_BIT_RATE value used with a 1MHz crystal. +#endif + +//***************************************************************************** +// +// An unsupported crystal frequency was specified. +// +//***************************************************************************** +#else +#error The CRYSTAL_FREQ value is not supported by the CAN controller. +#endif + +#endif + +#endif // __BL_CAN_TIMING_H__ diff --git a/boot_loader/bl_check.c b/boot_loader/bl_check.c new file mode 100644 index 0000000..b481013 --- /dev/null +++ b/boot_loader/bl_check.c @@ -0,0 +1,266 @@ +//***************************************************************************** +// +// bl_check.c - Code to check for a forced update. +// +// 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_memmap.h" +#include "inc/hw_sysctl.h" +#include "inc/hw_types.h" +#include "bl_config.h" +#include "boot_loader/bl_check.h" +#include "boot_loader/bl_hooks.h" +#ifdef CHECK_CRC +#include "boot_loader/bl_crc32.h" +#endif + +//***************************************************************************** +// +//! \addtogroup bl_check_api +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// This global is used to remember if a forced update occurred. +// +//***************************************************************************** +#ifdef ENABLE_UPDATE_CHECK +uint32_t g_ui32Forced; +#endif + +//***************************************************************************** +// +// A prototype for the function (in the startup code) for a predictable length +// delay. +// +//***************************************************************************** +extern void Delay(uint32_t ui32Count); + +//***************************************************************************** +// +//! Checks a GPIO for a forced update. +//! +//! This function checks the state of a GPIO to determine if a update is being +//! requested. +//! +//! \return Returns a non-zero value if an update is being requested and zero +//! otherwise. +// +//***************************************************************************** +#ifdef ENABLE_UPDATE_CHECK +uint32_t +CheckGPIOForceUpdate(void) +{ + // + // Enable the required GPIO module. + // + HWREG(SYSCTL_RCGC2) |= FORCED_UPDATE_PERIPH; + + // + // Wait a while before accessing the peripheral. + // + Delay(3); + +#ifdef FORCED_UPDATE_KEY + // + // Unlock the GPIO Access. + // + HWREG(FORCED_UPDATE_PORT + GPIO_O_LOCK) = FORCED_UPDATE_KEY; + HWREG(FORCED_UPDATE_PORT + GPIO_O_CR) = 1 << FORCED_UPDATE_PIN; +#endif + + // + // Enable the pin used to see if an update is being requested. + // + HWREG(FORCED_UPDATE_PORT + GPIO_O_DEN) |= 1 << FORCED_UPDATE_PIN; +#ifdef FORCED_UPDATE_WPU + // + // Set the output drive strength. + // + HWREG(FORCED_UPDATE_PORT + GPIO_O_DR2R) |= 1 << FORCED_UPDATE_PIN; + + // + // Enable the weak pull up. + // + HWREG(FORCED_UPDATE_PORT + GPIO_O_PUR) |= 1 << FORCED_UPDATE_PIN; + + // + // Make sure that the analog mode select register is clear for this pin. + // + HWREG(FORCED_UPDATE_PORT + GPIO_O_AMSEL) &= ~(1 << FORCED_UPDATE_PIN); +#endif +#ifdef FORCED_UPDATE_WPD + // + // Set the output drive strength. + // + HWREG(FORCED_UPDATE_PORT + GPIO_O_DR2R) |= 1 << FORCED_UPDATE_PIN; + + // + // Enable the weak pull down. + // + HWREG(FORCED_UPDATE_PORT + GPIO_O_PDR) |= 1 << FORCED_UPDATE_PIN; + + // + // Make sure that the analog mode select register is clear for this pin. + // This register only appears in DustDevil-class (and later) devices, but + // is a harmless write on Sandstorm- and Fury-class devices. + // + HWREG(FORCED_UPDATE_PORT + GPIO_O_AMSEL) &= ~(1 << FORCED_UPDATE_PIN); +#endif + +#ifdef FORCED_UPDATE_KEY + // + // Unlock the GPIO Access. + // + HWREG(FORCED_UPDATE_PORT + GPIO_O_LOCK) = FORCED_UPDATE_KEY; + HWREG(FORCED_UPDATE_PORT + GPIO_O_CR) = 0; +#endif + + // + // Wait a while before reading the pin. + // + Delay(1000); + + // + // Check the pin to see if an update is being requested. + // + if(HWREG(FORCED_UPDATE_PORT + (1 << (FORCED_UPDATE_PIN + 2))) == + (FORCED_UPDATE_POLARITY << FORCED_UPDATE_PIN)) + { + // + // Remember that this was a forced update. + // + g_ui32Forced = 1; + + return(1); + } + + // + // No update is being requested so return 0. + // + return(0); +} +#endif + +//***************************************************************************** +// +//! Checks if an update is needed or is being requested. +//! +//! This function detects if an update is being requested or if there is no +//! valid code presently located on the microcontroller. This is used to tell +//! whether or not to enter update mode. +//! +//! \return Returns a non-zero value if an update is needed or is being +//! requested and zero otherwise. +// +//***************************************************************************** +uint32_t +CheckForceUpdate(void) +{ +#ifdef CHECK_CRC + uint32_t ui32Retcode; +#endif + +#ifdef BL_CHECK_UPDATE_FN_HOOK + // + // If the update check function is hooked, call the application to determine + // how to proceed. + // + return(BL_CHECK_UPDATE_FN_HOOK()); +#else + uint32_t *pui32App; + +#ifdef ENABLE_UPDATE_CHECK + g_ui32Forced = 0; +#endif + + // + // See if the first location is 0xfffffffff or something that does not + // look like a stack pointer, or if the second location is 0xffffffff or + // something that does not look like a reset vector. + // + pui32App = (uint32_t *)APP_START_ADDRESS; + if((pui32App[0] == 0xffffffff) || + ((pui32App[0] & 0xfff00000) != 0x20000000) || + (pui32App[1] == 0xffffffff) || + ((pui32App[1] & 0xfff00001) != 0x00000001)) + { + return(1); + } + + // + // If required, scan the image for an embedded CRC and ensure that it + // matches the current CRC of the image. + // +#ifdef CHECK_CRC + InitCRC32Table(); + ui32Retcode = CheckImageCRC32(pui32App); + + // + // If ENFORCE_CRC is defined, we only boot the image if the CRC is + // present in the image information header and the value calculated + // matches the value in the header. If ENFORCE_CRC is not defined, we + // the image if the CRC is good but also if the length field of the header + // is zero (which typically indicates that the post-build step of running + // binpack to add the length and CRC to the header was not run). + // +#ifdef ENFORCE_CRC + if(ui32Retcode != CHECK_CRC_OK) +#else + if((ui32Retcode != CHECK_CRC_OK) && (ui32Retcode != CHECK_CRC_NO_LENGTH)) +#endif + { + // + // The CRC32 image check failed indicating that the image is + // corrupt (or doesn't have the CRC embedded correctly). Either way, + // fail the update check and force the boot loader to retain control. + // + return(2); + } +#endif + +#ifdef ENABLE_UPDATE_CHECK + // + // If simple GPIO checking is configured, determine whether or not to force + // an update. + // + return(CheckGPIOForceUpdate()); +#else + // + // GPIO checking is not required so, if we get here, a valid image exists + // and no update is needed. + // + return(0); +#endif +#endif +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/boot_loader/bl_check.h b/boot_loader/bl_check.h new file mode 100644 index 0000000..a3e0519 --- /dev/null +++ b/boot_loader/bl_check.h @@ -0,0 +1,39 @@ +//***************************************************************************** +// +// bl_check.h - Definitions for the forced update check function. +// +// Copyright (c) 2007-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. +// +//***************************************************************************** + +#ifndef __BL_CHECK_H__ +#define __BL_CHECK_H__ + +//***************************************************************************** +// +// Prototype for the forced update check function. +// +//***************************************************************************** +extern uint32_t CheckForceUpdate(void); +#ifdef ENABLE_UPDATE_CHECK +extern uint32_t CheckGPIOForceUpdate(void); +extern uint32_t g_ui32Forced; +#endif + +#endif // __BL_CHECK_H__ diff --git a/boot_loader/bl_commands.h b/boot_loader/bl_commands.h new file mode 100644 index 0000000..f666e15 --- /dev/null +++ b/boot_loader/bl_commands.h @@ -0,0 +1,242 @@ +//***************************************************************************** +// +// bl_commands.h - The list of commands and return messages supported by 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. +// +//***************************************************************************** + +#ifndef __BL_COMMANDS_H__ +#define __BL_COMMANDS_H__ + +//***************************************************************************** +// +// This command is used to receive an acknowledge from the the boot loader +// proving that communication has been established. This command is a single +// byte. +// +// The format of the command is as follows: +// +// uint8_t ui8Command[1]; +// +// ui8Command[0] = COMMAND_PING; +// +//***************************************************************************** +#define COMMAND_PING 0x20 + +//***************************************************************************** +// +// This command is sent to the boot loader to indicate where to store data and +// how many bytes will be sent by the COMMAND_SEND_DATA commands that follow. +// The command consists of two 32-bit values that are both transferred MSB +// first. The first 32-bit value is the address to start programming data +// into, while the second is the 32-bit size of the data that will be sent. +// This command also triggers an erasure of the full application area in the +// flash or possibly the entire flash depending on the address used. This +// causes the command to take longer to send the ACK/NAK in response to the +// command. This command should be followed by a COMMAND_GET_STATUS to ensure +// that the program address and program size were valid for the microcontroller +// running the boot loader. +// +// The format of the command is as follows: +// +// uint8_t ui8Command[9]; +// +// ui8Command[0] = COMMAND_DOWNLOAD; +// ui8Command[1] = Program Address [31:24]; +// ui8Command[2] = Program Address [23:16]; +// ui8Command[3] = Program Address [15:8]; +// ui8Command[4] = Program Address [7:0]; +// ui8Command[5] = Program Size [31:24]; +// ui8Command[6] = Program Size [23:16]; +// ui8Command[7] = Program Size [15:8]; +// ui8Command[8] = Program Size [7:0]; +// +//***************************************************************************** +#define COMMAND_DOWNLOAD 0x21 + +//***************************************************************************** +// +// This command is sent to the boot loader to transfer execution control to the +// specified address. The command is followed by a 32-bit value, transferred +// MSB first, that is the address to which execution control is transferred. +// +// The format of the command is as follows: +// +// uint8_t ui8Command[5]; +// +// ui8Command[0] = COMMAND_RUN; +// ui8Command[1] = Run Address [31:24]; +// ui8Command[2] = Run Address [23:16]; +// ui8Command[3] = Run Address [15:8]; +// ui8Command[4] = Run Address [7:0]; +// +//***************************************************************************** +#define COMMAND_RUN 0x22 + +//***************************************************************************** +// +// This command returns the status of the last command that was issued. +// Typically this command should be received after every command is sent to +// ensure that the previous command was successful or, if unsuccessful, to +// properly respond to a failure. The command requires one byte in the data of +// the packet and the boot loader should respond by sending a packet with one +// byte of data that contains the current status code. +// +// The format of the command is as follows: +// +// uint8_t ui8Command[1]; +// +// ui8Command[0] = COMMAND_GET_STATUS; +// +// The following are the definitions for the possible status values that can be +// returned from the boot loader when COMMAND_GET_STATUS is sent to +// the microcontroller. +// +// COMMAND_RET_SUCCESS +// COMMAND_RET_UNKNOWN_CMD +// COMMAND_RET_INVALID_CMD +// COMMAND_RET_INVALID_ADD +// COMMAND_RET_FLASH_FAIL +// COMMAND_RET_CRC_FAIL +// +//***************************************************************************** +#define COMMAND_GET_STATUS 0x23 + +//***************************************************************************** +// +// This command should only follow a COMMAND_DOWNLOAD command or another +// COMMAND_SEND_DATA command, if more data is needed. Consecutive send data +// commands automatically increment the address and continue programming from +// the previous location. The transfer size is limited by the size of the +// receive buffer in the boot loader (as configured by the BUFFER_SIZE +// parameter). The command terminates programming once the number of bytes +// indicated by the COMMAND_DOWNLOAD command has been received. Each time this +// function is called, it should be followed by a COMMAND_GET_STATUS command to +// ensure that the data was successfully programmed into the flash. If the +// boot loader sends a NAK to this command, the boot loader will not increment +// the current address to allow retransmission of the previous data. +// +// The format of the command is as follows: +// +// uint8_t ui8Command[9]; +// +// ui8Command[0] = COMMAND_SEND_DATA; +// ui8Command[1] = Data[0]; +// ui8Command[2] = Data[1]; +// ui8Command[3] = Data[2]; +// ui8Command[4] = Data[3]; +// ui8Command[5] = Data[4]; +// ui8Command[6] = Data[5]; +// ui8Command[7] = Data[6]; +// ui8Command[8] = Data[7]; +// +//***************************************************************************** +#define COMMAND_SEND_DATA 0x24 + +//***************************************************************************** +// +// This command is used to tell the boot loader to reset. This is used after +// downloading a new image to the microcontroller to cause the new application +// or the new boot loader to start from a reset. The normal boot sequence +// occurs and the image runs as if from a hardware reset. It can also be used +// to reset the boot loader if a critical error occurs and the host device +// wants to restart communication with the boot loader. +// +// The format of the command is as follows: +// +// uint8_t ui8Command[1]; +// +// ui8Command[0] = COMMAND_RESET; +// +// The boot loader responds with an ACK signal to the host device before +// actually executing the software reset on the microcontroller running the +// boot loader. This informs the updater application that the command was +// received successfully and the part will be reset. +// +//***************************************************************************** +#define COMMAND_RESET 0x25 + +//***************************************************************************** +// +// This is returned in response to a COMMAND_GET_STATUS command and indicates +// that the previous command completed successful. +// +//***************************************************************************** +#define COMMAND_RET_SUCCESS 0x40 + +//***************************************************************************** +// +// This is returned in response to a COMMAND_GET_STATUS command and indicates +// that the command sent was an unknown command. +// +//***************************************************************************** +#define COMMAND_RET_UNKNOWN_CMD 0x41 + +//***************************************************************************** +// +// This is returned in response to a COMMAND_GET_STATUS command and indicates +// that the previous command was formatted incorrectly. +// +//***************************************************************************** +#define COMMAND_RET_INVALID_CMD 0x42 + +//***************************************************************************** +// +// This is returned in response to a COMMAND_GET_STATUS command and indicates +// that the previous download command contained an invalid address value. +// +//***************************************************************************** +#define COMMAND_RET_INVALID_ADR 0x43 + +//***************************************************************************** +// +// This is returned in response to a COMMAND_GET_STATUS command and indicates +// that an attempt to program or erase the flash has failed. +// +//***************************************************************************** +#define COMMAND_RET_FLASH_FAIL 0x44 + +//***************************************************************************** +// +// This is returned in response to a COMMAND_GET_STATUS command and indicates +// that the boot loader is configured to check the embedded CRC32 in the +// downloaded image but the check failed. This status can only be returned +// after the last COMMAND_SEND_DATA has been received and processed, and only +// if CHECK_CRC is defined in the boot loader configuration. +// +//***************************************************************************** +#define COMMAND_RET_CRC_FAIL 0x45 + +//***************************************************************************** +// +// This is the value that is sent to acknowledge a packet. +// +//***************************************************************************** +#define COMMAND_ACK 0xcc + +//***************************************************************************** +// +// This is the value that is sent to not-acknowledge a packet. +// +//***************************************************************************** +#define COMMAND_NAK 0x33 + +#endif // __BL_COMMANDS_H__ diff --git a/boot_loader/bl_config.c b/boot_loader/bl_config.c new file mode 100644 index 0000000..9c26068 --- /dev/null +++ b/boot_loader/bl_config.c @@ -0,0 +1,164 @@ +//***************************************************************************** +// +// bl_config.c - A dummy C file to generate bl_config.in from bl_config.h. +// +// Copyright (c) 2007-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 "bl_config.h" + +//***************************************************************************** +// +// Since the RV-MDK assembler is not able to run assembly code through the C +// preprocessor, the relevant contents of bl_config.h need to be converted to +// assembly format for inclusion into the RV-MDK startup code. This file +// performs this conversion when manually run through the C preprocessor via: +// +// armcc --device DLM -o bl_config.inc -E bl_config.c +// +// This file does not contain valid C code and will fail to compile (-E tells +// the compiler to preprocess but not attempt to compile the code). +// +//***************************************************************************** + +//***************************************************************************** +// +// Define an assembler symbol for the stack size. +// +//***************************************************************************** +_STACK_SIZE equ STACK_SIZE + +//***************************************************************************** +// +// Define an assembler symbol for the application starting address. +// +//***************************************************************************** +_APP_START_ADDRESS equ APP_START_ADDRESS + +//***************************************************************************** +// +// Define an assembler symbol for the application vector table address. +// +//***************************************************************************** +_VTABLE_START_ADDRESS equ VTABLE_START_ADDRESS + +//***************************************************************************** +// +// Define an assembler symbol if the MOSCFAIL handler is enabled. +// +//***************************************************************************** +#ifdef ENABLE_MOSCFAIL_HANDLER +_ENABLE_MOSCFAIL_HANDLER equ 1 +#endif + +//***************************************************************************** +// +// Define an assembler symbol if update via the UART is enabled. +// +//***************************************************************************** +#ifdef UART_ENABLE_UPDATE +_UART_ENABLE_UPDATE equ 1 +#endif + +//***************************************************************************** +// +// Define an assember symbol if UART autobauding is enabled. +// +//***************************************************************************** +#ifdef UART_AUTOBAUD +_UART_AUTOBAUD equ 1 +#endif + +//***************************************************************************** +// +// Define an assembler symbol if update via Ethernet is enabled. +// +//***************************************************************************** +#ifdef ENET_ENABLE_UPDATE +_ENET_ENABLE_UPDATE equ 1 +#endif + +//***************************************************************************** +// +// Define an assembler symbol if update via CAN is enabled. +// +//***************************************************************************** +#ifdef CAN_ENABLE_UPDATE +_CAN_ENABLE_UPDATE equ 1 +#endif + +//***************************************************************************** +// +// Define an assembler symbol if update via USB is enabled. +// +//***************************************************************************** +#ifdef USB_ENABLE_UPDATE +_USB_ENABLE_UPDATE equ 1 +#endif + +//***************************************************************************** +// +// Define an assembler symbol if a hardware initialization hook is provided. +// +//***************************************************************************** +#ifdef BL_HW_INIT_FN_HOOK +#define _quote(x) #x +#define quote(x) _quote(x) + gbls _BL_HW_INIT_FN_HOOK +_BL_HW_INIT_FN_HOOK sets quote(BL_HW_INIT_FN_HOOK) +#undef _quote +#undef quote +#endif + +//***************************************************************************** +// +// Define an assembler symbol if an initialization hook is provided. +// +//***************************************************************************** +#ifdef BL_INIT_FN_HOOK +#define _quote(x) #x +#define quote(x) _quote(x) + gbls _BL_INIT_FN_HOOK +_BL_INIT_FN_HOOK sets quote(BL_INIT_FN_HOOK) +#undef _quote +#undef quote +#endif + +//***************************************************************************** +// +// Define an assembler symbol if a re-initialization hook is provided. +// +//***************************************************************************** +#ifdef BL_REINIT_FN_HOOK +#define _quote(x) #x +#define quote(x) _quote(x) + gbls _BL_REINIT_FN_HOOK +_BL_REINIT_FN_HOOK sets quote(BL_REINIT_FN_HOOK) +#undef _quote +#undef quote +#endif + +//***************************************************************************** +// +// The assembler will require an end statement at the end of the output +// bl_config.inc file. +// +//***************************************************************************** + end diff --git a/boot_loader/bl_config.h.tmpl b/boot_loader/bl_config.h.tmpl new file mode 100644 index 0000000..99ab978 --- /dev/null +++ b/boot_loader/bl_config.h.tmpl @@ -0,0 +1,950 @@ +//***************************************************************************** +// +// bl_config.h - The configurable parameters of the boot loader. +// +// Copyright (c) 2010-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. +// +//***************************************************************************** + +#ifndef __BL_CONFIG_H__ +#define __BL_CONFIG_H__ + +//***************************************************************************** +// +// The following defines are used to configure the operation of the boot +// loader. For each define, its interactions with other defines are described. +// First is the dependencies (i.e. the defines that must also be defined if it +// is defined), next are the exclusives (i.e. the defines that can not be +// defined if it is defined), and finally are the requirements (i.e. the +// defines that must be defined if it is defined). +// +// The following defines must be defined in order for the boot loader to +// operate: +// +// One of CAN_ENABLE_UPDATE, ENET_ENABLE_UPDATE, I2C_ENABLE_UPDATE, +// SSI_ENABLE_UPDATE, UART_ENABLE_UPDATE, or USB_ENABLE_UPDATE +// APP_START_ADDRESS +// STACK_SIZE +// BUFFER_SIZE +// +//***************************************************************************** + +//***************************************************************************** +// +// The frequency of the crystal used to clock the microcontroller. +// +// This defines the crystal frequency used by the microcontroller running the +// boot loader. If this is unknown at the time of production, then use the +// UART_AUTOBAUD feature to properly configure the UART. +// +// Depends on: None +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +#define CRYSTAL_FREQ 8000000 + +//***************************************************************************** +// +// This enables the boosting of the LDO voltage to 2.75V. For boot loader +// configurations that enable the PLL (for example, using the Ethernet port) +// on a part that has the PLL errata, this should be enabled. This applies to +// revision A2 of Fury-class devices. +// +// Depends on: None +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define BOOST_LDO_VOLTAGE + +//***************************************************************************** +// +// The starting address of the application. This must be a multiple of 1024 +// bytes (making it aligned to a page boundary). A vector table is expected at +// this location, and the perceived validity of the vector table (stack located +// in SRAM, reset vector located in flash) is used as an indication of the +// validity of the application image. +// +// The flash image of the boot loader must not be larger than this value. +// +// Depends on: None +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +#define APP_START_ADDRESS 0x00001000 + +//***************************************************************************** +// +// The address at which the application locates its exception vector table. +// This must be a multiple of 1KB (making it aligned to a page boundary). +// Typically, an application will start with its vector table and this value +// will default to APP_START_ADDRESS. This option is provided to cater for +// applications which run from external memory which may not be accessible by +// the NVIC (the vector table offset register is only 30 bits long). +// +// Depends on: None +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +#define VTABLE_START_ADDRESS 0x00001000 + +//***************************************************************************** +// +// The size of a single, erasable page in the flash. This must be a power +// of 2. The default value of 1KB represents the page size for the internal +// flash on all Tiva MCUs and this value should only be overridden if +// configuring a boot loader to access external flash devices with a page size +// different from this. +// +// Depends on: None +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +#define FLASH_PAGE_SIZE 0x00000400 + +//***************************************************************************** +// +// The amount of space at the end of flash to reserved. This must be a +// multiple of 1024 bytes (making it aligned to a page boundary). This +// reserved space is not erased when the application is updated, providing +// non-volatile storage that can be used for parameters. +// +// Depends on: None +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define FLASH_RSVD_SPACE 0x00000800 + +//***************************************************************************** +// +// The number of words of stack space to reserve for the boot loader. +// +// Depends on: None +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +#define STACK_SIZE 64 + +//***************************************************************************** +// +// The number of words in the data buffer used for receiving packets. This +// value must be at least 3. If using autobauding on the UART, this must be at +// least 20. The maximum usable value is 65 (larger values will result in +// unused space in the buffer). +// +// Depends on: None +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +#define BUFFER_SIZE 20 + +//***************************************************************************** +// +// Enables updates to the boot loader. Updating the boot loader is an unsafe +// operation since it is not fully fault tolerant (losing power to the device +// part way though could result in the boot loader no longer being present in +// flash). +// +// Depends on: None +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define ENABLE_BL_UPDATE + +//***************************************************************************** +// +// This definition will cause the the boot loader to erase the entire flash on +// updates to the boot loader or to erase the entire application area when the +// application is updated. This erases any unused sections in the flash before +// the firmware is updated. +// +// Depends on: None +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define FLASH_CODE_PROTECTION + +//***************************************************************************** +// +// Enables the call to decrypt the downloaded data before writing it into +// flash. The decryption routine is empty in the reference boot loader source, +// which simply provides a placeholder for adding an actual decrypter. +// +// Depends on: None +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define ENABLE_DECRYPTION + +//***************************************************************************** +// +// Enables support for the MOSCFAIL handler in the NMI interrupt. +// Note: Sandstorm or Fury devices do not provide the MOSCFAIL reset, so this +// feature should not be enabled for these devices. +// +// Depends on: None +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define ENABLE_MOSCFAIL_HANDLER + +//***************************************************************************** +// +// Enables the pin-based forced update check. When enabled, the boot loader +// will go into update mode instead of calling the application if a pin is read +// at a particular polarity, forcing an update operation. In either case, the +// application is still able to return control to the boot loader in order to +// start an update. +// +// Depends on: None +// Exclusive of: None +// Requires: FORCED_UPDATE_PERIPH, FORCED_UPDATE_PORT, FORCED_UPDATE_PIN, +// FORCED_UPDATE_POLARITY +// +//***************************************************************************** +//#define ENABLE_UPDATE_CHECK + +//***************************************************************************** +// +// The GPIO module to enable in order to check for a forced update. This will +// be one of the SYSCTL_RCGC2_GPIOx values, where "x" is replaced with the port +// name (such as B). The value of "x" should match the value of "x" for +// FORCED_UPDATE_PORT. +// +// Depends on: ENABLE_UPDATE_CHECK +// Exclusive of: None +// Requries: None +// +//***************************************************************************** +//#define FORCED_UPDATE_PERIPH SYSCTL_RCGC2_GPIOB + +//***************************************************************************** +// +// The GPIO port to check for a forced update. This will be one of the +// GPIO_PORTx_BASE values, where "x" is replaced with the port name (such as +// B). The value of "x" should match the value of "x" for +// FORCED_UPDATE_PERIPH. +// +// Depends on: ENABLE_UPDATE_CHECK +// Exclusive of: None +// Requries: None +// +//***************************************************************************** +//#define FORCED_UPDATE_PORT GPIO_PORTB_BASE + +//***************************************************************************** +// +// The pin to check for a forced update. This is a value between 0 and 7. +// +// Depends on: ENABLE_UPDATE_CHECK +// Exclusive of: None +// Requries: None +// +//***************************************************************************** +//#define FORCED_UPDATE_PIN 4 + +//***************************************************************************** +// +// The polarity of the GPIO pin that results in a forced update. This value +// should be 0 if the pin should be low and 1 if the pin should be high. +// +// Depends on: ENABLE_UPDATE_CHECK +// Exclusive of: None +// Requries: None +// +//***************************************************************************** +//#define FORCED_UPDATE_POLARITY 0 + +//***************************************************************************** +// +// This enables a weak pull up for the GPIO pin used in a forced update. This +// value should be 0 if the pin should be have an internal weak pull down and +// 1 if the pin should have an interal weak pull up. +// Only FORCED_UPDATE_WPU or FORCED_UPDATE_WPD or neither should be defined. +// +// Depends on: ENABLE_UPDATE_CHECK +// Exclusive of: None +// Requries: None +// +//***************************************************************************** +//#define FORCED_UPDATE_WPU +//#define FORCED_UPDATE_WPD + +//***************************************************************************** +// +// This enables the use of the GPIO_LOCK mechanism for configuration of +// protected GPIO pins (for example JTAG pins). If this value is not defined, +// the locking mechanism will not be used. The only legal values for this +// feature are GPIO_LOCK_KEY for Fury devices and GPIO_LOCK_KEY_DD for all +// other devices except Sandstorm devices, which do not support this feature. +// +// Depends on: ENABLE_UPDATE_CHECK +// Exclusive of: None +// Requries: None +// +//***************************************************************************** +//#define FORCED_UPDATE_KEY GPIO_LOCK_KEY +//#define FORCED_UPDATE_KEY GPIO_LOCK_KEY_DD + +//***************************************************************************** +// +// Selects the UART as the port for communicating with the boot loader. +// +// Depends on: None +// Exclusive of: CAN_ENABLE_UPDATE, ENET_ENABLE_UPDATE, I2C_ENABLE_UPDATE, +// SSI_ENABLE_UPDATE, USB_ENABLE_UPDATE +// Requires: UART_AUTOBAUD or UART_FIXED_BAUDRATE +// +//***************************************************************************** +//#define UART_ENABLE_UPDATE + +//***************************************************************************** +// +// Enables automatic baud rate detection. This can be used if the crystal +// frequency is unknown, or if operation at different baud rates is desired. +// +// Depends on: UART_ENABLE_UPDATE +// Exclusive of: UART_FIXED_BAUDRATE +// Requires: None +// +//***************************************************************************** +//#define UART_AUTOBAUD + +//***************************************************************************** +// +// Selects the baud rate to be used for the UART. +// +// Depends on: UART_ENABLE_UPDATE, CRYSTAL_FREQ +// Exclusive of: UART_AUTOBAUD +// Requires: None +// +//***************************************************************************** +//#define UART_FIXED_BAUDRATE 115200 + +//***************************************************************************** +// +// Selects the SSI port as the port for communicating with the boot loader. +// +// Depends on: None +// Exclusive of: CAN_ENABLE_UPDATE, ENET_ENABLE_UPDATE, I2C_ENABLE_UPDATE, +// UART_ENABLE_UPDATE, USB_ENABLE_UPDATE +// Requires: None +// +//***************************************************************************** +//#define SSI_ENABLE_UPDATE + +//***************************************************************************** +// +// Selects the I2C port as the port for communicating with the boot loader. +// +// Depends on: None +// Exclusive of: CAN_ENABLE_UPDATE, ENET_ENABLE_UPDATE, SSI_ENABLE_UPDATE, +// UART_ENABLE_UPDATE, USB_ENABLE_UPDATE +// Requires: I2C_SLAVE_ADDR +// +//***************************************************************************** +//#define I2C_ENABLE_UPDATE + +//***************************************************************************** +// +// Specifies the I2C address of the boot loader. +// +// Depends on: I2C_ENABLE_UPDATE +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define I2C_SLAVE_ADDR 0x42 + +//***************************************************************************** +// +// Selects Ethernet update via the BOOTP/TFTP protocol. +// +// Depends on: None +// Exclusive of: CAN_ENABLE_UPDATE, I2C_ENABLE_UPDATE, SSI_ENABLE_UPDATE, +// UART_ENABLE_UPDATE, USB_ENABLE_UPDATE +// Requires: CRYSTAL_FREQ +// +//***************************************************************************** +//#define ENET_ENABLE_UPDATE + +//***************************************************************************** +// +// Selects if the Ethernet LEDs should be enabled. +// +// Depends on: ENET_ENABLE_UPDATE +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define ENET_ENABLE_LEDS + +//***************************************************************************** +// +// Selects the Ethernet MAC address. If not specified, the MAC address is +// taken from the user registers. +// +// Depends on: ENET_ENABLE_UPDATE +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define ENET_MAC_ADDR0 0x00 +//#define ENET_MAC_ADDR1 0x00 +//#define ENET_MAC_ADDR2 0x00 +//#define ENET_MAC_ADDR3 0x00 +//#define ENET_MAC_ADDR4 0x00 +//#define ENET_MAC_ADDR5 0x00 + +//***************************************************************************** +// +// Sets the name of the BOOTP server to use. This can be used to request that +// a particular BOOTP server respond to our request; the value will be either +// the server's name, or a nickname used by that server. If not defined then +// any BOOTP server is allowed to respond. +// +// Depends on: ENET_ENABLE_UPDATE +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define ENET_BOOTP_SERVER "tiva" + +//***************************************************************************** +// +// Selects USB update via Device Firmware Update class. +// +// Depends on: None +// Exclusive of: CAN_ENABLE_UPDATE, ENET_ENABLE_UPDATE, I2C_ENABLE_UPDATE, +// SSI_ENABLE_UPDATE, UART_ENABLE_UPDATE, +// Requires: CRYSTAL_FREQ, USB_VENDOR_ID, USB_PRODUCT_ID +// +//***************************************************************************** +//#define USB_ENABLE_UPDATE + +//***************************************************************************** +// +// The USB vendor ID published by the DFU device. This value is the TI +// Tiva vendor ID. Change this to the vendor ID you have been assigned by +// USB-IF. +// +// Depends on: USB_ENABLE_UPDATE +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define USB_VENDOR_ID 0x1cbe + +//***************************************************************************** +// +// The USB device ID published by the DFU device. If you are using your own +// vendor ID, chose a device ID that is different from the ID you use in +// non-update operation. If you have sublicensed TI's vendor ID, you must +// use an assigned product ID here. +// +// Depends on: USB_ENABLE_UPDATE +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define USB_PRODUCT_ID 0x00ff + +//***************************************************************************** +// +// Selects the BCD USB device release number published in the device +// descriptor. +// +// Depends on: USB_ENABLE_UPDATE +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define USB_DEVICE_ID 0x0001 + +//***************************************************************************** +// +// Sets the maximum power consumption that the DFU device will report to the +// USB host in the configuration descriptor. Units are milliamps. +// +// Depends on: USB_ENABLE_UPDATE +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define USB_MAX_POWER 150 + +//***************************************************************************** +// +// Determines whether the DFU device reports to the host that it is self +// powered (defined as 0) or bus powered (defined as 1). +// +// Depends on: USB_ENABLE_UPDATE +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define USB_BUS_POWERED 1 + +//***************************************************************************** +// +// Specifies the GPIO peripheral associated with the USB host/device mux. +// +// Depends on: USB_ENABLE_UPDATE +// Exclusive of: None +// Requires: USB_MUX_PERIPH, USB_MUX_PORT, USB_MUX_PIN, USB_MUX_DEVICE +// +//***************************************************************************** +//#define USB_HAS_MUX + +//***************************************************************************** +// +// Specifies the GPIO peripheral associated with the USB host/device mux. +// +// Depends on: USB_ENABLE_UPDATE, USB_HAS_MUX +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define USB_MUX_PERIPH SYSCTL_RCGC2_GPIOH + +//***************************************************************************** +// +// Specifies the GPIO port associated with the USB host/device mux. +// +// Depends on: USB_ENABLE_UPDATE, USB_HAS_MUX +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define USB_MUX_PORT GPIO_PORTH_BASE + +//***************************************************************************** +// +// Specifies the GPIO pin number used to switch the USB host/device mux. Valid +// values are 0 through 7. +// +// Depends on: USB_ENABLE_UPDATE, USB_HAS_MUX +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define USB_MUX_PIN 2 + +//***************************************************************************** +// +// Specifies the state to set the GPIO pin to to select USB device mode via +// the USB host/device mux. Valid values are 1 (high) or 0 (low). +// +// Depends on: USB_ENABLE_UPDATE, USB_HAS_MUX +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define USB_MUX_DEVICE 1 + +//***************************************************************************** +// +// Selects the CAN port as the port for communicating with the boot loader. +// +// Depends on: None +// Exclusive of: ENET_ENABLE_UPDATE, I2C_ENABLE_UPDATE, SSI_ENABLE_UPDATE, +// UART_ENABLE_UPDATE, USB_ENABLE_UPDATE +// Requires: CAN_RX_PERIPH, CAN_RX_PORT, CAN_RX_PIN, CAN_TX_PERIPH, +// CAN_TX_PORT, CAN_TX_PIN, CAN_BIT_RATE, CRYSTAL_FREQ. +// +//***************************************************************************** +//#define CAN_ENABLE_UPDATE + +//***************************************************************************** +// +// Enables the UART to CAN bridging for use when the CAN port is selected for +// communicating with the boot loader. +// +// Depends on: CAN_ENABLE_UPDATE +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define CAN_UART_BRIDGE + +//***************************************************************************** +// +// Specifies the GPIO peripheral associated with CAN0 RX pin used by the boot +// loader. +// +// Depends on: CAN_ENABLE_UPDATE +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define CAN_RX_PERIPH SYSCTL_RCGC2_GPIOA + +//***************************************************************************** +// +// Specifies the GPIO port associated with CAN0 RX pin used by the boot loader. +// +// Depends on: CAN_ENABLE_UPDATE +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define CAN_RX_PORT GPIO_PORTA_BASE + +//***************************************************************************** +// +// Specifies the GPIO pin number associated with CAN0 RX pin used by the boot +// loader. +// +// Depends on: CAN_ENABLE_UPDATE +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define CAN_RX_PIN 4 + +//***************************************************************************** +// +// Specifies the GPIO peripheral associated with CAN0 TX pin used by the boot +// loader. +// +// Depends on: CAN_ENABLE_UPDATE +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define CAN_TX_PERIPH SYSCTL_RCGC2_GPIOA + +//***************************************************************************** +// +// Specifies the GPIO port associated with CAN0 TX pin used by the boot loader. +// +// Depends on: CAN_ENABLE_UPDATE +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define CAN_TX_PORT GPIO_PORTA_BASE + +//***************************************************************************** +// +// Specifies the GPIO pin number associated with CAN0 TX pin used by the boot +// loader. +// +// Depends on: CAN_ENABLE_UPDATE +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define CAN_TX_PIN 5 + +//***************************************************************************** +// +// Specifies the bit rate for CAN0 used by the boot loader. +// +// Depends on: CAN_ENABLE_UPDATE +// Exclusive of: None +// Requires: None +// +//***************************************************************************** +//#define CAN_BIT_RATE 1000000 + +//***************************************************************************** +// +// Boot loader hook functions. +// +// The following defines allow you to add application-specific function which +// are called at various points during boot loader execution. +// +//***************************************************************************** + +//***************************************************************************** +// +// Performs application-specific low level hardware initialization on system +// reset. +// +// If hooked, this function will be called immediately after the boot loader +// code relocation completes. An application may perform any required low +// hardware initialization during this function. Note that the system clock +// has not been set when this function is called. Initialization that assumes +// the system clock is set may be performed in the BL_INIT_FN_HOOK function +// instead. +// +// void MyHwInitFunc(void); +// +//***************************************************************************** +//#define BL_HW_INIT_FN_HOOK MyHwInitFunc + +//***************************************************************************** +// +// Performs application-specific initialization on system reset. +// +// If hooked, this function will be called immediately after the boot loader +// sets the system clock. An application may perform any additional +// initialization during this function. +// +// void MyInitFunc(void); +// +//***************************************************************************** +//#define BL_INIT_FN_HOOK MyInitFunc + +//***************************************************************************** +// +// Performs application-specific reinitialization on boot loader entry via SVC. +// +// If hooked, this function will be called immediately after the boot loader +// reinitializes the system clock when it is entered from an application +// via the SVC mechanism rather than as a result of a system reset. An +// application may perform any additional reinitialization in this function. +// +// void MyReinitFunc(void); +// +//***************************************************************************** +//#define BL_REINIT_FN_HOOK MyReinitFunc + +//***************************************************************************** +// +// Informs an application that a download is starting. +// +// If hooked, this function will be called when a new firmware download is +// about to start. The application may use this signal to initialize any +// progress display. +// +// void MyStartFunc(void); +// +//***************************************************************************** +//#define BL_START_FN_HOOK MyStartFunc + +//***************************************************************************** +// +// Informs an application of download progress. +// +// If hooked, this function will be called periodically during firmware +// download. The application may use this to update its user interface. +// When using a protocol which does not inform the client of the final size of +// the download in advance (e.g. TFTP), the ulTotal parameter will be 0, +// otherwise it indicates the expected size of the complete download. +// +// void MyProgressFunc(unsigned long ulCompleted, unsigned long ulTotal); +// +// where: +// +// - ulCompleted indicates the number of bytes already downloaded. +// - ulTotal indicates the number of bytes expected or 0 if this is not known. +// +//***************************************************************************** +//#define BL_PROGRESS_FN_HOOK MyProgressFunc + +//***************************************************************************** +// +// Informs an application that a download has completed. +// +// If hooked, this function will be called when a firmware download ends. +// The application may use this signal to update its user interface. Typically +// a system reset will occur shortly after this function returns as the boot +// loader attempts to boot the new image. +// +// void MyEndFunc(void); +// +//***************************************************************************** +//#define BL_END_FN_HOOK MyEndFunc + +//***************************************************************************** +// +// Allows an application to perform in-place data decryption during download. +// +// If hooked, this function will be called on receipt of any new block of +// downloaded firmware image data. The application must decrypt this data +// in place then return at which point the boot loader will write the data to +// flash. +// +// void MyDecryptionFunc(unsigned char *pucBuffer, unsigned long ulSize); +// +// where: +// +// - pucBuffer points to the first byte of data to be decrypted. +// - ulSize indicates the number of bytes of data at pucBuffer. +// +//***************************************************************************** +//#define BL_DECRYPT_FN_HOOK MyDecryptionFunc + +//***************************************************************************** +// +// Allows an application to force a new firmware download. +// +// If hooked, this function will be called after a system reset (following +// basic initialization and the initialization hook function) to give the +// application an opportunity to force a new firmware download. Depending upon +// the return code, the boot loader will either boot the existing firmware +// image or wait for a new download to be started. +// +// Note that this hook takes precedence over ENABLE_UPDATE_CHECK settings. If +// the hook function is defined, the basic GPIO check offered by +// ENABLE_UPDATE_CHECK does not take place. +// +// unsigned long MyCheckUpdateFunc(void); +// +// where the return code is 0 if the boot loader should boot the existing +// image (if found) or non-zero to indicate that the boot loader should retain +// control and wait for a new firmware image to be downloaded. +// +//***************************************************************************** +//#define BL_CHECK_UPDATE_FN_HOOK MyCheckUpdateFunc + +//***************************************************************************** +// +// Allows an application to replace the flash block erase function. +// +// If hooked, this function will be called whenever a block of flash is to +// be erased. The function must erase the block and block until the operation +// has completed. The size of the block which will be erased is defined by +// FLASH_BLOCK_SIZE. +// +// void MyFlashEraseFunc(unsigned long ulBlockAddr); +// +// where: +// +// - ulBlockAddr is the address of the flash block to be erased. +// +//***************************************************************************** +//#define BL_FLASH_ERASE_FN_HOOK MyFlashEraseFunc + +//***************************************************************************** +// +// Allows an application to replace the flash programming function. +// +// If hooked, this function will be called whenever a block of data is to be +// be written to flash. The function must program the supplied data and block +// until the operation has has completed. +// +// void MyFlashProgramFunc(unsigned long ulDstAddr, +// unsigned char *pucSrcData, +// unsigned long ulLength); +// +// where: +// +// - ulDstAddr is the address in flash at which the data is to be programmed. +// This must be a multiple of 4. +// - pucSrcData points to the first byte of the data to program. +// - ulLength is the number of bytes of data to program. This must be a +// multiple of 4. +// +//***************************************************************************** +//#define BL_FLASH_PROGRAM_FN_HOOK MyFlashProgramFunc + +//***************************************************************************** +// +// Allows an application to replace the flash error clear function. +// +// If hooked, this function will be called before each flash erase or program +// operation. The function must clear any flash error indicators and prepare +// to detect access violations that may occur in a future erase or program +// operation. +// +// void MyFlashClearErrorFunc(void); +// +//***************************************************************************** +//#define BL_FLASH_CL_ERR_FN_HOOK MyFlashClearErrorFunc + +//***************************************************************************** +// +// Reports whether or not a flash access violation error has occurred. +// +// If hooked, this function will be called after flash erase or program +// operations. The return code indicates to the caller whether or not +// an access violation error has occurred since the last call to the function +// defined by BL_FLASH_CL_ERR_FN_HOOK. +// +// unsigned long MyFlashErrorFunc(void); +// +// where the return code is 0 if no error has occurred or non-zero if an +// error was detected. +// +//***************************************************************************** +//#define BL_FLASH_ERROR_FN_HOOK MyFlashErrorFunc + +//***************************************************************************** +// +// Reports the total size of the device flash. +// +// If hooked, this function will be called to determine the size of the flash +// device. +// +// unsigned long MyFlashSizeFunc(void); +// +// where the return code is the total number of bytes of flash supported by the +// device. Note that this does not take into account any reserved space +// defined via the FLASH_RSVD_SPACE value in this header file. +// +//***************************************************************************** +//#define BL_FLASH_SIZE_FN_HOOK MyFlashSizeFunc + +//***************************************************************************** +// +// Reports the address of the first byte after the end of the device flash. +// +// If hooked, this function will be called to determine the address of the end +// of valid flash. +// +// unsigned long MyFlashEndFunc(void); +// +// where the return code is the address of the first byte after the end of flash. +// Note that this does not take into account any reserved space defined via +// the FLASH_RSVD_SPACE value in this header file. +// +//***************************************************************************** +//#define BL_FLASH_END_FN_HOOK MyFlashEndFunc + +//***************************************************************************** +// +// Checks whether the start address and size of an image are valid. +// +// If hooked, this function will be called whenever a new download is to be +// started. It determines whether or not an image of a particular size may be +// flashed at a given address. Valid addresses are: +// +// 1. APP_START_ADDRESS in all cases. +// 2. 0x00000000 if ENABLE_BL_UPDATE is defined. +// 3. The start of the reserved space if FLASH_RSVD_SPACE is defined. +// +// unsigned long MyFlashAddrCheckFunc(unsigned long ulAddr, +// unsigned long ulSize); +// +// where: +// +// - ulAddr is the address in flash at which the image is to be programmed. +// - ulSize is the total size of the image if known or 0 otherwise. +// +// The return code will be 0 if the address or size is invalid or a non-zero +// value if valid. +// +//***************************************************************************** +//#define BL_FLASH_AD_CHECK_FN_HOOK MyFlashAddrCheckFunc + +#endif // __BL_CONFIG_H__ diff --git a/boot_loader/bl_crc32.c b/boot_loader/bl_crc32.c new file mode 100644 index 0000000..9413987 --- /dev/null +++ b/boot_loader/bl_crc32.c @@ -0,0 +1,267 @@ +//***************************************************************************** +// +// bl_crc32.c - CRC32 calculation functions used in the boot loader. +// +// Copyright (c) 2013-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_types.h" +#include "inc/hw_flash.h" +#include "inc/hw_sysctl.h" +#include "bl_config.h" +#include "boot_loader/bl_crc32.h" + +//***************************************************************************** +// +// Storage for the CRC32 calculation lookup table. +// +//***************************************************************************** +static uint32_t g_pui32CRC32Table[256]; + +//***************************************************************************** +// +// Initialize the CRC32 calculation table for the polynomial used. We pick +// the commonly used ANSI X 3.66 polymonial. This code was informed by an +// example found at http://www.createwindow.com/programming/crc32/index.htm. +// +//***************************************************************************** +static uint32_t +Reflect(uint32_t ui32Ref, uint8_t ui8Ch) +{ + uint_fast32_t ui32Value; + int_fast16_t i16Loop; + + // + // Clear our accumulator variable. + // + ui32Value = 0; + + // + // Swap bit 0 for bit 7, bit 1 for bit 6, etc. + // + for(i16Loop = 1; i16Loop < (ui8Ch + 1); i16Loop++) + { + if(ui32Ref & 1) + { + ui32Value |= 1 << (ui8Ch - i16Loop); + } + ui32Ref >>= 1; + } + + // + // Return the reflected value. + // + return(ui32Value); +} + +//***************************************************************************** +// +// Initialize the lookup table used in calculating the CRC32 value. +// +//***************************************************************************** +void +InitCRC32Table(void) +{ + uint_fast32_t ui32Polynomial; + int_fast16_t i16Loop, i16Bit; + + // + // This is the ANSI X 3.66 polynomial as required by the DFU + // specification. + // + ui32Polynomial = 0x04c11db7; + + for(i16Loop = 0; i16Loop <= 0xFF; i16Loop++) + { + g_pui32CRC32Table[i16Loop]=Reflect(i16Loop, 8) << 24; + for (i16Bit = 0; i16Bit < 8; i16Bit++) + { + g_pui32CRC32Table[i16Loop] = ((g_pui32CRC32Table[i16Loop] << 1) ^ + (g_pui32CRC32Table[i16Loop] & + ((uint32_t)1 << 31) ? + ui32Polynomial : 0)); + } + g_pui32CRC32Table[i16Loop] = Reflect(g_pui32CRC32Table[i16Loop], 32); + } +} + +//***************************************************************************** +// +// Calculate the CRC for the supplied block of data. +// +//***************************************************************************** +uint32_t +CalculateCRC32(uint8_t *pui8Data, uint32_t ui32Length, uint32_t ui32CRC) +{ + uint32_t ui32Count; + uint8_t *pui8Buffer; + uint8_t ui8Char; + + // + // Get a pointer to the start of the data and the number of bytes to + // process. + // + pui8Buffer = pui8Data; + ui32Count = ui32Length; + + // + // Perform the algorithm on each byte in the supplied buffer using the + // lookup table values calculated in InitCRC32Table(). + // + while(ui32Count--) + { + ui8Char = *pui8Buffer++; + ui32CRC = (ui32CRC >> 8) ^ g_pui32CRC32Table[(ui32CRC & 0xFF) ^ + ui8Char]; + } + + // + // Return the result. + // + return(ui32CRC); +} + +//***************************************************************************** +// +//! Checks that the embedded CRC in the image matches the expected value. +//! +//! \param pui32Image points to the start of the firmware image in memory. +//! +//! This function finds the firmware image information header and verifies that +//! the embedded CRC32 matches one calculated over the image. +//! +//! \return Returns \b CHECK_CRC_OK if the CRC calculated matches the value +//! embedded in the image, \b CHECK_CRC_NO_HEADER if no image information +//! header was found at the top of the vector table, \b CHECK_CRC_BAD_CRC if +//! an embedded CRC was found but did not match the calculated value or \b +//! CHECK_CRC_ZERO_LENGTH if the length field of the image information header +//! contains 0 (likely indicating that the image had not been run through the +//! binpack tool which inserts the length and CRC values into the header). +// +//***************************************************************************** +uint32_t +CheckImageCRC32(uint32_t *pui32Image) +{ + uint32_t ui32Loop, ui32FlashSize, ui32CRC; + + // + // Determine the size of flash (giving an upper bound for the image + // size). + // + if(CLASS_IS_TM4C129) + { + // + // Get the flash size from the FLASH_PP register. + // + ui32FlashSize = ((2048 * ((HWREG(FLASH_PP) & FLASH_PP_SIZE_M) + 1)) - + APP_START_ADDRESS); + } + else + { + // + // Compute the size of the flash. + // + ui32FlashSize = (((HWREG(SYSCTL_DC0) & SYSCTL_DC0_FLASHSZ_M) << 11) + + 0x800 - APP_START_ADDRESS); + } + + // + // Scan for the image information header marker bytes. Given that the + // largest possible vector table includes 16 system exceptions and 240 + // IC-specific vectors, we only need to search 257 words into memory before + // giving up. + // + for(ui32Loop = 0; ui32Loop < 257; ui32Loop++) + { + // + // Have we found the header marker words? + // + if((pui32Image[ui32Loop] == 0xFF01FF02) && + (pui32Image[ui32Loop + 1] == 0xFF03FF04)) + { + // + // Yes. Check to see if the length field is 0xFFFFFFFF. This + // likely indicates that the image has not been processed by the + // binpack tool which adds the length and CRC information to the + // image header. + // + if(pui32Image[ui32Loop + 2] == 0xFFFFFFFF) + { + // + // The header reports an image size of 0 so we can't go on and + // check the CRC. + // + return(CHECK_CRC_NO_LENGTH); + } + + // + // Extract the image length and ensure that it is sensible + // given the flash size. We assume the length is invalid if it + // is larger than the available flash size or smaller than the + // space taken up by the vector table and header we've already + // scanned through. + // + if((pui32Image[ui32Loop + 2] > ui32FlashSize) || + (pui32Image[ui32Loop + 2] < + ((ui32Loop + 4) * sizeof(uint32_t)))) + { + // + // The header reports an image size that is larger than the + // available flash so this is obviously incorrect. Fail the + // check. + // + return(CHECK_CRC_BAD_LENGTH); + } + + // + // Calculate the CRC32 value for the image. Note that we skip the + // 4 bytes that hold the check CRC. + // + ui32CRC = CalculateCRC32((uint8_t *)pui32Image, + (ui32Loop + 3) * sizeof(uint32_t), + 0xffffffff); + ui32CRC = CalculateCRC32((uint8_t *)&pui32Image[ui32Loop + 4], + (pui32Image[ui32Loop + 2] - + ((ui32Loop + 4) * sizeof(uint32_t))), + ui32CRC); + ui32CRC ^= 0xffffffff; + + // + // Determine whether the calculated CRC matches the value stored + // in the image information header. + // + if(ui32CRC == pui32Image[ui32Loop + 3]) + { + return(CHECK_CRC_OK); + } + else + { + return(CHECK_CRC_BAD_CRC); + } + } + } + + // + // If we drop out the loop, there was no image information header so + // fail the call. + // + return(CHECK_CRC_NO_HEADER); +} diff --git a/boot_loader/bl_crc32.h b/boot_loader/bl_crc32.h new file mode 100644 index 0000000..ab8848d --- /dev/null +++ b/boot_loader/bl_crc32.h @@ -0,0 +1,49 @@ +//***************************************************************************** +// +// bl_crc32.h - Public header for the boot loader CRC32 functions. +// +// Copyright (c) 2013-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. +// +//***************************************************************************** + +#ifndef __BL_CRC32_H__ +#define __BL_CRC32_H__ + +//***************************************************************************** +// +// Return codes generated by CheckImageCRC32(). +// +//***************************************************************************** +#define CHECK_CRC_OK 0 +#define CHECK_CRC_NO_HEADER 1 +#define CHECK_CRC_NO_LENGTH 2 +#define CHECK_CRC_BAD_LENGTH 3 +#define CHECK_CRC_BAD_CRC 4 + +//***************************************************************************** +// +// Exported function prototypes. +// +//***************************************************************************** +extern void InitCRC32Table(void); +extern uint32_t CheckImageCRC32(uint32_t *pui32Image); +extern uint32_t CalculateCRC32(uint8_t *pui8Data, uint32_t ui32Length, + uint32_t ui32CRC); + +#endif diff --git a/boot_loader/bl_crystal.h b/boot_loader/bl_crystal.h new file mode 100644 index 0000000..268d102 --- /dev/null +++ b/boot_loader/bl_crystal.h @@ -0,0 +1,79 @@ +//***************************************************************************** +// +// bl_crystal.h - Macros to convert a CRYSTAL_FREQ value into the appropriate +// RCC XTAL field define. +// +// Copyright (c) 2010-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. +// +//***************************************************************************** + +#ifndef __BL_CRYSTAL_H__ +#define __BL_CRYSTAL_H__ + +//***************************************************************************** +// +// Convert the CRYSTAL_FREQ value into the corresponding SYSCTL_RCC_XTAL_??? +// value. +// +//***************************************************************************** +#if CRYSTAL_FREQ == 3579545 +#define XTAL_VALUE SYSCTL_RCC_XTAL_3_57MHZ +#elif CRYSTAL_FREQ == 3686400 +#define XTAL_VALUE SYSCTL_RCC_XTAL_3_68MHZ +#elif CRYSTAL_FREQ == 4000000 +#define XTAL_VALUE SYSCTL_RCC_XTAL_4MHZ +#elif CRYSTAL_FREQ == 4096000 +#define XTAL_VALUE SYSCTL_RCC_XTAL_4_09MHZ +#elif CRYSTAL_FREQ == 4915200 +#define XTAL_VALUE SYSCTL_RCC_XTAL_4_91MHZ +#elif CRYSTAL_FREQ == 5000000 +#define XTAL_VALUE SYSCTL_RCC_XTAL_5MHZ +#elif CRYSTAL_FREQ == 5120000 +#define XTAL_VALUE SYSCTL_RCC_XTAL_5_12MHZ +#elif CRYSTAL_FREQ == 6000000 +#define XTAL_VALUE SYSCTL_RCC_XTAL_6MHZ +#elif CRYSTAL_FREQ == 6144000 +#define XTAL_VALUE SYSCTL_RCC_XTAL_6_14MHZ +#elif CRYSTAL_FREQ == 7372800 +#define XTAL_VALUE SYSCTL_RCC_XTAL_7_37MHZ +#elif CRYSTAL_FREQ == 8000000 +#define XTAL_VALUE SYSCTL_RCC_XTAL_8MHZ +#elif CRYSTAL_FREQ == 8192000 +#define XTAL_VALUE SYSCTL_RCC_XTAL_8_19MHZ +#elif CRYSTAL_FREQ == 10000000 +#define XTAL_VALUE SYSCTL_RCC_XTAL_10MHZ +#elif CRYSTAL_FREQ == 12000000 +#define XTAL_VALUE SYSCTL_RCC_XTAL_12MHZ +#elif CRYSTAL_FREQ == 12288000 +#define XTAL_VALUE SYSCTL_RCC_XTAL_12_2MHZ +#elif CRYSTAL_FREQ == 13560000 +#define XTAL_VALUE SYSCTL_RCC_XTAL_13_5MHZ +#elif CRYSTAL_FREQ == 14318180 +#define XTAL_VALUE SYSCTL_RCC_XTAL_14_3MHZ +#elif CRYSTAL_FREQ == 16000000 +#define XTAL_VALUE SYSCTL_RCC_XTAL_16MHZ +#elif CRYSTAL_FREQ == 16384000 +#define XTAL_VALUE SYSCTL_RCC_XTAL_16_3MHZ +#elif CRYSTAL_FREQ == 25000000 +#define XTAL_VALUE SYSCTL_RCC_XTAL_25MHZ +#else +#error ERROR: Unknown CRYSTAL_FREQ value specified! +#endif + +#endif // __BL_CRYSTAL_H__ diff --git a/boot_loader/bl_decrypt.c b/boot_loader/bl_decrypt.c new file mode 100644 index 0000000..6db64da --- /dev/null +++ b/boot_loader/bl_decrypt.c @@ -0,0 +1,64 @@ +//***************************************************************************** +// +// bl_decrypt.c - Code for performing an in-place decryption of the firmware +// image as it is downloaded. +// +// Copyright (c) 2007-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 "bl_config.h" +#include "boot_loader/bl_decrypt.h" + +//***************************************************************************** +// +//! \addtogroup bl_decrypt_api +//! @{ +// +//***************************************************************************** +#if defined(ENABLE_DECRYPTION) || defined(DOXYGEN) + +//***************************************************************************** +// +//! Performs an in-place decryption of downloaded data. +//! +//! \param pui8Buffer is the buffer that holds the data to decrypt. +//! \param ui32Size is the size, in bytes, of the buffer that was passed in via +//! the \e pui8Buffer parameter. +//! +//! This function is a stub that could provide in-place decryption of the data +//! that is being downloaded to the device. +//! +//! \return None. +// +//***************************************************************************** +void +DecryptData(uint8_t *pui8Buffer, uint32_t ui32Size) +{ +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** +#endif + diff --git a/boot_loader/bl_decrypt.h b/boot_loader/bl_decrypt.h new file mode 100644 index 0000000..c8eed0c --- /dev/null +++ b/boot_loader/bl_decrypt.h @@ -0,0 +1,35 @@ +//***************************************************************************** +// +// bl_decrypt.h - Definitions for the decryption function. +// +// Copyright (c) 2007-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. +// +//***************************************************************************** + +#ifndef __BL_DECRYPT_H__ +#define __BL_DECRYPT_H__ + +//***************************************************************************** +// +// Prototype for the decryption function. +// +//***************************************************************************** +extern void DecryptData(uint8_t *pui8Buffer, uint32_t ui32Size); + +#endif // __BL_DECRYPT_H__ diff --git a/boot_loader/bl_emac.c b/boot_loader/bl_emac.c new file mode 100644 index 0000000..c098da0 --- /dev/null +++ b/boot_loader/bl_emac.c @@ -0,0 +1,1914 @@ +//***************************************************************************** +// +// bl_emac.c - Functions to update via Ethernet. +// +// Copyright (c) 2013-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 +#include "bl_config.h" +#include "inc/hw_emac.h" +#include "inc/hw_flash.h" +#include "inc/hw_gpio.h" +#include "inc/hw_memmap.h" +#include "inc/hw_nvic.h" +#include "inc/hw_sysctl.h" +#include "inc/hw_types.h" +#include "driverlib/gpio.h" +#include "driverlib/pin_map.h" +#include "driverlib/emac.h" +#include "driverlib/sysctl.h" +#include "boot_loader/bl_decrypt.h" +#include "boot_loader/bl_flash.h" +#include "boot_loader/bl_hooks.h" +#include "driverlib/rom.h" +// +// Define ROM_SysCtlClockFreqSet() for snowflake RA0. Even though this function +// is deprecated in RA0 ROM, the function operates correctly when +// SYSCTL_MOSCCTL register is configured correctly prior to calling this +// function. +// +#if defined(TARGET_IS_TM4C129_RA0) +#define ROM_SysCtlClockFreqSet \ + ((uint32_t (*)(uint32_t ui32Config, \ + uint32_t ui32SysClock))ROM_SYSCTLTABLE[48]) +#endif + +// +// Define MAP_GPIOPadConfigSet() for the Boot Loader for Snowflake. +// This function fails in Snowflake for higher drive strengths, it will work +// properly for the instances where it is used here in the boot loader. +// +#if defined(TARGET_IS_TM4C129_RA0) || \ + defined(TARGET_IS_TM4C129_RA1) +#define ROM_GPIOPadConfigSet \ + ((void (*)(uint32_t ui32Port, \ + uint8_t ui8Pins, \ + uint32_t ui32Strength, \ + uint32_t ui32PadType))ROM_GPIOTABLE[5]) +#endif + +#include "driverlib/rom_map.h" + +//***************************************************************************** +// +//! \addtogroup bl_emac_api +//! @{ +// +//***************************************************************************** + +#if defined(ENET_ENABLE_UPDATE) || defined(DOXYGEN) +//***************************************************************************** +// +// Make sure that the crystal frequency is defined. +// +//***************************************************************************** +#if !defined(CRYSTAL_FREQ) +#error ERROR: CRYSTAL_FREQ must be defined for Ethernet update! +#endif + +//***************************************************************************** +// +// Make sure that boot loader update is not enabled (it is not supported via +// BOOTP given that there is no way to distinguish between a normal firmware +// image and a boot loader update image). +// +//***************************************************************************** +#if defined(ENABLE_BL_UPDATE) +#error ERROR: Updating the boot loader is not supported over Ethernet! +#endif + +//***************************************************************************** +// +// TFTP packets contain 512 bytes of data and a packet shorter than this +// indicates the end of the transfer. +// +//***************************************************************************** +#define TFTP_BLOCK_SIZE 512 + +//***************************************************************************** +// +// uIP uses memset, so a simple one is provided here. This is not as efficient +// as the one in the C library (from an execution time perspective), but it is +// much smaller. +// +//***************************************************************************** +void * +my_memset(void *pvDest, int iChar, size_t i32Length) +{ + int8_t *pi8Buf = (int8_t *)pvDest; + + // + // Fill the buffer with the given character. + // + while(i32Length--) + { + *pi8Buf++ = iChar; + } + + // + // Return a pointer to the beginning of the buffer. + // + return(pvDest); +} + +//***************************************************************************** +// +// uIP uses memcpy, so a simple one is provided here. This is not as efficient +// as the one in the C library (from an execution time perspective), but it is +// much smaller. +// +//***************************************************************************** +void * +my_memcpy(void *pvDest, const void *pvSrc, size_t i32Length) +{ + const int8_t *pi8Src = (const int8_t *)pvSrc; + int8_t *pi8Dest = (int8_t *)pvDest; + + // + // Copy bytes from the source buffer to the destination buffer. + // + while(i32Length--) + { + *pi8Dest++ = *pi8Src++; + } + + // + // Return a pointer to the beginning of the destination buffer. + // + return(pvDest); +} + +//***************************************************************************** +// +// Directly include the uIP code if using Ethernet for the update. This allows +// non-Ethernet boot loader builds to not have to supply the uip-conf.h file +// that would otherwise be required. +// +//***************************************************************************** +#define memcpy my_memcpy +#define memset my_memset +#undef htonl +#undef ntohl +#undef htons +#undef ntohs +#include "third_party/uip-1.0/uip/pt.h" +#include "third_party/uip-1.0/uip/uip_arp.c" +#undef BUF +#include "third_party/uip-1.0/uip/uip.c" + +//***************************************************************************** +// +// A prototype for the function (in the startup code) for a predictable length +// delay. +// +//***************************************************************************** +extern void Delay(uint32_t ui32Count); + +//***************************************************************************** +// +// Defines for setting up the system clock. +// +//***************************************************************************** +#define SYSTICKHZ 100 +#define SYSTICKMS (1000 / SYSTICKHZ) + +//***************************************************************************** +// +// UIP Timers (in ms) +// +//***************************************************************************** +#define UIP_PERIODIC_TIMER_MS 50 +#define UIP_ARP_TIMER_MS 10000 + +//***************************************************************************** +// +// This structure defines the fields in a BOOTP request/reply packet. +// +//***************************************************************************** +typedef struct +{ + // + // The operation; 1 is a request, 2 is a reply. + // + uint8_t ui8Op; + + // + // The hardware type; 1 is Ethernet. + // + uint8_t ui8HType; + + // + // The hardware address length; for Ethernet this will be 6, the length of + // the MAC address. + // + uint8_t ui8HLen; + + // + // Hop count, used by gateways for cross-gateway booting. + // + uint8_t ui8Hops; + + // + // The transaction ID. + // + uint32_t ui32XID; + + // + // The number of seconds elapsed since the client started trying to boot. + // + uint16_t ui16Secs; + + // + // The BOOTP flags. + // + uint16_t ui16Flags; + + // + // The client's IP address, if it knows it. + // + uint32_t ui32CIAddr; + + // + // The client's IP address, as assigned by the BOOTP server. + // + uint32_t ui32YIAddr; + + // + // The TFTP server's IP address. + // + uint32_t ui32SIAddr; + + // + // The gateway IP address, if booting cross-gateway. + // + uint32_t ui32GIAddr; + + // + // The hardware address; for Ethernet this is the MAC address. + // + uint8_t pui8CHAddr[16]; + + // + // The name, or nickname, of the server that should handle this BOOTP + // request. + // + char pcSName[64]; + + // + // The name of the boot file to be loaded via TFTP. + // + char pcFile[128]; + + // + // Optional vendor-specific area; not used for BOOTP. + // + uint8_t pui8Vend[64]; +} +tBOOTPPacket; + +//***************************************************************************** +// +// The BOOTP commands. +// +//***************************************************************************** +#define BOOTP_REQUEST 1 +#define BOOTP_REPLY 2 + +//***************************************************************************** +// +// The TFTP commands. +// +//***************************************************************************** +#define TFTP_RRQ 1 +#define TFTP_WRQ 2 +#define TFTP_DATA 3 +#define TFTP_ACK 4 +#define TFTP_ERROR 5 + +//***************************************************************************** +// +// The UDP ports used by the BOOTP protocol. +// +//***************************************************************************** +#define BOOTP_SERVER_PORT 67 +#define BOOTP_CLIENT_PORT 68 + +//***************************************************************************** +// +// The UDP port for the TFTP server. +// +//***************************************************************************** +#define TFTP_PORT 69 + +//***************************************************************************** +// +// The MAC address of the Ethernet interface. +// +//***************************************************************************** +#ifdef ENET_MAC_ADDR0 +static struct uip_eth_addr g_sMACAddr = +{ + { + ENET_MAC_ADDR0, + ENET_MAC_ADDR1, + ENET_MAC_ADDR2, + ENET_MAC_ADDR3, + ENET_MAC_ADDR4, + ENET_MAC_ADDR5 + } +}; +#else +static struct uip_eth_addr g_sMACAddr; +#endif + +//***************************************************************************** +// +// The number of SysTick interrupts since the start of the boot loader. +// +//***************************************************************************** +static uint32_t g_ui32Ticks; + +//***************************************************************************** +// +// The seed for the random number generator. +// +//***************************************************************************** +static uint32_t g_ui32RandomSeed; + +//***************************************************************************** +// +// The number of milliseconds since the last call to uip_udp_periodic(). +// +//***************************************************************************** +static volatile uint32_t g_ui32PeriodicTimer; + +//***************************************************************************** +// +// The number of milliseconds since the last call to uip_arp_timer(). +// +//***************************************************************************** +static volatile uint32_t g_ui32ARPTimer; + +//***************************************************************************** +// +// The transaction ID of the most recently sent out BOOTP request. +// +//***************************************************************************** +static uint32_t g_ui32XID; + +//***************************************************************************** +// +// The state for the proto-thread that handles the BOOTP process. +// +//***************************************************************************** +static struct pt g_sThread; + +//***************************************************************************** +// +// The amount of time to wait for a BOOTP reply before sending out a new BOOTP +// request. +// +//***************************************************************************** +static uint32_t g_ui32Delay; + +//***************************************************************************** +// +// The target time (relative to g_ui32Ticks) when the next timeout occurs. +// +//***************************************************************************** +static uint32_t g_ui32Target; + +//***************************************************************************** +// +// The IP address of the TFTP server. +// +//***************************************************************************** +static uip_ipaddr_t g_sServerAddr; + +//***************************************************************************** +// +// The name of the file to be read from the TFTP server. +// +//***************************************************************************** +static char g_pcFilename[128]; + +//***************************************************************************** +// +// The end of flash. If there is not a reserved block at the end of flash, +// this is the real end of flash. If there is a reserved block, this is the +// start of the reserved block (i.e. the virtual end of flash). +// +//***************************************************************************** +static uint32_t g_ui32FlashEnd; + +//***************************************************************************** +// +// The current block being read from the TFTP server. +// +//***************************************************************************** +static uint32_t g_ui32TFTPBlock; + +//***************************************************************************** +// +// The number of TFTP retries. +// +//***************************************************************************** +static uint32_t g_ui32TFTPRetries; + +//***************************************************************************** +// +// The UDP socket used to communicate with the BOOTP and TFTP servers (in +// sequence). +// +//***************************************************************************** +struct uip_udp_conn *g_pConn; + +//***************************************************************************** +// +// The current link status. +// +//***************************************************************************** +static uint32_t g_ui32Link; + +//***************************************************************************** +// +// Ethernet DMA descriptors. +// +// Although uIP uses a single buffer, the MAC hardware needs a minimum of +// 3 receive descriptors to operate. +// +//***************************************************************************** +#define NUM_TX_DESCRIPTORS 3 +#define NUM_RX_DESCRIPTORS 3 +tEMACDMADescriptor g_psRxDescriptor[NUM_TX_DESCRIPTORS]; +tEMACDMADescriptor g_psTxDescriptor[NUM_RX_DESCRIPTORS]; +uint32_t g_ui32RxDescIndex; +uint32_t g_ui32TxDescIndex; + +//***************************************************************************** +// +// Transmit and receive buffers. +// +//***************************************************************************** +#define RX_BUFFER_SIZE 1536 +#define TX_BUFFER_SIZE 1536 +uint8_t g_pui8RxBuffer[RX_BUFFER_SIZE]; +uint8_t g_pui8TxBuffer[TX_BUFFER_SIZE]; + +//***************************************************************************** +// +//! Handles the SysTick interrupt. +//! +//! This function is called when the SysTick interrupt occurs. It simply +//! keeps a running count of interrupts, used as a time basis for the BOOTP and +//! TFTP protocols. +//! +//! \return None. +// +//***************************************************************************** +void +SysTickIntHandler(void) +{ + // + // Increment the tick count. + // + g_ui32Ticks++; + g_ui32PeriodicTimer += SYSTICKMS; + g_ui32ARPTimer += SYSTICKMS; +} + +//***************************************************************************** +// +//! Computes a new random number. +//! +//! This function computes a new pseudo-random number, using a linear +//! congruence random number generator. Note that if the entire 32-bits of the +//! produced random number are not being used, the upper N bits should be used +//! instead of the lower N bits as they are much more random (for example, use +//! ``RandomNumber() >> 28'' instead of ``RandomNumber() & 15''). +//! +//! \return Returns a 32-bit pseudo-random number. +// +//***************************************************************************** +static uint32_t +RandomNumber(void) +{ + // + // Generate a new pseudo-random number with a linear congruence random + // number generator. This new random number becomes the seed for the next + // random number. + // + g_ui32RandomSeed = (g_ui32RandomSeed * 1664525) + 1013904223; + + // + // Return the new random number. + // + return(g_ui32RandomSeed); +} + +//***************************************************************************** +// +// Read a packet from the DMA receive buffer into the uIP packet buffer. +// +//***************************************************************************** +static int32_t +PacketReceive(uint8_t *pui8Buf, int32_t i32BufLen) +{ + int_fast32_t i32FrameLen, i32Loop; + + // + // By default, we assume we got a bad frame. + // + i32FrameLen = 0; + + // + // See if the receive descriptor contains a valid frame. Look for a + // descriptor error, indicating that the incoming packet was truncated or, + // if this is the last frame in a packet, the receive error bit. + // + if(!(g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus & + DES0_RX_STAT_ERR)) + { + // + // We have a valid frame so copy the content to the supplied buffer. + // First check that the "last descriptor" flag is set. We sized the + // receive buffer such that it can always hold a valid frame so this + // flag should never be clear at this point but... + // + if(g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus & + DES0_RX_STAT_LAST_DESC) + { + i32FrameLen = + ((g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus & + DES0_RX_STAT_FRAME_LENGTH_M) >> + DES0_RX_STAT_FRAME_LENGTH_S); + + // + // Sanity check. This shouldn't be required since we sized the uIP + // buffer such that it's the same size as the DMA receive buffer + // but, just in case... + // + if(i32FrameLen > i32BufLen) + { + i32FrameLen = i32BufLen; + } + + // + // Copy the data from the DMA receive buffer into the provided + // frame buffer. + // + for(i32Loop = 0; i32Loop < i32FrameLen; i32Loop++) + { + pui8Buf[i32Loop] = g_pui8RxBuffer[i32Loop]; + } + } + } + + // + // Move on to the next descriptor in the chain. + // + g_ui32RxDescIndex++; + if(g_ui32RxDescIndex == NUM_RX_DESCRIPTORS) + { + g_ui32RxDescIndex = 0; + } + + // + // Mark the next descriptor in the ring as available for the receiver to + // write into. + // + g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus = DES0_RX_CTRL_OWN; + + // + // Return the Frame Length + // + return(i32FrameLen); +} + +//***************************************************************************** +// +// Transmit a packet from the supplied buffer. +// +//***************************************************************************** +static int32_t +PacketTransmit(uint8_t *pui8Buf, int32_t i32BufLen) +{ + int_fast32_t i32Loop; + + // + // Wait for the previous packet to be transmitted. + // + while(g_psTxDescriptor[g_ui32TxDescIndex].ui32CtrlStatus & + DES0_TX_CTRL_OWN) + { + } + + // + // Check that we're not going to overflow the transmit buffer. This + // shouldn't be necessary since the uIP buffer is smaller than our DMA + // transmit buffer but, just in case... + // + if(i32BufLen > TX_BUFFER_SIZE) + { + i32BufLen = TX_BUFFER_SIZE; + } + + // + // Copy the packet data into the transmit buffer. + // + for(i32Loop = 0; i32Loop < i32BufLen; i32Loop++) + { + g_pui8TxBuffer[i32Loop] = pui8Buf[i32Loop]; + } + + // + // Move to the next descriptor. + // + g_ui32TxDescIndex++; + if(g_ui32TxDescIndex == NUM_TX_DESCRIPTORS) + { + g_ui32TxDescIndex = 0; + } + + // + // Fill in the packet size and tell the transmitter to start work. + // + g_psTxDescriptor[g_ui32TxDescIndex].ui32Count = (uint32_t)i32BufLen; + g_psTxDescriptor[g_ui32TxDescIndex].ui32CtrlStatus = + (DES0_TX_CTRL_LAST_SEG | DES0_TX_CTRL_FIRST_SEG | + DES0_TX_CTRL_INTERRUPT | DES0_TX_CTRL_IP_ALL_CKHSUMS | + DES0_TX_CTRL_CHAINED | DES0_TX_CTRL_OWN); + + // + // Tell the DMA to reacquire the descriptor now that we've filled it in. + // + ROM_EMACTxDMAPollDemand(EMAC0_BASE); + + // + // Return the number of bytes sent. + // + return(i32BufLen); +} + +//***************************************************************************** +// +//! Constructs and sends a BOOTP request packet. +//! +//! This function constructs a BOOTP request packet and sends it as a broadcast +//! message to the network. +//! +//! \return None. +// +//***************************************************************************** +static void +SendBOOTPRequest(void) +{ + uint8_t *pui8Packet = (uint8_t *)uip_appdata; + tBOOTPPacket *psBOOTP = (tBOOTPPacket *)uip_appdata; + uint32_t ui32Idx; + + // + // Zero fill the BOOTP request packet. + // + for(ui32Idx = 0; ui32Idx < sizeof(tBOOTPPacket); ui32Idx++) + { + pui8Packet[ui32Idx] = 0; + } + + // + // Construct a BOOTP request. + // + psBOOTP->ui8Op = BOOTP_REQUEST; + + // + // Set the hardware type to Ethernet. + // + psBOOTP->ui8HType = 0x01; + + // + // Set the hardware address length to 6. + // + psBOOTP->ui8HLen = 0x06; + + // + // Choose a random number for the transaction ID. + // + psBOOTP->ui32XID = g_ui32XID = RandomNumber(); + + // + // Set the number of seconds since we started. + // + psBOOTP->ui16Secs = HTONS(g_ui32Ticks / SYSTICKHZ); + + // + // Fill in the Ethernet MAC address. + // + for(ui32Idx = 0; ui32Idx < 6; ui32Idx++) + { + psBOOTP->pui8CHAddr[ui32Idx] = g_sMACAddr.addr[ui32Idx]; + } + + // + // Set the server name if defined. + // +#ifdef ENET_BOOTP_SERVER + for(ui32Idx = 0; + (psBOOTP->pcSName[ui32Idx] = ENET_BOOTP_SERVER[ui32Idx]) != 0; + ui32Idx++) + { + } +#endif + + // + // Send the BOOTP request packet. + // + uip_udp_send(sizeof(tBOOTPPacket)); +} + +//***************************************************************************** +// +//! Parses a packet checking for a BOOTP reply message. +//! +//! This function parses a packet to determine if it is a BOOTP reply to our +//! currently outstanding BOOTP request. If a valid reply is found, the +//! appropriate information from the packet is extracted and saved. +//! +//! \return Returns 1 if a valid BOOTP reply message was found and 0 otherwise. +// +//***************************************************************************** +static uint32_t +ParseBOOTPReply(void) +{ + tBOOTPPacket *psBOOTP = (tBOOTPPacket *)uip_appdata; + uint32_t ui32Idx; + + // + // See if this is a reply for our current BOOTP request. + // + if((psBOOTP->ui8Op != BOOTP_REPLY) || + (psBOOTP->ui32XID != g_ui32XID) || + (*(uint32_t *)psBOOTP->pui8CHAddr != *(uint32_t *)g_sMACAddr.addr) || + (*(uint16_t *)(psBOOTP->pui8CHAddr + 4) != + *(uint16_t *)(g_sMACAddr.addr + 4))) + { + return(0); + } + + // + // Extract our IP address from the response. + // + *((uint32_t *)(void *)(&uip_hostaddr)) = psBOOTP->ui32YIAddr; + + // + // Extract the server address from the response. + // + *((uint32_t *)(void *)(&g_sServerAddr)) = psBOOTP->ui32SIAddr; + + // + // Save the boot file name. + // + for(ui32Idx = 0; + ((g_pcFilename[ui32Idx] = psBOOTP->pcFile[ui32Idx]) != 0) && + (ui32Idx < (sizeof(g_pcFilename) - 1)); + ui32Idx++) + { + } + g_pcFilename[ui32Idx] = 0; + + // + // A valid BOOTP reply was found and decoded. + // + return(1); +} + + +//***************************************************************************** +// +//! Constructs and sends a TFTP error packet. +//! +//! This function constructs a TFTP read request packet (RRQ) and sends it to +//! the server. +//! +//! \return None. +// +//***************************************************************************** +static void +SendTFTPError(uint16_t ui16Error, char *pcString) +{ + uint8_t *pui8Packet = (uint8_t *)uip_appdata; + int32_t i32Len; + + pui8Packet[0] = (TFTP_ERROR >> 8) & 0xff; + pui8Packet[1] = TFTP_ERROR & 0xff; + pui8Packet[2] = (ui16Error >> 8) & 0xFF; + pui8Packet[3] = ui16Error & 0xFF; + + // + // Get ready to copy the error string. + // + i32Len = 4; + pui8Packet += 4; + + // + // Copy as much of the string as we can fit. + // + while((i32Len < (UIP_APPDATA_SIZE - 1)) && *pcString) + { + *pui8Packet++ = *pcString++; + i32Len++; + } + + // + // Write the terminating 0. + // + *pui8Packet = (uint8_t)0; + + // + // Send the error packet. + // + uip_udp_send(i32Len + 1); +} + +//***************************************************************************** +// +//! Constructs and sends a TFTP read packet. +//! +//! This function constructs a TFTP read request packet (RRQ) and sends it to +//! the server. +//! +//! \return None. +// +//***************************************************************************** +static void +SendTFTPGet(void) +{ + uint8_t *pui8Packet = (uint8_t *)uip_appdata; + uint32_t ui32Idx; + char *pcFilename; + + // + // The TFTP RRQ packet should be sent to the TFTP server port. + // + g_pConn->rport = HTONS(TFTP_PORT); + + // + // Set the TFTP packet opcode to RRQ. + // + pui8Packet[0] = (TFTP_RRQ >> 8) & 0xff; + pui8Packet[1] = TFTP_RRQ & 0xff; + + // + // Copy the file name into the RRQ packet. + // + for(ui32Idx = 2, pcFilename = g_pcFilename; + (pui8Packet[ui32Idx++] = *pcFilename++) != 0; ) + { + } + + // + // Set the transfer mode to binary. + // + for(pcFilename = "octet"; (pui8Packet[ui32Idx++] = *pcFilename++) != 0; ) + { + } + + // + // Send the TFTP read packet. + // + uip_udp_send(ui32Idx); +} + +//***************************************************************************** +// +//! 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); +} + +uint16_t +LOCAL_EMACPHYRead(uint32_t ui32Base, uint8_t ui8PhyAddr, uint8_t ui8RegAddr) +{ + + // + // Make sure the MII is idle. + // + while(HWREG(ui32Base + EMAC_O_MIIADDR) & EMAC_MIIADDR_MIIB) + { + } + + // + // Tell the MAC to read the given PHY register. + // + HWREG(ui32Base + EMAC_O_MIIADDR) = + ((HWREG(ui32Base + EMAC_O_MIIADDR) & EMAC_MIIADDR_CR_M) | + (ui8RegAddr << EMAC_MIIADDR_MII_S) | + (ui8PhyAddr << EMAC_MIIADDR_PLA_S) | EMAC_MIIADDR_MIIB); + + // + // Wait for the read to complete. + // + while(HWREG(ui32Base + EMAC_O_MIIADDR) & EMAC_MIIADDR_MIIB) + { + } + + // + // Return the result. + // + return(HWREG(ui32Base + EMAC_O_MIIDATA) & EMAC_MIIDATA_DATA_M); +} + +//***************************************************************************** +// +//! Handles the BOOTP process. +//! +//! This function contains the proto-thread for handling the BOOTP process. It +//! first communicates with the BOOTP server to get its boot parameters (IP +//! address, server address, and file name), then it communicates with the TFTP +//! server on the specified server to read the firmware image file. +//! +//! \return None. +// +//***************************************************************************** +#ifdef DOXYGEN +char +BOOTPThread(void) +#else +PT_THREAD(BOOTPThread(void)) +#endif +{ + // + // Begin the proto-thread. + // + PT_BEGIN(&g_sThread); + +wait_for_link: + PT_WAIT_UNTIL(&g_sThread, + (LOCAL_EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) & + EPHY_BMSR_LINKSTAT) != 0); + + // + // Reset the host address. + // + *((uint32_t *)(void *)(&uip_hostaddr)) = 0; + + // + // Re-bind the UDP socket for sending requests to the BOOTP server. + // + uip_udp_remove(g_pConn); + *((uint32_t *)(void *)(&g_sServerAddr)) = 0xffffffff; + uip_udp_new(&g_sServerAddr, HTONS(BOOTP_SERVER_PORT)); + uip_udp_bind(g_pConn, HTONS(BOOTP_CLIENT_PORT)); + + // + // Set the initial delay between BOOTP requests to 1 second. + // + g_ui32Delay = SYSTICKHZ; + + // + // Loop forever. This loop is explicitly exited when a valid BOOTP reply + // is received. + // + while(1) + { + // + // Send a BOOTP request. + // + SendBOOTPRequest(); + + // + // Set the amount of time to wait for the BOOTP reply message. + // + g_ui32Target = g_ui32Ticks + g_ui32Delay; + + // + // Wait until a packet is received or the timeout has occurred. + // +wait_for_bootp_reply: + PT_WAIT_UNTIL(&g_sThread, + ((g_ui32Link = (LOCAL_EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) & + EPHY_BMSR_LINKSTAT)) == 0) || + uip_newdata() || (g_ui32Ticks > g_ui32Target)); + + // + // If the link has been lost, go back to waiting for a link. + // + if(g_ui32Link == 0) + { + goto wait_for_link; + } + + // + // See if a packet has been received. + // + if(uip_newdata()) + { + // + // Clear the new data flag so that this packet will only be + // examined one time. + // + uip_flags &= ~(UIP_NEWDATA); + + // + // See if this is a BOOTP reply. + // + if(ParseBOOTPReply() == 1) + { + break; + } + + // + // This was not a BOOTP reply packet, so go back to waiting. + // + goto wait_for_bootp_reply; + } + + // + // If the delay between BOOTP requests is less than 60 seconds, double + // the delay time. This avoids constantly slamming the network with + // requests. + // + if(g_ui32Delay < (60 * SYSTICKHZ)) + { + g_ui32Delay *= 2; + } + } + + // + // Reconfigure the UDP socket to target the TFTP port on the server. + // + uip_ipaddr_copy(&g_pConn->ripaddr, g_sServerAddr); + uip_udp_bind(g_pConn, HTONS(13633)); + + // + // Send a TFTP read request. + // + SendTFTPGet(); + + // + // Since the first TFTP read request will result in an ARP request, delay + // for just a bit and then re-issue the TFTP read request. + // + PT_YIELD(&g_sThread); + + // + // Resend the TFTP read request. If the ARP request has already been + // answered, this will go out as is and avoid the two second timeout below. + // + SendTFTPGet(); + + // + // Start the TFTP transfer from block one. + // + g_ui32TFTPBlock = 1; + + // + // Set the number of TFTP retries to zero. + // + g_ui32TFTPRetries = 0; + + // + // Loop forever. This loop is explicitly exited when the TFTP transfer has + // completed. + // + while(1) + { + // + // Set the amount of time to wait for the TFTP data packet. + // + g_ui32Target = g_ui32Ticks + (SYSTICKHZ * 4); + + // + // Wait until a packet is received or the timeout has occurred. + // + PT_WAIT_UNTIL(&g_sThread, + ((g_ui32Link = (LOCAL_EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) & + EPHY_BMSR_LINKSTAT)) == 0) || + uip_newdata() || (g_ui32Ticks > g_ui32Target)); + + // + // If the link has been lost, go back to waiting for a link. + // + if(g_ui32Link == 0) + { + goto wait_for_link; + } + + // + // See if a packet has been received. + // + if(uip_newdata()) + { + // + // Clear the new data flag so that this packet will only be + // examined one time. + // + uip_flags &= ~(UIP_NEWDATA); + + // + // See if this is a TFTP data packet. + // + if(ParseTFTPData() == 1) + { + break; + } + } + else if(g_ui32TFTPRetries < 3) + { + // + // The transfer timed out, so send a new TFTP read request. + // + SendTFTPGet(); + + // + // Start the TFTP transfer from block one. + // + g_ui32TFTPBlock = 1; + + // + // Increment the count of TFTP retries. + // + g_ui32TFTPRetries++; + } + else + { + // + // The TFTP transfer failed after three retries, so start over. + // + goto wait_for_link; + } + } + // + // Wait for the last packet to be transmitted. + // + while(g_psTxDescriptor[g_ui32TxDescIndex].ui32CtrlStatus & + DES0_TX_CTRL_OWN) + { + } + + // + // Wait for a bit to make sure that the final ACK packet is transmitted. + // + g_ui32Target = g_ui32Ticks + (SYSTICKHZ / 4); + while(g_ui32Ticks < g_ui32Target) + { + PT_YIELD(&g_sThread); + } + + // + // 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) + { + } + + // + // End the proto-thread. + // + PT_END(&g_sThread); +} + +static void +LOCAL_EMACPHYConfigSet(uint32_t ui32Base, uint32_t ui32Config) +{ + // + // Write the Ethernet PHY configuration to the peripheral configuration + // register. + // + HWREG(ui32Base + EMAC_O_PC) = ui32Config; + + // + // If using the internal PHY, reset it to ensure that new configuration is + // latched there. + // + if((ui32Config & EMAC_PHY_TYPE_MASK) == EMAC_PHY_TYPE_INTERNAL) + { + ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0); + while(!ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_EPHY0)) + { + // + // Wait for the PHY reset to complete. + // + } + + // + // Delay a bit longer to ensure that the PHY reset has completed. + // + ROM_SysCtlDelay(1000); + } + + // + // If using an external RMII PHY, we must set 2 bits in the Ethernet MAC + // Clock Configuration Register. + // + if((ui32Config & EMAC_PHY_TYPE_MASK) == EMAC_PHY_TYPE_EXTERNAL_RMII) + { + // + // Select and enable the external clock from the RMII PHY. + // + HWREG(EMAC0_BASE + EMAC_O_CC) |= EMAC_CC_CLKEN; + } + else + { + // + // Disable the external clock. + // + HWREG(EMAC0_BASE + EMAC_O_CC) &= ~EMAC_CC_CLKEN; + } + + // + // Reset the MAC regardless of whether the PHY connection changed or not. + // + ROM_EMACReset(EMAC0_BASE); + + ROM_SysCtlDelay(1000); +} + +//***************************************************************************** +// +//! Reconfigures the Ethernet controller. +//! +//! \param ui32Clock is the system clock frequency. +//! +//! This function reconfigures the Ethernet controller, preparing it for use by +//! the boot loader. This performs the steps common between the direct +//! invocation of the boot loader and the application invocation of the boot +//! loader. +//! +//! \return None. +// +//***************************************************************************** +void +EnetReconfig(uint32_t ui32Clock) +{ + uip_ipaddr_t sAddr; + uint32_t ui32Loop; + uint32_t ui32User0, ui32User1; + + // + // Configure for use with the internal PHY. + // + LOCAL_EMACPHYConfigSet(EMAC0_BASE, + (EMAC_PHY_TYPE_INTERNAL | EMAC_PHY_INT_MDIX_EN | + EMAC_PHY_AN_100B_T_FULL_DUPLEX)); + + + // + // Reset the MAC. + // + ROM_EMACReset(EMAC0_BASE); + + // + // Initialize the MAC and set the DMA mode. + // + ROM_EMACInit(EMAC0_BASE, ui32Clock, + EMAC_BCONFIG_MIXED_BURST | EMAC_BCONFIG_PRIORITY_FIXED, 4, 4, 0); + + // + // Get the MAC address from the flash user registers. If it has not been + // programmed, then use the boot loader default MAC address. + // + ROM_FlashUserGet(&ui32User0, &ui32User1); + if((ui32User0 == 0xffffffff) || (ui32User1 == 0xffffffff)) + { + // + // MAC address has not been programmed, use default. + // + g_sMACAddr.addr[0] = 0x00; + g_sMACAddr.addr[1] = 0x1a; + g_sMACAddr.addr[2] = 0xb6; + g_sMACAddr.addr[3] = 0x00; + g_sMACAddr.addr[4] = 0x64; + g_sMACAddr.addr[5] = 0x00; + } + else + { + g_sMACAddr.addr[0] = ui32User0 & 0xff; + g_sMACAddr.addr[1] = (ui32User0 >> 8) & 0xff; + g_sMACAddr.addr[2] = (ui32User0 >> 16) & 0xff; + g_sMACAddr.addr[3] = ui32User1 & 0xff; + g_sMACAddr.addr[4] = (ui32User1 >> 8) & 0xff; + g_sMACAddr.addr[5] = (ui32User1 >> 16) & 0xff; + } + + // + // Set MAC configuration options. + // + ROM_EMACConfigSet(EMAC0_BASE, + (EMAC_CONFIG_FULL_DUPLEX | EMAC_CONFIG_CHECKSUM_OFFLOAD | + EMAC_CONFIG_7BYTE_PREAMBLE | EMAC_CONFIG_IF_GAP_96BITS | + EMAC_CONFIG_USE_MACADDR0 | EMAC_CONFIG_SA_FROM_DESCRIPTOR | + EMAC_CONFIG_BO_LIMIT_1024), + (EMAC_MODE_RX_STORE_FORWARD | EMAC_MODE_TX_STORE_FORWARD | + EMAC_MODE_TX_THRESHOLD_64_BYTES | + EMAC_MODE_RX_THRESHOLD_64_BYTES), 0); + + // + // Initialize each of the transmit descriptors. Note that we leave the OWN + // bit clear here since we have not set up any transmissions yet. + // + for(ui32Loop = 0; ui32Loop < NUM_TX_DESCRIPTORS; ui32Loop++) + { + g_psTxDescriptor[ui32Loop].ui32Count = + (DES1_TX_CTRL_SADDR_INSERT | + (TX_BUFFER_SIZE << DES1_TX_CTRL_BUFF1_SIZE_S)); + g_psTxDescriptor[ui32Loop].pvBuffer1 = g_pui8TxBuffer; + g_psTxDescriptor[ui32Loop].DES3.pLink = + (ui32Loop == (NUM_TX_DESCRIPTORS - 1)) ? + g_psTxDescriptor : &g_psTxDescriptor[ui32Loop + 1]; + g_psTxDescriptor[ui32Loop].ui32CtrlStatus = + (DES0_TX_CTRL_LAST_SEG | DES0_TX_CTRL_FIRST_SEG | + DES0_TX_CTRL_INTERRUPT | DES0_TX_CTRL_CHAINED | + DES0_TX_CTRL_IP_ALL_CKHSUMS); + } + + // + // Initialize each of the receive descriptors. We clear the OWN bit here + // to make sure that the receiver doesn't start writing anything + // immediately. + // + for(ui32Loop = 0; ui32Loop < NUM_RX_DESCRIPTORS; ui32Loop++) + { + g_psRxDescriptor[ui32Loop].ui32CtrlStatus = 0; + g_psRxDescriptor[ui32Loop].ui32Count = + (DES1_RX_CTRL_CHAINED | + (RX_BUFFER_SIZE << DES1_RX_CTRL_BUFF1_SIZE_S)); + g_psRxDescriptor[ui32Loop].pvBuffer1 = g_pui8RxBuffer; + g_psRxDescriptor[ui32Loop].DES3.pLink = + (ui32Loop == (NUM_RX_DESCRIPTORS - 1)) ? + g_psRxDescriptor : &g_psRxDescriptor[ui32Loop + 1]; + } + + // + // Set the descriptor pointers in the hardware. + // + ROM_EMACRxDMADescriptorListSet(EMAC0_BASE, g_psRxDescriptor); + ROM_EMACTxDMADescriptorListSet(EMAC0_BASE, g_psTxDescriptor); + + // + // Start from the beginning of both descriptor chains. We actually set + // the transmit descriptor index to the last descriptor in the chain + // since it will be incremented before use and this means the first + // transmission we perform will use the correct descriptor. + // + g_ui32RxDescIndex = 0; + g_ui32TxDescIndex = NUM_TX_DESCRIPTORS - 1; + + // + // Program the MAC address. + // + ROM_EMACAddrSet(EMAC0_BASE, 0, g_sMACAddr.addr); + + // + // Wait for the link to become active. + // + while((ROM_EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) & + EPHY_BMSR_LINKSTAT) == 0) + { + } + + // + // Set MAC filtering options. We receive all broadcast and multicast + // packets along with those addressed specifically for us. + // + ROM_EMACFrameFilterSet(EMAC0_BASE, (EMAC_FRMFILTER_SADDR | + EMAC_FRMFILTER_PASS_MULTICAST | + EMAC_FRMFILTER_PASS_NO_CTRL)); + + // + // Seed the random number generator from the MAC address. + // + g_ui32RandomSeed = *(uint32_t *)(g_sMACAddr.addr + 2); + + // + // Initialize the uIP stack. + // + uip_init(); + uip_arp_init(); + + // + // Set the MAC address. + // + uip_setethaddr(g_sMACAddr); + + // + // Initialize the proto-thread used by the BOOTP protocol handler. + // + PT_INIT(&g_sThread); + + // + // Create a UDP socket for sending requests to the BOOTP server. After the + // BOOTP portion of the protocol has been handled, this socket will be + // reused to communicate with the TFTP server. + // + *((uint32_t *)(void *)(&sAddr)) = 0xffffffff; + g_pConn = uip_udp_new(&sAddr, HTONS(BOOTP_SERVER_PORT)); + uip_udp_bind(g_pConn, HTONS(BOOTP_CLIENT_PORT)); + + // + // Enable the Ethernet MAC transmitter and receiver. + // + ROM_EMACTxEnable(EMAC0_BASE); + ROM_EMACRxEnable(EMAC0_BASE); + + // + // Mark the first receive descriptor as available to the DMA to start + // the receive processing. + // + g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus |= DES0_RX_CTRL_OWN; + + // + // Reset the counters that are incremented by SysTick. + // + g_ui32Ticks = 0; + g_ui32PeriodicTimer = 0; + g_ui32ARPTimer = 0; + + // + // Setup SysTick. + // + HWREG(NVIC_ST_RELOAD) = (ui32Clock / SYSTICKHZ) - 1; + HWREG(NVIC_ST_CTRL) = (NVIC_ST_CTRL_CLK_SRC | NVIC_ST_CTRL_INTEN | + NVIC_ST_CTRL_ENABLE); +} +//***************************************************************************** +// +//! Configures the Ethernet controller. +//! +//! This function configures the Ethernet controller, preparing it for use by +//! the boot loader. +//! +//! \return None. +// +//***************************************************************************** +void +ConfigureEnet(void) +{ + // + // Make sure the main oscillator is enabled because this is required by + // the PHY. The system must have a 25MHz crystal attached to the OSC + // pins. The SYSCTL_MOSC_HIGHFREQ parameter is used when the crystal + // frequency is 10MHz or higher. + // + HWREG(SYSCTL_MOSCCTL) = SYSCTL_MOSC_HIGHFREQ; + + // + // Delay while the main oscillator starts up. + // + Delay(5242880); + + MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | + SYSCTL_OSC_MAIN | + SYSCTL_USE_PLL | + SYSCTL_CFG_VCO_480), 120000000); + + +#ifdef ENET_ENABLE_LEDS + // + // PF1/PK4/PK6 are used for Ethernet LEDs. + // + ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); + ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK); + ROM_GPIOPinConfigure(GPIO_PF1_EN0LED2); + ROM_GPIOPinConfigure(GPIO_PK4_EN0LED0); + ROM_GPIOPinConfigure(GPIO_PK6_EN0LED1); + + // + // Make the pin(s) be peripheral controlled. + // + ROM_GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_DIR_MODE_HW); + ROM_GPIODirModeSet(GPIO_PORTK_BASE, GPIO_PIN_4|GPIO_PIN_6, GPIO_DIR_MODE_HW); + + // + // Set the pad(s) for standard push-pull operation. + // + ROM_GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD); + ROM_GPIOPadConfigSet(GPIO_PORTK_BASE, GPIO_PIN_4|GPIO_PIN_6, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD); +#endif + + // + // Enable and reset the Ethernet modules. + // + ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_EMAC0); + ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0); + ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_EMAC0); + ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0); + + while(!ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_EMAC0)) + { + } + +} + +//***************************************************************************** +// +//! Starts the update process via BOOTP. +//! +//! This function starts the Ethernet firmware update process. The BOOTP +//! (as defined by RFC951 at http://tools.ietf.org/html/rfc951) and TFTP (as +//! defined by RFC1350 at http://tools.ietf.org/html/rfc1350) protocols are +//! used to transfer the firmware image over Ethernet. +//! +//! \return Never returns. +// +//***************************************************************************** +void +UpdateBOOTP(void) +{ + // + // Get the size of flash. + // + g_ui32FlashEnd = ROM_SysCtlFlashSizeGet(); +#ifdef FLASH_RSVD_SPACE + g_ui32FlashEnd -= FLASH_RSVD_SPACE; +#endif + + // + // Perform the common Ethernet configuration. The frequency should + // match whatever the application sets the system clock. + // + EnetReconfig(120000000); + + // + // Main Application Loop. + // + while(1) + { + uint32_t ui32Temp; + + // + // See if there is a packet waiting to be read. + // + if(!(g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus & + DES0_RX_CTRL_OWN)) + { + // + // Read the packet from the Ethernet controller. + // + uip_len = PacketReceive(uip_buf, UIP_CONF_BUFFER_SIZE); + + // + // See if this is an IP packet. + // + if((uip_len != 0) && + (((struct uip_eth_hdr *)&uip_buf[0])->type == + HTONS(UIP_ETHTYPE_IP))) + { + // + // Update the ARP tables based on this packet. + // + uip_arp_ipin(); + + // + // Process this packet. + // + uip_input(); + + // + // See if the processing of this packet resulted in a packet to be + // sent. + // + if(uip_len > 0) + { + // + // Update the ARP tables based on the packet to be sent. + // + uip_arp_out(); + + // + // Send the packet. + // + PacketTransmit(uip_buf, uip_len); + + // + // Indicate that the packet has been sent. + // + uip_len = 0; + } + } + + // + // See if this is an ARP packet. + // + else if((uip_len != 0) && + (((struct uip_eth_hdr *)&uip_buf[0])->type == + HTONS(UIP_ETHTYPE_ARP))) + { + // + // Process this packet. + // + uip_arp_arpin(); + + // + // See if the processing of this packet resulted in a packet to be + // sent. + // + if(uip_len > 0) + { + // + // Send the packet. + // + PacketTransmit(uip_buf, uip_len); + + // + // Indicate that the packet has been sent. + // + uip_len = 0; + } + } + } + + // + // See if the periodic timer has expired. + // + if(g_ui32PeriodicTimer > UIP_PERIODIC_TIMER_MS) + { + // + // Reset the periodic timer. + // + g_ui32PeriodicTimer = 0; + + // + // Loop through the UDP connections. + // + for(ui32Temp = 0; ui32Temp < UIP_UDP_CONNS; ui32Temp++) + { + // + // Perform the periodic processing on this UDP connection. + // + uip_udp_periodic(ui32Temp); + + // + // See if the periodic processing of this connection resulted in a + // packet to be sent. + // + if(uip_len > 0) + { + // + // Update the ARP tables based on the packet to be sent. + // + uip_arp_out(); + + // + // Send the packet. + // + PacketTransmit(uip_buf, uip_len); + + // + // Indicate that the packet has been sent. + // + uip_len = 0; + } + } + } + + // + // See if the ARP timer has expired. + // + if(g_ui32ARPTimer > UIP_ARP_TIMER_MS) + { + // + // Reset the ARP timer. + // + g_ui32ARPTimer = 0; + + // + // Perform periodic processing on the ARP table. + // + uip_arp_timer(); + } + } +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** +#endif diff --git a/boot_loader/bl_flash.c b/boot_loader/bl_flash.c new file mode 100644 index 0000000..3bbb0ee --- /dev/null +++ b/boot_loader/bl_flash.c @@ -0,0 +1,218 @@ +//***************************************************************************** +// +// bl_flash.c - Flash programming functions used by 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 "inc/hw_types.h" +#include "inc/hw_flash.h" +#include "inc/hw_sysctl.h" +#include "inc/hw_memmap.h" +#include "bl_config.h" +#include "boot_loader/bl_flash.h" + +//***************************************************************************** +// +//! Erases a single 1KB block of internal flash. +//! +//! \param ui32Address is the address of the block of flash to erase. +//! +//! This function erases a single 1KB block of the internal flash, blocking +//! until the erase has completed. +//! +//! \return None +// +//***************************************************************************** +void +BLInternalFlashErase(uint32_t ui32Address) +{ + // + // Erase this block of the flash. + // + HWREG(FLASH_FMA) = ui32Address; + HWREG(FLASH_FMC) = FLASH_FMC_WRKEY | FLASH_FMC_ERASE; + + // + // Wait until the flash has been erased. + // + while(HWREG(FLASH_FMC) & FLASH_FMC_ERASE) + { + } +} + +//***************************************************************************** +// +//! Programs a block of data at a given address in the internal flash. +//! +//! \param ui32DstAddr is the address of the first word to be programmed in +//! flash. +//! \param pui8SrcData is a pointer to the first byte to be programmed. +//! \param ui32Length is the number of bytes to program. This must be a +//! multiple of 4. +//! +//! This function writes a block of data to the internal flash at a given +//! address. Since the flash is written a word at a time, the data must be a +//! multiple of 4 bytes and the destination address, ui32DstAddr, must be on a +//! word boundary. +//! +//! \return None +// +//***************************************************************************** +void +BLInternalFlashProgram(uint32_t ui32DstAddr, uint8_t *pui8SrcData, + uint32_t ui32Length) +{ + uint32_t ui32Loop; + + for(ui32Loop = 0; ui32Loop < ui32Length; ui32Loop += 4) + { + // + // Program this word into flash. + // + HWREG(FLASH_FMA) = ui32DstAddr + ui32Loop; + HWREG(FLASH_FMD) = *(uint32_t *)(pui8SrcData + ui32Loop); + HWREG(FLASH_FMC) = FLASH_FMC_WRKEY | FLASH_FMC_WRITE; + + // + // Wait until the flash has been programmed. + // + while(HWREG(FLASH_FMC) & FLASH_FMC_WRITE) + { + } + } +} + +//***************************************************************************** +// +//! Returns the size of the internal flash in bytes. +//! +//! This function returns the total number of bytes of internal flash in the +//! current part. No adjustment is made for any sections reserved via +//! options defined in bl_config.h. +//! +//! \return Returns the total number of bytes of internal flash. +// +//***************************************************************************** +uint32_t +BLInternalFlashSizeGet(void) +{ + return(((HWREG(SYSCTL_DC0) & SYSCTL_DC0_FLASHSZ_M) + 1) << 11); +} + +//***************************************************************************** +// +//! Checks whether a given start address is valid for a download. +//! +//! This function checks to determine whether the given address is a valid +//! download image start address given the options defined in bl_config.h. +//! +//! \return Returns non-zero if the address is valid or 0 otherwise. +// +//***************************************************************************** +uint32_t +BLInternalFlashStartAddrCheck(uint32_t ui32Addr, uint32_t ui32ImgSize) +{ + uint32_t ui32FlashSize; + + // + // Determine the size of the flash available on the part in use. + // + ui32FlashSize = ((HWREG(SYSCTL_DC0) & SYSCTL_DC0_FLASHSZ_M) + 1) << 11; + + // + // If we are reserving space at the top of flash then this space is not + // available for application download but it is availble to be updated + // directly. + // +#ifdef FLASH_RSVD_SPACE + if((ui32FlashSize - FLASH_RSVD_SPACE) != ui32Addr) + { + ui32FlashSize -= FLASH_RSVD_SPACE; + } +#endif + + // + // Is the address we were passed a valid start address? We allow: + // + // 1. Address 0 if configured to update the boot loader. + // 2. The start of the reserved block if parameter space is reserved (to + // allow a download of the parameter block contents). + // 3. The application start address specified in bl_config.h. + // + // The function fails if the address is not one of these, if the image + // size is larger than the available space or if the address is not word + // aligned. + // + if(( +#ifdef ENABLE_BL_UPDATE + (ui32Addr != 0) && +#endif +#ifdef FLASH_RSVD_SPACE + (ui32Addr != (ui32FlashSize - FLASH_RSVD_SPACE)) && +#endif + (ui32Addr != APP_START_ADDRESS)) || + ((ui32Addr + ui32ImgSize) > ui32FlashSize) || ((ui32Addr & 3) != 0)) + { + return(0); + } + else + { + return(1); + } +} + +//***************************************************************************** +// +//! Checks whether a flash access violation occurred. +//! +//! This function checks whether an access violation error occurred during +//! the previous program or erase operation. +//! +//! \return Returns 0 if no error occurred or a non-zero value if an error was +//! reported. +// +//***************************************************************************** +void +BLInternalFlashErrorClear(void) +{ + // + // Clear the flash controller access interrupt. + // + HWREG(FLASH_FCMISC) = FLASH_FCMISC_AMISC; +} + +//***************************************************************************** +// +//! Checks whether a flash access violation occurred. +//! +//! This function checks whether an access violation error occurred since the +//! last call to BLInternalFlashErrorClear(). +//! +//! \return Returns 0 if no error occurred or a non-zero value if an error was +//! reported. +// +//***************************************************************************** +uint32_t +BLInternalFlashErrorCheck(void) +{ + return(HWREG(FLASH_FCRIS) & FLASH_FCRIS_ARIS); +} diff --git a/boot_loader/bl_flash.h b/boot_loader/bl_flash.h new file mode 100644 index 0000000..4a23f00 --- /dev/null +++ b/boot_loader/bl_flash.h @@ -0,0 +1,127 @@ +//***************************************************************************** +// +// bl_flash.h - Flash programming functions used by 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. +// +//***************************************************************************** + +#ifndef __BL_FLASH_H__ +#define __BL_FLASH_H__ + +#include "driverlib/rom.h" + +//***************************************************************************** +// +// Basic functions for erasing and programming internal flash. +// +//***************************************************************************** +extern void BLInternalFlashErase(uint32_t ui32Address); +extern void BLInternalFlashProgram(uint32_t ui32DstAddr, uint8_t *pui8SrcData, + uint32_t ui32Length); +extern uint32_t BLInternalFlashSizeGet(void); +extern uint32_t BLInternalFlashStartAddrCheck(uint32_t ui32Addr, + uint32_t ui32ImgSize); +extern uint32_t BLInternalFlashErrorCheck(void); +extern void BLInternalFlashErrorClear(void); + +//***************************************************************************** +// +// If the user has not specified which flash programming functions to use, +// default to the basic, internal flash functions on Sandstorm, Fury and +// DustDevil parts or the ROM-resident function for Tempest-class parts. +// +//***************************************************************************** +#ifndef BL_FLASH_ERASE_FN_HOOK +#define BL_FLASH_ERASE_FN_HOOK(ui32Address) \ + { \ + HWREG(FLASH_FMA) = (ui32Address); \ + HWREG(FLASH_FMC) = FLASH_FMC_WRKEY | FLASH_FMC_ERASE; \ + while(HWREG(FLASH_FMC) & FLASH_FMC_ERASE) \ + { \ + } \ + } +#else +extern void BL_FLASH_ERASE_FN_HOOK(uint32_t ui32Address); +#endif + +#ifndef BL_FLASH_PROGRAM_FN_HOOK +#ifdef ROM_FlashProgram +#define BL_FLASH_PROGRAM_FN_HOOK(ui32DstAddr, pui8SrcData, ui32Length) \ + ROM_FlashProgram((uint32_t *)pui8SrcData, ui32DstAddr, \ + (((ui32Length) + 3) & ~3)) +#else +#define BL_FLASH_PROGRAM_FN_HOOK(ui32DstAddr, pui8SrcData, ui32Length) \ + { \ + uint32_t ui32FlashProgLoop; \ + \ + for(ui32FlashProgLoop = 0; ui32FlashProgLoop < (ui32Length); \ + ui32FlashProgLoop += 4) \ + { \ + HWREG(FLASH_FMA) = (ui32DstAddr) + ui32FlashProgLoop; \ + HWREG(FLASH_FMD) = *(uint32_t *)((pui8SrcData) + \ + ui32FlashProgLoop); \ + HWREG(FLASH_FMC) = FLASH_FMC_WRKEY | FLASH_FMC_WRITE; \ + while(HWREG(FLASH_FMC) & FLASH_FMC_WRITE) \ + { \ + } \ + } \ + } +#endif +#else +extern uint32_t BL_FLASH_PROGRAM_FN_HOOK(uint32_t ui32DstAddr, + uint8_t *pui8SrcData, + uint32_t ui32Length); +#endif + +#ifndef BL_FLASH_CL_ERR_FN_HOOK +#define BL_FLASH_CL_ERR_FN_HOOK() HWREG(FLASH_FCMISC) = FLASH_FCMISC_AMISC +#else +extern void BL_FLASH_CL_ERR_FN_HOOK(void); +#endif + +#ifndef BL_FLASH_ERROR_FN_HOOK +#define BL_FLASH_ERROR_FN_HOOK() (HWREG(FLASH_FCRIS) & FLASH_FCRIS_ARIS) +#else +extern uint32_t BL_FLASH_ERROR_FN_HOOK(void); +#endif + +#ifndef BL_FLASH_SIZE_FN_HOOK +#define BL_FLASH_SIZE_FN_HOOK() \ + (((HWREG(SYSCTL_DC0) & SYSCTL_DC0_FLASHSZ_M) + 1) << 11) +#else +extern uint32_t BL_FLASH_SIZE_FN_HOOK(void); +#endif + +#ifndef BL_FLASH_END_FN_HOOK +#define BL_FLASH_END_FN_HOOK() \ + (((HWREG(SYSCTL_DC0) & SYSCTL_DC0_FLASHSZ_M) + 1) << 11) +#else +extern uint32_t BL_FLASH_END_FN_HOOK(void); +#endif + +#ifndef BL_FLASH_AD_CHECK_FN_HOOK +#define BL_FLASH_AD_CHECK_FN_HOOK(ui32Addr, ui32Size) \ + BLInternalFlashStartAddrCheck((ui32Addr), (ui32Size)) +#else +extern uint32_t BL_FLASH_AD_CHECK_FN_HOOK(uint32_t ui32Address, + uint32_t ui32Length); +#endif + +#endif // __BL_FLASH_H__ diff --git a/boot_loader/bl_hooks.h b/boot_loader/bl_hooks.h new file mode 100644 index 0000000..1a174e3 --- /dev/null +++ b/boot_loader/bl_hooks.h @@ -0,0 +1,72 @@ +//***************************************************************************** +// +// bl_hooks.h - Definitions for the application-specific hook function. +// +// Copyright (c) 2009-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. +// +//***************************************************************************** + +#ifndef __BL_HOOKS_H__ +#define __BL_HOOKS_H__ + +//***************************************************************************** +// +// Prototypes for any application-specific hook functions that are defined in +// bl_config.h. Note that the low level flash programming hooks are handled +// in bl_flash.h to allow us to define macros for internal flash programming +// in the normal case where no override functions are provided. +// +//***************************************************************************** +#ifdef BL_HW_INIT_FN_HOOK +extern void BL_HW_INIT_FN_HOOK(void); +#endif +#ifdef BL_INIT_FN_HOOK +extern void BL_INIT_FN_HOOK(void); +#endif +#ifdef BL_REINIT_FN_HOOK +extern void BL_REINIT_FN_HOOK(void); +#endif +#ifdef BL_START_FN_HOOK +extern void BL_START_FN_HOOK(void); +#endif +#ifdef BL_PROGRESS_FN_HOOK +extern void BL_PROGRESS_FN_HOOK(uint32_t ui32Completed, uint32_t ui32Total); +#endif +#ifdef BL_END_FN_HOOK +extern void BL_END_FN_HOOK(void); +#endif +#ifdef BL_DECRYPT_FN_HOOK +extern void BL_DECRYPT_FN_HOOK(uint8_t *pui8Buffer, uint32_t ui32Size); +#endif +#ifdef BL_CHECK_UPDATE_FN_HOOK +extern uint32_t BL_CHECK_UPDATE_FN_HOOK(void); +#endif + +//***************************************************************************** +// +// If ENABLE_DECRYPTION is defined but we don't have a hook function set for +// decryption, default to the previous behavior which calls the stub function +// DecryptData. +// +//***************************************************************************** +#if (defined ENABLE_DECRYPTION) && !(defined BL_DECRYPT_FN_HOOK) +#define BL_DECRYPT_FN_HOOK DecryptData +#endif + +#endif // __BL_HOOKS_H__ diff --git a/boot_loader/bl_i2c.c b/boot_loader/bl_i2c.c new file mode 100644 index 0000000..bc2b62c --- /dev/null +++ b/boot_loader/bl_i2c.c @@ -0,0 +1,149 @@ +//***************************************************************************** +// +// bl_i2c.c - This file contains the function used to transfer data via the I2C +// port. +// +// 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 "inc/hw_gpio.h" +#include "inc/hw_i2c.h" +#include "inc/hw_memmap.h" +#include "inc/hw_sysctl.h" +#include "inc/hw_types.h" +#include "bl_config.h" +#include "boot_loader/bl_i2c.h" + +//***************************************************************************** +// +//! \addtogroup bl_i2c_api +//! @{ +// +//***************************************************************************** +#if defined(I2C_ENABLE_UPDATE) || defined(DOXYGEN) + +//***************************************************************************** +// +//! Sends data over the I2C port. +//! +//! \param pui8Data is the buffer containing the data to write out to the I2C +//! port. +//! \param ui32Size is the number of bytes provided in \e pui8Data buffer that +//! will be written out to the I2C port. +//! +//! This function sends \e ui32Size bytes of data from the buffer pointed to by +//! \e pui8Data via the I2C port. The function will wait till the I2C Slave +//! port has been properly addressed by the I2C Master device before sending +//! the first byte. +//! +//! \return None. +// +//***************************************************************************** +void +I2CSend(const uint8_t *pui8Data, uint32_t ui32Size) +{ + // + // Transmit the number of bytes requested on the UART port. + // + while(ui32Size--) + { + // + // Wait for request to come in at slave. + // + while(!(HWREG(I2C0_BASE + I2C_O_SCSR) & I2C_SCSR_TREQ)) + { + } + + // + // Send out the next byte. + // + HWREG(I2C0_BASE + I2C_O_SDR) = *pui8Data++; + } +} + +//***************************************************************************** +// +//! Waits until all data has been transmitted by the I2C port. +//! +//! This function waits until all data written to the I2C port has been read by +//! the master. +//! +//! \return None. +// +//***************************************************************************** +void +I2CFlush(void) +{ + // + // Wait until the I2C bus is no longer busy, meaning that the last byte has + // been sent. + // + while(HWREG(I2C0_BASE + I2C_O_MCS) & I2C_MCS_BUSBSY) + { + } +} + +//***************************************************************************** +// +//! Receives data over the I2C port. +//! +//! \param pui8Data is the buffer to read data into from the I2C port. +//! \param ui32Size is the number of bytes provided in the \e pui8Data buffer +//! that should be written with data from the I2C port. +//! +//! This function reads back \e ui32Size bytes of data from the I2C port, into +//! the buffer that is pointed to by \e pui8Data. This function will not +//! return until \e ui32Size number of bytes have been received. This function +//! will wait till the I2C Slave port has been properly addressed by the I2C +//! Master before reading the first byte of data from the I2C port. +//! +//! \return None. +// +//***************************************************************************** +void +I2CReceive(uint8_t *pui8Data, uint32_t ui32Size) +{ + // + // Send out the number of bytes requested. + // + while(ui32Size--) + { + // + // Wait until the slave has received the character. + // + while(!(HWREG(I2C0_BASE + I2C_O_SCSR) & I2C_SCSR_RREQ)) + { + } + + // + // Receive a byte from the I2C. + // + *pui8Data++ = HWREG(I2C0_BASE + I2C_O_SDR); + } +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** +#endif diff --git a/boot_loader/bl_i2c.h b/boot_loader/bl_i2c.h new file mode 100644 index 0000000..4b7a01a --- /dev/null +++ b/boot_loader/bl_i2c.h @@ -0,0 +1,70 @@ +//***************************************************************************** +// +// bl_i2c.h - Definitions for the I2C transport functions. +// +// 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. +// +//***************************************************************************** + +#ifndef __BL_I2C_H__ +#define __BL_I2C_H__ + +//***************************************************************************** +// +// This defines the I2C clock pin that is being used by the boot loader. +// +//***************************************************************************** +#define I2C_CLK (1 << 2) + +//***************************************************************************** +// +// This defines the I2C data pin that is being used by the boot loader. +// +//***************************************************************************** +#define I2C_DATA (1 << 3) + +//***************************************************************************** +// +// This defines the combination of pins used to implement the I2C port used by +// the boot loader. +// +//***************************************************************************** +#define I2C_PINS (I2C_CLK | I2C_DATA) + +//***************************************************************************** +// +// I2C Transport APIs +// +//***************************************************************************** +extern void I2CSend(const uint8_t *pui8Data, uint32_t ui32Size); +extern void I2CReceive(uint8_t *pui8Data, uint32_t ui32Size); +extern void I2CFlush(void); + +//***************************************************************************** +// +// Define the transport functions if the I2C port is being used. +// +//***************************************************************************** +#ifdef I2C_ENABLE_UPDATE +#define SendData I2CSend +#define FlushData I2CFlush +#define ReceiveData I2CReceive +#endif + +#endif // __BL_I2C_H__ diff --git a/boot_loader/bl_link.icf b/boot_loader/bl_link.icf new file mode 100644 index 0000000..3e7af89 --- /dev/null +++ b/boot_loader/bl_link.icf @@ -0,0 +1,83 @@ +//***************************************************************************** +// +// bl_link.icf - Linker script for EW-ARM. +// +// Copyright (c) 2007-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. +// +//***************************************************************************** + +// +// Define a memory region that covers the entire 4 GB addressible space of the +// processor. +// +define memory mem with size = 4G; + +// +// Define a region for the on-chip flash. +// +define region FLASH = mem:[from 0x00000000 to 0x0000ffff]; + +// +// Define a region for the on-chip SRAM. +// +define region SRAM = mem:[from 0x20000000 to 0x2000ffff]; + +// +// Indicate that the sections containing the boot loader code should be +// initialized by copying. +// +initialize manually with packing = none { section INTVEC }; +initialize manually with packing = none { section CODE }; +initialize manually with packing = none { section .text }; +initialize manually with packing = none { section .rodata }; +initialize manually with packing = none { section .data }; + +keep { section INTVEC }; +keep { section INTVEC_init }; + +// +// Indicate that the noinit values should be left alone. This includes the +// stack, which if initialized will destroy the return address from the +// initialization code, causing the processor to branch to zero and fault. +// +do not initialize { section .noinit }; + +// +// Place the interrupt vectors at the start of flash/SRAM. +// +place at start of FLASH { readonly section INTVEC_init }; +place at start of SRAM { readwrite section INTVEC }; + +// +// Place the remainder of the read-only items into flash/SRAM. +// +place in FLASH { readonly section CODE_init }; +place in SRAM { readwrite section CODE }; +place in FLASH { readonly section .text_init }; +place in SRAM { readwrite section .text }; +place in FLASH { readonly section .rodata_init }; +place in SRAM { readwrite section .rodata }; +place in FLASH { readonly section .data_init }; +place in SRAM { readwrite section .data }; +place in FLASH { readonly }; + +// +// Place all read/write items into SRAM. +// +place in SRAM { readwrite }; diff --git a/boot_loader/bl_link.ld b/boot_loader/bl_link.ld new file mode 100644 index 0000000..aae5f00 --- /dev/null +++ b/boot_loader/bl_link.ld @@ -0,0 +1,51 @@ +/****************************************************************************** + * + * bl_link.ld - Scatter file for Gnu tools + * + * Copyright (c) 2007-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. + * + *****************************************************************************/ + +SECTIONS +{ + .text 0x20000000 : AT (0x00000000) + { + _text = .; + KEEP(*(.isr_vector)) + *(.text*) + *(.rodata*) + _etext = .; + } + + .data 0x20000000 + SIZEOF(.text) : AT (SIZEOF(.text)) + { + _data = .; + *(.data*) + _edata = .; + } + + .bss 0x20000000 + SIZEOF(.text) + SIZEOF(.data) : + AT (ADDR(.data) + SIZEOF(.data)) + { + _bss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } +} diff --git a/boot_loader/bl_link.sct b/boot_loader/bl_link.sct new file mode 100644 index 0000000..fe22bd1 --- /dev/null +++ b/boot_loader/bl_link.sct @@ -0,0 +1,45 @@ +;****************************************************************************** +; +; bl_link.sct - Scatter file for RV-MDK. +; +; 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. +; +;****************************************************************************** + +; +; The contents of this application reside in flash. +; +FLASH 0x00000000 0x00010000 +{ + ; + ; Place the vector table and reset handlers into flash. + ; + RESET 0x00000000 0x00010000 + { + *.o (RESET, +First) + } + + ; + ; Place everything else remaining into SRAM (RO, RW, and ZI) + ; + SRAM +0x20000000 0x00010000 + { + * (+RO, +RW, +ZI) + } +} diff --git a/boot_loader/bl_link_ccs.cmd b/boot_loader/bl_link_ccs.cmd new file mode 100644 index 0000000..0e09b6e --- /dev/null +++ b/boot_loader/bl_link_ccs.cmd @@ -0,0 +1,63 @@ +/****************************************************************************** + * + * bl_link_ccs.cmd - CCS linker configuration file for boot loader. + * + * Copyright (c) 2009-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. + * + *****************************************************************************/ + +--retain=Vectors + +/* The following command line options are set as part of the CCS project. */ +/* If you are building using the command line, or for some reason want to */ +/* define them here, you can uncomment and modify these lines as needed. */ +/* If you are using CCS for building, it is probably better to make any such */ +/* modifications in your CCS project and leave this file alone. */ +/* */ +/* --heap_size=0 */ +/* --stack_size=256 */ +/* --library=rtsv7M3_T_le_eabi.lib */ + +/* System memory map */ + +MEMORY +{ + FLASH (RX) : origin = 0x00000000, length = 0x00010000 + SRAM (RWX) : origin = 0x20000000, length = 0x00010000 +} + +/* Section allocation in memory */ + +SECTIONS +{ + GROUP + { + .intvecs + .text + .const + .data + } load = FLASH, run = 0x20000000, LOAD_START(init_load), RUN_START(init_run), SIZE(init_size) + + GROUP + { + .bss + .stack + } run = SRAM, RUN_START(bss_run), RUN_END(bss_end), SIZE(bss_size), RUN_END(__STACK_TOP) + +} 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 diff --git a/boot_loader/bl_packet.c b/boot_loader/bl_packet.c new file mode 100644 index 0000000..f54495c --- /dev/null +++ b/boot_loader/bl_packet.c @@ -0,0 +1,295 @@ +//***************************************************************************** +// +// bl_packet.c - Packet handler functions used by 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 "bl_config.h" +#include "boot_loader/bl_commands.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" + +//***************************************************************************** +// +//! \addtogroup bl_packet_api +//! @{ +// +//***************************************************************************** +#if defined(I2C_ENABLE_UPDATE) || defined(SSI_ENABLE_UPDATE) || \ + defined(UART_ENABLE_UPDATE) || defined(DOXYGEN) + +//***************************************************************************** +// +// The packet that is sent to acknowledge a received packet. +// +//***************************************************************************** +static const uint8_t g_pui8ACK[2] = { 0, COMMAND_ACK }; + +//***************************************************************************** +// +// The packet that is sent to not-acknowledge a received packet. +// +//***************************************************************************** +static const uint8_t g_pui8NAK[2] = { 0, COMMAND_NAK }; + +//***************************************************************************** +// +//! Calculates an 8-bit checksum +//! +//! \param pui8Data is a pointer to an array of 8-bit data of size ui32Size. +//! \param ui32Size is the size of the array that will run through the checksum +//! algorithm. +//! +//! This function simply calculates an 8-bit checksum on the data passed in. +//! +//! \return Returns the calculated checksum. +// +//***************************************************************************** +uint32_t +CheckSum(const uint8_t *pui8Data, uint32_t ui32Size) +{ + uint32_t ui32CheckSum; + + // + // Initialize the checksum to zero. + // + ui32CheckSum = 0; + + // + // Add up all the bytes, do not do anything for an overflow. + // + while(ui32Size--) + { + ui32CheckSum += *pui8Data++; + } + + // + // Return the caculated check sum. + // + return(ui32CheckSum & 0xff); +} + +//***************************************************************************** +// +//! Sends an Acknowledge packet. +//! +//! This function is called to acknowledge that a packet has been received by +//! the microcontroller. +//! +//! \return None. +// +//***************************************************************************** +void +AckPacket(void) +{ + // + // ACK/NAK packets are the only ones with no size. + // + SendData(g_pui8ACK, 2); +} + +//***************************************************************************** +// +//! Sends a no-acknowledge packet. +//! +//! This function is called when an invalid packet has been received by the +//! microcontroller, indicating that it should be retransmitted. +//! +//! \return None. +// +//***************************************************************************** +void +NakPacket(void) +{ + // + // ACK/NAK packets are the only ones with no size. + // + SendData(g_pui8NAK, 2); +} + +//***************************************************************************** +// +//! Receives a data packet. +//! +//! \param pui8Data is the location to store the data that is sent to the boot +//! loader. +//! \param pui32Size is the number of bytes returned in the pui8Data buffer +//! that was provided. +//! +//! This function receives a packet of data from specified transfer function. +//! +//! \return Returns zero to indicate success while any non-zero value indicates +//! a failure. +// +//***************************************************************************** +int +ReceivePacket(uint8_t *pui8Data, uint32_t *pui32Size) +{ + uint32_t ui32Size, ui32CheckSum; + + // + // Wait for non-zero data before getting the first byte that holds the + // size of the packet we are receiving. + // + ui32Size = 0; + while(ui32Size == 0) + { + ReceiveData((uint8_t *)&ui32Size, 1); + } + + // + // Subtract off the size and checksum bytes. + // + ui32Size -= 2; + + // + // Receive the checksum followed by the actual data. + // + ReceiveData((uint8_t *)&ui32CheckSum, 1); + + // + // If there is room in the buffer then receive the requested data. + // + if(*pui32Size >= ui32Size) + { + // + // Receive the actual data in the packet. + // + ReceiveData(pui8Data, ui32Size); + + // + // Send a no acknowledge if the checksum does not match, otherwise send + // an acknowledge to the packet later. + // + if(CheckSum(pui8Data, ui32Size) != (ui32CheckSum & 0xff)) + { + // + // Indicate tha the packet was not received correctly. + // + NakPacket(); + + // + // Packet was not received, there is no valid data in the buffer. + // + return(-1); + } + } + else + { + // + // If the caller allocated a buffer that was too small for the received + // data packet, receive it but don't fill the buffer. + // Then inform the caller that the packet was not received correctly. + // + while(ui32Size--) + { + ReceiveData(pui8Data, 1); + } + + // + // Packet was not received, there is no valid data in the buffer. + // + return(-1); + } + + // + // Make sure to return the number of bytes received. + // + *pui32Size = ui32Size; + + // + // Packet was received successfully. + // + return(0); +} + +//***************************************************************************** +// +//! Sends a data packet. +//! +//! \param pui8Data is the location of the data to be sent. +//! \param ui32Size is the number of bytes to send. +//! +//! This function sends the data provided in the \e pui8Data parameter in the +//! packet format used by the boot loader. The caller only needs to specify +//! the buffer with the data that needs to be transferred. This function +//! addresses all other packet formatting issues. +//! +//! \return Returns zero to indicate success while any non-zero value indicates +//! a failure. +// +//***************************************************************************** +int +SendPacket(uint8_t *pui8Data, uint32_t ui32Size) +{ + uint32_t ui32Temp; + + // + // Caculate the checksum to be sent out with the data. + // + ui32Temp = CheckSum(pui8Data, ui32Size); + + // + // Need to include the size and checksum bytes in the packet. + // + ui32Size += 2; + + // + // Send out the size followed by the data. + // + SendData((uint8_t *)&ui32Size, 1); + SendData((uint8_t *)&ui32Temp, 1); + SendData(pui8Data, ui32Size - 2); + + // + // Wait for a non zero byte. + // + ui32Temp = 0; + while(ui32Temp == 0) + { + ReceiveData((uint8_t *)&ui32Temp, 1); + } + + // + // Check if the byte was a valid ACK and return a negative value if it was + // not and aknowledge. + // + if(ui32Temp != COMMAND_ACK) + { + return(-1); + } + + // + // This packet was sent and received successfully. + // + return(0); +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** +#endif diff --git a/boot_loader/bl_packet.h b/boot_loader/bl_packet.h new file mode 100644 index 0000000..3c4f78d --- /dev/null +++ b/boot_loader/bl_packet.h @@ -0,0 +1,37 @@ +//***************************************************************************** +// +// bl_packet.h - The global variables and definitions 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. +// +//***************************************************************************** + +#ifndef __BL_PACKET_H__ +#define __BL_PACKET_H__ + +//***************************************************************************** +// +// Packet Handling APIs +// +//***************************************************************************** +extern int ReceivePacket(uint8_t *pui8Data, uint32_t *pui32Size); +extern int SendPacket(uint8_t *pui8Data, uint32_t ui32Size); +extern void AckPacket(void); + +#endif // __BL_PACKET_H__ diff --git a/boot_loader/bl_ssi.c b/boot_loader/bl_ssi.c new file mode 100644 index 0000000..ca10517 --- /dev/null +++ b/boot_loader/bl_ssi.c @@ -0,0 +1,161 @@ +//***************************************************************************** +// +// bl_ssi.c - Functions used to transfer data via the SSI port. +// +// 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 "inc/hw_gpio.h" +#include "inc/hw_memmap.h" +#include "inc/hw_ssi.h" +#include "inc/hw_sysctl.h" +#include "inc/hw_types.h" +#include "bl_config.h" +#include "boot_loader/bl_ssi.h" + +//***************************************************************************** +// +//! \addtogroup bl_ssi_api +//! @{ +// +//***************************************************************************** +#if defined(SSI_ENABLE_UPDATE) || defined(DOXYGEN) + +//***************************************************************************** +// +//! Sends data via the SSI port in slave mode. +//! +//! \param pui8Data is the location of the data to send through the SSI port. +//! \param ui32Size is the number of bytes of data to send. +//! +//! This function sends data through the SSI port in slave mode. This function +//! will not return until all bytes are sent. +//! +//! \return None. +// +//***************************************************************************** +void +SSISend(const uint8_t *pui8Data, uint32_t ui32Size) +{ + // + // Send the requested number of bytes over the SSI port. + // + while(ui32Size--) + { + // + // Wait until there is space in the SSI FIFO. + // + while(!(HWREG(SSI0_BASE + SSI_O_SR) & SSI_SR_TNF)) + { + } + + // + // Write the next byte to the SSI port. + // + HWREG(SSI0_BASE + SSI_O_DR) = *pui8Data++; + } + + // + // Empty the receive FIFO. + // + while(HWREG(SSI0_BASE + SSI_O_SR) & SSI_SR_RNE) + { + HWREG(SSI0_BASE + SSI_O_DR); + } +} + +//***************************************************************************** +// +//! Waits until all data has been transmitted by the SSI port. +//! +//! This function waits until all data written to the SSI port has been read by +//! the master. +//! +//! \return None. +// +//***************************************************************************** +void +SSIFlush(void) +{ + // + // Wait until the transmit FIFO is empty. + // + while(!(HWREG(SSI0_BASE + SSI_O_SR) & SSI_SR_TFE)) + { + } + + // + // Wait until the interface is not busy. + // + while(HWREG(SSI0_BASE + SSI_O_SR) & SSI_SR_BSY) + { + } +} + +//***************************************************************************** +// +//! Receives data from the SSI port in slave mode. +//! +//! \param pui8Data is the location to store the data received from the SSI +//! port. +//! \param ui32Size is the number of bytes of data to receive. +//! +//! This function receives data from the SSI port in slave mode. The function +//! will not return until \e ui32Size number of bytes have been received. +//! +//! \return None. +// +//***************************************************************************** +void +SSIReceive(uint8_t *pui8Data, uint32_t ui32Size) +{ + // + // Ensure that we are sending out zeros so that we don't confuse the host. + // + HWREG(SSI0_BASE + SSI_O_DR) = 0; + + // + // Wait for the requested number of bytes. + // + while(ui32Size--) + { + // + // Wait until there is data in the FIFO. + // + while(!(HWREG(SSI0_BASE + SSI_O_SR) & SSI_SR_RNE)) + { + } + + // + // Read the next byte from the FIFO. + // + *pui8Data++ = HWREG(SSI0_BASE + SSI_O_DR); + HWREG(SSI0_BASE + SSI_O_DR) = 0; + } +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** +#endif diff --git a/boot_loader/bl_ssi.h b/boot_loader/bl_ssi.h new file mode 100644 index 0000000..05ec3bb --- /dev/null +++ b/boot_loader/bl_ssi.h @@ -0,0 +1,92 @@ +//***************************************************************************** +// +// bl_ssi.h - Definitions for the SSI transport functions. +// +// 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. +// +//***************************************************************************** + +#ifndef __BL_SSI_H__ +#define __BL_SSI_H__ + +//***************************************************************************** +// +// This is the number of bits per transfer for SSI. This is a constant and +// cannot be changed without corresponding code changes. +// +//***************************************************************************** +#define DATA_BITS_SSI 8 + +//***************************************************************************** +// +// This defines the SSI chip select pin that is being used by the boot loader. +// +//***************************************************************************** +#define SSI_CS (1 << 3) + +//***************************************************************************** +// +// This defines the SSI clock pin that is being used by the boot loader. +// +//***************************************************************************** +#define SSI_CLK (1 << 2) + +//***************************************************************************** +// +// This defines the SSI transmit pin that is being used by the boot loader. +// +//***************************************************************************** +#define SSI_TX (1 << 5) + +//***************************************************************************** +// +// This defines the SSI receive pin that is being used by the boot loader. +// +//***************************************************************************** +#define SSI_RX (1 << 4) + +//***************************************************************************** +// +// This defines the combination of pins used to implement the SSI port used by +// the boot loader. +// +//***************************************************************************** +#define SSI_PINS (SSI_CLK | SSI_TX | SSI_RX | SSI_CS) + +//***************************************************************************** +// +// SSI Transport APIs +// +//***************************************************************************** +extern void SSISend(const uint8_t *pui8Data, uint32_t ui32Size); +extern void SSIReceive(uint8_t *pui8Data, uint32_t ui32Size); +extern void SSIFlush(void); + +//***************************************************************************** +// +// Define the transport functions if the SSI port is being used. +// +//***************************************************************************** +#ifdef SSI_ENABLE_UPDATE +#define SendData SSISend +#define FlushData SSIFlush +#define ReceiveData SSIReceive +#endif + +#endif // __BL_SSI_H__ diff --git a/boot_loader/bl_startup_ccs.s b/boot_loader/bl_startup_ccs.s new file mode 100644 index 0000000..8bfa96b --- /dev/null +++ b/boot_loader/bl_startup_ccs.s @@ -0,0 +1,645 @@ +;;***************************************************************************** +;; +;; bl_startup_ccs.s - Boot loader startup code for Code Composer Studio +;; +;; Copyright (c) 2009-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 the boot loader configuration options. +;; +;;***************************************************************************** + .cdecls C, NOLIST, WARN + %{ + #include "inc/hw_nvic.h" + #include "inc/hw_sysctl.h" + #include "bl_config.h" + %} + +;;***************************************************************************** +;; +;; Export symbols from this file that are used elsewhere +;; +;;***************************************************************************** + .global ResetISR, Delay, Vectors + +;;***************************************************************************** +;; +;; Create the stack and put it in a section +;; +;;***************************************************************************** + .global __stack +__stack:.usect ".stack", STACK_SIZE * 4, 8 + +;;***************************************************************************** +;; +;; Put the assembler into the correct configuration. +;; +;;***************************************************************************** + .thumb + +;;***************************************************************************** +;; +;; This portion of the file goes into interrupt vectors section +;; +;;***************************************************************************** + .sect ".intvecs" + +;;***************************************************************************** +;; +;; The minimal vector table for a Cortex-M3 processor. +;; +;;***************************************************************************** +Vectors: + .ref __STACK_TOP + .word __STACK_TOP ;; Offset 00: Initial stack pointer + .word ResetISR - 0x20000000 ;; Offset 04: Reset handler + .word NmiSR - 0x20000000 ;; Offset 08: NMI handler + .word FaultISR - 0x20000000 ;; Offset 0C: Hard fault handler + .word IntDefaultHandler ;; Offset 10: MPU fault handler + .word IntDefaultHandler ;; Offset 14: Bus fault handler + .word IntDefaultHandler ;; Offset 18: Usage fault handler + .word 0 ;; Offset 1C: Reserved + .word 0 ;; Offset 20: Reserved + .word 0 ;; Offset 24: Reserved + .word 0 ;; Offset 28: Reserved + .word UpdateHandler - 0x20000000 ;; Offset 2C: SVCall handler + .word IntDefaultHandler ;; Offset 30: Debug monitor handler + .word 0 ;; Offset 34: Reserved + .word IntDefaultHandler ;; Offset 38: PendSV handler + .if $$defined(ENET_ENABLE_UPDATE) + .ref SysTickIntHandler + .word SysTickIntHandler ;; Offset 3C: SysTick handler + .else + .word IntDefaultHandler ;; Offset 3C: SysTick handler + .endif + .if $$defined(UART_ENABLE_UPDATE) & $$defined(UART_AUTOBAUD) + .ref GPIOIntHandler + .word GPIOIntHandler ;; Offset 40: GPIO port A handler + .else + .word IntDefaultHandler ;; Offset 40: GPIO port A handler + .endif + .if ($$defined(USB_ENABLE_UPDATE) | (APP_START_ADDRESS != VTABLE_START_ADDRESS)) + .word IntDefaultHandler ;; Offset 44: GPIO Port B + .word IntDefaultHandler ;; Offset 48: GPIO Port C + .word IntDefaultHandler ;; Offset 4C: GPIO Port D + .word IntDefaultHandler ;; Offset 50: GPIO Port E + .word IntDefaultHandler ;; Offset 54: UART0 Rx and Tx + .word IntDefaultHandler ;; Offset 58: UART1 Rx and Tx + .word IntDefaultHandler ;; Offset 5C: SSI0 Rx and Tx + .word IntDefaultHandler ;; Offset 60: I2C0 Master and Slave + .word IntDefaultHandler ;; Offset 64: PWM Fault + .word IntDefaultHandler ;; Offset 68: PWM Generator 0 + .word IntDefaultHandler ;; Offset 6C: PWM Generator 1 + .word IntDefaultHandler ;; Offset 70: PWM Generator 2 + .word IntDefaultHandler ;; Offset 74: Quadrature Encoder 0 + .word IntDefaultHandler ;; Offset 78: ADC Sequence 0 + .word IntDefaultHandler ;; Offset 7C: ADC Sequence 1 + .word IntDefaultHandler ;; Offset 80: ADC Sequence 2 + .word IntDefaultHandler ;; Offset 84: ADC Sequence 3 + .word IntDefaultHandler ;; Offset 88: Watchdog timer + .word IntDefaultHandler ;; Offset 8C: Timer 0 subtimer A + .word IntDefaultHandler ;; Offset 90: Timer 0 subtimer B + .word IntDefaultHandler ;; Offset 94: Timer 1 subtimer A + .word IntDefaultHandler ;; Offset 98: Timer 1 subtimer B + .word IntDefaultHandler ;; Offset 9C: Timer 2 subtimer A + .word IntDefaultHandler ;; Offset A0: Timer 2 subtimer B + .word IntDefaultHandler ;; Offset A4: Analog Comparator 0 + .word IntDefaultHandler ;; Offset A8: Analog Comparator 1 + .word IntDefaultHandler ;; Offset AC: Analog Comparator 2 + .word IntDefaultHandler ;; Offset B0: System Control + .word IntDefaultHandler ;; Offset B4: FLASH Control + .endif + .if ($$defined(USB_ENABLE_UPDATE) | (APP_START_ADDRESS != VTABLE_START_ADDRESS)) + .word IntDefaultHandler ;; Offset B8: GPIO Port F + .word IntDefaultHandler ;; Offset BC: GPIO Port G + .word IntDefaultHandler ;; Offset C0: GPIO Port H + .word IntDefaultHandler ;; Offset C4: UART2 Rx and Tx + .word IntDefaultHandler ;; Offset C8: SSI1 Rx and Tx + .word IntDefaultHandler ;; Offset CC: Timer 3 subtimer A + .word IntDefaultHandler ;; Offset D0: Timer 3 subtimer B + .word IntDefaultHandler ;; Offset D4: I2C1 Master and Slave + .word IntDefaultHandler ;; Offset D8: Quadrature Encoder 1 + .word IntDefaultHandler ;; Offset DC: CAN0 + .word IntDefaultHandler ;; Offset E0: CAN1 + .word IntDefaultHandler ;; Offset E4: CAN2 + .word IntDefaultHandler ;; Offset E8: Ethernet + .word IntDefaultHandler ;; Offset EC: Hibernation module + .if $$defined(USB_ENABLE_UPDATE) + .ref USB0DeviceIntHandler + .word USB0DeviceIntHandler ;; Offset F0: USB 0 Controller + .else + .word IntDefaultHandler ;; Offset F0: USB 0 Controller + .endif + .endif + +;;***************************************************************************** +;; +;; This portion of the file goes into the text section. +;; +;;***************************************************************************** + .text + +;;***************************************************************************** +;; +;; Initialize the processor by copying the boot loader from flash to SRAM, zero +;; filling the .bss section, and moving the vector table to the beginning of +;; SRAM. The return address is modified to point to the SRAM copy of the boot +;; loader instead of the flash copy, resulting in a branch to the copy now in +;; SRAM. +;; +;;***************************************************************************** + .ref bss_run +bss_start .word bss_run + .ref __STACK_TOP +bss_end .word __STACK_TOP + + .thumbfunc ProcessorInit +ProcessorInit: .asmfunc + ;; + ;; Copy the code image from flash to SRAM. + ;; + movs r0, #0x0000 + movs r1, #0x0000 + movt r1, #0x2000 + ldr r2, bss_start +copy_loop: + ldr r3, [r0], #4 + str r3, [r1], #4 + cmp r1, r2 + blt copy_loop + + ;; + ;; Zero fill the .bss section. + ;; + movs r0, #0x0000 + ldr r2, bss_end +zero_loop: + str r0, [r1], #4 + cmp r1, r2 + blt zero_loop + + ;; + ;; Set the vector table pointer to the beginning of SRAM. + ;; + movw r0, #(NVIC_VTABLE & 0xffff) + movt r0, #(NVIC_VTABLE >> 16) + movs r1, #0x0000 + movt r1, #0x2000 + str r1, [r0] + + ;; + ;; Set the return address to the code just copied into SRAM. + ;; + orr lr, lr, #0x20000000 + + ;; + ;; Return to the caller. + ;; + bx lr + .endasmfunc + +;;***************************************************************************** +;; +;; The reset handler, which gets called when the processor starts. +;; +;;***************************************************************************** + .thumbfunc ResetISR +ResetISR: .asmfunc + ;; + ;; Enable the floating-point unit. This must be done here in case any + ;; later C functions use floating point. Note that some toolchains will + ;; use the FPU registers for general workspace even if no explicit floating + ;; point data types are in use. + ;; + movw r0, #0xED88 + movt r0, #0xE000 + ldr r1, [r0] + orr r1, r1, #0x00F00000 + str r1, [r0] + + ;; + ;; Initialize the processor. + ;; + bl ProcessorInit + + ;; + ;; Call the user-supplied low level hardware initialization function + ;; if provided. + ;; + .if $$defined(BL_HW_INIT_FN_HOOK) + .ref BL_HW_INIT_FN_HOOK + bl BL_HW_INIT_FN_HOOK + .endif + + ;; + ;; See if an update should be performed. + ;; + .ref CheckForceUpdate + bl CheckForceUpdate + cbz r0, CallApplication + + ;; + ;; Configure the microcontroller. + ;; + .thumbfunc EnterBootLoader +EnterBootLoader: + .if $$defined(ENET_ENABLE_UPDATE) + .ref ConfigureEnet + bl ConfigureEnet + .elseif $$defined(CAN_ENABLE_UPDATE) + .ref ConfigureCAN + bl ConfigureCAN + .elseif $$defined(USB_ENABLE_UPDATE) + .ref ConfigureUSB + bl ConfigureUSB + .else + .ref ConfigureDevice + bl ConfigureDevice + .endif + + ;; + ;; Call the user-supplied initialization function if provided. + ;; + .if $$defined(BL_INIT_FN_HOOK) + .ref BL_INIT_FN_HOOK + bl BL_INIT_FN_HOOK + .endif + + ;; + ;; Branch to the update handler. + ;; + .if $$defined(ENET_ENABLE_UPDATE) + .ref UpdateBOOTP + b UpdateBOOTP + .elseif $$defined(CAN_ENABLE_UPDATE) + .ref UpdaterCAN + b UpdaterCAN + .elseif $$defined(USB_ENABLE_UPDATE) + .ref UpdaterUSB + b UpdaterUSB + .else + .ref Updater + b Updater + .endif + .endasmfunc + + ;; + ;; This is a second symbol to allow starting the application from the boot + ;; loader the linker may not like the perceived jump. + ;; + .global StartApplication + .thumbfunc StartApplication +StartApplication: + ;; + ;; Call the application via the reset handler in its vector table. Load + ;; the address of the application vector table. + ;; + .thumbfunc CallApplication +CallApplication: .asmfunc + ;; + ;; Copy the application's vector table to the target address if necessary. + ;; Note that incorrect boot loader configuration could cause this to + ;; corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start + ;; of SRAM) is safe since this will use the same memory that the boot loader + ;; already uses for its vector table. Great care will have to be taken if + ;; other addresses are to be used. + ;; + .if (APP_START_ADDRESS != VTABLE_START_ADDRESS) + movw r0, #(VTABLE_START_ADDRESS & 0xffff) + .if (VTABLE_START_ADDRESS > 0xffff) + movt r0, #(VTABLE_START_ADDRESS >> 16) + .endif + movw r1, #(APP_START_ADDRESS & 0xffff) + .if (APP_START_ADDRESS > 0xffff) + movt r1, #(APP_START_ADDRESS >> 16) + .endif + + ;; + ;; Calculate the end address of the vector table assuming that it has the + ;; maximum possible number of vectors. We don't know how many the app has + ;; populated so this is the safest approach though it may copy some non + ;; vector data if the app table is smaller than the maximum. + ;; + movw r2, #(70 * 4) + adds r2, r2, r0 +VectorCopyLoop: + ldr r3, [r1], #4 + str r3, [r0], #4 + cmp r0, r2 + blt VectorCopyLoop + .endif + + ;; + ;; Set the application's vector table start address. Typically this is the + ;; application start address but in some cases an application may relocate + ;; this so we can't assume that these two addresses are equal. + ;; + movw r0, #(VTABLE_START_ADDRESS & 0xffff) + .if (VTABLE_START_ADDRESS > 0xffff) + movt r0, #(VTABLE_START_ADDRESS >> 16) + .endif + movw r1, #(NVIC_VTABLE & 0xffff) + movt r1, #(NVIC_VTABLE >> 16) + str r0, [r1] + + ;; + ;; Load the stack pointer from the application's vector table. + ;; + .if (APP_START_ADDRESS != VTABLE_START_ADDRESS) + movw r0, #(APP_START_ADDRESS & 0xffff) + .if (APP_START_ADDRESS > 0xffff) + movt r0, #(APP_START_ADDRESS >> 16) + .endif + .endif + ldr sp, [r0] + + ;; + ;; Load the initial PC from the application's vector table and branch to + ;; the application's entry point. + ;; + ldr r0, [r0, #4] + bx r0 + .endasmfunc + +;;***************************************************************************** +;; +;; The update handler, which gets called when the application would like to +;; start an update. +;; +;;***************************************************************************** + .thumbfunc UpdateHandler +UpdateHandler: .asmfunc + ;; + ;; Initialize the processor. + ;; + bl ProcessorInit + + ;; + ;; Load the stack pointer from the vector table. + ;; + movs r0, #0x0000 + ldr sp, [r0] + + ;; + ;; Call the user-supplied low level hardware initialization function + ;; if provided. + ;; + .if $$defined(BL_HW_INIT_FN_HOOK) + bl BL_HW_INIT_FN_HOOK + .endif + + ;; + ;; Call the user-supplied re-initialization function if provided. + ;; + .if $$defined(BL_REINIT_FN_HOOK) + .ref BL_REINIT_FN_HOOK + bl BL_REINIT_FN_HOOK + .endif + + ;; + ;; Branch to the update handler. + ;; + .if $$defined(ENET_ENABLE_UPDATE) + b UpdateBOOTP + .elseif $$defined(CAN_ENABLE_UPDATE) + .ref AppUpdaterCAN + b AppUpdaterCAN + .elseif $$defined(USB_ENABLE_UPDATE) + .ref AppUpdaterUSB + b AppUpdaterUSB + .else + b Updater + .endif + .endasmfunc + +;;***************************************************************************** +;; +;; The NMI handler. +;; +;;***************************************************************************** + .thumbfunc NmiSR +NmiSR: .asmfunc + .if $$defined(ENABLE_MOSCFAIL_HANDLER) + ;; + ;; Grab the fault frame from the stack (the stack will be cleared by the + ;; processor initialization that follows). + ;; + ldm sp, {r4-r11} + mov r12, lr + + ;; + ;; Initialize the processor. + ;; + bl ProcessorInit + + ;; + ;; Restore the stack frame. + ;; + mov lr, r12 + stm sp, {r4-r11} + + ;; + ;; Save the link register. + ;; + mov r9, lr + + ;; + ;; Call the user-supplied low level hardware initialization function + ;; if provided. + ;; + .if $$defined(BL_HW_INIT_FN_HOOK) + bl BL_HW_INIT_FN_HOOK + .endif + + ;; + ;; See if an update should be performed. + ;; + bl CheckForceUpdate + cbz r0, EnterApplication + + ;; + ;; Clear the MOSCFAIL bit in RESC. + ;; + movw r0, #(SYSCTL_RESC & 0xffff) + movt r0, #(SYSCTL_RESC >> 16) + ldr r1, [r0] + bic r1, r1, #SYSCTL_RESC_MOSCFAIL + str r1, [r0] + + ;; + ;; Fix up the PC on the stack so that the boot pin check is bypassed + ;; (since it has already been performed). + ;; + ldr r0, =EnterBootLoader + bic r0, #0x00000001 + str r0, [sp, #0x18] + + ;; + ;; Return from the NMI handler. This will then start execution of the + ;; boot loader. + ;; + bx r9 + + ;; + ;; Restore the link register. + ;; +EnterApplication: + mov lr, r9 + + ;; + ;; Copy the application's vector table to the target address if necessary. + ;; Note that incorrect boot loader configuration could cause this to + ;; corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start + ;; of SRAM) is safe since this will use the same memory that the boot loader + ;; already uses for its vector table. Great care will have to be taken if + ;; other addresses are to be used. + ;; + .if (APP_START_ADDRESS != VTABLE_START_ADDRESS) + movw r0, #(VTABLE_START_ADDRESS & 0xffff) + .if (VTABLE_START_ADDRESS > 0xffff) + movt r0, #(VTABLE_START_ADDRESS >> 16) + .endif + movw r1, #(APP_START_ADDRESS & 0xffff) + .if (APP_START_ADDRESS > 0xffff) + movt r1, #(APP_START_ADDRESS >> 16) + .endif + + ;; + ;; Calculate the end address of the vector table assuming that it has the + ;; maximum possible number of vectors. We don't know how many the app has + ;; populated so this is the safest approach though it may copy some non + ;; vector data if the app table is smaller than the maximum. + ;; + movw r2, #(70 * 4) + adds r2, r2, r0 +VectorCopyLoop2: + ldr r3, [r1], #4 + str r3, [r0], #4 + cmp r0, r2 + blt VectorCopyLoop2 + .endif + + ;; + ;; Set the application's vector table start address. Typically this is the + ;; application start address but in some cases an application may relocate + ;; this so we can't assume that these two addresses are equal. + ;; + movw r0, #(VTABLE_START_ADDRESS & 0xffff) + .if (VTABLE_START_ADDRESS > 0xffff) + movt r0, #(VTABLE_START_ADDRESS >> 16) + .endif + movw r1, #(NVIC_VTABLE & 0xffff) + movt r1, #(NVIC_VTABLE >> 16) + str r0, [r1] + + ;; + ;; Remove the NMI stack frame from the boot loader's stack. + ;; + ldmia sp, {r4-r11} + + ;; + ;; Get the application's stack pointer. + ;; + .if (APP_START_ADDRESS != VTABLE_START_ADDRESS) + movw r0, #(APP_START_ADDRESS & 0xffff) + .if (APP_START_ADDRESS > 0xffff) + movt r0, #(APP_START_ADDRESS >> 16) + .endif + .endif + ldr sp, [r0, #0x00] + + ;; + ;; Fix up the NMI stack frame's return address to be the reset handler of + ;; the application. + ;; + ldr r10, [r0, #0x04] + bic r10, #0x00000001 + + ;; + ;; Store the NMI stack frame onto the application's stack. + ;; + stmdb sp!, {r4-r11} + + ;; + ;; Branch to the application's NMI handler. + ;; + ldr r0, [r0, #0x08] + bx r0 + .else + ;; + ;; Loop forever since there is nothing that we can do about a NMI. + ;; + b NmiSR + .endif + .endasmfunc + +;;***************************************************************************** +;; +;; The hard fault handler. +;; +;;***************************************************************************** + .thumbfunc FaultISR +FaultISR: .asmfunc + ;; + ;; Loop forever since there is nothing that we can do about a hard fault. + ;; + b FaultISR + .endasmfunc + +;;***************************************************************************** +;; +;; The default interrupt handler. +;; +;;***************************************************************************** + .thumbfunc IntDefaultHandler +IntDefaultHandler: .asmfunc + ;; + ;; Loop forever since there is nothing that we can do about an unexpected + ;; interrupt. + ;; + b IntDefaultHandler + .endasmfunc + +;;***************************************************************************** +;; +;; Provides a small delay. The loop below takes 3 cycles/loop. +;; +;;***************************************************************************** +; .globl Delay + .thumbfunc Delay +Delay: .asmfunc + subs r0, #1 + bne Delay + bx lr + .endasmfunc + + .thumbfunc _c_int00 + .global _c_int00 +_c_int00: .asmfunc + b ResetISR + +;;***************************************************************************** +;; +;; This is the end of the file. +;; +;;***************************************************************************** + .end diff --git a/boot_loader/bl_startup_ewarm.S b/boot_loader/bl_startup_ewarm.S new file mode 100644 index 0000000..2100b96 --- /dev/null +++ b/boot_loader/bl_startup_ewarm.S @@ -0,0 +1,612 @@ +//***************************************************************************** +// +// bl_startup_ewarm.S - Startup code for EWARM. +// +// Copyright (c) 2007-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 the assember definitions used to make this code compiler +// independent. +// +//***************************************************************************** +#include "inc/hw_nvic.h" +#include "inc/hw_sysctl.h" +#include "bl_config.h" + +//***************************************************************************** +// +// The stack gets placed into the zero-init section. +// +//***************************************************************************** + rseg .bss:DATA(2) + +//***************************************************************************** +// +// Allocate storage for the stack. +// +//***************************************************************************** + export g_pulStack +g_pulStack ds8 STACK_SIZE * 4 + +//***************************************************************************** +// +// This portion of the file goes into the vector section. +// +//***************************************************************************** + rseg INTVEC:CONST(2) + +//***************************************************************************** +// +// The minimal vector table for a Cortex-M3 processor. +// +//***************************************************************************** + export __vector_table +__vector_table + dcd g_pulStack + (STACK_SIZE * 4) // Offset 00: Initial stack pointer + dcd ResetISR - 0x20000000 // Offset 04: Reset handler + dcd NmiSR - 0x20000000 // Offset 08: NMI handler + dcd FaultISR - 0x20000000 // Offset 0C: Hard fault handler + dcd IntDefaultHandler // Offset 10: MPU fault handler + dcd IntDefaultHandler // Offset 14: Bus fault handler + dcd IntDefaultHandler // Offset 18: Usage fault handler + dcd 0 // Offset 1C: Reserved + dcd 0 // Offset 20: Reserved + dcd 0 // Offset 24: Reserved + dcd 0 // Offset 28: Reserved + dcd UpdateHandler - 0x20000000 // Offset 2C: SVCall handler + dcd IntDefaultHandler // Offset 30: Debug monitor handler + dcd 0 // Offset 34: Reserved + dcd IntDefaultHandler // Offset 38: PendSV handler +#if defined(ENET_ENABLE_UPDATE) + import SysTickIntHandler + dcd SysTickIntHandler // Offset 3C: SysTick handler +#else + dcd IntDefaultHandler // Offset 3C: SysTick handler +#endif +#if defined(UART_ENABLE_UPDATE) && defined(UART_AUTOBAUD) + import GPIOIntHandler + dcd GPIOIntHandler // Offset 40: GPIO port A handler +#else + dcd IntDefaultHandler // Offset 40: GPIO port A handler +#endif +#if (defined(USB_ENABLE_UPDATE) || \ + (APP_START_ADDRESS != VTABLE_START_ADDRESS)) + dcd IntDefaultHandler // Offset 44: GPIO Port B + dcd IntDefaultHandler // Offset 48: GPIO Port C + dcd IntDefaultHandler // Offset 4C: GPIO Port D + dcd IntDefaultHandler // Offset 50: GPIO Port E + dcd IntDefaultHandler // Offset 54: UART0 Rx and Tx + dcd IntDefaultHandler // Offset 58: UART1 Rx and Tx + dcd IntDefaultHandler // Offset 5C: SSI0 Rx and Tx + dcd IntDefaultHandler // Offset 60: I2C0 Master and Slave + dcd IntDefaultHandler // Offset 64: PWM Fault + dcd IntDefaultHandler // Offset 68: PWM Generator 0 + dcd IntDefaultHandler // Offset 6C: PWM Generator 1 + dcd IntDefaultHandler // Offset 70: PWM Generator 2 + dcd IntDefaultHandler // Offset 74: Quadrature Encoder 0 + dcd IntDefaultHandler // Offset 78: ADC Sequence 0 + dcd IntDefaultHandler // Offset 7C: ADC Sequence 1 + dcd IntDefaultHandler // Offset 80: ADC Sequence 2 + dcd IntDefaultHandler // Offset 84: ADC Sequence 3 + dcd IntDefaultHandler // Offset 88: Watchdog timer + dcd IntDefaultHandler // Offset 8C: Timer 0 subtimer A + dcd IntDefaultHandler // Offset 90: Timer 0 subtimer B + dcd IntDefaultHandler // Offset 94: Timer 1 subtimer A + dcd IntDefaultHandler // Offset 98: Timer 1 subtimer B + dcd IntDefaultHandler // Offset 9C: Timer 2 subtimer A + dcd IntDefaultHandler // Offset A0: Timer 2 subtimer B + dcd IntDefaultHandler // Offset A4: Analog Comparator 0 + dcd IntDefaultHandler // Offset A8: Analog Comparator 1 + dcd IntDefaultHandler // Offset AC: Analog Comparator 2 + dcd IntDefaultHandler // Offset B0: System Control + dcd IntDefaultHandler // Offset B4: FLASH Control +#endif +#if (defined(USB_ENABLE_UPDATE) || (APP_START_ADDRESS != VTABLE_START_ADDRESS)) + dcd IntDefaultHandler // Offset B8: GPIO Port F + dcd IntDefaultHandler // Offset BC: GPIO Port G + dcd IntDefaultHandler // Offset C0: GPIO Port H + dcd IntDefaultHandler // Offset C4: UART2 Rx and Tx + dcd IntDefaultHandler // Offset C8: SSI1 Rx and Tx + dcd IntDefaultHandler // Offset CC: Timer 3 subtimer A + dcd IntDefaultHandler // Offset D0: Timer 3 subtimer B + dcd IntDefaultHandler // Offset D4: I2C1 Master and Slave + dcd IntDefaultHandler // Offset D8: Quadrature Encoder 1 + dcd IntDefaultHandler // Offset DC: CAN0 + dcd IntDefaultHandler // Offset E0: CAN1 + dcd IntDefaultHandler // Offset E4: CAN2 + dcd IntDefaultHandler // Offset E8: Ethernet + dcd IntDefaultHandler // Offset EC: Hibernation module +#if defined(USB_ENABLE_UPDATE) + import USB0DeviceIntHandler + dcd USB0DeviceIntHandler // Offset F0: USB 0 Controller +#else + dcd IntDefaultHandler // Offset F0: USB 0 Controller +#endif +#endif + +//***************************************************************************** +// +// This portion of the file goes into the text section. +// +//***************************************************************************** + rseg CODE:CODE(2) + thumb + +//***************************************************************************** +// +// Initialize the processor by copying the boot loader from flash to SRAM, zero +// filling the .bss section, and moving the vector table to the beginning of +// SRAM. The return address is modified to point to the SRAM copy of the boot +// loader instead of the flash copy, resulting in a branch to the copy now in +// SRAM. +// +//***************************************************************************** +ProcessorInit + // + // Copy the code image from flash to SRAM. + // + movs r0, #0x0000 + movs r1, #0x0000 + movt r1, #0x2000 + ldr r2, =SFB(.bss) +copy_loop + ldr r3, [r0], #4 + str r3, [r1], #4 + cmp r1, r2 + blt copy_loop + + // + // Zero fill the .bss section. + // + movs r0, #0x0000 + ldr r2, =SFE(.bss) +zero_loop + str r0, [r1], #4 + cmp r1, r2 + blt zero_loop + + // + // Set the vector table pointer to the beginning of SRAM. + // + movw r0, #(NVIC_VTABLE & 0xffff) + movt r0, #(NVIC_VTABLE >> 16) + movs r1, #0x0000 + movt r1, #0x2000 + str r1, [r0] + + // + // Set the return address to the code just copied into SRAM. + // + orr lr, lr, #0x20000000 + + // + // Return to the caller. + // + bx lr + +//***************************************************************************** +// +// The reset handler, which gets called when the processor starts. +// +//***************************************************************************** + export ResetISR +ResetISR + // + // Enable the floating-point unit. This must be done here in case any + // later C functions use floating point. Note that some toolchains will + // use the FPU registers for general workspace even if no explicit floating + // point data types are in use. + // + movw r0, #0xED88 + movt r0, #0xE000 + ldr r1, [r0] + orr r1, r1, #0x00F00000 + str r1, [r0] + + // + // Initialize the processor. + // + bl ProcessorInit + + // + // Call the user-supplied low level hardware initialization function + // if provided. + // +#ifdef BL_HW_INIT_FN_HOOK + import BL_HW_INIT_FN_HOOK + bl BL_HW_INIT_FN_HOOK +#endif + + // + // See if an update should be performed. + // + import CheckForceUpdate + bl CheckForceUpdate + cbz r0, CallApplication + + // + // Configure the microcontroller. + // +EnterBootLoader +#ifdef ENET_ENABLE_UPDATE + import ConfigureEnet + bl ConfigureEnet +#elif defined(CAN_ENABLE_UPDATE) + import ConfigureCAN + bl ConfigureCAN +#elif defined(USB_ENABLE_UPDATE) + import ConfigureUSB + bl ConfigureUSB +#else + import ConfigureDevice + bl ConfigureDevice +#endif + + // + // Call the user-supplied initialization function if provided. + // +#ifdef BL_INIT_FN_HOOK + import BL_INIT_FN_HOOK + bl BL_INIT_FN_HOOK +#endif + + // + // Branch to the update handler. + // +#ifdef ENET_ENABLE_UPDATE + import UpdateBOOTP + b UpdateBOOTP +#elif defined(CAN_ENABLE_UPDATE) + import UpdaterCAN + b UpdaterCAN +#elif defined(USB_ENABLE_UPDATE) + import UpdaterUSB + b UpdaterUSB +#else + import Updater + b Updater +#endif + + // + // This is a second symbol to allow starting the application from the boot + // loader the linker may not like the perceived jump. + // + export StartApplication +StartApplication + // + // Call the application via the reset handler in its vector table. Load + // the address of the application's vector table first. + // +CallApplication + // + // Copy the application's vector table to the target address if necessary. + // Note that incorrect boot loader configuration could cause this to + // corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start + // of SRAM) is safe since this will use the same memory that the boot loader + // already uses for its vector table. Great care will have to be taken if + // other addresses are to be used. + // +#if (APP_START_ADDRESS != VTABLE_START_ADDRESS) + movw r0, #(VTABLE_START_ADDRESS & 0xffff) +#if (VTABLE_START_ADDRESS > 0xffff) + movt r0, #(VTABLE_START_ADDRESS >> 16) +#endif + movw r1, #(APP_START_ADDRESS & 0xffff) +#if (APP_START_ADDRESS > 0xffff) + movt r1, #(APP_START_ADDRESS >> 16) +#endif + + // + // Calculate the end address of the vector table assuming that it has the + // maximum possible number of vectors. We don't know how many the app has + // populated so this is the safest approach though it may copy some non + // vector data if the app table is smaller than the maximum. + // + movw r2, #(70 * 4) + adds r2, r2, r0 +VectorCopyLoop + ldr r3, [r1], #4 + str r3, [r0], #4 + cmp r0, r2 + blt VectorCopyLoop +#endif + + // + // Set the application's vector table start address. Typically this is the + // application start address but in some cases an application may relocate + // this so we can't assume that these two addresses are equal. + // + movw r0, #(VTABLE_START_ADDRESS & 0xffff) +#if (VTABLE_START_ADDRESS > 0xffff) + movt r0, #(VTABLE_START_ADDRESS >> 16) +#endif + movw r1, #(NVIC_VTABLE & 0xffff) + movt r1, #(NVIC_VTABLE >> 16) + str r0, [r1] + + // + // Load the stack pointer from the application's vector table at the + // beginning of the image. + // +#if (APP_START_ADDRESS != VTABLE_START_ADDRESS) + movw r0, #(APP_START_ADDRESS & 0xffff) +#if (APP_START_ADDRESS > 0xffff) + movt r0, #(APP_START_ADDRESS >> 16) +#endif +#endif + ldr sp, [r0] + + // + // Load the initial PC from the application's vector table and branch to + // the application's entry point. + // + ldr r0, [r0, #4] + bx r0 + +//***************************************************************************** +// +// The update handler, which gets called when the application would like to +// start an update. +// +//***************************************************************************** +UpdateHandler + // + // Initialize the processor. + // + bl ProcessorInit + + // + // Load the stack pointer from the vector table. + // + movs r0, #0x0000 + ldr sp, [r0] + + // + // Call the user-supplied low level hardware initialization function + // if provided. + // +#ifdef BL_HW_INIT_FN_HOOK + bl BL_HW_INIT_FN_HOOK +#endif + + // + // Call the user-supplied re-initialization function if provided. + // +#ifdef BL_REINIT_FN_HOOK + import BL_REINIT_FN_HOOK + bl BL_REINIT_FN_HOOK +#endif + + // + // Branch to the update handler. + // +#ifdef ENET_ENABLE_UPDATE + b UpdateBOOTP +#elif defined(CAN_ENABLE_UPDATE) + import AppUpdaterCAN + b AppUpdaterCAN +#elif defined(USB_ENABLE_UPDATE) + import AppUpdaterUSB + b AppUpdaterUSB +#else + b Updater +#endif + +//***************************************************************************** +// +// The NMI handler. +// +//***************************************************************************** +NmiSR +#ifdef ENABLE_MOSCFAIL_HANDLER + // + // Grab the fault frame from the stack (the stack will be cleared by the + // processor initialization that follows). + // + ldm sp, {r4-r11} + mov r12, lr + + // + // Initialize the processor. + // + bl ProcessorInit + + // + // Restore the stack frame. + // + mov lr, r12 + stm sp, {r4-r11} + + // + // Save the link register. + // + mov r9, lr + + // + // Call the user-supplied low level hardware initialization function + // if provided. + // +#ifdef BL_HW_INIT_FN_HOOK + bl BL_HW_INIT_FN_HOOK +#endif + + // + // See if an update should be performed. + // + bl CheckForceUpdate + cbz r0, EnterApplication + + // + // Clear the MOSCFAIL bit in RESC. + // + movw r0, #(SYSCTL_RESC & 0xffff) + movt r0, #(SYSCTL_RESC >> 16) + ldr r1, [r0] + bic r1, r1, #SYSCTL_RESC_MOSCFAIL + str r1, [r0] + + // + // Fix up the PC on the stack so that the boot pin check is bypassed + // (since it has already been performed). + // + ldr r0, =EnterBootLoader + bic r0, #0x00000001 + str r0, [sp, #0x18] + + // + // Return from the NMI handler. This will then start execution of the + // boot loader. + // + bx r9 + + // + // Restore the link register. + // +EnterApplication: + mov lr, r9 + + // + // Copy the application's vector table to the target address if necessary. + // Note that incorrect boot loader configuration could cause this to + // corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start + // of SRAM) is safe since this will use the same memory that the boot loader + // already uses for its vector table. Great care will have to be taken if + // other addresses are to be used. + // +#if (APP_START_ADDRESS != VTABLE_START_ADDRESS) + movw r0, #(VTABLE_START_ADDRESS & 0xffff) +#if (VTABLE_START_ADDRESS > 0xffff) + movt r0, #(VTABLE_START_ADDRESS >> 16) +#endif + movw r1, #(APP_START_ADDRESS & 0xffff) +#if (APP_START_ADDRESS > 0xffff) + movt r1, #(APP_START_ADDRESS >> 16) +#endif + + // + // Calculate the end address of the vector table assuming that it has the + // maximum possible number of vectors. We don't know how many the app has + // populated so this is the safest approach though it may copy some non + // vector data if the app table is smaller than the maximum. + // + movw r2, #(70 * 4) + adds r2, r2, r0 +VectorCopyLoop2: + ldr r3, [r1], #4 + str r3, [r0], #4 + cmp r0, r2 + blt VectorCopyLoop2 +#endif + + // + // Set the application's vector table start address. Typically this is the + // application start address but in some cases an application may relocate + // this so we can't assume that these two addresses are equal. + // + movw r0, #(VTABLE_START_ADDRESS & 0xffff) +#if (VTABLE_START_ADDRESS > 0xffff) + movt r0, #(VTABLE_START_ADDRESS >> 16) +#endif + movw r1, #(NVIC_VTABLE & 0xffff) + movt r1, #(NVIC_VTABLE >> 16) + str r0, [r1] + + // + // Remove the NMI stack frame from the boot loader's stack. + // + ldmia sp, {r4-r11} + + // + // Get the application's stack pointer. + // +#if (APP_START_ADDRESS != VTABLE_START_ADDRESS) + movw r0, #(APP_START_ADDRESS & 0xffff) +#if (APP_START_ADDRESS > 0xffff) + movt r0, #(APP_START_ADDRESS >> 16) +#endif +#endif + ldr sp, [r0, #0x00] + + // + // Fix up the NMI stack frame's return address to be the reset handler of + // the application. + // + ldr r10, [r0, #0x04] + bic r10, #0x00000001 + + // + // Store the NMI stack frame onto the application's stack. + // + stmdb sp!, {r4-r11} + + // + // Branch to the application's NMI handler. + // + ldr r0, [r0, #0x08] + bx r0 +#else + // + // Loop forever since there is nothing that we can do about a NMI. + // + b . +#endif + +//***************************************************************************** +// +// The hard fault handler. +// +//***************************************************************************** +FaultISR + // + // Loop forever since there is nothing that we can do about a hard fault. + // + b . + +//***************************************************************************** +// +// The default interrupt handler. +// +//***************************************************************************** +IntDefaultHandler + // + // Loop forever since there is nothing that we can do about an unexpected + // interrupt. + // + b . + +//***************************************************************************** +// +// Provides a small delay. The loop below takes 3 cycles/loop. +// +//***************************************************************************** + export Delay +Delay + subs r0, #1 + bne Delay + bx lr + +//***************************************************************************** +// +// This is the end of the file. +// +//***************************************************************************** + end diff --git a/boot_loader/bl_startup_gcc.S b/boot_loader/bl_startup_gcc.S new file mode 100644 index 0000000..53f28d1 --- /dev/null +++ b/boot_loader/bl_startup_gcc.S @@ -0,0 +1,630 @@ +//***************************************************************************** +// +// bl_startup_gcc.S - Startup code for GNU. +// +// Copyright (c) 2007-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 the assember definitions used to make this code compiler +// independent. +// +//***************************************************************************** +#include "inc/hw_nvic.h" +#include "inc/hw_sysctl.h" +#include "bl_config.h" + +//***************************************************************************** +// +// Put the assembler into the correct configuration. +// +//***************************************************************************** + .syntax unified + .thumb + +//***************************************************************************** +// +// The stack gets placed into the zero-init section. +// +//***************************************************************************** + .bss + +//***************************************************************************** +// +// Allocate storage for the stack. +// +//***************************************************************************** +g_pulStack: + .space STACK_SIZE * 4 + +//***************************************************************************** +// +// This portion of the file goes into the text section. +// +//***************************************************************************** + .section .isr_vector + +//***************************************************************************** +// +// The minimal vector table for a Cortex-M3 processor. +// +//***************************************************************************** +Vectors: + .word g_pulStack + (STACK_SIZE * 4) // Offset 00: Initial stack pointer + .word ResetISR - 0x20000000 // Offset 04: Reset handler + .word NmiSR - 0x20000000 // Offset 08: NMI handler + .word FaultISR - 0x20000000 // Offset 0C: Hard fault handler + .word IntDefaultHandler // Offset 10: MPU fault handler + .word IntDefaultHandler // Offset 14: Bus fault handler + .word IntDefaultHandler // Offset 18: Usage fault handler + .word 0 // Offset 1C: Reserved + .word 0 // Offset 20: Reserved + .word 0 // Offset 24: Reserved + .word 0 // Offset 28: Reserved + .word UpdateHandler - 0x20000000 // Offset 2C: SVCall handler + .word IntDefaultHandler // Offset 30: Debug monitor handler + .word 0 // Offset 34: Reserved + .word IntDefaultHandler // Offset 38: PendSV handler +#if defined(ENET_ENABLE_UPDATE) + .extern SysTickIntHandler + .word SysTickIntHandler // Offset 3C: SysTick handler +#else + .word IntDefaultHandler // Offset 3C: SysTick handler +#endif +#if defined(UART_ENABLE_UPDATE) && defined(UART_AUTOBAUD) + .extern GPIOIntHandler + .word GPIOIntHandler // Offset 40: GPIO port A handler +#else + .word IntDefaultHandler // Offset 40: GPIO port A handler +#endif +#if (defined(USB_ENABLE_UPDATE) || \ + (APP_START_ADDRESS != VTABLE_START_ADDRESS)) + .word IntDefaultHandler // Offset 44: GPIO Port B + .word IntDefaultHandler // Offset 48: GPIO Port C + .word IntDefaultHandler // Offset 4C: GPIO Port D + .word IntDefaultHandler // Offset 50: GPIO Port E + .word IntDefaultHandler // Offset 54: UART0 Rx and Tx + .word IntDefaultHandler // Offset 58: UART1 Rx and Tx + .word IntDefaultHandler // Offset 5C: SSI0 Rx and Tx + .word IntDefaultHandler // Offset 60: I2C0 Master and Slave + .word IntDefaultHandler // Offset 64: PWM Fault + .word IntDefaultHandler // Offset 68: PWM Generator 0 + .word IntDefaultHandler // Offset 6C: PWM Generator 1 + .word IntDefaultHandler // Offset 70: PWM Generator 2 + .word IntDefaultHandler // Offset 74: Quadrature Encoder 0 + .word IntDefaultHandler // Offset 78: ADC Sequence 0 + .word IntDefaultHandler // Offset 7C: ADC Sequence 1 + .word IntDefaultHandler // Offset 80: ADC Sequence 2 + .word IntDefaultHandler // Offset 84: ADC Sequence 3 + .word IntDefaultHandler // Offset 88: Watchdog timer + .word IntDefaultHandler // Offset 8C: Timer 0 subtimer A + .word IntDefaultHandler // Offset 90: Timer 0 subtimer B + .word IntDefaultHandler // Offset 94: Timer 1 subtimer A + .word IntDefaultHandler // Offset 98: Timer 1 subtimer B + .word IntDefaultHandler // Offset 9C: Timer 2 subtimer A + .word IntDefaultHandler // Offset A0: Timer 2 subtimer B + .word IntDefaultHandler // Offset A4: Analog Comparator 0 + .word IntDefaultHandler // Offset A8: Analog Comparator 1 + .word IntDefaultHandler // Offset AC: Analog Comparator 2 + .word IntDefaultHandler // Offset B0: System Control + .word IntDefaultHandler // Offset B4: FLASH Control +#endif +#if (defined(USB_ENABLE_UPDATE) || (APP_START_ADDRESS != VTABLE_START_ADDRESS)) + .word IntDefaultHandler // Offset B8: GPIO Port F + .word IntDefaultHandler // Offset BC: GPIO Port G + .word IntDefaultHandler // Offset C0: GPIO Port H + .word IntDefaultHandler // Offset C4: UART2 Rx and Tx + .word IntDefaultHandler // Offset C8: SSI1 Rx and Tx + .word IntDefaultHandler // Offset CC: Timer 3 subtimer A + .word IntDefaultHandler // Offset D0: Timer 3 subtimer B + .word IntDefaultHandler // Offset D4: I2C1 Master and Slave + .word IntDefaultHandler // Offset D8: Quadrature Encoder 1 + .word IntDefaultHandler // Offset DC: CAN0 + .word IntDefaultHandler // Offset E0: CAN1 + .word IntDefaultHandler // Offset E4: CAN2 + .word IntDefaultHandler // Offset E8: Ethernet + .word IntDefaultHandler // Offset EC: Hibernation module +#if defined(USB_ENABLE_UPDATE) + .extern USB0DeviceIntHandler + .word USB0DeviceIntHandler // Offset F0: USB 0 Controller +#else + .word IntDefaultHandler // Offset F0: USB 0 Controller +#endif +#endif + +//***************************************************************************** +// +// This portion of the file goes into the text section. +// +//***************************************************************************** + .text + +//***************************************************************************** +// +// Initialize the processor by copying the boot loader from flash to SRAM, zero +// filling the .bss section, and moving the vector table to the beginning of +// SRAM. The return address is modified to point to the SRAM copy of the boot +// loader instead of the flash copy, resulting in a branch to the copy now in +// SRAM. +// +//***************************************************************************** + .thumb_func +ProcessorInit: + // + // Copy the code image from flash to SRAM. + // + movs r0, #0x0000 + movs r1, #0x0000 + movt r1, #0x2000 + .extern _bss + ldr r2, =_bss +copy_loop: + ldr r3, [r0], #4 + str r3, [r1], #4 + cmp r1, r2 + blt copy_loop + + // + // Zero fill the .bss section. + // + movs r0, #0x0000 + .extern _ebss + ldr r2, =_ebss +zero_loop: + str r0, [r1], #4 + cmp r1, r2 + blt zero_loop + + // + // Set the vector table pointer to the beginning of SRAM. + // + movw r0, #(NVIC_VTABLE & 0xffff) + movt r0, #(NVIC_VTABLE >> 16) + movs r1, #0x0000 + movt r1, #0x2000 + str r1, [r0] + + // + // Set the return address to the code just copied into SRAM. + // + orr lr, lr, #0x20000000 + + // + // Return to the caller. + // + bx lr + +//***************************************************************************** +// +// The reset handler, which gets called when the processor starts. +// +//***************************************************************************** + .globl ResetISR + .thumb_func +ResetISR: + // + // Enable the floating-point unit. This must be done here in case any + // later C functions use floating point. Note that some toolchains will + // use the FPU registers for general workspace even if no explicit floating + // point data types are in use. + // + movw r0, #0xED88 + movt r0, #0xE000 + ldr r1, [r0] + orr r1, r1, #0x00F00000 + str r1, [r0] + + // + // Initialize the processor. + // + bl ProcessorInit + + // + // Call the user-supplied low level hardware initialization function + // if provided. + // +#ifdef BL_HW_INIT_FN_HOOK + .extern BL_HW_INIT_FN_HOOK + bl BL_HW_INIT_FN_HOOK +#endif + + // + // See if an update should be performed. + // + .extern CheckForceUpdate + bl CheckForceUpdate + cbz r0, CallApplication + + // + // Configure the microcontroller. + // + .thumb_func +EnterBootLoader: +#ifdef ENET_ENABLE_UPDATE + .extern ConfigureEnet + bl ConfigureEnet +#elif defined(CAN_ENABLE_UPDATE) + .extern ConfigureCAN + bl ConfigureCAN +#elif defined(USB_ENABLE_UPDATE) + .extern ConfigureUSB + bl ConfigureUSB +#else + .extern ConfigureDevice + bl ConfigureDevice +#endif + + // + // Call the user-supplied initialization function if provided. + // +#ifdef BL_INIT_FN_HOOK + .extern BL_INIT_FN_HOOK + bl BL_INIT_FN_HOOK +#endif + + // + // Branch to the update handler. + // +#ifdef ENET_ENABLE_UPDATE + .extern UpdateBOOTP + b UpdateBOOTP +#elif defined(CAN_ENABLE_UPDATE) + .extern UpdaterCAN + b UpdaterCAN +#elif defined(USB_ENABLE_UPDATE) + .extern UpdaterUSB + b UpdaterUSB +#else + .extern Updater + b Updater +#endif + + // + // This is a second symbol to allow starting the application from the boot + // loader the linker may not like the perceived jump. + // + .globl StartApplication + .thumb_func +StartApplication: + // + // Call the application via the reset handler in its vector table. Load + // the address of the application vector table. + // + .thumb_func +CallApplication: + // + // Copy the application's vector table to the target address if necessary. + // Note that incorrect boot loader configuration could cause this to + // corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start + // of SRAM) is safe since this will use the same memory that the boot loader + // already uses for its vector table. Great care will have to be taken if + // other addresses are to be used. + // +#if (APP_START_ADDRESS != VTABLE_START_ADDRESS) + movw r0, #(VTABLE_START_ADDRESS & 0xffff) +#if (VTABLE_START_ADDRESS > 0xffff) + movt r0, #(VTABLE_START_ADDRESS >> 16) +#endif + movw r1, #(APP_START_ADDRESS & 0xffff) +#if (APP_START_ADDRESS > 0xffff) + movt r1, #(APP_START_ADDRESS >> 16) +#endif + + // + // Calculate the end address of the vector table assuming that it has the + // maximum possible number of vectors. We don't know how many the app has + // populated so this is the safest approach though it may copy some non + // vector data if the app table is smaller than the maximum. + // + movw r2, #(70 * 4) + adds r2, r2, r0 +VectorCopyLoop: + ldr r3, [r1], #4 + str r3, [r0], #4 + cmp r0, r2 + blt VectorCopyLoop +#endif + + // + // Set the application's vector table start address. Typically this is the + // application start address but in some cases an application may relocate + // this so we can't assume that these two addresses are equal. + // + movw r0, #(VTABLE_START_ADDRESS & 0xffff) +#if (VTABLE_START_ADDRESS > 0xffff) + movt r0, #(VTABLE_START_ADDRESS >> 16) +#endif + movw r1, #(NVIC_VTABLE & 0xffff) + movt r1, #(NVIC_VTABLE >> 16) + str r0, [r1] + + // + // Load the stack pointer from the application's vector table. + // +#if (APP_START_ADDRESS != VTABLE_START_ADDRESS) + movw r0, #(APP_START_ADDRESS & 0xffff) +#if (APP_START_ADDRESS > 0xffff) + movt r0, #(APP_START_ADDRESS >> 16) +#endif +#endif + ldr sp, [r0] + + // + // Load the initial PC from the application's vector table and branch to + // the application's entry point. + // + ldr r0, [r0, #4] + bx r0 + +//***************************************************************************** +// +// The update handler, which gets called when the application would like to +// start an update. +// +//***************************************************************************** + .thumb_func +UpdateHandler: + // + // Initialize the processor. + // + bl ProcessorInit + + // + // Load the stack pointer from the vector table. + // + movs r0, #0x0000 + ldr sp, [r0] + + // + // Call the user-supplied low level hardware initialization function + // if provided. + // +#ifdef BL_HW_INIT_FN_HOOK + bl BL_HW_INIT_FN_HOOK +#endif + + // + // Call the user-supplied re-initialization function if provided. + // +#ifdef BL_REINIT_FN_HOOK + .extern BL_REINIT_FN_HOOK + bl BL_REINIT_FN_HOOK +#endif + + // + // Branch to the update handler. + // +#ifdef ENET_ENABLE_UPDATE + b UpdateBOOTP +#elif defined(CAN_ENABLE_UPDATE) + .extern AppUpdaterCAN + b AppUpdaterCAN +#elif defined(USB_ENABLE_UPDATE) + .extern AppUpdaterUSB + b AppUpdaterUSB +#else + b Updater +#endif + +//***************************************************************************** +// +// The NMI handler. +// +//***************************************************************************** + .thumb_func +NmiSR: +#ifdef ENABLE_MOSCFAIL_HANDLER + // + // Grab the fault frame from the stack (the stack will be cleared by the + // processor initialization that follows). + // + ldm sp, {r4-r11} + mov r12, lr + + // + // Initialize the processor. + // + bl ProcessorInit + + // + // Restore the stack frame. + // + mov lr, r12 + stm sp, {r4-r11} + + // + // Save the link register. + // + mov r9, lr + + // + // Call the user-supplied low level hardware initialization function + // if provided. + // +#ifdef BL_HW_INIT_FN_HOOK + bl BL_HW_INIT_FN_HOOK +#endif + + // + // See if an update should be performed. + // + bl CheckForceUpdate + cbz r0, EnterApplication + + // + // Clear the MOSCFAIL bit in RESC. + // + movw r0, #(SYSCTL_RESC & 0xffff) + movt r0, #(SYSCTL_RESC >> 16) + ldr r1, [r0] + bic r1, r1, #SYSCTL_RESC_MOSCFAIL + str r1, [r0] + + // + // Fix up the PC on the stack so that the boot pin check is bypassed + // (since it has already been performed). + // + ldr r0, =EnterBootLoader + bic r0, #0x00000001 + str r0, [sp, #0x18] + + // + // Return from the NMI handler. This will then start execution of the + // boot loader. + // + bx r9 + + // + // Restore the link register. + // + .thumb_func +EnterApplication: + mov lr, r9 + + // + // Copy the application's vector table to the target address if necessary. + // Note that incorrect boot loader configuration could cause this to + // corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start + // of SRAM) is safe since this will use the same memory that the boot loader + // already uses for its vector table. Great care will have to be taken if + // other addresses are to be used. + // +#if (APP_START_ADDRESS != VTABLE_START_ADDRESS) + movw r0, #(VTABLE_START_ADDRESS & 0xffff) +#if (VTABLE_START_ADDRESS > 0xffff) + movt r0, #(VTABLE_START_ADDRESS >> 16) +#endif + movw r1, #(APP_START_ADDRESS & 0xffff) +#if (APP_START_ADDRESS > 0xffff) + movt r1, #(APP_START_ADDRESS >> 16) +#endif + + // + // Calculate the end address of the vector table assuming that it has the + // maximum possible number of vectors. We don't know how many the app has + // populated so this is the safest approach though it may copy some non + // vector data if the app table is smaller than the maximum. + // + movw r2, #(70 * 4) + adds r2, r2, r0 +VectorCopyLoop2: + ldr r3, [r1], #4 + str r3, [r0], #4 + cmp r0, r2 + blt VectorCopyLoop2 +#endif + + // + // Set the application's vector table start address. Typically this is the + // application start address but in some cases an application may relocate + // this so we can't assume that these two addresses are equal. + // + movw r0, #(VTABLE_START_ADDRESS & 0xffff) +#if (VTABLE_START_ADDRESS > 0xffff) + movt r0, #(VTABLE_START_ADDRESS >> 16) +#endif + movw r1, #(NVIC_VTABLE & 0xffff) + movt r1, #(NVIC_VTABLE >> 16) + str r0, [r1] + + // + // Remove the NMI stack frame from the boot loader's stack. + // + ldmia sp, {r4-r11} + + // + // Get the application's stack pointer. + // +#if (APP_START_ADDRESS != VTABLE_START_ADDRESS) + movw r0, #(APP_START_ADDRESS & 0xffff) +#if (APP_START_ADDRESS > 0xffff) + movt r0, #(APP_START_ADDRESS >> 16) +#endif +#endif + ldr sp, [r0, #0x00] + + // + // Fix up the NMI stack frame's return address to be the reset handler of + // the application. + // + ldr r10, [r0, #0x04] + bic r10, #0x00000001 + + // + // Store the NMI stack frame onto the application's stack. + // + stmdb sp!, {r4-r11} + + // + // Branch to the application's NMI handler. + // + ldr r0, [r0, #0x08] + bx r0 +#else + // + // Loop forever since there is nothing that we can do about a NMI. + // + b . +#endif + +//***************************************************************************** +// +// The hard fault handler. +// +//***************************************************************************** + .thumb_func +FaultISR: + // + // Loop forever since there is nothing that we can do about a hard fault. + // + b . + +//***************************************************************************** +// +// The default interrupt handler. +// +//***************************************************************************** + .thumb_func +IntDefaultHandler: + // + // Loop forever since there is nothing that we can do about an unexpected + // interrupt. + // + b . + +//***************************************************************************** +// +// Provides a small delay. The loop below takes 3 cycles/loop. +// +//***************************************************************************** + .globl Delay + .thumb_func +Delay: + subs r0, #1 + bne Delay + bx lr + +//***************************************************************************** +// +// This is the end of the file. +// +//***************************************************************************** + .end diff --git a/boot_loader/bl_startup_rvmdk.S b/boot_loader/bl_startup_rvmdk.S new file mode 100644 index 0000000..435c325 --- /dev/null +++ b/boot_loader/bl_startup_rvmdk.S @@ -0,0 +1,653 @@ +;****************************************************************************** +; +; bl_startup_rvmdk.S - Startup code for RV-MDK. +; +; Copyright (c) 2007-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 bl_config.inc + +;****************************************************************************** +; +; A couple of defines that would normally be obtained from the appropriate C +; header file, but must be manually provided here since the Keil compiler does +; not have a mechanism for passing assembly source through the C preprocessor. +; +;****************************************************************************** +SYSCTL_RESC equ 0x400fe05c +SYSCTL_RESC_MOSCFAIL equ 0x00010000 +NVIC_VTABLE equ 0xe000ed08 + +;****************************************************************************** +; +; Put the assembler into the correct configuration. +; +;****************************************************************************** + thumb + require8 + preserve8 + +;****************************************************************************** +; +; The stack gets placed into the zero-init section. +; +;****************************************************************************** + area ||.bss||, noinit, align=2 + +;****************************************************************************** +; +; Allocate storage for the stack. +; +;****************************************************************************** +g_pulStack + space _STACK_SIZE * 4 + +;****************************************************************************** +; +; This portion of the file goes into the reset section. +; +;****************************************************************************** + area RESET, code, readonly, align=3 + +;****************************************************************************** +; +; The minimal vector table for a Cortex-M3 processor. +; +;****************************************************************************** + export __Vectors +__Vectors + dcd g_pulStack + (_STACK_SIZE * 4) ; Offset 00: Initial stack pointer + dcd Reset_Handler ; Offset 04: Reset handler + dcd NmiSR ; Offset 08: NMI handler + dcd FaultISR ; Offset 0C: Hard fault handler + dcd IntDefaultHandler ; Offset 10: MPU fault handler + dcd IntDefaultHandler ; Offset 14: Bus fault handler + dcd IntDefaultHandler ; Offset 18: Usage fault handler + dcd 0 ; Offset 1C: Reserved + dcd 0 ; Offset 20: Reserved + dcd 0 ; Offset 24: Reserved + dcd 0 ; Offset 28: Reserved + dcd UpdateHandler ; Offset 2C: SVCall handler + dcd IntDefaultHandler ; Offset 30: Debug monitor handler + dcd 0 ; Offset 34: Reserved + dcd IntDefaultHandler ; Offset 38: PendSV handler + if :def:_ENET_ENABLE_UPDATE + import SysTickIntHandler + dcd SysTickIntHandler ; Offset 3C: SysTick handler + else + dcd IntDefaultHandler ; Offset 3C: SysTick handler + endif + if :def:_UART_ENABLE_UPDATE :land: :def:_UART_AUTOBAUD + import GPIOIntHandler + dcd GPIOIntHandler ; Offset 40: GPIO port A handler + else + dcd IntDefaultHandler ; Offset 40: GPIO port A handler + endif + if :def:_USB_ENABLE_UPDATE :lor: \ + (_APP_START_ADDRESS != _VTABLE_START_ADDRESS) + dcd IntDefaultHandler ; Offset 44: GPIO Port B + dcd IntDefaultHandler ; Offset 48: GPIO Port C + dcd IntDefaultHandler ; Offset 4C: GPIO Port D + dcd IntDefaultHandler ; Offset 50: GPIO Port E + dcd IntDefaultHandler ; Offset 54: UART0 Rx and Tx + dcd IntDefaultHandler ; Offset 58: UART1 Rx and Tx + dcd IntDefaultHandler ; Offset 5C: SSI0 Rx and Tx + dcd IntDefaultHandler ; Offset 60: I2C0 Master and Slave + dcd IntDefaultHandler ; Offset 64: PWM Fault + dcd IntDefaultHandler ; Offset 68: PWM Generator 0 + dcd IntDefaultHandler ; Offset 6C: PWM Generator 1 + dcd IntDefaultHandler ; Offset 70: PWM Generator 2 + dcd IntDefaultHandler ; Offset 74: Quadrature Encoder 0 + dcd IntDefaultHandler ; Offset 78: ADC Sequence 0 + dcd IntDefaultHandler ; Offset 7C: ADC Sequence 1 + dcd IntDefaultHandler ; Offset 80: ADC Sequence 2 + dcd IntDefaultHandler ; Offset 84: ADC Sequence 3 + dcd IntDefaultHandler ; Offset 88: Watchdog timer + dcd IntDefaultHandler ; Offset 8C: Timer 0 subtimer A + dcd IntDefaultHandler ; Offset 90: Timer 0 subtimer B + dcd IntDefaultHandler ; Offset 94: Timer 1 subtimer A + dcd IntDefaultHandler ; Offset 98: Timer 1 subtimer B + dcd IntDefaultHandler ; Offset 9C: Timer 2 subtimer A + dcd IntDefaultHandler ; Offset A0: Timer 2 subtimer B + dcd IntDefaultHandler ; Offset A4: Analog Comparator 0 + dcd IntDefaultHandler ; Offset A8: Analog Comparator 1 + dcd IntDefaultHandler ; Offset AC: Analog Comparator 2 + dcd IntDefaultHandler ; Offset B0: System Control + dcd IntDefaultHandler ; Offset B4: FLASH Control + endif + if :def:_USB_ENABLE_UPDATE :lor: \ + (_APP_START_ADDRESS != _VTABLE_START_ADDRESS) + dcd IntDefaultHandler ; Offset B8: GPIO Port F + dcd IntDefaultHandler ; Offset BC: GPIO Port G + dcd IntDefaultHandler ; Offset C0: GPIO Port H + dcd IntDefaultHandler ; Offset C4: UART2 Rx and Tx + dcd IntDefaultHandler ; Offset C8: SSI1 Rx and Tx + dcd IntDefaultHandler ; Offset CC: Timer 3 subtimer A + dcd IntDefaultHandler ; Offset D0: Timer 3 subtimer B + dcd IntDefaultHandler ; Offset D4: I2C1 Master and Slave + dcd IntDefaultHandler ; Offset D8: Quadrature Encoder 1 + dcd IntDefaultHandler ; Offset DC: CAN0 + dcd IntDefaultHandler ; Offset E0: CAN1 + dcd IntDefaultHandler ; Offset E4: CAN2 + dcd IntDefaultHandler ; Offset E8: Ethernet + dcd IntDefaultHandler ; Offset EC: Hibernation module + if :def: _USB_ENABLE_UPDATE + import USB0DeviceIntHandler + dcd USB0DeviceIntHandler ; Offset F0: USB 0 Controller + else + dcd IntDefaultHandler ; Offset F0: USB 0 Controller + endif + endif + +;****************************************************************************** +; +; Initialize the processor by copying the boot loader from flash to SRAM, zero +; filling the .bss section, and moving the vector table to the beginning of +; SRAM. The return address is modified to point to the SRAM copy of the boot +; loader instead of the flash copy, resulting in a branch to the copy now in +; SRAM. +; +;****************************************************************************** + export ProcessorInit +ProcessorInit + ; + ; Copy the code image from flash to SRAM. + ; + movs r0, #0x0000 + movs r1, #0x0000 + movt r1, #0x2000 + import ||Image$$SRAM$$ZI$$Base|| + ldr r2, =||Image$$SRAM$$ZI$$Base|| +copy_loop + ldr r3, [r0], #4 + str r3, [r1], #4 + cmp r1, r2 + blt copy_loop + + ; + ; Zero fill the .bss section. + ; + movs r0, #0x0000 + import ||Image$$SRAM$$ZI$$Limit|| + ldr r2, =||Image$$SRAM$$ZI$$Limit|| +zero_loop + str r0, [r1], #4 + cmp r1, r2 + blt zero_loop + + ; + ; Set the vector table pointer to the beginning of SRAM. + ; + movw r0, #(NVIC_VTABLE & 0xffff) + movt r0, #(NVIC_VTABLE >> 16) + movs r1, #0x0000 + movt r1, #0x2000 + str r1, [r0] + + ; + ; Return to the caller. + ; + bx lr + +;****************************************************************************** +; +; The reset handler, which gets called when the processor starts. +; +;****************************************************************************** + export Reset_Handler +Reset_Handler + + ; + ; Enable the floating-point unit. This must be done here in case any + ; later C functions use floating point. Note that some toolchains will + ; use the FPU registers for general workspace even if no explicit floating + ; point data types are in use. + ; + movw r0, #0xED88 + movt r0, #0xE000 + ldr r1, [r0] + orr r1, #0x00F00000 + str r1, [r0] + + ; + ; Initialize the processor. + ; + bl ProcessorInit + + ; + ; Branch to the SRAM copy of the reset handler. + ; + ldr pc, =Reset_Handler_In_SRAM + +;****************************************************************************** +; +; The NMI handler. +; +;****************************************************************************** +NmiSR + if :def:_ENABLE_MOSCFAIL_HANDLER + ; + ; Grab the fault frame from the stack (the stack will be cleared by the + ; processor initialization that follows). + ; + ldm sp, {r4-r11} + mov r12, lr + + ; + ; Initialize the processor. + ; + bl ProcessorInit + + ; + ; Branch to the SRAM copy of the NMI handler. + ; + ldr pc, =NmiSR_In_SRAM + else + ; + ; Loop forever since there is nothing that we can do about a NMI. + ; + b . + endif + +;****************************************************************************** +; +; The hard fault handler. +; +;****************************************************************************** +FaultISR + ; + ; Loop forever since there is nothing that we can do about a hard fault. + ; + b . + +;****************************************************************************** +; +; The update handler, which gets called when the application would like to +; start an update. +; +;****************************************************************************** +UpdateHandler + ; + ; Initialize the processor. + ; + bl ProcessorInit + + ; + ; Branch to the SRAM copy of the update handler. + ; + ldr pc, =UpdateHandler_In_SRAM + +;****************************************************************************** +; +; This portion of the file goes into the text section. +; +;****************************************************************************** + align 4 + area ||.text||, code, readonly, align=2 + +Reset_Handler_In_SRAM + ; + ; Call the user-supplied low level hardware initialization function + ; if provided. + ; + if :def:_BL_HW_INIT_FN_HOOK + import $_BL_HW_INIT_FN_HOOK + bl $_BL_HW_INIT_FN_HOOK + endif + + ; + ; See if an update should be performed. + ; + import CheckForceUpdate + bl CheckForceUpdate + cbz r0, CallApplication + + ; + ; Configure the microcontroller. + ; +EnterBootLoader + if :def:_ENET_ENABLE_UPDATE + import ConfigureEnet + bl ConfigureEnet + elif :def:_CAN_ENABLE_UPDATE + import ConfigureCAN + bl ConfigureCAN + elif :def:_USB_ENABLE_UPDATE + import ConfigureUSB + bl ConfigureUSB + else + import ConfigureDevice + bl ConfigureDevice + endif + + ; + ; Call the user-supplied initialization function if provided. + ; + if :def:_BL_INIT_FN_HOOK + import $_BL_INIT_FN_HOOK + bl $_BL_INIT_FN_HOOK + endif + + ; + ; Branch to the update handler. + ; + if :def:_ENET_ENABLE_UPDATE + import UpdateBOOTP + b UpdateBOOTP + elif :def:_CAN_ENABLE_UPDATE + import UpdaterCAN + b UpdaterCAN + elif :def:_USB_ENABLE_UPDATE + import UpdaterUSB + b UpdaterUSB + else + import Updater + b Updater + endif + + ; + ; This is a second symbol to allow starting the application from the boot + ; loader the linker may not like the perceived jump. + ; + export StartApplication +StartApplication + ; + ; Call the application via the reset handler in its vector table. Load the + ; address of the application vector table. + ; +CallApplication + ; + ; Copy the application's vector table to the target address if necessary. + ; Note that incorrect boot loader configuration could cause this to + ; corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start + ; of SRAM) is safe since this will use the same memory that the boot loader + ; already uses for its vector table. Great care will have to be taken if + ; other addresses are to be used. + ; + if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS) + movw r0, #(_VTABLE_START_ADDRESS & 0xffff) + if (_VTABLE_START_ADDRESS > 0xffff) + movt r0, #(_VTABLE_START_ADDRESS >> 16) + endif + movw r1, #(_APP_START_ADDRESS & 0xffff) + if (_APP_START_ADDRESS > 0xffff) + movt r1, #(_APP_START_ADDRESS >> 16) + endif + + ; + ; Calculate the end address of the vector table assuming that it has the + ; maximum possible number of vectors. We don't know how many the app has + ; populated so this is the safest approach though it may copy some non + ; vector data if the app table is smaller than the maximum. + ; + movw r2, #(70 * 4) + adds r2, r2, r0 +VectorCopyLoop + ldr r3, [r1], #4 + str r3, [r0], #4 + cmp r0, r2 + blt VectorCopyLoop + endif + + ; + ; Set the vector table address to the beginning of the application. + ; + movw r0, #(_VTABLE_START_ADDRESS & 0xffff) + if (_VTABLE_START_ADDRESS > 0xffff) + movt r0, #(_VTABLE_START_ADDRESS >> 16) + endif + movw r1, #(NVIC_VTABLE & 0xffff) + movt r1, #(NVIC_VTABLE >> 16) + str r0, [r1] + + ; + ; Load the stack pointer from the application's vector table. + ; + if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS) + movw r0, #(_APP_START_ADDRESS & 0xffff) + if (_APP_START_ADDRESS > 0xffff) + movt r0, #(_APP_START_ADDRESS >> 16) + endif + endif + ldr sp, [r0] + + ; + ; Load the initial PC from the application's vector table and branch to + ; the application's entry point. + ; + ldr r0, [r0, #4] + bx r0 + +;****************************************************************************** +; +; The update handler, which gets called when the application would like to +; start an update. +; +;****************************************************************************** +UpdateHandler_In_SRAM + ; + ; Load the stack pointer from the vector table. + ; + movs r0, #0x0000 + ldr sp, [r0] + + ; + ; Call the user-supplied low level hardware initialization function + ; if provided. + ; + if :def:_BL_HW_INIT_FN_HOOK + bl $_BL_HW_INIT_FN_HOOK + endif + + ; + ; Call the user-supplied re-initialization function if provided. + ; + if :def:_BL_REINIT_FN_HOOK + import $_BL_REINIT_FN_HOOK + bl $_BL_REINIT_FN_HOOK + endif + + ; + ; Branch to the update handler. + ; + if :def:_ENET_ENABLE_UPDATE + b UpdateBOOTP + elif :def:_CAN_ENABLE_UPDATE + import AppUpdaterCAN + b AppUpdaterCAN + elif :def:_USB_ENABLE_UPDATE + import AppUpdaterUSB + b AppUpdaterUSB + else + b Updater + endif + +;****************************************************************************** +; +; The NMI handler. +; +;****************************************************************************** + if :def:_ENABLE_MOSCFAIL_HANDLER +NmiSR_In_SRAM + ; + ; Restore the stack frame. + ; + mov lr, r12 + stm sp, {r4-r11} + + ; + ; Save the link register. + ; + mov r9, lr + + ; + ; Call the user-supplied low level hardware initialization function + ; if provided. + ; + if :def:_BL_HW_INIT_FN_HOOK + bl _BL_HW_INIT_FN_HOOK + endif + + ; + ; See if an update should be performed. + ; + bl CheckForceUpdate + cbz r0, EnterApplication + + ; + ; Clear the MOSCFAIL bit in RESC. + ; + movw r0, #(SYSCTL_RESC & 0xffff) + movt r0, #(SYSCTL_RESC >> 16) + ldr r1, [r0] + bic r1, r1, #SYSCTL_RESC_MOSCFAIL + str r1, [r0] + + ; + ; Fix up the PC on the stack so that the boot pin check is bypassed + ; (since it has already been performed). + ; + ldr r0, =EnterBootLoader + bic r0, #0x00000001 + str r0, [sp, #0x18] + + ; + ; Return from the NMI handler. This will then start execution of the + ; boot loader. + ; + bx r9 + + ; + ; Restore the link register. + ; +EnterApplication + mov lr, r9 + + ; + ; Copy the application's vector table to the target address if necessary. + ; Note that incorrect boot loader configuration could cause this to + ; corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start + ; of SRAM) is safe since this will use the same memory that the boot loader + ; already uses for its vector table. Great care will have to be taken if + ; other addresses are to be used. + ; + if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS) + movw r0, #(_VTABLE_START_ADDRESS & 0xffff) + if (_VTABLE_START_ADDRESS > 0xffff) + movt r0, #(_VTABLE_START_ADDRESS >> 16) + endif + movw r1, #(_APP_START_ADDRESS & 0xffff) + if (_APP_START_ADDRESS > 0xffff) + movt r1, #(_APP_START_ADDRESS >> 16) + endif + + ; + ; Calculate the end address of the vector table assuming that it has the + ; maximum possible number of vectors. We don't know how many the app has + ; populated so this is the safest approach though it may copy some non + ; vector data if the app table is smaller than the maximum. + ; + movw r2, #(70 * 4) + adds r2, r2, r0 +VectorCopyLoop2 + ldr r3, [r1], #4 + str r3, [r0], #4 + cmp r0, r2 + blt VectorCopyLoop2 + endif + + ; + ; Set the application's vector table start address. Typically this is the + ; application start address but in some cases an application may relocate + ; this so we can't assume that these two addresses are equal. + ; + movw r0, #(_VTABLE_START_ADDRESS & 0xffff) + if (_VTABLE_START_ADDRESS > 0xffff) + movt r0, #(_VTABLE_START_ADDRESS >> 16) + endif + movw r1, #(NVIC_VTABLE & 0xffff) + movt r1, #(NVIC_VTABLE >> 16) + str r0, [r1] + + ; + ; Remove the NMI stack frame from the boot loader's stack. + ; + ldmia sp, {r4-r11} + + ; + ; Get the application's stack pointer. + ; + if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS) + movw r0, #(_APP_START_ADDRESS & 0xffff) + if (_APP_START_ADDRESS > 0xffff) + movt r0, #(_APP_START_ADDRESS >> 16) + endif + endif + ldr sp, [r0, #0x00] + + ; + ; Fix up the NMI stack frame's return address to be the reset handler of + ; the application. + ; + ldr r10, [r0, #0x04] + bic r10, #0x00000001 + + ; + ; Store the NMI stack frame onto the application's stack. + ; + stmdb sp!, {r4-r11} + + ; + ; Branch to the application's NMI handler. + ; + ldr r0, [r0, #0x08] + bx r0 + endif + +;****************************************************************************** +; +; The default interrupt handler. +; +;****************************************************************************** +IntDefaultHandler + ; + ; Loop forever since there is nothing that we can do about an unexpected + ; interrupt. + ; + b . + +;****************************************************************************** +; +; Provides a small delay. The loop below takes 3 cycles/loop. +; +;****************************************************************************** + export Delay +Delay + subs r0, #1 + bne Delay + bx lr + +;****************************************************************************** +; +; This is the end of the file. +; +;****************************************************************************** + align 4 + end diff --git a/boot_loader/bl_startup_sourcerygxx.S b/boot_loader/bl_startup_sourcerygxx.S new file mode 100644 index 0000000..ded9231 --- /dev/null +++ b/boot_loader/bl_startup_sourcerygxx.S @@ -0,0 +1,630 @@ +//***************************************************************************** +// +// bl_startup_sourcerygxx.S - Startup code for Sourcery G++. +// +// Copyright (c) 2007-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 the assember definitions used to make this code compiler +// independent. +// +//***************************************************************************** +#include "inc/hw_nvic.h" +#include "inc/hw_sysctl.h" +#include "bl_config.h" + +//***************************************************************************** +// +// Put the assembler into the correct configuration. +// +//***************************************************************************** + .syntax unified + .thumb + +//***************************************************************************** +// +// The stack gets placed into the zero-init section. +// +//***************************************************************************** + .bss + +//***************************************************************************** +// +// Allocate storage for the stack. +// +//***************************************************************************** +g_pulStack: + .space STACK_SIZE * 4 + +//***************************************************************************** +// +// This portion of the file goes into the text section. +// +//***************************************************************************** + .section .isr_vector + +//***************************************************************************** +// +// The minimal vector table for a Cortex-M3 processor. +// +//***************************************************************************** +Vectors: + .word g_pulStack + (STACK_SIZE * 4) // Offset 00: Initial stack pointer + .word ResetISR - 0x20000000 // Offset 04: Reset handler + .word NmiSR - 0x20000000 // Offset 08: NMI handler + .word FaultISR - 0x20000000 // Offset 0C: Hard fault handler + .word IntDefaultHandler // Offset 10: MPU fault handler + .word IntDefaultHandler // Offset 14: Bus fault handler + .word IntDefaultHandler // Offset 18: Usage fault handler + .word 0 // Offset 1C: Reserved + .word 0 // Offset 20: Reserved + .word 0 // Offset 24: Reserved + .word 0 // Offset 28: Reserved + .word UpdateHandler - 0x20000000 // Offset 2C: SVCall handler + .word IntDefaultHandler // Offset 30: Debug monitor handler + .word 0 // Offset 34: Reserved + .word IntDefaultHandler // Offset 38: PendSV handler +#if defined(ENET_ENABLE_UPDATE) + .extern SysTickIntHandler + .word SysTickIntHandler // Offset 3C: SysTick handler +#else + .word IntDefaultHandler // Offset 3C: SysTick handler +#endif +#if defined(UART_ENABLE_UPDATE) && defined(UART_AUTOBAUD) + .extern GPIOIntHandler + .word GPIOIntHandler // Offset 40: GPIO port A handler +#else + .word IntDefaultHandler // Offset 40: GPIO port A handler +#endif +#if (defined(USB_ENABLE_UPDATE) || \ + (APP_START_ADDRESS != VTABLE_START_ADDRESS)) + .word IntDefaultHandler // Offset 44: GPIO Port B + .word IntDefaultHandler // Offset 48: GPIO Port C + .word IntDefaultHandler // Offset 4C: GPIO Port D + .word IntDefaultHandler // Offset 50: GPIO Port E + .word IntDefaultHandler // Offset 54: UART0 Rx and Tx + .word IntDefaultHandler // Offset 58: UART1 Rx and Tx + .word IntDefaultHandler // Offset 5C: SSI0 Rx and Tx + .word IntDefaultHandler // Offset 60: I2C0 Master and Slave + .word IntDefaultHandler // Offset 64: PWM Fault + .word IntDefaultHandler // Offset 68: PWM Generator 0 + .word IntDefaultHandler // Offset 6C: PWM Generator 1 + .word IntDefaultHandler // Offset 70: PWM Generator 2 + .word IntDefaultHandler // Offset 74: Quadrature Encoder 0 + .word IntDefaultHandler // Offset 78: ADC Sequence 0 + .word IntDefaultHandler // Offset 7C: ADC Sequence 1 + .word IntDefaultHandler // Offset 80: ADC Sequence 2 + .word IntDefaultHandler // Offset 84: ADC Sequence 3 + .word IntDefaultHandler // Offset 88: Watchdog timer + .word IntDefaultHandler // Offset 8C: Timer 0 subtimer A + .word IntDefaultHandler // Offset 90: Timer 0 subtimer B + .word IntDefaultHandler // Offset 94: Timer 1 subtimer A + .word IntDefaultHandler // Offset 98: Timer 1 subtimer B + .word IntDefaultHandler // Offset 9C: Timer 2 subtimer A + .word IntDefaultHandler // Offset A0: Timer 2 subtimer B + .word IntDefaultHandler // Offset A4: Analog Comparator 0 + .word IntDefaultHandler // Offset A8: Analog Comparator 1 + .word IntDefaultHandler // Offset AC: Analog Comparator 2 + .word IntDefaultHandler // Offset B0: System Control + .word IntDefaultHandler // Offset B4: FLASH Control +#endif +#if (defined(USB_ENABLE_UPDATE) || (APP_START_ADDRESS != VTABLE_START_ADDRESS)) + .word IntDefaultHandler // Offset B8: GPIO Port F + .word IntDefaultHandler // Offset BC: GPIO Port G + .word IntDefaultHandler // Offset C0: GPIO Port H + .word IntDefaultHandler // Offset C4: UART2 Rx and Tx + .word IntDefaultHandler // Offset C8: SSI1 Rx and Tx + .word IntDefaultHandler // Offset CC: Timer 3 subtimer A + .word IntDefaultHandler // Offset D0: Timer 3 subtimer B + .word IntDefaultHandler // Offset D4: I2C1 Master and Slave + .word IntDefaultHandler // Offset D8: Quadrature Encoder 1 + .word IntDefaultHandler // Offset DC: CAN0 + .word IntDefaultHandler // Offset E0: CAN1 + .word IntDefaultHandler // Offset E4: CAN2 + .word IntDefaultHandler // Offset E8: Ethernet + .word IntDefaultHandler // Offset EC: Hibernation module +#if defined(USB_ENABLE_UPDATE) + .extern USB0DeviceIntHandler + .word USB0DeviceIntHandler // Offset F0: USB 0 Controller +#else + .word IntDefaultHandler // Offset F0: USB 0 Controller +#endif +#endif + +//***************************************************************************** +// +// This portion of the file goes into the text section. +// +//***************************************************************************** + .text + +//***************************************************************************** +// +// Initialize the processor by copying the boot loader from flash to SRAM, zero +// filling the .bss section, and moving the vector table to the beginning of +// SRAM. The return address is modified to point to the SRAM copy of the boot +// loader instead of the flash copy, resulting in a branch to the copy now in +// SRAM. +// +//***************************************************************************** + .thumb_func +ProcessorInit: + // + // Copy the code image from flash to SRAM. + // + movs r0, #0x0000 + movs r1, #0x0000 + movt r1, #0x2000 + .extern _bss + ldr r2, =_bss +copy_loop: + ldr r3, [r0], #4 + str r3, [r1], #4 + cmp r1, r2 + blt copy_loop + + // + // Zero fill the .bss section. + // + movs r0, #0x0000 + .extern _ebss + ldr r2, =_ebss +zero_loop: + str r0, [r1], #4 + cmp r1, r2 + blt zero_loop + + // + // Set the vector table pointer to the beginning of SRAM. + // + movw r0, #(NVIC_VTABLE & 0xffff) + movt r0, #(NVIC_VTABLE >> 16) + movs r1, #0x0000 + movt r1, #0x2000 + str r1, [r0] + + // + // Set the return address to the code just copied into SRAM. + // + orr lr, lr, #0x20000000 + + // + // Return to the caller. + // + bx lr + +//***************************************************************************** +// +// The reset handler, which gets called when the processor starts. +// +//***************************************************************************** + .globl ResetISR + .thumb_func +ResetISR: + // + // Enable the floating-point unit. This must be done here in case any + // later C functions use floating point. Note that some toolchains will + // use the FPU registers for general workspace even if no explicit floating + // point data types are in use. + // + movw r0, #0xED88 + movt r0, #0xE000 + ldr r1, [r0] + orr r1, r1, #0x00F00000 + str r1, [r0] + + // + // Initialize the processor. + // + bl ProcessorInit + + // + // Call the user-supplied low level hardware initialization function + // if provided. + // +#ifdef BL_HW_INIT_FN_HOOK + .extern BL_HW_INIT_FN_HOOK + bl BL_HW_INIT_FN_HOOK +#endif + + // + // See if an update should be performed. + // + .extern CheckForceUpdate + bl CheckForceUpdate + cbz r0, CallApplication + + // + // Configure the microcontroller. + // + .thumb_func +EnterBootLoader: +#ifdef ENET_ENABLE_UPDATE + .extern ConfigureEnet + bl ConfigureEnet +#elif defined(CAN_ENABLE_UPDATE) + .extern ConfigureCAN + bl ConfigureCAN +#elif defined(USB_ENABLE_UPDATE) + .extern ConfigureUSB + bl ConfigureUSB +#else + .extern ConfigureDevice + bl ConfigureDevice +#endif + + // + // Call the user-supplied initialization function if provided. + // +#ifdef BL_INIT_FN_HOOK + .extern BL_INIT_FN_HOOK + bl BL_INIT_FN_HOOK +#endif + + // + // Branch to the update handler. + // +#ifdef ENET_ENABLE_UPDATE + .extern UpdateBOOTP + b UpdateBOOTP +#elif defined(CAN_ENABLE_UPDATE) + .extern UpdaterCAN + b UpdaterCAN +#elif defined(USB_ENABLE_UPDATE) + .extern UpdaterUSB + b UpdaterUSB +#else + .extern Updater + b Updater +#endif + + // + // This is a second symbol to allow starting the application from the boot + // loader the linker may not like the perceived jump. + // + .globl StartApplication + .thumb_func +StartApplication: + // + // Call the application via the reset handler in its vector table. Load + // the address of the application vector table. + // + .thumb_func +CallApplication: + // + // Copy the application's vector table to the target address if necessary. + // Note that incorrect boot loader configuration could cause this to + // corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start + // of SRAM) is safe since this will use the same memory that the boot loader + // already uses for its vector table. Great care will have to be taken if + // other addresses are to be used. + // +#if (APP_START_ADDRESS != VTABLE_START_ADDRESS) + movw r0, #(VTABLE_START_ADDRESS & 0xffff) +#if (VTABLE_START_ADDRESS > 0xffff) + movt r0, #(VTABLE_START_ADDRESS >> 16) +#endif + movw r1, #(APP_START_ADDRESS & 0xffff) +#if (APP_START_ADDRESS > 0xffff) + movt r1, #(APP_START_ADDRESS >> 16) +#endif + + // + // Calculate the end address of the vector table assuming that it has the + // maximum possible number of vectors. We don't know how many the app has + // populated so this is the safest approach though it may copy some non + // vector data if the app table is smaller than the maximum. + // + movw r2, #(70 * 4) + adds r2, r2, r0 +VectorCopyLoop: + ldr r3, [r1], #4 + str r3, [r0], #4 + cmp r0, r2 + blt VectorCopyLoop +#endif + + // + // Set the application's vector table start address. Typically this is the + // application start address but in some cases an application may relocate + // this so we can't assume that these two addresses are equal. + // + movw r0, #(VTABLE_START_ADDRESS & 0xffff) +#if (VTABLE_START_ADDRESS > 0xffff) + movt r0, #(VTABLE_START_ADDRESS >> 16) +#endif + movw r1, #(NVIC_VTABLE & 0xffff) + movt r1, #(NVIC_VTABLE >> 16) + str r0, [r1] + + // + // Load the stack pointer from the application's vector table. + // +#if (APP_START_ADDRESS != VTABLE_START_ADDRESS) + movw r0, #(APP_START_ADDRESS & 0xffff) +#if (APP_START_ADDRESS > 0xffff) + movt r0, #(APP_START_ADDRESS >> 16) +#endif +#endif + ldr sp, [r0] + + // + // Load the initial PC from the application's vector table and branch to + // the application's entry point. + // + ldr r0, [r0, #4] + bx r0 + +//***************************************************************************** +// +// The update handler, which gets called when the application would like to +// start an update. +// +//***************************************************************************** + .thumb_func +UpdateHandler: + // + // Initialize the processor. + // + bl ProcessorInit + + // + // Load the stack pointer from the vector table. + // + movs r0, #0x0000 + ldr sp, [r0] + + // + // Call the user-supplied low level hardware initialization function + // if provided. + // +#ifdef BL_HW_INIT_FN_HOOK + bl BL_HW_INIT_FN_HOOK +#endif + + // + // Call the user-supplied re-initialization function if provided. + // +#ifdef BL_REINIT_FN_HOOK + .extern BL_REINIT_FN_HOOK + bl BL_REINIT_FN_HOOK +#endif + + // + // Branch to the update handler. + // +#ifdef ENET_ENABLE_UPDATE + b UpdateBOOTP +#elif defined(CAN_ENABLE_UPDATE) + .extern AppUpdaterCAN + b AppUpdaterCAN +#elif defined(USB_ENABLE_UPDATE) + .extern AppUpdaterUSB + b AppUpdaterUSB +#else + b Updater +#endif + +//***************************************************************************** +// +// The NMI handler. +// +//***************************************************************************** + .thumb_func +NmiSR: +#ifdef ENABLE_MOSCFAIL_HANDLER + // + // Grab the fault frame from the stack (the stack will be cleared by the + // processor initialization that follows). + // + ldm sp, {r4-r11} + mov r12, lr + + // + // Initialize the processor. + // + bl ProcessorInit + + // + // Restore the stack frame. + // + mov lr, r12 + stm sp, {r4-r11} + + // + // Save the link register. + // + mov r9, lr + + // + // Call the user-supplied low level hardware initialization function + // if provided. + // +#ifdef BL_HW_INIT_FN_HOOK + bl BL_HW_INIT_FN_HOOK +#endif + + // + // See if an update should be performed. + // + bl CheckForceUpdate + cbz r0, EnterApplication + + // + // Clear the MOSCFAIL bit in RESC. + // + movw r0, #(SYSCTL_RESC & 0xffff) + movt r0, #(SYSCTL_RESC >> 16) + ldr r1, [r0] + bic r1, r1, #SYSCTL_RESC_MOSCFAIL + str r1, [r0] + + // + // Fix up the PC on the stack so that the boot pin check is bypassed + // (since it has already been performed). + // + ldr r0, =EnterBootLoader + bic r0, #0x00000001 + str r0, [sp, #0x18] + + // + // Return from the NMI handler. This will then start execution of the + // boot loader. + // + bx r9 + + // + // Restore the link register. + // + .thumb_func +EnterApplication: + mov lr, r9 + + // + // Copy the application's vector table to the target address if necessary. + // Note that incorrect boot loader configuration could cause this to + // corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start + // of SRAM) is safe since this will use the same memory that the boot loader + // already uses for its vector table. Great care will have to be taken if + // other addresses are to be used. + // +#if (APP_START_ADDRESS != VTABLE_START_ADDRESS) + movw r0, #(VTABLE_START_ADDRESS & 0xffff) +#if (VTABLE_START_ADDRESS > 0xffff) + movt r0, #(VTABLE_START_ADDRESS >> 16) +#endif + movw r1, #(APP_START_ADDRESS & 0xffff) +#if (APP_START_ADDRESS > 0xffff) + movt r1, #(APP_START_ADDRESS >> 16) +#endif + + // + // Calculate the end address of the vector table assuming that it has the + // maximum possible number of vectors. We don't know how many the app has + // populated so this is the safest approach though it may copy some non + // vector data if the app table is smaller than the maximum. + // + movw r2, #(70 * 4) + adds r2, r2, r0 +VectorCopyLoop2: + ldr r3, [r1], #4 + str r3, [r0], #4 + cmp r0, r2 + blt VectorCopyLoop2 +#endif + + // + // Set the application's vector table start address. Typically this is the + // application start address but in some cases an application may relocate + // this so we can't assume that these two addresses are equal. + // + movw r0, #(VTABLE_START_ADDRESS & 0xffff) +#if (VTABLE_START_ADDRESS > 0xffff) + movt r0, #(VTABLE_START_ADDRESS >> 16) +#endif + movw r1, #(NVIC_VTABLE & 0xffff) + movt r1, #(NVIC_VTABLE >> 16) + str r0, [r1] + + // + // Remove the NMI stack frame from the boot loader's stack. + // + ldmia sp, {r4-r11} + + // + // Get the application's stack pointer. + // +#if (APP_START_ADDRESS != VTABLE_START_ADDRESS) + movw r0, #(APP_START_ADDRESS & 0xffff) +#if (APP_START_ADDRESS > 0xffff) + movt r0, #(APP_START_ADDRESS >> 16) +#endif +#endif + ldr sp, [r0, #0x00] + + // + // Fix up the NMI stack frame's return address to be the reset handler of + // the application. + // + ldr r10, [r0, #0x04] + bic r10, #0x00000001 + + // + // Store the NMI stack frame onto the application's stack. + // + stmdb sp!, {r4-r11} + + // + // Branch to the application's NMI handler. + // + ldr r0, [r0, #0x08] + bx r0 +#else + // + // Loop forever since there is nothing that we can do about a NMI. + // + b . +#endif + +//***************************************************************************** +// +// The hard fault handler. +// +//***************************************************************************** + .thumb_func +FaultISR: + // + // Loop forever since there is nothing that we can do about a hard fault. + // + b . + +//***************************************************************************** +// +// The default interrupt handler. +// +//***************************************************************************** + .thumb_func +IntDefaultHandler: + // + // Loop forever since there is nothing that we can do about an unexpected + // interrupt. + // + b . + +//***************************************************************************** +// +// Provides a small delay. The loop below takes 3 cycles/loop. +// +//***************************************************************************** + .globl Delay + .thumb_func +Delay: + subs r0, #1 + bne Delay + bx lr + +//***************************************************************************** +// +// This is the end of the file. +// +//***************************************************************************** + .end diff --git a/boot_loader/bl_uart.c b/boot_loader/bl_uart.c new file mode 100644 index 0000000..71df5c3 --- /dev/null +++ b/boot_loader/bl_uart.c @@ -0,0 +1,156 @@ +//***************************************************************************** +// +// bl_uart.c - Functions to transfer data via the UART port. +// +// 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 "inc/hw_gpio.h" +#include "inc/hw_memmap.h" +#include "inc/hw_sysctl.h" +#include "inc/hw_types.h" +#include "inc/hw_uart.h" +#include "bl_config.h" +#include "boot_loader/bl_uart.h" + +//***************************************************************************** +// +//! \addtogroup bl_uart_api +//! @{ +// +//***************************************************************************** +#if defined(UART_ENABLE_UPDATE) || defined(DOXYGEN) + +//***************************************************************************** +// +//! Sends data over the UART port. +//! +//! \param pui8Data is the buffer containing the data to write out to the UART +//! port. +//! \param ui32Size is the number of bytes provided in \e pui8Data buffer that +//! will be written out to the UART port. +//! +//! This function sends \e ui32Size bytes of data from the buffer pointed to by +//! \e pui8Data via the UART port. +//! +//! \return None. +// +//***************************************************************************** +void +UARTSend(const uint8_t *pui8Data, uint32_t ui32Size) +{ + // + // Transmit the number of bytes requested on the UART port. + // + while(ui32Size--) + { + // + // Make sure that the transmit FIFO is not full. + // + while((HWREG(UART0_BASE + UART_O_FR) & UART_FR_TXFF)) + { + } + + // + // Send out the next byte. + // + HWREG(UART0_BASE + UART_O_DR) = *pui8Data++; + } + + // + // Wait until the UART is done transmitting. + // + UARTFlush(); +} + +//***************************************************************************** +// +//! Waits until all data has been transmitted by the UART port. +//! +//! This function waits until all data written to the UART port has been +//! transmitted. +//! +//! \return None. +// +//***************************************************************************** +void +UARTFlush(void) +{ + // + // Wait for the UART FIFO to empty and then wait for the shifter to get the + // bytes out the port. + // + while(!(HWREG(UART0_BASE + UART_O_FR) & UART_FR_TXFE)) + { + } + + // + // Wait for the FIFO to not be busy so that the shifter completes. + // + while((HWREG(UART0_BASE + UART_O_FR) & UART_FR_BUSY)) + { + } +} + +//***************************************************************************** +// +//! Receives data over the UART port. +//! +//! \param pui8Data is the buffer to read data into from the UART port. +//! \param ui32Size is the number of bytes provided in the \e pui8Data buffer +//! that should be written with data from the UART port. +//! +//! This function reads back \e ui32Size bytes of data from the UART port, into +//! the buffer that is pointed to by \e pui8Data. This function will not +//! return until \e ui32Size number of bytes have been received. +//! +//! \return None. +// +//***************************************************************************** +void +UARTReceive(uint8_t *pui8Data, uint32_t ui32Size) +{ + // + // Send out the number of bytes requested. + // + while(ui32Size--) + { + // + // Wait for the FIFO to not be empty. + // + while((HWREG(UART0_BASE + UART_O_FR) & UART_FR_RXFE)) + { + } + + // + // Receive a byte from the UART. + // + *pui8Data++ = HWREG(UART0_BASE + UART_O_DR); + } +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** +#endif diff --git a/boot_loader/bl_uart.h b/boot_loader/bl_uart.h new file mode 100644 index 0000000..8148995 --- /dev/null +++ b/boot_loader/bl_uart.h @@ -0,0 +1,81 @@ +//***************************************************************************** +// +// bl_uart.h - Definitions for the UART transport functions. +// +// 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. +// +//***************************************************************************** + +#ifndef __BL_UART_H__ +#define __BL_UART_H__ + +//***************************************************************************** +// +// This macro is used to generate a constant to represent the UART baud rate to +// processor clock rate ratio. This prevents the need for run-time calculation +// of the ratio of baud rate to processor clock rate ratio. +// +//***************************************************************************** +#define UART_BAUD_RATIO(ui32Baud) \ + ((((CRYSTAL_FREQ * 8) / ui32Baud) + 1) / 2) + +//***************************************************************************** +// +// This defines the UART receive pin that is being used by the boot loader. +// +//***************************************************************************** +#define UART_RX (1 << 0) + +//***************************************************************************** +// +// This defines the UART transmit pin that is being used by the boot loader. +// +//***************************************************************************** +#define UART_TX (1 << 1) + +//***************************************************************************** +// +// This defines the combination of pins used to implement the UART port used by +// the boot loader. +// +//***************************************************************************** +#define UART_PINS (UART_RX | UART_TX) + +//***************************************************************************** +// +// UART Transport APIs +// +//***************************************************************************** +extern void UARTSend(const uint8_t *pui8Data, uint32_t ui32Size); +extern void UARTReceive(uint8_t *pui8Data, uint32_t ui32Size); +extern void UARTFlush(void); +extern int UARTAutoBaud(uint32_t *pui32Ratio); + +//***************************************************************************** +// +// Define the transport functions if the UART is being used. +// +//***************************************************************************** +#ifdef UART_ENABLE_UPDATE +#define SendData UARTSend +#define FlushData UARTFlush +#define ReceiveData UARTReceive +#endif + +#endif // __BL_UART_H__ diff --git a/boot_loader/bl_usb.c b/boot_loader/bl_usb.c new file mode 100644 index 0000000..00ccd7a --- /dev/null +++ b/boot_loader/bl_usb.c @@ -0,0 +1,2166 @@ +//***************************************************************************** +// +// bl_usb.c - Functions to transfer data via the USB port. +// +// Copyright (c) 2009-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_memmap.h" +#include "inc/hw_flash.h" +#include "inc/hw_sysctl.h" +#include "inc/hw_types.h" +#include "inc/hw_nvic.h" +#include "inc/hw_usb.h" +#include "bl_config.h" +#include "boot_loader/bl_crystal.h" +#include "boot_loader/bl_flash.h" +#include "boot_loader/bl_hooks.h" +#include "boot_loader/bl_usbfuncs.h" +#include "boot_loader/usbdfu.h" + +//***************************************************************************** +// +// DFU Notes: +// +// 1. This implementation is manifestation-tolerant and doesn't time out +// waiting for a reset after a download completes. As a result, the detach +// timeout in the DFU functional descriptor is set to the maximum possible +// value representing a timeout of 65.536 seconds. +// +// 2. This implementation does not support the BUSY state. By skipping this +// and remaining in DNLOAD_SYNC when we are waiting for a programming or +// erase operation to complete, we save the overhead of having to support a +// timeout mechanism. Host-side implementations don't seem to rely upon +// the busy state so this does not appear to be a problem. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup bl_usb_api +//! @{ +// +//***************************************************************************** +#if defined(USB_ENABLE_UPDATE) || defined(DOXYGEN) + +//***************************************************************************** +// +// Make sure that the crystal frequency is defined. +// +//***************************************************************************** +#if !defined(CRYSTAL_FREQ) +#error ERROR: CRYSTAL_FREQ must be defined for USB update! +#endif + +//***************************************************************************** +// +// Make sure that the crystal frequency is one of the ones that support USB +// operation. +// +//***************************************************************************** +#if CRYSTAL_FREQ != 4000000 && \ + CRYSTAL_FREQ != 5000000 && \ + CRYSTAL_FREQ != 6000000 && \ + CRYSTAL_FREQ != 8000000 && \ + CRYSTAL_FREQ != 10000000 && \ + CRYSTAL_FREQ != 12000000 && \ + CRYSTAL_FREQ != 16000000 +#error ERROR: Invalid CRYSTAL_FREQ specified for USB update! +#endif + +//***************************************************************************** +// +// The DFU device information structure was developed assuming flash block +// sizes in the 1KB to 32KB range but large external flash devices may have +// 64KB or larger blocks. If the configuration options indicate a target +// device with large pages, we fake the size at 32KB to keep the client happy. +// The other option would be to redefine this field as an uint32_t but that +// would break existing applications using the interface. +// +// For normal operation, this is unlikely to cause a problem since we will not +// allow a flash operation to start anywhere other than at APP_START_ADDRESS +// (which must fall on a real flash page boundary) or the start of the +// reserved +// +//***************************************************************************** +#if (FLASH_PAGE_SIZE > 0x10000) +#define DFU_REPORTED_PAGE_SIZE 0x8000 +#else +#define DFU_REPORTED_PAGE_SIZE FLASH_PAGE_SIZE +#endif + +//***************************************************************************** +// +// This holds the total size of the firmware image being downloaded (which is +// needed if we have a progress reporting hook function provided). +// +//***************************************************************************** +#ifdef BL_PROGRESS_FN_HOOK +uint32_t g_ui32ImageSize; +#endif + +//***************************************************************************** +// +// The structure used to define a block of memory. +// +//***************************************************************************** +typedef struct +{ + uint8_t *pui8Start; + uint32_t ui32Length; +} +tMemoryBlock; + +//***************************************************************************** +// +// The block of memory that is to be sent back in response to the next upload +// request. +// +//***************************************************************************** +tMemoryBlock g_sNextUpload; + +//***************************************************************************** +// +// The block of memory into which the next programming operation will write. +// +//***************************************************************************** +volatile tMemoryBlock g_sNextDownload; + +//***************************************************************************** +// +// The block of flash to be erased. +// +//***************************************************************************** +volatile tMemoryBlock g_sErase; + +//***************************************************************************** +// +// Information on the device we are running on. This will be returned to the +// host after a download request containing command DFU_CMD_INFO. +// +//***************************************************************************** +tDFUDeviceInfo g_sDFUDeviceInfo; + +//***************************************************************************** +// +// This variable keeps track of the last software-specific command received +// from the host via a download request. +// +//***************************************************************************** +uint8_t g_ui8LastCommand; + +//***************************************************************************** +// +// The current status of the DFU device as reported to the host in response to +// USBD_DFU_REQUEST_GETSTATUS. +// +//***************************************************************************** +tDFUGetStatusResponse g_sDFUStatus = +{ + 0, { 5, 0, 0 }, (uint8_t)STATE_IDLE, 0 +}; + +//***************************************************************************** +// +// The structure sent in response to a valid USBD_DFU_REQUEST_TIVA. +// +//***************************************************************************** +tDFUQueryTIVAProtocol g_sDFUProtocol = +{ + DFU_PROTOCOL_USBLIB_MARKER, + DFU_PROTOCOL_USBLIB_VERSION_1 +}; + +//***************************************************************************** +// +// The current state of the device. +// +//***************************************************************************** +volatile tDFUState g_eDFUState = STATE_IDLE; + +//***************************************************************************** +// +// The current status of the device. +// +//***************************************************************************** +volatile tDFUStatus g_eDFUStatus = STATUS_OK; + +//***************************************************************************** +// +// The buffer used to hold download data from the host prior to writing it to +// flash or image data in the process of being uploaded to the host. +// +//***************************************************************************** +uint8_t g_pui8DFUBuffer[DFU_TRANSFER_SIZE]; + +//***************************************************************************** +// +// The start of the image data within g_pui8DFUBuffer. +// +//***************************************************************************** +uint8_t *g_pui8DFUWrite; + +//***************************************************************************** +// +// The number of bytes of valid data in the DFU buffer. +// +//***************************************************************************** +volatile uint16_t g_ui16DFUBufferUsed; + +//***************************************************************************** +// +// Flags used to indicate that the main thread is being asked to do something. +// +//***************************************************************************** +volatile uint32_t g_ui32CommandFlags; +#define CMD_FLAG_ERASE 0 +#define CMD_FLAG_WRITE 1 +#define CMD_FLAG_RESET 2 + +//***************************************************************************** +// +// This global determines whether or not we add a DFU header to any uploaded +// image data. If true, the binary image is sent without the header. If false +// the header is included. This is a DFU requirement since uploaded images +// must be able to be downloaded again and hence must have the header in place +// so that the destination address is available. +// +//***************************************************************************** +bool g_bUploadBinary = false; + +//***************************************************************************** +// +// If the upload format includes the header, we need to be able to suppress +// this when replying to TIVA-specific commands such as CMD_DFU_INFO. This +// global determines whether we need to suppress the header that would +// otherwise be send in response to the first USBD_DFU_REQUEST_UPLOAD received +// while in STATE_IDLE. +// +//***************************************************************************** +bool g_bSuppressUploadHeader = false; + +//***************************************************************************** +// +// A flag we use to indicate when the device has been enumerated. +// +//***************************************************************************** +bool g_bAddressSet = false; + +//***************************************************************************** +// +// The languages supported by this device. +// +//***************************************************************************** +const uint8_t g_pui8LangDescriptor[] = +{ + 4, + USB_DTYPE_STRING, + USBShort(USB_LANG_EN_US) +}; + +//***************************************************************************** +// +// The jump table used to implement request handling in the DFU state machine. +// +//***************************************************************************** +typedef void (* tHandleRequests)(tUSBRequest *psUSBRequest); + +extern void HandleRequestIdle(tUSBRequest *psUSBRequest); +extern void HandleRequestDnloadSync(tUSBRequest *psUSBRequest); +extern void HandleRequestDnloadIdle(tUSBRequest *psUSBRequest); +extern void HandleRequestManifestSync(tUSBRequest *psUSBRequest); +extern void HandleRequestUploadIdle(tUSBRequest *psUSBRequest); +extern void HandleRequestError(tUSBRequest *psUSBRequest); + +tHandleRequests g_pfnRequestHandlers[] = +{ + 0, // STATE_APP_IDLE + 0, // STATE_APP_DETACH + HandleRequestIdle, // STATE_IDLE + HandleRequestDnloadSync, // STATE_DNLOAD_SYNC + HandleRequestDnloadSync, // STATE_DNBUSY + HandleRequestDnloadIdle, // STATE_DNLOAD_IDLE + HandleRequestManifestSync, // STATE_MANIFEST_SYNC + 0, // STATE_MANIFEST + 0, // STATE_MANIFEST_WAIT_RESET + HandleRequestUploadIdle, // STATE_UPLOAD_IDLE + HandleRequestError // STATE_ERROR +}; + +//***************************************************************************** +// +// The manufacturer string. +// +//***************************************************************************** +const uint8_t g_pui8ManufacturerString[] = +{ + (17 + 1) * 2, + USB_DTYPE_STRING, + 'T', 0, 'e', 0, 'x', 0, 'a', 0, 's', 0, ' ', 0, 'I', 0, 'n', 0, + 's', 0, 't', 0, 'r', 0, 'u', 0, 'm', 0, 'e', 0, 'n', 0, 't', 0, + 's', 0 +}; + +//***************************************************************************** +// +// The product string. +// +//***************************************************************************** +const uint8_t g_pui8ProductString[] = +{ + (23 + 1) * 2, + USB_DTYPE_STRING, + 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, ' ', 0, 'F', 0, 'i', 0, + 'r', 0, 'm', 0, 'w', 0, 'a', 0, 'r', 0, 'e', 0, ' ', 0, 'U', 0, 'p', 0, + 'g', 0, 'r', 0, 'a', 0, 'd', 0, 'e', 0 +}; + +//***************************************************************************** +// +// The serial number string. +// +//***************************************************************************** +const uint8_t g_pui8SerialNumberString[] = +{ + (3 + 1) * 2, + USB_DTYPE_STRING, + '0', 0, '.', 0, '1', 0 +}; + +//***************************************************************************** +// +// The descriptor string table. +// +//***************************************************************************** +const uint8_t *const g_ppui8StringDescriptors[] = +{ + g_pui8LangDescriptor, + g_pui8ManufacturerString, + g_pui8ProductString, + g_pui8SerialNumberString +}; + +//***************************************************************************** +// +// DFU Device Descriptor. +// +//***************************************************************************** +const uint8_t g_pui8DFUDeviceDescriptor[] = +{ + 18, // Size of this structure. + USB_DTYPE_DEVICE, // Type of this structure. + USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts assume + // high-speed - see USB 2.0 spec 9.2.6.6) + USB_CLASS_VEND_SPECIFIC, // USB Device Class + 0, // USB Device Sub-class + 0, // USB Device protocol + 64, // Maximum packet size for default pipe. + USBShort(USB_VENDOR_ID), // Vendor ID (VID). + USBShort(USB_PRODUCT_ID), // Product ID (PID). + USBShort(USB_DEVICE_ID), // Device Release Number BCD. + 1, // Manufacturer string identifier. + 2, // Product string identifier. + 3, // Product serial number. + 1 // Number of configurations. +}; + +//***************************************************************************** +// +// DFU device configuration descriptor. +// +//***************************************************************************** +const uint8_t g_pui8DFUConfigDescriptor[] = +{ + // + // Configuration descriptor header. + // + 9, // Size of the configuration descriptor. + USB_DTYPE_CONFIGURATION, // Type of this descriptor. + USBShort(27), // The total size of this full structure. + 1, // The number of interfaces in this + // configuration. + 1, // The unique value for this configuration. + 0, // The string identifier that describes this + // configuration. +#if USB_BUS_POWERED + USB_CONF_ATTR_BUS_PWR, // Bus Powered +#else + USB_CONF_ATTR_SELF_PWR, // Self Powered +#endif + (USB_MAX_POWER / 2), // The maximum power in 2mA increments. + + // + // Interface descriptor. + // + 9, // Length of this descriptor. + USB_DTYPE_INTERFACE, // This is an interface descriptor. + 0, // Interface number . + 0, // Alternate setting number. + 0, // Number of endpoints (only endpoint 0 used) + USB_CLASS_APP_SPECIFIC, // Application specific interface class + USB_DFU_SUBCLASS, // Device Firmware Upgrade subclass + USB_DFU_PROTOCOL, // DFU protocol + 0, // No interface description string present. + + // + // Device Firmware Upgrade functional descriptor. + // + 9, // Length of this descriptor. + 0x21, // DFU Functional descriptor type + (DFU_ATTR_CAN_DOWNLOAD | // DFU attributes. + DFU_ATTR_CAN_UPLOAD | + DFU_ATTR_MANIFEST_TOLERANT), + USBShort(0xFFFF), // Detach timeout (set to maximum). + USBShort(DFU_TRANSFER_SIZE),// Transfer size 1KB. + USBShort(0x0110) // DFU Version 1.1 +}; + +//***************************************************************************** +// +// The USB device interrupt handler. +// +// This function is called to process USB interrupts when in device mode. +// This handler will branch the interrupt off to the appropriate application or +// stack handlers depending on the current status of the USB controller. +// +// \return None. +// +//***************************************************************************** +void +USB0DeviceIntHandler(void) +{ + uint32_t ui32TxStatus, ui32GenStatus; + + // + // Get the current full USB interrupt status. + // + ui32TxStatus = HWREGH(USB0_BASE + USB_O_TXIS); + ui32GenStatus = HWREGB(USB0_BASE + USB_O_IS); + + // + // Received a reset from the host. + // + if(ui32GenStatus & USB_IS_RESET) + { + USBDeviceEnumResetHandler(); + } + + // + // USB device was disconnected. + // + if(ui32GenStatus & USB_IS_DISCON) + { + HandleDisconnect(); + } + + // + // Handle end point 0 interrupts. + // + if(ui32TxStatus & USB_TXIE_EP0) + { + USBDeviceEnumHandler(); + } +} + +//***************************************************************************** +// +// A prototype for the function (in the startup code) for a predictable length +// delay. +// +//***************************************************************************** +extern void Delay(uint32_t ui32Count); + +//***************************************************************************** +// +// Send the current state or status structure back to the host. This function +// also acknowledges the request which causes us to send back this data. +// +//***************************************************************************** +void +SendDFUStatus(void) +{ + // + // Acknowledge the original request. + // + USBDevEndpoint0DataAck(false); + + // + // Copy the current state into the status structure we will return. + // + g_sDFUStatus.bState = (uint8_t)g_eDFUState; + g_sDFUStatus.bStatus = (uint8_t)g_eDFUStatus; + + // + // Send the status structure back to the host. + // + USBBLSendDataEP0((uint8_t *)&g_sDFUStatus, sizeof(tDFUGetStatusResponse)); +} + +//***************************************************************************** +// +// Send the next block of upload data back to the host assuming data remains +// to be sent. +// +// \param ui16Length is the requested amount of data. +// \param bAppendHeader is \b true to append a tDFUDownloadProgHeader at the +// start of the uploaded data or \b false if no header is required. +// +// Returns \b true if a full packet containing DFU_TRANSFER_SIZE bytes +// was sent and data remains to be sent following this transaction, or \b +// false if no more data remains to be sent following this transaction. +// +//***************************************************************************** +bool +SendUploadData(uint16_t ui16Length, bool bAppendHeader) +{ + uint16_t ui16ToSend; + uint32_t ui32Available; + + // + // Acknowledge the original request. + // + USBDevEndpoint0DataAck(false); + + // + // How much data is available to be sent? + // + ui32Available = (g_sNextUpload.ui32Length + + (bAppendHeader ? sizeof(tDFUDownloadProgHeader) : 0)); + + // + // How much data can we send? This is the smallest of the maximum transfer + // size, the requested length or the available data. + // + ui16ToSend = + (ui16Length > DFU_TRANSFER_SIZE) ? DFU_TRANSFER_SIZE : ui16Length; + ui16ToSend = + ((uint32_t)ui16ToSend > ui32Available) ? ui32Available : ui16ToSend; + + // + // If we have been asked to send a header, we need to copy some of the data + // into a buffer and send from there. If we don't do this, we run the risk + // of sending a long packet prematurely and ending the upload before it is + // complete. + // + if(bAppendHeader) + { + tDFUDownloadProgHeader *psHdr; + uint8_t *pui8From; + uint8_t *pui8To; + uint32_t ui32Loop; + + // + // We are appending a header so write the header information into a + // buffer then copy the first chunk of data from its original position + // into the same buffer. + // + psHdr = (tDFUDownloadProgHeader *)g_pui8DFUBuffer; + + // + // Build the header. + // + psHdr->ui8Command = DFU_CMD_PROG; + psHdr->ui8Reserved = 0; + psHdr->ui16StartAddr = ((uint32_t)(g_sNextUpload.pui8Start) / 1024); + psHdr->ui32Length = g_sNextUpload.ui32Length; + + // + // Copy the remainder of the first transfer's data from its original + // position. + // + pui8From = g_sNextUpload.pui8Start; + pui8To = (uint8_t *)(psHdr + 1); + for(ui32Loop = (ui16ToSend - sizeof(tDFUDownloadProgHeader)); ui32Loop; + ui32Loop--) + { + *pui8To++ = *pui8From++; + } + + // + // Send the data. + // + USBBLSendDataEP0((uint8_t *)psHdr, ui16ToSend); + + // + // Update our upload pointer and length. + // + g_sNextUpload.pui8Start += ui16ToSend - sizeof(tDFUDownloadProgHeader); + g_sNextUpload.ui32Length -= + ui16ToSend - sizeof(tDFUDownloadProgHeader); + } + else + { + // + // We are not sending a header so send the requested upload data back + // to the host directly from its original position. + // + USBBLSendDataEP0(g_sNextUpload.pui8Start, ui16ToSend); + + // + // Update our upload pointer and length. + // + g_sNextUpload.pui8Start += ui16ToSend; + g_sNextUpload.ui32Length -= ui16ToSend; + } + + // + // We return true if we sent a full packet (containing the maximum transfer + // size bytes) or false to indicate that a long packet was sent or no more + // data remains. + // + return(((ui16ToSend == DFU_TRANSFER_SIZE) && g_sNextUpload.ui32Length) ? + true : false); +} + +//***************************************************************************** +// +// Send the current state back to the host. +// +//***************************************************************************** +void +SendDFUState(void) +{ + // + // Acknowledge the original request. + // + USBDevEndpoint0DataAck(false); + + // + // Update the status structure with the current state. + // + g_sDFUStatus.bState = (uint8_t)g_eDFUState; + + // + // Send the state from the status structure back to the host. + // + USBBLSendDataEP0((uint8_t *)&g_sDFUStatus.bState, 1); +} + +//***************************************************************************** +// +//! Handle USB requests sent to the DFU device. +//! +//! \param psUSBRequest is a pointer to the USB request that the device has +//! been sent. +//! +//! This function is called to handle all non-standard requests received +//! by the device. This will include all the DFU endpoint 0 commands along +//! with the TIVA-specific request we use to query whether the device +//! supports our flavor of the DFU binary format. Incoming DFU requests are +//! processed by request handlers specific to the particular state of the DFU +//! connection. This state machine implementation is chosen to keep the +//! software as close as possible to the USB DFU class documentation. +//! +//! \return None. +// +//***************************************************************************** +void +HandleRequests(tUSBRequest *psUSBRequest) +{ + // + // This request is used by the host to determine whether the connected + // device supports the TIVA protocol extensions to DFU (our + // DFU_CMD_xxxx command headers passed alongside DNLOAD requests). We + // check the parameters and, if they are as expected, we respond with + // a 4 byte structure providing a marker and the protocol version + // number. + // + if(psUSBRequest->bRequest == USBD_DFU_REQUEST_TIVA) + { + // + // Check that the request parameters are all as expected. We are + // using the wValue value merely as a way of making it less likely + // that we respond to another vendor's device-specific request. + // + if((psUSBRequest->wLength == sizeof(tDFUQueryTIVAProtocol)) && + (psUSBRequest->wValue == REQUEST_TIVA_VALUE)) + { + // + // Acknowledge the original request. + // + USBDevEndpoint0DataAck(false); + + // + // Send the status structure back to the host. + // + USBBLSendDataEP0((uint8_t *)&g_sDFUProtocol, + sizeof(tDFUQueryTIVAProtocol)); + } + else + { + // + // The request parameters were not as expected so we assume + // that this is not our request and stall the endpoint to + // indicate an error. + // + USBBLStallEP0(); + } + + return; + } + + // + // Pass the request to the relevant handler depending upon our current + // state. If no handler is configured, we stall the endpoint since this + // implies that requests can't be handled in this state. + // + if(g_pfnRequestHandlers[g_eDFUState]) + { + // + // Dispatch the request to the relevant handler depending upon the + // current state. + // + (g_pfnRequestHandlers[g_eDFUState])(psUSBRequest); + } + else + { + USBBLStallEP0(); + } +} + +//***************************************************************************** +// +// Handle all incoming DFU requests while in state STATE_IDLE. +// +//***************************************************************************** +void +HandleRequestIdle(tUSBRequest *psUSBRequest) +{ + switch(psUSBRequest->bRequest) + { + // + // This is a download request. We need to request the transaction + // payload unless this is a zero length request in which case we mark + // the error by stalling the endpoint. + // + case USBD_DFU_REQUEST_DNLOAD: + { + if(psUSBRequest->wLength) + { + USBBLRequestDataEP0(g_pui8DFUBuffer, psUSBRequest->wLength); + } + else + { + USBBLStallEP0(); + return; + } + break; + } + + // + // This is an upload request. We send back a block of data + // corresponding to the current upload pointer as held in + // g_sNextUpload. + // + case USBD_DFU_REQUEST_UPLOAD: + { + // + // If we have any upload data to send, send it. Make sure we append + // a header if required. + // + if(SendUploadData(psUSBRequest->wLength, + g_bSuppressUploadHeader ? false : + !g_bUploadBinary)) + { + // + // We sent a full (max packet size) frame to the host so + // transition to UPLOAD_IDLE state since we expect another + // upload request to continue the process. + // + g_eDFUState = STATE_UPLOAD_IDLE; + } + + // + // Clear the flag we use to suppress sending the DFU header. + // + g_bSuppressUploadHeader = false; + + return; + } + + // + // Return the current device status structure. + // + case USBD_DFU_REQUEST_GETSTATUS: + { + SendDFUStatus(); + return; + } + + // + // Return the current device state. + // + case USBD_DFU_REQUEST_GETSTATE: + { + SendDFUState(); + return; + } + + // + // Ignore the ABORT request. This returns us to IDLE state but we're + // there already. + // + case USBD_DFU_REQUEST_ABORT: + { + break; + } + + // + // All other requests are illegal in this state so signal the error + // by stalling the endpoint. + // + case USBD_DFU_REQUEST_CLRSTATUS: + case USBD_DFU_REQUEST_DETACH: + default: + { + USBBLStallEP0(); + return; + } + } + + // + // If we drop out of the switch, we need to ACK the received request. + // + USBDevEndpoint0DataAck(false); +} + +//***************************************************************************** +// +// Handle all incoming DFU requests while in state STATE_DNLOAD_SYNC or +// STATE_DNBUSY. +// +//***************************************************************************** +void +HandleRequestDnloadSync(tUSBRequest *psUSBRequest) +{ + // + // In this state, we have received a block of the download and are waiting + // for a USBD_DFU_REQUEST_GETSTATUS which will trigger a return + // to STATE_DNLOAD_IDLE assuming we have finished programming the block. + // If the last command we received was not DFU_CMD_PROG, we transition + // directly from this state back to STATE_IDLE once the last operation has + // completed since we need to be able to accept a new command. + // + switch(psUSBRequest->bRequest) + { + // + // The host is requesting the current device status. Return this and + // revert to STATE_IDLE. + // + case USBD_DFU_REQUEST_GETSTATUS: + { + // + // Are we finished processing whatever the last flash-operation + // was? Note that we don't support DNLOAD_BUSY state in this + // implementation, we merely continue to report DNLOAD_SYNC state + // until we are finished with the command. + // + if(!g_ui32CommandFlags) + { + // + // If we are in the middle of a programming operation, + // transition back to DNLOAD_IDLE state to wait for the + // next block. If not, go back to idle since we expect a + // new command. + // + g_eDFUState = ((g_ui8LastCommand == DFU_CMD_PROG) ? + STATE_DNLOAD_IDLE : STATE_IDLE); + } + + // + // Send the latest status back to the host. + // + SendDFUStatus(); + + // + // Return here since we've already ACKed the request. + // + return; + } + + // + // The host is requesting the current device state. + // + case USBD_DFU_REQUEST_GETSTATE: + { + // + // Are we currently in DNLOAD_SYNC state? + // + if(g_eDFUState == STATE_DNLOAD_SYNC) + { + // + // Yes - send back the state. + // + SendDFUState(); + } + else + { + // + // In STATE_BUSY, we can't respond to any requests so stall + // the endpoint. + // + USBBLStallEP0(); + } + + // + // Return here since the incoming request has already been either + // ACKed or stalled by the processing above. + // + return; + } + + // + // Any other request is ignored and causes us to stall the control + // endpoint and remain in STATE_ERROR. + // + default: + { + USBBLStallEP0(); + return; + } + } +} + +//***************************************************************************** +// +// Handle all incoming DFU requests while in state STATE_DNLOAD_IDLE. +// +//***************************************************************************** +void +HandleRequestDnloadIdle(tUSBRequest *psUSBRequest) +{ + switch(psUSBRequest->bRequest) + { + // + // This is a download request. We need to request the transaction + // payload unless this is a zero length request in which case we mark + // the error by stalling the endpoint. + // + case USBD_DFU_REQUEST_DNLOAD: + { + // + // Are we being passed data to program? + // + if(psUSBRequest->wLength) + { + // + // Yes - request the data. + // + USBBLRequestDataEP0(g_pui8DFUBuffer, psUSBRequest->wLength); + } + else + { + // + // No - this is the signal that a download operation is + // complete. Do we agree? + // + if(g_sNextDownload.ui32Length) + { + // + // We think there should still be some data to be received + // so mark this as an error. + // + g_eDFUState = STATE_ERROR; + g_eDFUStatus = STATUS_ERR_NOTDONE; + } + else + { + // + // We agree that the download has completed. Enter state + // STATE_MANIFEST_SYNC. + // + g_eDFUState = STATE_MANIFEST_SYNC; + } + } + break; + } + + // + // Return the current device status structure. + // + case USBD_DFU_REQUEST_GETSTATUS: + { + SendDFUStatus(); + return; + } + + // + // Return the current device state. + // + case USBD_DFU_REQUEST_GETSTATE: + { + SendDFUState(); + return; + } + + // + // An ABORT request causes us to abort the current transfer and + // return the the idle state regardless of the state of the previous + // programming operation. + // + case USBD_DFU_REQUEST_ABORT: + { + // + // Default to downloading the main code image. + // + g_sNextDownload.pui8Start = + (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr; + g_sNextDownload.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop - + g_sDFUDeviceInfo.ui32AppStartAddr); + g_eDFUState = STATE_IDLE; + break; + } + + // + // All other requests are illegal in this state so signal the error + // by stalling the endpoint. + // + case USBD_DFU_REQUEST_CLRSTATUS: + case USBD_DFU_REQUEST_DETACH: + case USBD_DFU_REQUEST_UPLOAD: + default: + { + USBBLStallEP0(); + return; + } + } + + // + // If we drop out of the switch, we need to ACK the received request. + // + USBDevEndpoint0DataAck(false); +} + +//***************************************************************************** +// +// Handle all incoming DFU requests while in state STATE_MANIFEST_SYNC. +// +//***************************************************************************** +void +HandleRequestManifestSync(tUSBRequest *psUSBRequest) +{ + // + // In this state, we have received the last block of a download and are + // waiting for a USBD_DFU_REQUEST_GETSTATUS which will trigger a return + // to STATE_IDLE. + // + switch(psUSBRequest->bRequest) + { + // + // The host is requesting the current device status. Return this and + // revert to STATE_IDLE. + // + case USBD_DFU_REQUEST_GETSTATUS: + { + g_eDFUState = STATE_IDLE; + SendDFUStatus(); + break; + } + + // + // The host is requesting the current device state. + // + case USBD_DFU_REQUEST_GETSTATE: + { + SendDFUState(); + break; + } + + // + // Any other request is ignored and causes us to stall the control + // endpoint and remain in STATE_MANIFEST_SYNC. + // + default: + { + USBBLStallEP0(); + break; + } + } +} + +//***************************************************************************** +// +// Handle all incoming DFU requests while in state STATE_UPLOAD_IDLE. +// +//***************************************************************************** +void +HandleRequestUploadIdle(tUSBRequest *psUSBRequest) +{ + // + // In this state, we have already received the first upload request. What + // are we being asked to do now? + // + switch(psUSBRequest->bRequest) + { + // + // The host is requesting more upload data. + // + case USBD_DFU_REQUEST_UPLOAD: + { + // + // See if there is any more data to transfer and, if there is, + // send it back to the host. + // + if(!SendUploadData(psUSBRequest->wLength, false)) + { + // + // We sent less than a full packet of data so the transfer is + // complete. Revert to idle state and ensure that we reset + // our upload pointer and size to the default flash region. + // + g_eDFUState = STATE_IDLE; + g_sNextUpload.pui8Start = + (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr; + g_sNextUpload.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop - + g_sDFUDeviceInfo.ui32AppStartAddr); + } + break; + } + + // + // The host is requesting the current device status. + // + case USBD_DFU_REQUEST_GETSTATUS: + { + SendDFUStatus(); + break; + } + + // + // The host is requesting the current device state. + // + case USBD_DFU_REQUEST_GETSTATE: + { + SendDFUState(); + break; + } + + // + // The host is requesting that we abort the current upload. + // + case USBD_DFU_REQUEST_ABORT: + { + // + // Default to sending the main application image for the next + // upload. + // + g_sNextUpload.pui8Start = + (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr; + g_sNextUpload.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop - + g_sDFUDeviceInfo.ui32AppStartAddr); + g_eDFUState = STATE_IDLE; + break; + } + + // + // Any other request is ignored and causes us to stall the control + // endpoint and remain in STATE_ERROR. + // + default: + { + USBBLStallEP0(); + break; + } + } +} + +//***************************************************************************** +// +// Handle all incoming DFU requests while in state STATE_ERROR. +// +//***************************************************************************** +void +HandleRequestError(tUSBRequest *psUSBRequest) +{ + // + // In this state, we respond to state and status requests and also to + // USBD_DFU_REQUEST_CLRSTATUS which clears the previous error condition. + // + switch(psUSBRequest->bRequest) + { + // + // The host is requesting the current device status. + // + case USBD_DFU_REQUEST_GETSTATUS: + { + SendDFUStatus(); + break; + } + + // + // The host is requesting the current device state. + // + case USBD_DFU_REQUEST_GETSTATE: + { + SendDFUState(); + break; + } + + // + // The host is asking us to clear our previous error condition and + // revert to idle state in preparation to receive new commands. + // + case USBD_DFU_REQUEST_CLRSTATUS: + { + g_eDFUState = STATE_IDLE; + g_eDFUStatus = STATUS_OK; + USBDevEndpoint0DataAck(false); + break; + } + + // + // Any other request is ignored and causes us to stall the control + // endpoint and remain in STATE_ERROR. + // + default: + { + USBBLStallEP0(); + break; + } + } +} + +//***************************************************************************** +// +// Handle cases where the host sets a new USB configuration. +// +//***************************************************************************** +void +HandleConfigChange(uint32_t ui32Info) +{ + // + // Revert to idle state. + // + g_eDFUState = STATE_IDLE; + g_eDFUStatus = STATUS_OK; +} + +//***************************************************************************** +// +// Setting the device address indicates that we are now connected to the host +// and can expect some DFU communication so we use this opportunity to clean +// out our state just in case we were not idle last time the host disconnected. +// +//***************************************************************************** +void +HandleSetAddress(void) +{ + g_eDFUState = STATE_IDLE; + g_eDFUStatus = STATUS_OK; + g_bAddressSet = true; + + // + // Default the download address to the app start address and valid length + // to the whole of the programmable flash area. + // + g_sNextDownload.pui8Start = + (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr; + g_sNextDownload.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop - + g_sDFUDeviceInfo.ui32AppStartAddr); + + // + // Default the upload address to the app start address and valid length + // to the whole of the programmable flash area. + // + g_sNextUpload.pui8Start = + (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr; + g_sNextUpload.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop - + g_sDFUDeviceInfo.ui32AppStartAddr); +} + +//***************************************************************************** +// +// Check that a range of addresses passed is within the region of flash that +// the boot loader is allowed to access. +// +// Returns true if the address range is accessible or false otherwise. +// +//***************************************************************************** +bool +FlashRangeCheck(uint32_t ui32Start, uint32_t ui32Length) +{ +#ifdef ENABLE_BL_UPDATE + if((ui32Length <= + (g_sDFUDeviceInfo.ui32FlashTop - g_sDFUDeviceInfo.ui32AppStartAddr)) && + ((ui32Start + ui32Length) <= g_sDFUDeviceInfo.ui32FlashTop)) +#else + if((ui32Start >= g_sDFUDeviceInfo.ui32AppStartAddr) && + (ui32Length <= + (g_sDFUDeviceInfo.ui32FlashTop - g_sDFUDeviceInfo.ui32AppStartAddr)) && + ((ui32Start + ui32Length) <= g_sDFUDeviceInfo.ui32FlashTop)) +#endif + { + // + // The block passed lies wholly within the flash address range of + // this device. + // + return(true); + } + else + { + // + // We were passed an address that is out of range so set the + // appropriate status code. + // + g_eDFUStatus = STATUS_ERR_ADDRESS; + return(false); + } +} + +//***************************************************************************** +// +//! Process TIVA-specific commands passed via DFU download requests. +//! +//! \param psCmd is a pointer to the first byte of the \b DFU_DNLOAD payload +//! that is expected to hold a command. +//! \param ui32Size is the number of bytes of data pointed to by \e psCmd. +//! This function is called when a DFU download command is received while in +//! \b STATE_IDLE. New downloads are assumed to contain a prefix structure +//! containing one of several TIVA-specific commands and this function +//! is responsible for parsing the download data and processing whichever +//! command is contained within it. +//! +//! \return Returns \b true on success or \b false on failure. +// +//***************************************************************************** +bool +ProcessDFUDnloadCommand(tDFUDownloadHeader *psCmd, uint32_t ui32Size) +{ + // + // Make sure we got enough data to contain a valid command header. + // + if(ui32Size < sizeof(tDFUDownloadHeader)) + { + return(false); + } + + // + // Remember the command that we have been passed since we will need thi + // to determine which state to transition to on exit from STATE_DNLOAD_SYNC. + // + g_ui8LastCommand = psCmd->ui8Command; + + // + // Which command have we been passed? + // + switch(psCmd->ui8Command) + { + // + // We are being asked to start a programming operation. + // + case DFU_CMD_PROG: + { + tDFUDownloadProgHeader *psHdr; + + // + // Extract the address and size from the command header. + // + psHdr = (tDFUDownloadProgHeader *)psCmd; + + // + // Is the passed address range valid? + // + if(BL_FLASH_AD_CHECK_FN_HOOK(psHdr->ui16StartAddr * 1024, + psHdr->ui32Length)) + { + // + // Yes - remember the range passed so that we will write the + // passed data to the correct place. + // + g_sNextDownload.pui8Start = + (uint8_t *)(psHdr->ui16StartAddr * 1024); + g_sNextDownload.ui32Length = psHdr->ui32Length; + + // + // If we have been provided with a progress reporting hook + // function, remember the total length of the image so that + // we can report this later. + // +#ifdef BL_PROGRESS_FN_HOOK + g_ui32ImageSize = psHdr->ui32Length; +#endif + + // + // Also set the upload address and size to match this download + // so that, by default, the host will get back what it just + // wrote if it performs an upload without an intermediate + // DFU_CMD_READ to set the address and size. + // + g_sNextUpload.pui8Start = + (uint8_t *)(psHdr->ui16StartAddr * 1024); + g_sNextUpload.ui32Length = psHdr->ui32Length; + + // + // Also remember that we have data in this packet to write. + // + g_pui8DFUWrite = (uint8_t *)(psHdr + 1); + g_ui16DFUBufferUsed = ui32Size - sizeof(tDFUDownloadHeader); + + // + // If a start signal hook function has been provided, call it + // here since we are about to start a new download. + // +#ifdef BL_START_FN_HOOK + BL_START_FN_HOOK(); +#endif + + // + // If FLASH_CODE_PROTECTION is defined in bl_config.h we + // erase the whole application area at this point before we + // start to flash the new image. + // +#ifdef FLASH_CODE_PROTECTION + g_sErase.pui8Start = + (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr; + + g_sErase.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop - + g_sDFUDeviceInfo.ui32AppStartAddr); + HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_ERASE) = 1; +#endif + + // + // Tell the main thread to write the data we just received it. + // + HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_WRITE) = 1; + } + else + { + // + // The flash range was invalid so switch to error state. + // + return(false); + } + break; + } + + // + // We are being passed the position and size of a block of flash to + // return in a following upload operation. + // + case DFU_CMD_READ: + { + tDFUDownloadReadCheckHeader *psHdr; + + // + // Extract the address and size from the command header. + // + psHdr = (tDFUDownloadReadCheckHeader *)psCmd; + + // + // Is the passed address range valid? + // + if(FlashRangeCheck(psHdr->ui16StartAddr * 1024, psHdr->ui32Length)) + { + // + // Yes - remember the range passed so that we will return + // this block of flash on the next upload request. + // + g_sNextUpload.pui8Start = + (uint8_t *)(psHdr->ui16StartAddr * 1024); + g_sNextUpload.ui32Length = psHdr->ui32Length; + } + else + { + // + // The flash range was invalid so switch to error state. + // + return(false); + } + break; + } + + // + // We are being passed the position and size of a block of flash which + // we will check to ensure that it is erased. + // + case DFU_CMD_CHECK: + { + tDFUDownloadReadCheckHeader *psHdr; + uint32_t *pui32Check; + uint32_t ui32Loop; + + // + // Extract the address and size from the command header. + // + psHdr = (tDFUDownloadReadCheckHeader *)psCmd; + + // + // Make sure the range we have been passed is within the area of + // flash that we are allowed to look at. + // + if(FlashRangeCheck(psHdr->ui16StartAddr * 1024, psHdr->ui32Length)) + { + // + // The range is valid so perform the check here. + // + pui32Check = (uint32_t *)(psHdr->ui16StartAddr * 1024); + + // + // Check each word in the range to ensure that it is erased. If + // not, set the error status and return. + // + for(ui32Loop = 0; ui32Loop < (psHdr->ui32Length / 4); + ui32Loop++) + { + if(*pui32Check != 0xFFFFFFFF) + { + g_eDFUStatus = STATUS_ERR_CHECK_ERASED; + return(false); + } + pui32Check++; + } + + // + // If we get here, the check passed so set the status to + // indicate this. + // + g_eDFUStatus = STATUS_OK; + } + else + { + // + // The flash range was invalid so switch to error state. + // + return(false); + } + break; + } + + // + // We are being asked to erase a block of flash. + // + case DFU_CMD_ERASE: + { + tDFUDownloadEraseHeader *psHdr; + + // + // Extract the address and size from the command header. + // + psHdr = (tDFUDownloadEraseHeader *)psCmd; + + // + // Make sure the range we have been passed is within the area of + // flash that we are allowed to look at. + // + if(FlashRangeCheck((uint32_t)psHdr->ui16StartAddr * 1024, + ((uint32_t)psHdr->ui16NumBlocks * + DFU_REPORTED_PAGE_SIZE ))) + { + // + // The range is valid so tell the main loop to erase the + // block. + // + g_sErase.pui8Start = (uint8_t *) + ((uint32_t)psHdr->ui16StartAddr * 1024); + g_sErase.ui32Length = ((uint32_t)psHdr->ui16NumBlocks * + DFU_REPORTED_PAGE_SIZE); + HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_ERASE) = 1; + } + else + { + // + // The flash range was invalid so switch to error state. + // + return(false); + } + break; + } + + // + // We are being asked to send back device information on the next + // upload request. + // + case DFU_CMD_INFO: + { + // + // Register that we need to send the device info structure on the + // next upload request. + // + g_sNextUpload.pui8Start = (uint8_t *)&g_sDFUDeviceInfo; + g_sNextUpload.ui32Length = sizeof(tDFUDeviceInfo); + + // + // Make sure we don't append the DFU_CMD_PROG header when we send + // back the data. + // + g_bSuppressUploadHeader = true; + break; + } + + // + // We are being asked to set the format of uploaded images. + // + case DFU_CMD_BIN: + { + tDFUDownloadBinHeader *psHdr; + + // + // Extract the required format the command header. + // + psHdr = (tDFUDownloadBinHeader *)psCmd; + + // + // Set the global format appropriately. + // + g_bUploadBinary = psHdr->bBinary ? true : false; + break; + } + + // + // We are being asked to prepare to reset the board and, as a result, + // run the main application image. + // + case DFU_CMD_RESET: + { + // + // Tell the main thread that it's time to go bye-bye... + // + HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_RESET) = 1; + + break; + } + + // + // We have been passed an unrecognized command identifier so report an + // error. + // + default: + { + g_eDFUStatus = STATUS_ERR_VENDOR; + return(false); + } + } + + return(true); +} + +//***************************************************************************** +// +// This callback function is called when data is received for the DATA phase +// of an EP0 OUT transaction. This data will either be a block of download +// data (if we are in STATE_DNLOAD_IDLE) or a new command (if we are in +// STATE_IDLE). +// +//***************************************************************************** +void +HandleEP0Data(uint32_t ui32Size) +{ + bool bRetcode; + + if(g_eDFUState == STATE_IDLE) + { + // + // This must be a new DFU download command header so parse it and + // determine what to do next. + // + bRetcode = + ProcessDFUDnloadCommand((tDFUDownloadHeader *)g_pui8DFUBuffer, + ui32Size); + + // + // Did we receive a recognized and valid command? + // + if(!bRetcode) + { + // + // No - set the error state. The status is set within the + // ProcessDFUDnloadCommand() function. + // + g_eDFUState = STATE_ERROR; + return; + } + } + else + { + // + // If we are not in STATE_IDLE, this must be a block of data for an + // ongoing download so signal the main thread to write it to flash. + // + g_ui16DFUBufferUsed = (uint16_t)ui32Size; + g_pui8DFUWrite = g_pui8DFUBuffer; + + // + // Tell the main thread to write the new data. + // + HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_WRITE) = 1; + } + + // + // Move to STATE_DNLOAD_SYNC since we now expect USBD_DFU_REQUEST_GETSTATUS + // before the next USBD_DFU_REQUEST_DNLOAD. + // + g_eDFUState = STATE_DNLOAD_SYNC; +} + +//***************************************************************************** +// +// Handle bus resets +// +// This function is called if the USB controller detects a reset condition on +// the bus. If we are not in the process of downloading a new image, we use +// this as a signal to reboot and run the main application image. +// +//***************************************************************************** +void +HandleReset(void) +{ + // + // Are we currently in the middle of a download operation? + // + if((g_eDFUState != STATE_DNLOAD_IDLE) && + (g_eDFUState != STATE_DNLOAD_SYNC) && (g_eDFUState != STATE_IDLE)) + { + // + // No - tell the main thread that it should reboot the system assuming + // that we are already configured. If we don't check that we are + // already configured, this will cause a reset during initial + // enumeration and that wouldn't be very helpful. + // + if(g_bAddressSet) + { + HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_RESET) = 1; + } + } +} + +//***************************************************************************** +// +// Handle cases where the USB host disconnects. +// +//***************************************************************************** +void +HandleDisconnect(void) +{ + // + // For error resilience, it may be desireable to note if the host + // disconnects and, if partway through a main image download, clear the + // first block of the flash to ensure that the image is not considered + // valid on the next boot. For now, however, we merely wait for the host + // to connect again, remaining in DFU mode. + // + + // + // Remember that we are waiting for enumeration. + // + g_bAddressSet = false; +} + +//***************************************************************************** +// +// Erase a single block of flash +// +// This function erases a single, 1KB block of flash, returning once the +// operation has completed. +// +// \return None. +// +//***************************************************************************** +static void +EraseFlashBlock(uint32_t ui32Addr) +{ + BL_FLASH_ERASE_FN_HOOK(ui32Addr); +} + +//***************************************************************************** +// +//! This is the main routine for handling updating over USB. +//! +//! This function forms the main loop of the USB DFU updater. It polls for +//! commands sent from the USB request handlers and is responsible for +//! erasing flash blocks, programming data into erased blocks and resetting +//! the device. +//! +//! \return None. +// +//***************************************************************************** +void +UpdaterUSB(void) +{ + uint32_t ui32Idx, ui32Start, ui32Temp; + uint16_t ui16Used; +#ifndef FLASH_CODE_PROTECTION + uint32_t ui32End; +#endif + + // + // Loop forever waiting for the USB interrupt handlers to tell us to do + // something. + // + while(1) + { + while(g_ui32CommandFlags == 0) + { + // + // Wait for something to do. + // + } + + // + // Are we being asked to perform a system reset? + // + if(HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_RESET)) + { + // + // Time to go bye-bye... 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) + { + } + } + + // + // Are we being asked to erase a range of blocks in flash? + // + if(HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_ERASE)) + { + // + // Loop through the pages in the block of flash we have been asked + // to erase and clear each one. + // + ui32Temp = g_sErase.ui32Length; + for(ui32Idx = (uint32_t)g_sErase.pui8Start; + ui32Idx < (uint32_t)(g_sErase.pui8Start + ui32Temp); + ui32Idx += FLASH_PAGE_SIZE) + { + EraseFlashBlock(ui32Idx); + } + + // + // Clear the command flag to indicate that we are done. + // + HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_ERASE) = 0; + } + + // + // Are we being asked to program a block of flash? + // + if(HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_WRITE)) + { + // + // Decrypt the data if required. + // +#ifdef BL_DECRYPT_FN_HOOK + BL_DECRYPT_FN_HOOK(g_pui8DFUWrite, g_ui16DFUBufferUsed); +#endif + + // + // Where will the new block be written? + // + ui32Start = (uint32_t)(g_sNextDownload.pui8Start); + +#ifndef FLASH_CODE_PROTECTION + // + // What is the address of the last byte we will write in this + // block of data? We copy g_ui16DFUBufferUsed to prevent warnings + // about "undefined order of volatile accesses" from some + // compilers. + // + ui16Used = g_ui16DFUBufferUsed; + + ui32End = (uint32_t)g_sNextDownload.pui8Start + ui16Used - 1; + + // + // Are we writing data at the start of a new flash block? If so, + // we need to erase the content of the block first. + // + if((ui32Start & (FLASH_PAGE_SIZE - 1)) == 0) + { + // + // We are writing to the start of a block so erase it. + // + EraseFlashBlock(ui32Start & ~(FLASH_PAGE_SIZE - 1)); + } + else + { + // + // Will this block of data straddle two flash blocks? If so, + // we need to erase the following block. + // + if((ui32Start & ~(FLASH_PAGE_SIZE - 1)) != + (ui32End & ~(FLASH_PAGE_SIZE - 1))) + { + EraseFlashBlock(ui32End & ~(FLASH_PAGE_SIZE - 1)); + } + } +#endif + + // + // Write the new block of data to the flash + // + BL_FLASH_PROGRAM_FN_HOOK(ui32Start, g_pui8DFUWrite, ui16Used); + + // + // Update our position and remaining size. + // + g_sNextDownload.pui8Start += ui16Used; + g_sNextDownload.ui32Length -= ui16Used; + + // + // Clear the command flag to indicate that we are done. + // + HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_WRITE) = 0; + + // + // If a progress hook function has been provided, call + // it here. + // +#ifdef BL_PROGRESS_FN_HOOK + BL_PROGRESS_FN_HOOK(g_ui32ImageSize - g_sNextDownload.ui32Length, + g_ui32ImageSize); +#endif + + // + // If we just finished the download and an end signal hook function + // has been provided, call it too. + // +#ifdef BL_END_FN_HOOK + if(g_sNextDownload.ui32Length == 0) + { + BL_END_FN_HOOK(); + } +#endif + } + } +} + +//***************************************************************************** +// +//! Configure the USB controller and place the DFU device on the bus. +//! +//! This function configures the USB controller for DFU device operation, +//! initializes the state machines required to control the firmware update and +//! places the device on the bus in preparation for requests from the host. It +//! is assumed that the main system clock has been configured at this point. +//! +//! \return None. +// +//***************************************************************************** +void +ConfigureUSBInterface(void) +{ + uint32_t ui32FlashSize; + + // + // Initialize our device information structure. + // + ui32FlashSize = BL_FLASH_SIZE_FN_HOOK(); + + g_sDFUDeviceInfo.ui16FlashBlockSize = DFU_REPORTED_PAGE_SIZE; + g_sDFUDeviceInfo.ui16NumFlashBlocks = + ui32FlashSize / DFU_REPORTED_PAGE_SIZE; + g_sDFUDeviceInfo.ui32ClassInfo = HWREG(SYSCTL_DID0); + g_sDFUDeviceInfo.ui32PartInfo = HWREG(SYSCTL_DID1); + g_sDFUDeviceInfo.ui32AppStartAddr = APP_START_ADDRESS; +#ifdef FLASH_RSVD_SPACE + g_sDFUDeviceInfo.ui32FlashTop = ui32FlashSize - FLASH_RSVD_SPACE; +#else + g_sDFUDeviceInfo.ui32FlashTop = ui32FlashSize; +#endif + + // + // Publish our DFU device descriptors and place the device on the bus. + // + USBBLInit(); +} + +#if (defined USB_HAS_MUX) || (defined DOXYGEN) +//***************************************************************************** +// +//! Configures and set the mux selecting USB device-mode operation. +//! +//! On target boards which use a multiplexer to switch between USB host and +//! device operation, this function is used to configure the relevant GPIO +//! pin and drive it such that the mux selects USB device-mode operation. +//! If \b USB_HAS_MUX is not defined in bl_config.h, this function is compiled +//! out. +//! +//! \return None. +// +//***************************************************************************** +static void +SetUSBMux(void) +{ + // + // Enable the GPIO peripheral that contains the mux control pin. + // + HWREG(SYSCTL_RCGC2) |= USB_MUX_PERIPH; + + // + // Delay a very short period before we access the newly-enabled peripheral. + // + Delay(1); + + // + // Make the pin be an output. + // + HWREG(USB_MUX_PORT + GPIO_O_DIR) |= (1 << USB_MUX_PIN); + HWREG(USB_MUX_PORT + GPIO_O_AFSEL) &= ~(1 << USB_MUX_PIN); + + // + // Set the output drive strength to 2mA. + // + HWREG(USB_MUX_PORT + GPIO_O_DR2R) |= (1 << USB_MUX_PIN); + HWREG(USB_MUX_PORT + GPIO_O_DR4R) &= ~(1 << USB_MUX_PIN); + HWREG(USB_MUX_PORT + GPIO_O_DR8R) &= ~(1 << USB_MUX_PIN); + HWREG(USB_MUX_PORT + GPIO_O_SLR) &= ~(1 << USB_MUX_PIN); + + // + // Set the pin type to a normal, GPIO output. + // + HWREG(USB_MUX_PORT + GPIO_O_ODR) &= ~(1 << USB_MUX_PIN); + HWREG(USB_MUX_PORT + GPIO_O_PUR) &= ~(1 << USB_MUX_PIN); + HWREG(USB_MUX_PORT + GPIO_O_PDR) &= ~(1 << USB_MUX_PIN); + HWREG(USB_MUX_PORT + GPIO_O_DEN) |= (1 << USB_MUX_PIN); + + // + // Clear this pin's bit in the analog mode select register. + // + HWREG(USB_MUX_PORT + GPIO_O_AMSEL) &= ~(1 << USB_MUX_PIN); + + // + // Write the pin to the appropriate level to select USB device mode. + // + HWREG(USB_MUX_PORT + (GPIO_O_DATA + ((1 << USB_MUX_PIN) << 2))) = + (USB_MUX_DEVICE ? (1 << USB_MUX_PIN) : 0); +} +#endif + +//***************************************************************************** +// +//! Generic configuration is handled in this function. +//! +//! This function is called by the start up code to perform any configuration +//! necessary before calling the update routine. It is responsible for setting +//! the system clock to the expected rate and setting flash programming +//! parameters prior to calling ConfigureUSBInterface() to set up the USB +//! hardware and place the DFU device on the bus. +//! +//! \return None. +// +//***************************************************************************** +void +ConfigureUSB(void) +{ + // + // Enable the main oscillator. + // + HWREG(SYSCTL_RCC) &= ~(SYSCTL_RCC_MOSCDIS); + + // + // Delay while the main oscillator starts up. + // + Delay(524288); + + // + // Set the crystal frequency, switch to the main oscillator, and enable the + // PLL. + // + HWREG(SYSCTL_RCC) = ((HWREG(SYSCTL_RCC) & + ~(SYSCTL_RCC_PWRDN | SYSCTL_RCC_XTAL_M | + SYSCTL_RCC_OSCSRC_M)) | + XTAL_VALUE | SYSCTL_RCC_OSCSRC_MAIN); + + // + // Delay while the PLL locks. + // + Delay(524288); + + // + // Disable the PLL bypass so that the part is clocked from the PLL, and set + // sysdiv to 8. This yields a system clock of 25MHz. + // + HWREG(SYSCTL_RCC) = ((HWREG(SYSCTL_RCC) & ~(SYSCTL_RCC_BYPASS | + SYSCTL_RCC_SYSDIV_M)) | + ((8 - 1) << SYSCTL_RCC_SYSDIV_S) | + SYSCTL_RCC_USESYSDIV); + + // + // If the target device has a mux to allow selection of USB host or + // device mode, make sure this is set to device mode. + // +#ifdef USB_HAS_MUX + SetUSBMux(); +#endif + + // + // Configure the USB interface and put the device on the bus. + // + ConfigureUSBInterface(); +} + +//***************************************************************************** +// +//! This is the application entry point to the USB updater. +//! +//! This function should only be entered from a running application and not +//! when running the boot loader with no application present. If the +//! calling application supports any USB device function, it must remove +//! itself from the USB bus prior to calling this function. This function +//! assumes that the calling application has already configured the system +//! clock to run from the PLL. +//! +//! \return None. +// +//***************************************************************************** +void +AppUpdaterUSB(void) +{ + // + // Set sysdiv to 8. This yields a system clock of 25MHz. + // + HWREG(SYSCTL_RCC) = ((HWREG(SYSCTL_RCC) & ~(SYSCTL_RCC_SYSDIV_M)) | + ((8 - 1) << SYSCTL_RCC_SYSDIV_S)); + + // + // If the target device has a mux to allow selection of USB host or + // device mode, make sure this is set to device mode. + // +#ifdef USB_HAS_MUX + SetUSBMux(); +#endif + + // + // Configure the USB interface and put the device on the bus. + // + ConfigureUSBInterface(); + + // + // Call the main update routine. + // + UpdaterUSB(); +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** +#endif diff --git a/boot_loader/bl_usbfuncs.c b/boot_loader/bl_usbfuncs.c new file mode 100644 index 0000000..552fabc --- /dev/null +++ b/boot_loader/bl_usbfuncs.c @@ -0,0 +1,1915 @@ +//***************************************************************************** +// +// bl_usbfuncs.c - The subset of USB library functions required by the USB DFU +// boot loader. +// +// Copyright (c) 2008-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_types.h" +#include "inc/hw_memmap.h" +#include "inc/hw_usb.h" +#include "inc/hw_sysctl.h" +#include "inc/hw_nvic.h" +#include "inc/hw_ints.h" +#include "inc/hw_gpio.h" +#include "bl_config.h" +#include "boot_loader/bl_usbfuncs.h" + +//***************************************************************************** +// +//! \addtogroup bl_usb_api +//! @{ +// +//***************************************************************************** +#if defined(USB_ENABLE_UPDATE) || defined(DOXYGEN) + +//***************************************************************************** +// +// Local functions prototypes. +// +//***************************************************************************** +static void USBDGetStatus(tUSBRequest *pUSBRequest); +static void USBDClearFeature(tUSBRequest *pUSBRequest); +static void USBDSetFeature(tUSBRequest *pUSBRequest); +static void USBDSetAddress(tUSBRequest *pUSBRequest); +static void USBDGetDescriptor(tUSBRequest *pUSBRequest); +static void USBDSetDescriptor(tUSBRequest *pUSBRequest); +static void USBDGetConfiguration(tUSBRequest *pUSBRequest); +static void USBDSetConfiguration(tUSBRequest *pUSBRequest); +static void USBDGetInterface(tUSBRequest *pUSBRequest); +static void USBDSetInterface(tUSBRequest *pUSBRequest); +static void USBDEP0StateTx(void); +static int32_t USBDStringIndexFromRequest(uint16_t ui16Lang, + uint16_t ui16Index); + +//***************************************************************************** +// +// This structure holds the full state for the device enumeration. +// +//***************************************************************************** +typedef struct +{ + // + // The devices current address, this also has a change pending bit in the + // MSB of this value specified by DEV_ADDR_PENDING. + // + volatile uint32_t ui32DevAddress; + + // + // This holds the current active configuration for this device. + // + uint32_t ui32Configuration; + + // + // This holds the current alternate interface for this device. We only have + // 1 interface so only need to hold 1 setting. + // + uint8_t ui8AltSetting; + + // + // This is the pointer to the current data being sent out or received + // on endpoint zero. + // + uint8_t *pui8EP0Data; + + // + // This is the number of bytes that remain to be sent from or received + // into the g_sUSBDeviceState.pui8EP0Data data buffer. + // + volatile uint32_t ui32EP0DataRemain; + + // + // The amount of data being sent/received due to a custom request. + // + uint32_t ui32OUTDataSize; + + // + // Holds the current device status. + // + uint8_t ui8Status; + + // + // This flag indicates whether or not remote wakeup signalling is in + // progress. + // + bool bRemoteWakeup; + + // + // During remote wakeup signalling, this counter is used to track the + // number of milliseconds since the signalling was initiated. + // + uint8_t ui8RemoteWakeupCount; +} +tDeviceState; + +//***************************************************************************** +// +// The states for endpoint zero during enumeration. +// +//***************************************************************************** +typedef enum +{ + // + // The USB device is waiting on a request from the host controller on + // endpoint zero. + // + USB_STATE_IDLE, + + // + // The USB device is sending data back to the host due to an IN request. + // + USB_STATE_TX, + + // + // The USB device is receiving data from the host due to an OUT + // request from the host. + // + USB_STATE_RX, + + // + // The USB device has completed the IN or OUT request and is now waiting + // for the host to acknowledge the end of the IN/OUT transaction. This + // is the status phase for a USB control transaction. + // + USB_STATE_STATUS, + + // + // This endpoint has signaled a stall condition and is waiting for the + // stall to be acknowledged by the host controller. + // + USB_STATE_STALL +} +tEP0State; + +//***************************************************************************** +// +// Define the max packet size for endpoint zero. +// +//***************************************************************************** +#define EP0_MAX_PACKET_SIZE 64 + +//***************************************************************************** +// +// This is a flag used with g_sUSBDeviceState.ui32DevAddress to indicate that a +// device address change is pending. +// +//***************************************************************************** +#define DEV_ADDR_PENDING 0x80000000 + +//***************************************************************************** +// +// This label defines the default configuration number to use after a bus +// reset. +// +//***************************************************************************** +#define DEFAULT_CONFIG_ID 1 + +//***************************************************************************** +// +// This label defines the number of milliseconds that the remote wakeup signal +// must remain asserted before removing it. Section 7.1.7.7 of the USB 2.0 spec +// states that "the remote wakeup device must hold the resume signaling for at +// least 1ms but for no more than 15ms" so 10mS seems a reasonable choice. +// +//***************************************************************************** +#define REMOTE_WAKEUP_PULSE_MS 10 + +//***************************************************************************** +// +// This label defines the number of milliseconds between the point where we +// assert the remote wakeup signal and calling the client back to tell it that +// bus operation has been resumed. This value is based on the timings provided +// in section 7.1.7.7 of the USB 2.0 specification which indicates that the host +// (which takes over resume signalling when the device's initial signal is +// detected) must hold the resume signalling for at least 20mS. +// +//***************************************************************************** +#define REMOTE_WAKEUP_READY_MS 20 + +//***************************************************************************** +// +// The buffer for reading data coming into EP0 +// +//***************************************************************************** +static uint8_t g_pui8DataBufferIn[EP0_MAX_PACKET_SIZE]; + +//***************************************************************************** +// +// This global holds the current state information for the USB device. +// +//***************************************************************************** +static volatile tDeviceState g_sUSBDeviceState; + +//***************************************************************************** +// +// This global holds the current state of endpoint zero. +// +//***************************************************************************** +static volatile tEP0State g_eUSBDEP0State = USB_STATE_IDLE; + +//***************************************************************************** +// +// Function table to handle standard requests. +// +//***************************************************************************** +static const tStdRequest g_ppfnUSBDStdRequests[] = +{ + USBDGetStatus, + USBDClearFeature, + 0, + USBDSetFeature, + 0, + USBDSetAddress, + USBDGetDescriptor, + USBDSetDescriptor, + USBDGetConfiguration, + USBDSetConfiguration, + USBDGetInterface, + USBDSetInterface, +}; + +//***************************************************************************** +// +// Amount to shift the RX interrupt sources by in the flags used in the +// interrupt calls. +// +//***************************************************************************** +#define USB_INT_RX_SHIFT 8 + +//***************************************************************************** +// +// Amount to shift the status interrupt sources by in the flags used in the +// interrupt calls. +// +//***************************************************************************** +#define USB_INT_STATUS_SHIFT 24 + +//***************************************************************************** +// +// Amount to shift the RX endpoint status sources by in the flags used in the +// calls. +// +//***************************************************************************** +#define USB_RX_EPSTATUS_SHIFT 16 + +//***************************************************************************** +// +// Converts from an endpoint specifier to the offset of the endpoint's +// control/status registers. +// +//***************************************************************************** +#define EP_OFFSET(Endpoint) (Endpoint - 0x10) + +//***************************************************************************** +// +// Retrieves data from endpoint 0's FIFO. +// +// \param pui8Data is a pointer to the data area used to return the data from +// the FIFO. +// \param pui32Size is initially the size of the buffer passed into this call +// via the \e pui8Data parameter. It will be set to the amount of data +// returned in the buffer. +// +// This function will return the data from the FIFO for endpoint 0. +// The \e pui32Size parameter should indicate the size of the buffer passed in +// the \e pui32Data parameter. The data in the \e pui32Size parameter will be +// changed to match the amount of data returned in the \e pui8Data parameter. +// If a zero byte packet was received this call will not return a error but +// will instead just return a zero in the \e pui32Size parameter. The only +// error case occurs when there is no data packet available. +// +// \return This call will return 0, or -1 if no packet was received. +// +//***************************************************************************** +int32_t +USBEndpoint0DataGet(uint8_t *pui8Data, uint32_t *pui32Size) +{ + uint32_t ui32ByteCount; + + // + // Don't allow reading of data if the RxPktRdy bit is not set. + // + if((HWREGH(USB0_BASE + USB_O_CSRL0) & USB_CSRL0_RXRDY) == 0) + { + // + // Can't read the data because none is available. + // + *pui32Size = 0; + + // + // Return a failure since there is no data to read. + // + return(-1); + } + + // + // Get the byte count in the FIFO. + // + ui32ByteCount = HWREGH(USB0_BASE + USB_O_COUNT0 + USB_EP_0); + + // + // Determine how many bytes we will actually copy. + // + ui32ByteCount = (ui32ByteCount < *pui32Size) ? ui32ByteCount : *pui32Size; + + // + // Return the number of bytes we are going to read. + // + *pui32Size = ui32ByteCount; + + // + // Read the data out of the FIFO. + // + for(; ui32ByteCount > 0; ui32ByteCount--) + { + // + // Read a byte at a time from the FIFO. + // + *pui8Data++ = HWREGB(USB0_BASE + USB_O_FIFO0 + (USB_EP_0 >> 2)); + } + + // + // Success. + // + return(0); +} + +//***************************************************************************** +// +// Acknowledge that data was read from endpoint 0's FIFO. +// +// \param bIsLastPacket indicates if this is the last packet. +// +// This function acknowledges that the data was read from the endpoint 0's +// FIFO. The \e bIsLastPacket parameter is set to a \b true value if this is +// the last in a series of data packets. This call can be used if processing +// is required between reading the data and acknowledging that the data has +// been read. +// +// \return None. +// +//***************************************************************************** +void +USBDevEndpoint0DataAck(bool bIsLastPacket) +{ + // + // Clear RxPktRdy, and optionally DataEnd, on endpoint zero. + // + HWREGB(USB0_BASE + USB_O_CSRL0) = + USB_CSRL0_RXRDYC | (bIsLastPacket ? USB_CSRL0_DATAEND : 0); + +} + +//***************************************************************************** +// +// Puts data into endpoint 0's FIFO. +// +// \param pui8Data is a pointer to the data area used as the source for the +// data to put into the FIFO. +// \param ui32Size is the amount of data to put into the FIFO. +// +// This function will put the data from the \e pui8Data parameter into the FIFO +// for endpoint 0. If a packet is already pending for transmission then +// this call will not put any of the data into the FIFO and will return -1. +// +// \return This call will return 0 on success, or -1 to indicate that the FIFO +// is in use and cannot be written. +// +//***************************************************************************** +int32_t +USBEndpoint0DataPut(uint8_t *pui8Data, uint32_t ui32Size) +{ + // + // Don't allow transmit of data if the TxPktRdy bit is already set. + // + if(HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) & USB_CSRL0_TXRDY) + { + return(-1); + } + + // + // Write the data to the FIFO. + // + for(; ui32Size > 0; ui32Size--) + { + HWREGB(USB0_BASE + USB_O_FIFO0 + (USB_EP_0 >> 2)) = *pui8Data++; + } + + // + // Success. + // + return(0); +} + +//***************************************************************************** +// +// Starts the transfer of data from endpoint 0's FIFO. +// +// \param ui32TransType is set to indicate what type of data is being sent. +// +// This function will start the transfer of data from the FIFO for +// endpoint 0. This is necessary if the \b USB_EP_AUTO_SET bit was not enabled +// for the endpoint. Setting the \e ui32TransType parameter will allow the +// appropriate signaling on the USB bus for the type of transaction being +// requested. The \e ui32TransType parameter should be one of the following: +// +// - USB_TRANS_OUT for OUT transaction on any endpoint in host mode. +// - USB_TRANS_IN for IN transaction on any endpoint in device mode. +// - USB_TRANS_IN_LAST for the last IN transactions on endpoint zero in a +// sequence of IN transactions. +// - USB_TRANS_SETUP for setup transactions on endpoint zero. +// - USB_TRANS_STATUS for status results on endpoint zero. +// +// \return This call will return 0 on success, or -1 if a transmission is +// already in progress. +// +//***************************************************************************** +int32_t +USBEndpoint0DataSend(uint32_t ui32TransType) +{ + // + // Don't allow transmit of data if the TxPktRdy bit is already set. + // + if(HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) & USB_CSRL0_TXRDY) + { + return(-1); + } + + // + // Set TxPktRdy in order to send the data. + // + HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) = ui32TransType & 0xff; + + // + // Success. + // + return(0); +} + +#if defined(USB_VBUS_CONFIG) || defined(USB_ID_CONFIG) || \ + defined(USB_DP_CONFIG) || defined(USB_DM_CONFIG) || defined(DOXYGEN) +//***************************************************************************** +// +//! Initialize the pins used by USB functions. +//! +//! This function configures the pins for USB functions depending on defines +//! from the bl_config.h file. +//! +//! \return None. +// +//***************************************************************************** +void +USBConfigurePins(void) +{ + // + // Enable the clocks to the GPIOs. + // + HWREG(SYSCTL_RCGCGPIO) |= (0x0 +#if defined(USB_VBUS_CONFIG) + | USB_VBUS_PERIPH +#endif +#if defined(USB_ID_CONFIG) + | USB_ID_PERIPH +#endif +#if defined(USB_DP_CONFIG) + | USB_DP_PERIPH +#endif +#if defined(USB_DM_CONFIG) + | USB_DM_PERIPH +#endif + ); + + // + // Setup the pins based on bl_config.h + // +#if defined(USB_VBUS_CONFIG) + // + // Set the VBUS pin to be an analog input. + // + HWREG(USB_VBUS_PORT + GPIO_O_DIR) &= ~(1 << USB_VBUS_PIN); + HWREG(USB_VBUS_PORT + GPIO_O_AMSEL) |= (1 << USB_VBUS_PIN); +#endif + +#if defined(USB_ID_CONFIG) + // + // Set the ID pin to be an analog input. + // + HWREG(USB_ID_PORT + GPIO_O_DIR) &= ~(1 << USB_ID_PIN); + HWREG(USB_ID_PORT + GPIO_O_AMSEL) |= (1 << USB_ID_PIN); +#endif + +#if defined(USB_DP_CONFIG) + // + // Set the DP pin to be an analog input. + // + HWREG(USB_DP_PORT + GPIO_O_DIR) &= ~(1 << USB_DP_PIN); + HWREG(USB_DP_PORT + GPIO_O_AMSEL) |= (1 << USB_DP_PIN); +#endif + +#if defined(USB_DM_CONFIG) + // + // Set the DM pin to be an analog input. + // + HWREG(USB_DM_PORT + GPIO_O_DIR) &= ~(1 << USB_DM_PIN); + HWREG(USB_DM_PORT + GPIO_O_AMSEL) |= (1 << USB_DM_PIN); +#endif + +} +#endif + +//***************************************************************************** +// +//! Initialize the boot loader USB functions. +//! +//! This function initializes the boot loader USB functions and places the DFU +//! device onto the USB bus. +//! +//! \return None. +// +//***************************************************************************** +void +USBBLInit(void) +{ + // + // Configure the USB Pins based on the bl_config.h settings. + // +#if defined(USB_VBUS_CONFIG) || defined(USB_ID_CONFIG) || \ + defined(USB_DP_CONFIG) || defined(USB_DM_CONFIG) + USBConfigurePins(); +#endif + + // + // Initialize a couple of fields in the device state structure. + // + g_sUSBDeviceState.ui32Configuration = DEFAULT_CONFIG_ID; + + // + // Enable the USB controller. + // + HWREG(SYSCTL_RCGC2) |= 0x10000; + + // + // Turn on USB Phy clock. + // + HWREG(SYSCTL_RCC2) &= ~SYSCTL_RCC2_USBPWRDN; + + // + // Clear any pending interrupts. + // + HWREGH(USB0_BASE + USB_O_TXIS); + HWREGB(USB0_BASE + USB_O_IS); + + // + // Enable USB Interrupts. + // + HWREGH(USB0_BASE + USB_O_TXIE) = USB_TXIS_EP0; + HWREGB(USB0_BASE + USB_O_IE) = (USB_IS_DISCON | USB_IS_RESET); + + // + // Default to the state where remote wakeup is disabled. + // + g_sUSBDeviceState.ui8Status = 0; + g_sUSBDeviceState.bRemoteWakeup = false; + + // + // Determine the self- or bus-powered state based on bl_config.h setting. + // +#if USB_BUS_POWERED + g_sUSBDeviceState.ui8Status &= ~USB_STATUS_SELF_PWR; +#else + g_sUSBDeviceState.ui8Status |= USB_STATUS_SELF_PWR; +#endif + + // + // Attach the device using the soft connect. + // + HWREGB(USB0_BASE + USB_O_POWER) |= USB_POWER_SOFTCONN; + + // + // Enable the USB interrupt. + // + HWREG(NVIC_EN1) = 1 << (INT_USB0 - 48); +} + +//***************************************************************************** +// +// This function starts the request for data from the host on endpoint zero. +// +// \param pui8Data is a pointer to the buffer to fill with data from the USB +// host. +// \param ui32Size is the size of the buffer or data to return from the USB +// host. +// +// This function handles retrieving data from the host when a custom command +// has been issued on endpoint zero. When the requested data is received, +// the function HandleEP0Data() will be called. +// +// \return None. +// +//***************************************************************************** +void +USBBLRequestDataEP0(uint8_t *pui8Data, uint32_t ui32Size) +{ + // + // Enter the RX state on end point 0. + // + g_eUSBDEP0State = USB_STATE_RX; + + // + // Save the pointer to the data. + // + g_sUSBDeviceState.pui8EP0Data = pui8Data; + + // + // Location to save the current number of bytes received. + // + g_sUSBDeviceState.ui32OUTDataSize = ui32Size; + + // + // Bytes remaining to be received. + // + g_sUSBDeviceState.ui32EP0DataRemain = ui32Size; +} + +//***************************************************************************** +// +//! This function requests transfer of data to the host on endpoint zero. +//! +//! \param pui8Data is a pointer to the buffer to send via endpoint zero. +//! \param ui32Size is the amount of data to send in bytes. +//! +//! This function handles sending data to the host when a custom command is +//! issued or non-standard descriptor has been requested on endpoint zero. +//! +//! \return None. +// +//***************************************************************************** +void +USBBLSendDataEP0(uint8_t *pui8Data, uint32_t ui32Size) +{ + // + // Return the externally provided device descriptor. + // + g_sUSBDeviceState.pui8EP0Data = pui8Data; + + // + // The size of the device descriptor is in the first byte. + // + g_sUSBDeviceState.ui32EP0DataRemain = ui32Size; + + // + // Save the total size of the data sent. + // + g_sUSBDeviceState.ui32OUTDataSize = ui32Size; + + // + // Now in the transmit data state. + // + USBDEP0StateTx(); +} + +//***************************************************************************** +// +//! This function generates a stall condition on endpoint zero. +//! +//! This function is typically called to signal an error condition to the host +//! when an unsupported request is received by the device. It should be +//! called from within the callback itself (in interrupt context) and not +//! deferred until later since it affects the operation of the endpoint zero +//! state machine. +//! +//! \return None. +// +//***************************************************************************** +void +USBBLStallEP0(void) +{ + // + // Perform a stall on endpoint zero. + // + HWREGB(USB0_BASE + USB_O_CSRL0) |= (USB_CSRL0_STALL | USB_CSRL0_RXRDYC); + + // + // Enter the stalled state. + // + g_eUSBDEP0State = USB_STATE_STALL; +} + +//***************************************************************************** +// +// This internal function reads a request data packet and dispatches it to +// either a standard request handler or the registered device request +// callback depending upon the request type. +// +// \return None. +// +//***************************************************************************** +static void +USBDReadAndDispatchRequest(void) +{ + uint32_t ui32Size; + tUSBRequest *pRequest; + + // + // Cast the buffer to a request structure. + // + pRequest = (tUSBRequest *)g_pui8DataBufferIn; + + // + // Set the buffer size. + // + ui32Size = EP0_MAX_PACKET_SIZE; + + // + // Get the data from the USB controller end point 0. + // + USBEndpoint0DataGet(g_pui8DataBufferIn, &ui32Size); + + if(!ui32Size) + { + return; + } + + // + // See if this is a standard request or not. + // + if((pRequest->bmRequestType & USB_RTYPE_TYPE_M) != USB_RTYPE_STANDARD) + { + // + // Pass this non-standard request on to the DFU handler + // + HandleRequests(pRequest); + } + else + { + // + // Assure that the jump table is not out of bounds. + // + if((pRequest->bRequest < + (sizeof(g_ppfnUSBDStdRequests) / sizeof(tStdRequest))) && + (g_ppfnUSBDStdRequests[pRequest->bRequest] != 0)) + { + // + // Jump table to the appropriate handler. + // + g_ppfnUSBDStdRequests[pRequest->bRequest](pRequest); + } + else + { + // + // If there is no handler then stall this request. + // + USBBLStallEP0(); + } + } +} + +//***************************************************************************** +// +// This is the low level interrupt handler for endpoint zero. +// +// This function handles all interrupts on endpoint zero in order to maintain +// the state needed for the control endpoint on endpoint zero. In order to +// successfully enumerate and handle all USB standard requests, all requests +// on endpoint zero must pass through this function. The endpoint has the +// following states: \b USB_STATE_IDLE, \b USB_STATE_TX, \b USB_STATE_RX, +// \b USB_STATE_STALL, and \b USB_STATE_STATUS. In the \b USB_STATE_IDLE +// state the USB controller has not received the start of a request, and once +// it does receive the data for the request it will either enter the +// \b USB_STATE_TX, \b USB_STATE_RX, or \b USB_STATE_STALL depending on the +// command. If the controller enters the \b USB_STATE_TX or \b USB_STATE_RX +// then once all data has been sent or received, it must pass through the +// \b USB_STATE_STATUS state to allow the host to acknowledge completion of +// the request. The \b USB_STATE_STALL is entered from \b USB_STATE_IDLE in +// the event that the USB request was not valid. Both the \b USB_STATE_STALL +// and \b USB_STATE_STATUS are transitional states that return to the +// \b USB_STATE_IDLE state. +// +// \return None. +// +// USB_STATE_IDLE -*--> USB_STATE_TX -*-> USB_STATE_STATUS -*->USB_STATE_IDLE +// | | | +// |--> USB_STATE_RX - | +// | | +// |--> USB_STATE_STALL ---------->--------- +// +// ---------------------------------------------------------------- +// | Current State | State 0 | State 1 | +// | --------------------|-------------------|---------------------- +// | USB_STATE_IDLE | USB_STATE_TX/RX | USB_STATE_STALL | +// | USB_STATE_TX | USB_STATE_STATUS | | +// | USB_STATE_RX | USB_STATE_STATUS | | +// | USB_STATE_STATUS | USB_STATE_IDLE | | +// | USB_STATE_STALL | USB_STATE_IDLE | | +// ---------------------------------------------------------------- +// +//***************************************************************************** +void +USBDeviceEnumHandler(void) +{ + uint32_t ui32EPStatus; + + // + // Get the TX portion of the endpoint status. + // + ui32EPStatus = HWREGH(USB0_BASE + EP_OFFSET(USB_EP_0) + USB_O_TXCSRL1); + + // + // Get the RX portion of the endpoint status. + // + ui32EPStatus |= + ((HWREGH(USB0_BASE + EP_OFFSET(USB_EP_0) + USB_O_RXCSRL1)) << + USB_RX_EPSTATUS_SHIFT); + + // + // What state are we currently in? + // + switch(g_eUSBDEP0State) + { + // + // Handle the status state, this is a transitory state from + // USB_STATE_TX or USB_STATE_RX back to USB_STATE_IDLE. + // + case USB_STATE_STATUS: + { + // + // Just go back to the idle state. + // + g_eUSBDEP0State = USB_STATE_IDLE; + + // + // If there is a pending address change then set the address. + // + if(g_sUSBDeviceState.ui32DevAddress & DEV_ADDR_PENDING) + { + // + // Clear the pending address change and set the address. + // + g_sUSBDeviceState.ui32DevAddress &= ~DEV_ADDR_PENDING; + HWREGB(USB0_BASE + USB_O_FADDR) = + (uint8_t)g_sUSBDeviceState.ui32DevAddress; + } + + // + // If a new packet is already pending, we need to read it + // and handle whatever request it contains. + // + if(ui32EPStatus & USB_DEV_EP0_OUT_PKTRDY) + { + // + // Process the newly arrived packet. + // + USBDReadAndDispatchRequest(); + } + break; + } + + // + // In the IDLE state the code is waiting to receive data from the host. + // + case USB_STATE_IDLE: + { + // + // Is there a packet waiting for us? + // + if(ui32EPStatus & USB_DEV_EP0_OUT_PKTRDY) + { + // + // Yes - process it. + // + USBDReadAndDispatchRequest(); + } + break; + } + + // + // Data is still being sent to the host so handle this in the + // EP0StateTx() function. + // + case USB_STATE_TX: + { + USBDEP0StateTx(); + break; + } + + // + // Handle the receive state for commands that are receiving data on + // endpoint zero. + // + case USB_STATE_RX: + { + uint32_t ui32DataSize; + + // + // Set the number of bytes to get out of this next packet. + // + if(g_sUSBDeviceState.ui32EP0DataRemain > EP0_MAX_PACKET_SIZE) + { + // + // Don't send more than EP0_MAX_PACKET_SIZE bytes. + // + ui32DataSize = EP0_MAX_PACKET_SIZE; + } + else + { + // + // There was space so send the remaining bytes. + // + ui32DataSize = g_sUSBDeviceState.ui32EP0DataRemain; + } + + // + // Get the data from the USB controller end point 0. + // + USBEndpoint0DataGet(g_sUSBDeviceState.pui8EP0Data, &ui32DataSize); + + // + // If there we not more that EP0_MAX_PACKET_SIZE or more bytes + // remaining then this transfer is complete. If there were exactly + // EP0_MAX_PACKET_SIZE remaining then there still needs to be + // null packet sent before this is complete. + // + if(g_sUSBDeviceState.ui32EP0DataRemain < EP0_MAX_PACKET_SIZE) + { + // + // Need to ack the data on end point 0 in this case + // without setting data end. + // + USBDevEndpoint0DataAck(true); + + // + // Return to the idle state. + // + g_eUSBDEP0State = USB_STATE_IDLE; + + // + // If there is a receive callback then call it. + // + if(g_sUSBDeviceState.ui32OUTDataSize != 0) + { + // + // Call the receive handler to handle the data + // that was received. + // + HandleEP0Data(g_sUSBDeviceState.ui32OUTDataSize); + + // + // Indicate that there is no longer any data being waited + // on. + // + g_sUSBDeviceState.ui32OUTDataSize = 0; + } + } + else + { + // + // Need to ack the data on end point 0 in this case + // without setting data end. + // + USBDevEndpoint0DataAck(false); + } + + // + // Advance the pointer. + // + g_sUSBDeviceState.pui8EP0Data += ui32DataSize; + + // + // Decrement the number of bytes that are being waited on. + // + g_sUSBDeviceState.ui32EP0DataRemain -= ui32DataSize; + + break; + } + // + // The device stalled endpoint zero so check if the stall needs to be + // cleared once it has been successfully sent. + // + case USB_STATE_STALL: + { + // + // If we sent a stall then acknowledge this interrupt. + // + if(ui32EPStatus & USB_DEV_EP0_SENT_STALL) + { + // + // Clear the stall condition. + // + HWREGB(USB0_BASE + USB_O_CSRL0) &= ~(USB_DEV_EP0_SENT_STALL); + + // + // Reset the global end point 0 state to IDLE. + // + g_eUSBDEP0State = USB_STATE_IDLE; + + } + break; + } + // + // Halt on an unknown state, but only in DEBUG mode builds. + // + default: + { +#ifdef DEBUG + while(1); +#endif + break; + } + } +} + +//***************************************************************************** +// +// This function handles bus reset notifications. +// +// This function is called from the low level USB interrupt handler whenever +// a bus reset is detected. It performs tidy-up as required and resets the +// configuration back to defaults in preparation for descriptor queries from +// the host. +// +// \return None. +// +//***************************************************************************** +void +USBDeviceEnumResetHandler(void) +{ + // + // Disable remote wakeup signalling (as per USB 2.0 spec 9.1.1.6). + // + g_sUSBDeviceState.ui8Status &= ~USB_STATUS_REMOTE_WAKE; + g_sUSBDeviceState.bRemoteWakeup = false; + + // + // Call the device dependent code to indicate a bus reset has occurred. + // + HandleReset(); + + // + // Reset the default configuration identifier and alternate function + // selections. + // + g_sUSBDeviceState.ui32Configuration = DEFAULT_CONFIG_ID; + g_sUSBDeviceState.ui8AltSetting = 0; +} + +//***************************************************************************** +// +// This function handles the GET_STATUS standard USB request. +// +// \param pUSBRequest holds the request type and endpoint number if endpoint +// status is requested. +// +// This function handles responses to a Get Status request from the host +// controller. A status request can be for the device, an interface or an +// endpoint. If any other type of request is made this function will cause +// a stall condition to indicate that the command is not supported. The +// \e pUSBRequest structure holds the type of the request in the +// bmRequestType field. If the type indicates that this is a request for an +// endpoint's status, then the wIndex field holds the endpoint number. +// +// \return None. +// +//***************************************************************************** +static void +USBDGetStatus(tUSBRequest *pUSBRequest) +{ + uint16_t ui16Data; + + // + // Determine what type of status was requested. + // + switch(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M) + { + // + // This was a Device Status request. + // + case USB_RTYPE_DEVICE: + { + // + // Return the current status for the device. + // + ui16Data = g_sUSBDeviceState.ui8Status; + + break; + } + + // + // This was a Interface status request. + // + case USB_RTYPE_INTERFACE: + { + // + // Interface status always returns 0. + // + ui16Data = 0; + + break; + } + + // + // This was an unknown request or a request for an endpoint (of which + // we have none) so set a stall. + // + case USB_RTYPE_ENDPOINT: + default: + { + // + // Anything else causes a stall condition to indicate that the + // command was not supported. + // + USBBLStallEP0(); + return; + } + } + + // + // Send the two byte status response. + // + g_sUSBDeviceState.ui32EP0DataRemain = 2; + g_sUSBDeviceState.pui8EP0Data = (uint8_t *)&ui16Data; + + // + // Send the response. + // + USBDEP0StateTx(); +} + +//***************************************************************************** +// +// This function handles the CLEAR_FEATURE standard USB request. +// +// \param pUSBRequest holds the options for the Clear Feature USB request. +// +// This function handles device or endpoint clear feature requests. The +// \e pUSBRequest structure holds the type of the request in the bmRequestType +// field and the feature is held in the wValue field. For device, the only +// clearable feature is the Remote Wake feature. This device request +// should only be made if the descriptor indicates that Remote Wake is +// implemented by the device. For endpoint requests the only clearable +// feature is the ability to clear a halt on a given endpoint. If any other +// requests are made, then the device will stall the request to indicate to +// the host that the command was not supported. +// +// \return None. +// +//***************************************************************************** +static void +USBDClearFeature(tUSBRequest *pUSBRequest) +{ + // + // Determine what type of status was requested. + // + switch(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M) + { + // + // This is a clear feature request at the device level. + // + case USB_RTYPE_DEVICE: + { + // + // Only remote wake is clearable by this function. + // + if(USB_FEATURE_REMOTE_WAKE & pUSBRequest->wValue) + { + // + // Clear the remote wake up state. + // + g_sUSBDeviceState.ui8Status &= ~USB_STATUS_REMOTE_WAKE; + + // + // Need to ack the data on end point 0. + // + USBDevEndpoint0DataAck(true); + } + else + { + USBBLStallEP0(); + } + break; + } + + // + // This is an unknown request or one destined for an invalid endpoint. + // + case USB_RTYPE_ENDPOINT: + default: + { + USBBLStallEP0(); + return; + } + } +} + +//***************************************************************************** +// +// This function handles the SET_FEATURE standard USB request. +// +// \param pUSBRequest holds the feature in the wValue field of the USB +// request. +// +// This function handles device or endpoint set feature requests. The +// \e pUSBRequest structure holds the type of the request in the bmRequestType +// field and the feature is held in the wValue field. For device, the only +// settable feature is the Remote Wake feature. This device request +// should only be made if the descriptor indicates that Remote Wake is +// implemented by the device. For endpoint requests the only settable feature +// is the ability to issue a halt on a given endpoint. If any other requests +// are made, then the device will stall the request to indicate to the host +// that the command was not supported. +// +// \return None. +// +//***************************************************************************** +static void +USBDSetFeature(tUSBRequest *pUSBRequest) +{ + // + // Determine what type of status was requested. + // + switch(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M) + { + // + // This is a set feature request at the device level. + // + case USB_RTYPE_DEVICE: + { + // + // Only remote wake is setable by this function. + // + if(USB_FEATURE_REMOTE_WAKE & pUSBRequest->wValue) + { + // + // Set the remote wakeup state. + // + g_sUSBDeviceState.ui8Status |= USB_STATUS_REMOTE_WAKE; + + // + // Need to ack the data on end point 0. + // + USBDevEndpoint0DataAck(true); + } + else + { + USBBLStallEP0(); + } + break; + } + + // + // This is an unknown request or one destined for an invalid endpoint. + // + case USB_RTYPE_ENDPOINT: + default: + { + USBBLStallEP0(); + return; + } + } +} + +//***************************************************************************** +// +// This function handles the SET_ADDRESS standard USB request. +// +// \param pUSBRequest holds the new address to use in the wValue field of the +// USB request. +// +// This function is called to handle the change of address request from the +// host controller. This can only start the sequence as the host must +// acknowledge that the device has changed address. Thus this function sets +// the address change as pending until the status phase of the request has +// been completed successfully. This prevents the devices address from +// changing and not properly responding to the status phase. +// +// \return None. +// +//***************************************************************************** +static void +USBDSetAddress(tUSBRequest *pUSBRequest) +{ + // + // The data needs to be acknowledged on end point 0 without setting data + // end because there is no data coming. + // + USBDevEndpoint0DataAck(true); + + // + // Save the device address as we cannot change address until the status + // phase is complete. + // + g_sUSBDeviceState.ui32DevAddress = pUSBRequest->wValue | DEV_ADDR_PENDING; + + // + // Transition directly to the status state since there is no data phase + // for this request. + // + g_eUSBDEP0State = USB_STATE_STATUS; + + // + // Clear the DFU status just in case we were in an error state last time + // the device was accessed and we were unplugged and replugged (for a self- + // powered implementation, of course). + // + HandleSetAddress(); +} + +//***************************************************************************** +// +// This function handles the GET_DESCRIPTOR standard USB request. +// +// \param pUSBRequest holds the data for this request. +// +// This function will return all configured standard USB descriptors to the +// host - device, config and string descriptors. Any request for a descriptor +// which is not available will result in endpoint 0 being stalled. +// +// \return None. +// +//***************************************************************************** +static void +USBDGetDescriptor(tUSBRequest *pUSBRequest) +{ + uint32_t ui32Stall; + + // + // Default to no stall. + // + ui32Stall = 0; + + // + // Which descriptor are we being asked for? + // + switch(pUSBRequest->wValue >> 8) + { + // + // This request was for a device descriptor. + // + case USB_DTYPE_DEVICE: + { + // + // Return the externally provided device descriptor. + // + g_sUSBDeviceState.pui8EP0Data = + (uint8_t *)g_pui8DFUDeviceDescriptor; + + // + // The size of the device descriptor is in the first byte. + // + g_sUSBDeviceState.ui32EP0DataRemain = + g_pui8DFUDeviceDescriptor[0]; + break; + } + + // + // This request was for a configuration descriptor. + // + case USB_DTYPE_CONFIGURATION: + { + uint8_t ui8Index; + + // + // Which configuration are we being asked for? + // + ui8Index = (uint8_t)(pUSBRequest->wValue & 0xFF); + + // + // Is this valid? + // + if(ui8Index != 0) + { + // + // This is an invalid configuration index. Stall EP0 to + // indicate a request error. + // + USBBLStallEP0(); + g_sUSBDeviceState.pui8EP0Data = 0; + g_sUSBDeviceState.ui32EP0DataRemain = 0; + } + else + { + // + // Start by sending data from the beginning of the first + // descriptor. + // + + g_sUSBDeviceState.pui8EP0Data = + (uint8_t *)g_pui8DFUConfigDescriptor; + + // + // Get the size of the config descriptor (remembering that in + // this case, we only have a single section) + // + g_sUSBDeviceState.ui32EP0DataRemain = + *(uint16_t *)&(g_pui8DFUConfigDescriptor[2]); + } + break; + } + + // + // This request was for a string descriptor. + // + case USB_DTYPE_STRING: + { + int32_t i32Index; + + // + // Determine the correct descriptor index based on the requested + // language ID and index. + // + i32Index = USBDStringIndexFromRequest(pUSBRequest->wIndex, + pUSBRequest->wValue & 0xFF); + + // + // If the mapping function returned -1 then stall the request to + // indicate that the request was not valid. + // + if(i32Index == -1) + { + USBBLStallEP0(); + break; + } + + // + // Return the externally specified configuration descriptor. + // + g_sUSBDeviceState.pui8EP0Data = + (uint8_t *)g_ppui8StringDescriptors[i32Index]; + + // + // The total size of a string descriptor is in byte 0. + // + g_sUSBDeviceState.ui32EP0DataRemain = + g_ppui8StringDescriptors[i32Index][0]; + + break; + } + + // + // Any other request is not handled by the default enumeration handler + // so see if it needs to be passed on to another handler. + // + default: + { + // + // All other requests are not handled. + // + USBBLStallEP0(); + ui32Stall = 1; + break; + } + } + + // + // If there was no stall, ACK the data and see if data needs to be sent. + // + if(ui32Stall == 0) + { + // + // Need to ack the data on end point 0 in this case without + // setting data end. + // + USBDevEndpoint0DataAck(false); + + // + // If this request has data to send, then send it. + // + if(g_sUSBDeviceState.pui8EP0Data) + { + // + // If there is more data to send than is requested then just + // send the requested amount of data. + // + if(g_sUSBDeviceState.ui32EP0DataRemain > pUSBRequest->wLength) + { + g_sUSBDeviceState.ui32EP0DataRemain = pUSBRequest->wLength; + } + + // + // Now in the transmit data state. Be careful to call the correct + // function since we need to handle the config descriptor + // differently from the others. + // + USBDEP0StateTx(); + } + } +} + +//***************************************************************************** +// +// This function determines which string descriptor to send to satisfy a +// request for a given index and language. +// +// \param ui16Lang is the requested string language ID. +// \param ui16Index is the requested string descriptor index. +// +// When a string descriptor is requested, the host provides a language ID and +// index to identify the string ("give me string number 5 in French"). This +// function maps these two parameters to an index within our device's string +// descriptor array which is arranged as multiple groups of strings with +// one group for each language advertised via string descriptor 0. +// +// We assume that there are an equal number of strings per language and +// that the first descriptor is the language descriptor and use this fact to +// perform the mapping. +// +// \return The index of the string descriptor to return or -1 if the string +// could not be found. +// +//***************************************************************************** +static int32_t +USBDStringIndexFromRequest(uint16_t ui16Lang, uint16_t ui16Index) +{ + tString0Descriptor *pLang; + uint32_t ui32NumLangs; + uint32_t ui32NumStringsPerLang; + uint32_t ui32Loop; + + // + // First look for the trivial case where descriptor 0 is being + // requested. This is the special case since descriptor 0 contains the + // language codes supported by the device. + // + if(ui16Index == 0) + { + return(0); + } + + // + // How many languages does this device support? This is determined by + // looking at the length of the first descriptor in the string table, + // subtracting 2 for the header and dividing by two (the size of each + // language code). + // + ui32NumLangs = (g_ppui8StringDescriptors[0][0] - 2) / 2; + + // + // We assume that the table includes the same number of strings for each + // supported language. We know the number of entries in the string table, + // so how many are there for each language? This may seem an odd way to + // do this (why not just have the application tell us in the device info + // structure?) but it's needed since we didn't want to change the API + // after the first release which did not support multiple languages. + // + ui32NumStringsPerLang = ((NUM_STRING_DESCRIPTORS - 1) / ui32NumLangs); + + // + // Just to be sure, make sure that the calculation indicates an equal + // number of strings per language. We expect the string table to contain + // (1 + (strings_per_language * languages)) entries. + // + if((1 + (ui32NumStringsPerLang * ui32NumLangs)) != NUM_STRING_DESCRIPTORS) + { + return(-1); + } + + // + // Now determine which language we are looking for. It is assumed that + // the order of the groups of strings per language in the table is the + // same as the order of the language IDs listed in the first descriptor. + // + pLang = (tString0Descriptor *)(g_ppui8StringDescriptors[0]); + + // + // Look through the supported languages looking for the one we were asked + // for. + // + for(ui32Loop = 0; ui32Loop < ui32NumLangs; ui32Loop++) + { + // + // Have we found the requested language? + // + if(pLang->wLANGID[ui32Loop] == ui16Lang) + { + // + // Yes - calculate the index of the descriptor to send. + // + return((ui32NumStringsPerLang * ui32Loop) + ui16Index); + } + } + + // + // If we drop out of the loop, the requested language was not found so + // return -1 to indicate the error. + // + return(-1); +} + +//***************************************************************************** +// +// This function handles the SET_DESCRIPTOR standard USB request. +// +// \param pUSBRequest holds the data for this request. +// +// This function currently is not supported and will respond with a Stall +// to indicate that this command is not supported by the device. +// +// \return None. +// +//***************************************************************************** +static void +USBDSetDescriptor(tUSBRequest *pUSBRequest) +{ + // + // This function is not handled by default. + // + USBBLStallEP0(); +} + +//***************************************************************************** +// +// This function handles the GET_CONFIGURATION standard USB request. +// +// \param pUSBRequest holds the data for this request. +// +// This function responds to a host request to return the current +// configuration of the USB device. The function will send the configuration +// response to the host and return. This value will either be 0 or the last +// value received from a call to SetConfiguration(). +// +// \return None. +// +//***************************************************************************** +static void +USBDGetConfiguration(tUSBRequest *pUSBRequest) +{ + uint8_t ui8Value; + + // + // If we still have an address pending then the device is still not + // configured. + // + if(g_sUSBDeviceState.ui32DevAddress & DEV_ADDR_PENDING) + { + ui8Value = 0; + } + else + { + ui8Value = (uint8_t)g_sUSBDeviceState.ui32Configuration; + } + + g_sUSBDeviceState.ui32EP0DataRemain = 1; + g_sUSBDeviceState.pui8EP0Data = &ui8Value; + + // + // Send the single byte response. + // + USBDEP0StateTx(); +} + +//***************************************************************************** +// +// This function handles the SET_CONFIGURATION standard USB request. +// +// \param pUSBRequest holds the data for this request. +// +// This function responds to a host request to change the current +// configuration of the USB device. The actual configuration number is taken +// from the structure passed in via \e pUSBRequest. +// +// \return None. +// +//***************************************************************************** +static void +USBDSetConfiguration(tUSBRequest *pUSBRequest) +{ + // + // Cannot set the configuration to one that does not exist so check the + // enumeration structure to see how many valid configurations are present. + // + if(pUSBRequest->wValue > 1) + { + // + // The passed configuration number is not valid. Stall the endpoint to + // signal the error to the host. + // + USBBLStallEP0(); + } + else + { + // + // Need to ack the data on end point 0. + // + USBDevEndpoint0DataAck(true); + + // + // Save the configuration. + // + g_sUSBDeviceState.ui32Configuration = pUSBRequest->wValue; + + // + // If passed a configuration other than 0 (which tells us that we are + // not currently configured), configure the endpoints (other than EP0) + // appropriately. + // + if(g_sUSBDeviceState.ui32Configuration) + { + // + // Set the power state + // +#if USB_BUS_POWERED + g_sUSBDeviceState.ui8Status &= ~USB_STATUS_SELF_PWR; +#else + g_sUSBDeviceState.ui8Status |= USB_STATUS_SELF_PWR; +#endif + } + + // + // Do whatever needs to be done as a result of the config change. + // + HandleConfigChange(g_sUSBDeviceState.ui32Configuration); + } +} + +//***************************************************************************** +// +// This function handles the GET_INTERFACE standard USB request. +// +// \param pUSBRequest holds the data for this request. +// +// This function is called when the host controller request the current +// interface that is in use by the device. This simply returns the value set +// by the last call to SetInterface(). +// +// \return None. +// +//***************************************************************************** +static void +USBDGetInterface(tUSBRequest *pUSBRequest) +{ + uint8_t ui8Value; + + // + // If we still have an address pending then the device is still not + // configured. + // + if(g_sUSBDeviceState.ui32DevAddress & DEV_ADDR_PENDING) + { + ui8Value = 0; + } + else + { + // + // Is the interface number valid? + // + if(pUSBRequest->wIndex == 0) + { + // + // Read the current alternate setting for the required interface. + // + ui8Value = g_sUSBDeviceState.ui8AltSetting; + } + else + { + // + // An invalid interface number was specified. + // + USBBLStallEP0(); + return; + } + } + + // + // Send the single byte response. + // + g_sUSBDeviceState.ui32EP0DataRemain = 1; + g_sUSBDeviceState.pui8EP0Data = &ui8Value; + + // + // Send the single byte response. + // + USBDEP0StateTx(); +} + +//***************************************************************************** +// +// This function handles the SET_INTERFACE standard USB request. +// +// \param pUSBRequest holds the data for this request. +// +// The DFU device supports a single interface with no alternate settings so +// this handler is hardcoded assuming this configuration. +// +// \return None. +// +//***************************************************************************** +static void +USBDSetInterface(tUSBRequest *pUSBRequest) +{ + if((pUSBRequest->wIndex == 0) && (pUSBRequest->wValue == 0)) + { + // + // We were passed a valid interface number so acknowledge the request. + // + USBDevEndpoint0DataAck(true); + } + else + { + // + // The values passed were not valid so stall endpoint 0. + // + USBBLStallEP0(); + } +} + +//***************************************************************************** +// +// This internal function handles sending data on endpoint zero. +// +// \return None. +// +//***************************************************************************** +static void +USBDEP0StateTx(void) +{ + uint32_t ui32NumBytes; + uint8_t *pui8Data; + + // + // In the TX state on endpoint zero. + // + g_eUSBDEP0State = USB_STATE_TX; + + // + // Set the number of bytes to send this iteration. + // + ui32NumBytes = g_sUSBDeviceState.ui32EP0DataRemain; + + // + // Limit individual transfers to 64 bytes. + // + if(ui32NumBytes > EP0_MAX_PACKET_SIZE) + { + ui32NumBytes = EP0_MAX_PACKET_SIZE; + } + + // + // Save the pointer so that it can be passed to the USBEndpointDataPut() + // function. + // + pui8Data = g_sUSBDeviceState.pui8EP0Data; + + // + // Advance the data pointer and counter to the next data to be sent. + // + g_sUSBDeviceState.ui32EP0DataRemain -= ui32NumBytes; + g_sUSBDeviceState.pui8EP0Data += ui32NumBytes; + + // + // Put the data in the correct FIFO. + // + USBEndpoint0DataPut(pui8Data, ui32NumBytes); + + // + // If this is exactly 64 then don't set the last packet yet. + // + if(ui32NumBytes == EP0_MAX_PACKET_SIZE) + { + // + // There is more data to send or exactly 64 bytes were sent, this + // means that there is either more data coming or a null packet needs + // to be sent to complete the transaction. + // + USBEndpoint0DataSend(USB_TRANS_IN); + } + else + { + // + // Now go to the status state and wait for the transmit to complete. + // + g_eUSBDEP0State = USB_STATE_STATUS; + + // + // Send the last bit of data. + // + USBEndpoint0DataSend(USB_TRANS_IN_LAST); + g_sUSBDeviceState.ui32OUTDataSize = 0; + } +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** +#endif // USB_ENABLE_UPDATE diff --git a/boot_loader/bl_usbfuncs.h b/boot_loader/bl_usbfuncs.h new file mode 100644 index 0000000..7c3868c --- /dev/null +++ b/boot_loader/bl_usbfuncs.h @@ -0,0 +1,505 @@ +//***************************************************************************** +// +// bl_usbfuncs.h - Prototypes for the subset of USB library functions used in +// the USB DFU boot loader. +// +// Copyright (c) 2008-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. +// +//***************************************************************************** + +#ifndef __BL_USBFUNCS_H__ +#define __BL_USBFUNCS_H__ + +//***************************************************************************** +// +//! \addtogroup bl_usb_api +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// The following macro allows compiler-independent syntax to be used to +// define packed structures. A typical structure definition using these +// macros will look similar to the following example: +// +// #ifdef ewarm +// #pragma pack(1) +// #endif +// +// typedef struct _PackedStructName +// { +// uint32_t ui32FirstField; +// int8_t i8CharMember; +// uint16_t ui16Short; +// } +// PACKED tPackedStructName; +// +// #ifdef ewarm +// #pragma pack() +// #endif +// +// The conditional blocks related to ewarm include the #pragma pack() lines +// only if the IAR Embedded Workbench compiler is being used. Unfortunately, +// it is not possible to emit a #pragma from within a macro definition so this +// must be done explicitly. +// +//***************************************************************************** +#if defined(ccs) || \ + defined(codered) || \ + defined(gcc) || \ + defined(rvmdk) || \ + defined(__ARMCC_VERSION) || \ + defined(sourcerygxx) +#define PACKED __attribute__ ((packed)) +#elif defined(ewarm) +#define PACKED +#else +#error Unrecognized COMPILER! +#endif + +//***************************************************************************** +// +// Standard USB descriptor types. These values are passed in the upper bytes +// of tUSBRequest.wValue on USBREQ_GET_DESCRIPTOR and also appear in the +// bDescriptorType field of standard USB descriptors. +// +//***************************************************************************** +#define USB_DTYPE_DEVICE 1 +#define USB_DTYPE_CONFIGURATION 2 +#define USB_DTYPE_STRING 3 +#define USB_DTYPE_INTERFACE 4 +#define USB_DTYPE_ENDPOINT 5 +#define USB_DTYPE_DEVICE_QUAL 6 +#define USB_DTYPE_OSPEED_CONF 7 +#define USB_DTYPE_INTERFACE_PWR 8 + +#define USBShort(ui16Value) (ui16Value & 0xff), (ui16Value >> 8) + +#define USB_LANG_EN_US 0x0409 // English (United States) + +#define USB_EP_DEV_IN 0x00002000 // Device IN endpoint +#define USB_EP_DEV_OUT 0x00001000 // Device OUT endpoint + +//***************************************************************************** +// +// All structures defined in this section of the header require byte packing of +// fields. This is usually accomplished using the PACKED macro but, for IAR +// Embedded Workbench, this requires a pragma. +// +//***************************************************************************** +#ifdef ewarm +#pragma pack(1) +#endif + +//***************************************************************************** +// +// Definitions related to standard USB device requests (sections 9.3 & 9.4) +// +//***************************************************************************** + +//***************************************************************************** +// +//! The standard USB request header as defined in section 9.3 of the USB 2.0 +//! specification. +// +//***************************************************************************** +typedef struct +{ + // + //! Determines the type and direction of the request. + // + uint8_t bmRequestType; + + // + //! Identifies the specific request being made. + // + uint8_t bRequest; + + // + //! Word-sized field that varies according to the request. + // + uint16_t wValue; + + // + //! Word-sized field that varies according to the request; typically used + //! to pass an index or offset. + // + uint16_t wIndex; + + // + //! The number of bytes to transfer if there is a data stage to the + //! request. + // + uint16_t wLength; +} +PACKED tUSBRequest; + +//***************************************************************************** +// +// The following defines are used with the bmRequestType member of tUSBRequest. +// +// Request types have 3 bit fields: +// 4:0 - Is the recipient type. +// 6:5 - Is the request type. +// 7 - Is the direction of the request. +// +//***************************************************************************** +#define USB_RTYPE_DIR_IN 0x80 +#define USB_RTYPE_DIR_OUT 0x00 + +#define USB_RTYPE_TYPE_M 0x60 +#define USB_RTYPE_VENDOR 0x40 +#define USB_RTYPE_CLASS 0x20 +#define USB_RTYPE_STANDARD 0x00 + +#define USB_RTYPE_RECIPIENT_M 0x1f +#define USB_RTYPE_OTHER 0x03 +#define USB_RTYPE_ENDPOINT 0x02 +#define USB_RTYPE_INTERFACE 0x01 +#define USB_RTYPE_DEVICE 0x00 + +//***************************************************************************** +// +// Standard USB requests IDs used in the bRequest field of tUSBRequest. +// +//***************************************************************************** +#define USBREQ_GET_STATUS 0x00 +#define USBREQ_CLEAR_FEATURE 0x01 +#define USBREQ_SET_FEATURE 0x03 +#define USBREQ_SET_ADDRESS 0x05 +#define USBREQ_GET_DESCRIPTOR 0x06 +#define USBREQ_SET_DESCRIPTOR 0x07 +#define USBREQ_GET_CONFIG 0x08 +#define USBREQ_SET_CONFIG 0x09 +#define USBREQ_GET_INTERFACE 0x0a +#define USBREQ_SET_INTERFACE 0x0b +#define USBREQ_SYNC_FRAME 0x0c + +//***************************************************************************** +// +// Data returned from a USBREQ_GET_STATUS request to a device. +// +//***************************************************************************** +#define USB_STATUS_SELF_PWR 0x0001 // Currently self powered. +#define USB_STATUS_BUS_PWR 0x0000 // Currently bus-powered. +#define USB_STATUS_PWR_M 0x0001 // Mask for power mode. +#define USB_STATUS_REMOTE_WAKE 0x0002 // Remote wake-up is currently enabled. + + +//***************************************************************************** +// +//! This structure describes the USB configuration descriptor as defined in +//! USB 2.0 specification section 9.6.3. This structure also applies to the +//! USB other speed configuration descriptor defined in section 9.6.4. +// +//***************************************************************************** +typedef struct +{ + // + //! The length of this descriptor in bytes. All configuration descriptors + //! are 9 bytes long. + // + uint8_t bLength; + + // + //! The type of the descriptor. For a configuration descriptor, this will + //! be USB_DTYPE_CONFIGURATION (2). + // + uint8_t bDescriptorType; + + // + //! The total length of data returned for this configuration. This + //! includes the combined length of all descriptors (configuration, + //! interface, endpoint and class- or vendor-specific) returned for this + //! configuration. + // + uint16_t wTotalLength; + + // + //! The number of interface supported by this configuration. + // + uint8_t bNumInterfaces; + + // + //! The value used as an argument to the SetConfiguration standard request + //! to select this configuration. + // + uint8_t bConfigurationValue; + + // + //! The index of a string descriptor describing this configuration. + // + uint8_t iConfiguration; + + // + //! Attributes of this configuration. + // + uint8_t bmAttributes; + + // + //! The maximum power consumption of the USB device from the bus in this + //! configuration when the device is fully operational. This is expressed + //! in units of 2mA so, for example, 100 represents 200mA. + // + uint8_t bMaxPower; +} +PACKED tConfigDescriptor; + +//***************************************************************************** +// +// Flags used in constructing the value assigned to the field +// tConfigDescriptor.bmAttributes. Note that bit 7 is reserved and must be set +// to 1. +// +//***************************************************************************** +#define USB_CONF_ATTR_PWR_M 0xC0 + +#define USB_CONF_ATTR_SELF_PWR 0xC0 +#define USB_CONF_ATTR_BUS_PWR 0x80 +#define USB_CONF_ATTR_RWAKE 0xA0 + +//***************************************************************************** +// +// Feature Selectors (tUSBRequest.wValue) passed on USBREQ_CLEAR_FEATURE and +// USBREQ_SET_FEATURE. +// +//***************************************************************************** +#define USB_FEATURE_EP_HALT 0x0000 // Endpoint halt feature. +#define USB_FEATURE_REMOTE_WAKE 0x0001 // Remote wake feature, device only. +#define USB_FEATURE_TEST_MODE 0x0002 // Test mode + +//***************************************************************************** +// +//! This structure describes the USB string descriptor for index 0 as defined +//! in USB 2.0 specification section 9.6.7. Note that the number of language +//! IDs is variable and can be determined by examining bLength. The number of +//! language IDs present in the descriptor is given by ((bLength - 2) / 2). +// +//***************************************************************************** +typedef struct +{ + // + //! The length of this descriptor in bytes. This value will vary + //! depending upon the number of language codes provided in the descriptor. + // + uint8_t bLength; + + // + //! The type of the descriptor. For a string descriptor, this will be + //! USB_DTYPE_STRING (3). + // + uint8_t bDescriptorType; + + // + //! The language code (LANGID) for the first supported language. Note that + //! this descriptor may support multiple languages, in which case, the + //! number of elements in the wLANGID array will increase and bLength will + //! be updated accordingly. + // + uint16_t wLANGID[1]; +} +PACKED tString0Descriptor; + +//***************************************************************************** +// +//! This structure describes the USB string descriptor for all string indexes +//! other than 0 as defined in USB 2.0 specification section 9.6.7. +// +//***************************************************************************** +typedef struct +{ + // + //! The length of this descriptor in bytes. This value will be 2 greater + //! than the number of bytes comprising the UNICODE string that the + //! descriptor contains. + // + uint8_t bLength; + + // + //! The type of the descriptor. For a string descriptor, this will be + //! USB_DTYPE_STRING (3). + // + uint8_t bDescriptorType; + + // + //! The first byte of the UNICODE string. This string is not NULL + //! terminated. Its length (in bytes) can be computed by subtracting 2 + //! from the value in the bLength field. + // + uint8_t bString; +} +PACKED tStringDescriptor; + +//***************************************************************************** +// +// Return to default packing when using the IAR Embedded Workbench compiler. +// +//***************************************************************************** +#ifdef ewarm +#pragma pack() +#endif + +//***************************************************************************** +// +// Some standard USB class definitions. +// +//***************************************************************************** +#define USB_CLASS_APP_SPECIFIC 0xfe +#define USB_CLASS_VEND_SPECIFIC 0xff + +//***************************************************************************** +// +// The following are values that are returned from USBEndpointStatus(). The +// USB_HOST_* values are used when the USB controller is in host mode and the +// USB_DEV_* values are used when the USB controller is in device mode. +// +//***************************************************************************** +#define USB_DEV_RX_SENT_STALL 0x00400000 // Stall was sent on this endpoint +#define USB_DEV_RX_DATA_ERROR 0x00080000 // CRC error on the data +#define USB_DEV_RX_OVERRUN 0x00040000 // OUT packet was not loaded due to + // a full FIFO +#define USB_DEV_RX_FIFO_FULL 0x00020000 // RX FIFO full +#define USB_DEV_RX_PKT_RDY 0x00010000 // Data packet ready +#define USB_DEV_TX_NOT_COMP 0x00000080 // Large packet split up, more data + // to come +#define USB_DEV_TX_SENT_STALL 0x00000020 // Stall was sent on this endpoint +#define USB_DEV_TX_UNDERRUN 0x00000004 // IN received with no data ready +#define USB_DEV_TX_FIFO_NE 0x00000002 // The TX FIFO is not empty +#define USB_DEV_TX_TXPKTRDY 0x00000001 // Transmit still being transmitted +#define USB_DEV_EP0_SETUP_END 0x00000010 // Control transaction ended before + // Data End seen +#define USB_DEV_EP0_SENT_STALL 0x00000004 // Stall was sent on this endpoint +#define USB_DEV_EP0_IN_PKTPEND 0x00000002 // Transmit data packet pending +#define USB_DEV_EP0_OUT_PKTRDY 0x00000001 // Receive data packet ready + +//***************************************************************************** +// +// This value specifies the maximum size of transfers on endpoint 0 as 64 +// bytes. This value is fixed in hardware as the FIFO size for endpoint 0. +// +//***************************************************************************** +#define MAX_PACKET_SIZE_EP0 64 + +//***************************************************************************** +// +// These values are used to indicate which endpoint to access. +// +//***************************************************************************** +#define USB_EP_0 0x00000000 // Endpoint 0 +#define NUM_USB_EP 4 // Number of supported endpoints + +//***************************************************************************** +// +// These macros allow conversion between 0-based endpoint indices and the +// USB_EP_x values required when calling various USB APIs. +// +//***************************************************************************** +#define INDEX_TO_USB_EP(x) ((x) << 4) +#define USB_EP_TO_INDEX(x) ((x) >> 4) + +//***************************************************************************** +// +// The following are values that can be passed to USBEndpointDataSend() as the +// ui32TransType parameter. +// +//***************************************************************************** +#define USB_TRANS_OUT 0x00000102 // Normal OUT transaction +#define USB_TRANS_IN 0x00000102 // Normal IN transaction +#define USB_TRANS_IN_LAST 0x0000010a // Final IN transaction (for + // endpoint 0 in device mode) +#define USB_TRANS_SETUP 0x0000110a // Setup transaction (for endpoint + // 0) +#define USB_TRANS_STATUS 0x00000142 // Status transaction (for endpoint + // 0) + +//***************************************************************************** +// +// Function prototype for any standard USB request. +// +//***************************************************************************** +typedef void (* tStdRequest)(tUSBRequest *psUSBRequest); + +//***************************************************************************** +// +// Data structures defined in bl_usb.c but referenced elsewhere. +// +//***************************************************************************** +extern const uint8_t g_pui8DFUConfigDescriptor[]; +extern const uint8_t g_pui8DFUDeviceDescriptor[]; +extern const uint8_t * const g_ppui8StringDescriptors[]; + +#define NUM_STRING_DESCRIPTORS 4 + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** + +//***************************************************************************** +// +// Prototypes of the various USB handler functions. +// +//***************************************************************************** +extern void HandleRequests(tUSBRequest *psUSBRequest); +extern void HandleConfigChange(uint32_t ui32Info); +extern void HandleEP0Data(uint32_t ui32Info); +extern void HandleReset(void); +extern void HandleDisconnect(void); +extern void HandleSetAddress(void); + +//***************************************************************************** +// +// Prototypes for the APIs. +// +//***************************************************************************** +extern void USBDevEndpoint0DataAck(bool bIsLastPacket); +extern int32_t USBEndpoint0DataGet(uint8_t *pui8Data, uint32_t *pui32Size); +extern int32_t USBEndpoint0DataPut(uint8_t *pui8Data, uint32_t ui32Size); +extern int32_t USBEndpoint0DataSend(uint32_t ui32TransType); +extern void USBBLInit(void); +extern void USBBLStallEP0(void); +extern void USBBLRequestDataEP0(uint8_t *pui8Data, uint32_t ui32Size); +extern void USBBLSendDataEP0(uint8_t *pui8Data, uint32_t ui32Size); +extern void USBDeviceEnumHandler(void); +extern void USBDeviceEnumResetHandler(void); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // __BL_USBFUNCS_H__ diff --git a/boot_loader/readme.txt b/boot_loader/readme.txt new file mode 100644 index 0000000..6c37d28 --- /dev/null +++ b/boot_loader/readme.txt @@ -0,0 +1,28 @@ +Boot Loader + +The boot loader is a small piece of code that can be programmed at the +beginning of flash to act as an application loader as well as an update +mechanism for an application running on a Tiva microcontroller, utilizing +either UART0, I2C0, SSI0, Ethernet or USB. The capabilities of the boot loader +are configured via the bl_config.h include file (which is located in the +application directory, not in the boot loader source directory). + +------------------------------------------------------------------------------- + +Copyright (c) 2007-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. diff --git a/boot_loader/uip-conf.h b/boot_loader/uip-conf.h new file mode 100644 index 0000000..5c1d770 --- /dev/null +++ b/boot_loader/uip-conf.h @@ -0,0 +1,108 @@ +//***************************************************************************** +// +// uip-conf.h - uIP configuration for the boot loader. +// +// Copyright (c) 2007-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. +// +//***************************************************************************** + +#ifndef __UIP_CONF_H__ +#define __UIP_CONF_H__ + +//***************************************************************************** +// +// This typedef defines the 8-bit type used throughout uIP. +// +//***************************************************************************** +typedef uint8_t u8_t; + +//***************************************************************************** +// +// This typedef defines the 16-bit type used throughout uIP. +// +//***************************************************************************** +typedef uint16_t u16_t; + +//***************************************************************************** +// +// This typedef defines the dataype used for keeping statistics in uIP. +// +//***************************************************************************** +typedef uint16_t uip_stats_t; + +//***************************************************************************** +// +// Turn off TCP support. +// +//***************************************************************************** +#define UIP_CONF_TCP 0 + +//***************************************************************************** +// +// Turn on UDP support. +// +//***************************************************************************** +#define UIP_CONF_UDP 1 + +//***************************************************************************** +// +// Only support a single UDP connection. +// +//***************************************************************************** +#define UIP_CONF_UDP_CONNS 1 + +//***************************************************************************** +// +// Only support a single entry in the ARP table. +// +//***************************************************************************** +#define UIP_CONF_ARPTAB_SIZE 1 + +//***************************************************************************** +// +// Set the size of the uIP packet data buffer. +// +//***************************************************************************** +#define UIP_CONF_BUFFER_SIZE 1600//700 + +//***************************************************************************** +// +// Enable UDP broadcast support. +// +//***************************************************************************** +#define UIP_CONF_BROADCAST 1 + +//***************************************************************************** +// +// Define a data type for the UDP application state. This is not used, but +// must be defined for uIP. +// +//***************************************************************************** +typedef uint32_t uip_udp_appstate_t; + +//***************************************************************************** +// +// The name of the function to be called when UDP packets arrive, or when the +// UDP periodic timer expires. +// +//***************************************************************************** +extern char BOOTPThread(void); +#define UIP_UDP_APPCALL BOOTPThread + +#endif // __UIP_CONF_H__ diff --git a/boot_loader/usbdfu.h b/boot_loader/usbdfu.h new file mode 100644 index 0000000..3ae00e1 --- /dev/null +++ b/boot_loader/usbdfu.h @@ -0,0 +1,420 @@ +//***************************************************************************** +// +// usbdfu.h - Definitions related to the USB Device Firmware Upgrade class. +// +// Copyright (c) 2008-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. +// +//***************************************************************************** + +#ifndef __USBDFU_H__ +#define __USBDFU_H__ + +//***************************************************************************** +// +// DFU attributes as published in the functional descriptor. +// +//***************************************************************************** +#define DFU_ATTR_WILL_DETACH 0x08 +#define DFU_ATTR_MANIFEST_TOLERANT \ + 0x04 +#define DFU_ATTR_CAN_UPLOAD 0x02 +#define DFU_ATTR_CAN_DOWNLOAD 0x01 + +//***************************************************************************** +// +// The states that the DFU device can be in. These values are reported to +// the host in response to a USBD_DFU_REQUEST_GETSTATE request. +// +//***************************************************************************** +typedef enum +{ + STATE_APP_IDLE = 0, + STATE_APP_DETACH, + STATE_IDLE, + STATE_DNLOAD_SYNC, + STATE_DNBUSY, + STATE_DNLOAD_IDLE, + STATE_MANIFEST_SYNC, + STATE_MANIFEST, + STATE_MANIFEST_WAIT_RESET, + STATE_UPLOAD_IDLE, + STATE_ERROR +} +tDFUState; + +//***************************************************************************** +// +// The current error status of the DFU device. These values are reported to +// the host in response to a USBD_DFU_REQUEST_GETSTATUS request. +// +//***************************************************************************** +typedef enum +{ + STATUS_OK = 0, + STATUS_ERR_TARGET, + STATUS_ERR_FILE, + STATUS_ERR_WRITE, + STATUS_ERR_ERASE, + STATUS_ERR_CHECK_ERASED, + STATUS_ERR_PROG, + STATUS_ERR_VERIFY, + STATUS_ERR_ADDRESS, + STATUS_ERR_NOTDONE, + STATUS_ERR_FIRMWARE, + STATUS_ERR_VENDOR, + STATUS_ERR_USBR, + STATUS_ERR_POR, + STATUS_ERR_UNKNOWN, + STATUS_ERR_STALLEDPKT +} +tDFUStatus; + +//***************************************************************************** +// +// The descriptor type for the DFU functional descriptor. +// +//***************************************************************************** +#define USB_DFU_FUNC_DESCRIPTOR_TYPE 0x21 + +//***************************************************************************** +// +// The subclass identifier for DFU as reported to the host in the +// bInterfaceSubClass field of the DFU interface descriptor. +// +//***************************************************************************** +#define USB_DFU_SUBCLASS 0x01 + +//***************************************************************************** +// +// The protocol identifier for DFU as reported to the host in the +// bInterfaceProtocol field of the DFU interface descriptor. +// +//***************************************************************************** +#define USB_DFU_PROTOCOL 0x02 +#define USB_DFU_RUNTIME_PROTOCOL 0x01 + +//***************************************************************************** +// +// DFU class-specific request identifiers. +// +//***************************************************************************** +#define USBD_DFU_REQUEST_DETACH 0 +#define USBD_DFU_REQUEST_DNLOAD 1 +#define USBD_DFU_REQUEST_UPLOAD 2 +#define USBD_DFU_REQUEST_GETSTATUS 3 +#define USBD_DFU_REQUEST_CLRSTATUS 4 +#define USBD_DFU_REQUEST_GETSTATE 5 +#define USBD_DFU_REQUEST_ABORT 6 + +//***************************************************************************** +// +// Request 1KB blocks from the host. This value is published in the USB +// functional descriptor. +// +//***************************************************************************** +#define DFU_TRANSFER_SIZE 1024 + +//***************************************************************************** +// +// TIVA-specific request identifier. This is used to determine whether +// the target device supports our DFU command protocol. It is expected that +// a device not supporting our extensions will stall this request. This +// request is only supported while the DFU device is in STATE_IDLE. +// +// An IN request containing the following parameters will result in the device +// sending back a tDFUQueryTIVAProtocol structure indicating that +// TIVA extensions are supported. The actual values in wValue and wIndex +// have no meaning other than to act as markers in the unlikely event that +// another DFU device also chooses to use request ID 0x42 for some other +// purpose. +// +// wValue - 0x23(REQUEST_TIVA_VALUE) +// wIndex - Interface number +// wLength - sizeof(tDFUQueryTIVAProtocol) +// +//***************************************************************************** +#define USBD_DFU_REQUEST_TIVA 0x42 +#define REQUEST_TIVA_VALUE 0x23 + +#define DFU_PROTOCOL_USBLIB_MARKER \ + 0x4C4D +#define DFU_PROTOCOL_USBLIB_VERSION_1 \ + 0x0001 + +#ifdef ewarm +#pragma pack(1) +#endif + +//***************************************************************************** +// +// The structure sent to the host when a valid USBD_DFU_REQUEST_TIVA is +// received while the DFU device is in idle state. +// +//***************************************************************************** +typedef struct +{ + uint16_t ui16Marker; // DFU_PROTOCOL_USBLIB_MARKER + uint16_t ui16Version; // DFU_PROTOCOL_USBLIB_VERSION_1 +} +PACKED tDFUQueryTIVAProtocol; + +//***************************************************************************** +// +// Structure sent to the host in response to USBD_DFU_REQUEST_GETSTATUS. +// +//***************************************************************************** +typedef struct +{ + uint8_t bStatus; + uint8_t bwPollTimeout[3]; + uint8_t bState; + uint8_t iString; +} +PACKED tDFUGetStatusResponse; + +//***************************************************************************** +// +// Firmware Download Commands +// +// The data passed on a USBD_DFU_REQUEST_DNLOAD request is comprised of a +// header which instructs the boot loader how to interpret the block and +// block-specific data. The following definitions relate to the download +// block headers. +// +//***************************************************************************** + +//***************************************************************************** +// +// Supported command identifiers +// +//***************************************************************************** +#define DFU_CMD_PROG 0x01 +#define DFU_CMD_READ 0x02 +#define DFU_CMD_CHECK 0x03 +#define DFU_CMD_ERASE 0x04 +#define DFU_CMD_INFO 0x05 +#define DFU_CMD_BIN 0x06 +#define DFU_CMD_RESET 0x07 + +//***************************************************************************** +// +// Generic download command header. +// +//***************************************************************************** +typedef struct +{ + uint8_t ui8Command; // Command identifier. + uint8_t pui8Data[7]; // Command-specific data elements. +} +PACKED tDFUDownloadHeader; + +//***************************************************************************** +// +// Header for the DFU_CMD_PROG command. +// +// This command is used to program a section of the flash with the binary data +// which immediately follows the header. The start address of the data is +// expressed as a 1KB block number so 0 would represent the bottom of flash +// (which, incidentally, the USB boot loader will not let you program) and 0x10 +// would represent address 16KB or 16384 (0x4000). The ui32Length field +// contains the total number of bytes of data in the following programming +// operation. The DFU device will not look for any command header on following +// USBD_DFU_REQUEST_DNLOAD requests until the operation is completed or +// aborted. +// +// By using this protocol, the DFU_CMD_PROG command header may be used as a +// simple header on the binary files to be sent to the DFU device for +// programming. If we enforce the requirement that the DFU_CMD_PROG header is +// applied to each USBD_DFU_REQUEST_DNLOAD (one per block), this means that the +// host-side DFU application must be aware of the underlying protocol and +// insert these headers dynamically during programming operations. This could +// be handled by post processing the binary to insert the headers at the +// appropriate points but this would then tie the binary structure to the +// chosen transfer size and break the operation if the transfer size were to +// change in the future. +// +//***************************************************************************** +typedef struct +{ + uint8_t ui8Command; // DFU_CMD_PROG + uint8_t ui8Reserved; // Reserved - set to 0x00. + uint16_t ui16StartAddr; // Block start address / 1024 + uint32_t ui32Length; // Total length, in bytes, of following data + // for the complete download operation. +} +PACKED tDFUDownloadProgHeader; + +//***************************************************************************** +// +// Header for the DFU_CMD_READ and DFU_CMD_CHECK commands. +// +// This command may be used to set the address range whose content will be +// returned on subsequent USBD_DFU_REQUEST_UPLOAD requests from the host. +// +// To read back a the contents of a region of flash, the host should send +// USBD_DFU_REQUEST_DNLOAD with ui8Command DFU_CMD_READ, ui16StartAddr set to +// the 1KB block start address and ui32Length set to the number of bytes to +// read. The host should then send one or more USBD_DFU_REQUEST_UPLOAD +// requests to receive the current flash contents from the configured +// addresses. Data returned will include an 8 byte DFU_CMD_PROG prefix +// structure unless the prefix has been disabled by sending a DFU_CMD_BIN +// command with the bBinary parameter set to 1. +// +// To check that a region of flash is erased, the DFU_CMD_CHECK command should +// be sent with ui16StartAddr and ui32Length set to describe the region to +// check. The host should then send a USBD_DFU_REQUEST_GETSTATUS. If the +// erase check was successful, the returned bStatus value will be STATUS_OK, +// otherwise it will be STATUS_ERR_CHECK_ERASED. Note that ui32Length passed +// must be a multiple of 4. If this is not the case, the value will be +// truncated before the check is performed. +// +//***************************************************************************** +typedef struct +{ + uint8_t ui8Command; // DFU_CMD_READ or DFU_CMD_CHECK + uint8_t ui8Reserved; // Reserved - write to 0 + uint16_t ui16StartAddr; // Block start address / 1024 + uint32_t ui32Length; // The number of bytes of data to read back or + // check. +} +PACKED tDFUDownloadReadCheckHeader; + +//***************************************************************************** +// +// Header for the DFU_CMD_ERASE command. +// +// This command may be used to erase a number of flash blocks. The address of +// the first block to be erased is passed in ui16StartAddr with ui16NumBlocks +// containing the number of blocks to be erased from this address. The block +// size of the device may be determined using the DFU_CMD_INFO command. +// +//***************************************************************************** +typedef struct +{ + uint8_t ui8Command; // DFU_CMD_ERASE + uint8_t ui8Reserved; // Reserved - set to 0 + uint16_t ui16StartAddr; // Block start address / 1024 + uint16_t ui16NumBlocks; // The number of blocks to erase + uint8_t pui8Reserved2[2]; // Reserved - set to 0 +} +PACKED tDFUDownloadEraseHeader; + +//***************************************************************************** +// +// Header for the DFU_CMD_INFO command. +// +// This command may be used to query information about the connected device. +// After sending the command, the information is returned on the next +// USBD_DFU_REQUEST_UPLOAD request. +// +//***************************************************************************** +typedef struct +{ + uint8_t ui8Command; // DFU_CMD_INFO + uint8_t pui8Reserved[7]; // Reserved - set to 0 +} +PACKED tDFUDownloadInfoHeader; + +//***************************************************************************** +// +// Header for the DFU_CMD_BIN command. +// +// This command may be used to set the format of uploaded data. By default, +// images read using USBD_DFU_REQUEST_UPLOAD are formatted with the appropriate +// header to allow the same image to be flashed back to the device and have it +// located at the address from which it originated. This is a requirement of +// the DFU class specification (section 6.2 "the uploaded image must be +// usable in a subsequent download") but may not be helpful in some cases where +// the application wishes to receive only the binary image from flash. To +// instruct the DFU device to omit the position and size header, send this +// command with the bBinary field set to \b true prior to issuing a +// USBD_DFU_REQUEST_UPLOAD for image data. The format choice remains in effect +// until the command is sent once again with bBinary set to \b false. +// +// Note that the format choice affects only image data sent and not responses +// read via USBD_DFU_REQUEST_UPLOAD following software-specific commands such +// as DFU_CMD_INFO. +// +//***************************************************************************** +typedef struct +{ + uint8_t ui8Command; // DFU_CMD_BIN + uint8_t bBinary; // Set to true to omit image header or false + // to include it (the default) + uint8_t pui8Reserved[6]; // Reserved - set to 0 +} +PACKED tDFUDownloadBinHeader; + +//***************************************************************************** +// +// The DFU_CMD_RESET command uses a tDFUDownloadHeader structure since +// only the ui8Command field is important. This command causes an immediate +// reset of the the target board. +// +//***************************************************************************** + +//***************************************************************************** +// +//! Payload returned in response to the DFU_CMD_INFO command. +//! +//! This is structure is returned in response to the first +//! USBD_DFU_REQUEST_UPLOAD request following a DFU_CMD_INFO command. +// +//***************************************************************************** +typedef struct +{ + // + //! The size of a flash block in bytes. + // + uint16_t ui16FlashBlockSize; + + // + //! The number of blocks of flash in the device. Total flash size is + //! ui16NumFlashBlocks * ui16FlashBlockSize. + // + uint16_t ui16NumFlashBlocks; + + // + //! Information on the part number, family, version and package as read + //! from SYSCTL register DID1. + // + uint32_t ui32PartInfo; + + // + //! Information on the part class and revision as read from SYSCTL DID0. + // + uint32_t ui32ClassInfo; + + // + //! Address 1 byte above the highest location the boot loader can access. + // + uint32_t ui32FlashTop; + + // + //! Lowest address the boot loader can write or erase. + // + uint32_t ui32AppStartAddr; +} +PACKED tDFUDeviceInfo; + +#ifdef ewarm +#pragma pack() +#endif + +#endif // __USBDFU_H__ -- cgit v1.3.1