www.pudn.com > MicroCANOPEN.rar > mcohwCC01.c, change:2003-05-28,size:11862b


/************************************************************************** 
MODULE:    MCOHWCC01 
CONTAINS:  Preliminary, limited hardware driver implementation for 
           Atmel 89C51CC01 - tested using the Atmel CANopen Demo Board 
		   using a 20Mhz clock (CANgine board: www.cangine.com) 
           This version was tested with the Keil compiler system. 
           www.keil.com 
COPYRIGHT: Embedded Systems Academy, Inc. 2002-2003. 
           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:   Users that have purchased a license for PCANopenMagic 
           (www.esacademy.com/software/pcanopenmagic) 
           may use this code in commercial projects. 
           Otherwise only educational use is acceptable. 
VERSION:   1.20, Pf/Aa/Ck 27-MAY-03 
--------------------------------------------------------------------------- 
HISTORY:   1.20, Pf 27-MAY-03, Adapted for 20MHz Atmel CANopen Demo Board 
                 added support for CANopen ERR and RUN LED 
           1.00, Ck 07-OCT-02, First Published Version 
--------------------------------------------------------------------------- 
Known Shortcomings: 
Only supports a transmit queue of length "1" 
If queue occupied, waits until it is clear 
***************************************************************************/  
 
#include <Reg51cc01.h> 
#include "mcohw.h" 
 
#ifdef USE_LED 
BYTE data m200cnt = 0; 
#endif // USE_LED 
 
// Global timer/conter variable, incremented every millisecond 
WORD data gTimCnt = 0; 
 
