MCP2515 : SPI CAN controller management

#ifndef __MCP2515_H
#define __MCP2515_H

/*
mcp2515.h

This file contains constants that are specific to the MCP2515.

Version     Date        Description
----------------------------------------------------------------------
v1.00       2003/12/11  Initial release

Copyright 2003 Kimberly Otten Software Consulting
*/

// Define MCP2515 register addresses

#define MCP_RXF0SIDH    0x00
#define MCP_RXF0SIDL    0x01
#define MCP_RXF0EID8    0x02
#define MCP_RXF0EID0    0x03
#define MCP_RXF1SIDH    0x04
#define MCP_RXF1SIDL    0x05
#define MCP_RXF1EID8    0x06
#define MCP_RXF1EID0    0x07
#define MCP_RXF2SIDH    0x08
#define MCP_RXF2SIDL    0x09
#define MCP_RXF2EID8    0x0A
#define MCP_RXF2EID0    0x0B
#define MCP_CANSTAT        0x0E
#define MCP_CANCTRL        0x0F
#define MCP_RXF3SIDH    0x10
#define MCP_RXF3SIDL    0x11
#define MCP_RXF3EID8    0x12
#define MCP_RXF3EID0    0x13
#define MCP_RXF4SIDH    0x14
#define MCP_RXF4SIDL    0x15
#define MCP_RXF4EID8    0x16
#define MCP_RXF4EID0    0x17
#define MCP_RXF5SIDH    0x18
#define MCP_RXF5SIDL    0x19
#define MCP_RXF5EID8    0x1A
#define MCP_RXF5EID0    0x1B
#define MCP_TEC            0x1C
#define MCP_REC            0x1D
#define MCP_RXM0SIDH    0x20
#define MCP_RXM0SIDL    0x21
#define MCP_RXM0EID8    0x22
#define MCP_RXM0EID0    0x23
#define MCP_RXM1SIDH    0x24
#define MCP_RXM1SIDL    0x25
#define MCP_RXM1EID8    0x26
#define MCP_RXM1EID0    0x27
#define MCP_CNF3        0x28
#define MCP_CNF2        0x29
#define MCP_CNF1        0x2A
#define MCP_CANINTE        0x2B
#define MCP_CANINTF        0x2C
#define MCP_EFLG        0x2D
#define MCP_TXB0CTRL    0x30
#define MCP_TXB1CTRL    0x40
#define MCP_TXB2CTRL    0x50
#define MCP_RXB0CTRL    0x60
#define MCP_RXB0SIDH    0x61
#define MCP_RXB1CTRL    0x70
#define MCP_RXB1SIDH    0x71


#define MCP_TX_INT        0x1C        // Enable all transmit interrupts
#define MCP_TX01_INT    0x0C        // Enable TXB0 and TXB1 interrupts
#define MCP_RX_INT        0x03        // Enable receive interrupts
#define MCP_NO_INT        0x00        // Disable all interrupts

#define MCP_TX01_MASK    0x14
#define MCP_TX_MASK        0x54

// Define SPI Instruction Set

#define MCP_WRITE        0x02

#define MCP_READ        0x03

#define MCP_BITMOD        0x05

#define MCP_LOAD_TX0    0x40
#define MCP_LOAD_TX1    0x42
#define MCP_LOAD_TX2    0x44

#define MCP_RTS_TX0        0x81
#define MCP_RTS_TX1        0x82
#define MCP_RTS_TX2        0x84
#define MCP_RTS_ALL        0x87

#define MCP_READ_RX0    0x90
#define MCP_READ_RX1    0x94

#define MCP_READ_STATUS    0xA0

#define MCP_RX_STATUS    0xB0

#define MCP_RESET        0xC0


// CANCTRL Register Values

#define MODE_NORMAL     0x00
#define MODE_SLEEP      0x20
#define MODE_LOOPBACK   0x40
#define MODE_LISTENONLY 0x60
#define MODE_CONFIG     0x80
#define MODE_POWERUP    0xE0
#define MODE_MASK        0xE0
#define ABORT_TX        0x10
#define MODE_ONESHOT    0x08
#define CLKOUT_ENABLE    0x04
#define CLKOUT_DISABLE    0x00
#define CLKOUT_PS1        0x00
#define CLKOUT_PS2        0x01
#define CLKOUT_PS4        0x02
#define CLKOUT_PS8        0x03


// CNF1 Register Values

#define SJW1            0x00
#define SJW2            0x40
#define SJW3            0x80
#define SJW4            0xC0


// CNF2 Register Values

#define BTLMODE            0x80
#define SAMPLE_1X       0x00
#define SAMPLE_3X       0x40


// CNF3 Register Values

#define SOF_ENABLE        0x80
#define SOF_DISABLE        0x00
#define WAKFIL_ENABLE    0x40
#define WAKFIL_DISABLE    0x00


// CANINTF Register Bits

#define MCP_RX0IF        0x01
#define MCP_RX1IF        0x02
#define MCP_TX0IF        0x04
#define MCP_TX1IF        0x08
#define MCP_TX2IF        0x10
#define MCP_ERRIF        0x20
#define MCP_WAKIF        0x40
#define MCP_MERRF        0x80



