⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ecan.cpp

📁 ECAN OOP implementation for TMS320 280x and x281x
💻 CPP
字号:
#include <c280xpcl.h>
#include <bin.h>

#if    defined(__C280X_ECANA)\
    || defined(__C280X_ECANB)

//
// class ecan_base
//
ecan_base::ecan_base (
    volatile ECAN_REGS&   EcanxRegs
  , volatile ECAN_MBOXES& EcanxMboxes
  , volatile LAM_REGS&    EcanxLAMRegs
  , const pclk& /*pclk_ena*/
  , pio& CANTX
  , pio& CANRX
  , unsigned long bitrate
) : EcanRegs(EcanxRegs)
  , EcanMboxes(EcanxMboxes)
  , EcanLAMRegs(EcanxLAMRegs)
{
/* Create a shadow register structure for the CAN control registers. This is
 * needed, since only 32-bit access is allowed to these registers. 16-bit access
 * to these registers could potentially corrupt the register contents or return
 * false data. This is especially true while writing to/reading from a bit
 * (or group of bits) among bits 16 - 31
 */
  struct ECAN_REGS EcanShadow;

  EALLOW; // EALLOW enables access to protected bits

  // Configure eCAN RX and TX pins for CAN operation using eCAN regs
  EcanShadow.CANTIOC.all = EcanRegs.CANTIOC.all;
  EcanShadow.CANTIOC.bit.TXFUNC = 1;
  EcanRegs.CANTIOC.all = EcanShadow.CANTIOC.all;

  EcanShadow.CANRIOC.all = EcanRegs.CANRIOC.all;
  EcanShadow.CANRIOC.bit.RXFUNC = 1;
  EcanRegs.CANRIOC.all = EcanShadow.CANRIOC.all;

// Configure eCAN for HECC mode - (reqd to access mailboxes 16 thru 31)
// HECC mode also enables time-stamping feature
  EcanShadow.CANMC.all = EcanRegs.CANMC.all;
  EcanShadow.CANMC.bit.SCB = 1;
  EcanRegs.CANMC.all = EcanShadow.CANMC.all;

  // Initialize all bits of 'Master Control Field' to zero
  // Some bits of MSGCTRL register come up in an unknown state. For proper operation,
  // all bits (including reserved bits) of MSGCTRL must be initialized to zero
  volatile struct MBOX *pmb = &EcanMboxes.MBOX0;
  for(unsigned short n = 0; n < mbox_number; n++, pmb++)
    (*pmb).MSGCTRL.all = 0x00000000;


  // TAn, RMPn, GIFn bits are all zero upon reset and are cleared again
  // as a matter of precaution.
  EcanRegs.CANTA.all = 0xFFFFFFFF;    /* Clear all TAn bits */

  EcanRegs.CANRMP.all = 0xFFFFFFFF;   /* Clear all RMPn bits */

  EcanRegs.CANGIF0.all = 0xFFFFFFFF;  /* Clear all interrupt flag bits */
  EcanRegs.CANGIF1.all = 0xFFFFFFFF;


  // Configure bit timing parameters for eCAN
  EcanShadow.CANMC.all = EcanRegs.CANMC.all;
  EcanShadow.CANMC.bit.CCR = 1 ;  // Set CCR = 1
  EcanRegs.CANMC.all = EcanShadow.CANMC.all;

  // Wait until the CPU has been granted permission to change the configuration registers
  do
  { EcanShadow.CANES.all = EcanRegs.CANES.all;
  } while(EcanShadow.CANES.bit.CCE != 1 );  // Wait for CCE bit to be set..

  EcanShadow.CANBTC.all = 0;

  // sysclk = 10^9 / CPU_RATE
  // BRPREG = sysclk / (15 * br)
  EcanShadow.CANBTC.bit.BRPREG = 
    (unsigned short)(((long double)66666666.667/((long double)CPU_RATE * bitrate)) + 0.5)
       - 1;

  // bit-time = 15qt, sp = 73,(3)%
  EcanShadow.CANBTC.bit.TSEG2REG = 3;
  EcanShadow.CANBTC.bit.TSEG1REG = 9;

  EcanShadow.CANBTC.bit.SAM = 1;
  EcanRegs.CANBTC.all = EcanShadow.CANBTC.all;

  EcanShadow.CANMC.all = EcanRegs.CANMC.all;
  EcanShadow.CANMC.bit.CCR = 0; // Set CCR = 0
  EcanShadow.CANMC.bit.PDR  = 0;
  EcanShadow.CANMC.bit.DBO  = 1;
  EcanShadow.CANMC.bit.WUBA = 0;
  EcanShadow.CANMC.bit.CDR  = 0;
  EcanShadow.CANMC.bit.ABO  = 1;
  EcanShadow.CANMC.bit.STM  = 0;
  EcanShadow.CANMC.bit.SRES = 0;
  EcanShadow.CANMC.bit.MBNR = 0;
  EcanShadow.CANMC.bit.SUSP = 1; // free mode
  EcanRegs.CANMC.all = EcanShadow.CANMC.all;

  // Wait until the CPU no longer has permission to change the configuration registers
  do
  { EcanShadow.CANES.all = EcanRegs.CANES.all;
  } while(EcanShadow.CANES.bit.CCE != 0 );  // Wait for CCE bit to be  cleared..

  /* Disable all Mailboxes  */
  EcanRegs.CANME.all = 0;  // Required before writing the MSGIDs

  EcanRegs.CANMIL.all = 0xFFFFFFFF; // set all mailbox interrupts to level 1 (ECAN1INT)
  EcanRegs.CANMIM.all = 0xFFFFFFFF; // enable all mailbox interrupts

  EcanShadow.CANGIM.all = 0;
  EcanShadow.CANGIM.bit.GIL = 0;  // All global interrupts are mapped to the ECAN0INT interrupt line.
  EcanShadow.CANGIM.bit.I0EN = 1; // enable all interrupts for the ECAN0INT
  EcanShadow.CANGIM.bit.I1EN = 1; // enable all interrupts for the ECAN1INT

  EcanShadow.CANGIM.bit.AAIM = 1; // Abort Acknowledge Interrupt Mask
  EcanShadow.CANGIM.bit.WDIM = 1; // Write denied interrupt mask
  EcanShadow.CANGIM.bit.WUIM = 1; // Wake-up interrupt mask
  EcanShadow.CANGIM.bit.BOIM = 1; // Bus-off interrupt mask
  EcanShadow.CANGIM.bit.EPIM = 1; // Error-passive interrupt mask
  EcanShadow.CANGIM.bit.WLIM = 1; // Warning level interrupt mask

  EcanRegs.CANGIM.all   = EcanShadow.CANGIM.all;

  EDIS;
}

