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 = ; // 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 = ; // 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[]; // 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()
{ 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 = ;
INTCON2bits.INTEDG1 = ;
INTCON3bits.INT1IF = ;
INTCON3bits.INT1IE = ; 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[] = CAN2510_CMD_RESET;
// Address of the raw data to send
SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[];
SPI_MCP2515.SDO_num_bytes = ;
SPI_MCP2515.SDI_num_bytes = ;
// 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[] = CAN2510_CMD_READ;
mcp2515_cmd[] = CAN2510_REG_CANSTAT;
// It is not necessary to send instruction
// Address of the raw data to send
SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[];
// Length of the message to send ( 0 = no SDO)
SPI_MCP2515.SDO_num_bytes = ; // Address of the raw data to receive
SPI_MCP2515.SDI_ram_data = &CANSTAT;
SPI_MCP2515.SDI_num_bytes = ;
//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[] = CAN2510_CMD_BITMOD;
mcp2515_cmd[] = addr;
mcp2515_cmd[] = mask;
mcp2515_cmd[] = data; // It is not necessary to send instruction
// Address of the raw data to send
SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[];
// Length of the message to send ( 0 = no SDO)
SPI_MCP2515.SDO_num_bytes = ; SPI_MCP2515.SDI_num_bytes = ; // 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[] = CAN2510_CMD_WRITE;
mcp2515_cmd[] = addr;
mcp2515_cmd[] = data; // Address of the raw data to send
SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[];
// Length of the message to send ( 0 = no SDO)
SPI_MCP2515.SDO_num_bytes = ;
SPI_MCP2515.SDI_num_bytes = ; // 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[] = CAN2510_CMD_READ;
mcp2515_cmd[] = addr; // Address of the raw data to send
SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[];
// Length of the message to send ( 0 = no SDO)
SPI_MCP2515.SDO_num_bytes = ;
SPI_MCP2515.SDI_ram_data = pdata;
SPI_MCP2515.SDI_num_bytes = ; // 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[] = CAN2510_CMD_RTS | buffer_TX; // Address of the raw data to send
SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[];
// Length of the message to send ( 0 = no SDO)
SPI_MCP2515.SDO_num_bytes = ;
SPI_MCP2515.SDI_num_bytes = ; // 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[] = 0x40; // TXB0 0x31
for (i=;i<;i++)
{
mcp2515_cmd[i]= *pst;
pst++;
} // Length of the message to send ( 0 = no SDO)
SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[];
SPI_MCP2515.SDO_num_bytes = ;
SPI_MCP2515.SDI_num_bytes = ; // 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[] = 0x90; // Adress -> 0x61
SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[];
// Length of the message to send ( 0 = no SDO)
SPI_MCP2515.SDO_num_bytes = ; // Address of the raw data to receive
SPI_MCP2515.SDI_ram_data = (unsigned char*)&RXB0;
SPI_MCP2515.SDI_num_bytes = ; // 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[] = 0x94; // Adress -> 0x71
SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[];
// Length of the message to send ( 0 = no SDO)
SPI_MCP2515.SDO_num_bytes = ; // Address of the raw data to receive
SPI_MCP2515.SDI_ram_data = (unsigned char*)&RXB0;
SPI_MCP2515.SDI_num_bytes = ; // 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 >> ;
TXB0.TXBnSIDL = (CAN_current_message->CANID >> ) & 0x03;
foo = (CAN_current_message->CANID >> ) & 0xE0;
foo = foo | 0x08;
TXB0.TXBnSIDL = TXB0.TXBnSIDL + foo;
TXB0.TXBnSIDH = CAN_current_message->CANID >> ;
#else
#ifdef __STD11BITS__
TXB0.TXBnSIDL = CAN_current_message->CANID << ;
TXB0.TXBnSIDH = CAN_current_message->CANID >> ;
#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[];
TXB0.TXBnD1 = CAN_current_message->data[];
TXB0.TXBnD2 = CAN_current_message->data[];
TXB0.TXBnD3 = CAN_current_message->data[];
TXB0.TXBnD4 = CAN_current_message->data[];
TXB0.TXBnD5 = CAN_current_message->data[];
TXB0.TXBnD6 = CAN_current_message->data[];
TXB0.TXBnD7 = CAN_current_message->data[];
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 ()
#else
#ifdef __EXT29BITS__
ID_received = ;
ID_received += (unsigned long)(RXB0.RXBnEID0);
ID_received += (unsigned long)(RXB0.RXBnEID8) << ;
ID_received += (unsigned long)(RXB0.RXBnSIDL & 0x03) << ;
ID_received += (unsigned long)(RXB0.RXBnSIDL & 0xE0) << ;
ID_received += (unsigned long)(RXB0.RXBnSIDH & 0xFF) << ;
#else
#ifdef __STD11BITS__
ID_received = ;
ID_received += (unsigned long)(RXB0.RXBnSIDL) >> ;
ID_received += (unsigned long)(RXB0.RXBnSIDH) << ;
#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[] = RXB0.RXBnD0;
CAN_list_itor->data[] = RXB0.RXBnD1;
CAN_list_itor->data[] = RXB0.RXBnD2;
CAN_list_itor->data[] = RXB0.RXBnD3;
CAN_list_itor->data[] = RXB0.RXBnD4;
CAN_list_itor->data[] = RXB0.RXBnD5;
CAN_list_itor->data[] = RXB0.RXBnD6;
CAN_list_itor->data[] = 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 = ;
// 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[];
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 */
MCP2515 : SPI CAN controller management的更多相关文章
- imx6 生成 spi设备节点
开发板需要使用spi接口,但是spi接口被touch占用,使用event进行操作.所以需要更改配置,生成spi设备节点. 参考链接 https://community.nxp.com/thread/3 ...
- SPI相位跟极性介绍
[详解]SPI中的极性CPOL和相位CPHA是什么以及如何设置 2012-03-0214:34:10| 分类:单片机 | 标签: |字号大中小 订阅 版本:2011-08-15 作者:crif ...
- devicetree -- SPI
SPI (Serial Peripheral Interface) busses SPI busses can be described with a node for the SPI master ...
- Linux内核SPI支持概述
1. 什么是SPI? Serial Peripheral Interface是一种同步4线串口链路,用于连接传感器.内存和外设到微控制器.他是一种简单的事实标准,还不足以复杂到需要一份正式的规范.SP ...
- linux驱动基础系列--linux spi驱动框架分析
前言 主要是想对Linux 下spi驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.设备模型等也不进行详细说明原理.如果有任何错误地方,请指出,谢谢! spi ...
- Solid-state storage management
Solid-state storage management for a system, the management including establishing, externally to a ...
- windows7命令帮助大全
有关某个命令的详细信息,请键入 HELP 命令名ASSOC 显示或修改文件扩展名关联.ATTRIB 显示或更改文件属性.BREAK 设置或清除扩展式 CTRL+C 检查.BCDEDIT 设置启动数据库 ...
- 16061701(地图灯光编译Beast报错)
[目标] 地图灯光编译报错 [思路] 1 我自己测c2_cwd_rt 附件为当时log 2 ExampleGame\BeastCache\PersistentCache 3 重新删除掉BeastCac ...
- 12G服务器在BIOS中收集阵列卡日志(TTY日志)的方法
如果系统进不去.请参考如下方法收集日志. 请准备个U 盘,容量在8G以下(含8G),否则会识别不到. 图片参考,以描述为准 F2 enter BIOS option--> Enter the ...
随机推荐
- python基础-类的封装
封装:类中封装了公有属性和方法,对象封装了私有属性的值 class F1: def __init__(self,n): self.N=n print('F') class F2: def __init ...
- 回归模型效果评估系列2-MAE、MSE、RMSE、MAPE(MAPD)
MAE.MSE.RMSE.MAPE(MAPD)这些都是常见的回归预测评估指标,重温下它们的定义和区别以及优缺点吧 MAE(Mean Absolute Error) 平均绝对误差 ...
- Hexo命令无法找到 -问题修复
本人PC安装hexo按照官方npm方式下载: npm install -g hexo-cli 但是到了控制台,输入hexo总是无法找到该命令,提示:Command not Found!!!,无论git ...
- 调研助力4S店,解码困境谜团
关键词————4S店.汽车.销售.精准营销.闭环.用户满意度.精细化管理 一.背景 4S店是“四位一体”的汽车销售专卖店,包括了整车销售.零配件供应.售后服务.信息反馈四项功能. 信息化管理 精细化管 ...
- Maven使用—拷贝Maven依赖jar包到指定目录
https://blog.csdn.net/u013514928/article/details/77930183
- codis+redis 集群搭建管理
Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 (不支持的命令列表), 上层应用可以像使 ...
- 淘宝IP地址库API地址
淘宝IP地址库:http://ip.taobao.com/instructions.php 接口说明 1. 请求接口(GET): http://ip.taobao.com/service/getI ...
- 【知了堂学习笔记】java 底层容易忽略的知识点
1. java中的关键字 提到关键字,最主要的就是不能用关键字作为标识符,值得注意的有以下几点. ①其中goto与const在java中没有定义,但是也是关键字.这个基本用不到,但是应该有个认知. ② ...
- 【原创】MySQL常用脚本整理
#1.查看表容量空间 ) ) ) AS 'free_size(G)' FROM information_schema.tables WHERE TABLE_SCHEMA='test' AND TABL ...
- leetcode 入门第一题 4ms? 8ms? Two Sum
今天开启leetcode 入门第一题 题意很简单,就是一个数组中求取两数之和等于目标数的一对儿下标 1.暴力 n^2 两个for循环遍历 用时0.1s 开外 代码就不用写了 2.二分 nlogn 我们 ...