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

📄 mcohw_lpc2.c

📁 Canopen 最小实现源码, 只支持最小的CANOPEN功能
💻 C
字号:
/**************************************************************************
MODULE:    MCOHW_LPC2
CONTAINS:  Preliminary, limited hardware driver implementation for 
           Philips LPC2000 derivatives with CAN interface.
           Compiled and Tested with Keil Tools www.keil.com
COPYRIGHT: Embedded Systems Academy, Inc. 2002-2005.
           All rights reserved. www.microcanopen.com
           This software was written in accordance to the guidelines at
           www.esacademy.com/software/softwarestyleguide.pdf
DISCLAIM:  Read and understand our disclaimer before using this code!
           www.esacademy.com/disclaim.htm
LICENSE:   THIS IS THE EDUCATIONAL VERSION OF MICROCANOPEN
           See file license_educational.txt or
           www.microcanopen.com/license_educational.txt
           A commercial MicroCANopen license is available at
           www.CANopenStore.com
VERSION:   2.10, ESA 12-JAN-05
           $LastChangedDate: 2005-01-12 13:53:59 -0700 (Wed, 12 Jan 2005) $
           $LastChangedRevision: 48 $
***************************************************************************/ 

#include <LPC21XX.H> // LPC21XX Peripheral Registers

#include "mcohw.h"

// Process data communicated via CAN
extern UNSIGNED8 gProcImg[PROCIMG_SIZE];

// Define CAN SFR address bases 
#define CAN_REG_BASE                    (0xE0000000)
#define ACCEPTANCE_FILTER_RAM_BASE      (CAN_REG_BASE + 0x00038000)
#define ACCEPTANCE_FILTER_REGISTER_BASE (CAN_REG_BASE + 0x0003C000)
#define CENTRAL_CAN_REGISTER_BASE       (CAN_REG_BASE + 0x00040000)              
#define CAN_1_BASE                      (CAN_REG_BASE + 0x00044000)              
#define CAN_2_BASE                      (CAN_REG_BASE + 0x00048000)              

// Common CAN bit rates
#define   CANBitrate125k_12MHz          0x001C001D
#define   CANBitrate250k_12MHz          0x001C000E

// Maximum number of FullCAN Filters
#define MAX_FILTERS 20

// Timer Interrupt
void MCOHW_TimerISR (void) __attribute__ ((interrupt)); 

// CAN Interrupt
void MCOHW_CANISR_Err (void) __attribute__ ((interrupt));
void MCOHW_CANISR_Tx1 (void) __attribute__ ((interrupt));
void MCOHW_CANISR_Rx1 (void) __attribute__ ((interrupt));
void MCOHW_DefaultISR (void) __attribute__ ((interrupt)); 


// Global timer/conter variable, incremented every millisecond
UNSIGNED16 volatile gTimCnt = 0;

// Counts number of filters (CAN message objects) used
UNSIGNED16 volatile gCANFilter = 0;

// Type definition to hold a FullCAN message
typedef struct
{
  UNSIGNED32 Dat1;
  UNSIGNED32 DatA;
  UNSIGNED32 DatB;
} FULLCAN_MSGFIELD;

// FullCAN Message List
FULLCAN_MSGFIELD volatile gFullCANList[MAX_FILTERS];

// Lookup table for receive filters
UNSIGNED16 gFilterList[20];                           


// Pull the next CAN message from receive buffer
UNSIGNED8 MCOHW_PullMessage (CAN_MSG MEM_FAR *pReceiveBuf)
{
UNSIGNED16 obj;
UNSIGNED32 *pSrc; // Source Pointer
UNSIGNED32 *pDst; // Destination Pointer

  obj = 0;
  pDst = (UNSIGNED32 *) &(pReceiveBuf->BUF[0]);
  pSrc = (UNSIGNED32 *) &(gFullCANList[0].Dat1);
  
  while (obj < gCANFilter)
  {
      // if its currently updated, we come back next time and do not wait here
    // semaphore set to 11?
    if ((*pSrc & 0x03000000L) == 0x03000000L)
    { // Object Updated since last access
      *pSrc &= 0xFCFFFFFF; // clear Semaphore
      pSrc++; // Set to DatA
      *pDst = *pSrc; // Copy DatA
      pSrc++; // Set to DatB
      pDst++; // Set to DatB
      *pDst = *pSrc; // Copy DatB
      pSrc -= 2; // Back to Dat1

      pReceiveBuf->ID = (UNSIGNED16) *pSrc & 0x07FF;
      pReceiveBuf->LEN = (UNSIGNED8) (*pSrc >> 16) & 0x0F;

      // Re-read semaphore
      if ((*pSrc & 0x03000000L) == 0)
      { // Only return it, if not updated while reading
        return 1;
      }
    }
    obj ++; // Next message object buffer
    pSrc += 3; // Next record in gFullCANList array
  }
  return 0; // Return False, no msg rcvd 
}

