diff options
| author | Yuval Adam <yuval@y3xz.com> | 2015-03-13 12:24:52 +0200 |
|---|---|---|
| committer | Yuval Adam <yuval@y3xz.com> | 2015-03-13 12:24:52 +0200 |
| commit | 4085ae3ddfbbf10c8ccbd3dccd43452c40a1fe40 (patch) | |
| tree | ac63581949a49511136e7e9e47d265bfb4119b26 /boot_loader/bl_can.c | |
| parent | 788db64b8642bf31de6930d18a62177c64163ee0 (diff) | |
Add bootloader, nfclib and sensorlib
Diffstat (limited to 'boot_loader/bl_can.c')
| -rw-r--r-- | boot_loader/bl_can.c | 1403 |
1 files changed, 1403 insertions, 0 deletions
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 <stdint.h>
+#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 <tt>bl_config.h</tt> 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
|
