openblt/Target/Demo/ARMCM0_S32K11_S32K118EVB_IAR/Prog/boot.c

773 lines
32 KiB
C

/************************************************************************************//**
* \file Demo/ARMCM0_S32K14_S32K118EVB_IAR/Prog/boot.c
* \brief Demo program bootloader interface source file.
* \ingroup Prog_ARMCM0_S32K14_S32K118EVB_IAR
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2020 by Feaser http://www.feaser.com All rights reserved
*
*----------------------------------------------------------------------------------------
* L I C E N S E
*----------------------------------------------------------------------------------------
* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include "header.h" /* generic header */
/****************************************************************************************
* Function prototypes
****************************************************************************************/
#if (BOOT_COM_RS232_ENABLE > 0)
static void BootComRs232Init(void);
static void BootComRs232CheckActivationRequest(void);
#endif
#if (BOOT_COM_CAN_ENABLE > 0)
static void BootComCanInit(void);
static void BootComCanCheckActivationRequest(void);
#endif
/************************************************************************************//**
** \brief Initializes the communication interface.
** \return none.
**
****************************************************************************************/
void BootComInit(void)
{
#if (BOOT_COM_RS232_ENABLE > 0)
BootComRs232Init();
#endif
#if (BOOT_COM_CAN_ENABLE > 0)
BootComCanInit();
#endif
} /*** end of BootComInit ***/
/************************************************************************************//**
** \brief Receives the CONNECT request from the host, which indicates that the
** bootloader should be activated and, if so, activates it.
** \return none.
**
****************************************************************************************/
void BootComCheckActivationRequest(void)
{
#if (BOOT_COM_RS232_ENABLE > 0)
BootComRs232CheckActivationRequest();
#endif
#if (BOOT_COM_CAN_ENABLE > 0)
BootComCanCheckActivationRequest();
#endif
} /*** end of BootComCheckActivationRequest ***/
/************************************************************************************//**
** \brief Bootloader activation function.
** \return none.
**
****************************************************************************************/
void BootActivate(void)
{
/* Activate the bootloader by performing a software reset. */
SystemSoftwareReset();
} /*** end of BootActivate ***/
#if (BOOT_COM_RS232_ENABLE > 0)
/****************************************************************************************
* U N I V E R S A L A S Y N C H R O N O U S R X T X I N T E R F A C E
****************************************************************************************/
/****************************************************************************************
* Macro definitions
****************************************************************************************/
/** \brief Timeout time for the reception of a CTO packet. The timer is started upon
* reception of the first packet byte.
*/
#define RS232_CTO_RX_PACKET_TIMEOUT_MS (100u)
/** \brief Set the peripheral LPUART base pointer. */
#define LPUARTx (LPUART0)
/** \brief Set the PCC index offset for LPUART. */
#define PCC_LPUARTx_INDEX (PCC_LPUART0_INDEX)
/****************************************************************************************
* Function prototypes
****************************************************************************************/
static unsigned char Rs232ReceiveByte(unsigned char *data);
/************************************************************************************//**
** \brief Initializes the UART communication interface.
** \return none.
**
****************************************************************************************/
static void BootComRs232Init(void)
{
unsigned long sourceClockFreqHz;
unsigned long div2RegValue;
unsigned short baudrateSbr0_12;
unsigned char const div2DividerLookup[] =
{
0U, /* 0b000. Output disabled. */
1U, /* 0b001. Divide by 1. */
2U, /* 0b010. Divide by 2. */
4U, /* 0b011. Divide by 4. */
8U, /* 0b100. Divide by 8. */
16U, /* 0b101. Divide by 16. */
32U, /* 0b110. Divide by 32. */
64U, /* 0b111. Divide by 64. */
};
/* Make sure the UART peripheral clock is disabled before configuring its source
* clock.
*/
PCC->PCCn[PCC_LPUARTx_INDEX] &= ~PCC_PCCn_CGC_MASK;
/* Select option 2 as the UART peripheral source clock and enable the clock. Option 2
* is the SIRCDIV2_CLK, which is available on all peripherals and configurations.
*/
PCC->PCCn[PCC_LPUARTx_INDEX] |= PCC_PCCn_PCS(2) | PCC_PCCn_CGC_MASK;
/* Obtain the DIV2 divider value of the SIRC_CLK. */
div2RegValue = (SCG->SIRCDIV & SCG_SIRCDIV_SIRCDIV2_MASK) >> SCG_SIRCDIV_SIRCDIV2_SHIFT;
/* Check if the DIV2 register value for SIRC is 0. In this case SIRCDIV2_CLK is
* currently disabled.
*/
if (div2RegValue == 0U)
{
/* Configure the DIV2 for a default divide by 1 to make sure the SIRCDIV2_CLK is
* actually enabled.
*/
div2RegValue = 1U;
SCG->SIRCDIV = SCG_SIRCDIV_SIRCDIV2(div2RegValue);
}
/* Determine the SIRC clock frequency. If SIRC high range is enabled, it is 8 MHz. If
* SIRC low range is enabled, it is 2 MHz.
*/
sourceClockFreqHz = 8000000U;
if ((SCG->SIRCCFG & SCG_SIRCCFG_RANGE_MASK) == SCG_SIRCCFG_RANGE(0))
{
sourceClockFreqHz = 2000000U;
}
/* Now process the configured DIV2 divider factor to get the actual frequency of the
* UART peripheral source clock.
*/
sourceClockFreqHz /= div2DividerLookup[div2RegValue];
/* Configure the baudrate from BOOT_COM_RS232_BAUDRATE, taking into account that an
* oversampling of 8 will be configured. Default 8,n,1 format is used. Integer
* rounding is used to get the best value for baudrateSbr0_12. Actual baudrate equals
* sourceClockFreqHz / 8 / baudrateSbr0_12.
*/
baudrateSbr0_12 = (((sourceClockFreqHz / BOOT_COM_RS232_BAUDRATE) + (8U - 1U)) / 8U) &
LPUART_BAUD_SBR_MASK;
/* OSR=7: Over sampling ratio = 7+1=8.
* SBNS=0: One stop bit.
* BOTHEDGE=0: receiver samples only on rising edge.
* M10=0: Rx and Tx use 7 to 9 bit data characters.
* RESYNCDIS=0: Resync during rec'd data word supported.
* LBKDIE, RXEDGIE=0: interrupts disable.
* TDMAE, RDMAE, TDMAE=0: DMA requests disabled.
* MAEN1, MAEN2, MATCFG=0: Match disabled.
*/
LPUARTx->BAUD = LPUART_BAUD_SBR(baudrateSbr0_12) | LPUART_BAUD_OSR(7);
/* Clear the error/interrupt flags */
LPUARTx->STAT = FEATURE_LPUART_STAT_REG_FLAGS_MASK;
/* Reset all features/interrupts by default */
LPUARTx->CTRL = 0x00000000;
/* Reset match addresses */
LPUARTx->MATCH = 0x00000000;
#if FEATURE_LPUART_HAS_MODEM_SUPPORT
/* Reset IrDA modem features */
LPUARTx->MODIR = 0x00000000;
#endif
#if FEATURE_LPUART_FIFO_SIZE > 0U
/* Reset FIFO feature */
LPUARTx->FIFO = FEATURE_LPUART_FIFO_RESET_MASK;
/* Enable the transmit and receive FIFOs. */
LPUARTx->FIFO |= LPUART_FIFO_TXFE(1) | LPUART_FIFO_RXFE(1);
/* Set the reception water mark to 0 and the transmitter water mark to 1. */
LPUARTx->WATER = LPUART_WATER_TXWATER(1) | LPUART_WATER_RXWATER(0);
#endif
/* Enable transmitter and receiver, no parity, 8 bit char:
* RE=1: Receiver enabled.
* TE=1: Transmitter enabled.
* PE,PT=0: No hw parity generation or checking.
* M7,M,R8T9,R9T8=0: 8-bit data characters.
* DOZEEN=0: LPUART enabled in Doze mode.
* ORIE,NEIE,FEIE,PEIE,TIE,TCIE,RIE,ILIE,MA1IE,MA2IE=0: no IRQ.
* TxDIR=0: TxD pin is input if in single-wire mode.
* TXINV=0: Transmit data not inverted.
* RWU,WAKE=0: normal operation; rcvr not in standby.
* IDLCFG=0: one idle character.
* ILT=0: Idle char bit count starts after start bit.
* SBK=0: Normal transmitter operation - no break char.
* LOOPS,RSRC=0: no loop back.
*/
LPUARTx->CTRL = LPUART_CTRL_RE_MASK | LPUART_CTRL_TE_MASK;
} /*** end of BootComRs232Init ***/
/************************************************************************************//**
** \brief Receives the CONNECT request from the host, which indicates that the
** bootloader should be activated and, if so, activates it.
** \return none.
**
****************************************************************************************/
static void BootComRs232CheckActivationRequest(void)
{
static unsigned char xcpCtoReqPacket[BOOT_COM_RS232_RX_MAX_DATA+1];
static unsigned char xcpCtoRxLength;
static unsigned char xcpCtoRxInProgress = 0;
static unsigned long xcpCtoRxStartTime = 0;
/* start of cto packet received? */
if (xcpCtoRxInProgress == 0)
{
/* store the message length when received */
if (Rs232ReceiveByte(&xcpCtoReqPacket[0]) == 1)
{
/* check that the length has a valid value. it should not be 0 */
if ( (xcpCtoReqPacket[0] > 0) &&
(xcpCtoReqPacket[0] <= BOOT_COM_RS232_RX_MAX_DATA) )
{
/* store the start time */
xcpCtoRxStartTime = TimerGet();
/* indicate that a cto packet is being received */
xcpCtoRxInProgress = 1;
/* reset packet data count */
xcpCtoRxLength = 0;
}
}
}
else
{
/* store the next packet byte */
if (Rs232ReceiveByte(&xcpCtoReqPacket[xcpCtoRxLength+1]) == 1)
{
/* increment the packet data count */
xcpCtoRxLength++;
/* check to see if the entire packet was received */
if (xcpCtoRxLength == xcpCtoReqPacket[0])
{
/* done with cto packet reception */
xcpCtoRxInProgress = 0;
/* check if this was an XCP CONNECT command */
if ((xcpCtoReqPacket[1] == 0xff) && (xcpCtoReqPacket[2] == 0x00))
{
/* connection request received so start the bootloader */
BootActivate();
}
}
}
else
{
/* check packet reception timeout */
if (TimerGet() > (xcpCtoRxStartTime + RS232_CTO_RX_PACKET_TIMEOUT_MS))
{
/* cancel cto packet reception due to timeout. note that this automatically
* discards the already received packet bytes, allowing the host to retry.
*/
xcpCtoRxInProgress = 0;
}
}
}
} /*** end of BootComRs232CheckActivationRequest ***/
/************************************************************************************//**
** \brief Receives a communication interface byte if one is present.
** \param data Pointer to byte where the data is to be stored.
** \return 1 if a byte was received, 0 otherwise.
**
****************************************************************************************/
static unsigned char Rs232ReceiveByte(unsigned char *data)
{
unsigned char result = 0;
/* Check if a new byte was received by means of the RDRF-bit. */
if (((LPUARTx->STAT & LPUART_STAT_RDRF_MASK) >> LPUART_STAT_RDRF_SHIFT) != 0U)
{
/* Retrieve and store the newly received byte. */
*data = LPUARTx->DATA;
/* Update the result. */
result = 1;
}
/* Give the result back to the caller. */
return result;
} /*** end of Rs232ReceiveByte ***/
#endif /* BOOT_COM_RS232_ENABLE > 0 */
#if (BOOT_COM_CAN_ENABLE > 0)
/****************************************************************************************
* C O N T R O L L E R A R E A N E T W O R K I N T E R F A C E
****************************************************************************************/
/****************************************************************************************
* Macro definitions
****************************************************************************************/
/** \brief Timeout for entering/leaving CAN initialization mode in milliseconds. */
#define CAN_INIT_TIMEOUT_MS (250U)
/** \brief Set the peripheral CAN0 base pointer. */
#define CANx (CAN0)
/** \brief Set the PCC index offset for CAN0. */
#define PCC_FlexCANx_INDEX (PCC_FlexCAN0_INDEX)
/** \brief Set the number of message boxes supported by CAN0. */
#define CANx_MAX_MB_NUM (FEATURE_CAN0_MAX_MB_NUM)
/** \brief The mailbox used for receiving the XCP command message. */
#define CAN_RX_MSGBOX_NUM (9U)
/****************************************************************************************
* Type definitions
****************************************************************************************/
/** \brief Structure type for grouping CAN bus timing related information. */
typedef struct t_can_bus_timing
{
unsigned char timeQuanta; /**< Total number of time quanta */
unsigned char propSeg; /**< CAN propagation segment */
unsigned char phaseSeg1; /**< CAN phase segment 1 */
unsigned char phaseSeg2; /**< CAN phase segment 2 */
} tCanBusTiming;
/****************************************************************************************
* Local constant declarations
****************************************************************************************/
/** \brief CAN bit timing table for dynamically calculating the bittiming settings.
* \details According to the CAN protocol 1 bit-time can be made up of between 8..25
* time quanta (TQ). The total TQ in a bit is SYNC + TSEG1 + TSEG2 with SYNC
* always being 1. The sample point is (SYNC + TSEG1) / (SYNC + TSEG1 + TSEG2)
* * 100%. This array contains possible and valid time quanta configurations
* with a sample point between 68..78%. A visual representation of the TQ in
* a bit is:
* | SYNCSEG | TIME1SEG | TIME2SEG |
* Or with an alternative representation:
* | SYNCSEG | PROPSEG | PHASE1SEG | PHASE2SEG |
* With the alternative representation TIME1SEG = PROPSEG + PHASE1SEG.
*
*/
static const tCanBusTiming canTiming[] =
{
/* Time-Quanta | PROPSEG | PSEG1 | PSEG2 | Sample-Point */
/* ---------------------------------------------------- */
{ 8U, 3U, 2U, 2U }, /*1+3+2+1=8 | 3 | 2 | 2 | 75% */
{ 9U, 3U, 3U, 2U }, /* 9 | 3 | 3 | 2 | 78% */
{ 10U, 3U, 3U, 3U }, /* 10 | 3 | 3 | 3 | 70% */
{ 11U, 4U, 3U, 3U }, /* 11 | 4 | 3 | 3 | 73% */
{ 12U, 4U, 4U, 3U }, /* 12 | 4 | 4 | 3 | 75% */
{ 13U, 5U, 4U, 3U }, /* 13 | 5 | 4 | 3 | 77% */
{ 14U, 5U, 4U, 4U }, /* 14 | 5 | 4 | 4 | 71% */
{ 15U, 6U, 4U, 4U }, /* 15 | 6 | 4 | 4 | 73% */
{ 16U, 6U, 5U, 4U }, /* 16 | 6 | 5 | 4 | 75% */
{ 17U, 7U, 5U, 4U }, /* 17 | 7 | 5 | 4 | 76% */
{ 18U, 7U, 5U, 5U }, /* 18 | 7 | 5 | 5 | 72% */
{ 19U, 8U, 5U, 5U }, /* 19 | 8 | 5 | 5 | 74% */
{ 20U, 8U, 6U, 5U }, /* 20 | 8 | 6 | 5 | 75% */
{ 21U, 8U, 7U, 5U }, /* 21 | 8 | 7 | 5 | 76% */
{ 22U, 8U, 7U, 6U }, /* 22 | 8 | 7 | 6 | 73% */
{ 23U, 8U, 8U, 6U }, /* 23 | 8 | 8 | 6 | 74% */
{ 24U, 8U, 8U, 7U }, /* 24 | 8 | 8 | 7 | 71% */
{ 25U, 8U, 8U, 8U } /* 25 | 8 | 8 | 8 | 68% */
};
/****************************************************************************************
* Local data declarations
****************************************************************************************/
/** \brief Dummy variable to store the CAN controller's free running timer value in.
* This is needed at the end of a CAN message reception to unlock the mailbox
* again. If this variable is declared locally within the function, it generates
* an unwanted compiler warning about assigning a value and not using it.
* For this reason this dummy variabled is declare here as a module global.
*/
static volatile unsigned long dummyTimerVal;
/************************************************************************************//**
** \brief Search algorithm to match the desired baudrate to a possible bus
** timing configuration.
** \param baud The desired baudrate in kbps. Valid values are 10..1000.
** \param prescaler Pointer to where the value for the prescaler will be stored.
** \param busTimingCfg Pointer to where the bus timing values will be stored.
** \return 1 if the CAN bustiming register values were found, 0 otherwise.
**
****************************************************************************************/
static unsigned char CanGetSpeedConfig(unsigned short baud, unsigned short * prescaler,
tCanBusTiming * busTimingCfg)
{
unsigned char cnt;
unsigned long canClockFreqkHz;
unsigned long div2RegValue;
unsigned char const div2DividerLookup[] =
{
0U, /* 0b000. Output disabled. */
1U, /* 0b001. Divide by 1. */
2U, /* 0b010. Divide by 2. */
4U, /* 0b011. Divide by 4. */
8U, /* 0b100. Divide by 8. */
16U, /* 0b101. Divide by 16. */
32U, /* 0b110. Divide by 32. */
64U, /* 0b111. Divide by 64. */
};
/* Obtain the DIV2 divider value of the SOSC_CLK. */
div2RegValue = (SCG->SOSCDIV & SCG_SOSCDIV_SOSCDIV2_MASK) >> SCG_SOSCDIV_SOSCDIV2_SHIFT;
/* Check if the DIV2 register value for SOSC is 0. In this case SOSCDIV2_CLK is
* currently disabled.
*/
if (div2RegValue == 0U)
{
/* Configure the DIV2 for a default divide by 1 to make sure the SOSCDIV2_CLK is
* actually enabled.
*/
div2RegValue = 1U;
SCG->SOSCDIV = SCG_SOSCDIV_SOSCDIV2(div2RegValue);
}
/* Determine the SOSC clock frequency. */
canClockFreqkHz = BOOT_CPU_XTAL_SPEED_KHZ;
/* Now process the configured DIV2 divider factor to get the actual frequency of the
* CAN peripheral source clock.
*/
canClockFreqkHz /= div2DividerLookup[div2RegValue];
/* Loop through all possible time quanta configurations to find a match. */
for (cnt=0; cnt < sizeof(canTiming)/sizeof(canTiming[0]); cnt++)
{
if ((canClockFreqkHz % (baud * canTiming[cnt].timeQuanta)) == 0U)
{
/* Compute the prescaler that goes with this TQ configuration. */
*prescaler = canClockFreqkHz/(baud * canTiming[cnt].timeQuanta);
/* Make sure the prescaler is valid. */
if ((*prescaler > 0U) && (*prescaler <= 256U))
{
/* Store the bustiming configuration. */
*busTimingCfg = canTiming[cnt];
/* Found a good bus timing configuration. */
return 1U;
}
}
}
/* Could not find a good bus timing configuration. */
return 0U;
} /*** end of CanGetSpeedConfig ***/
/************************************************************************************//**
** \brief Places the CAN controller in freeze mode. Note that the CAN controller
** can only be placed in freeze mode, if it is actually enabled.
** \return none.
**
****************************************************************************************/
static void CanFreezeModeEnter(void)
{
unsigned long timeout;
/* Request to enter freeze mode. */
CANx->MCR = (CANx->MCR & ~CAN_MCR_FRZ_MASK) | CAN_MCR_FRZ(1U);
CANx->MCR = (CANx->MCR & ~CAN_MCR_HALT_MASK) | CAN_MCR_HALT(1U);
/* Set timeout time for entering freeze mode. */
timeout = TimerGet() + CAN_INIT_TIMEOUT_MS;
/* Wait for freeze mode acknowledgement. */
while (((CANx->MCR & CAN_MCR_FRZACK_MASK)) == 0U)
{
/* Break loop upon timeout. This would indicate a hardware failure. */
if (TimerGet() > timeout)
{
break;
}
}
} /*** end of CanFreezeModeEnter ***/
/************************************************************************************//**
** \brief Leaves the CAN controller's freeze mode. Note that this operation can
** only be done, if it is actually enabled.
** \return none.
**
****************************************************************************************/
static void CanFreezeModeExit(void)
{
unsigned long timeout;
/* Request to leave freeze mode. */
CANx->MCR = (CANx->MCR & ~CAN_MCR_FRZ_MASK) | CAN_MCR_FRZ(0U);
CANx->MCR = (CANx->MCR & ~CAN_MCR_HALT_MASK) | CAN_MCR_HALT(0U);
/* Set timeout time for leaving freeze mode. */
timeout = TimerGet() + CAN_INIT_TIMEOUT_MS;
/* Wait for non freeze mode acknowledgement. */
while (((CANx->MCR & CAN_MCR_FRZACK_MASK)) != 0U)
{
/* Break loop upon timeout. This would indicate a hardware failure. */
if (TimerGet() > timeout)
{
break;
}
}
} /*** end of CanFreezeModeExit ***/
/************************************************************************************//**
** \brief Places the CAN controller in disabled mode.
** \return none.
**
****************************************************************************************/
static void CanDisabledModeEnter(void)
{
unsigned long timeout;
/* Only continue if the CAN controller is currently enabled. */
if ((CANx->MCR & CAN_MCR_MDIS_MASK) == 0U)
{
/* Request disabled mode. */
CANx->MCR = (CANx->MCR & ~CAN_MCR_MDIS_MASK) | CAN_MCR_MDIS(1U);
/* Set timeout time for entering disabled mode. */
timeout = TimerGet() + CAN_INIT_TIMEOUT_MS;
/* Wait for disabled mode acknowledgement. */
while (((CANx->MCR & CAN_MCR_LPMACK_MASK)) == 0U)
{
/* Break loop upon timeout. This would indicate a hardware failure. */
if (TimerGet() > timeout)
{
break;
}
}
}
} /*** end of CanDisabledModeEnter ***/
/************************************************************************************//**
** \brief Places the CAN controller in enabled mode.
** \return none.
**
****************************************************************************************/
static void CanDisabledModeExit(void)
{
unsigned long timeout;
/* Only continue if the CAN controller is currently disabled. */
if ((CANx->MCR & CAN_MCR_MDIS_MASK) != 0U)
{
/* Request enabled mode. */
CANx->MCR = (CANx->MCR & ~CAN_MCR_MDIS_MASK) | CAN_MCR_MDIS(0U);
/* Set timeout time for leaving disabled mode. */
timeout = TimerGet() + CAN_INIT_TIMEOUT_MS;
/* Wait for disabled mode acknowledgement. */
while (((CANx->MCR & CAN_MCR_LPMACK_MASK)) != 0U)
{
/* Break loop upon timeout. This would indicate a hardware failure. */
if (TimerGet() > timeout)
{
break;
}
}
}
} /*** end of CanDisabledModeExit ***/
/************************************************************************************//**
** \brief Initializes the CAN communication interface.
** \return none.
**
****************************************************************************************/
static void BootComCanInit(void)
{
unsigned short prescaler = 0;
tCanBusTiming timingCfg = { 0 };
unsigned char rjw;
unsigned short idx;
unsigned long timeout;
unsigned long rxMsgId = BOOT_COM_CAN_RX_MSG_ID;
/* Enable the CAN peripheral clock. */
PCC->PCCn[PCC_FlexCANx_INDEX] |= PCC_PCCn_CGC_MASK;
/* The source clock needs to be configured first. For this the CAN controller must be
* in disabled mode, but that can only be entered after first entering freeze mode,
* which in turn can only be in enabled mode. So first enable the module, then goto
* freeze mode and finally enter disabled mode.
*/
CanDisabledModeExit();
CanFreezeModeEnter();
CanDisabledModeEnter();
/* Configure SOSCDIV2 as the source clock. This assumes that an external oscillator
* is available, which is typically the case to meet the clock tolerance requirements
* of the CAN 2.0B secification.
*/
CANx->CTRL1 &= ~CAN_CTRL1_CLKSRC_MASK;
/* Leave disabled mode. */
CanDisabledModeExit();
/* Make sure freeze mode is active to be able to initialize the CAN controller. */
CanFreezeModeEnter();
/* Obtain bittiming configuration information. */
(void)CanGetSpeedConfig(BOOT_COM_CAN_BAUDRATE/1000, &prescaler, &timingCfg);
/* Reset the current bittiming configuration. */
CANx->CTRL1 &= ~(CAN_CTRL1_PRESDIV_MASK | CAN_CTRL1_PROPSEG_MASK |
CAN_CTRL1_PSEG1_MASK | CAN_CTRL1_PSEG2_MASK | CAN_CTRL1_RJW_MASK |
CAN_CTRL1_SMP_MASK);
/* Configure the baudrate prescaler. */
CANx->CTRL1 |= CAN_CTRL1_PRESDIV(prescaler - 1U);
/* Configure the propagation segment. */
CANx->CTRL1 |= CAN_CTRL1_PROPSEG(timingCfg.propSeg - 1U);
/* Configure the phase segments. */
CANx->CTRL1 |= CAN_CTRL1_PSEG1(timingCfg.phaseSeg1 - 1U);
CANx->CTRL1 |= CAN_CTRL1_PSEG2(timingCfg.phaseSeg2 - 1U);
/* The resynchronization jump width (RJW) can be 1 - 4 TQ, yet should never be larger
* than pseg1. Configure the longest possible value for RJW.
*/
rjw = (timingCfg.phaseSeg1 < 4) ? timingCfg.phaseSeg1 : 4;
CANx->CTRL1 |= CAN_CTRL1_RJW(rjw - 1U);
/* All the entries in canTiming[] have a PSEG1 >= 2, so three samples can be used to
* determine the value of the received bit, instead of the default one.
*/
CANx->CTRL1 |= CAN_CTRL1_SMP(1U);
/* Clear the message box RAM. Each message box covers 4 words (1 word = 32-bits. */
for (idx = 0; idx < (CANx_MAX_MB_NUM * 4U); idx++)
{
CANx->RAMn[idx] = 0U;
}
/* Clear the reception mask register for each message box. */
for (idx = 0; idx < CANx_MAX_MB_NUM; idx++)
{
CANx->RXIMR[idx] = 0U;
}
/* Configure the maximum number of message boxes. */
CANx->MCR = (CANx->MCR & ~CAN_MCR_MAXMB_MASK) | CAN_MCR_MAXMB(CANx_MAX_MB_NUM - 1U);
/* Disable the self reception feature. */
CANx->MCR = (CANx->MCR & ~CAN_MCR_SRXDIS_MASK) | CAN_MCR_SRXDIS(1U);
/* Enable individual reception masking. This disables the legacy support for the
* global reception mask and the mailbox 14/15 individual reception mask.
*/
CANx->MCR = (CANx->MCR & ~CAN_MCR_IRMQ_MASK) | CAN_MCR_IRMQ(1U);
/* Disable the reception FIFO. This driver only needs to receive one CAN message
* identifier. It is sufficient to use just one dedicated mailbox for this.
*/
CANx->MCR &= ~CAN_MCR_RFEN_MASK;
/* Configure the mask of the invididual message reception mailbox to check all ID bits
* and also the IDE bit.
*/
CANx->RXIMR[CAN_RX_MSGBOX_NUM] = 0x40000000U | 0x1FFFFFFFU;
/* Configure the reception mailbox to receive just the CAN message configured with
* BOOT_COM_CAN_RX_MSG_ID.
* EDL, BRS, ESI=0: CANFD not used.
* CODE=0b0100: mailbox set to active and empty.
* IDE=0: 11-bit CAN identifier.
* SRR, RTR, TIME STAMP=0: not applicable.
*/
CANx->RAMn[(CAN_RX_MSGBOX_NUM * 4U) + 0U] = 0x04000000;
/* Store the message identifier to receive in the mailbox RAM. */
if ((rxMsgId & 0x80000000U) != 0U)
{
/* It is a 29-bit extended CAN identifier. */
rxMsgId &= ~0x80000000U;
/* Set the IDE bit to configure the message for a 29-bit identifier. */
CANx->RAMn[(CAN_RX_MSGBOX_NUM * 4U) + 0U] |= CAN_WMBn_CS_IDE_MASK;
/* Store the 29-bit CAN identifier. */
CANx->RAMn[(CAN_RX_MSGBOX_NUM * 4U) + 1U] = CAN_WMBn_ID_ID(rxMsgId);
}
else
{
/* Store the 11-bit CAN identifier. */
CANx->RAMn[(CAN_RX_MSGBOX_NUM * 4U) + 1U] = CAN_WMBn_ID_ID(rxMsgId << 18U);
}
/* Disable all message box interrupts. */
CANx->IMASK1 = 0U;
/* Clear all mesasge box interrupt flags. */
CANx->IFLAG1 = CAN_IMASK1_BUF31TO0M_MASK;
/* Clear all error interrupt flags */
CANx->ESR1 = CAN_ESR1_ERRINT_MASK | CAN_ESR1_BOFFINT_MASK | CAN_ESR1_RWRNINT_MASK |
CAN_ESR1_TWRNINT_MASK | CAN_ESR1_BOFFDONEINT_MASK |
CAN_ESR1_ERRINT_FAST_MASK | CAN_ESR1_ERROVR_MASK;
/* Switch to normal user mode. */
CANx->MCR &= ~CAN_MCR_SUPV_MASK;
CANx->CTRL1 &= ~(CAN_CTRL1_LOM_MASK | CAN_CTRL1_LPB_MASK);
/* Exit freeze mode. */
CanFreezeModeExit();
/* Set timeout time for entering normal user mode. */
timeout = TimerGet() + CAN_INIT_TIMEOUT_MS;
/* Wait for normal user mode acknowledgement. */
while (((CANx->MCR & CAN_MCR_NOTRDY_MASK)) != 0U)
{
/* Break loop upon timeout. This would indicate a hardware failure. */
if (TimerGet() > timeout)
{
break;
}
}
} /*** end of BootComCanInit ***/
/************************************************************************************//**
** \brief Receives the CONNECT request from the host, which indicates that the
** bootloader should be activated and, if so, activates it.
** \return none.
**
****************************************************************************************/
static void BootComCanCheckActivationRequest(void)
{
unsigned char * pMsgBoxData;
unsigned char byteIdx;
unsigned char rxMsgData[8];
unsigned char rxMsgLen;
/* Check if a message was received in the individual mailbox configured to receive
* the BOOT_COM_CAN_RX_MSG_ID message.
*/
if ((CANx->IFLAG1 & (1U << CAN_RX_MSGBOX_NUM)) != 0U)
{
/* Note that there is no need to verify the identifier of the CAN message because the
* mailbox is configured to only receive the BOOT_COM_CAN_TX_MSG_ID message. Start
* by reading out the DLC of the newly received CAN message.
*/
rxMsgLen = (CANx->RAMn[(CAN_RX_MSGBOX_NUM * 4U) + 0U] & CAN_WMBn_CS_DLC_MASK) >> CAN_WMBn_CS_DLC_SHIFT;
/* Read the data bytes of the CAN message from the mailbox RAM. */
pMsgBoxData = (unsigned char *)(&CANx->RAMn[(CAN_RX_MSGBOX_NUM * 4U) + 2U]);
for (byteIdx = 0; byteIdx < rxMsgLen; byteIdx++)
{
rxMsgData[byteIdx] = pMsgBoxData[((byteIdx) & ~3U) + (3U - ((byteIdx) & 3U))];
}
/* Clear the mailbox interrupt flag by writing a 1 to the corresponding box. */
CANx->IFLAG1 = (1U << CAN_RX_MSGBOX_NUM);
/* Read the free running timer to unlock the mailbox. */
dummyTimerVal = CANx->TIMER;
/* check if this was an XCP CONNECT command */
if ((rxMsgData[0] == 0xff) && (rxMsgLen == 2))
{
/* connection request received so start the bootloader */
BootActivate();
}
}
} /*** end of BootComCanCheckActivationRequest ***/
#endif /* BOOT_COM_CAN_ENABLE > 0 */
/*********************************** end of boot.c *************************************/