// Push the next transmit message into transmit queue
UNSIGNED8 MCOHW_PushMessage (CAN_MSG MEM_FAR *pTransmitBuf)
{
UNSIGNED32 *pAddr;  
UNSIGNED32 status;
UNSIGNED32 candata;
UNSIGNED32 *pCandata;
UNSIGNED32 TXBufOffset;
  
  if (pTransmitBuf->ID == 0)
  { // This may not happen
    pTransmitBuf->ID = 1;
    pTransmitBuf->LEN = 8;
  }
  
  status = C1SR; // CANSR

  if (!(status & 0x00000004L))
  { // Transmit Channel 1 is not available
    if (!(status & 0x00000400L))
    { // Transmit Channel 2 is not available
      if (!(status & 0x00040000L))
      { // Transmit Channel 3 is not available
        return 0; // No channel available
      }
      else
      {
        TXBufOffset = 0x08;
      }
    }
    else
    {
      TXBufOffset = 0x04;
    }
  }
  else
  {
    TXBufOffset = 0x00;
  }

  candata = pTransmitBuf->LEN;
  candata <<= 16;

  pAddr = (UNSIGNED32 *) &C1TFI1 + TXBufOffset;
  *pAddr = candata;  
  
  pAddr++;
  *pAddr = pTransmitBuf->ID;
 
  pCandata = (UNSIGNED32 *) &(pTransmitBuf->BUF[0]);
  pAddr++;
  *pAddr = *pCandata;

  pCandata++;
  pAddr++;
  *pAddr = *pCandata;
  
  if (TXBufOffset == 0x00)
  {
    C1CMR = 0x21; // Transmission Request  Buf 1
  }
  else if (TXBufOffset == 0x04)
  {
    C1CMR = 0x41; // Transmission Request Buf 2
  }
  else if (TXBufOffset == 0x08)
  {
    C1CMR = 0x81; // Transmission Request Buf 3
  }
  else
  {
    return 0;
  }

  return 1;
}


/**************************************************************************
DOES: Reads and returns the value of the current 1 millisecond system
      timer tick.
**************************************************************************/
UNSIGNED16 MCOHW_GetTime (void)
{
  return gTimCnt;
}


// Checks if a TimeStamp expired
UNSIGNED8 MCOHW_IsTimeExpired(UNSIGNED16 timestamp)
{
UNSIGNED16 time_now;

  time_now = gTimCnt;
  if (time_now > timestamp)
  {
    if ((time_now - timestamp) < 0x8000)
      return 1;
    else
      return 0;
  }
  else
  {
    if ((timestamp - time_now) > 0x8000)
      return 1;
    else
      return 0;
  }
}

// Timer ISR
void MCOHW_TimerISR 
  (
  void
  ) 
{
  gTimCnt++;
  T0IR = 1; // Clear interrupt flag
  VICVectAddr = 0xFFFFFFFF; // Acknowledge Interrupt
}

// CDefault ISR
void MCOHW_DefaultISR 
  (
  void
  ) 
{
  VICVectAddr = 0xFFFFFFFF; // Acknowledge Interrupt
  while (1)
  {
  // DEBUG: WE SHOULD NEVER GET HERE
  }
}
                                                        
// CAN ISR
void MCOHW_CANISR_Err 
  (
  void
  ) 
{
  VICVectAddr = 0xFFFFFFFF; // Acknowledge Interrupt
  while (1)
  {
  // DEBUG: WE SHOULD NEVER GET HERE
  }
}

void MCOHW_CANISR_Tx1 
  (
  void
  ) 
{
  VICVectAddr = 0xFFFFFFFF; // Acknowledge Interrupt
}


void MCOHW_CANISR_Rx1 
  (
  void
  ) 
{
UNSIGNED32 buf;
UNSIGNED32 *pDest;

  if (!(C1RFS & 0xC0000400L))
  { // 11-bit ID, no RTR, matched a filter

    // initialize destination pointer
    // filter number is in lower 10 bits of C1RFS
    pDest = (UNSIGNED32 *) &(gFullCANList[(C1RFS & 0x000003FFL)].Dat1);
    
    // calculate contents for first entry into FullCAN list
    buf = C1RFS & 0xC00F0000L; // mask FF, RTR and DLC
    buf |= 0x01000000L; // set semaphore to 01b
    buf |= C1RID & 0x000007FFL; // get CAN message ID

    // now copy entire message to FullCAN list
    *pDest = buf; 
    pDest++; // set to gFullCANList[(C1RFS & 0x000003FFL)].DatA
    *pDest = C1RDA; 
    pDest++; // set to gFullCANList[(C1RFS & 0x000003FFL)].DatB
    *pDest = C1RDB; 

    // now set the sempahore to complete
    buf |= 0x03000000L; // set semaphore to 11b
    pDest -= 2; // set to gFullCANList[(C1RFS & 0x000003FFL)].Dat1
    *pDest = buf; 
  }

  C1CMR = 0x04; // release receive buffer
  VICVectAddr = 0xFFFFFFFF; // acknowledge Interrupt
}


