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 */