// Global conter for number of receive filters used 
BYTE gCANFilter = 0; 
 
 
#ifdef USE_LED 
/************************************************************************** 
Variables for LED management 
**************************************************************************/ 
BYTE data mLEDtoggle = 0; 
BYTE data mLEDcnt = 0; 
BYTE data gRLED = LED_OFF; // Current pattern on run led 
BYTE data gELED = LED_OFF; // Current pattern on error led 
 
 
/************************************************************************** 
DOES: This function switches the CANopen Err and Run LEDs 
as specified by DR-303-3 
It must be called once every 200ms 
**************************************************************************/ 
void MCO_SwitchLEDs 
  ( 
  void 
  ) 
{ 
  mLEDtoggle = ~mLEDtoggle; 
  mLEDcnt++; 
  if (mLEDcnt >= 6) 
  { 
    mLEDcnt = 0; 
  } 
 
  switch(gRLED) // Run LED 
  { 
    case LED_OFF: 
	  LED_RUN = 1; 
	  break; 
	case LED_ON: 
	  LED_RUN = 0; 
	  break; 
	case LED_BLINK: 
	  LED_RUN = mLEDtoggle; 
	  break; 
	case LED_FLASH1: 
	  if (mLEDcnt == 0) 
	  { 
	    LED_RUN = 0; 
	  } 
	  else 
	  { 
	    LED_RUN = 1; 
	  } 
	  break; 
	default: 
	  break; 
  } 
 
  switch(gELED) // Error LED 
  { 
    case LED_OFF: 
	  LED_ERR = 1; 
	  break; 
	case LED_ON: 
	  LED_ERR = 0; 
	  break; 
	case LED_BLINK: 
	  LED_ERR = mLEDtoggle; 
	  break; 
	case LED_FLASH1: 
	  if (mLEDcnt == 1) 
	  { 
	    LED_ERR = 0; 
	  } 
	  else 
	  { 
	    LED_ERR = 1; 
	  } 
	  break; 
	default: 
	  break; 
  } 
 
} 
#endif // USE_LED 
 
 
/*======================================================================*/ 
/* FUNCTION:   init_can_125_20                                          */ 
/* DESCRIPTION:Initializes the CAN interface. Bus operates at 125kBit,  */ 
/*             if processor clock is 20MHz.                             */ 
/* CAUTION:    Does not initialize filters - nothing will be received   */ 
/*             unless screeners are set using set_screener_std          */ 
/* INPUT:      none                                                     */ 
/* OUTPUT:     none                                                     */ 
/*======================================================================*/ 
void init_can_125_20 ( void ) 
{ 
BYTE i; 
 
/* Enable X2 mode */ 
   CKCON = 0x01; 
 
/* timing for X2 mode, 20MHz, 125kbps */ 
   CANBT1 = 7 << 1; 
   CANBT2 = (1 << 5) | (7 << 1); // SJW << 5, PRS << 1 
   CANBT3 = (2 << 4) | (7 << 1); // PHS2 << 4, PHS << 1 
 
/* Clear all acceptance filters and masks, receive nothing */ 
   for (i=0; i<15; i++) 
   { 
      CANPAGE  = i << 4;            /* select msg object i */ 
      CANIDT1  = 0xFF;              /* msg id bits 3-10 */ 
      CANIDT2  = 0xE0;              /* msg id bits 0-2 */ 
      CANIDT4  = 0x00;              /* no remote request */ 
      CANIDM1  = 0xFF;              /* mask bits 3-10 */ 
      CANIDM2  = 0xE0;              /* mask bits 0-2 */ 
      CANIDM4  = 0x05;              /* only accept that msg id */ 
      if (i!=0) 
         CANSTCH = 0x00;            /* clear receive ok (and all other) flags */ 
      else 
         CANSTCH = 0x40;            /* for transmit buffer we need to set TX for first transmit */ 
/* disable msg object */ 
      CANCONCH = 0x00;              /* msg object is disabled */ 
   } 
   
   CANGCON = 0x02;                 /* enable CAN controller */ 
   while (!(CANGSTA & 0x04));      /* wait for can controller to be enabled */ 
 
   // Initialize Timer interrupt here.  
   // MCOHW_TimerISR must be executed once every millisecond. 
   TR0     =  0;                   /* timer 0: stop */ 
   TMOD    |= 1;                   /* mode 1 */ 
   TH0     =  0xFF; 
   TL0     =  0xFF; 
   TR0     =  1;                   /* timer 0: start */ 
   ET0     =  1;                   /* enable timer 0 int */ 
} 
 
 
/*======================================================================*/ 
/* FUNCTION:   set_screener_std                                         */ 
/* DESCRIPTION:Sets one of the four screeners (acceptance filters) of   */ 
/*             the CAN controller.                                      */ 
/* CAUTION:    For the AT89C51CC01 from Atmel the screeners translate   */ 
/*             to individual message buffers 1-14. The parameters       */ 
/*             x_Mask and Bx_Match are ignored.                         */ 
/* INPUT:      Screener - 1 to 4, one of the four screeners             */ 
/*             ID_Match - Match/Code value for ID                       */ 
/* OUTPUT:     none                                                     */ 
/*======================================================================*/ 
void set_screener_std ( BYTE Screener, WORD ID_Match ) 
{ 
   CANPAGE  = Screener << 4;        /* select msg object */ 
   CANIDT1  = (ID_Match & 0x07F8) >> 3; /* msg id bits 3-10 */ 
   CANIDT2  = (ID_Match & 0x0007) << 5; /* msg id bits 0-2 */ 
   CANIDT4  = 0x00;                 /* no remote request */ 
   CANIDM1  = 0xFF;                 /* mask bits 3-10: must match */ 
   CANIDM2  = 0xE0;                 /* mask bits 0-2: must match */ 
   CANIDM4  = 0x05;                 /* only accept that msg id */ 
/* clear receive ok (and all other) flags */ 
   CANSTCH  = 0x00;                /* initialize */ 
/* enable msg object */ 
   CANCONCH = 0x88;                /* msg object is enabled for receive, expected 8 bytes */ 
} 
 
 
 
BYTE MCOHW_PullMessage (CAN_MSG *pReceiveBuf) 
{ 
DWORD Identifier;                   /* Definition of vars */ 
BYTE  Length; 
BYTE  i,j; 
 
   for (j=1; j<=gCANFilter; j++)   /* Find msg object that has received something */ 
   { 
      CANPAGE = j << 4;    // select msg object 
 
/* Check the CAN status register for received message                */ 
      if (CANSTCH & 0x20) 
      {                                       /* Message received!   */ 
         /* Copy message to application message buffer.              */ 
         Identifier = (unsigned int)(CANIDT1 << 3) | (CANIDT2 >> 5); 
         Length     = CANCONCH & 0x0F; 
  
         pReceiveBuf->ID  = Identifier; 
         pReceiveBuf->LEN = Length; 
 
         /* Read data bytes and write to buffer                      */ 
         for (i=0; i < Length; i++) 
    	      *(BYTE *)(pReceiveBuf->BUF+i) = CANMSG;  /* copy bytes   */ 
  
         // clear receive ok flag 
         CANSTCH &= 0xDF; 
         // re-enable msg object 
         CANCONCH = 0x88;      /* msg object receives and is enabled */ 
                               /* 8 bytes excpected                  */ 
 
         return (1);                /* Return TRUE, msg rcvd    */ 
     } 
  } 
 
  return (0);                      /* Return False, no msg rcvd */ 
} 
 