// Init CAN Interface and Timer
UNSIGNED8 MCOHW_Init 
  (
  UNSIGNED16 BaudRate
  )
{
  if (BaudRate != 125) 
  { // This implementation only supports 125kbit
      return 0;
  }

  // Enable Pins for CAN port 1 and 2
  PINSEL1 |= (UNSIGNED32) 0x00054000; 
  
  C1MOD = 1; // Enter Reset Mode
  C1GSR = 0; // Clear status register
  C1BTR = CANBitrate125k_12MHz; // Set bit timing
  
  AFMR = 0x00000001; // Disable acceptance filter

  // Disable All Interrupts
  C1IER = 0;

  // Enter Normal Operating Mode
  C1MOD = 0; // Operating Mode 

  // Init Interrupts
  VICDefVectAddr = (unsigned long) MCOHW_DefaultISR;

  // Initialize Timer Interrupt
  T0MR0 = 59999; // 1mSec = 60.000-1 counts
  T0MCR = 3; // Interrupt and Reset on MR0
  T0TCR = 1;  // Timer0 Enable

  VICVectAddr0 = (unsigned long) MCOHW_TimerISR; // set interrupt vector
  VICVectCntl0 = 0x20 | 4;  // use it for Timer 0 Interrupt
  VICIntEnable = 0x00000010;  // Enable Timer0 Interrupt

  VICVectAddr1 = (unsigned long) MCOHW_CANISR_Rx1; // set interrupt vector
  VICVectCntl1 = 0x20 | 26;  // use it for CAN Rx1 Interrupt
  VICIntEnable = 0x04000000;  // Enable CAN Rx1 Interrupt
  
  C1IER = 0x0001; // Enable CAN 1 RX interrupt

  gCANFilter = 0; // Reset all filters

  return 1;
}


UNSIGNED8 MCOHW_SetCANFilter 
  (
  UNSIGNED16 CANID
  )
{
int p, n;
int buf0, buf1;
int ID_lower, ID_upper;
UNSIGNED32 candata;
UNSIGNED32 *pAddr;

  if (gCANFilter == 0)
  { // First call, init entry zero
    gFilterList[0] = 0x17FF; // Disabled and unused
  }
  if (gCANFilter >= MAX_FILTERS)
  {
    return 0;
  }

  // Filters must be sorted by priority

  // new filter is sorted into array
  p = 0;
  while (p < gCANFilter) // loop through all existing filters 
  {
    if (gFilterList[p] > CANID)
    {
      break;
    }
    p++;
  }
  // insert new filter here
  buf0 = gFilterList[p]; // save current entry
  gFilterList[p] = CANID; // insert the new entry
  // move all remaining entries one row up
  gCANFilter++;
  while (p < gCANFilter)
  {
    p++;
    buf1 = gFilterList[p];
    gFilterList[p] = buf0;
    buf0 = buf1;
  }

  // Now work on Acceptance Filter Configuration     
  // Acceptance Filter Mode Register = off !
  AFMR = 0x00000001;
  
  // Set CAN filter for 11-bit standard identifiers
  p = 0;

  // Set pointer for Standard Frame Individual
  // Standard Frame Explicit
  SFF_sa = p;

  pAddr = (UNSIGNED32 *) ACCEPTANCE_FILTER_RAM_BASE;
  for (n = 0; n < ((gCANFilter+1)/2); n++)
  {
    ID_lower = gFilterList[n * 2];
    ID_upper = gFilterList[n * 2 + 1];
    // 0x20002000 indicates CAN interface 1
    candata = 0x20002000 + (ID_lower << 16) + ID_upper;
    *pAddr = candata;
    p += 4;
    pAddr++;
  }

  // p is still ENDofTable;
  
  // Set pointer for Standard Frame Groups
  // Standard Frame Group Start Address Register
  SFF_GRP_sa = p;

  // Set pointer for Extended Frame Individual
  // Extended Frame Start Address Register
  EFF_sa = p;

  // Set pointer for Extended Frame Groups
  // Extended Frame Group Start Address Register
  EFF_GRP_sa = p;

  // Set ENDofTable 
  // End of AF Tables Register
  ENDofTable = p;

  // Acceptance Filter Mode Register, start using filter
  AFMR = 0x00000000;
  
  return 1;
}


/*----------------------- END OF FILE ----------------------------------*/

⌨️ 快捷键说明

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