Skip to content

Instantly share code, notes, and snippets.

@petscare
Forked from fbstj/C_CAN.c
Created October 13, 2012 15:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save petscare/3884991 to your computer and use it in GitHub Desktop.
Save petscare/3884991 to your computer and use it in GitHub Desktop.
Keil_C: Module for communicating with C_CAN device on C8051F500 and other
/*
Module for communicating with C_CAN device on C8051F500 and F580.
*/
#include "myPlatform.h"
#define __C_CAN_H 1
# include "C_CAN.h"
#undef __C_CAN_H
// CAN0STAT masks
#define BOff 0x80 // Busoff Status
#define EWarn 0x40 // Warning Status
#define EPass 0x20 // Error Passive
#define RxOk 0x10 // Receive Message Successfully
#define TxOk 0x08 // Transmitted Message Successfully
#define LEC 0x07 // Last Error Code
// breaks between write-read pairs
#define CAN_nop() NOP();NOP();NOP();NOP()
#ifdef CAN0_PAGE
void CAN0_init(void)
{
unsigned char SFRPAGE_save = SFRPAGE;
SFRPAGE = CAN0_PAGE;
CAN0CN = 1; // start Intialization mode
CAN_nop(); // wait
// initialize general CAN peripheral settings
CAN0CN |= 0x4E; // enable Error, Module and access to bit timing register
CAN_nop(); // wait
CAN0BT = 0x1402; // based on 24 Mhz CAN clock, set the CAN bit rate to 1 Mbps
CAN0CN |= 0x80; // enable test mode
CAN_nop(); // wait
CAN0TST = 0x04; // enalbe basic mode
// CAN initalization is complete
CAN0CN &= ~0x41; // return to Normal Mode and disable access to bit timing register
SFRPAGE = SFRPAGE_save;
}
void CAN0_send(CAN_message_t *m)
{
unsigned char SFRPAGE_save = SFRPAGE;
unsigned short _A2, _A1; // temporary arbitration regs
SFRPAGE = CAN0_PAGE;
// message control register
CAN0IF1MC = 0x1480 | m->Length;
// command request and mask registers
CAN0IF1CR = 0x0000;
CAN0IF1CM = 0x00F3;
// arbitration registers
if (m->Extended)
{ // extended frame
m->ID &= 0x1FFFFFFF;
_A1 = m->ID; // lower half of id
_A2 = (m->ID >> 16); // upper half of id
_A2 |= 0x4000; // set extended flag
}
else
{ // standard frame
m->ID &= 0x000007FF;
_A1 = 0;
_A2 = (m->ID << 2); // id fits in bits 28-18
}
if (m->Remote)
_A2 &= ~0x2000; // a remote frame
else
_A2 |= 0x2000; // not a remote frame
CAN0IF1A1 = _A1;
CAN0IF1A2 = _A2;
// data registers
CAN0IF1DA1H = m->Data[0]; CAN0IF1DA1L = m->Data[1];
CAN0IF1DA2H = m->Data[2]; CAN0IF1DA2L = m->Data[3];
CAN0IF1DB1H = m->Data[4]; CAN0IF1DB1L = m->Data[5];
CAN0IF1DB2H = m->Data[6]; CAN0IF1DB2L = m->Data[7];
// send message
CAN0IF1CM = 0x0087; // set Direction to Write TxRqst
CAN0IF1CR = 0x8000; // start command request
CAN_nop();
while (CAN0IF1CRH & 0x80) {} // poll on Busy bit
SFRPAGE = SFRPAGE_save;
}
#ifdef CAN0_RAW
void CAN0_send_raw(long id, unsigned char *msg, unsigned char len)
{
unsigned char SFRPAGE_save = SFRPAGE;
short idN = id & 0x07FF;
long idX = id & 0x1FFFFFFF;
unsigned short _A2, _A1; // temporary arbitration regs
SFRPAGE = CAN0_PAGE;
// message control register
CAN0IF1MC = 0x1480 | (len & 0x0F);
// command request and mask registers
CAN0IF1CR = 0x0000;
CAN0IF1CM = 0x00F3;
// arbitration registers
if (idN != id)
{ // extended frame
_A1 = idX; // lower half of id
_A2 = (idX >> 16); // upper half of id
_A2|= 0x4000; // set extended flag
}
else
{ // standard frame
_A1 = 0;
_A2 = (idN << 2); // id fits in bits 28-18
}
_A2 |= 0x2000; // not a remote frame
CAN0IF1A1 = _A1;
CAN0IF1A2 = _A2;
// data registers
CAN0IF1DA1H = msg[0]; CAN0IF1DA1L = msg[1];
CAN0IF1DA2H = msg[2]; CAN0IF1DA2L = msg[3];
CAN0IF1DB1H = msg[4]; CAN0IF1DB1L = msg[5];
CAN0IF1DB2H = msg[6]; CAN0IF1DB2L = msg[7];
// send message
CAN0IF1CM = 0x0087; // set Direction to Write TxRqst
CAN0IF1CR = 0x8000; // start command request
CAN_nop();
while (CAN0IF1CRH & 0x80) {} // poll on Busy bit
SFRPAGE = SFRPAGE_save;
}
#endif
void CAN0_ISR(void) interrupt INTERRUPT_CAN0
{ // SFRPAGE is set to CAN0_Page automatically when ISR starts
unsigned char status;
long _arb;
CAN_message_t *m = &CAN0_receive;
//unsigned char Interrupt_ID;
status = CAN0STAT; // read status, which clears the Status Interrupt bit pending in CAN0IID
CAN0IF2CM = 0x007F; // read all of message object to IF2 Clear IntPnd and newData
CAN_nop();
while (CAN0IF2CRH & 0x80) {} // poll on Busy bit
if (status & RxOk)
{ // receive completed successfully
_arb = ((long)CAN0IF2A2 << 16) | CAN0IF2A1;
m->Extended = (_arb >> 30) & 1;
m->Remote = (_arb >> 29) & 1;
if(m->Extended)
m->ID = (_arb & 0x1FFFFFFF);
else
m->ID = ((_arb >> 18) & 0x07FF);
// retreive the number of bytes in the packet (upto 8)
m->Length = (CAN0IF2MCL & 0x0F);
// copy message into CAN0rx;
m->Data[0] = CAN0IF2DA1L; m->Data[1] = CAN0IF2DA1H;
m->Data[2] = CAN0IF2DA2L; m->Data[3] = CAN0IF2DA2H;
m->Data[4] = CAN0IF2DB1L; m->Data[5] = CAN0IF2DB1H;
m->Data[6] = CAN0IF2DB2L; m->Data[7] = CAN0IF2DB2H;
CAN0_received = 1; // indicate recieved
}
// if an error occured, simply update the global variable and continue
if (status & LEC)
{ // the LEC bits identify the type of error, but those are grouped here
if ((status & LEC) != 0x07)
{
CAN0_error = 1;
}
}
if (status & BOff)
{
CAN0_error = 1;
}
if (status & EWarn)
{
CAN0_error = 1;
}
}
#else // CAN0_PAGE
#error CAN0 not defined (check myPlatform includes the correct target definitions)
#endif // CAN0_PAGE
/*
Module for communicating with C_CAN device on C8051F500 and F580.
NB: make sure init.c:CAN_Init() sets the clock to below 25Mhz (and enable CAN0_interrupt)
USAGE:
to send a CAN packet, fill in CAN0_transmit with the desired state and call
CAN0_send(&CAN0_transmit);
on the arrival of a message, the interrupt will fill CAN0_receive and set CAN0_received
to a truthy value, which can be checked in your main loop. Example loop:
while(1)
{
if(CAN0_received == 1)
{
CAN_message_t *m = &CAN0_receive;
if(m->Remote == 1)
{
m->Remote = 0;
CAN0_send(m);
}
CAN0_received = 0;
}
}
will reply to remote frames with random data.
*/
// magic externs
#ifdef __C_CAN_H
# define EXTERN /**/
#else
#ifdef __cplusplus
# define EXTERN extern "C"
#else
# define EXTERN extern
#endif // C++
#endif // __C_CAN_H
typedef struct CAN_MSG{
long ID;
unsigned char Data[8];
char Length : 4;
char Extended : 1;
char Remote : 1;
} CAN_message_t;
// only define thins if there exists a C_CAN device on the processor
#ifdef CAN0_PAGE
//#define CAN0_RAW
// holds error state for CAN0
EXTERN unsigned char CAN0_error;
// true if a message has been received
EXTERN unsigned char CAN0_received;
// a received message
EXTERN CAN_message_t xdata CAN0_receive;
// a message to use for sending data
EXTERN CAN_message_t xdata CAN0_transmit;
// initialise CAN0
EXTERN void CAN0_init(void);
// send a message object
EXTERN void CAN0_send(CAN_message_t *message);
// send the `len` bytes in `*msg` with `id` as the identifier
EXTERN void CAN0_send_raw(long id, unsigned char *msg, unsigned char len);
#endif // CAN0_PAGE
#undef EXTERN
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment