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_can.c | 1403 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1403 insertions(+) create mode 100644 boot_loader/bl_can.c (limited to 'boot_loader/bl_can.c') 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 -- cgit v1.3.1