From 44b979ac3dc53b29ee8176517b7d9a10935630c0 Mon Sep 17 00:00:00 2001 From: Yuval Adam Date: Mon, 29 Oct 2012 21:36:23 +0200 Subject: Initial code --- driverlib/can.c | 2265 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2265 insertions(+) create mode 100644 driverlib/can.c (limited to 'driverlib/can.c') diff --git a/driverlib/can.c b/driverlib/can.c new file mode 100644 index 0000000..d55ee80 --- /dev/null +++ b/driverlib/can.c @@ -0,0 +1,2265 @@ +//***************************************************************************** +// +// can.c - Driver for the CAN module. +// +// Copyright (c) 2006-2012 Texas Instruments Incorporated. All rights reserved. +// Software License Agreement +// +// 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. +// +// This is part of revision 9453 of the Stellaris Peripheral Driver Library. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup can_api +//! @{ +// +//***************************************************************************** + +#include "inc/hw_can.h" +#include "inc/hw_ints.h" +#include "inc/hw_nvic.h" +#include "inc/hw_memmap.h" +#include "inc/hw_types.h" +#include "driverlib/can.h" +#include "driverlib/debug.h" +#include "driverlib/interrupt.h" + +//***************************************************************************** +// +// This is the maximum number that can be stored as an 11bit Message +// identifier. +// +//***************************************************************************** +#define CAN_MAX_11BIT_MSG_ID 0x7ff + +//***************************************************************************** +// +// This is used as the loop delay for accessing the CAN controller registers. +// +//***************************************************************************** +#define CAN_RW_DELAY 5 + +//***************************************************************************** +// +// The maximum CAN bit timing divisor is 19. +// +//***************************************************************************** +#define CAN_MAX_BIT_DIVISOR 19 + +//***************************************************************************** +// +// The minimum CAN bit timing divisor is 4. +// +//***************************************************************************** +#define CAN_MIN_BIT_DIVISOR 4 + +//***************************************************************************** +// +// The maximum CAN pre-divisor is 1024. +// +//***************************************************************************** +#define CAN_MAX_PRE_DIVISOR 1024 + +//***************************************************************************** +// +// The minimum CAN pre-divisor is 1. +// +//***************************************************************************** +#define CAN_MIN_PRE_DIVISOR 1 + +//***************************************************************************** +// +// Converts a set of CAN bit timing values into the value that needs to be +// programmed into the CAN_BIT register to achieve those timings. +// +//***************************************************************************** +#define CAN_BIT_VALUE(seg1, seg2, sjw) \ + ((((seg1 - 1) << CAN_BIT_TSEG1_S) & \ + CAN_BIT_TSEG1_M) | \ + (((seg2 - 1) << CAN_BIT_TSEG2_S) & \ + CAN_BIT_TSEG2_M) | \ + (((sjw - 1) << CAN_BIT_SJW_S) & \ + CAN_BIT_SJW_M)) + +//***************************************************************************** +// +// This table is used by the CANBitRateSet() API as the register defaults for +// the bit timing values. +// +//***************************************************************************** +static const unsigned short g_usCANBitValues[] = +{ + CAN_BIT_VALUE(2, 1, 1), // 4 clocks/bit + CAN_BIT_VALUE(3, 1, 1), // 5 clocks/bit + CAN_BIT_VALUE(3, 2, 2), // 6 clocks/bit + CAN_BIT_VALUE(4, 2, 2), // 7 clocks/bit + CAN_BIT_VALUE(4, 3, 3), // 8 clocks/bit + CAN_BIT_VALUE(5, 3, 3), // 9 clocks/bit + CAN_BIT_VALUE(5, 4, 4), // 10 clocks/bit + CAN_BIT_VALUE(6, 4, 4), // 11 clocks/bit + CAN_BIT_VALUE(6, 5, 4), // 12 clocks/bit + CAN_BIT_VALUE(7, 5, 4), // 13 clocks/bit + CAN_BIT_VALUE(7, 6, 4), // 14 clocks/bit + CAN_BIT_VALUE(8, 6, 4), // 15 clocks/bit + CAN_BIT_VALUE(8, 7, 4), // 16 clocks/bit + CAN_BIT_VALUE(9, 7, 4), // 17 clocks/bit + CAN_BIT_VALUE(9, 8, 4), // 18 clocks/bit + CAN_BIT_VALUE(10, 8, 4) // 19 clocks/bit +}; + +//***************************************************************************** +// +//! \internal +//! Checks a CAN base address. +//! +//! \param ulBase is the base address of the CAN controller. +//! +//! This function determines if a CAN controller base address is valid. +//! +//! \return Returns \b true if the base address is valid and \b false +//! otherwise. +// +//***************************************************************************** +#ifdef DEBUG +static tBoolean +CANBaseValid(unsigned long ulBase) +{ + return((ulBase == CAN0_BASE) || (ulBase == CAN1_BASE) || + (ulBase == CAN2_BASE)); +} +#endif + +//***************************************************************************** +// +//! \internal +//! +//! Returns the CAN controller interrupt number. +//! +//! \param ulBase is the base address of the selected CAN controller +//! +//! Given a CAN controller base address, this function returns the +//! corresponding interrupt number. +//! +//! This function replaces the original CANGetIntNumber() API and performs the +//! same actions. A macro is provided in can.h to map the original +//! API to this API. +//! +//! \return Returns a CAN interrupt number, or -1 if \e ulPort is invalid. +// +//***************************************************************************** +static long +CANIntNumberGet(unsigned long ulBase) +{ + long lIntNumber; + + // + // Return the interrupt number for the given CAN controller. + // + switch(ulBase) + { + // + // Return the interrupt number for CAN 0 + // + case CAN0_BASE: + { + lIntNumber = INT_CAN0; + break; + } + + // + // Return the interrupt number for CAN 1 + // + case CAN1_BASE: + { + lIntNumber = INT_CAN1; + break; + } + + // + // Return the interrupt number for CAN 2 + // + case CAN2_BASE: + { + lIntNumber = INT_CAN2; + break; + } + + // + // Return -1 to indicate a bad address was passed in. + // + default: + { + lIntNumber = -1; + } + } + return(lIntNumber); +} + +//***************************************************************************** +// +//! \internal +//! +//! Reads a CAN controller register. +//! +//! \param ulRegAddress is the full address of the CAN register to be read. +//! +//! This function performs the necessary synchronization to read from a CAN +//! controller register. +//! +//! This function replaces the original CANReadReg() API and performs the same +//! actions. A macro is provided in can.h to map the original API to +//! this API. +//! +//! \note This function provides the delay required to access CAN registers. +//! This delay is required when accessing CAN registers directly. +//! +//! \return Returns the value read from the register. +// +//***************************************************************************** +static unsigned long +CANRegRead(unsigned long ulRegAddress) +{ + volatile unsigned long ulDelay; + unsigned long ulRetVal; + unsigned long ulIntNumber; + unsigned long ulReenableInts; + + // + // Get the CAN interrupt number from the register base address. + // + ulIntNumber = CANIntNumberGet(ulRegAddress & 0xfffff000); + + // + // Make sure that the CAN base address was valid. + // + ASSERT(ulIntNumber != (unsigned long)-1); + + // + // Remember current state so that CAN interrupts are only re-enabled if + // they were already enabled. + // + ulReenableInts = HWREG(NVIC_EN1) & (1 << (ulIntNumber - 48)); + + // + // If the CAN interrupt was enabled then disable it. + // + if(ulReenableInts) + { + IntDisable(ulIntNumber); + } + + // + // Trigger the initial read to the CAN controller. The value returned at + // this point is not valid. + // + HWREG(ulRegAddress); + + // + // This delay is necessary for the CAN have the correct data on the bus. + // + for(ulDelay = 0; ulDelay < CAN_RW_DELAY; ulDelay++) + { + } + + // + // Do the final read that has the valid value of the register. + // + ulRetVal = HWREG(ulRegAddress); + + // + // Enable CAN interrupts if they were enabled before this call. + // + if(ulReenableInts) + { + IntEnable(ulIntNumber); + } + + return(ulRetVal); +} + +//***************************************************************************** +// +//! \internal +//! +//! Writes a CAN controller register. +//! +//! \param ulRegAddress is the full address of the CAN register to be written. +//! \param ulRegValue is the value to write into the register specified by +//! \e ulRegAddress. +//! +//! This function takes care of the synchronization necessary to write to a +//! CAN controller register. +//! +//! This function replaces the original CANWriteReg() API and performs the same +//! actions. A macro is provided in can.h to map the original API to +//! this API. +//! +//! \note The delays in this function are required when accessing CAN registers +//! directly. +//! +//! \return None. +// +//***************************************************************************** +static void +CANRegWrite(unsigned long ulRegAddress, unsigned long ulRegValue) +{ + volatile unsigned long ulDelay; + + // + // Trigger the initial write to the CAN controller. The value will not make + // it out to the CAN controller for CAN_RW_DELAY cycles. + // + HWREG(ulRegAddress) = ulRegValue; + + // + // Delay to allow the CAN controller to receive the new data. + // + for(ulDelay = 0; ulDelay < CAN_RW_DELAY; ulDelay++) + { + } +} + +//***************************************************************************** +// +//! \internal +//! +//! Copies data from a buffer to the CAN Data registers. +//! +//! \param pucData is a pointer to the data to be written out to the CAN +//! controller's data registers. +//! \param pulRegister is an unsigned long pointer to the first register of the +//! CAN controller's data registers. For example, in order to use the IF1 +//! register set on CAN controller 0, the value would be: \b CAN0_BASE \b + +//! \b CAN_O_IF1DA1. +//! \param iSize is the number of bytes to copy into the CAN controller. +//! +//! This function takes the steps necessary to copy data from a contiguous +//! buffer in memory into the non-contiguous data registers used by the CAN +//! controller. This function is rarely used outside of the CANMessageSet() +//! function. +//! +//! This function replaces the original CANWriteDataReg() API and performs the +//! same actions. A macro is provided in can.h to map the original +//! API to this API. +//! +//! \return None. +// +//***************************************************************************** +static void +CANDataRegWrite(unsigned char *pucData, unsigned long *pulRegister, + unsigned long ulSize) +{ + unsigned long ulIdx, ulValue; + + // + // Loop always copies 1 or 2 bytes per iteration. + // + for(ulIdx = 0; ulIdx < ulSize; ) + { + + // + // Write out the data 16 bits at a time since this is how the registers + // are aligned in memory. + // + ulValue = pucData[ulIdx++]; + + // + // Only write the second byte if needed otherwise it will be zero. + // + if(ulIdx < ulSize) + { + ulValue |= (pucData[ulIdx++] << 8); + } + CANRegWrite((unsigned long)(pulRegister++), ulValue); + } +} + +//***************************************************************************** +// +//! \internal +//! +//! Copies data from a buffer to the CAN Data registers. +//! +//! \param pucData is a pointer to the location to store the data read from the +//! CAN controller's data registers. +//! \param pulRegister is an unsigned long pointer to the first register of the +//! CAN controller's data registers. For example, in order to use the IF1 +//! register set on CAN controller 1, the value would be: \b CAN0_BASE \b + +//! \b CAN_O_IF1DA1. +//! \param iSize is the number of bytes to copy from the CAN controller. +//! +//! This function takes the steps necessary to copy data to a contiguous buffer +//! in memory from the non-contiguous data registers used by the CAN +//! controller. This function is rarely used outside of the CANMessageGet() +//! function. +//! +//! This function replaces the original CANReadDataReg() API and performs the +//! same actions. A macro is provided in can.h to map the original +//! API to this API. +//! +//! \return None. +// +//***************************************************************************** +static void +CANDataRegRead(unsigned char *pucData, unsigned long *pulRegister, + unsigned long ulSize) +{ + unsigned long ulIdx, ulValue; + + // + // Loop always copies 1 or 2 bytes per iteration. + // + for(ulIdx = 0; ulIdx < ulSize; ) + { + // + // Read out the data 16 bits at a time since this is how the registers + // are aligned in memory. + // + ulValue = CANRegRead((unsigned long)(pulRegister++)); + + // + // Store the first byte. + // + pucData[ulIdx++] = (unsigned char)ulValue; + + // + // Only read the second byte if needed. + // + if(ulIdx < ulSize) + { + pucData[ulIdx++] = (unsigned char)(ulValue >> 8); + } + } +} + +//***************************************************************************** +// +//! Initializes the CAN controller after reset. +//! +//! \param ulBase is the base address of the CAN controller. +//! +//! 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. +// +//***************************************************************************** +void +CANInit(unsigned long ulBase) +{ + unsigned long ulMsg; + + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + + // + // 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. + // + CANRegWrite(ulBase + CAN_O_CTL, CAN_CTL_INIT); + + // + // Wait for busy bit to clear + // + while(CANRegRead(ulBase + 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. The same arb reg is used to program all the message objects. + // + CANRegWrite(ulBase + CAN_O_IF1CMSK, CAN_IF1CMSK_WRNRD | CAN_IF1CMSK_ARB | + CAN_IF1CMSK_CONTROL); + CANRegWrite(ulBase + CAN_O_IF1ARB2, 0); + CANRegWrite(ulBase + CAN_O_IF1MCTL, 0); + + // + // Loop through to program all 32 message objects + // + for(ulMsg = 1; ulMsg <= 32; ulMsg++) + { + // + // Wait for busy bit to clear + // + while(CANRegRead(ulBase + CAN_O_IF1CRQ) & CAN_IF1CRQ_BUSY) + { + } + + // + // Initiate programming the message object + // + CANRegWrite(ulBase + CAN_O_IF1CRQ, ulMsg); + } + + // + // Make sure that the interrupt and new data flags are updated for the + // message objects. + // + CANRegWrite(ulBase + CAN_O_IF1CMSK, CAN_IF1CMSK_NEWDAT | + CAN_IF1CMSK_CLRINTPND); + + // + // Loop through to program all 32 message objects + // + for(ulMsg = 1; ulMsg <= 32; ulMsg++) + { + // + // Wait for busy bit to clear. + // + while(CANRegRead(ulBase + CAN_O_IF1CRQ) & CAN_IF1CRQ_BUSY) + { + } + + // + // Initiate programming the message object + // + CANRegWrite(ulBase + CAN_O_IF1CRQ, ulMsg); + } + + // + // Acknowledge any pending status interrupts. + // + CANRegRead(ulBase + CAN_O_STS); +} + +//***************************************************************************** +// +//! Enables the CAN controller. +//! +//! \param ulBase is the base address of the CAN controller to enable. +//! +//! Enables the CAN controller for message processing. Once enabled, the +//! controller automatically transmits any pending frames, and processes any +//! received frames. The controller can be stopped by calling CANDisable(). +//! Prior to calling CANEnable(), CANInit() should have been called to +//! initialize the controller and the CAN bus clock should be configured by +//! calling CANBitTimingSet(). +//! +//! \return None. +// +//***************************************************************************** +void +CANEnable(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + + // + // Clear the init bit in the control register. + // + CANRegWrite(ulBase + CAN_O_CTL, + CANRegRead(ulBase + CAN_O_CTL) & ~CAN_CTL_INIT); +} + +//***************************************************************************** +// +//! Disables the CAN controller. +//! +//! \param ulBase is the base address of the CAN controller to disable. +//! +//! Disables the CAN controller for message processing. When disabled, the +//! controller no longer automatically processes data on the CAN bus. The +//! controller can be restarted by calling CANEnable(). The state of the CAN +//! controller and the message objects in the controller are left as they were +//! before this call was made. +//! +//! \return None. +// +//***************************************************************************** +void +CANDisable(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + + // + // Set the init bit in the control register. + // + CANRegWrite(ulBase + CAN_O_CTL, + CANRegRead(ulBase + CAN_O_CTL) | CAN_CTL_INIT); +} + +//***************************************************************************** +// +//! Reads the current settings for the CAN controller bit timing. +//! +//! \param ulBase is the base address of the CAN controller. +//! \param pClkParms is a pointer to a structure to hold the timing parameters. +//! +//! This function reads the current configuration of the CAN controller bit +//! clock timing and stores the resulting information in the structure +//! supplied by the caller. Refer to CANBitTimingSet() for the meaning of the +//! values that are returned in the structure pointed to by \e pClkParms. +//! +//! This function replaces the original CANGetBitTiming() API and performs the +//! same actions. A macro is provided in can.h to map the original +//! API to this API. +//! +//! \return None. +// +//***************************************************************************** +void +CANBitTimingGet(unsigned long ulBase, tCANBitClkParms *pClkParms) +{ + unsigned long ulBitReg; + + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + ASSERT(pClkParms != 0); + + // + // Read out all the bit timing values from the CAN controller registers. + // + ulBitReg = CANRegRead(ulBase + CAN_O_BIT); + + // + // Set the phase 2 segment. + // + pClkParms->ulPhase2Seg = + ((ulBitReg & CAN_BIT_TSEG2_M) >> CAN_BIT_TSEG2_S) + 1; + + // + // Set the phase 1 segment. + // + pClkParms->ulSyncPropPhase1Seg = + ((ulBitReg & CAN_BIT_TSEG1_M) >> CAN_BIT_TSEG1_S) + 1; + + // + // Set the synchronous jump width. + // + pClkParms->ulSJW = ((ulBitReg & CAN_BIT_SJW_M) >> CAN_BIT_SJW_S) + 1; + + // + // Set the pre-divider for the CAN bus bit clock. + // + pClkParms->ulQuantumPrescaler = + ((ulBitReg & CAN_BIT_BRP_M) | + ((CANRegRead(ulBase + CAN_O_BRPE) & CAN_BRPE_BRPE_M) << 6)) + 1; +} + +//***************************************************************************** +// +//! Sets the CAN bit timing values to a nominal setting based on a desired +//! bit rate. +//! +//! \param ulBase is the base address of the CAN controller. +//! \param ulSourceClock is the system clock for the device in Hz. +//! \param ulBitRate is the desired bit rate. +//! +//! This function sets the CAN bit timing for the bit rate passed in the +//! \e ulBitRate parameter based on the \e ulSourceClock parameter. Because the +//! CAN clock is based off of the system clock, the calling function should pass +//! in the source clock rate either by retrieving it from SysCtlClockGet() or +//! using a specific value in Hz. The CAN bit timing is calculated assuming a +//! minimal amount of propagation delay, which works for most cases where +//! the network length is short. If tighter timing requirements or longer +//! network lengths are needed, then the CANBitTimingSet() function is +//! available for full customization of all of the CAN bit timing values. +//! Because not all bit rates can be matched exactly, the bit rate is set to +//! the value closest to the desired bit rate without being higher than the +//! \e ulBitRate value. +//! +//! \note On some devices the source clock is fixed at 8MHz so the +//! \e ulSourceClock should be set to 8000000. +//! +//! \return This function returns the bit rate that the CAN controller was +//! configured to use or it returns 0 to indicate that the bit rate was not +//! changed because the requested bit rate was not valid. +//! +//***************************************************************************** +unsigned long +CANBitRateSet(unsigned long ulBase, unsigned long ulSourceClock, + unsigned long ulBitRate) +{ + unsigned long ulDesiredRatio; + unsigned long ulCANBits; + unsigned long ulPreDivide; + unsigned long ulRegValue; + unsigned short usCANCTL; + + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + ASSERT(ulSourceClock != 0); + ASSERT(ulBitRate != 0); + + // + // Calculate the desired clock rate. + // + ulDesiredRatio = ulSourceClock / ulBitRate; + + // + // Make sure that the ratio of CAN bit rate to processor clock is not too + // small or too large. + // + ASSERT(ulDesiredRatio <= (CAN_MAX_PRE_DIVISOR * CAN_MAX_BIT_DIVISOR)); + ASSERT(ulDesiredRatio >= (CAN_MIN_PRE_DIVISOR * CAN_MIN_BIT_DIVISOR)); + + // + // Make sure that the Desired Ratio is not too large. This enforces the + // requirement that the bit rate is larger than requested. + // + if((ulSourceClock / ulDesiredRatio) > ulBitRate) + { + ulDesiredRatio += 1; + } + + // + // Check all possible values to find a matching value. + // + while(ulDesiredRatio <= (CAN_MAX_PRE_DIVISOR * CAN_MAX_BIT_DIVISOR)) + { + // + // Loop through all possible CAN bit divisors. + // + for(ulCANBits = CAN_MAX_BIT_DIVISOR; ulCANBits >= CAN_MIN_BIT_DIVISOR; + ulCANBits--) + { + // + // For a given CAN bit divisor save the pre divisor. + // + ulPreDivide = ulDesiredRatio / ulCANBits; + + // + // If the calculated divisors match the desired clock ratio then + // return these bit rate and set the CAN bit timing. + // + if((ulPreDivide * ulCANBits) == ulDesiredRatio) + { + // + // Start building the bit timing value by adding the bit timing + // in time quanta. + // + ulRegValue = g_usCANBitValues[ulCANBits - CAN_MIN_BIT_DIVISOR]; + + // + // To set the bit timing register, the controller must be placed + // in init mode (if not already), and also configuration change + // bit enabled. The state of the register should be saved + // so it can be restored. + // + usCANCTL = CANRegRead(ulBase + CAN_O_CTL); + CANRegWrite(ulBase + CAN_O_CTL, + usCANCTL | CAN_CTL_INIT | CAN_CTL_CCE); + + // + // Now add in the pre-scalar on the bit rate. + // + ulRegValue |= ((ulPreDivide - 1) & CAN_BIT_BRP_M); + + // + // Set the clock bits in the and the lower bits of the + // pre-scalar. + // + CANRegWrite(ulBase + CAN_O_BIT, ulRegValue); + + // + // Set the divider upper bits in the extension register. + // + CANRegWrite(ulBase + CAN_O_BRPE, + ((ulPreDivide - 1) >> 6) & CAN_BRPE_BRPE_M); + + // + // Restore the saved CAN Control register. + // + CANRegWrite(ulBase + CAN_O_CTL, usCANCTL); + + // + // Return the computed bit rate. + // + return(ulSourceClock / ( ulPreDivide * ulCANBits)); + } + } + + // + // Move the divisor up one and look again. Only in rare cases are + // more than 2 loops required to find the value. + // + ulDesiredRatio++; + } + + // + // A valid combination could not be found, so return 0 to indicate that the + // bit rate was not changed. + // + return(0); +} + +//***************************************************************************** +// +//! Configures the CAN controller bit timing. +//! +//! \param ulBase is the base address of the CAN controller. +//! \param pClkParms points to the structure with the clock parameters. +//! +//! Configures the various timing parameters for the CAN bus bit timing: +//! Propagation segment, Phase Buffer 1 segment, Phase Buffer 2 segment, and +//! the Synchronization Jump Width. The values for Propagation and Phase +//! Buffer 1 segments are derived from the combination +//! \e pClkParms->ulSyncPropPhase1Seg parameter. Phase Buffer 2 is determined +//! from the \e pClkParms->ulPhase2Seg parameter. These two parameters, along +//! with \e pClkParms->ulSJW are based in units of bit time quanta. The actual +//! quantum time is determined by the \e pClkParms->ulQuantumPrescaler value, +//! which specifies the divisor for the CAN module clock. +//! +//! The total bit time, in quanta, is the sum of the two Seg parameters, +//! as follows: +//! +//! bit_time_q = ulSyncPropPhase1Seg + ulPhase2Seg + 1 +//! +//! Note that the Sync_Seg is always one quantum in duration, and is added +//! to derive the correct duration of Prop_Seg and Phase1_Seg. +//! +//! The equation to determine the actual bit rate is as follows: +//! +//! CAN Clock / +//! ((\e ulSyncPropPhase1Seg + \e ulPhase2Seg + 1) * (\e ulQuantumPrescaler)) +//! +//! Thus with \e ulSyncPropPhase1Seg = 4, \e ulPhase2Seg = 1, +//! \e ulQuantumPrescaler = 2 and an 8 MHz CAN clock, the bit rate is +//! (8 MHz) / ((5 + 2 + 1) * 2) or 500 Kbit/sec. +//! +//! This function replaces the original CANSetBitTiming() API and performs the +//! same actions. A macro is provided in can.h to map the original +//! API to this API. +//! +//! \return None. +// +//***************************************************************************** +void +CANBitTimingSet(unsigned long ulBase, tCANBitClkParms *pClkParms) +{ + unsigned long ulBitReg, ulSavedInit; + + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + ASSERT(pClkParms != 0); + + // + // The phase 1 segment must be in the range from 2 to 16. + // + ASSERT((pClkParms->ulSyncPropPhase1Seg >= 2) && + (pClkParms->ulSyncPropPhase1Seg <= 16)); + + // + // The phase 2 segment must be in the range from 1 to 8. + // + ASSERT((pClkParms->ulPhase2Seg >= 1) && (pClkParms->ulPhase2Seg <= 8)); + + // + // The synchronous jump windows must be in the range from 1 to 4. + // + ASSERT((pClkParms->ulSJW >= 1) && (pClkParms->ulSJW <= 4)); + + // + // The CAN clock pre-divider must be in the range from 1 to 1024. + // + ASSERT((pClkParms->ulQuantumPrescaler <= 1024) && + (pClkParms->ulQuantumPrescaler >= 1)); + + // + // 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. + // + ulSavedInit = CANRegRead(ulBase + CAN_O_CTL); + CANRegWrite(ulBase + CAN_O_CTL, ulSavedInit | CAN_CTL_INIT | CAN_CTL_CCE); + + // + // Set the bit fields of the bit timing register according to the parms. + // + ulBitReg = (((pClkParms->ulPhase2Seg - 1) << CAN_BIT_TSEG2_S) & + CAN_BIT_TSEG2_M); + ulBitReg |= (((pClkParms->ulSyncPropPhase1Seg - 1) << CAN_BIT_TSEG1_S) & + CAN_BIT_TSEG1_M); + ulBitReg |= ((pClkParms->ulSJW - 1) << CAN_BIT_SJW_S) & CAN_BIT_SJW_M; + ulBitReg |= (pClkParms->ulQuantumPrescaler - 1) & CAN_BIT_BRP_M; + CANRegWrite(ulBase + CAN_O_BIT, ulBitReg); + + // + // Set the divider upper bits in the extension register. + // + CANRegWrite(ulBase + CAN_O_BRPE, + ((pClkParms->ulQuantumPrescaler - 1) >> 6) & CAN_BRPE_BRPE_M); + + // + // Clear the config change bit, and restore the init bit. + // + ulSavedInit &= ~CAN_CTL_CCE; + + // + // If Init was not set before, then clear it. + // + if(ulSavedInit & CAN_CTL_INIT) + { + ulSavedInit &= ~CAN_CTL_INIT; + } + CANRegWrite(ulBase + CAN_O_CTL, ulSavedInit); +} + +//***************************************************************************** +// +//! Registers an interrupt handler for the CAN controller. +//! +//! \param ulBase is the base address of the CAN controller. +//! \param pfnHandler is a pointer to the function to be called when the +//! enabled CAN interrupts occur. +//! +//! This function registers the interrupt handler in the interrupt vector +//! table, and enables CAN interrupts on the interrupt controller; specific CAN +//! interrupt sources must be enabled using CANIntEnable(). The interrupt +//! handler being registered must clear the source of the interrupt using +//! CANIntClear(). +//! +//! If the application is using a static interrupt vector table stored in +//! flash, then it is not necessary to register the interrupt handler this way. +//! Instead, IntEnable() should be used to enable CAN interrupts on the +//! interrupt controller. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +CANIntRegister(unsigned long ulBase, void (*pfnHandler)(void)) +{ + unsigned long ulIntNumber; + + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + + // + // Get the actual interrupt number for this CAN controller. + // + ulIntNumber = CANIntNumberGet(ulBase); + + // + // Register the interrupt handler. + // + IntRegister(ulIntNumber, pfnHandler); + + // + // Enable the Ethernet interrupt. + // + IntEnable(ulIntNumber); +} + +//***************************************************************************** +// +//! Unregisters an interrupt handler for the CAN controller. +//! +//! \param ulBase is the base address of the controller. +//! +//! This function unregisters the previously registered interrupt handler and +//! disables the interrupt in the interrupt controller. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +CANIntUnregister(unsigned long ulBase) +{ + unsigned long ulIntNumber; + + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + + // + // Get the actual interrupt number for this CAN controller. + // + ulIntNumber = CANIntNumberGet(ulBase); + + // + // Disable the CAN interrupt. + // + IntDisable(ulIntNumber); + + // + // Register the interrupt handler. + // + IntUnregister(ulIntNumber); +} + +//***************************************************************************** +// +//! Enables individual CAN controller interrupt sources. +//! +//! \param ulBase is the base address of the CAN controller. +//! \param ulIntFlags is the bit mask of the interrupt sources to be enabled. +//! +//! This function enables specific interrupt sources of the CAN controller. +//! Only enabled sources cause a processor interrupt. +//! +//! The \e ulIntFlags parameter is the logical OR of any of the following: +//! +//! - \b CAN_INT_ERROR - a controller error condition has occurred +//! - \b CAN_INT_STATUS - a message transfer has completed, or a bus error has +//! been detected +//! - \b CAN_INT_MASTER - allow CAN controller to generate interrupts +//! +//! In order to generate any interrupts, \b CAN_INT_MASTER must be enabled. +//! Further, for any particular transaction from a message object to generate +//! an interrupt, that message object must have interrupts enabled (see +//! CANMessageSet()). \b CAN_INT_ERROR will generate an interrupt if the +//! controller enters the ``bus off'' condition, or if the error counters reach +//! a limit. \b CAN_INT_STATUS generates an interrupt under quite a few +//! status conditions and may provide more interrupts than the application +//! needs to handle. When an interrupt occurs, use CANIntStatus() to determine +//! the cause. +//! +//! \return None. +// +//***************************************************************************** +void +CANIntEnable(unsigned long ulBase, unsigned long ulIntFlags) +{ + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + ASSERT((ulIntFlags & ~(CAN_CTL_EIE | CAN_CTL_SIE | CAN_CTL_IE)) == 0); + + // + // Enable the specified interrupts. + // + CANRegWrite(ulBase + CAN_O_CTL, + CANRegRead(ulBase + CAN_O_CTL) | ulIntFlags); +} + +//***************************************************************************** +// +//! Disables individual CAN controller interrupt sources. +//! +//! \param ulBase is the base address of the CAN controller. +//! \param ulIntFlags is the bit mask of the interrupt sources to be disabled. +//! +//! Disables the specified CAN controller interrupt sources. Only enabled +//! interrupt sources can cause a processor interrupt. +//! +//! The \e ulIntFlags parameter has the same definition as in the +//! CANIntEnable() function. +//! +//! \return None. +// +//***************************************************************************** +void +CANIntDisable(unsigned long ulBase, unsigned long ulIntFlags) +{ + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + ASSERT((ulIntFlags & ~(CAN_CTL_EIE | CAN_CTL_SIE | CAN_CTL_IE)) == 0); + + // + // Disable the specified interrupts. + // + CANRegWrite(ulBase + CAN_O_CTL, + CANRegRead(ulBase + CAN_O_CTL) & ~(ulIntFlags)); +} + +//***************************************************************************** +// +//! Returns the current CAN controller interrupt status. +//! +//! \param ulBase is the base address of the CAN controller. +//! \param eIntStsReg indicates which interrupt status register to read +//! +//! This function returns the value of one of two interrupt status registers. +//! The interrupt status register read is determined by the \e eIntStsReg +//! parameter, which can have one of the following values: +//! +//! - \b CAN_INT_STS_CAUSE - indicates the cause of the interrupt +//! - \b CAN_INT_STS_OBJECT - indicates pending interrupts of all message +//! objects +//! +//! \b CAN_INT_STS_CAUSE returns the value of the controller interrupt register +//! and indicates the cause of the interrupt. The value returned is +//! \b CAN_INT_INTID_STATUS if the cause is a status interrupt. In this case, +//! the status register should be read with the CANStatusGet() function. +//! Calling this function to read the status also clears the status +//! interrupt. If the value of the interrupt register is in the range 1-32, +//! then this indicates the number of the highest priority message object that +//! has an interrupt pending. The message object interrupt can be cleared by +//! using the CANIntClear() function, or by reading the message using +//! CANMessageGet() in the case of a received message. The interrupt handler +//! can read the interrupt status again to make sure all pending interrupts are +//! cleared before returning from the interrupt. +//! +//! \b CAN_INT_STS_OBJECT returns a bit mask indicating which message objects +//! have pending interrupts. This value can be used to discover all of the +//! pending interrupts at once, as opposed to repeatedly reading the interrupt +//! register by using \b CAN_INT_STS_CAUSE. +//! +//! \return Returns the value of one of the interrupt status registers. +// +//***************************************************************************** +unsigned long +CANIntStatus(unsigned long ulBase, tCANIntStsReg eIntStsReg) +{ + unsigned long ulStatus; + + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + + // + // See which status the caller is looking for. + // + switch(eIntStsReg) + { + // + // The caller wants the global interrupt status for the CAN controller + // specified by ulBase. + // + case CAN_INT_STS_CAUSE: + { + ulStatus = CANRegRead(ulBase + CAN_O_INT); + break; + } + + // + // The caller wants the current message status interrupt for all + // messages. + // + case CAN_INT_STS_OBJECT: + { + // + // Read and combine both 16 bit values into one 32bit status. + // + ulStatus = (CANRegRead(ulBase + CAN_O_MSG1INT) & + CAN_MSG1INT_INTPND_M); + ulStatus |= (CANRegRead(ulBase + CAN_O_MSG2INT) << 16); + break; + } + + // + // Request was for unknown status so just return 0. + // + default: + { + ulStatus = 0; + break; + } + } + + // + // Return the interrupt status value + // + return(ulStatus); +} + +//***************************************************************************** +// +//! Clears a CAN interrupt source. +//! +//! \param ulBase is the base address of the CAN controller. +//! \param ulIntClr is a value indicating which interrupt source to clear. +//! +//! This function can be used to clear a specific interrupt source. The +//! \e ulIntClr parameter should be one of the following values: +//! +//! - \b CAN_INT_INTID_STATUS - Clears a status interrupt. +//! - 1-32 - Clears the specified message object interrupt +//! +//! It is not necessary to use this function to clear an interrupt. This +//! function should only be used if the application wants to clear an interrupt +//! source without taking the normal interrupt action. +//! +//! Normally, the status interrupt is cleared by reading the controller status +//! using CANStatusGet(). A specific message object interrupt is normally +//! cleared by reading the message object using CANMessageGet(). +//! +//! \note Because there is a write buffer in the Cortex-M processor, it may +//! take several clock cycles before the interrupt source is actually cleared. +//! Therefore, it is recommended that the interrupt source be cleared early in +//! the interrupt handler (as opposed to the very last action) to avoid +//! returning from the interrupt handler before the interrupt source is +//! actually cleared. Failure to do so may result in the interrupt handler +//! being immediately reentered (because the interrupt controller still sees +//! the interrupt source asserted). +//! +//! \return None. +// +//***************************************************************************** +void +CANIntClear(unsigned long ulBase, unsigned long ulIntClr) +{ + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + ASSERT((ulIntClr == CAN_INT_INTID_STATUS) || + ((ulIntClr>=1) && (ulIntClr <=32))); + + if(ulIntClr == CAN_INT_INTID_STATUS) + { + // + // Simply read and discard the status to clear the interrupt. + // + CANRegRead(ulBase + CAN_O_STS); + } + else + { + // + // Wait to be sure that this interface is not busy. + // + while(CANRegRead(ulBase + CAN_O_IF1CRQ) & CAN_IF1CRQ_BUSY) + { + } + + // + // Only change the interrupt pending state by setting only the + // CAN_IF1CMSK_CLRINTPND bit. + // + CANRegWrite(ulBase + CAN_O_IF1CMSK, CAN_IF1CMSK_CLRINTPND); + + // + // Send the clear pending interrupt command to the CAN controller. + // + CANRegWrite(ulBase + CAN_O_IF1CRQ, ulIntClr & CAN_IF1CRQ_MNUM_M); + + // + // Wait to be sure that this interface is not busy. + // + while(CANRegRead(ulBase + CAN_O_IF1CRQ) & CAN_IF1CRQ_BUSY) + { + } + } +} + +//***************************************************************************** +// +//! Sets the CAN controller automatic retransmission behavior. +//! +//! \param ulBase is the base address of the CAN controller. +//! \param bAutoRetry enables automatic retransmission. +//! +//! This function enables or disables automatic retransmission of messages with +//! detected errors. If \e bAutoRetry is \b true, then automatic +//! retransmission is enabled, otherwise it is disabled. +//! +//! \return None. +// +//***************************************************************************** +void +CANRetrySet(unsigned long ulBase, tBoolean bAutoRetry) +{ + unsigned long ulCtlReg; + + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + + ulCtlReg = CANRegRead(ulBase + CAN_O_CTL); + + // + // Conditionally set the DAR bit to enable/disable auto-retry. + // + if(bAutoRetry) + { + // + // Clearing the DAR bit tells the controller to not disable the + // auto-retry of messages which were not transmitted or received + // correctly. + // + ulCtlReg &= ~CAN_CTL_DAR; + } + else + { + // + // Setting the DAR bit tells the controller to disable the auto-retry + // of messages which were not transmitted or received correctly. + // + ulCtlReg |= CAN_CTL_DAR; + } + + CANRegWrite(ulBase + CAN_O_CTL, ulCtlReg); +} + +//***************************************************************************** +// +//! Returns the current setting for automatic retransmission. +//! +//! \param ulBase is the base address of the CAN controller. +//! +//! This function reads the current setting for automatic retransmission in the CAN +//! controller and returns it to the caller. +//! +//! \return Returns \b true if automatic retransmission is enabled, \b false +//! otherwise. +// +//***************************************************************************** +tBoolean +CANRetryGet(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + + // + // Read the disable automatic retry setting from the CAN controller. + // + if(CANRegRead(ulBase + CAN_O_CTL) & CAN_CTL_DAR) + { + // + // Automatic data retransmission is not enabled. + // + return(false); + } + + // + // Automatic data retransmission is enabled. + // + return(true); +} + +//***************************************************************************** +// +//! Reads one of the controller status registers. +//! +//! \param ulBase is the base address of the CAN controller. +//! \param eStatusReg is the status register to read. +//! +//! This function reads a status register of the CAN controller and returns it +//! to the caller. +//! The different status registers are: +//! +//! - \b CAN_STS_CONTROL - the main controller status +//! - \b CAN_STS_TXREQUEST - bit mask of objects pending transmission +//! - \b CAN_STS_NEWDAT - bit mask of objects with new data +//! - \b CAN_STS_MSGVAL - bit mask of objects with valid configuration +//! +//! When reading the main controller status register, a pending status +//! interrupt is cleared. This parameter should be used in the interrupt +//! handler for the CAN controller if the cause is a status interrupt. The +//! controller status register fields are as follows: +//! +//! - \b CAN_STATUS_BUS_OFF - controller is in bus-off condition +//! - \b CAN_STATUS_EWARN - an error counter has reached a limit of at least 96 +//! - \b CAN_STATUS_EPASS - CAN controller is in the error passive state +//! - \b CAN_STATUS_RXOK - a message was received successfully (independent of +//! any message filtering). +//! - \b CAN_STATUS_TXOK - a message was successfully transmitted +//! - \b CAN_STATUS_LEC_MSK - mask of last error code bits (3 bits) +//! - \b CAN_STATUS_LEC_NONE - no error +//! - \b CAN_STATUS_LEC_STUFF - stuffing error detected +//! - \b CAN_STATUS_LEC_FORM - a format error occurred in the fixed format part +//! of a message +//! - \b CAN_STATUS_LEC_ACK - a transmitted message was not acknowledged +//! - \b CAN_STATUS_LEC_BIT1 - dominant level detected when trying to send in +//! recessive mode +//! - \b CAN_STATUS_LEC_BIT0 - recessive level detected when trying to send in +//! dominant mode +//! - \b CAN_STATUS_LEC_CRC - CRC error in received message +//! +//! The remaining status registers consist of 32-bit-wide bit maps to the +//! message objects. They can be used to quickly obtain information about the +//! status of all the message objects without needing to query each one. They +//! contain the following information: +//! +//! - \b CAN_STS_TXREQUEST - if a message object's TXRQST bit is set, a +//! transmission is pending on that object. The application can use this +//! information to determine which objects are still waiting to send a +//! message. +//! - \b CAN_STS_NEWDAT - if a message object's NEWDAT bit is set, a new +//! message has been received in that object, and has not yet been picked up +//! by the host application +//! - \b CAN_STS_MSGVAL - if a message object's MSGVAL bit is set, the object +//! has a valid configuration programmed. The host application can use this +//! information to determine which message objects are empty/unused. +//! +//! \return Returns the value of the status register. +// +//***************************************************************************** +unsigned long +CANStatusGet(unsigned long ulBase, tCANStsReg eStatusReg) +{ + unsigned long ulStatus; + + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + + switch(eStatusReg) + { + // + // Just return the global CAN status register since that is what was + // requested. + // + case CAN_STS_CONTROL: + { + ulStatus = CANRegRead(ulBase + CAN_O_STS); + CANRegWrite(ulBase + CAN_O_STS, + ~(CAN_STS_RXOK | CAN_STS_TXOK | CAN_STS_LEC_M)); + break; + } + + // + // Combine the Transmit status bits into one 32bit value. + // + case CAN_STS_TXREQUEST: + { + ulStatus = CANRegRead(ulBase + CAN_O_TXRQ1); + ulStatus |= CANRegRead(ulBase + CAN_O_TXRQ2) << 16; + break; + } + + // + // Combine the New Data status bits into one 32bit value. + // + case CAN_STS_NEWDAT: + { + ulStatus = CANRegRead(ulBase + CAN_O_NWDA1); + ulStatus |= CANRegRead(ulBase + CAN_O_NWDA2) << 16; + break; + } + + // + // Combine the Message valid status bits into one 32bit value. + // + case CAN_STS_MSGVAL: + { + ulStatus = CANRegRead(ulBase + CAN_O_MSG1VAL); + ulStatus |= CANRegRead(ulBase + CAN_O_MSG2VAL) << 16; + break; + } + + // + // Unknown CAN status requested so return 0. + // + default: + { + ulStatus = 0; + break; + } + } + return(ulStatus); +} + +//***************************************************************************** +// +//! Reads the CAN controller error counter register. +//! +//! \param ulBase is the base address of the CAN controller. +//! \param pulRxCount is a pointer to storage for the receive error counter. +//! \param pulTxCount is a pointer to storage for the transmit error counter. +//! +//! This function reads the error counter register and returns the transmit and +//! receive error counts to the caller along with a flag indicating if the +//! controller receive counter has reached the error passive limit. The values +//! of the receive and transmit error counters are returned through the +//! pointers provided as parameters. +//! +//! After this call, \e *pulRxCount holds the current receive error count +//! and \e *pulTxCount holds the current transmit error count. +//! +//! \return Returns \b true if the receive error count has reached the error +//! passive limit, and \b false if the error count is below the error passive +//! limit. +// +//***************************************************************************** +tBoolean +CANErrCntrGet(unsigned long ulBase, unsigned long *pulRxCount, + unsigned long *pulTxCount) +{ + unsigned long ulCANError; + + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + + // + // Read the current count of transmit/receive errors. + // + ulCANError = CANRegRead(ulBase + CAN_O_ERR); + + // + // Extract the error numbers from the register value. + // + *pulRxCount = (ulCANError & CAN_ERR_REC_M) >> CAN_ERR_REC_S; + *pulTxCount = (ulCANError & CAN_ERR_TEC_M) >> CAN_ERR_TEC_S; + + if(ulCANError & CAN_ERR_RP) + { + return(true); + } + return(false); +} + +//***************************************************************************** +// +//! Configures a message object in the CAN controller. +//! +//! \param ulBase is the base address of the CAN controller. +//! \param ulObjID is the object number to configure (1-32). +//! \param pMsgObject is a pointer to a structure containing message object +//! settings. +//! \param eMsgType indicates the type of message for this object. +//! +//! This function is used to configure any one of the 32 message objects in the +//! CAN controller. A message object can be configured to be any type of CAN +//! message object as well as to use automatic transmission and reception. +//! This call also allows the message object to be configured to generate +//! interrupts on completion of message receipt or transmission. The +//! message object can also be configured with a filter/mask so that actions +//! are only taken when a message that meets certain parameters is seen on the +//! CAN bus. +//! +//! The \e eMsgType parameter must be one of the following values: +//! +//! - \b MSG_OBJ_TYPE_TX - CAN transmit message object. +//! - \b MSG_OBJ_TYPE_TX_REMOTE - CAN transmit remote request message object. +//! - \b MSG_OBJ_TYPE_RX - CAN receive message object. +//! - \b MSG_OBJ_TYPE_RX_REMOTE - CAN receive remote request message object. +//! - \b MSG_OBJ_TYPE_RXTX_REMOTE - CAN remote frame receive remote, then +//! transmit message object. +//! +//! The message object pointed to by \e pMsgObject must be populated by the +//! caller, as follows: +//! +//! - \e ulMsgID - contains the message ID, either 11 or 29 bits. +//! - \e ulMsgIDMask - mask of bits from \e ulMsgID that must match if +//! identifier filtering is enabled. +//! - \e ulFlags +//! - Set \b MSG_OBJ_TX_INT_ENABLE flag to enable interrupt on transmission. +//! - Set \b MSG_OBJ_RX_INT_ENABLE flag to enable interrupt on receipt. +//! - Set \b MSG_OBJ_USE_ID_FILTER flag to enable filtering based on the +//! identifier mask specified by \e ulMsgIDMask. +//! - \e ulMsgLen - the number of bytes in the message data. This parameter +//! should be non-zero even for a remote frame; it should match the expected +//! bytes of data in the responding data frame. +//! - \e pucMsgData - points to a buffer containing up to 8 bytes of data for a +//! data frame. +//! +//! \b Example: To send a data frame or remote frame (in response to a remote +//! request), take the following steps: +//! +//! -# Set \e eMsgType to \b MSG_OBJ_TYPE_TX. +//! -# Set \e pMsgObject->ulMsgID to the message ID. +//! -# Set \e pMsgObject->ulFlags. Make sure to set \b MSG_OBJ_TX_INT_ENABLE to +//! allow an interrupt to be generated when the message is sent. +//! -# Set \e pMsgObject->ulMsgLen to the number of bytes in the data frame. +//! -# Set \e pMsgObject->pucMsgData to point to an array containing the bytes +//! to send in the message. +//! -# Call this function with \e ulObjID set to one of the 32 object buffers. +//! +//! \b Example: To receive a specific data frame, take the following steps: +//! +//! -# Set \e eMsgObjType to \b MSG_OBJ_TYPE_RX. +//! -# Set \e pMsgObject->ulMsgID to the full message ID, or a partial mask to +//! use partial ID matching. +//! -# Set \e pMsgObject->ulMsgIDMask bits that should be used for masking +//! during comparison. +//! -# Set \e pMsgObject->ulFlags as follows: +//! - Set \b MSG_OBJ_RX_INT_ENABLE flag to be interrupted when the data frame +//! is received. +//! - Set \b MSG_OBJ_USE_ID_FILTER flag to enable identifier-based filtering. +//! -# Set \e pMsgObject->ulMsgLen to the number of bytes in the expected data +//! frame. +//! -# The buffer pointed to by \e pMsgObject->pucMsgData is not used by this +//! call as no data is present at the time of the call. +//! -# Call this function with \e ulObjID set to one of the 32 object buffers. +//! +//! If you specify a message object buffer that already contains a message +//! definition, it is overwritten. +//! +//! \return None. +// +//***************************************************************************** +void +CANMessageSet(unsigned long ulBase, unsigned long ulObjID, + tCANMsgObject *pMsgObject, tMsgObjType eMsgType) +{ + unsigned short usCmdMaskReg; + unsigned short usMaskReg0, usMaskReg1; + unsigned short usArbReg0, usArbReg1; + unsigned short usMsgCtrl; + tBoolean bTransferData; + tBoolean bUseExtendedID; + + bTransferData = 0; + + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + ASSERT((ulObjID <= 32) && (ulObjID != 0)); + ASSERT((eMsgType == MSG_OBJ_TYPE_TX) || + (eMsgType == MSG_OBJ_TYPE_TX_REMOTE) || + (eMsgType == MSG_OBJ_TYPE_RX) || + (eMsgType == MSG_OBJ_TYPE_RX_REMOTE) || + (eMsgType == MSG_OBJ_TYPE_TX_REMOTE) || + (eMsgType == MSG_OBJ_TYPE_RXTX_REMOTE)); + + // + // Wait for busy bit to clear + // + while(CANRegRead(ulBase + CAN_O_IF1CRQ) & CAN_IF1CRQ_BUSY) + { + } + + // + // See if we need to use an extended identifier or not. + // + if((pMsgObject->ulMsgID > CAN_MAX_11BIT_MSG_ID) || + (pMsgObject->ulFlags & MSG_OBJ_EXTENDED_ID)) + { + bUseExtendedID = 1; + } + else + { + bUseExtendedID = 0; + } + + // + // 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. + // + usCmdMaskReg = (CAN_IF1CMSK_WRNRD | CAN_IF1CMSK_DATAA | CAN_IF1CMSK_DATAB | + CAN_IF1CMSK_CONTROL); + + // + // Initialize the values to a known state before filling them in based on + // the type of message object that is being configured. + // + usArbReg0 = 0; + usArbReg1 = 0; + usMsgCtrl = 0; + usMaskReg0 = 0; + usMaskReg1 = 0; + + switch(eMsgType) + { + // + // Transmit message object. + // + case MSG_OBJ_TYPE_TX: + { + // + // Set the TXRQST bit and the reset the rest of the register. + // + usMsgCtrl |= CAN_IF1MCTL_TXRQST; + usArbReg1 = CAN_IF1ARB2_DIR; + bTransferData = 1; + break; + } + + // + // Transmit remote request message object + // + case MSG_OBJ_TYPE_TX_REMOTE: + { + // + // Set the TXRQST bit and the reset the rest of the register. + // + usMsgCtrl |= CAN_IF1MCTL_TXRQST; + usArbReg1 = 0; + break; + } + + // + // Receive message object. + // + case MSG_OBJ_TYPE_RX: + { + // + // This clears the DIR bit along with everything else. The TXRQST + // bit was cleared by defaulting usMsgCtrl to 0. + // + usArbReg1 = 0; + break; + } + + // + // Receive remote request message object. + // + case MSG_OBJ_TYPE_RX_REMOTE: + { + // + // The DIR bit is set to one for remote receivers. The TXRQST bit + // was cleared by defaulting usMsgCtrl to 0. + // + usArbReg1 = CAN_IF1ARB2_DIR; + + // + // Set this object so that it only indicates that a remote frame + // was received and allow for software to handle it by sending back + // a data frame. + // + usMsgCtrl = CAN_IF1MCTL_UMASK; + + // + // Use the full Identifier by default. + // + usMaskReg0 = 0xffff; + usMaskReg1 = 0x1fff; + + // + // Make sure to send the mask to the message object. + // + usCmdMaskReg |= CAN_IF1CMSK_MASK; + break; + } + + // + // Remote frame receive remote, with auto-transmit message object. + // + case MSG_OBJ_TYPE_RXTX_REMOTE: + { + // + // Oddly the DIR bit is set to one for remote receivers. + // + usArbReg1 = CAN_IF1ARB2_DIR; + + // + // Set this object to auto answer if a matching identifier is seen. + // + usMsgCtrl = CAN_IF1MCTL_RMTEN | CAN_IF1MCTL_UMASK; + + // + // The data to be returned needs to be filled in. + // + bTransferData = 1; + break; + } + + // + // This case should never happen due to the ASSERT statement at the + // beginning of this function. + // + default: + { + return; + } + } + + // + // Configure the Mask Registers. + // + if(pMsgObject->ulFlags & MSG_OBJ_USE_ID_FILTER) + { + if(bUseExtendedID) + { + // + // Set the 29 bits of Identifier mask that were requested. + // + usMaskReg0 = pMsgObject->ulMsgIDMask & CAN_IF1MSK1_IDMSK_M; + usMaskReg1 = ((pMsgObject->ulMsgIDMask >> 16) & + CAN_IF1MSK2_IDMSK_M); + } + else + { + // + // Lower 16 bit are unused so set them to zero. + // + usMaskReg0 = 0; + + // + // Put the 11 bit Mask Identifier into the upper bits of the field + // in the register. + // + usMaskReg1 = ((pMsgObject->ulMsgIDMask << 2) & + CAN_IF1MSK2_IDMSK_M); + } + } + + // + // If the caller wants to filter on the extended ID bit then set it. + // + if((pMsgObject->ulFlags & MSG_OBJ_USE_EXT_FILTER) == + MSG_OBJ_USE_EXT_FILTER) + { + usMaskReg1 |= CAN_IF1MSK2_MXTD; + } + + // + // The caller wants to filter on the message direction field. + // + if((pMsgObject->ulFlags & MSG_OBJ_USE_DIR_FILTER) == + MSG_OBJ_USE_DIR_FILTER) + { + usMaskReg1 |= CAN_IF1MSK2_MDIR; + } + + if(pMsgObject->ulFlags & (MSG_OBJ_USE_ID_FILTER | MSG_OBJ_USE_DIR_FILTER | + MSG_OBJ_USE_EXT_FILTER)) + { + // + // Set the UMASK bit to enable using the mask register. + // + usMsgCtrl |= CAN_IF1MCTL_UMASK; + + // + // Set the MASK bit so that this gets transferred to the Message Object. + // + usCmdMaskReg |= CAN_IF1CMSK_MASK; + } + + // + // Set the Arb bit so that this gets transferred to the Message object. + // + usCmdMaskReg |= CAN_IF1CMSK_ARB; + + // + // Configure the Arbitration registers. + // + if(bUseExtendedID) + { + // + // Set the 29 bit version of the Identifier for this message object. + // + usArbReg0 |= pMsgObject->ulMsgID & CAN_IF1ARB1_ID_M; + usArbReg1 |= (pMsgObject->ulMsgID >> 16) & CAN_IF1ARB2_ID_M; + + // + // Mark the message as valid and set the extended ID bit. + // + usArbReg1 |= CAN_IF1ARB2_MSGVAL | CAN_IF1ARB2_XTD; + } + else + { + // + // Set the 11 bit version of the Identifier for this message object. + // The lower 18 bits are set to zero. + // + usArbReg1 |= (pMsgObject->ulMsgID << 2) & CAN_IF1ARB2_ID_M; + + // + // Mark the message as valid. + // + usArbReg1 |= CAN_IF1ARB2_MSGVAL; + } + + // + // 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. + // + usMsgCtrl |= (pMsgObject->ulMsgLen & CAN_IF1MCTL_DLC_M); + + // + // Mark this as the last entry if this is not the last entry in a FIFO. + // + if((pMsgObject->ulFlags & MSG_OBJ_FIFO) == 0) + { + usMsgCtrl |= CAN_IF1MCTL_EOB; + } + + // + // Enable transmit interrupts if they should be enabled. + // + if(pMsgObject->ulFlags & MSG_OBJ_TX_INT_ENABLE) + { + usMsgCtrl |= CAN_IF1MCTL_TXIE; + } + + // + // Enable receive interrupts if they should be enabled. + // + if(pMsgObject->ulFlags & MSG_OBJ_RX_INT_ENABLE) + { + usMsgCtrl |= CAN_IF1MCTL_RXIE; + } + + // + // Write the data out to the CAN Data registers if needed. + // + if(bTransferData) + { + CANDataRegWrite(pMsgObject->pucMsgData, + (unsigned long *)(ulBase + CAN_O_IF1DA1), + pMsgObject->ulMsgLen); + } + + // + // Write out the registers to program the message object. + // + CANRegWrite(ulBase + CAN_O_IF1CMSK, usCmdMaskReg); + CANRegWrite(ulBase + CAN_O_IF1MSK1, usMaskReg0); + CANRegWrite(ulBase + CAN_O_IF1MSK2, usMaskReg1); + CANRegWrite(ulBase + CAN_O_IF1ARB1, usArbReg0); + CANRegWrite(ulBase + CAN_O_IF1ARB2, usArbReg1); + CANRegWrite(ulBase + CAN_O_IF1MCTL, usMsgCtrl); + + // + // Transfer the message object to the message object specified by ulObjID. + // + CANRegWrite(ulBase + CAN_O_IF1CRQ, ulObjID & CAN_IF1CRQ_MNUM_M); +} + +//***************************************************************************** +// +//! Reads a CAN message from one of the message object buffers. +//! +//! \param ulBase is the base address of the CAN controller. +//! \param ulObjID is the object number to read (1-32). +//! \param pMsgObject points to a structure containing message object fields. +//! \param bClrPendingInt indicates whether an associated interrupt should be +//! cleared. +//! +//! This function is used to read the contents of one of the 32 message objects +//! in the CAN controller and return it to the caller. The data returned is +//! stored in the fields of the caller-supplied structure pointed to by +//! \e pMsgObject. The data consists of all of the parts of a CAN message, +//! plus some control and status information. +//! +//! Normally, this function is used to read a message object that has received +//! and stored a CAN message with a certain identifier. However, this function +//! could also be used to read the contents of a message object in order to +//! load the fields of the structure in case only part of the structure must +//! be changed from a previous setting. +//! +//! When using CANMessageGet(), all of the same fields of the structure are +//! populated in the same way as when the CANMessageSet() function is used, +//! with the following exceptions: +//! +//! \e pMsgObject->ulFlags: +//! +//! - \b MSG_OBJ_NEW_DATA indicates if this data is new since the last time it +//! was read +//! - \b MSG_OBJ_DATA_LOST indicates that at least one message was received on +//! this message object and not read by the host before being overwritten. +//! +//! \return None. +// +//***************************************************************************** +void +CANMessageGet(unsigned long ulBase, unsigned long ulObjID, + tCANMsgObject *pMsgObject, tBoolean bClrPendingInt) +{ + unsigned short usCmdMaskReg; + unsigned short usMaskReg0, usMaskReg1; + unsigned short usArbReg0, usArbReg1; + unsigned short usMsgCtrl; + + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + ASSERT((ulObjID <= 32) && (ulObjID != 0)); + + // + // This is always a read to the Message object as this call is setting a + // message object. + // + usCmdMaskReg = (CAN_IF1CMSK_DATAA | CAN_IF1CMSK_DATAB | + CAN_IF1CMSK_CONTROL | CAN_IF1CMSK_MASK | CAN_IF1CMSK_ARB); + + // + // Clear a pending interrupt and new data in a message object. + // + if(bClrPendingInt) + { + usCmdMaskReg |= CAN_IF1CMSK_CLRINTPND; + } + + // + // Set up the request for data from the message object. + // + CANRegWrite(ulBase + CAN_O_IF2CMSK, usCmdMaskReg); + + // + // Transfer the message object to the message object specified by ulObjID. + // + CANRegWrite(ulBase + CAN_O_IF2CRQ, ulObjID & CAN_IF1CRQ_MNUM_M); + + // + // Wait for busy bit to clear + // + while(CANRegRead(ulBase + CAN_O_IF2CRQ) & CAN_IF1CRQ_BUSY) + { + } + + // + // Read out the IF Registers. + // + usMaskReg0 = CANRegRead(ulBase + CAN_O_IF2MSK1); + usMaskReg1 = CANRegRead(ulBase + CAN_O_IF2MSK2); + usArbReg0 = CANRegRead(ulBase + CAN_O_IF2ARB1); + usArbReg1 = CANRegRead(ulBase + CAN_O_IF2ARB2); + usMsgCtrl = CANRegRead(ulBase + CAN_O_IF2MCTL); + + pMsgObject->ulFlags = MSG_OBJ_NO_FLAGS; + + // + // Determine if this is a remote frame by checking the TXRQST and DIR bits. + // + if((!(usMsgCtrl & CAN_IF1MCTL_TXRQST) && (usArbReg1 & CAN_IF1ARB2_DIR)) || + ((usMsgCtrl & CAN_IF1MCTL_TXRQST) && (!(usArbReg1 & CAN_IF1ARB2_DIR)))) + { + pMsgObject->ulFlags |= MSG_OBJ_REMOTE_FRAME; + } + + // + // Get the identifier out of the register, the format depends on size of + // the mask. + // + if(usArbReg1 & CAN_IF1ARB2_XTD) + { + // + // Set the 29 bit version of the Identifier for this message object. + // + pMsgObject->ulMsgID = ((usArbReg1 & CAN_IF1ARB2_ID_M) << 16) | + usArbReg0; + + pMsgObject->ulFlags |= MSG_OBJ_EXTENDED_ID; + } + else + { + // + // The Identifier is an 11 bit value. + // + pMsgObject->ulMsgID = (usArbReg1 & CAN_IF1ARB2_ID_M) >> 2; + } + + // + // Indicate that we lost some data. + // + if(usMsgCtrl & CAN_IF1MCTL_MSGLST) + { + pMsgObject->ulFlags |= MSG_OBJ_DATA_LOST; + } + + // + // Set the flag to indicate if ID masking was used. + // + if(usMsgCtrl & CAN_IF1MCTL_UMASK) + { + if(usArbReg1 & CAN_IF1ARB2_XTD) + { + // + // The Identifier Mask is assumed to also be a 29 bit value. + // + pMsgObject->ulMsgIDMask = + ((usMaskReg1 & CAN_IF1MSK2_IDMSK_M) << 16) | usMaskReg0; + + // + // If this is a fully specified Mask and a remote frame then don't + // set the MSG_OBJ_USE_ID_FILTER because the ID was not really + // filtered. + // + if((pMsgObject->ulMsgIDMask != 0x1fffffff) || + ((pMsgObject->ulFlags & MSG_OBJ_REMOTE_FRAME) == 0)) + { + pMsgObject->ulFlags |= MSG_OBJ_USE_ID_FILTER; + } + } + else + { + // + // The Identifier Mask is assumed to also be an 11 bit value. + // + pMsgObject->ulMsgIDMask = ((usMaskReg1 & CAN_IF1MSK2_IDMSK_M) >> + 2); + + // + // If this is a fully specified Mask and a remote frame then don't + // set the MSG_OBJ_USE_ID_FILTER because the ID was not really + // filtered. + // + if((pMsgObject->ulMsgIDMask != 0x7ff) || + ((pMsgObject->ulFlags & MSG_OBJ_REMOTE_FRAME) == 0)) + { + pMsgObject->ulFlags |= MSG_OBJ_USE_ID_FILTER; + } + } + + // + // Indicate if the extended bit was used in filtering. + // + if(usMaskReg1 & CAN_IF1MSK2_MXTD) + { + pMsgObject->ulFlags |= MSG_OBJ_USE_EXT_FILTER; + } + + // + // Indicate if direction filtering was enabled. + // + if(usMaskReg1 & CAN_IF1MSK2_MDIR) + { + pMsgObject->ulFlags |= MSG_OBJ_USE_DIR_FILTER; + } + } + + // + // Set the interrupt flags. + // + if(usMsgCtrl & CAN_IF1MCTL_TXIE) + { + pMsgObject->ulFlags |= MSG_OBJ_TX_INT_ENABLE; + } + if(usMsgCtrl & CAN_IF1MCTL_RXIE) + { + pMsgObject->ulFlags |= MSG_OBJ_RX_INT_ENABLE; + } + + // + // See if there is new data available. + // + if(usMsgCtrl & CAN_IF1MCTL_NEWDAT) + { + // + // Get the amount of data needed to be read. + // + pMsgObject->ulMsgLen = (usMsgCtrl & CAN_IF1MCTL_DLC_M); + + // + // Don't read any data for a remote frame, there is nothing valid in + // that buffer anyway. + // + if((pMsgObject->ulFlags & MSG_OBJ_REMOTE_FRAME) == 0) + { + // + // Read out the data from the CAN registers. + // + CANDataRegRead(pMsgObject->pucMsgData, + (unsigned long *)(ulBase + CAN_O_IF2DA1), + pMsgObject->ulMsgLen); + } + + // + // Now clear out the new data flag. + // + CANRegWrite(ulBase + CAN_O_IF2CMSK, CAN_IF1CMSK_NEWDAT); + + // + // Transfer the message object to the message object specified by + // ulObjID. + // + CANRegWrite(ulBase + CAN_O_IF2CRQ, ulObjID & CAN_IF1CRQ_MNUM_M); + + // + // Wait for busy bit to clear + // + while(CANRegRead(ulBase + CAN_O_IF2CRQ) & CAN_IF1CRQ_BUSY) + { + } + + // + // Indicate that there is new data in this message. + // + pMsgObject->ulFlags |= MSG_OBJ_NEW_DATA; + } + else + { + // + // Along with the MSG_OBJ_NEW_DATA not being set the amount of data + // needs to be set to zero if none was available. + // + pMsgObject->ulMsgLen = 0; + } +} + +//***************************************************************************** +// +//! Clears a message object so that it is no longer used. +//! +//! \param ulBase is the base address of the CAN controller. +//! \param ulObjID is the message object number to disable (1-32). +//! +//! This function frees the specified message object from use. Once a message +//! object has been ``cleared,'' it no longer automatically sends or +//! receives messages, nor does it generate interrupts. +//! +//! \return None. +// +//***************************************************************************** +void +CANMessageClear(unsigned long ulBase, unsigned long ulObjID) +{ + // + // Check the arguments. + // + ASSERT(CANBaseValid(ulBase)); + ASSERT((ulObjID >= 1) && (ulObjID <= 32)); + + // + // Wait for busy bit to clear + // + while(CANRegRead(ulBase + CAN_O_IF1CRQ) & CAN_IF1CRQ_BUSY) + { + } + + // + // Clear the message value bit in the arbitration register. This indicates + // the message is not valid. + // + CANRegWrite(ulBase + CAN_O_IF1CMSK, CAN_IF1CMSK_WRNRD | CAN_IF1CMSK_ARB); + CANRegWrite(ulBase + CAN_O_IF1ARB1, 0); + CANRegWrite(ulBase + CAN_O_IF1ARB2, 0); + + // + // Initiate programming the message object + // + CANRegWrite(ulBase + CAN_O_IF1CRQ, ulObjID & CAN_IF1CRQ_MNUM_M); +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** -- cgit v1.3.1