/* * CAN.c */ #include "can.h" #include "spi.h" #include "gpio.h" #include "board.h" #include "regs2515.h" #include "delay.h" #define PRIVATE static #define XMIT_TIMEOUT 100 //milli sec #define RemoteFrameId 0x01 #define R 82 // Dec ASCII /********************************************************************* * Function: void ClearMessages(UINT8* Msg) * * PreCondition: None * * Input: Pointer to array of UINT8. * * Output: None * * Side Effects: None * * Overview: This function clears the message content * * Note: None. * * Example: ClearMessages(msg); ********************************************************************/ void ClearMessages(UINT8* Msg) { Msg[0] = 0; Msg[1] = 0; Msg[2] = 0; Msg[3] = 0; Msg[4] = 0; Msg[5] = 0; Msg[6] = 0; Msg[7] = 0; } /********************************************************************* * Function: void Evk1100PrintDisp(UINT32* pIdentifier, UINT8* Msg, UINT8* pMsgSize) * * PreCondition: void config_dpi204(void) has to be run first * * Input: pIdentifier: Pointer to Identifier of UINT32 * Msg: Pointer to array of UINT8 * pMsgSize: Pointer to the size of the messaged of UINT8 * * Output: None * * Side Effects: None * * Overview: This function prints all eight message bytes, the identifier and the message size * * Note: None. * * Example: Evk1100PrintDisp(&Ident, msg, &mSize ); ********************************************************************/ void Evk1100PrintDisp(UINT32* pIdentifier, UINT8* Msg, UINT8* pMsgSize ) { dip204_set_cursor_position(1,1); dip204_printf_string("%x", Msg[0]); dip204_set_cursor_position(6,1); dip204_printf_string("%x", Msg[1]); dip204_set_cursor_position(11,1); dip204_printf_string("%x", Msg[2]); dip204_set_cursor_position(16,1); dip204_printf_string("%x", Msg[3]); dip204_set_cursor_position(1,2); dip204_printf_string("%x", Msg[4]); dip204_set_cursor_position(6,2); dip204_printf_string("%x", Msg[5]); dip204_set_cursor_position(11,2); dip204_printf_string("%x", Msg[6]); dip204_set_cursor_position(16,2); dip204_printf_string("%x", Msg[7]); dip204_set_cursor_position(1,3); dip204_printf_string("Id: "); dip204_set_cursor_position(4,3); dip204_printf_string("%x", *pIdentifier); dip204_set_cursor_position(13,3); dip204_printf_string("DLC:"); dip204_set_cursor_position(17,3); dip204_printf_string("%x", *pMsgSize); } /********************************************************************* * Function: void config_SPI_SPARE(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: This function setups the SPI spare port. This to be able to communicate with other devices, e.g. MCP2515 * * Note: None. * * Example: config_SPI_SPARE(); ********************************************************************/ void config_SPI_SPARE(void){ static const gpio_map_t SPARE_SPI_GPIO_MAP = { {SPARE_SPI_SCK_PIN, SPARE_SPI_SCK_FUNCTION }, // SPI Clock. {SPARE_SPI_MISO_PIN, SPARE_SPI_MISO_FUNCTION}, // MISO. {SPARE_SPI_MOSI_PIN, SPARE_SPI_MOSI_FUNCTION}, // MOSI. {SPARE_SPI_NPCS_PIN, SPARE_SPI_NPCS_FUNCTION} // Chip Select NPCS. }; spi_options_t spiOptions = { .reg = SPARE_SPI_NPCS, .baudrate = 1000000, .bits = 8, .spck_delay = 0, .trans_delay = 0, .stay_act = 0, .spi_mode = 0, .modfdis = 1 }; gpio_enable_module(SPARE_SPI_GPIO_MAP, sizeof(SPARE_SPI_GPIO_MAP) / sizeof(SPARE_SPI_GPIO_MAP[0])); spi_initMaster(SPARE_SPI,&spiOptions); spi_selectionMode(SPARE_SPI, 0, 0, 0); spi_selectChip(SPARE_SPI,0); spi_setupChipReg(SPARE_SPI, &spiOptions, FOSC0); spi_enable(SPARE_SPI); } /********************************************************************* * Function: void mASSERT_CS(unsigned char channel) * * PreCondition: void config_SPI_SPARE(void) has to run first * * Input: channel: channel of unsigned char * * Output: None * * Side Effects: None * * Overview: See the documentation for spi_selectchip in spi.h * * Note: spi.h has to be included. ********************************************************************/ void mASSERT_CS(unsigned char channel){ spi_selectChip(SPARE_SPI,channel); } /********************************************************************* * Function: void mDEASSERT_CS(unsigned char channel) * * PreCondition: void config_SPI_SPARE(void) has to run first * * Input: channel: channel of unsigned char * * Output: None * * Side Effects: None * * Overview: See the documentation for spi_unselectchip in spi.h * * Note: spi.h has to be included. ********************************************************************/ void mDEASSERT_CS(unsigned char channel){ spi_unselectChip(SPARE_SPI,channel); } /********************************************************************* * Function: PRIVATE UINT8 XferSPI_send( int Channel, UINT8 dat ) * * PreCondition: void config_SPI_SPARE(void) has to run first * * Input: channel: channel of type int * dat: data to send * * Output: None * * Side Effects: None * * Overview: Selects a slave in master variable peripheral select mode and writes * one data word to it. See the documentation for spi_write in spi.h * * Note: spi.h has to be included. ********************************************************************/ PRIVATE UINT8 XferSPI_send( int Channel, UINT8 dat ) { spi_write(SPARE_SPI, dat); return 0; } /********************************************************************* * Function: PRIVATE UINT8 XferSPI_receive( int Channel, UINT8 dat ) * * PreCondition: void config_SPI_SPARE(void) has to run first * * Input: channel: channel of type int * dat: data * * Output: None * * Side Effects: None * * Overview: See the documentation for spi_write and spi_read in spi.h * * Note: spi.h has to be included. ********************************************************************/ PRIVATE UINT8 XferSPI_receive( int Channel, UINT8 dat ) { unsigned short *spidatareadpointer_temp; unsigned short spidataread_temp; spidatareadpointer_temp=&spidataread_temp; spi_write(SPARE_SPI, DUMMY_BYTE); while(spi_readRegisterFullCheck(SPARE_SPI)==0){ asm("NOP;"); } spi_read(SPARE_SPI,spidatareadpointer_temp); return spidataread_temp; } /********************************************************************* * Function: void CANReset(int Channel) * * PreCondition: SPI initialization and configuration * * Input: channel: channel of type int * * Output: None * * Side Effects: None * * Overview: Sends a software reset commmand over spi port to MCP2515 chip * * Note: None. ********************************************************************/ void CANReset(int Channel) { mASSERT_CS(Channel); XferSPI_send(Channel, CAN_RESET); mDEASSERT_CS(Channel); } /********************************************************************* * Function: void CAN2515ByteWrite(int Channel, unsigned char addr, unsigned char value ) * * PreCondition: SPI initialization and configuration * * Input: channel: channel of type int * addr: address of type unsigned char * value: the value to be send to the address * * Output: None * * Side Effects: None * * Overview: This function is used for setting register values e.g. registers in the MCP2515 module * * Note: None. * * Example: CANReset(0) ********************************************************************/ void CAN2515ByteWrite(int Channel, unsigned char addr, unsigned char value ) { mASSERT_CS(Channel); XferSPI_send(Channel, CAN_WRITE); XferSPI_send(Channel, addr); XferSPI_send(Channel, value); mDEASSERT_CS(Channel); } /********************************************************************* * Function: PRIVATE UINT8 CAN2515ByteRead(int Channel, unsigned char addr) * * PreCondition: SPI initialization * * Input: channel: channel of type int * addr: address of type unsigned char * * Output: None * * Side Effects: None * * Overview: This function reads the value of a byte. It is used to read register values in e.g. the MCP2515 module * * Note: None. ********************************************************************/ PRIVATE UINT8 CAN2515ByteRead(int Channel, unsigned char addr) { unsigned char tempdata; mASSERT_CS(Channel); XferSPI_send(Channel, CAN_READ); XferSPI_send(Channel, addr); tempdata = XferSPI_receive(Channel,0); mDEASSERT_CS(Channel); return tempdata; } /********************************************************************* * Function: void CAN2515SetRXB0Filters(int Channel, UINT16 Mask0, UINT16* pFlt0_1 ) * * PreCondition: SPI port configured * * Input: Channel: SPI channel number, 1 based * Mask0: define identifier 11 bits that are must match. * pFlt0_1: Pointer to array of UINT16, 2 words, * ie. Filter 0 and Filer 1. Lower 11 bits are siginicant * 1 = Rcvd Idenifier bit must match filter bit * 0 = Don't care Rcvd identifier bit. * * Output: None * * Side Effects: None * * Overview: Initialize RXB0 mask and 2 filters. See MCP2515 datasheet for more information. * * Note: None. * * Example: CAN2515SetRXB0Filters(Channel, 0, Flt); ********************************************************************/ void CAN2515SetRXB0Filters(int Channel, UINT16 Mask0, UINT16* pFlt0_1 ) { CAN2515ByteWrite(Channel, RXM0SIDH, Mask0 >> 3); CAN2515ByteWrite(Channel, RXM0SIDL, Mask0 << 5); // Set two filters associated with RXB0 CAN2515ByteWrite(Channel, RXF0SIDH, *pFlt0_1 >> 3); CAN2515ByteWrite(Channel, RXF0SIDL, *pFlt0_1 << 5); pFlt0_1++; CAN2515ByteWrite(Channel, RXF1SIDH, *pFlt0_1 >> 3); CAN2515ByteWrite(Channel, RXF1SIDL, *pFlt0_1 << 5); } /********************************************************************* * Function: void CAN2515SetRXB1Filters(int Channel,UINT16 Mask0, UINT16* pFlt0_1 ) * * PreCondition: SPI port configured * * Input: Channel: SPI channel number, 1 based * Mask0: define identifier 11 bits that are must match. * pFlt2_5: Pointer to array of UINT16, 4 words, * ie. Filter 2 thru Filer 5. Lower 11 bits are siginicant. * 1 = Rcvd Idenifier bit must match filter bit * 0 = Don't care Rcvd identifier bit. * * Output: None * * Side Effects: None * * Overview: Initialize RXB1 mask and 4 filters. See MCP2515 datasheet for more information. * * Note: None. * * Example: CAN2515SetRXB1Filters(Channel, 0, &Flt[2]); ********************************************************************/ void CAN2515SetRXB1Filters(int Channel, UINT16 Mask1, UINT16* pFlt2_5 ) { CAN2515ByteWrite(Channel, RXM1SIDH, Mask1 >> 3); CAN2515ByteWrite(Channel, RXM1SIDL, Mask1 << 5); // Set Four filters associated with RXB1 CAN2515ByteWrite(Channel, RXF2SIDH, *pFlt2_5 >> 3); CAN2515ByteWrite(Channel, RXF2SIDL, (*pFlt2_5 << 5) |0x08 ); pFlt2_5++; CAN2515ByteWrite(Channel, RXF3SIDH, *pFlt2_5 >> 3); CAN2515ByteWrite(Channel, RXF2SIDL, (*pFlt2_5 << 5) |0x08 ); pFlt2_5++; CAN2515ByteWrite(Channel, RXF4SIDH, *pFlt2_5 >> 3); CAN2515ByteWrite(Channel, RXF2SIDL, (*pFlt2_5 << 5) |0x08 ); pFlt2_5++; CAN2515ByteWrite(Channel, RXF5SIDH, *pFlt2_5 >> 3); CAN2515ByteWrite(Channel, RXF2SIDL, (*pFlt2_5 << 5) |0x08 ); } /********************************************************************* * Function: PRIVATE UINT8 ReadStatus2515(int Channel) * * PreCondition: SPI port configured * * Input: Channel: SPI channel number, 1 based * * Output: None * * Side Effects: None * * Overview: Reads status from MCP2515 * * Note: None. ********************************************************************/ PRIVATE UINT8 ReadStatus2515(int Channel) { unsigned short *spidatareadpointer_temp; unsigned short spidataread_temp; spidatareadpointer_temp=&spidataread_temp; spi_selectChip(SPARE_SPI,0); spi_write(SPARE_SPI,CAN_RD_STATUS); spi_write(SPARE_SPI,DUMMY_BYTE); spi_read(SPARE_SPI,spidatareadpointer_temp); spi_unselectChip(SPARE_SPI,0); return spidataread_temp; } /********************************************************************* * Function: BOOL CANSendMsg( int Channel, UINT16 Identifier,UINT8* Msg, UINT8 MsgSize, int r ) * * PreCondition: CAN initialized * * Input: Channel: SPI channel number, 1 based * Identifier: 11bit or 29 bit data for identifier * Msg: Data bytes, 8 bytes max * MsgSize: number of data bytes * r: If user wants to send a remote frame or not * * Output: Return true if the message was successfuly transferred * to the CAN controller Tx buffer. * * Side Effects: None * * Overview: Application call this function to send a message to the CAN bus * * Note: None. * * Example: // Channel, Identifier (max 0x1fffffff (29 bits)), Message, Number of bytes, Remote frame R or 0 (no remote frame) // Standard id CANSendMsg( 0, 0x00, msg, 8, 0 );(no remote frame) CANSendMsg( 0, 0x00, msg, 8, R );(remote frame) // Extended id CANSendMsg( 0, 0x8ff, msg, 8, 0 );(no remote frame) CANSendMsg( 0, 0x8ff, msg, 8, R );(remote frame) ********************************************************************/ Bool CANSendMsg( int Channel, UINT32 IdentifierS, UINT8* MsgS, UINT8 MsgSizeS, int r ) { int WaitCntr = 0; // wait for TXB0 to get ready. If not ready within XMIT_TIMEOUT ms,then return false while( CAN2515ByteRead( Channel, TXB0CTRL ) & 0x08 ) //TXREQ == 1 { delay_ms( 1 ); if( WaitCntr++ >= XMIT_TIMEOUT ) return FALSE; } if ((IdentifierS>>11)==0) // Standard id { CAN2515ByteWrite(Channel, TXB0SIDH, (IdentifierS >> 3) & 0xff ); //Set TXB0 SIDH CAN2515ByteWrite(Channel, TXB0SIDL,((IdentifierS << 5) & 0xe0)); //Set TXB0 SIDL } else // Extended id { CAN2515ByteWrite(Channel, TXB0SIDH, (IdentifierS >> 21) & 0xff ); //Set TXB0 SIDH CAN2515ByteWrite(Channel, TXB0SIDL,(((IdentifierS >> 13)& 0xe0) | ((IdentifierS>>16) & 0x03) )| 0x08 ); //Set TXB0 SIDL CAN2515ByteWrite(Channel, TXB0EID8, (IdentifierS>>8) & 0xff); CAN2515ByteWrite(Channel, TXB0EID0, (IdentifierS & 0xff)); } if( MsgSizeS > 8 ) MsgSizeS = 8; if( r==82) //Remote frame { CAN2515ByteWrite(Channel, TXB0DLC, (MsgSizeS |=0x40)); //Set DLC dip204_set_cursor_position(17,4); dip204_printf_string("Re F"); } else // No remote frame { CAN2515ByteWrite(Channel, TXB0DLC, MsgSizeS); //Set DLC } int temp; for( temp = 0; temp < MsgSizeS; temp++ ) CAN2515ByteWrite( Channel, TXB0D0+temp, MsgS[temp] ); CAN2515ByteWrite( Channel, TXB0CTRL, 0x08 ); //Start Transmission. return TRUE; } /********************************************************************* * Function: BOOL CANGetMsg( int Channel, UINT16 *pIdentifier,UINT8* Msg, UINT8 *pMsgSize ) * * PreCondition: CAN initialized * * Input: Channel: SPI channel number, 1 based * Identifier: 11bit or 29bit data for identifier * Msg: Data bytes, 8 bytes max * MsgSize: number of data bytes * * Output: Return true if a message is received * * Side Effects: None * * Overview: Application call this function to read the CAN message * received by the CAN controller * * Note: None. * * Example: CANGetMsg(0, &Ident, msg, &mSize ); ********************************************************************/ Bool CANGetMsg( int Channel, UINT32* pIdentifier, UINT8* Msg, UINT8* pMsgSize ) { int temp; UINT8 loc, S1, S2, S3, S4; temp = ReadStatus2515(Channel); if( (temp & 3) == 0 ) return FALSE; temp&=0x03; if(temp==1){ loc=0x61; } else if (temp==2){ loc=0x71; } else{ return FALSE; } S1=CAN2515ByteRead(Channel, loc); S2=CAN2515ByteRead(Channel, loc+1); S3=CAN2515ByteRead(Channel, loc+2); S4=CAN2515ByteRead(Channel, loc+3); if (((S2>>3)&0x01)==0) //format the 11 bit identifier { *pIdentifier = S1<<3 | S2>>5; LED_On(LED0); LED_Off(LED1); dip204_set_cursor_position(1,4); dip204_printf_string("St Id"); } else if (((S2>>3)&0x01)==1) //format the 29 bit identifier { *pIdentifier = (S1<<21 |((S2>>3 & 0x1c)|(S2&0x03))<<16 | S3 <<8 | S4); LED_On(LED1); LED_Off(LED0); dip204_set_cursor_position(1,4); dip204_printf_string("Ex Id"); } *pMsgSize = CAN2515ByteRead(Channel, loc+4) & 0x0F; //Data Length if(*pMsgSize>8) *pMsgSize = 8; for( temp = 0; temp < *pMsgSize; temp++ ){ Msg[temp] = CAN2515ByteRead(Channel, loc+5+temp); } // Here the RXRTR bit is check to see if a remote frame was received. // Here is the identifier of the remote frame being set. When a remote frame messages with the same identifier as defined here the //node will respond with a user predefined message. //UINT8 RemoteFrameId=User defined; LED_Off(LED2); if ( ((CAN2515ByteRead( Channel, RXB0CTRL ) & 0x08) || (CAN2515ByteRead( Channel, RXB1CTRL ) & 0x08)) && *pIdentifier==RemoteFrameId) { Msg[0] = 0; Msg[1] = 1; Msg[2] = 2; Msg[3] = 3; CANSendMsg( Channel,*pIdentifier, Msg, 4, 0 ); dip204_set_cursor_position(17,4); dip204_printf_string("Re F"); LED_On(LED2); } //clear CANINTF RX01F_RESET=0x00. To be able to receive new messages CAN2515ByteWrite(0,CANINTF,RX0IF_RESET); CAN2515ByteWrite(0,CANINTF,RX1IF_RESET); return TRUE; } /********************************************************************* * Function: void CANEnable(int Channel, int BusSpeed ) * * PreCondition: SPI port configured, CANReset is called, and RXB * Filters intitialized. * * Input: Channel: SPI channel number, 1 based * BusSpeed: Bus Speed code: CAN_1000kbps, CAN_500kbps * CAN_250kbps, or CAN_125kbps * * Output: None * * Side Effects: None * * Overview: Sets the CAN bus speed and turns on the CAN controller. * * Note: None. ********************************************************************/ void CANEnable( int Channel, int BusSpeed ) { // CNF1 -> 0x03 = 125kB. 0x01 = 250 kB, 0x00 = 500kB if (BusSpeed==10) // For 125 kB { CAN2515ByteWrite(Channel, CNF1,0x03); //used to be: BusSpeed CAN2515ByteWrite(Channel, CNF2,0xac); //used to be: BusSpeed CAN2515ByteWrite(Channel, CNF3,0x07); //used to be: BusSpeed } else if (BusSpeed==7) // For 250 kB { CAN2515ByteWrite(Channel, CNF1,0x01); //used to be: BusSpeed CAN2515ByteWrite(Channel, CNF2,0xac); //used to be: BusSpeed CAN2515ByteWrite(Channel, CNF3,0x07); //used to be: BusSpeed } else if(BusSpeed==5) // For 500 kB { CAN2515ByteWrite(Channel, CNF1,0x00); //used to be: BusSpeed CAN2515ByteWrite(Channel, CNF2,0xac); //used to be: BusSpeed CAN2515ByteWrite(Channel, CNF3,0x07); //used to be: BusSpeed } else if (BusSpeed==1) // For 1000 kB { CAN2515ByteWrite(Channel, CNF1,0x00); //used to be: BusSpeed CAN2515ByteWrite(Channel, CNF2,0x91); //used to be: BusSpeed CAN2515ByteWrite(Channel, CNF3,0x03); //used to be: BusSpeed } //Interrupt on RXB0 - CANINTE CAN2515ByteWrite(Channel, CANINTE,0x03); // Interrupts are on //Set NORMAL mode CAN2515ByteWrite(Channel, CANCTRL,REQOP_NORMAL | CLKOUT_ENABLED); CAN2515ByteRead(Channel, CANSTAT); //dummy read to give 2515 time to switch to normal mode if( (CAN2515ByteRead(Channel, CANSTAT) & 0xE0) != OPMODE_NORMAL ) CAN2515ByteWrite(Channel, CANCTRL,REQOP_NORMAL | CLKOUT_ENABLED); } /********************************************************************* * Function: void InitializeCAN( int Channel , int BusSpeed) * * PreCondition: SPI port configured * * Input: Channel: SPI channel number, 1 based * BusSpeed: Bus Speed code: CAN_1000kbps, CAN_500kbps * CAN_250kbps, or CAN_125kbps * * Output: None * * Side Effects: None * * Overview: Sets upp the Rx filters and resets the CAN module * * Note: None. * * Example: InitializeCAN(0,CAN_125kbps) ********************************************************************/ void InitializeCAN( int Channel , int BusSpeed) { CANReset(Channel); // Setup the filter to receive all messages UINT16 Flt[] = {0,0,0,0,0,0}; CAN2515SetRXB0Filters(Channel, 0, Flt); CAN2515SetRXB1Filters(Channel, 0, &Flt[2]); CANEnable(Channel, BusSpeed); } /********************************************************************* * Function: BOOL CANTxReady( int Channel ) * * PreCondition: CAN initialized * * Input: Channel: SPI channel number, 1 based * * Output: Return true if the CAN controller Transmit buffer is available * * Side Effects: None * * Overview: Application can check is Tx buffer is available before * calling CANSendMSg. * * Note: None. * * Example: CANTxReady(0); ********************************************************************/ inline Bool CANTxReady( int Channel ) { return (ReadStatus2515(Channel)&0x04) == 0; } /********************************************************************* * Function: BOOL CANRxReady( int Channel ) * * PreCondition: CAN initialized * * Input: Channel: SPI channel number, 1 based * * Output: Return true if the CAN controller Receive buffer is Full * * Side Effects: None * * Overview: Application can check is Rx buffer is full before * calling CANGetMSg. * * Note: None. * * Example: CANRxReady(0); ********************************************************************/ inline Bool CANRxReady( int Channel ) { return (ReadStatus2515(Channel)&0x3) != 0; } /********************************************************************* * Function: void config_dpi204(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: This function setups the Evk1100 display settings for the SPI interface * * Note: None. * * Example: config_dpi204(); ********************************************************************/ void config_dpi204(void){ static const gpio_map_t DIP204_SPI_GPIO_MAP = { {DIP204_SPI_SCK_PIN, DIP204_SPI_SCK_FUNCTION }, // SPI Clock. {DIP204_SPI_MISO_PIN, DIP204_SPI_MISO_FUNCTION}, // MISO. {DIP204_SPI_MOSI_PIN, DIP204_SPI_MOSI_FUNCTION}, // MOSI. {DIP204_SPI_NPCS_PIN, DIP204_SPI_NPCS_FUNCTION} // Chip Select NPCS. }; spi_options_t spiOptions2 = { .reg = DIP204_SPI_NPCS, .baudrate = 1000000, .bits = 8, .spck_delay = 0, .trans_delay = 0, .stay_act = 1, .spi_mode = 0, .modfdis = 1 }; gpio_enable_module(DIP204_SPI_GPIO_MAP, sizeof(DIP204_SPI_GPIO_MAP) / sizeof(DIP204_SPI_GPIO_MAP[0])); spi_initMaster(DIP204_SPI, &spiOptions2); spi_selectionMode(DIP204_SPI, 0, 0, 0); spi_enable(DIP204_SPI); spi_setupChipReg(DIP204_SPI, &spiOptions2, FOSC0); }