#ifdef __C280X_ECANxxx_ISR
//iointctrl
void ecan_base::enable_rx_interrupt (unsigned short /*ena*/)
{
}
void ecan_base::enable_rx_interrupt (unsigned short /*ena*/, unsigned short /*level*/)
{
}
void ecan_base::enable_tx_interrupt (unsigned short /*ena*/)
{
}
void ecan_base::enable_tx_interrupt (unsigned short /*ena*/, unsigned short /*level*/)
{
}
#endif //__C280X_ECANxxx_ISR


//
// class mbox
//
mbox::mbox( // configure for transmit
    ecan_base& ecanref
  , unsigned short n
  , unsigned long  msgid
  , unsigned short rtr
) : ecan(ecanref)
  , MboxRegs(*(&ECanaMboxes.MBOX0 + n))
  , mbnr(n)
  , mask((unsigned long)1 << n)
{ struct ECAN_REGS EcanShadow;
  // Clear the appropriate bit in the CANTRS register to 0
  ecan.EcanRegs.CANTRR.all |= mask;

  // wait until TRS.n clears
  do
  { EcanShadow.CANTRS.all = ecan.EcanRegs.CANTRS.all;
  } while((EcanShadow.CANTRS.all & mask)  != 0 );  // Wait for CCE bit to be  cleared..

  // Clear the appropriate Abort-Acknowledge bit
  ecan.EcanRegs.CANAA.all |= mask;

  // Disable the mailbox
  EcanShadow.CANME.all = ecan.EcanRegs.CANME.all;
  EcanShadow.CANME.all&= ~mask;
  ecan.EcanRegs.CANME.all = EcanShadow.CANME.all;

  // Loading the message identifier (MSGID) register of the mailbox
  MboxRegs.MSGID.all = msgid;
  MboxRegs.MSGID.bit.AAM = 0; // ensure that AAM and AME bit cleared for a normal send mailbox
  MboxRegs.MSGID.bit.AME = 0;
  MboxRegs.MSGID.bit.IDE = 0; // The RECEIVED message had a standard identifier

  // Write the data length and RTR flag
  MboxRegs.MSGCTRL.bit.DLC = 0;
  MboxRegs.MSGCTRL.bit.RTR = rtr;

  // Set the mailbox direction (transmit)
  EcanShadow.CANMD.all = ecan.EcanRegs.CANMD.all;
  EcanShadow.CANMD.all&= ~mask;
  ecan.EcanRegs.CANMD.all = EcanShadow.CANMD.all;

  // Enable the mailbox
  EcanShadow.CANME.all = ecan.EcanRegs.CANME.all;
  EcanShadow.CANME.all|= mask;
  ecan.EcanRegs.CANME.all = EcanShadow.CANME.all;
}