#endif
/**********************************************************************/
/*                                                                    */
/* File name: drv_mcp2515.c                                           */
/*                                                                    */
/* Since:     2005-Nov-30                                             */
/*                                                                    */
/* Version:   PICos18 v2.04                                           */
/*            Copyright (C) 2003, 2004, 2005 Pragmatec.               */
/*            MCP2515 CAN driver v1.00                                */
/*                                                                    */
/* Author:    Designed by Pragmatec S.A.R.L.        www.pragmatec.net */
/*            ROZIER Bertrand [RZR]     bertrand.rozier@pragmatec.net */
/*                                                                    */
/* Purpose:   MCP2515 : SPI CAN controller management.                */
/*            It allows task tosend data at the send time through a   */
/*            dedicated FIFO, and to wait for a certain CAN frame.    */
/*                                                                    */
/* Distribution: This file is part of PICos18.                        */
/*            PICos18 is free software; you can redistribute it       */
/*            and/or modify it under the terms of the GNU General     */
/*            Public License as published by the Free Software        */
/*            Foundation; either version 2, or (at your option)       */
/*            any later version.                                      */
/*                                                                    */
/*            PICos18 is distributed in the hope that it will be      */
/*            useful, but WITHOUT ANY WARRANTY; without even the      */
/*            implied warranty of MERCHANTABILITY or FITNESS FOR A    */
/*            PARTICULAR PURPOSE.  See the GNU General Public         */
/*            License for more details.                               */
/*                                                                    */
/*            You should have received a copy of the GNU General      */
/*            Public License along with gpsim; see the file           */
/*            COPYING.txt. If not, write to the Free Software         */
/*            Foundation, 59 Temple Place - Suite 330,                */
/*            Boston, MA 02111-1307, USA.                             */
/*                                                                    */
/*          > A special exception to the GPL can be applied should    */
/*            you wish to distribute a combined work that includes    */
/*            PICos18, without being obliged to provide the source    */
/*            code for any proprietary components.                    */
/*                                                                    */
/* History:                                                           */
/* 2005/11/30 [RZR] Create this file                                  */
/**********************************************************************/

#include "define.h"
#include "drv_mcp2515.h"
#include "drv_spi.h"

#define MCP2515_CS_PORT       PORTC
#define MCP2515_CS_BIT            0

/**********************************************************************
 * Definition dedicated to the local functions.
 **********************************************************************/
void MCP2515_Init(void);
void MCP2515_Config(void);
void MCP2515_Reset(void);
void MCP2515_GetStatus(void);
void MCP2515_SetMode(unsigned char mode);
void MCP2515_BitModify(unsigned char addr, unsigned char mask, unsigned char data);
void MCP2515_ByteWrite(unsigned char addr, unsigned char data);
void MCP2515_ByteRead(unsigned char addr, unsigned char * pdata);
void MCP2515_RTS(unsigned char buffer_TX);
void MCP2515_ReadRXbuffer0(void);
void MCP2515_ReadRXbuffer1(void);
void ManageISR(void);

StatusType mcp2515_write_buffer(unsigned char registre, unsigned char *pdata);

EventMaskType       CAN_event;

CAN_message_tRef    CAN_list_head;            //    Start of message queue
CAN_message_tRef    CAN_current_message;    //    Current message
unsigned char        CAN_list_count = 0;        //    Number of items currently in queue

CAN_message_tRef    CAN_list_head_rcv;        //    Start of message queue
CAN_message_tRef    CAN_current_message_rcv;//    Current message
unsigned char        CAN_list_count_rcv = 0;    //    Number of items currently in queue

SPI_message_t       SPI_MCP2515;

TXBn_t                TXB0,TXB1,TXB2;
TXBn_tRef            pTXBn;
RXBn_t                RXB0,RXB1;
RXBn_tRef            pRXBn;

// Local mcp2515 control register
unsigned char     CANSTAT;
unsigned char     CANCTRL;
unsigned char     CNF1;
unsigned char     CNF2;
unsigned char     CNF3;
unsigned char     TXRTSCTRL;
unsigned char     CANINTE;
unsigned char     CANINTF;
unsigned char     EFLG;
unsigned char     RXB0CTRL;

unsigned char mcp2515_cmd[15];

// Fort debug only
#define ALARM_MCP2515      1

/**********************************************************************
 * Task of the CAN driver, waiting for any of these 4 events :
 *  CAN_TX_EVENT  : A message has been sent then a hardware transmitter
 *                  is free. The driver will tranfer a software buffer
 *                  into a free TX[0,1,2] hardware buffer.
 *  CAN_RX_EVENT  : A message is arrived in the RX[0,1] buffer.
 *                  the driver transfer the *§bjjcontent of the message into
 *                  a software buffer waiting for this message ID or
 *                  discard the message to free the hardware.
 *  CAN_ERR_EVENT : Something wrong appended and the driver must clean
 *                  the hardware before being disconnected. To be
 *                  completed...
 *  ALARM_EVENT   : Sometimes a task waiting for a specific message is
 *                  not fast enough to read all the content of the
 *                  hardware buffers. The driver have to keep available
 *                  this content the time needed by other tasks.
 *                  Then the driver periodicaly checks if the other tasks
 *                  have finished to read the hardware buffers or needs
 *                  more time.
 *
 * @param  void
 * @return void
 **********************************************************************/
