mirror of https://github.com/rusefi/openblt.git
617 lines
26 KiB
C
617 lines
26 KiB
C
/************************************************************************************//**
|
|
* \file Source/ARMCM4_S32K14/can.c
|
|
* \brief Bootloader CAN communication interface source file.
|
|
* \ingroup Target_ARMCM4_S32K14
|
|
* \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 "boot.h" /* bootloader generic header */
|
|
#if (BOOT_COM_CAN_ENABLE > 0)
|
|
#include "device_registers.h" /* device registers */
|
|
|
|
|
|
/****************************************************************************************
|
|
* Macro definitions
|
|
****************************************************************************************/
|
|
/** \brief Timeout for entering/leaving CAN initialization mode in milliseconds. */
|
|
#define CAN_INIT_TIMEOUT_MS (250U)
|
|
/** \brief Timeout for transmitting a CAN message in milliseconds. */
|
|
#define CAN_MSG_TX_TIMEOUT_MS (50U)
|
|
|
|
#if (BOOT_COM_CAN_CHANNEL_INDEX == 0)
|
|
/** \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)
|
|
#elif (BOOT_COM_CAN_CHANNEL_INDEX == 1)
|
|
/** \brief Set the peripheral CAN1 base pointer. */
|
|
#define CANx (CAN1)
|
|
/** \brief Set the PCC index offset for CAN1. */
|
|
#define PCC_FlexCANx_INDEX (PCC_FlexCAN1_INDEX)
|
|
/** \brief Set the number of message boxes supported by CAN1. */
|
|
#define CANx_MAX_MB_NUM (FEATURE_CAN1_MAX_MB_NUM)
|
|
#elif (BOOT_COM_CAN_CHANNEL_INDEX == 2)
|
|
/** \brief Set the peripheral CAN2 base pointer. */
|
|
#define CANx (CAN2)
|
|
/** \brief Set the PCC index offset for CAN2. */
|
|
#define PCC_FlexCANx_INDEX (PCC_FlexCAN2_INDEX)
|
|
/** \brief Set the number of message boxes supported by CAN2. */
|
|
#define CANx_MAX_MB_NUM (FEATURE_CAN2_MAX_MB_NUM)
|
|
#endif
|
|
|
|
/** \brief The mailbox used for transmitting the XCP respond message. */
|
|
#define CAN_TX_MSGBOX_NUM (8U)
|
|
/** \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
|
|
{
|
|
blt_int8u timeQuanta; /**< Total number of time quanta */
|
|
blt_int8u propSeg; /**< CAN propagation segment */
|
|
blt_int8u phaseSeg1; /**< CAN phase segment 1 */
|
|
blt_int8u 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 blt_int32u 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 BLT_TRUE if the CAN bustiming register values were found, BLT_FALSE
|
|
** otherwise.
|
|
**
|
|
****************************************************************************************/
|
|
static blt_bool CanGetSpeedConfig(blt_int16u baud, blt_int16u * prescaler,
|
|
tCanBusTiming * busTimingCfg)
|
|
{
|
|
blt_int8u cnt;
|
|
blt_int32u canClockFreqkHz;
|
|
blt_int32u div2RegValue;
|
|
blt_int8u 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 BLT_TRUE;
|
|
}
|
|
}
|
|
}
|
|
/* Could not find a good bus timing configuration. */
|
|
return BLT_FALSE;
|
|
} /*** 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)
|
|
{
|
|
blt_int32u timeout;
|
|
|
|
/* This function should only be called with the module enabled. */
|
|
ASSERT_RT((CANx->MCR & CAN_MCR_MDIS_MASK) == 0U);
|
|
|
|
/* 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)
|
|
{
|
|
/* Keep the watchdog happy. */
|
|
CopService();
|
|
/* 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)
|
|
{
|
|
blt_int32u timeout;
|
|
|
|
/* This function should only be called with the module enabled. */
|
|
ASSERT_RT((CANx->MCR & CAN_MCR_MDIS_MASK) == 0U);
|
|
|
|
/* 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)
|
|
{
|
|
/* Keep the watchdog happy. */
|
|
CopService();
|
|
/* 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)
|
|
{
|
|
blt_int32u 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)
|
|
{
|
|
/* Keep the watchdog happy. */
|
|
CopService();
|
|
/* 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)
|
|
{
|
|
blt_int32u 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)
|
|
{
|
|
/* Keep the watchdog happy. */
|
|
CopService();
|
|
/* Break loop upon timeout. This would indicate a hardware failure. */
|
|
if (TimerGet() > timeout)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} /*** end of CanDisabledModeExit ***/
|
|
|
|
|
|
/************************************************************************************//**
|
|
** \brief Initializes the CAN controller and synchronizes it to the CAN bus.
|
|
** \return none.
|
|
**
|
|
****************************************************************************************/
|
|
void CanInit(void)
|
|
{
|
|
blt_int16u prescaler = 0;
|
|
tCanBusTiming timingCfg = { 0 };
|
|
blt_int8u rjw;
|
|
blt_int16u idx;
|
|
blt_int32u timeout;
|
|
blt_int32u rxMsgId = BOOT_COM_CAN_RX_MSG_ID;
|
|
|
|
/* Perform compile time assertion to check that the configured CAN channel is actually
|
|
* supported by this driver.
|
|
*/
|
|
ASSERT_CT((BOOT_COM_CAN_CHANNEL_INDEX == 0) ||
|
|
(BOOT_COM_CAN_CHANNEL_INDEX == 1) ||
|
|
(BOOT_COM_CAN_CHANNEL_INDEX == 2));
|
|
|
|
/* Verify the correct configuration of the transmit and receive mailboxes. */
|
|
ASSERT_CT(CAN_TX_MSGBOX_NUM < CANx_MAX_MB_NUM);
|
|
ASSERT_CT(CAN_RX_MSGBOX_NUM < CANx_MAX_MB_NUM);
|
|
|
|
/* 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. */
|
|
if (CanGetSpeedConfig(BOOT_COM_CAN_BAUDRATE/1000, &prescaler, &timingCfg) == BLT_FALSE)
|
|
{
|
|
/* Incorrect configuration. The specified baudrate is not supported for the given
|
|
* clock configuration. Verify the following settings in blt_conf.h:
|
|
* - BOOT_COM_CAN_BAUDRATE
|
|
* - BOOT_CPU_XTAL_SPEED_KHZ
|
|
* - BOOT_CPU_SYSTEM_SPEED_KHZ
|
|
*/
|
|
ASSERT_RT(BLT_FALSE);
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
/* Keep the watchdog happy. */
|
|
CopService();
|
|
/* Break loop upon timeout. This would indicate a hardware failure. */
|
|
if (TimerGet() > timeout)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
} /*** end of CanInit ***/
|
|
|
|
|
|
/************************************************************************************//**
|
|
** \brief Transmits a packet formatted for the communication interface.
|
|
** \param data Pointer to byte array with data that it to be transmitted.
|
|
** \param len Number of bytes that are to be transmitted.
|
|
** \return none.
|
|
**
|
|
****************************************************************************************/
|
|
void CanTransmitPacket(blt_int8u *data, blt_int8u len)
|
|
{
|
|
blt_int32u timeout;
|
|
blt_bool isExtId = BLT_FALSE;
|
|
blt_int32u txMsgId = BOOT_COM_CAN_TX_MSG_ID;
|
|
blt_int8u * pMsgBoxData;
|
|
blt_int8u byteIdx;
|
|
|
|
/* Prepare information about the message identifier. */
|
|
if ((txMsgId & 0x80000000U) != 0U)
|
|
{
|
|
/* It is a 29-bit extended CAN identifier. */
|
|
txMsgId &= ~0x80000000U;
|
|
isExtId = BLT_TRUE;
|
|
}
|
|
|
|
/* Clear the mailbox interrupt flag by writing a 1 to the corresponding box. */
|
|
CANx->IFLAG1 = (1U << CAN_TX_MSGBOX_NUM);
|
|
|
|
/* Prepare the mailbox RAM for a basic CAN message.
|
|
* EDL,BRS,ESI=0: CANFD not used.
|
|
*/
|
|
CANx->RAMn[(CAN_TX_MSGBOX_NUM * 4U) + 0U] &= ~0xE0000000U;
|
|
/* Configure SRR, IDE, RTR bits for a standard 11-bit transmit frame. */
|
|
CANx->RAMn[(CAN_TX_MSGBOX_NUM * 4U) + 0U] &= ~(CAN_WMBn_CS_IDE_MASK |
|
|
CAN_WMBn_CS_RTR_MASK);
|
|
CANx->RAMn[(CAN_TX_MSGBOX_NUM * 4U) + 0U] |= CAN_WMBn_CS_SRR_MASK;
|
|
/* Configure the DLC. */
|
|
CANx->RAMn[(CAN_TX_MSGBOX_NUM * 4U) + 0U] &= ~CAN_WMBn_CS_DLC_MASK;
|
|
CANx->RAMn[(CAN_TX_MSGBOX_NUM * 4U) + 0U] |= CAN_WMBn_CS_DLC(len);
|
|
/* Write the data bytes of the CAN message to the mailbox RAM. */
|
|
pMsgBoxData = (blt_int8u * )(&CANx->RAMn[(CAN_TX_MSGBOX_NUM * 4U) + 2U]);
|
|
for (byteIdx = 0; byteIdx < len; byteIdx++)
|
|
{
|
|
pMsgBoxData[((byteIdx) & ~3U) + (3U - ((byteIdx) & 3U))] = data[byteIdx];
|
|
}
|
|
/* Store the CAN message identifier in the mailbox RAM. */
|
|
if (isExtId == BLT_FALSE)
|
|
{
|
|
/* Store the 11-bit CAN identifier. */
|
|
CANx->RAMn[(CAN_TX_MSGBOX_NUM * 4U) + 1U] = CAN_WMBn_ID_ID(txMsgId << 18U);
|
|
}
|
|
else
|
|
{
|
|
/* Set the IDE bit to configure the message for a 29-bit identifier. */
|
|
CANx->RAMn[(CAN_TX_MSGBOX_NUM * 4U) + 0U] |= CAN_WMBn_CS_IDE_MASK;
|
|
/* Store the 29-bit CAN identifier. */
|
|
CANx->RAMn[(CAN_TX_MSGBOX_NUM * 4U) + 1U] = CAN_WMBn_ID_ID(txMsgId);
|
|
}
|
|
/* Activate the mailbox to start the transmission by writing 0x0C to the CODE field. */
|
|
CANx->RAMn[(CAN_TX_MSGBOX_NUM * 4U) + 0U] |= (0x0CU << 24U) & 0x0F000000U;
|
|
|
|
/* Determine timeout time for the transmit completion. */
|
|
timeout = TimerGet() + CAN_MSG_TX_TIMEOUT_MS;
|
|
/* Poll for completion of the transmit operation. */
|
|
while ((CANx->IFLAG1 & (1U << CAN_TX_MSGBOX_NUM)) == 0U)
|
|
{
|
|
/* Service the watchdog. */
|
|
CopService();
|
|
/* Break loop upon timeout. this would indicate a hardware failure or no other
|
|
* nodes connected to the bus.
|
|
*/
|
|
if (TimerGet() > timeout)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
} /*** end of CanTransmitPacket ***/
|
|
|
|
|
|
/************************************************************************************//**
|
|
** \brief Receives a communication interface packet if one is present.
|
|
** \param data Pointer to byte array where the data is to be stored.
|
|
** \param len Pointer where the length of the packet is to be stored.
|
|
** \return BLT_TRUE is a packet was received, BLT_FALSE otherwise.
|
|
**
|
|
****************************************************************************************/
|
|
blt_bool CanReceivePacket(blt_int8u *data, blt_int8u *len)
|
|
{
|
|
blt_bool result = BLT_FALSE;
|
|
blt_int8u * pMsgBoxData;
|
|
blt_int8u byteIdx;
|
|
|
|
/* 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.
|
|
*/
|
|
*len = (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 = (blt_int8u *)(&CANx->RAMn[(CAN_RX_MSGBOX_NUM * 4U) + 2U]);
|
|
for (byteIdx = 0; byteIdx < *len; byteIdx++)
|
|
{
|
|
data[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;
|
|
/* Update the result. */
|
|
result = BLT_TRUE;
|
|
}
|
|
|
|
/* Give the result back to the caller. */
|
|
return result;
|
|
} /*** end of CanReceivePacket ***/
|
|
#endif /* BOOT_COM_CAN_ENABLE > 0 */
|
|
|
|
|
|
/*********************************** end of can.c **************************************/
|