//***************************************************************************** // // 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