TASK(MCP2515_Drv)
{

      MCP2515_Init();
    MCP2515_Config();

  // Just for cyclique update of CAN register
  // useful until on debug
  // SetRelAlarm(ALARM_MCP2515, 500, 500);

  while(1)
  {

    WaitEvent(CAN_NEW_MSG | CAN_RCV_MSG | CAN_ERR_MSG | MCP2515_IRQ_REQUEST | ALARM_EVENT);
    GetEvent(MCP2515_DRV_ID, &CAN_event);

    if (CAN_event & ALARM_EVENT)
    {
      ClearEvent(ALARM_EVENT);
      // Mainly for debug
      MCP2515_ByteRead(CAN2510_REG_CANINTF, &CANINTF);
      MCP2515_ByteRead(CAN2510_REG_EFLG, &EFLG);
       MCP2515_GetStatus();
       }

    if (CAN_event & CAN_NEW_MSG)
    {
      ClearEvent(CAN_NEW_MSG);
      CopyFrameBuffer2Hard();
    }

    if (CAN_event & CAN_RCV_MSG)
    {
      ClearEvent(CAN_RCV_MSG);
      CopyHard2FrameBuffer();
    }

    if (CAN_event & CAN_ERR_MSG)
    {
      ClearEvent(CAN_ERR_MSG);
    }

    if (CAN_event & MCP2515_IRQ_REQUEST)
    {
      ClearEvent(MCP2515_IRQ_REQUEST);
      // Get back the flag code
      MCP2515_ByteRead(CAN2510_REG_CANINTF, &CANINTF);
      MCP2515_ByteRead(CAN2510_REG_EFLG, &EFLG);
      MCP2515_GetStatus();

          if ( CANINTF & 0x01) // RXB0 full
        {
            // Clear the flag
            MCP2515_BitModify(CAN2510_REG_CANINTF, 0x01, 0x00);
            // Clear the local variable
            CANINTF &= 0xFE;
            // Get RX buffer
            MCP2515_ReadRXbuffer0();
            SetEvent(MCP2515_DRV_ID,CAN_RCV_MSG);
        }
        if ( CANINTF & 0x02) // RXB1 full
        {
            // Clear the flag
            MCP2515_BitModify(CAN2510_REG_CANINTF, 0x02, 0x00);
            // Clear the local variable
            CANINTF &= 0xFD;
            // Get RX buffer
            MCP2515_ReadRXbuffer1();
            SetEvent(MCP2515_DRV_ID,CAN_RCV_MSG);
        }
        if ( CANINTF & 0x04) // TXB0 full
            MCP2515_BitModify(CAN2510_REG_CANINTF, 0x04, 0x00);
        if ( CANINTF & 0x08) // TXB1 full
            MCP2515_BitModify(CAN2510_REG_CANINTF, 0x08, 0x00);
        if ( CANINTF & 0x10) // TXB2 full
            MCP2515_BitModify(CAN2510_REG_CANINTF, 0x10, 0x00);
        if ( CANINTF & 0x20) // Error
            MCP2515_BitModify(CAN2510_REG_CANINTF, 0x20, 0x00);
        if ( CANINTF & 0x40) // WAKEIF
            MCP2515_BitModify(CAN2510_REG_CANINTF, 0x40, 0x00);
        if ( CANINTF & 0x80) // message error
            MCP2515_BitModify(CAN2510_REG_CANINTF, 0x80, 0x00);
    }
  }
}



void MCP2515_Init(void)
{
    // define the CS pin
      // See the drv_spi.h and set the correct value
      SPI_MCP2515.CS_address = (ram char*)&MCP2515_CS_PORT;
      SPI_MCP2515.CS_bit = MCP2515_CS_BIT;

      // ID of the calling task
      GetTaskID (&SPI_MCP2515.CallerID);

    // Enable INT1 for MCP2515 interrupt
    ADCON1 = 0x0F;
    INTCON3bits.INT1IP = 0;
    INTCON2bits.INTEDG1 = 0;
    INTCON3bits.INT1IF = 0;
    INTCON3bits.INT1IE = 1;

    MCP2515_Reset();
    return;
}


void MCP2515_Config(void)
{
    // First: enter in configuration mode
    MCP2515_BitModify(CAN2510_REG_CANCTRL, 0xE0, 0x80);
    MCP2515_GetStatus();
    if ( (CANSTAT & 0xE0) != 0x80)
    {
        Nop(); // config error !
    }

    // bit timing configuration 125khz Q=10Mhz
    CNF1 = 0x41; // Synchro = 1 Tq et BRP = 1
    MCP2515_ByteWrite(CAN2510_REG_CNF1, CNF1);
    CNF2 = 0xac;
    MCP2515_ByteWrite(CAN2510_REG_CNF2, CNF2);
    CNF3 = 0x07;
    MCP2515_ByteWrite(CAN2510_REG_CNF3, CNF3);

    TXRTSCTRL = 0x00; // No IT pin or RTS pin
    MCP2515_ByteWrite(CAN2510_REG_TXRTSCTRL, TXRTSCTRL);
    // No filter and mask for this release

    CANINTE = 0xE3; // All interrupts enable without TX
    MCP2515_ByteWrite(CAN2510_REG_CANINTE, CANINTE);
    CANINTF = 0x00; // Clear interrupt flags
    MCP2515_ByteWrite(CAN2510_REG_CANINTF, CANINTF);

    #ifdef __LOOPBACK__
      MCP2515_BitModify(CAN2510_REG_CANCTRL, 0xE0, 0x40);
      #else
      MCP2515_BitModify(CAN2510_REG_CANCTRL, 0xE0, 0x00);
      #endif

    // Test
    MCP2515_ByteRead(CAN2510_REG_RXB0CTRL, &RXB0CTRL);

    /* Init the different FIFO */
      CAN_current_message = NULL;
      CAN_list_head       = NULL;
      CAN_list_head_rcv   = NULL;


    return;
}

void MCP2515_Reset(void)
{
    mcp2515_cmd[0] = CAN2510_CMD_RESET;
    // Address of the raw data to send
    SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
    SPI_MCP2515.SDO_num_bytes = 1;
    SPI_MCP2515.SDI_num_bytes = 0;
      // Place the message in the SPI driver queue
      SPI_enqMsg(&SPI_MCP2515);
      SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
      // Wait for the end of operation
      WaitEvent(SPI_QUEUE_EMPTY);
      ClearEvent(SPI_QUEUE_EMPTY);
}