mbox::mbox( // configure for receive
    ecan_base& ecanref
  , unsigned short n
  , unsigned long  msgid
  , unsigned long  lam
  , unsigned short opc
  , unsigned short rtr
) : ecan(ecanref)
  , MboxRegs(*(&ECanaMboxes.MBOX0 + n))
  , mbnr(n)
  , mask((unsigned long)1 << n)
{ struct ECAN_REGS EcanShadow;
  // Disable the mailbox
  EcanShadow.CANME.all = ecan.EcanRegs.CANME.all;
  EcanShadow.CANME.all&= ~mask;
  ecan.EcanRegs.CANME.all = EcanShadow.CANME.all;

  // Loading the message identifier (MSGID) 
  // and corresponding acceptance mask 
  MboxRegs.MSGID.all = msgid;
  if(MboxRegs.MSGID.bit.AME != 0)
    (*(&ecan.EcanLAMRegs.LAM0 + mbnr)).all = lam;

  // Set the mailbox direction (receive)
  EcanShadow.CANMD.all = ecan.EcanRegs.CANMD.all;
  EcanShadow.CANMD.all|= mask;
  ecan.EcanRegs.CANMD.all = EcanShadow.CANMD.all;

  // overwrite protection control
  EcanShadow.CANOPC.all = ecan.EcanRegs.CANOPC.all;
  if(opc)
    EcanShadow.CANOPC.all |= mask;
  else
    EcanShadow.CANOPC.all &= ~mask;
  ecan.EcanRegs.CANOPC.all = EcanShadow.CANOPC.all;

  // Write the RTR flag
  MboxRegs.MSGCTRL.bit.RTR = rtr;

  // Enable the mailbox
  EcanShadow.CANME.all = ecan.EcanRegs.CANME.all;
  EcanShadow.CANME.all|= mask;
  ecan.EcanRegs.CANME.all = EcanShadow.CANME.all;
}

mbox::size_type mbox::size()
{ return (size_type)MboxRegs.MSGCTRL.bit.DLC;
}

template bool __safe_wait_helper<mbox::transmission>(mbox::transmission);
void mbox::write(data_type* buf, size_type bufsize )
{ if(    buf == 0
      || bufsize == 0
      || (ecan.EcanRegs.CANMD.all & mask) != 0)
    return;
  struct ECAN_REGS EcanShadow;

  // wait for previous trasmission end
  safe_wait(transmission(*this));

  if(ecan.EcanRegs.CANTRS.all & mask)
  { ecan.EcanRegs.CANTRR.all |= mask;
  }

  // clear transmit acknowledge bit
  EcanShadow.CANTA.all = ecan.EcanRegs.CANTA.all;
  EcanShadow.CANTA.all|= mask;
  ecan.EcanRegs.CANTA.all = EcanShadow.CANTA.all;
  while(ecan.EcanRegs.CANTA.all & mask);

  if(bufsize > max_bufsize)
    bufsize = max_bufsize;

  EALLOW;

  EcanShadow.CANMC.all = ecan.EcanRegs.CANMC.all;
  EcanShadow.CANMC.bit.MBNR = mbnr;
  EcanShadow.CANMC.bit.CDR  = 1;
  ecan.EcanRegs.CANMC.all = EcanShadow.CANMC.all;

  if(bufsize != size())
    MboxRegs.MSGCTRL.bit.DLC = bufsize;

  for(size_type n = 0; n < bufsize; n++)
    binarizer((binarizer::value_type*)&MboxRegs.MDL.all, n) = *binarizer(buf, n);

  EcanShadow.CANMC.all = ecan.EcanRegs.CANMC.all;
  EcanShadow.CANMC.bit.MBNR = 0;
  EcanShadow.CANMC.bit.CDR  = 0;
  ecan.EcanRegs.CANMC.all = EcanShadow.CANMC.all;

  EDIS;

  // transmit request
  ecan.EcanRegs.CANTRS.all |= mask;
}

void mbox::read (data_type* buf, size_type bufsize )
{ if((ecan.EcanRegs.CANRMP.all & mask) == 0)
    return;

  if(bufsize < size())
    bufsize = size();

  for(size_type n = 0; n < bufsize; n++)
    binarizer(buf, n) = *binarizer((binarizer::value_type*)&MboxRegs.MDL.all, n);

  ecan.EcanRegs.CANRMP.all |= mask;
}

//
// class mbox::transmission
//
mbox::transmission::transmission(mbox& mbRef)
 : mb(mbRef)
{
}
bool mbox::transmission::operator()(void) const
{ return mb.ecan.EcanRegs.CANTRS.all & mb.mask;
}

#if    defined(__C280X_ECANA)
//
// class ecana
//
ecana::ecana(
    pio& CANTX
  , pio& CANRX
  , unsigned long bitrate
) : ecan_base (
        ECanaRegs
      , ECanaMboxes
      , ECanaLAMRegs
      , pclk(SysCtrlRegs.PCLKCR0.all, 0x4000)
      , CANTX
      , CANRX
      , bitrate
    )
{ EALLOW;
#ifdef __C280X_ECANA0_ISR
    PieVectTable.ECAN0INTA = (PINT)&ecana0_isr;
#endif //__C280X_ECANA0_ISR

#ifdef __C280X_ECANA1_ISR
    PieVectTable.ECAN1INTA = (PINT)&ecana1_isr;
#endif //__C280X_ECANA1_ISR
  EDIS;
}

#ifdef __C280X_ECANxxx_ISR
//iointctrl
void ecana::enable_pie_interrupt(unsigned short ena)
{ ::enable_pie_interrupt(ena, 9, 0x0030);
}
#endif //__C280X_ECANxxx_ISR

#endif // __C280X_ECANA


#endif // #if    defined(__C280X_ECANA)\
              || defined(__C280X_ECANB)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -