1121 lines
30 KiB
C
1121 lines
30 KiB
C
//###########################################################################
|
|
//
|
|
// FILE: can.c
|
|
//
|
|
// TITLE: C28x CAN driver.
|
|
//
|
|
//###########################################################################
|
|
// $Copyright:
|
|
// Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions
|
|
// are met:
|
|
//
|
|
// Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
//
|
|
// Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the
|
|
// distribution.
|
|
//
|
|
// Neither the name of Texas Instruments Incorporated nor the names of
|
|
// its contributors may be used to endorse or promote products derived
|
|
// from this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
// $
|
|
//###########################################################################
|
|
#include "can.h"
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// CAN_initModule
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
CAN_initModule(uint32_t base)
|
|
{
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(CAN_isBaseValid(base));
|
|
|
|
//
|
|
// Place CAN controller in init state, regardless of previous state. This
|
|
// will put controller in idle, and allow the message object RAM to be
|
|
// programmed.
|
|
//
|
|
HWREGH(base + CAN_O_CTL) |= ((uint16_t)CAN_CTL_INIT |
|
|
(uint16_t)CAN_INIT_PARITY_DISABLE);
|
|
|
|
//
|
|
// Initialize the message RAM before using it.
|
|
//
|
|
CAN_initRAM(base);
|
|
|
|
//
|
|
// Force module to reset state
|
|
//
|
|
|
|
HWREGH(base + CAN_O_CTL) |= CAN_CTL_SWR;
|
|
|
|
//
|
|
// Delay for 14 cycles
|
|
//
|
|
SysCtl_delay(1U);
|
|
|
|
//
|
|
// Enable write access to the configuration registers
|
|
//
|
|
HWREGH(base + CAN_O_CTL) |= CAN_CTL_CCE;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// CAN_setBitRate
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
CAN_setBitRate(uint32_t base, uint32_t clockFreq, uint32_t bitRate,
|
|
uint16_t bitTime)
|
|
{
|
|
uint16_t brp;
|
|
uint16_t tPhase;
|
|
uint16_t phaseSeg2;
|
|
uint16_t tSync = 1U;
|
|
uint16_t tProp = 2U;
|
|
uint16_t tSeg1;
|
|
uint16_t tSeg2;
|
|
uint16_t sjw;
|
|
uint16_t prescaler;
|
|
uint16_t prescalerExtension;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(CAN_isBaseValid(base));
|
|
ASSERT((bitTime > 7U) && (bitTime < 26U));
|
|
ASSERT(bitRate <= 1000000U);
|
|
|
|
//
|
|
// Calculate bit timing values
|
|
//
|
|
brp = (uint16_t)(clockFreq / (bitRate * bitTime));
|
|
tPhase = bitTime - (tSync + tProp);
|
|
if((tPhase / 2U) <= 8U)
|
|
{
|
|
phaseSeg2 = tPhase / 2U;
|
|
}
|
|
else
|
|
{
|
|
phaseSeg2 = 8U;
|
|
}
|
|
tSeg1 = ((tPhase - phaseSeg2) + tProp) - 1U;
|
|
tSeg2 = phaseSeg2 - 1U;
|
|
if(phaseSeg2 > 4U)
|
|
{
|
|
sjw = 3U;
|
|
}
|
|
else
|
|
{
|
|
sjw = tSeg2;
|
|
}
|
|
prescalerExtension = ((brp - 1U) / 64U);
|
|
prescaler = ((brp - 1U) % 64U);
|
|
|
|
//
|
|
// Set the calculated timing parameters
|
|
//
|
|
CAN_setBitTiming(base, prescaler, prescalerExtension, tSeg1, tSeg2, sjw);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// CAN_setBitTiming
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
CAN_setBitTiming(uint32_t base, uint16_t prescaler,
|
|
uint16_t prescalerExtension, uint16_t tSeg1, uint16_t tSeg2,
|
|
uint16_t sjw)
|
|
{
|
|
uint16_t savedInit;
|
|
uint32_t bitReg;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(CAN_isBaseValid(base));
|
|
ASSERT(prescaler < 64U);
|
|
ASSERT((tSeg1 > 0U) && (tSeg1 < 16U));
|
|
ASSERT(tSeg2 < 8U);
|
|
ASSERT(sjw < 4U);
|
|
ASSERT(prescalerExtension < 16U);
|
|
|
|
//
|
|
// To set the bit timing register, the controller must be placed in init
|
|
// mode (if not already), and also configuration change bit enabled.
|
|
// State of the init bit should be saved so it can be restored at the end.
|
|
//
|
|
savedInit = HWREGH(base + CAN_O_CTL);
|
|
HWREGH(base + CAN_O_CTL) = savedInit | CAN_CTL_INIT | CAN_CTL_CCE;
|
|
|
|
//
|
|
// Set the bit fields of the bit timing register
|
|
//
|
|
bitReg = (uint32_t)((uint32_t)prescaler & CAN_BTR_BRP_M);
|
|
bitReg |= (uint32_t)(((uint32_t)sjw << CAN_BTR_SJW_S) & CAN_BTR_SJW_M);
|
|
bitReg |= (uint32_t)(((uint32_t)tSeg1 << CAN_BTR_TSEG1_S) &
|
|
CAN_BTR_TSEG1_M);
|
|
bitReg |= (uint32_t)(((uint32_t)tSeg2 << CAN_BTR_TSEG2_S) &
|
|
CAN_BTR_TSEG2_M);
|
|
bitReg |= (uint32_t)(((uint32_t)prescalerExtension << CAN_BTR_BRPE_S) &
|
|
CAN_BTR_BRPE_M);
|
|
|
|
HWREG_BP(base + CAN_O_BTR) = bitReg;
|
|
|
|
//
|
|
// Clear the config change bit, and restore the init bit.
|
|
//
|
|
savedInit &= ~((uint16_t)CAN_CTL_CCE);
|
|
|
|
HWREGH(base + CAN_O_CTL) = savedInit;
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// CAN_clearInterruptStatus
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
CAN_clearInterruptStatus(uint32_t base, uint32_t intClr)
|
|
{
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(CAN_isBaseValid(base));
|
|
ASSERT((intClr == CAN_INT_INT0ID_STATUS) ||
|
|
((intClr >= 1U) && (intClr <= 32U)));
|
|
|
|
if(intClr == (uint32_t)CAN_INT_INT0ID_STATUS)
|
|
{
|
|
//
|
|
// Simply read and discard the status to clear the interrupt.
|
|
//
|
|
HWREGH(base + CAN_O_ES);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Wait to be sure that this interface is not busy.
|
|
//
|
|
while((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) ==
|
|
CAN_IF1CMD_BUSY)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Only change the interrupt pending state by setting only the
|
|
// CAN_IF1CMD_CLRINTPND bit.
|
|
//
|
|
// Send the clear pending interrupt command to the CAN controller.
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1CMD) = ((uint32_t)CAN_IF1CMD_CLRINTPND |
|
|
(intClr & CAN_IF1CMD_MSG_NUM_M));
|
|
|
|
//
|
|
// Wait to be sure that this interface is not busy.
|
|
//
|
|
while((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) ==
|
|
CAN_IF1CMD_BUSY)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// CAN_setupMessageObject
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
CAN_setupMessageObject(uint32_t base, uint32_t objID, uint32_t msgID,
|
|
CAN_MsgFrameType frame, CAN_MsgObjType msgType,
|
|
uint32_t msgIDMask, uint32_t flags, uint16_t msgLen)
|
|
{
|
|
uint32_t cmdMaskReg = 0U;
|
|
uint32_t maskReg = 0U;
|
|
uint32_t arbReg = 0U;
|
|
uint32_t msgCtrl = 0U;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(CAN_isBaseValid(base));
|
|
ASSERT((objID <= 32U) && (objID > 0U));
|
|
ASSERT(msgLen <= 8U);
|
|
|
|
//
|
|
// Wait for busy bit to clear
|
|
//
|
|
while((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) == CAN_IF1CMD_BUSY)
|
|
{
|
|
}
|
|
|
|
switch(msgType)
|
|
{
|
|
//
|
|
// Transmit message object.
|
|
//
|
|
case CAN_MSG_OBJ_TYPE_TX:
|
|
{
|
|
//
|
|
// Set message direction to transmit.
|
|
//
|
|
arbReg = CAN_IF1ARB_DIR;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Remote frame receive remote, with auto-transmit message object.
|
|
//
|
|
case CAN_MSG_OBJ_TYPE_RXTX_REMOTE:
|
|
{
|
|
//
|
|
// Set message direction to Tx for remote receivers.
|
|
//
|
|
arbReg = CAN_IF1ARB_DIR;
|
|
|
|
//
|
|
// Set this object to auto answer if a matching identifier is seen.
|
|
//
|
|
msgCtrl = (uint32_t)((uint32_t)CAN_IF1MCTL_RMTEN |
|
|
(uint32_t)CAN_IF1MCTL_UMASK);
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Transmit remote request message object (CAN_MSG_OBJ_TYPE_TX_REMOTE)
|
|
// or Receive message object (CAN_MSG_OBJ_TYPE_RX).
|
|
//
|
|
default:
|
|
{
|
|
//
|
|
// Set message direction to read.
|
|
//
|
|
arbReg = 0U;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set values based on Extended Frame or Standard Frame
|
|
//
|
|
if(frame == CAN_MSG_FRAME_EXT)
|
|
{
|
|
//
|
|
// Configure the Mask Registers for 29 bit Identifier mask.
|
|
//
|
|
if((flags & CAN_MSG_OBJ_USE_ID_FILTER) == CAN_MSG_OBJ_USE_ID_FILTER)
|
|
{
|
|
maskReg = msgIDMask & CAN_IF1MSK_MSK_M;
|
|
}
|
|
|
|
//
|
|
// Set the 29 bit version of the Identifier for this message
|
|
// object. Mark the message as valid and set the extended ID bit.
|
|
//
|
|
arbReg |= (msgID & CAN_IF1ARB_ID_M) | CAN_IF1ARB_MSGVAL |
|
|
CAN_IF1ARB_XTD;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Configure the Mask Registers for 11 bit Identifier mask.
|
|
//
|
|
if((flags & CAN_MSG_OBJ_USE_ID_FILTER) == CAN_MSG_OBJ_USE_ID_FILTER)
|
|
{
|
|
maskReg = ((msgIDMask << CAN_IF1ARB_STD_ID_S) &
|
|
CAN_IF1ARB_STD_ID_M);
|
|
}
|
|
|
|
//
|
|
// Set the 11 bit version of the Identifier for this message
|
|
// object. The lower 18 bits are set to zero. Mark the message as
|
|
// valid.
|
|
//
|
|
arbReg |= ((msgID << CAN_IF1ARB_STD_ID_S) & CAN_IF1ARB_STD_ID_M) |
|
|
CAN_IF1ARB_MSGVAL;
|
|
}
|
|
|
|
//
|
|
// If the caller wants to filter on the extended ID bit then set it.
|
|
//
|
|
maskReg |= (flags & CAN_MSG_OBJ_USE_EXT_FILTER);
|
|
|
|
//
|
|
// The caller wants to filter on the message direction field.
|
|
//
|
|
maskReg |= (flags & CAN_MSG_OBJ_USE_DIR_FILTER);
|
|
|
|
//
|
|
// If any filtering is requested, set the UMASK bit to use mask register
|
|
//
|
|
if(((flags & CAN_MSG_OBJ_USE_ID_FILTER) |
|
|
(flags & CAN_MSG_OBJ_USE_DIR_FILTER) |
|
|
(flags & CAN_MSG_OBJ_USE_EXT_FILTER)) != 0U)
|
|
{
|
|
msgCtrl |= CAN_IF1MCTL_UMASK;
|
|
}
|
|
|
|
//
|
|
// Set the data length for the transfers. This is applicable only for
|
|
// Tx mailboxes. For Rx mailboxes, dlc is updated on receving a frame.
|
|
//
|
|
if((msgType == CAN_MSG_OBJ_TYPE_TX) ||
|
|
(msgType == CAN_MSG_OBJ_TYPE_RXTX_REMOTE))
|
|
{
|
|
msgCtrl |= ((uint32_t)msgLen & CAN_IF1MCTL_DLC_M);
|
|
}
|
|
|
|
//
|
|
// If this is a single transfer or the last mailbox of a FIFO, set EOB bit.
|
|
// If this is not the last entry in a FIFO, leave the EOB bit as 0.
|
|
//
|
|
if((flags & CAN_MSG_OBJ_FIFO) == 0U)
|
|
{
|
|
msgCtrl |= CAN_IF1MCTL_EOB;
|
|
}
|
|
|
|
//
|
|
// Enable transmit interrupts if they should be enabled.
|
|
//
|
|
msgCtrl |= (flags & CAN_MSG_OBJ_TX_INT_ENABLE);
|
|
|
|
//
|
|
// Enable receive interrupts if they should be enabled.
|
|
//
|
|
msgCtrl |= (flags & CAN_MSG_OBJ_RX_INT_ENABLE);
|
|
|
|
//
|
|
// Set the Control, Arb, and Mask bit so that they get transferred to the
|
|
// Message object.
|
|
//
|
|
cmdMaskReg |= CAN_IF1CMD_ARB;
|
|
cmdMaskReg |= CAN_IF1CMD_CONTROL;
|
|
cmdMaskReg |= CAN_IF1CMD_MASK;
|
|
cmdMaskReg |= CAN_IF1CMD_DIR;
|
|
|
|
//
|
|
// Write out the registers to program the message object.
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1MSK) = maskReg;
|
|
HWREG_BP(base + CAN_O_IF1ARB) = arbReg;
|
|
HWREG_BP(base + CAN_O_IF1MCTL) = msgCtrl;
|
|
|
|
//
|
|
// Transfer data to message object RAM
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1CMD) =
|
|
cmdMaskReg | (objID & CAN_IF1CMD_MSG_NUM_M);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// CAN_sendMessage
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
CAN_sendMessage(uint32_t base, uint32_t objID, uint16_t msgLen,
|
|
const uint16_t *msgData)
|
|
{
|
|
uint32_t msgCtrl = 0U;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(CAN_isBaseValid(base));
|
|
ASSERT((objID <= 32U) && (objID > 0U));
|
|
ASSERT(msgLen <= 8U);
|
|
|
|
//
|
|
// Set IF command to read message object control value
|
|
//
|
|
// Set up the request for data from the message object.
|
|
// Transfer the message object to the IF register.
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1CMD) = ((uint32_t)CAN_IF1CMD_CONTROL |
|
|
(objID & CAN_IF1CMD_MSG_NUM_M));
|
|
|
|
//
|
|
// Wait for busy bit to clear
|
|
//
|
|
while((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) == CAN_IF1CMD_BUSY)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Read IF message control
|
|
//
|
|
msgCtrl = HWREGH(base + CAN_O_IF1MCTL);
|
|
|
|
//
|
|
// Check provided DLC size with actual Message DLC size
|
|
//
|
|
ASSERT((msgCtrl & CAN_IF1MCTL_DLC_M) == msgLen);
|
|
|
|
//
|
|
// Write the data out to the CAN Data registers.
|
|
//
|
|
CAN_writeDataReg(msgData, (base + CAN_O_IF1DATA),
|
|
(msgCtrl & CAN_IF1MCTL_DLC_M));
|
|
|
|
//
|
|
// Set Data to be transferred from IF
|
|
//
|
|
if(msgLen > 0U)
|
|
{
|
|
msgCtrl = CAN_IF1CMD_DATA_B | CAN_IF1CMD_DATA_A;
|
|
}
|
|
else
|
|
{
|
|
msgCtrl = 0U;
|
|
}
|
|
|
|
//
|
|
// Set Direction to write
|
|
//
|
|
// Set Tx Request Bit
|
|
//
|
|
// Transfer the message object to the message object specified by
|
|
// objID.
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1CMD) = (msgCtrl | (uint32_t)CAN_IF1CMD_DIR |
|
|
(uint32_t)CAN_IF1CMD_TXRQST |
|
|
(objID & CAN_IF1CMD_MSG_NUM_M));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// CAN_sendMessage_16bit
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
CAN_sendMessage_16bit(uint32_t base, uint32_t objID, uint16_t msgLen,
|
|
const uint16_t *msgData)
|
|
{
|
|
uint32_t msgCtrl = 0U;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(CAN_isBaseValid(base));
|
|
ASSERT((objID <= 32U) && (objID > 0U));
|
|
ASSERT(msgLen <= 8U);
|
|
|
|
//
|
|
// Set IF command to read message object control value
|
|
//
|
|
// Set up the request for data from the message object.
|
|
// Transfer the message object to the IF register.
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1CMD) = ((uint32_t)CAN_IF1CMD_CONTROL |
|
|
(objID & CAN_IF1CMD_MSG_NUM_M));
|
|
|
|
//
|
|
// Wait for busy bit to clear
|
|
//
|
|
while((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) == CAN_IF1CMD_BUSY)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Read IF message control
|
|
//
|
|
msgCtrl = HWREGH(base + CAN_O_IF1MCTL);
|
|
|
|
//
|
|
// Check provided DLC size with actual Message DLC size
|
|
//
|
|
ASSERT((msgCtrl & CAN_IF1MCTL_DLC_M) == msgLen);
|
|
|
|
//
|
|
// Write the data out to the CAN Data registers.
|
|
//
|
|
CAN_writeDataReg_16bit(msgData, (base + CAN_O_IF1DATA),
|
|
(msgCtrl & CAN_IF1MCTL_DLC_M));
|
|
|
|
//
|
|
// Set Data to be transferred from IF
|
|
//
|
|
if(msgLen > 0U)
|
|
{
|
|
msgCtrl = CAN_IF1CMD_DATA_B | CAN_IF1CMD_DATA_A;
|
|
}
|
|
else
|
|
{
|
|
msgCtrl = 0U;
|
|
}
|
|
|
|
//
|
|
// Set Direction to write
|
|
//
|
|
// Set Tx Request Bit
|
|
//
|
|
// Transfer the message object to the message object specified by
|
|
// objID.
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1CMD) = (msgCtrl | (uint32_t)CAN_IF1CMD_DIR |
|
|
(uint32_t)CAN_IF1CMD_TXRQST |
|
|
(objID & CAN_IF1CMD_MSG_NUM_M));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// CAN_sendMessage_32bit
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
CAN_sendMessage_32bit(uint32_t base, uint32_t objID, uint16_t msgLen,
|
|
const uint32_t *msgData)
|
|
{
|
|
uint32_t msgCtrl = 0U;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(CAN_isBaseValid(base));
|
|
ASSERT((objID <= 32U) && (objID > 0U));
|
|
ASSERT(msgLen <= 8U);
|
|
|
|
//
|
|
// Set IF command to read message object control value
|
|
//
|
|
// Set up the request for data from the message object.
|
|
// Transfer the message object to the IF register.
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1CMD) = ((uint32_t)CAN_IF1CMD_CONTROL |
|
|
(objID & CAN_IF1CMD_MSG_NUM_M));
|
|
|
|
//
|
|
// Wait for busy bit to clear
|
|
//
|
|
while((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) == CAN_IF1CMD_BUSY)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Read IF message control
|
|
//
|
|
msgCtrl = HWREGH(base + CAN_O_IF1MCTL);
|
|
|
|
//
|
|
// Check provided DLC size with actual Message DLC size
|
|
//
|
|
ASSERT((msgCtrl & CAN_IF1MCTL_DLC_M) == msgLen);
|
|
|
|
//
|
|
// Write the data out to the CAN Data registers.
|
|
//
|
|
CAN_writeDataReg_32bit(msgData, (base + CAN_O_IF1DATA),
|
|
(msgCtrl & CAN_IF1MCTL_DLC_M));
|
|
|
|
//
|
|
// Set Data to be transferred from IF
|
|
//
|
|
if(msgLen > 0U)
|
|
{
|
|
msgCtrl = CAN_IF1CMD_DATA_B | CAN_IF1CMD_DATA_A;
|
|
}
|
|
else
|
|
{
|
|
msgCtrl = 0U;
|
|
}
|
|
|
|
//
|
|
// Set Direction to write
|
|
//
|
|
// Set Tx Request Bit
|
|
//
|
|
// Transfer the message object to the message object specified by
|
|
// objID.
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1CMD) = (msgCtrl | (uint32_t)CAN_IF1CMD_DIR |
|
|
(uint32_t)CAN_IF1CMD_TXRQST |
|
|
(objID & CAN_IF1CMD_MSG_NUM_M));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// CAN_sendMessage_updateDLC
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
CAN_sendMessage_updateDLC(uint32_t base, uint32_t objID, uint16_t msgLen,
|
|
const uint16_t *msgData)
|
|
{
|
|
uint32_t msgCtrl = 0U;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(CAN_isBaseValid(base));
|
|
ASSERT((objID <= 32U) && (objID > 0U));
|
|
ASSERT(msgLen <= 8U);
|
|
|
|
//
|
|
// Set IF command to read message object control value
|
|
//
|
|
// Set up the request for data from the message object.
|
|
// Transfer the message object to the IF register.
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1CMD) = ((uint32_t)CAN_IF1CMD_CONTROL |
|
|
(objID & CAN_IF1CMD_MSG_NUM_M));
|
|
|
|
//
|
|
// Wait for busy bit to clear
|
|
//
|
|
while((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) == CAN_IF1CMD_BUSY)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Read IF message control
|
|
//
|
|
msgCtrl = HWREGH(base + CAN_O_IF1MCTL);
|
|
|
|
//
|
|
// Update to the new data length
|
|
//
|
|
msgCtrl &= ~CAN_IF1MCTL_DLC_M;
|
|
msgCtrl |= (msgLen & CAN_IF1MCTL_DLC_M);
|
|
|
|
//
|
|
// Write out to the register to program the message object
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1MCTL) = msgCtrl;
|
|
|
|
//
|
|
// Transfer data to message object RAM
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1CMD) =
|
|
(CAN_IF1CMD_CONTROL | CAN_IF1CMD_DIR | (objID & CAN_IF1CMD_MSG_NUM_M));
|
|
|
|
//
|
|
// Wait for busy bit to clear
|
|
//
|
|
while((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) == CAN_IF1CMD_BUSY)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Set IF command to read message object control value
|
|
//
|
|
// Set up the request for data from the message object.
|
|
// Transfer the message object to the IF register.
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1CMD) = ((uint32_t)CAN_IF1CMD_CONTROL |
|
|
(objID & CAN_IF1CMD_MSG_NUM_M));
|
|
|
|
//
|
|
// Wait for busy bit to clear
|
|
//
|
|
while((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) == CAN_IF1CMD_BUSY)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Read IF message control
|
|
//
|
|
msgCtrl = HWREGH(base + CAN_O_IF1MCTL);
|
|
|
|
//
|
|
// Check provided DLC size with actual Message DLC size
|
|
//
|
|
ASSERT((msgCtrl & CAN_IF1MCTL_DLC_M) == msgLen);
|
|
|
|
//
|
|
// Write the data out to the CAN Data registers.
|
|
//
|
|
CAN_writeDataReg(msgData, (base + CAN_O_IF1DATA),
|
|
(msgCtrl & CAN_IF1MCTL_DLC_M));
|
|
|
|
//
|
|
// Set Data to be transferred from IF
|
|
//
|
|
if(msgLen > 0U)
|
|
{
|
|
msgCtrl = CAN_IF1CMD_DATA_B | CAN_IF1CMD_DATA_A;
|
|
}
|
|
else
|
|
{
|
|
msgCtrl = 0U;
|
|
}
|
|
|
|
//
|
|
// Set Direction to write
|
|
//
|
|
// Set Tx Request Bit
|
|
//
|
|
// Transfer the message object to the message object specified by
|
|
// objID.
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1CMD) = (msgCtrl | (uint32_t)CAN_IF1CMD_DIR |
|
|
(uint32_t)CAN_IF1CMD_TXRQST |
|
|
(objID & CAN_IF1CMD_MSG_NUM_M));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// CAN_sendRemoteRequestMessage
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
CAN_sendRemoteRequestMessage(uint32_t base, uint32_t objID)
|
|
{
|
|
uint32_t msgCtrl = 0U;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(CAN_isBaseValid(base));
|
|
ASSERT((objID <= 32U) && (objID > 0U));
|
|
|
|
//
|
|
// Set IF command to read message object control value
|
|
//
|
|
// Set up the request for data from the message object.
|
|
// Transfer the message object to the IF register.
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1CMD) = ((uint32_t)CAN_IF1CMD_CONTROL |
|
|
(objID & CAN_IF1CMD_MSG_NUM_M));
|
|
|
|
//
|
|
// Wait for busy bit to clear
|
|
//
|
|
while((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) == CAN_IF1CMD_BUSY)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Read IF message control
|
|
//
|
|
msgCtrl = HWREGH(base + CAN_O_IF1MCTL);
|
|
|
|
//
|
|
// Check configured DLC size with 0 as this is a remote frame
|
|
//
|
|
ASSERT((msgCtrl & CAN_IF1MCTL_DLC_M) == 0U);
|
|
|
|
//
|
|
// Set Direction to write
|
|
//
|
|
// Set Tx Request Bit for this remote frame
|
|
//
|
|
// Transfer the message object to the message object specified by
|
|
// objID.
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1CMD) = (msgCtrl | (uint32_t)CAN_IF1CMD_DIR |
|
|
(uint32_t)CAN_IF1CMD_TXRQST |
|
|
(objID & CAN_IF1CMD_MSG_NUM_M));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// CAN_readMessage
|
|
//
|
|
//*****************************************************************************
|
|
bool
|
|
CAN_readMessage(uint32_t base, uint32_t objID,
|
|
uint16_t *msgData)
|
|
{
|
|
bool status;
|
|
uint16_t msgCtrl = 0U;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(CAN_isBaseValid(base));
|
|
ASSERT((objID <= 32U) && (objID != 0U));
|
|
|
|
//
|
|
// Set the Message Data A, Data B, and control values to be read
|
|
// on request for data from the message object.
|
|
//
|
|
// Transfer the message object to the message object IF register.
|
|
//
|
|
HWREG_BP(base + CAN_O_IF2CMD) =
|
|
((uint32_t)CAN_IF2CMD_DATA_A | (uint32_t)CAN_IF2CMD_DATA_B |
|
|
(uint32_t)CAN_IF2CMD_CONTROL | (objID & CAN_IF2CMD_MSG_NUM_M) |
|
|
(uint32_t)CAN_IF2CMD_ARB);
|
|
|
|
//
|
|
// Wait for busy bit to clear
|
|
//
|
|
while((HWREGH(base + CAN_O_IF2CMD) & CAN_IF2CMD_BUSY) == CAN_IF2CMD_BUSY)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Read out the IF control Register.
|
|
//
|
|
msgCtrl = HWREGH(base + CAN_O_IF2MCTL);
|
|
|
|
//
|
|
// See if there is new data available.
|
|
//
|
|
if((msgCtrl & CAN_IF2MCTL_NEWDAT) == CAN_IF2MCTL_NEWDAT)
|
|
{
|
|
//
|
|
// Read out the data from the CAN registers.
|
|
//
|
|
CAN_readDataReg(msgData, (base + CAN_O_IF2DATA),
|
|
((uint32_t)msgCtrl & CAN_IF2MCTL_DLC_M));
|
|
|
|
status = true;
|
|
|
|
//
|
|
// Now clear out the new data flag
|
|
//
|
|
HWREG_BP(base + CAN_O_IF2CMD) = ((uint32_t)CAN_IF2CMD_TXRQST |
|
|
(objID & CAN_IF2CMD_MSG_NUM_M));
|
|
|
|
//
|
|
// Wait for busy bit to clear
|
|
//
|
|
while((HWREGH(base + CAN_O_IF2CMD) & CAN_IF2CMD_BUSY) ==
|
|
CAN_IF2CMD_BUSY)
|
|
{
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = false;
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// CAN_readMessageWithID
|
|
//
|
|
//*****************************************************************************
|
|
bool CAN_readMessageWithID(uint32_t base,
|
|
uint32_t objID,
|
|
CAN_MsgFrameType *frameType,
|
|
uint32_t *msgID,
|
|
uint16_t *msgData)
|
|
{
|
|
bool status;
|
|
|
|
//
|
|
// Check the pointers.
|
|
//
|
|
ASSERT(msgID != 0U);
|
|
ASSERT(frameType != 0U);
|
|
|
|
//
|
|
//Read the message first this fills the IF2 registers
|
|
//with received message for that mailbox
|
|
//
|
|
status = CAN_readMessage(base, objID, msgData);
|
|
//
|
|
// See if there is new data available.
|
|
//
|
|
if(status)
|
|
{
|
|
if((HWREG_BP(base + CAN_O_IF2ARB) & CAN_IF2ARB_XTD) != 0U)
|
|
{
|
|
*frameType = CAN_MSG_FRAME_EXT;
|
|
*msgID = ((HWREG_BP(base + CAN_O_IF2ARB)) & CAN_IF2ARB_ID_M);
|
|
}
|
|
else
|
|
{
|
|
*frameType = CAN_MSG_FRAME_STD;
|
|
*msgID = (((HWREG_BP(base + CAN_O_IF2ARB)) &
|
|
CAN_IF2ARB_STD_ID_M) >>
|
|
CAN_IF2ARB_STD_ID_S);
|
|
}
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// CAN_transferMessage
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
CAN_transferMessage(uint32_t base, uint16_t interface, uint32_t objID,
|
|
bool direction)
|
|
{
|
|
uint32_t cmdMaskReg;
|
|
|
|
ASSERT(CAN_isBaseValid(base));
|
|
ASSERT((objID >= 1U) && (objID <= 32U));
|
|
ASSERT((interface == 1U) || (interface == 2U));
|
|
|
|
//
|
|
// This is always a read to the Message object as this call is setting a
|
|
// message object.
|
|
//
|
|
cmdMaskReg =
|
|
((uint32_t)CAN_IF1CMD_DATA_A | (uint32_t)CAN_IF1CMD_DATA_B |
|
|
(uint32_t)CAN_IF1CMD_TXRQST | (uint32_t)CAN_IF1CMD_CONTROL |
|
|
(uint32_t)CAN_IF1CMD_MASK | (uint32_t)CAN_IF1CMD_ARB) |
|
|
(direction ? CAN_IF1CMD_DIR : 0U);
|
|
|
|
//
|
|
// Ensure this IF isn't busy
|
|
//
|
|
while((HWREGH(base + ((interface == 2U) ? CAN_O_IF2CMD : CAN_O_IF1CMD)) &
|
|
CAN_IF1CMD_BUSY) == CAN_IF1CMD_BUSY)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Set up the request for data from the message object. Transfer the
|
|
// message object to the message object specified by objID.
|
|
//
|
|
HWREG_BP(base + ((interface == 2U) ? CAN_O_IF2CMD : CAN_O_IF1CMD)) =
|
|
(cmdMaskReg | (objID & CAN_IF1CMD_MSG_NUM_M));
|
|
|
|
//
|
|
// Wait for busy bit to clear
|
|
//
|
|
while((HWREGH(base + ((interface == 2U) ? CAN_O_IF2CMD : CAN_O_IF1CMD)) &
|
|
CAN_IF1CMD_BUSY) == CAN_IF1CMD_BUSY)
|
|
{
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// CAN_clearMessage
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
CAN_clearMessage(uint32_t base, uint32_t objID)
|
|
{
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(CAN_isBaseValid(base));
|
|
ASSERT((objID >= 1U) && (objID <= 32U));
|
|
|
|
//
|
|
// Wait for busy bit to clear
|
|
//
|
|
while((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) == CAN_IF1CMD_BUSY)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Clear the message valid bit in the arbitration register. This disables
|
|
// the mailbox.
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1ARB) = 0U;
|
|
|
|
//
|
|
// Initiate programming the message object
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1CMD) =
|
|
(((uint32_t)CAN_IF1CMD_DIR | (uint32_t)CAN_IF1CMD_ARB) |
|
|
(objID & CAN_IF1CMD_MSG_NUM_M));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// CAN_disableMessageObject
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
CAN_disableMessageObject(uint32_t base, uint32_t objID)
|
|
{
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(CAN_isBaseValid(base));
|
|
ASSERT((objID >= 1U) && (objID <= 32U));
|
|
|
|
//
|
|
// Wait for busy bit to clear
|
|
//
|
|
while((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) == CAN_IF1CMD_BUSY)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Clear the message valid bit in the arbitration register. This disables
|
|
// the mailbox.
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1ARB) = 0U;
|
|
|
|
//
|
|
// Initiate programming the message object
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1CMD) =
|
|
(((uint32_t)CAN_IF1CMD_DIR | (uint32_t)CAN_IF1CMD_ARB) |
|
|
(objID & CAN_IF1CMD_MSG_NUM_M));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// CAN_disableAllMessageObjects
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
CAN_disableAllMessageObjects(uint32_t base)
|
|
{
|
|
uint32_t objID;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(CAN_isBaseValid(base));
|
|
|
|
//
|
|
// Loop to disable all valid message objects
|
|
//
|
|
for(objID = 0x01UL; objID <= 0x20UL; objID++)
|
|
{
|
|
//
|
|
// Wait for busy bit to clear
|
|
//
|
|
while((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) == CAN_IF1CMD_BUSY)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Clear the message valid bit in the arbitration register. This disables
|
|
// the mailbox.
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1ARB) = 0U;
|
|
|
|
//
|
|
// Initiate programming the message object
|
|
//
|
|
HWREG_BP(base + CAN_O_IF1CMD) =
|
|
(((uint32_t)CAN_IF1CMD_DIR | (uint32_t)CAN_IF1CMD_ARB) |
|
|
(objID & CAN_IF1CMD_MSG_NUM_M));
|
|
}
|
|
}
|
|
|