void MCP2515_GetStatus(void)
{
    mcp2515_cmd[0] = CAN2510_CMD_READ;
    mcp2515_cmd[1] = CAN2510_REG_CANSTAT;
    // It is not necessary to send instruction
    // Address of the raw data to send
    SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
      // Length of the message to send ( 0 = no SDO)
    SPI_MCP2515.SDO_num_bytes = 2;

    // Address of the raw data to receive
      SPI_MCP2515.SDI_ram_data = &CANSTAT;
      SPI_MCP2515.SDI_num_bytes = 1;
      //SPI_MCP2515.instruction = CAN2510_CMD_READ;

      // Place the message in the SPI driver queue
      SPI_enqMsg(&SPI_MCP2515);
      SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
      // Wait for the end of operation
      WaitEvent(SPI_QUEUE_EMPTY);
      ClearEvent(SPI_QUEUE_EMPTY);
}

void MCP2515_BitModify(unsigned char addr, unsigned char mask, unsigned char data)
{
    mcp2515_cmd[0] = CAN2510_CMD_BITMOD;
    mcp2515_cmd[1] = addr;
    mcp2515_cmd[2] = mask;
    mcp2515_cmd[3] = data;

    // It is not necessary to send instruction
    // Address of the raw data to send
      SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
      // Length of the message to send ( 0 = no SDO)
    SPI_MCP2515.SDO_num_bytes = 4;

      SPI_MCP2515.SDI_num_bytes = 0;

      // Place the message in the SPI driver queue
      SPI_enqMsg(&SPI_MCP2515);
      SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
      // Wait for the end of operation
      WaitEvent(SPI_QUEUE_EMPTY);
      ClearEvent(SPI_QUEUE_EMPTY);
}


void MCP2515_ByteWrite(unsigned char addr, unsigned char data)
{
    mcp2515_cmd[0] = CAN2510_CMD_WRITE;
    mcp2515_cmd[1] = addr;
    mcp2515_cmd[2] = data;

    // Address of the raw data to send
    SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
    // Length of the message to send ( 0 = no SDO)
      SPI_MCP2515.SDO_num_bytes = 3;
      SPI_MCP2515.SDI_num_bytes = 0;

      // Place the message in the SPI driver queue
      SPI_enqMsg(&SPI_MCP2515);
      SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
      // Wait for the end of operation
      WaitEvent(SPI_QUEUE_EMPTY);
      ClearEvent(SPI_QUEUE_EMPTY);
}

void MCP2515_ByteRead(unsigned char addr, unsigned char* pdata)
{
    mcp2515_cmd[0] = CAN2510_CMD_READ;
    mcp2515_cmd[1] = addr;

    // Address of the raw data to send
    SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
      // Length of the message to send ( 0 = no SDO)
    SPI_MCP2515.SDO_num_bytes = 2;
    SPI_MCP2515.SDI_ram_data = pdata;
      SPI_MCP2515.SDI_num_bytes = 1;

      // Place the message in the SPI driver queue
      SPI_enqMsg(&SPI_MCP2515);
      SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
      // Wait for the end of operation
      WaitEvent(SPI_QUEUE_EMPTY);
      ClearEvent(SPI_QUEUE_EMPTY);
}

void MCP2515_RTS(unsigned char buffer_TX)
{
    mcp2515_cmd[0] = CAN2510_CMD_RTS | buffer_TX;

    // Address of the raw data to send
    SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
      // Length of the message to send ( 0 = no SDO)
    SPI_MCP2515.SDO_num_bytes = 1;
      SPI_MCP2515.SDI_num_bytes = 0;

      // Place the message in the SPI driver queue
      SPI_enqMsg(&SPI_MCP2515);
      SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
      // Wait for the end of operation
      WaitEvent(SPI_QUEUE_EMPTY);
      ClearEvent(SPI_QUEUE_EMPTY);
}

void MCP2515_LoadTXbuffer0(void)
{
    unsigned char i;
    unsigned char *pst;

    pst = (unsigned char*)&TXB0;
    mcp2515_cmd[0] = 0x40; // TXB0 0x31
    for (i=1;i<14;i++)
    {
        mcp2515_cmd[i]= *pst;
        pst++;
    }

    // Length of the message to send ( 0 = no SDO)
    SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
      SPI_MCP2515.SDO_num_bytes = 14;
      SPI_MCP2515.SDI_num_bytes = 0;

      // Place the message in the SPI driver queue
      SPI_enqMsg(&SPI_MCP2515);
      SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
      // Wait for the end of operation
      WaitEvent(SPI_QUEUE_EMPTY);
      ClearEvent(SPI_QUEUE_EMPTY);
}

void MCP2515_ReadRXbuffer0(void)
{
    mcp2515_cmd[0] = 0x90; // Adress -> 0x61
    SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
    // Length of the message to send ( 0 = no SDO)
      SPI_MCP2515.SDO_num_bytes = 1;

    // Address of the raw data to receive
    SPI_MCP2515.SDI_ram_data = (unsigned char*)&RXB0;
      SPI_MCP2515.SDI_num_bytes = 13;

      // Place the message in the SPI driver queue
      SPI_enqMsg(&SPI_MCP2515);
      SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
      // Wait for the end of operation
      WaitEvent(SPI_QUEUE_EMPTY);
      ClearEvent(SPI_QUEUE_EMPTY);
}