BYTE MCOHW_PushMessage (CAN_MSG *pTransmitBuf) 
{ 
DWORD Identifier;                   /* CAN message identifier */ 
BYTE  Length;                       /* length of data frame */ 
BYTE  i;                            /* local loop counter */ 
 
/* Prepare length code and identifier.                                  */ 
   Length     = pTransmitBuf->LEN; 
   Identifier = pTransmitBuf->ID; 
 
   CANPAGE  = 0 << 4;               /* select msg object 0 */ 
 
/* Check if write access to CAN controller buffer is allowed          */ 
   while (!(CANSTCH & 0x40))  
   { 
   } 
   if (!(CANSTCH & 0x40)) 
   { 
     return 0; 
   } 
 
   CANCONCH &=  0x3F;              /* disable object */ 
   CANSTCH  &= ~0x40;              /* clear TXOK bit */ 
 
   CANIDT1  = (Identifier & 0x07F8) >> 3;  /* msg id bits 3-10 */ 
   CANIDT2  = (Identifier & 0x0007) << 5;  /* msg id bits 0-2 */ 
   CANIDT4  = 0x00;                /* no remote request */ 
 
/* Write message to transmit buffer                                     */ 
   for (i=0; i < Length; i++)        /* write data bytes */ 
      CANMSG = pTransmitBuf->BUF[i]; /* copy data byte  */ 
 
/* set length and enable msg object => send */ 
   CANCONCH = 0x40 | (Length & 0x0F); 
    
   return 1; 
} 
 
 
/************************************************************************** 
DOES: Reads and returns the value of the current 1 millisecond system 
      timer tick. 
**************************************************************************/ 
WORD MCOHW_GetTime (void) 
{ 
WORD tmp; 
 
  EA = 0; // Disable Interrupts 
  tmp = gTimCnt; 
  EA = 1; // Enable Interrupts 
  return tmp; 
} 
 
 
BYTE MCOHW_IsTimeExpired(WORD timestamp) 
{ 
WORD time_now; 
 
  EA = 0; // Disable Interrupts 
  time_now = gTimCnt; 
  EA = 1; // Enable Interrupts 
  timestamp++; // To ensure the minimum runtime 
  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; 
  } 
} 
 
/************************************************************************** 
DOES: Timer Interrupt Service Routine.  
      Increments the global millisecond counter tick. 
      This function needs to be executed once every millisecond! 
**************************************************************************/ 
#define T0_RELOAD 62210  
// Time reload to achieve 1 millisecond at 20MHz, 6-clock 
 
void MCOHW_TimerISR (void) interrupt 1 
{ 
 
  TR0 = 0; // Stop Timer 0 
  TH0 = T0_RELOAD / 256; 
  TL0 = T0_RELOAD % 256; // Timer reload value 
  TR0 = 1; // Start Timer 0 
 
  gTimCnt++; // Increment global counter 
 
#ifdef USE_LED 
  m200cnt++; 
  if (m200cnt >= 200) 
  { 
    MCO_SwitchLEDs(); // Call all 200ms 
    m200cnt = 0; 
  } 
#endif // USE_LED 
} 
 
BYTE MCOHW_Init (WORD BaudRate) 
{ 
// This version only supports 125kbit at 20MHz 
  if (BaudRate == 125) 
  { 
    init_can_125_20(); 
    gCANFilter = 0; 
	return 1; 
  } 
  else 
  { 
    return 0; 
  } 
} 
 
BYTE MCOHW_SetCANFilter (WORD CANID) 
{ 
  gCANFilter++; 
  if (gCANFilter > 14)  // Kl, 10/9/02 Modified for CC01 
  { 
    return 0; 
  } 
  else 
  { 
    set_screener_std(gCANFilter, CANID);  
    return 1; 
  } 
} 
 
 
/*----------------------- END OF FILE ----------------------------------*/