blob: 0ef9d5c2c28381c76e04335ddfca6b40bc532830 [file] [log] [blame]
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2012, Atmel Corporation
*
* All rights reserved.
*
* 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 disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
* ----------------------------------------------------------------------------
*/
/** \file
* Implements functions for Controller Area Network (CAN)
* peripheral operations.
*/
/** \addtogroup can_module
*@{*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include <assert.h>
#if defined(REG_CAN0_MR) || defined(REG_CAN_MR)
/* ----------- CAN_MR Operations --------------- */
/**
* \brief Set CAN Mode Register (CAN_MR)
* \param pCan Pointer to Can instance.
* \param dwMr Mode register settings.
*/
void CAN_ConfigureMode(Can *pCan, uint32_t dwMr)
{
pCan->CAN_MR = dwMr;
}
/**
* \brief CAN Controller Enable/Disable
* \param pCan Pointer to Can instance.
* \param bEnDis 1 to enable and 0 to disable.
*/
void CAN_Enable(Can *pCan, uint8_t bEnDis)
{
if (bEnDis) pCan->CAN_MR |= CAN_MR_CANEN;
else pCan->CAN_MR &= ~CAN_MR_CANEN;
}
/**
* \brief CAN Low Power Mode Enable/Disable
* \param pCan Pointer to Can instance.
* \param bEnDis 1 to enable and 0 to disable.
*/
void CAN_EnableLowPower(Can *pCan, uint8_t bEnDis)
{
if (bEnDis) pCan->CAN_MR |= CAN_MR_LPM;
else pCan->CAN_MR &= ~CAN_MR_LPM;
}
/**
* \brief CAN Autobaud/Listen mode
* \param pCan Pointer to Can instance.
* \param bEnDis 1 to enable and 0 to disable.
*/
void CAN_EnableAutobaud(Can *pCan, uint8_t bEnDis)
{
if (bEnDis) pCan->CAN_MR |= CAN_MR_ABM;
else pCan->CAN_MR &= ~CAN_MR_ABM;
}
/**
* \brief CAN Overload Frame Enable/Disable
* \param pCan Pointer to Can instance.
* \param bEnDis 1 to enable and 0 to disable.
*/
void CAN_EnableOverloadFrame(Can *pCan, uint8_t bEnDis)
{
if (bEnDis) pCan->CAN_MR |= CAN_MR_OVL;
else pCan->CAN_MR &= ~CAN_MR_OVL;
}
/**
* \brief CAN Timestamp capture mode (@EOF/@SOF).
* \param pCan Pointer to Can instance.
* \param bEofSof 1 for EOF/0 for SOF.
*/
void CAN_EnableTimeStampEof(Can *pCan, uint8_t bEofSof)
{
if (bEofSof) pCan->CAN_MR |= CAN_MR_TEOF;
else pCan->CAN_MR &= ~CAN_MR_TEOF;
}
/**
* \brief CAN Time Triggered Mode Enable/Disable
* \param pCan Pointer to Can instance.
* \param bEnDis Enable/Disable Time Trigger Mode.
*/
void CAN_EnableTimeTriggerMode(Can *pCan, uint8_t bEnDis)
{
if (bEnDis) pCan->CAN_MR |= CAN_MR_TTM;
else pCan->CAN_MR &= ~CAN_MR_TTM;
}
/**
* \brief CAN Timer Freeze Enable/Disable
* \param pCan Pointer to Can instance.
* \param bEnDis Enable/Disable Timer Freeze.
*/
void CAN_EnableTimerFreeze(Can *pCan, uint8_t bEnDis)
{
if (bEnDis) pCan->CAN_MR |= CAN_MR_TIMFRZ;
else pCan->CAN_MR &= ~CAN_MR_TIMFRZ;
}
/**
* \brief CAN Repeat Disable/Enable.
* \param pCan Pointer to Can instance.
* \param bEnDis Disable/Enable Repeat.
*/
void CAN_DisableRepeat(Can *pCan, uint8_t bDisEn)
{
if (bDisEn) pCan->CAN_MR |= CAN_MR_DRPT;
else pCan->CAN_MR &= ~CAN_MR_DRPT;
}
/* ---------- Interrupt settings ------------- */
/**
* \brief CAN Interrupts Enable
* \param pCan Pointer to Can instance.
* \param dwSources Interrupt sources bits.
*/
void CAN_EnableIt(Can *pCan, uint32_t dwSources)
{
pCan->CAN_IER = dwSources;
}
/**
* \brief CAN Interrupts Disable
* \param pCan Pointer to Can instance.
* \param dwSources Interrupt sources bits.
*/
void CAN_DisableIt(Can *pCan, uint32_t dwSources)
{
pCan->CAN_IDR = dwSources;
}
/**
* \brief Return CAN Interrupts Masks
* \param pCan Pointer to Can instance.
*/
uint32_t CAN_GetItMask(Can *pCan)
{
return pCan->CAN_IMR;
}
/**
* \brief Return CAN Statuses
* \param pCan Pointer to Can instance.
*/
uint32_t CAN_GetStatus(Can *pCan)
{
return pCan->CAN_SR;
}
/**
* \brief Calculate and configure the baudrate
* \param pCan Pointer to Can instance.
* \param dwBaudrate Baudrate value (kB/s)
* allowed: 100, 800, 500, 250, 125, 50, 25, 10
* \param dwMck MCK.
* \return 1 in success, otherwise return 0.
*/
uint8_t CAN_CalcBaudrate(Can *pCan, uint32_t dwBaudrate, uint32_t dwMck)
{
uint32_t BRP, PROPAG, PHASE1, PHASE2, SJW;
uint8_t TQ;
uint32_t t1t2;
uint32_t maxClock;
uint32_t id = ID_CAN0;
if ((uint32_t)pCan == (uint32_t)CAN0) id = ID_CAN0;
else if ((uint32_t)pCan == (uint32_t)CAN1) id = ID_CAN1;
maxClock = PMC_SetPeriMaxClock(id, dwMck);
if (dwBaudrate >= 1000) TQ = 8;
else TQ = 16;
BRP = (maxClock / (dwBaudrate * 1000 * TQ)) - 1;
if (BRP == 0) {
return 0;
}
/* Timing delay:
Delay Bus Driver - 50ns
Delay Receiver - 30ns
Delay Bus Line (20m) - 110ns */
if ( (TQ * dwBaudrate * 2 * (50+30+110)/1000000) >= 1 )
PROPAG = (TQ * dwBaudrate * 2 * (50+30+110)/1000000) - 1;
else
PROPAG = 0;
t1t2 = TQ - 1 - (PROPAG + 1);
if ( (t1t2 & 0x01) == 0x01 ) {
PHASE1 = ((t1t2 - 1) / 2) - 1;
PHASE2 = PHASE1 + 1;
}
else {
PHASE1 = ((t1t2) / 2) - 1;
PHASE2 = PHASE1;
}
if ( 1 > (4/(PHASE1 + 1)) ) SJW = 3;
else SJW = PHASE1;
if ( (PROPAG + PHASE1 + PHASE2) != (uint32_t)(TQ - 4) ) {
return 0;
}
pCan->CAN_BR = CAN_BR_PHASE2(PHASE2)
| CAN_BR_PHASE1(PHASE1)
| CAN_BR_PROPAG(PROPAG)
| CAN_BR_SJW(SJW)
| CAN_BR_BRP(BRP)
| CAN_BR_SMP_ONCE;
return 1;
}
/**
* \brief Set CAN baudrate register
* \param pCan Pointer to Can instance.
* \param dwBr Setting value for CAN_BR.
*/
void CAN_ConfigureBaudrate(Can *pCan, uint32_t dwBr)
{
pCan->CAN_BR = dwBr;
}
/**
* \brief Set CAN Sampling Mode
* \param pCan Pointer to Can instance.
* \param bAvg3 Sample 3 times/sample once at sample point.
*/
void CAN_SetSamplingMode(Can *pCan, uint8_t bAvg3)
{
if (bAvg3) pCan->CAN_BR |= CAN_BR_SMP;
else pCan->CAN_BR &= ~CAN_BR_SMP;
}
/**
* \brief Return CAN Timer Register
* \param pCan Pointer to Can instance.
*/
uint32_t CAN_GetTimer(Can *pCan)
{
return pCan->CAN_TIM;
}
/**
* \brief Return CAN TimeStamp Register
* \param pCan Pointer to Can instance.
*/
uint32_t CAN_GetTimestamp(Can *pCan)
{
return pCan->CAN_TIMESTP;
}
/**
* \brief Return Error Count (TEC << 16) + REC
* \param pCan Pointer to Can instance.
*/
uint32_t CAN_GetErrorCount(Can *pCan)
{
return pCan->CAN_ECR;
}
/**
* \brief Return Receive Error Count
* \param pCan Pointer to Can instance.
*/
uint32_t CAN_GetRxErrorCount(Can *pCan)
{
return (pCan->CAN_ECR & CAN_ECR_REC_Msk) >> CAN_ECR_REC_Pos;
}
/**
* \brief Return Transmit Error Count
* \param pCan Pointer to Can instance.
*/
uint32_t CAN_GetTxErrorCount(Can *pCan)
{
return (pCan->CAN_ECR & CAN_ECR_TEC_Msk) >> CAN_ECR_TEC_Pos;
}
/**
* \brief Set Transfer Command Register to initialize transfer requests.
* \param pCan Pointer to Can instance.
* \param dwRequests Transfer Command Requests.
*/
void CAN_Command(Can *pCan, uint32_t dwRequests)
{
pCan->CAN_TCR = dwRequests;
}
/**
* \brief Resets CAN internal timer counter.
* \param pCan Pointer to Can instance.
*/
void CAN_ResetTimer(Can *pCan)
{
pCan->CAN_TCR = CAN_TCR_TIMRST;
}
/**
* \brief Request transfer on mailbox.
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
*/
void CAN_Tx(Can *pCan, uint8_t bMb)
{
pCan->CAN_TCR = CAN_TCR_MB0 << bMb;
}
/**
* \brief Abort transfer on several mailboxes.
* \param pCan Pointer to Can instance.
* \param dwAborts Abort requests.
*/
void CAN_Abort(Can *pCan, uint32_t dwAborts)
{
pCan->CAN_ACR = dwAborts;
}
/**
* \brief Abort transfer on single mailbox.
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
*/
void CAN_AbortMailbox(Can *pCan, uint8_t bMb)
{
pCan->CAN_ACR = CAN_ACR_MB0 << bMb;
}
/**
* \brief Configure CAN Message Mode (_MMRx)
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param dwMr Mode settings.
*/
void CAN_ConfigureMessageMode(Can *pCan, uint8_t bMb, uint32_t dwMr)
{
pCan->CAN_MB[bMb].CAN_MMR = dwMr;
}
/**
* \brief Return CAN Message Mode (_MMRx)
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
*/
uint32_t CAN_GetMessageMode(Can *pCan, uint8_t bMb)
{
return pCan->CAN_MB[bMb].CAN_MMR;
}
/**
* \brief Set Mailbox Timemark for Time Triggered Mode.
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param bTimemarks Mailbox timemarks.
*/
void CAN_SetTimemark(Can *pCan, uint8_t bMb, uint8_t bTimemarks)
{
uint32_t dwMmr = (pCan->CAN_MB[bMb].CAN_MMR) & (~0xFFu);
pCan->CAN_MB[bMb].CAN_MMR = dwMmr | ((bTimemarks << 0) & 0xFF);
}
/**
* \brief Set Mailbox Priority.
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param bPriority Mailbox Priority.
*/
void CAN_SetPriority(Can *pCan, uint8_t bMb, uint8_t bPriority)
{
uint32_t dwMmr = (pCan->CAN_MB[bMb].CAN_MMR & ~CAN_MMR_PRIOR_Msk);
pCan->CAN_MB[bMb].CAN_MMR = dwMmr | CAN_MMR_PRIOR(bPriority);
}
/**
* \brief Set Mailbox Object Type.
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param bType Mailbox Object Type.
*/
void CAN_SetObjectType(Can *pCan, uint8_t bMb, uint8_t bType)
{
uint32_t dwMr = (pCan->CAN_MB[bMb].CAN_MMR & CAN_MMR_MOT_Msk) >> CAN_MMR_MOT_Pos;
pCan->CAN_MB[bMb].CAN_MMR |= dwMr | ((bType << CAN_MMR_MOT_Pos) & CAN_MMR_MOT_Msk);
}
/**
* \brief Configure CAN Message Acceptance Mask (_MAMx)
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param dwMam The setting value for _MAMx.
*/
void CAN_ConfigureMessageAcceptanceMask(Can *pCan, uint8_t bMb, uint32_t dwMAM)
{
pCan->CAN_MB[bMb].CAN_MAM = dwMAM;
}
/**
* \brief Return CAN Message Acceptance Mask (_MAMx)
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
*/
uint32_t CAN_GetMessageAcceptanceMask(Can *pCan, uint8_t bMb)
{
return pCan->CAN_MB[bMb].CAN_MAM;
}
/**
* \brief Configure Identifier Version in CAN Message Acceptance Mask (_MAMx)
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param bIdCfg IDvA and IDvB/IDvA only Identify.
*/
void CAN_ConfigureIdentifierMask(Can *pCan, uint8_t bMb, uint8_t bIdCfg)
{
if (bIdCfg) pCan->CAN_MB[bMb].CAN_MAM |= CAN_MAM_MIDE;
else pCan->CAN_MB[bMb].CAN_MAM &= ~CAN_MAM_MIDE;
}
/**
* \brief Set Identifier for standard frame mode (MIDvA) mask
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param dwMIDvA Identifier for standard frame mode.
*/
void CAN_SetMIDvAMask(Can *pCan, uint8_t bMb, uint32_t dwIDvA)
{
uint32_t dwMam = pCan->CAN_MB[bMb].CAN_MAM & CAN_MAM_MIDvA_Msk;
pCan->CAN_MB[bMb].CAN_MAM = dwMam | CAN_MAM_MIDvA(dwIDvA);
}
/**
* \brief Set Complementary bits for identifier in extended frame mode (MIDvB) mask
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param dwMIDvB Identifier for extended frame mode.
*/
void CAN_SetMIDvBMask(Can *pCan, uint8_t bMb, uint32_t dwIDvA)
{
uint32_t dwMam = pCan->CAN_MB[bMb].CAN_MAM & CAN_MAM_MIDvB_Msk;
pCan->CAN_MB[bMb].CAN_MAM = dwMam | CAN_MAM_MIDvB(dwIDvA);
}
/**
* \brief Configure CAN Message ID (_MIDx)
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param dwMID The setting value for _MIDx.
*/
void CAN_ConfigureMessageID(Can *pCan, uint8_t bMb, uint32_t dwMID)
{
pCan->CAN_MB[bMb].CAN_MID = dwMID;
}
/**
* \brief Return CAN Message ID (_MIDx)
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
*/
uint32_t CAN_GetMessageID(Can *pCan, uint8_t bMb)
{
return pCan->CAN_MB[bMb].CAN_MID;
}
/**
* \brief Configure Identifier Version in CAN Message ID register (_MIDx)
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param bIdVer 2.0 Part B/2.0 Part A.
*/
void CAN_ConfigureIdVer(Can *pCan, uint8_t bMb, uint8_t bIdVer)
{
uint32_t dwMid = pCan->CAN_MB[bMb].CAN_MID & CAN_MID_MIDE;
pCan->CAN_MB[bMb].CAN_MID = dwMid | (bIdVer ? CAN_MID_MIDE : 0);
}
/**
* \brief Set Identifier for standard frame mode (MIDvA) value
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param dwMIDvA Identifier for standard frame mode.
*/
void CAN_SetMIDvA(Can *pCan, uint8_t bMb, uint32_t dwIDvA)
{
uint32_t dwMam = pCan->CAN_MB[bMb].CAN_MID & CAN_MID_MIDvA_Msk;
pCan->CAN_MB[bMb].CAN_MID = dwMam | CAN_MID_MIDvA(dwIDvA);
}
/**
* \brief Set Complementary bits for identifier in extended frame mode (MIDvB) value
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param dwMIDvB Identifier for extended frame mode.
*/
void CAN_SetMIDvB(Can *pCan, uint8_t bMb, uint32_t dwIDvA)
{
uint32_t dwMam = pCan->CAN_MB[bMb].CAN_MID & CAN_MID_MIDvB_Msk;
pCan->CAN_MB[bMb].CAN_MID = dwMam | CAN_MID_MIDvB(dwIDvA);
}
/**
* \brief Return CAN Message Family ID (Masked ID)
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
*/
uint32_t CAN_GetFamilyID(Can *pCan, uint8_t bMb)
{
return pCan->CAN_MB[bMb].CAN_MFID;
}
/**
* \brief Return CAN Message Status
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
*/
uint32_t CAN_GetMessageStatus(Can *pCan, uint8_t bMb)
{
return pCan->CAN_MB[bMb].CAN_MSR;
}
/**
* \brief Return CAN Message Data Low
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
*/
uint32_t CAN_GetMessageDataL(Can *pCan, uint8_t bMb)
{
return pCan->CAN_MB[bMb].CAN_MDL;
}
/**
* \brief Set CAN Message Data Low
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param dwL Data Low Value.
*/
void CAN_SetMessageDataL(Can *pCan, uint8_t bMb, uint32_t dwL)
{
pCan->CAN_MB[bMb].CAN_MDL = dwL;
}
/**
* \brief Set CAN Message Data High
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param dwH Data High Value.
*/
void CAN_SetMessageDataH(Can *pCan, uint8_t bMb, uint32_t dwH)
{
pCan->CAN_MB[bMb].CAN_MDH = dwH;
}
/**
* \brief Return CAN Message Data High
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
*/
uint32_t CAN_GetMessageDataH(Can *pCan, uint8_t bMb)
{
return pCan->CAN_MB[bMb].CAN_MDH;
}
/**
* \brief Copy DW array to CAN Message Data.
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param pDwData Pointer to a buffer for data.
*/
void CAN_SetMessage(Can *pCan, uint8_t bMb, uint32_t *pDwData)
{
pCan->CAN_MB[bMb].CAN_MDL = pDwData[0];
pCan->CAN_MB[bMb].CAN_MDH = pDwData[1];
}
/**
* \brief Copy CAN Message Data to DW array.
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param pDwData Pointer to a buffer for data.
*/
void CAN_GetMessage(Can *pCan, uint8_t bMb, uint32_t *pDwData)
{
pDwData[0] = pCan->CAN_MB[bMb].CAN_MDL;
pDwData[1] = pCan->CAN_MB[bMb].CAN_MDH;
}
/**
* \brief Set CAN Message Data in u64
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
*/
void CAN_SetMessageData64(Can *pCan, uint8_t bMb, uint64_t u64)
{
pCan->CAN_MB[bMb].CAN_MDL = (uint32_t)u64;
pCan->CAN_MB[bMb].CAN_MDH = (u64 >> 32);
}
/**
* \brief Return CAN Message Data in u64
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
*/
uint64_t CAN_GetMessageData64(Can *pCan, uint8_t bMb)
{
uint64_t ddwMd = (uint64_t)pCan->CAN_MB[bMb].CAN_MDH << 32;
ddwMd += pCan->CAN_MB[bMb].CAN_MDL;
return ddwMd;
}
/**
* \brief Set CAN Message Control Register (_MCRx).
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param dwCtrl Control value.
*/
void CAN_MessageControl(Can *pCan, uint8_t bMb, uint32_t dwCtrl)
{
pCan->CAN_MB[bMb].CAN_MCR = dwCtrl;
}
/**
* \brief Start remote frame.
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
*/
void CAN_MessageRemote(Can *pCan, uint8_t bMb)
{
pCan->CAN_MB[bMb].CAN_MCR = CAN_MCR_MRTR;
}
/**
* \brief Abort transmission.
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
*/
void CAN_MessageAbort(Can *pCan, uint8_t bMb)
{
pCan->CAN_MB[bMb].CAN_MCR = CAN_MCR_MACR;
}
/**
* \brief Start transmission.
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
* \param bLen Message length.
*/
void CAN_MessageTx(Can *pCan, uint8_t bMb, uint8_t bLen)
{
pCan->CAN_MB[bMb].CAN_MCR = CAN_MCR_MTCR | CAN_MCR_MDLC(bLen);
}
/**
* \brief Start reception.
* \param pCan Pointer to Can instance.
* \param bMb Mailbox number.
*/
void CAN_MessageRx(Can *pCan, uint8_t bMb)
{
pCan->CAN_MB[bMb].CAN_MCR = CAN_MCR_MTCR;
}
#endif
/**@}*/