void MCP2515_ReadRXbuffer1(void)
{
    mcp2515_cmd[0] = 0x94; // Adress -> 0x71
    SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
    // Length of the message to send ( 0 = no SDO)
      SPI_MCP2515.SDO_num_bytes = 1;

    // Address of the raw data to receive
    SPI_MCP2515.SDI_ram_data = (unsigned char*)&RXB0;
      SPI_MCP2515.SDI_num_bytes = 13;

      // Place the message in the SPI driver queue
      SPI_enqMsg(&SPI_MCP2515);
      SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
      // Wait for the end of operation
      WaitEvent(SPI_QUEUE_EMPTY);
      ClearEvent(SPI_QUEUE_EMPTY);
}


/**********************************************************************
 * Parse the entier TX message list to find any message to transfer.
 * Once a such message is found we post an event to the sending task
 * to tell the transfer is started and we break.
 * The event is used if the task want to send as fast as possible a
 * set of message. Doing so the task will be able to send a new message
 * every time a TASK_CAN_TX_EVENT event is received.
 *
 * @param  type    IN Number of the hardware buffer
 * @return Status     E_OK if tranfer initiated
 *                    E_OS_STATE otherwise
 **********************************************************************/
StatusType CopyFrameBuffer2Hard(void)
{
  StatusType returned_type;
  unsigned char foo;
  returned_type = E_OS_STATE;

  CAN_current_message = CAN_deqMsg();

  if (CAN_current_message == NULL)
    return(returned_type);

  #ifdef __EXT29BITS__
  TXB0.TXBnEID0 = CAN_current_message->CANID;
  TXB0.TXBnEID8 = CAN_current_message->CANID >> 8;
  TXB0.TXBnSIDL = (CAN_current_message->CANID >> 16) & 0x03;
  foo      = (CAN_current_message->CANID >> 13) & 0xE0;
  foo      = foo | 0x08;
  TXB0.TXBnSIDL = TXB0.TXBnSIDL + foo;
  TXB0.TXBnSIDH = CAN_current_message->CANID >> 21;
  #else
   #ifdef  __STD11BITS__
    TXB0.TXBnSIDL = CAN_current_message->CANID << 5;
    TXB0.TXBnSIDH = CAN_current_message->CANID >> 3;
   #else
    #error "you should define 11 or 29 bits for CANID !"
   #endif
  #endif
  TXB0.TXBnDLC  = CAN_current_message->length & 0x0F;
  TXB0.TXBnD0   = CAN_current_message->data[0];
  TXB0.TXBnD1   = CAN_current_message->data[1];
  TXB0.TXBnD2   = CAN_current_message->data[2];
  TXB0.TXBnD3   = CAN_current_message->data[3];
  TXB0.TXBnD4   = CAN_current_message->data[4];
  TXB0.TXBnD5   = CAN_current_message->data[5];
  TXB0.TXBnD6   = CAN_current_message->data[6];
  TXB0.TXBnD7   = CAN_current_message->data[7];
  CAN_current_message->state = CAN_MSG_SENT;

    // MCP2551 TX_buffer0 update
      MCP2515_LoadTXbuffer0();

    // Send the buffer0 transmit command
    MCP2515_RTS(0x01); // 1st buffer -> buffer0

    SetEvent(CAN_current_message->CallerID, CAN_QUEUE_EMPTY);
  //RXB0CONbits.RXRTRRO = 1;
  returned_type = E_OK;

  return(returned_type);
}

/**********************************************************************
 *    Enqueue a client packet object into the RS task queue.
 *
 *    Once placed in queue, client must not modify the data
 *    otherwise unpredictable results. To safely change the object,
 *    dequeue, modify, re-enqueue.
 *
 *  The code in mainly executed in critical region [SuspendAllInterrupt]
 *  because many tasks can call this function at the same time and break
 *  the FIFO list.
 *
 *    Returns 1 if successfull, 0 if message could not be enqueued
 **********************************************************************/
StatusType CAN_enqMsg(CAN_message_tRef toEnqueue)
{
  CAN_message_tRef CAN_list_itor;

  if (toEnqueue != NULL)
  {
    SuspendOSInterrupts();
    if (CAN_list_head == NULL)
      CAN_list_head = toEnqueue;
    else
    {
      CAN_list_itor = CAN_list_head;
      while (CAN_list_itor->next != NULL)
        CAN_list_itor = CAN_list_itor->next;
      CAN_list_itor->next = toEnqueue;
    }
    toEnqueue->next     = NULL;
    toEnqueue->CallerID = id_tsk_run;
    toEnqueue->state    = CAN_FULL;
    CAN_list_count++;
    ResumeOSInterrupts();
    return E_OK;
  }
  else
    return E_OS_STATE;
}

/**********************************************************************
 *    Dequeue a client message from the RS task queue.
 *
 *
 *********************************************************************/
CAN_message_tRef CAN_deqMsg(void)
{
  CAN_message_tRef CAN_list_itor;

  SuspendOSInterrupts();
  CAN_list_itor = NULL;
  if (CAN_list_head != NULL)
  {
    CAN_list_itor = CAN_list_head;
    CAN_list_head = CAN_list_head->next;
    CAN_list_count--;
  }
  ResumeOSInterrupts();
  return CAN_list_itor;
}

/**********************************************************************
 *    Enqueue a client packet object into the RS task queue.
 *
 *    Once placed in queue, client must not modify the data
 *    otherwise unpredictable results. To safely change the object,
 *    dequeue, modify, re-enqueue.
 *
 *  The code in mainly executed in critical region [SuspendAllInterrupt]
 *  because many tasks can call this function at the same time and break
 *  the FIFO list.
 *
 *    Returns 1 if successfull, 0 if message could not be enqueued
 **********************************************************************/
