Subversion Repositories HomeAutomation

Rev

Blame | Last modification | View Log | SVN | RSS feed

  1. /******************************************************************************
  2.  *
  3.  * Controller Area Network (CAN) Demo-Application
  4.  * Atmel AVR with Microchip MCP2515
  5.  *
  6.  * Copyright (C) 2005 Martin THOMAS, Kaiserslautern, Germany
  7.  * <eversmith@heizung-thomas.de>
  8.  * http://www.siwawi.arubi.uni-kl.de/avr_projects
  9.  *
  10.  *****************************************************************************
  11.  *
  12.  * File    : mcp2515.c
  13.  * Version : 0.9
  14.  *
  15.  * Summary : MCP2515 "low-level" driver
  16.  *
  17.  * Parts of this code are adapted from a MCP2510 sample-application
  18.  * by KVASER AB, http://www.kvaser.com (KVASER-code is marked as free)
  19.  *
  20.  * This code-module is free to use but you have to keep the copyright
  21.  * notice.
  22.  *
  23.  *****************************************************************************/
  24.  
  25. #include <inttypes.h>
  26.  
  27. #include "spi.h"
  28. #include "delay.h"
  29. #include "mcp2515.h"
  30. #include "mcp2515_defs.h"
  31. #include "mcp2515_bittime.h"
  32.  
  33. #include "can.h"
  34.  
  35. #if (MCPDEBUG)
  36. #include "termio.h"
  37. #include "debughelper.h"
  38. #endif
  39.  
  40. void mcp2515_reset(void)
  41. {
  42.     MCP2515_SELECT();
  43.     spi_readwrite(MCP_RESET);
  44.     MCP2515_UNSELECT();
  45.     delay_ms(10); // rough - but > 128 MCP clock-cycles
  46. }
  47.  
  48. uint8_t mcp2515_readRegister(const uint8_t address)
  49. {
  50.     uint8_t ret;
  51.    
  52.     MCP2515_SELECT();
  53.     spi_readwrite(MCP_READ);
  54.     spi_readwrite(address);
  55.     ret = spi_read();
  56.     MCP2515_UNSELECT();
  57.    
  58.     return ret;
  59. }
  60.  
  61. void mcp2515_readRegisterS(const uint8_t address,
  62.     uint8_t values[], const uint8_t n)
  63. {
  64.     uint8_t i;
  65.    
  66.     MCP2515_SELECT();
  67.     spi_readwrite(MCP_READ);
  68.     spi_readwrite(address);
  69.     // mcp2515 has auto-increment of address-pointer
  70.     for (i=0; i<n; i++) {
  71.         values[i] = spi_read();
  72.     }
  73.     MCP2515_UNSELECT();
  74. }
  75.  
  76. void mcp2515_setRegister(const uint8_t address, const uint8_t value)
  77. {
  78.     MCP2515_SELECT();
  79.     spi_readwrite(MCP_WRITE);
  80.     spi_readwrite(address);
  81.     spi_readwrite(value);
  82.     MCP2515_UNSELECT();
  83. }
  84.  
  85. void mcp2515_setRegisterS(const uint8_t address,
  86.     const uint8_t values[], const uint8_t n)
  87. {
  88.     uint8_t i;
  89.    
  90.     MCP2515_SELECT();
  91.     spi_readwrite(MCP_WRITE);
  92.     spi_readwrite(address);
  93.     // mcp2515 has auto-increment of address-pointer
  94.     for (i=0; i<n; i++) {
  95.         spi_readwrite(values[i]);
  96.     }
  97.     MCP2515_UNSELECT();
  98. }
  99.  
  100. void mcp2515_modifyRegister(const uint8_t address,
  101.     const uint8_t mask, const uint8_t data)
  102. {
  103.     MCP2515_SELECT();
  104.     spi_readwrite(MCP_BITMOD);
  105.     spi_readwrite(address);
  106.     spi_readwrite(mask);
  107.     spi_readwrite(data);
  108.     MCP2515_UNSELECT();
  109. }
  110.  
  111. static uint8_t mcp2515_readXXStatus_helper(const uint8_t cmd)
  112. {
  113.     uint8_t i;
  114.    
  115.     MCP2515_SELECT();
  116.     spi_readwrite(cmd);
  117.     i = spi_read();
  118.     MCP2515_UNSELECT();
  119.    
  120.     return i;
  121. }
  122.    
  123. uint8_t mcp2515_readStatus(void)
  124. {
  125.     return mcp2515_readXXStatus_helper(MCP_READ_STATUS);
  126. }
  127.  
  128. uint8_t mcp2515_RXStatus(void)
  129. {
  130.     return mcp2515_readXXStatus_helper(MCP_RX_STATUS);
  131. }
  132.  
  133. uint8_t mcp2515_setCANCTRL_Mode(const uint8_t newmode)
  134. {
  135.     uint8_t i;
  136.    
  137.     mcp2515_modifyRegister(MCP_CANCTRL, MODE_MASK, newmode);
  138.    
  139.     // verify as advised in datasheet
  140.     i = mcp2515_readRegister(MCP_CANCTRL);
  141.     i &= MODE_MASK;
  142.    
  143.     if ( i == newmode ) {
  144.         return MCP2515_OK;
  145.     }
  146.     else {
  147.         return MCP2515_FAIL;
  148.     }
  149. }
  150.  
  151.  
  152. uint8_t mcp2515_configRate(const uint8_t canSpeed)
  153. {
  154.     uint8_t set, cfg1, cfg2, cfg3;
  155.    
  156.     set = 0;
  157.    
  158.     switch (canSpeed) {
  159.         case (CAN_125KBPS) :
  160.             cfg1 = MCP_4MHz_125kBPS_CFG1 ;
  161.             cfg2 = MCP_4MHz_125kBPS_CFG2 ;
  162.             cfg3 = MCP_4MHz_125kBPS_CFG3 ;
  163.             set = 1;
  164.             break;
  165.         case (CAN_20KBPS) :
  166.             cfg1 = MCP_4MHz_20kBPS_CFG1 ;
  167.             cfg2 = MCP_4MHz_20kBPS_CFG2 ;
  168.             cfg3 = MCP_4MHz_20kBPS_CFG3 ;
  169.             set = 1;
  170.             break;
  171.         default:
  172.             set = 0;
  173.             break;
  174.     }
  175.    
  176.     if (set) {
  177.         mcp2515_setRegister(MCP_CNF1, cfg1);
  178.         mcp2515_setRegister(MCP_CNF2, cfg2);
  179.         mcp2515_setRegister(MCP_CNF3, cfg3);
  180.         return MCP2515_OK;
  181.     }
  182.     else {
  183.         return MCP2515_FAIL;
  184.     }
  185. }
  186.  
  187. // ---
  188.  
  189. void mcp2515_read_can_id( const uint8_t mcp_addr,
  190.     uint8_t* ext, uint32_t* can_id )
  191. {
  192.     uint8_t tbufdata[4];
  193.    
  194.     *ext = 0;
  195.     *can_id = 0;
  196.    
  197.     mcp2515_readRegisterS( mcp_addr, tbufdata, 4 );
  198.    
  199.     *can_id = (tbufdata[MCP_SIDH]<<3) + (tbufdata[MCP_SIDL]>>5);
  200.    
  201.     if ( (tbufdata[MCP_SIDL] & MCP_TXB_EXIDE_M) ==  MCP_TXB_EXIDE_M ) {
  202.         // extended id
  203.         *can_id = (*can_id<<2) + (tbufdata[MCP_SIDL] & 0x03);
  204.         *can_id <<= 16;
  205.         *can_id = *can_id +(tbufdata[MCP_EID8]<<8) + tbufdata[MCP_EID0];
  206.         *ext = 1;
  207.     }
  208. }
  209.  
  210. // Buffer can be MCP_RXBUF_0 or MCP_RXBUF_1
  211. void mcp2515_read_canMsg( const uint8_t buffer_sidh_addr,
  212.     CanMessage* msg)
  213. {
  214.  
  215.     uint8_t mcp_addr, ctrl;
  216.  
  217.     mcp_addr = buffer_sidh_addr;
  218.    
  219.     mcp2515_read_can_id( mcp_addr, &(msg->extended_identifier),
  220.         &(msg->identifier) );
  221.    
  222.     ctrl = mcp2515_readRegister( mcp_addr-1 );
  223.     msg->dlc = mcp2515_readRegister( mcp_addr+4 );
  224.    
  225.     if (/*(*dlc & RTR_MASK) || */(ctrl & 0x08)) {
  226.         msg->rtr = 1;
  227.     } else {
  228.         msg->rtr = 0;
  229.     }
  230.    
  231.     msg->dlc &= MCP_DLC_MASK;
  232.     mcp2515_readRegisterS( mcp_addr+5, &(msg->dta[0]), msg->dlc );
  233. }
  234.  
  235.  
  236. void mcp2515_write_can_id( const uint8_t mcp_addr,
  237.     const uint8_t ext, const uint32_t can_id )
  238. {
  239.     uint16_t canid;
  240.     uint8_t tbufdata[4];
  241.    
  242.     canid = (uint16_t)(can_id & 0x0FFFF);
  243.    
  244.     if ( ext == 1) {
  245.         tbufdata[MCP_EID0] = (uint8_t) (canid & 0xFF);
  246.         tbufdata[MCP_EID8] = (uint8_t) (canid / 256);
  247.         canid = (uint16_t)( can_id / 0x10000L );
  248.         tbufdata[MCP_SIDL] = (uint8_t) (canid & 0x03);
  249.         tbufdata[MCP_SIDL] += (uint8_t) ((canid & 0x1C )*8);
  250.         tbufdata[MCP_SIDL] |= MCP_TXB_EXIDE_M;
  251.         tbufdata[MCP_SIDH] = (uint8_t) (canid / 32 );
  252.     }
  253.     else {
  254.         tbufdata[MCP_SIDH] = (uint8_t) (canid / 8 );
  255.         tbufdata[MCP_SIDL] = (uint8_t) ((canid & 0x07 )*32);
  256.         tbufdata[MCP_EID0] = 0;
  257.         tbufdata[MCP_EID8] = 0;
  258.     }
  259.     mcp2515_setRegisterS( mcp_addr, tbufdata, 4 );
  260. }
  261.  
  262. // Buffer can be MCP_TXBUF_0 MCP_TXBUF_1 or MCP_TXBUF_2
  263. void mcp2515_write_canMsg( const uint8_t buffer_sidh_addr,
  264.     const CanMessage* msg)
  265. {
  266.     uint8_t mcp_addr, dlc;
  267.  
  268.     mcp_addr = buffer_sidh_addr;
  269.     dlc = msg->dlc;
  270.    
  271.     mcp2515_setRegisterS(mcp_addr+5, &(msg->dta[0]), dlc );  // write data bytes
  272.     mcp2515_write_can_id( mcp_addr, msg->extended_identifier,
  273.         msg->identifier );  // write CAN id
  274.     if ( msg->rtr == 1)  dlc |= MCP_RTR_MASK;  // if RTR set bit in byte
  275.     mcp2515_setRegister( (mcp_addr+4), dlc );  // write the RTR and DLC
  276. }
  277.  
  278. /*
  279.  ** Start the transmission from one of the tx buffers.
  280.  */
  281. // Buffer can be MCP_TXBUF_0 MCP_TXBUF_1 or MCP_TXBUF_2
  282. void mcp2515_start_transmit(const uint8_t buffer_sidh_addr)
  283. {
  284.     // TXBnCTRL_addr = TXBnSIDH_addr - 1
  285.     mcp2515_modifyRegister( buffer_sidh_addr-1 , MCP_TXB_TXREQ_M,
  286.         MCP_TXB_TXREQ_M );
  287. }
  288.  
  289. uint8_t mcp2515_getNextFreeTXBuf(uint8_t *txbuf_n)
  290. {
  291.     uint8_t res, i, ctrlval;
  292.     uint8_t ctrlregs[MCP_N_TXBUFFERS] = { MCP_TXB0CTRL, MCP_TXB1CTRL, MCP_TXB2CTRL };
  293.    
  294.     res = MCP_ALLTXBUSY;
  295.     *txbuf_n = 0x00;
  296.    
  297.     // check all 3 TX-Buffers
  298.     for (i=0; i<MCP_N_TXBUFFERS; i++) {
  299.         ctrlval = mcp2515_readRegister( ctrlregs[i] );
  300.         if ( (ctrlval & MCP_TXB_TXREQ_M) == 0 ) {
  301. #if (MCPDEBUG_TXBUF)
  302.             Debug_ByteToUart_P("Selected TX-Buffer", i+1);
  303. #endif
  304.             *txbuf_n = ctrlregs[i]+1; // return SIDH-address of Buffer
  305.             res = MCP2515_OK;
  306.             return res; /* ! function exit */
  307.         }
  308.     }
  309.    
  310.     return res;
  311. }
  312.  
  313. void mcp2515_initCANBuffers(void)
  314. {
  315.     uint8_t i, a1, a2, a3;
  316.    
  317.     // TODO: check why this is needed to receive extended
  318.     //   and standard frames
  319.     // Mark all filter bits as don't care:
  320.     mcp2515_write_can_id(MCP_RXM0SIDH, 0, 0);
  321.     mcp2515_write_can_id(MCP_RXM1SIDH, 0, 0);
  322.     // Anyway, set all filters to 0:
  323.     mcp2515_write_can_id(MCP_RXF0SIDH, 1, 0); // RXB0: extended
  324.     mcp2515_write_can_id(MCP_RXF1SIDH, 0, 0); //       AND standard
  325.     mcp2515_write_can_id(MCP_RXF2SIDH, 1, 0); // RXB1: extended
  326.     mcp2515_write_can_id(MCP_RXF3SIDH, 0, 0); //       AND standard
  327.     mcp2515_write_can_id(MCP_RXF4SIDH, 0, 0);
  328.     mcp2515_write_can_id(MCP_RXF5SIDH, 0, 0);
  329.    
  330.     // Clear, deactivate the three transmit buffers
  331.     // TXBnCTRL -> TXBnD7
  332.     a1 = MCP_TXB0CTRL;
  333.     a2 = MCP_TXB1CTRL;
  334.     a3 = MCP_TXB2CTRL;
  335.     for (i = 0; i < 14; i++) { // in-buffer loop
  336.         mcp2515_setRegister(a1, 0);
  337.         mcp2515_setRegister(a2, 0);
  338.         mcp2515_setRegister(a3, 0);
  339.         a1++;
  340.         a2++;
  341.         a3++;
  342.     }
  343.    
  344.     // and clear, deactivate the two receive buffers.
  345.     mcp2515_setRegister(MCP_RXB0CTRL, 0);
  346.     mcp2515_setRegister(MCP_RXB1CTRL, 0);
  347. }
  348.  
  349.  
  350. // ---
  351.  
  352. uint8_t mcp2515_init(const uint8_t canSpeed)
  353. {
  354.     uint8_t res;
  355.    
  356.     MCP2515_UNSELECT();
  357.     MCP_CS_DDR |= ( 1 << MCP_CS_BIT );
  358.    
  359.     mcp2515_reset();
  360.    
  361.     res = mcp2515_setCANCTRL_Mode(MODE_CONFIG);
  362.    
  363.     if ( res == MCP2515_FAIL ) return res;  /* function exit on error */
  364.    
  365.     res = mcp2515_configRate(canSpeed);
  366.    
  367.     if ( res == MCP2515_OK ) {
  368.         mcp2515_initCANBuffers();
  369.        
  370. #if (DEBUG_RXANY==1)
  371.         // enable both receive-buffers to receive any message
  372.         // and enable rollover
  373.         mcp2515_modifyRegister(MCP_RXB0CTRL,
  374.             MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK,
  375.             MCP_RXB_RX_ANY | MCP_RXB_BUKT_MASK);
  376.         mcp2515_modifyRegister(MCP_RXB1CTRL, MCP_RXB_RX_MASK,
  377.             MCP_RXB_RX_ANY);
  378. #else
  379.         // enable both receive-buffers to receive messages
  380.         // with std. and ext. identifiers
  381.         // and enable rollover
  382.         mcp2515_modifyRegister(MCP_RXB0CTRL,
  383.             MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK,
  384.             MCP_RXB_RX_STDEXT | MCP_RXB_BUKT_MASK );
  385.         mcp2515_modifyRegister(MCP_RXB1CTRL, MCP_RXB_RX_MASK,
  386.             MCP_RXB_RX_STDEXT);
  387. #endif
  388.     }
  389.    
  390.     return res;
  391. }
  392.  
  393. #ifdef MCPDEBUG
  394. void mcp2515_dumpExtendedStatus(void)
  395. {
  396.     uint8_t tec, rec, eflg;
  397.    
  398.     tec  = mcp2515_readRegister(MCP_TEC);
  399.     rec  = mcp2515_readRegister(MCP_REC);
  400.     eflg = mcp2515_readRegister(MCP_EFLG);
  401.    
  402.     term_puts_P("MCP2515 Extended Status:\n");
  403.     Debug_ByteToUart_p(PSTR("MCP Transmit Error Count"), tec);
  404.     Debug_ByteToUart_p(PSTR("MCP Receiver Error Count"), rec);
  405.     Debug_ByteToUart_p(PSTR("MCP Error Flag"), eflg);
  406.    
  407.     if ( (rec>127) || (tec>127) ) {
  408.         term_puts_P("Error-Passive or Bus-Off\n");
  409.     }
  410.  
  411.     if (eflg & MCP_EFLG_RX1OVR)
  412.         term_puts_P("Receive Buffer 1 Overflow\n");
  413.     if (eflg & MCP_EFLG_RX0OVR)
  414.         term_puts_P("Receive Buffer 0 Overflow\n");
  415.     if (eflg & MCP_EFLG_TXBO)
  416.         term_puts_P("Bus-Off\n");
  417.     if (eflg & MCP_EFLG_TXEP)
  418.         term_puts_P("Receive Error Passive\n");
  419.     if (eflg & MCP_EFLG_TXWAR)
  420.         term_puts_P("Transmit Error Warning\n");
  421.     if (eflg & MCP_EFLG_RXWAR)
  422.         term_puts_P("Receive Error Warning\n");
  423.     if (eflg & MCP_EFLG_EWARN )
  424.         term_puts_P("Receive Error Warning\n");
  425. }
  426. #endif
  427.  
  428. #if 0
  429. // read-modify-write - better: Bit Modify Instruction
  430. uint8_t mcp2515_setCANCTRL_Mode(uint8_t newmode)
  431. {
  432.     uint8_t i;
  433.    
  434.     i = mcp2515_readRegister(MCP_CANCTRL);
  435.     i &= ~(MODE_MASK);
  436.     i |= newmode;
  437.     mcp2515_setRegister(MCP_CANCTRL, i);
  438.    
  439.     // verify as advised in datasheet
  440.     i = mcp2515_readRegister(MCP_CANCTRL);
  441.     i &= MODE_MASK;
  442.     if ( i == newmode ) {
  443.         return MCP2515_OK;
  444.     }
  445.     else {
  446.         return MCP2515_FAIL;
  447.     }
  448. }
  449. #endif
  450.