StatusType CAN_RCV_Register(CAN_message_tRef toEnqueue)
{
  CAN_message_tRef CAN_list_itor;

  if (toEnqueue != NULL)
  {
    SuspendOSInterrupts();
    if (CAN_list_head_rcv == NULL)
      CAN_list_head_rcv = toEnqueue;
    else
    {
      CAN_list_itor = CAN_list_head_rcv;
      while (CAN_list_itor->next != NULL)
        CAN_list_itor = CAN_list_itor->next;
      CAN_list_itor->next = toEnqueue;
    }
    toEnqueue->next     = NULL;
    toEnqueue->CallerID = id_tsk_run;
    CAN_list_count_rcv++;
    ResumeOSInterrupts();
    return E_OK;
  }
  else
    return E_OS_STATE;
}

/**********************************************************************
 * Parse the entier RX message list to find any task waiting for the
 * received message ID.
 * Once a such taks is found we post an event to the waiting task
 * to tell its software buffer is full and we break.
 * The event is used if the task want to wait for a particular message
 * ID without overloading the CPU by a pooling method.
 *
 * @param  type    IN Number of the hardware buffer
 * @return Status     E_OK if tranfer initiated
 *                    E_OS_STATE otherwise
 **********************************************************************/
StatusType CopyHard2FrameBuffer(void)
{
  StatusType returned_type;
  unsigned long ID_received;
  CAN_message_tRef CAN_list_itor;

  returned_type = E_OK;

  if (CAN_list_head_rcv != NULL)
  {
    CAN_list_itor = CAN_list_head_rcv;
    do
    {
      #ifdef __NOFILTER__
      if (1)
      #else
      #ifdef __EXT29BITS__
      ID_received  = 0;
      ID_received += (unsigned long)(RXB0.RXBnEID0);
      ID_received += (unsigned long)(RXB0.RXBnEID8) << 8;
      ID_received += (unsigned long)(RXB0.RXBnSIDL & 0x03) << 16;
      ID_received += (unsigned long)(RXB0.RXBnSIDL & 0xE0) << 13;
      ID_received += (unsigned long)(RXB0.RXBnSIDH & 0xFF) << 21;
      #else
       #ifdef  __STD11BITS__
        ID_received  = 0;
        ID_received += (unsigned long)(RXB0.RXBnSIDL) >> 5;
        ID_received += (unsigned long)(RXB0.RXBnSIDH) << 3;
       #else
        #error "you should define 11 or 29 bits for CANID !"
       #endif
      #endif
      if (CAN_list_itor->CANID == ID_received)
      #endif
      {
        if (CAN_list_itor->state == CAN_FREE)
        {
          CAN_list_itor->data[0] = RXB0.RXBnD0;
          CAN_list_itor->data[1] = RXB0.RXBnD1;
          CAN_list_itor->data[2] = RXB0.RXBnD2;
          CAN_list_itor->data[3] = RXB0.RXBnD3;
          CAN_list_itor->data[4] = RXB0.RXBnD4;
          CAN_list_itor->data[5] = RXB0.RXBnD5;
          CAN_list_itor->data[6] = RXB0.RXBnD6;
          CAN_list_itor->data[7] = RXB0.RXBnD7;
          CAN_list_itor->length  = RXB0.RXBnDLC & 0x0F;
          CAN_list_itor->state   = CAN_FULL;
          SetEvent(CAN_list_itor->CallerID, CAN_QUEUE_FULL);
        }
        else
          returned_type = E_OS_STATE;
      }
      CAN_list_itor = CAN_list_itor->next;
    }
    while (CAN_list_itor != NULL);
  }

  return(returned_type);
}

/**********************************************************************
 * ISR of the CAN driver.
 *
 * For each interrupt we disable the IE first to avoid any infinite loop
 * and we clear the IF in the dedicated function (Read or Write CAN mess).
 * Indeed we have to clear the IT when the message has been properly
 * accessed and is no more used. The IF lets the peripheral accept a new
 * message.
 * If 3 frames arrive at the same time, the two first are stored in the
 * RCV buffers and the third is discarded (temporary overload bus).
 *
 * @return void
 **********************************************************************/
void MCP2551_INT(void)
{
    INTCON3bits.INT1IF = 0;
    // Send a request to the driver
    SetEvent(MCP2515_DRV_ID,MCP2515_IRQ_REQUEST);
}

/* End of File : drv_mcp2515.c */
/**********************************************************************/
/*                                                                    */
/* File name: drv_mcp2515.h                                           */
/*                                                                    */
/* Since:     2005-Nov-30                                             */
/*                                                                    */
/* Version:   PICos18 v2.04                                           */
/*            Copyright (C) 2003, 2004, 2005 Pragmatec.               */
/*            MCP2515 CAN driver v1.00                                */
/*                                                                    */
/* Author:    Designed by Pragmatec S.A.R.L.        www.pragmatec.net */
/*            ROZIER Bertrand [RZR]      bertrand.rozier@pragmatec.net*/
/*                                                                    */
/* Purpose:   MCP2515 : SPI CAN controller management.                */
/*            It allows task to send data at the same time through a  */
/*            dedicated FIFO, and to wait for a certain CAN frame.    */
/*                                                                    */
/* Distribution: This file is part of PICos18.                        */
/*            PICos18 is free software; you can redistribute it       */
/*            and/or modify it under the terms of the GNU General     */
/*            Public License as published by the Free Software        */
/*            Foundation; either version 2, or (at your option)       */
/*            any later version.                                      */
/*                                                                    */
/*            PICos18 is distributed in the hope that it will be      */
/*            useful, but WITHOUT ANY WARRANTY; without even the      */
/*            implied warranty of MERCHANTABILITY or FITNESS FOR A    */
/*            PARTICULAR PURPOSE.  See the GNU General Public         */
/*            License for more details.                               */
/*                                                                    */
/*            You should have received a copy of the GNU General      */
/*            Public License along with gpsim; see the file           */
/*            COPYING.txt. If not, write to the Free Software         */
/*            Foundation, 59 Temple Place - Suite 330,                */
/*            Boston, MA 02111-1307, USA.                             */
/*                                                                    */
/*          > A special exception to the GPL can be applied should    */
/*            you wish to distribute a combined work that includes    */
/*            PICos18, without being obliged to provide the source    */
/*            code for any proprietary components.                    */
/*                                                                    */
/* History:                                                           */
/* 2005/11/30 [RZR] Create this file.                                 */
/*                                                                    */
/**********************************************************************/


#ifndef _MCP2515_DRV_H_
#define _MCP2515_DRV_H_

#include "pro_man.h"
#include "even_man.h"
#include "alarm.h"


/*****************************************************
 * Definition dedicated to the local functions.
 ****************************************************/
#define CAN_MSG_SENT        0x02
#define CAN_FREE            0x00
#define CAN_FULL            0x01
#define CAN_EMPTY           0x00
#define TRUE                0x01
#define FALSE               0x00
#define TX_MESSAGE          0x01
#define RX_MESSAGE          0x00

#define TXB0_REG            0x30
#define TXB1_REG            0x40
#define TXB2_REG            0x50
#define RXB0_REG            0x60
#define RXB1_REG            0x70

struct _CAN_frame {
   unsigned long CANID;
   unsigned char length;
   unsigned char data[8];
   unsigned char CallerID;
   unsigned char state;
   struct _CAN_frame *next;
};
typedef struct _CAN_frame CAN_message_t, *CAN_message_tRef;

struct _TX_buffer {
//    unsigned char TXBnCTRL;
    unsigned char TXBnSIDH;
    unsigned char TXBnSIDL;
    unsigned char TXBnEID8;
    unsigned char TXBnEID0;
    unsigned char TXBnDLC;
    unsigned char TXBnD0;
    unsigned char TXBnD1;
    unsigned char TXBnD2;
    unsigned char TXBnD3;
    unsigned char TXBnD4;
    unsigned char TXBnD5;
    unsigned char TXBnD6;
    unsigned char TXBnD7;
};
typedef struct _TX_buffer TXBn_t, *TXBn_tRef;

struct _RX_buffer {
//    unsigned char RXBnCTRL;
    unsigned char RXBnSIDH; //0x61
    unsigned char RXBnSIDL;
    unsigned char RXBnEID8;
    unsigned char RXBnEID0;
    unsigned char RXBnDLC;
    unsigned char RXBnD0;
    unsigned char RXBnD1;
    unsigned char RXBnD2;
    unsigned char RXBnD3;
    unsigned char RXBnD4;
    unsigned char RXBnD5;
    unsigned char RXBnD6;
    unsigned char RXBnD7;

};
typedef struct _RX_buffer RXBn_t, *RXBn_tRef;


#define          CAN_freeMsg(x)        x.state = CAN_FREE;

StatusType       CAN_enqMsg(CAN_message_tRef toEnqueue);
CAN_message_tRef CAN_deqMsg(void);
StatusType       CopyHard2FrameBuffer(void);
StatusType       CopyFrameBuffer2Hard(void);
StatusType       CAN_RCV_Register(CAN_message_tRef toEnqueue);
void             CAN_config(void);


// CAN configuration registers
#define CAN2510_REG_BFPCTRL    0x0C
#define CAN2510_REG_TXRTSCTRL  0x0D
#define CAN2510_REG_CANSTAT    0x0E // Repeated every 16 locations (1E, 2E, ...)
#define CAN2510_REG_CANCTRL    0x0F // Repeated every 16 locations (1F, 2F, ...)

#define CAN2510_REG_TEC        0x1C
#define CAN2510_REG_REC        0x1D

#define CAN2510_REG_CNF3       0x28
#define CAN2510_REG_CNF2       0x29
#define CAN2510_REG_CNF1       0x2A
#define CAN2510_REG_CANINTE    0x2B
#define CAN2510_REG_CANINTF    0x2C
#define CAN2510_REG_EFLG       0x2D



// CAN Receive Mask/Filter registers
#define CAN2510_REG_RXM0SIDH   0x20
#define CAN2510_REG_RXM0SIDL   0x21
#define CAN2510_REG_RXM0EID8   0x22
#define CAN2510_REG_RXM0EID0   0x23
#define CAN2510_REG_RXM1SIDH   0x24
#define CAN2510_REG_RXM1SIDL   0x25
#define CAN2510_REG_RXM1EID8   0x26
#define CAN2510_REG_RXM1EID0   0x27
#define CAN2510_REG_RXF0SIDH   0x00
#define CAN2510_REG_RXF0SIDL   0x01
#define CAN2510_REG_RXF0EID8   0x02
#define CAN2510_REG_RXF0EID0   0x03
#define CAN2510_REG_RXF1SIDH   0x04
#define CAN2510_REG_RXF1SIDL   0x05
#define CAN2510_REG_RXF1EID8   0x06
#define CAN2510_REG_RXF1EID0   0x07
#define CAN2510_REG_RXF2SIDH   0x08
#define CAN2510_REG_RXF2SIDL   0x09
#define CAN2510_REG_RXF2EID8   0x0A
#define CAN2510_REG_RXF2EID0   0x0B
#define CAN2510_REG_RXF3SIDH   0x10
#define CAN2510_REG_RXF3SIDL   0x11
#define CAN2510_REG_RXF3EID8   0x12
#define CAN2510_REG_RXF3EID0   0x13
#define CAN2510_REG_RXF4SIDH   0x14
#define CAN2510_REG_RXF4SIDL   0x15
#define CAN2510_REG_RXF4EID8   0x16
#define CAN2510_REG_RXF4EID0   0x17
#define CAN2510_REG_RXF5SIDH   0x18
#define CAN2510_REG_RXF5SIDL   0x19
#define CAN2510_REG_RXF5EID8   0x1A
#define CAN2510_REG_RXF5EID0   0x1B

// CAN Transmit Control/Header/Data registers
#define CAN2510_REG_TXB0CTRL   0x30
#define CAN2510_REG_TXB0SIDH   0x31
#define CAN2510_REG_TXB0SIDL   0x32
#define CAN2510_REG_TXB0EID8   0x33
#define CAN2510_REG_TXB0EID0   0x34
#define CAN2510_REG_TXB0DLC    0x35
#define CAN2510_REG_TXB0D0     0x36
#define CAN2510_REG_TXB0D1     0x37
#define CAN2510_REG_TXB0D2     0x38
#define CAN2510_REG_TXB0D3     0x39
#define CAN2510_REG_TXB0D4     0x3A
#define CAN2510_REG_TXB0D5     0x3B
#define CAN2510_REG_TXB0D6     0x3C
#define CAN2510_REG_TXB0D7     0x3D

#define CAN2510_REG_TXB1CTRL   0x40
#define CAN2510_REG_TXB1SIDH   0x41
#define CAN2510_REG_TXB1SIDL   0x42
#define CAN2510_REG_TXB1EID8   0x43
#define CAN2510_REG_TXB1EID0   0x44
#define CAN2510_REG_TXB1DLC    0x45
#define CAN2510_REG_TXB1D0     0x46
#define CAN2510_REG_TXB1D1     0x47
#define CAN2510_REG_TXB1D2     0x48
#define CAN2510_REG_TXB1D3     0x49
#define CAN2510_REG_TXB1D4     0x4A
#define CAN2510_REG_TXB1D5     0x4B
#define CAN2510_REG_TXB1D6     0x4C
#define CAN2510_REG_TXB1D7     0x4D

#define CAN2510_REG_TXB2CTRL   0x50
#define CAN2510_REG_TXB2SIDH   0x51
#define CAN2510_REG_TXB2SIDL   0x52
#define CAN2510_REG_TXB2EID8   0x53
#define CAN2510_REG_TXB2EID0   0x54
#define CAN2510_REG_TXB2DLC    0x55
#define CAN2510_REG_TXB2D0     0x56
#define CAN2510_REG_TXB2D1     0x57
#define CAN2510_REG_TXB2D2     0x58
#define CAN2510_REG_TXB2D3     0x59
#define CAN2510_REG_TXB2D4     0x5A
#define CAN2510_REG_TXB2D5     0x5B
#define CAN2510_REG_TXB2D6     0x5C
#define CAN2510_REG_TXB2D7     0x5D

// CAN Transmit Control/Header/Data registers
#define CAN2510_REG_RXB0CTRL   0x60
#define CAN2510_REG_RXB0SIDH   0x61
#define CAN2510_REG_RXB0SIDL   0x62
#define CAN2510_REG_RXB0EID8   0x63
#define CAN2510_REG_RXB0EID0   0x64
#define CAN2510_REG_RXB0DLC    0x65
#define CAN2510_REG_RXB0D0     0x66
#define CAN2510_REG_RXB0D1     0x67
#define CAN2510_REG_RXB0D2     0x68
#define CAN2510_REG_RXB0D3     0x69
#define CAN2510_REG_RXB0D4     0x6A
#define CAN2510_REG_RXB0D5     0x6B
#define CAN2510_REG_RXB0D6     0x6C
#define CAN2510_REG_RXB0D7     0x6D

#define CAN2510_REG_RXB1CTRL   0x70
#define CAN2510_REG_RXB1SIDH   0x71
#define CAN2510_REG_RXB1SIDL   0x72
#define CAN2510_REG_RXB1EID8   0x73
#define CAN2510_REG_RXB1EID0   0x74
#define CAN2510_REG_RXB1DLC    0x75
#define CAN2510_REG_RXB1D0     0x76
#define CAN2510_REG_RXB1D1     0x77
#define CAN2510_REG_RXB1D2     0x78
#define CAN2510_REG_RXB1D3     0x79
#define CAN2510_REG_RXB1D4     0x7A
#define CAN2510_REG_RXB1D5     0x7B
#define CAN2510_REG_RXB1D6     0x7C
#define CAN2510_REG_RXB1D7     0x7D

#define CAN2510_CMD_RESET      0xC0
#define CAN2510_CMD_WRITE      0x02
#define CAN2510_CMD_READ       0x03
#define CAN2510_CMD_RTS        0x80
#define CAN2510_CMD_BITMOD     0x05
#define CAN2510_CMD_STATUS     0xA0


// Define for RTS ( Request to send)
#define TX_B0                  0x01
#define TX_B1                  0x02
#define TX_B2                  0x04

#endif /* _MCP2515_DRV_H_ */

/* End of File : drv_mcp2515.h */
原文地址:https://www.cnblogs.com/shangdawei/p/4538915.html