MCP2515 CAN library

Fork of mcp2515 by Jason Engelman

Committer:
nimig
Date:
Thu Jul 27 22:18:03 2017 +0000
Revision:
15:5a3fdb039965
Parent:
13:ff12c7f532f9
Update 7-27-17

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tecnosys 0:d8f50b1e384f 1 /******************************************************************************
tecnosys 1:dbc44582f2f8 2 *
tecnosys 0:d8f50b1e384f 3 * Controller Area Network (CAN) Demo-Application
tecnosys 1:dbc44582f2f8 4 * Atmel AVR with Microchip MCP2515
tecnosys 1:dbc44582f2f8 5 *
tecnosys 0:d8f50b1e384f 6 * Copyright (C) 2005 Martin THOMAS, Kaiserslautern, Germany
tecnosys 0:d8f50b1e384f 7 * <eversmith@heizung-thomas.de>
tecnosys 0:d8f50b1e384f 8 * http://www.siwawi.arubi.uni-kl.de/avr_projects
tecnosys 0:d8f50b1e384f 9 *
tecnosys 0:d8f50b1e384f 10 *****************************************************************************
tecnosys 0:d8f50b1e384f 11 *
tecnosys 0:d8f50b1e384f 12 * File : mcp2515.c
tecnosys 0:d8f50b1e384f 13 * Version : 0.9
tecnosys 1:dbc44582f2f8 14 *
tecnosys 0:d8f50b1e384f 15 * Summary : MCP2515 "low-level" driver
tecnosys 0:d8f50b1e384f 16 *
tecnosys 1:dbc44582f2f8 17 * Parts of this code are adapted from a MCP2510 sample-application
tecnosys 0:d8f50b1e384f 18 * by KVASER AB, http://www.kvaser.com (KVASER-code is marked as free)
tecnosys 0:d8f50b1e384f 19 *
tecnosys 0:d8f50b1e384f 20 * This code-module is free to use but you have to keep the copyright
tecnosys 0:d8f50b1e384f 21 * notice.
tecnosys 0:d8f50b1e384f 22 *
tecnosys 0:d8f50b1e384f 23 *
tecnosys 0:d8f50b1e384f 24 *****************************************************************************
tecnosys 0:d8f50b1e384f 25 *
tecnosys 0:d8f50b1e384f 26 * File : mcp2515.cpp (mbed LPC1768 version)
tecnosys 0:d8f50b1e384f 27 * Version : 0.1
tecnosys 0:d8f50b1e384f 28 *
tecnosys 1:dbc44582f2f8 29 * All credits to the nerds above, this source has been adapted for the
driscoll85 9:d50f103848e0 30 * LPC1768 platform by J.Engelman. And doesn't require and of the copyrighted
tecnosys 0:d8f50b1e384f 31 * SPI or AVR controller code that Martin or co have excluded copyright.
tecnosys 0:d8f50b1e384f 32 * This module remains free.
tecnosys 0:d8f50b1e384f 33 *
tecnosys 0:d8f50b1e384f 34 *
tecnosys 0:d8f50b1e384f 35 *****************************************************************************/
tecnosys 0:d8f50b1e384f 36
tecnosys 0:d8f50b1e384f 37 #include "mcp2515.h"
tecnosys 0:d8f50b1e384f 38
tecnosys 1:dbc44582f2f8 39 #include "mbed.h"
tecnosys 0:d8f50b1e384f 40 #include "mcp2515_can.h"
tecnosys 0:d8f50b1e384f 41 #include "mcp2515_defs.h"
tecnosys 0:d8f50b1e384f 42 #include "mcp2515_bittime.h"
tecnosys 0:d8f50b1e384f 43
tecnosys 0:d8f50b1e384f 44 #define SPI_NULL (0x00)
tecnosys 0:d8f50b1e384f 45
tecnosys 1:dbc44582f2f8 46 #define PHSEG11 4
tecnosys 1:dbc44582f2f8 47 #define PHSEG21 1
tecnosys 1:dbc44582f2f8 48 #define BTLMODE2 7
tecnosys 1:dbc44582f2f8 49 //BTLMODE 0x80 (128)
tecnosys 1:dbc44582f2f8 50 #define BRP2 2
tecnosys 1:dbc44582f2f8 51 #define BRP1 1
tecnosys 1:dbc44582f2f8 52 #define BRP0 0
tecnosys 0:d8f50b1e384f 53
tecnosys 1:dbc44582f2f8 54 #define CNF2_BTLMODE 0x80
tecnosys 1:dbc44582f2f8 55 #define CNF3 0x28
tecnosys 1:dbc44582f2f8 56 #define CNF3_SOF 0x08
tecnosys 1:dbc44582f2f8 57 #define CNF3_WAKFIL 0x04
tecnosys 1:dbc44582f2f8 58 #define CNF3_PHSEG2_MASK 0x07
tecnosys 0:d8f50b1e384f 59
tecnosys 1:dbc44582f2f8 60 mcp2515::mcp2515(SPI& _spi, PinName ncs)
tecnosys 1:dbc44582f2f8 61 : spi(_spi), _ncs(ncs) {
tecnosys 1:dbc44582f2f8 62 printf("\n\rmcp2515 = %d",this);
tecnosys 1:dbc44582f2f8 63 printf("\n\rpin = %d",ncs);
tecnosys 0:d8f50b1e384f 64
tecnosys 0:d8f50b1e384f 65 }
tecnosys 0:d8f50b1e384f 66
tecnosys 0:d8f50b1e384f 67
tecnosys 1:dbc44582f2f8 68
tecnosys 0:d8f50b1e384f 69 void mcp2515::_reset() {
tecnosys 0:d8f50b1e384f 70
tecnosys 0:d8f50b1e384f 71 _select();
tecnosys 0:d8f50b1e384f 72 _spi_readwrite(MCP_RESET);
tecnosys 0:d8f50b1e384f 73 _deselect();
tecnosys 0:d8f50b1e384f 74 wait(0.001);
tecnosys 0:d8f50b1e384f 75 }
tecnosys 0:d8f50b1e384f 76
tecnosys 1:dbc44582f2f8 77 void mcp2515::setRegister( uint8_t address, uint8_t value) {
tecnosys 0:d8f50b1e384f 78 _select();
tecnosys 0:d8f50b1e384f 79 _spi_readwrite(MCP_WRITE);
tecnosys 0:d8f50b1e384f 80 _spi_readwrite(address);
tecnosys 0:d8f50b1e384f 81 _spi_readwrite(value);
tecnosys 0:d8f50b1e384f 82 _deselect();
tecnosys 0:d8f50b1e384f 83 }
tecnosys 0:d8f50b1e384f 84
tecnosys 1:dbc44582f2f8 85 uint8_t mcp2515::configRate( uint8_t canSpeed) {
tecnosys 0:d8f50b1e384f 86 uint8_t set, cfg1, cfg2, cfg3;
tecnosys 1:dbc44582f2f8 87
tecnosys 0:d8f50b1e384f 88 set = 0;
tecnosys 1:dbc44582f2f8 89
tecnosys 0:d8f50b1e384f 90 switch (canSpeed) {
tecnosys 1:dbc44582f2f8 91 case (CAN_500KBPS_8MHZ) :
driscoll85 10:6d6fd99da044 92 cfg1 = 0x04;
tecnosys 1:dbc44582f2f8 93 cfg2 = 0xA0;
tecnosys 1:dbc44582f2f8 94 cfg3 = 0x02;
tecnosys 1:dbc44582f2f8 95 case (CAN_50KBPS_8MHZ) :
driscoll85 10:6d6fd99da044 96 cfg1 = 0x04; //0x09;
tecnosys 1:dbc44582f2f8 97 cfg2 = 0xB8; //0x90;
tecnosys 1:dbc44582f2f8 98 cfg3 = 0x05; //0x02;
tecnosys 0:d8f50b1e384f 99 case (CAN_125KBPS) :
driscoll85 10:6d6fd99da044 100 cfg1 = MCP_4MHz_125kBPS_CFG1 ;
tecnosys 0:d8f50b1e384f 101 cfg2 = MCP_4MHz_125kBPS_CFG2 ;
tecnosys 0:d8f50b1e384f 102 cfg3 = MCP_4MHz_125kBPS_CFG3 ;
tecnosys 0:d8f50b1e384f 103 set = 1;
tecnosys 0:d8f50b1e384f 104 break;
tecnosys 0:d8f50b1e384f 105 case (CAN_20KBPS) :
driscoll85 10:6d6fd99da044 106 cfg1 = MCP_4MHz_20kBPS_CFG1 ;
tecnosys 0:d8f50b1e384f 107 cfg2 = MCP_4MHz_20kBPS_CFG2 ;
tecnosys 0:d8f50b1e384f 108 cfg3 = MCP_4MHz_20kBPS_CFG3 ;
tecnosys 0:d8f50b1e384f 109 set = 1;
tecnosys 0:d8f50b1e384f 110 break;
driscoll85 10:6d6fd99da044 111 case (CAN_500KBPS_10MHz) :
driscoll85 10:6d6fd99da044 112 cfg1 = 0x00;
driscoll85 10:6d6fd99da044 113 cfg2 = 0x92;
driscoll85 10:6d6fd99da044 114 cfg3 = 0x02;
driscoll85 10:6d6fd99da044 115 set = 1;
driscoll85 10:6d6fd99da044 116 break;
tecnosys 0:d8f50b1e384f 117 default:
tecnosys 0:d8f50b1e384f 118 set = 0;
tecnosys 0:d8f50b1e384f 119 break;
tecnosys 0:d8f50b1e384f 120 }
tecnosys 1:dbc44582f2f8 121
tecnosys 0:d8f50b1e384f 122 if (set) {
tecnosys 0:d8f50b1e384f 123 setRegister(MCP_CNF1, cfg1);
tecnosys 0:d8f50b1e384f 124 setRegister(MCP_CNF2, cfg2);
tecnosys 0:d8f50b1e384f 125 setRegister(MCP_CNF3, cfg3);
tecnosys 0:d8f50b1e384f 126 return MCP2515_OK;
tecnosys 1:dbc44582f2f8 127 } else {
tecnosys 0:d8f50b1e384f 128 return MCP2515_FAIL;
tecnosys 0:d8f50b1e384f 129 }
tecnosys 1:dbc44582f2f8 130 }
tecnosys 1:dbc44582f2f8 131
tecnosys 1:dbc44582f2f8 132 int mcp2515::configRate2(int bit_rate)
tecnosys 1:dbc44582f2f8 133 {
tecnosys 1:dbc44582f2f8 134 //struct spi_device *spi = to_spi_device(can->cdev.dev);
tecnosys 1:dbc44582f2f8 135 //struct mcp251x *chip = dev_get_drvdata(&spi->dev);
tecnosys 1:dbc44582f2f8 136 //struct mcp251x_platform_data *pdata = spi->dev.platform_data;
tecnosys 1:dbc44582f2f8 137 printf("\n\rcanspeed=%d",bit_rate);
driscoll85 13:ff12c7f532f9 138 int f_osc = 20000000;
tecnosys 1:dbc44582f2f8 139 int tqs; /* tbit/TQ */
tecnosys 1:dbc44582f2f8 140 int brp;
tecnosys 1:dbc44582f2f8 141 int ps1, ps2, propseg, sjw;
tecnosys 1:dbc44582f2f8 142
tecnosys 1:dbc44582f2f8 143 /* Determine the BRP value that gives the requested bit rate. */
tecnosys 1:dbc44582f2f8 144 for(brp = 0; brp < 8; brp++) {
tecnosys 1:dbc44582f2f8 145 tqs = f_osc / (2 * (brp + 1)) / bit_rate;
tecnosys 1:dbc44582f2f8 146 if (tqs >= 5 && tqs <= 25
tecnosys 1:dbc44582f2f8 147 && (f_osc / (2 * (brp + 1)) / tqs) == bit_rate)
tecnosys 1:dbc44582f2f8 148 break;
tecnosys 1:dbc44582f2f8 149 }
tecnosys 1:dbc44582f2f8 150 if (brp >= 8) printf("Spaztic BRP");
tecnosys 1:dbc44582f2f8 151 // return -1;
tecnosys 0:d8f50b1e384f 152
tecnosys 1:dbc44582f2f8 153 /* The CAN bus bit time (tbit) is determined by:
tecnosys 1:dbc44582f2f8 154 * tbit = (SyncSeg + PropSeg + PS1 + PS2) * TQ
tecnosys 1:dbc44582f2f8 155 * with:
tecnosys 1:dbc44582f2f8 156 * SyncSeg = 1
tecnosys 1:dbc44582f2f8 157 * sample point (between PS1 and PS2) must be at 60%-70% of the bit time
tecnosys 1:dbc44582f2f8 158 * PropSeg + PS1 >= PS2
tecnosys 1:dbc44582f2f8 159 * PropSeg + PS1 >= Tdelay
tecnosys 1:dbc44582f2f8 160 * PS2 > SJW
tecnosys 1:dbc44582f2f8 161 * 1 <= PropSeg <= 8, 1 <= PS1 <=8, 2 <= PS2 <= 8
tecnosys 1:dbc44582f2f8 162 * SJW = 1 is sufficient in most cases.
tecnosys 1:dbc44582f2f8 163 * Tdelay is usually 1 or 2 TQ.
tecnosys 1:dbc44582f2f8 164 */
tecnosys 1:dbc44582f2f8 165
tecnosys 1:dbc44582f2f8 166 propseg = ps1 = ps2 = (tqs - 1) / 3;
tecnosys 1:dbc44582f2f8 167 if (tqs - (1 + propseg + ps1 + ps2) == 2)
tecnosys 1:dbc44582f2f8 168 ps1++;
tecnosys 1:dbc44582f2f8 169 if (tqs - (1 + propseg + ps1 + ps2) == 1)
tecnosys 1:dbc44582f2f8 170 ps2++;
tecnosys 1:dbc44582f2f8 171 sjw = 1;
tecnosys 1:dbc44582f2f8 172
tecnosys 1:dbc44582f2f8 173 printf("\n\rbit rate: BRP = %d, Tbit = %d TQ, PropSeg = %d, PS1 = %d, PS2 = %d, SJW = %d\n",
tecnosys 1:dbc44582f2f8 174 brp, tqs, propseg, ps1, ps2, sjw);
tecnosys 1:dbc44582f2f8 175
tecnosys 1:dbc44582f2f8 176 /* Since we can only change the bit rate when the network device is
tecnosys 1:dbc44582f2f8 177 * down the chip must be in sleep mode. Wake it up and put it into
tecnosys 1:dbc44582f2f8 178 * config mode. */
tecnosys 1:dbc44582f2f8 179 //mcp251x_hw_wakeup(spi);
tecnosys 1:dbc44582f2f8 180 //mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK, CANCTRL_REQOP_CONF);
tecnosys 1:dbc44582f2f8 181
tecnosys 1:dbc44582f2f8 182 //mcp251x_write_reg(spi, CNF1, ((sjw-1) << 6) | brp);
tecnosys 1:dbc44582f2f8 183 //mcp251x_write_reg(spi, CNF2, CNF2_BTLMODE | ((ps1-1) << 3) | (propseg-1));
tecnosys 1:dbc44582f2f8 184 //mcp251x_write_bits(spi, CNF3, CNF3_PHSEG2_MASK, (ps2-1));
tecnosys 1:dbc44582f2f8 185 setRegister(MCP_CNF1, ((sjw-1) << 6) | brp );
tecnosys 1:dbc44582f2f8 186 setRegister(MCP_CNF2, CNF2_BTLMODE | ((ps1-1) << 3) | (propseg-1) );
tecnosys 1:dbc44582f2f8 187 modifyRegister(MCP_CNF3, CNF3_PHSEG2_MASK, (ps2-1) );
tecnosys 1:dbc44582f2f8 188 //mcp251x_hw_sleep(spi);
tecnosys 1:dbc44582f2f8 189
tecnosys 1:dbc44582f2f8 190 /* Calculate actual bit rate. */
tecnosys 1:dbc44582f2f8 191 //chip->bit_rate = pdata->f_osc / (2 * (brp + 1)) / tqs;
tecnosys 1:dbc44582f2f8 192
tecnosys 1:dbc44582f2f8 193 return 0;
tecnosys 1:dbc44582f2f8 194 }
tecnosys 1:dbc44582f2f8 195
tecnosys 1:dbc44582f2f8 196 uint8_t mcp2515::readRegister( uint8_t address) {
tecnosys 0:d8f50b1e384f 197 uint8_t ret;
tecnosys 1:dbc44582f2f8 198
tecnosys 0:d8f50b1e384f 199 _select();
tecnosys 0:d8f50b1e384f 200 _spi_readwrite(MCP_READ);
tecnosys 0:d8f50b1e384f 201 _spi_readwrite(address);
tecnosys 0:d8f50b1e384f 202 ret = _spi_read();
tecnosys 0:d8f50b1e384f 203 _deselect();
tecnosys 1:dbc44582f2f8 204
tecnosys 0:d8f50b1e384f 205 return ret;
tecnosys 0:d8f50b1e384f 206 }
tecnosys 0:d8f50b1e384f 207
tecnosys 1:dbc44582f2f8 208 void mcp2515::readRegisterS( uint8_t address,
tecnosys 1:dbc44582f2f8 209 uint8_t values[], uint8_t n) {
tecnosys 0:d8f50b1e384f 210 uint8_t i;
tecnosys 1:dbc44582f2f8 211
tecnosys 0:d8f50b1e384f 212 _select();
tecnosys 0:d8f50b1e384f 213 _spi_readwrite(MCP_READ);
tecnosys 0:d8f50b1e384f 214 _spi_readwrite(address);
tecnosys 0:d8f50b1e384f 215 // mcp2515 has auto-increment of address-pointer
tecnosys 0:d8f50b1e384f 216 for (i=0; i<n; i++) {
tecnosys 0:d8f50b1e384f 217 values[i] = _spi_read();
tecnosys 0:d8f50b1e384f 218 }
tecnosys 0:d8f50b1e384f 219 _deselect();
tecnosys 0:d8f50b1e384f 220 }
tecnosys 0:d8f50b1e384f 221
tecnosys 1:dbc44582f2f8 222 void mcp2515::modifyRegister( uint8_t address,
tecnosys 1:dbc44582f2f8 223 uint8_t mask, uint8_t data) {
tecnosys 0:d8f50b1e384f 224 _select();
tecnosys 0:d8f50b1e384f 225 _spi_readwrite(MCP_BITMOD);
tecnosys 0:d8f50b1e384f 226 _spi_readwrite(address);
tecnosys 0:d8f50b1e384f 227 _spi_readwrite(mask);
tecnosys 0:d8f50b1e384f 228 _spi_readwrite(data);
tecnosys 0:d8f50b1e384f 229 _deselect();
tecnosys 0:d8f50b1e384f 230 }
tecnosys 0:d8f50b1e384f 231
tecnosys 0:d8f50b1e384f 232
tecnosys 1:dbc44582f2f8 233 uint8_t mcp2515::readXXStatus_helper( uint8_t cmd) {
tecnosys 0:d8f50b1e384f 234 uint8_t i;
tecnosys 1:dbc44582f2f8 235
tecnosys 0:d8f50b1e384f 236 _select();
tecnosys 0:d8f50b1e384f 237 _spi_readwrite(cmd);
tecnosys 0:d8f50b1e384f 238 i = _spi_read();
tecnosys 0:d8f50b1e384f 239 _deselect();
tecnosys 1:dbc44582f2f8 240
tecnosys 0:d8f50b1e384f 241 return i;
tecnosys 0:d8f50b1e384f 242 }
tecnosys 1:dbc44582f2f8 243
tecnosys 1:dbc44582f2f8 244 uint8_t mcp2515::readStatus(void) {
tecnosys 0:d8f50b1e384f 245 return readXXStatus_helper(MCP_READ_STATUS);
tecnosys 0:d8f50b1e384f 246 }
tecnosys 0:d8f50b1e384f 247
tecnosys 1:dbc44582f2f8 248 uint8_t mcp2515::RXStatus(void) {
tecnosys 0:d8f50b1e384f 249 return readXXStatus_helper(MCP_RX_STATUS);
tecnosys 0:d8f50b1e384f 250 }
tecnosys 0:d8f50b1e384f 251
tecnosys 0:d8f50b1e384f 252 // read-modify-write - better: Bit Modify Instruction
tecnosys 1:dbc44582f2f8 253 uint8_t mcp2515::setCANCTRL_Mode(uint8_t newmode) {
tecnosys 1:dbc44582f2f8 254
tecnosys 0:d8f50b1e384f 255 uint8_t i;
tecnosys 1:dbc44582f2f8 256
tecnosys 0:d8f50b1e384f 257 i = readRegister(MCP_CANCTRL);
tecnosys 0:d8f50b1e384f 258 i &= ~(MODE_MASK);
tecnosys 0:d8f50b1e384f 259 i |= newmode;
tecnosys 0:d8f50b1e384f 260 setRegister(MCP_CANCTRL, i);
tecnosys 1:dbc44582f2f8 261
tecnosys 0:d8f50b1e384f 262 // verify as advised in datasheet
tecnosys 0:d8f50b1e384f 263 i = readRegister(MCP_CANCTRL);
tecnosys 0:d8f50b1e384f 264 i &= MODE_MASK;
tecnosys 0:d8f50b1e384f 265 if ( i == newmode ) {
tecnosys 1:dbc44582f2f8 266 return MCP2515_OK;
tecnosys 1:dbc44582f2f8 267 } else {
tecnosys 0:d8f50b1e384f 268 return MCP2515_FAIL;
tecnosys 0:d8f50b1e384f 269 }
tecnosys 1:dbc44582f2f8 270
tecnosys 0:d8f50b1e384f 271 }
tecnosys 0:d8f50b1e384f 272
tecnosys 0:d8f50b1e384f 273
tecnosys 1:dbc44582f2f8 274 void mcp2515::setRegisterS( uint8_t address,
tecnosys 1:dbc44582f2f8 275 uint8_t values[], uint8_t n) {
tecnosys 0:d8f50b1e384f 276 uint8_t i;
tecnosys 1:dbc44582f2f8 277
tecnosys 0:d8f50b1e384f 278 _select();
tecnosys 0:d8f50b1e384f 279 _spi_readwrite(MCP_WRITE);
tecnosys 0:d8f50b1e384f 280 _spi_readwrite(address);
tecnosys 0:d8f50b1e384f 281 // mcp2515 has auto-increment of address-pointer
tecnosys 0:d8f50b1e384f 282 for (i=0; i<n; i++) {
tecnosys 0:d8f50b1e384f 283 _spi_readwrite(values[i]);
tecnosys 0:d8f50b1e384f 284 }
tecnosys 0:d8f50b1e384f 285 _deselect();
tecnosys 0:d8f50b1e384f 286 }
tecnosys 0:d8f50b1e384f 287
tecnosys 1:dbc44582f2f8 288 void mcp2515::read_can_id( uint8_t mcp_addr,
tecnosys 1:dbc44582f2f8 289 uint8_t* ext, uint32_t* can_id ) {
tecnosys 0:d8f50b1e384f 290 uint8_t tbufdata[4];
tecnosys 1:dbc44582f2f8 291
tecnosys 0:d8f50b1e384f 292 *ext = 0;
tecnosys 0:d8f50b1e384f 293 *can_id = 0;
tecnosys 1:dbc44582f2f8 294
tecnosys 0:d8f50b1e384f 295 readRegisterS( mcp_addr, tbufdata, 4 );
tecnosys 1:dbc44582f2f8 296
tecnosys 0:d8f50b1e384f 297 *can_id = (tbufdata[MCP_SIDH]<<3) + (tbufdata[MCP_SIDL]>>5);
tecnosys 1:dbc44582f2f8 298
tecnosys 0:d8f50b1e384f 299 if ( (tbufdata[MCP_SIDL] & MCP_TXB_EXIDE_M) == MCP_TXB_EXIDE_M ) {
tecnosys 0:d8f50b1e384f 300 // extended id
tecnosys 0:d8f50b1e384f 301 *can_id = (*can_id<<2) + (tbufdata[MCP_SIDL] & 0x03);
tecnosys 0:d8f50b1e384f 302 *can_id <<= 16;
tecnosys 0:d8f50b1e384f 303 *can_id = *can_id +(tbufdata[MCP_EID8]<<8) + tbufdata[MCP_EID0];
tecnosys 0:d8f50b1e384f 304 *ext = 1;
tecnosys 0:d8f50b1e384f 305 }
tecnosys 0:d8f50b1e384f 306 }
tecnosys 0:d8f50b1e384f 307
tecnosys 0:d8f50b1e384f 308
tecnosys 1:dbc44582f2f8 309 void mcp2515::read_can_idN( uint8_t mcp_addr,
tecnosys 1:dbc44582f2f8 310 CANFormat* ext, unsigned int* can_id ) {
tecnosys 1:dbc44582f2f8 311 uint8_t tbufdata[4];
tecnosys 1:dbc44582f2f8 312
tecnosys 1:dbc44582f2f8 313 *ext = CANStandard;
tecnosys 1:dbc44582f2f8 314 *can_id = 0;
tecnosys 1:dbc44582f2f8 315
tecnosys 1:dbc44582f2f8 316 readRegisterS( mcp_addr, tbufdata, 4 );
tecnosys 1:dbc44582f2f8 317
tecnosys 1:dbc44582f2f8 318 *can_id = (tbufdata[MCP_SIDH]<<3) + (tbufdata[MCP_SIDL]>>5);
tecnosys 1:dbc44582f2f8 319
tecnosys 1:dbc44582f2f8 320 if ( (tbufdata[MCP_SIDL] & MCP_TXB_EXIDE_M) == MCP_TXB_EXIDE_M ) {
tecnosys 1:dbc44582f2f8 321 // extended id
tecnosys 1:dbc44582f2f8 322 *can_id = (*can_id<<2) + (tbufdata[MCP_SIDL] & 0x03);
tecnosys 1:dbc44582f2f8 323 *can_id <<= 16;
tecnosys 1:dbc44582f2f8 324 *can_id = *can_id +(tbufdata[MCP_EID8]<<8) + tbufdata[MCP_EID0];
tecnosys 1:dbc44582f2f8 325 *ext = CANExtended;//1;
tecnosys 1:dbc44582f2f8 326 }
tecnosys 1:dbc44582f2f8 327 }
tecnosys 1:dbc44582f2f8 328
tecnosys 0:d8f50b1e384f 329 // Buffer can be MCP_RXBUF_0 or MCP_RXBUF_1
tecnosys 1:dbc44582f2f8 330 void mcp2515::read_canMsg( uint8_t buffer_sidh_addr, CANMessage* msg)
tecnosys 1:dbc44582f2f8 331 //CANMessage mcp2515::read_canMsg( uint8_t buffer_sidh_addr)
tecnosys 0:d8f50b1e384f 332 {
tecnosys 1:dbc44582f2f8 333 uint8_t mcp_addr, ctrl,dlc;
tecnosys 1:dbc44582f2f8 334
tecnosys 1:dbc44582f2f8 335
tecnosys 0:d8f50b1e384f 336
tecnosys 0:d8f50b1e384f 337 mcp_addr = buffer_sidh_addr;
tecnosys 1:dbc44582f2f8 338
tecnosys 1:dbc44582f2f8 339 read_can_idN( mcp_addr, &msg->format, &msg->id );
tecnosys 1:dbc44582f2f8 340
tecnosys 0:d8f50b1e384f 341 ctrl = readRegister( mcp_addr-1 );
tecnosys 1:dbc44582f2f8 342 dlc = readRegister( mcp_addr+4 );
tecnosys 1:dbc44582f2f8 343
tecnosys 0:d8f50b1e384f 344 //if ((*dlc & RTR_MASK) || (ctrl & 0x08)) {
tecnosys 0:d8f50b1e384f 345 if ((ctrl & 0x08)) {
tecnosys 1:dbc44582f2f8 346 msg->type = CANRemote; //1 CANRemote
tecnosys 0:d8f50b1e384f 347 } else {
tecnosys 1:dbc44582f2f8 348 msg->type = CANData; //0 CANData
tecnosys 0:d8f50b1e384f 349 }
tecnosys 1:dbc44582f2f8 350
tecnosys 1:dbc44582f2f8 351 dlc &= MCP_DLC_MASK;
tecnosys 1:dbc44582f2f8 352 readRegisterS( mcp_addr+5, &(msg->data[0]), dlc );
tecnosys 1:dbc44582f2f8 353 msg->len =dlc;
tecnosys 1:dbc44582f2f8 354
tecnosys 0:d8f50b1e384f 355 }
tecnosys 0:d8f50b1e384f 356
tecnosys 1:dbc44582f2f8 357 void mcp2515::setDebugConsole(Serial c){
tecnosys 1:dbc44582f2f8 358 //console=c;
tecnosys 1:dbc44582f2f8 359 debug=true;
tecnosys 1:dbc44582f2f8 360 }
tecnosys 0:d8f50b1e384f 361
tecnosys 1:dbc44582f2f8 362 void mcp2515::write_can_id( uint8_t mcp_addr,
tecnosys 1:dbc44582f2f8 363 uint8_t ext, uint32_t can_id ) {
tecnosys 0:d8f50b1e384f 364 uint16_t canid;
tecnosys 0:d8f50b1e384f 365 uint8_t tbufdata[4];
tecnosys 1:dbc44582f2f8 366
tecnosys 0:d8f50b1e384f 367 canid = (uint16_t)(can_id & 0x0FFFF);
tecnosys 1:dbc44582f2f8 368
tecnosys 0:d8f50b1e384f 369 if ( ext == 1) {
tecnosys 0:d8f50b1e384f 370 tbufdata[MCP_EID0] = (uint8_t) (canid & 0xFF);
tecnosys 0:d8f50b1e384f 371 tbufdata[MCP_EID8] = (uint8_t) (canid / 256);
tecnosys 0:d8f50b1e384f 372 canid = (uint16_t)( can_id / 0x10000L );
tecnosys 0:d8f50b1e384f 373 tbufdata[MCP_SIDL] = (uint8_t) (canid & 0x03);
tecnosys 0:d8f50b1e384f 374 tbufdata[MCP_SIDL] += (uint8_t) ((canid & 0x1C )*8);
tecnosys 0:d8f50b1e384f 375 tbufdata[MCP_SIDL] |= MCP_TXB_EXIDE_M;
tecnosys 0:d8f50b1e384f 376 tbufdata[MCP_SIDH] = (uint8_t) (canid / 32 );
tecnosys 1:dbc44582f2f8 377 } else {
tecnosys 0:d8f50b1e384f 378 tbufdata[MCP_SIDH] = (uint8_t) (canid / 8 );
tecnosys 0:d8f50b1e384f 379 tbufdata[MCP_SIDL] = (uint8_t) ((canid & 0x07 )*32);
tecnosys 0:d8f50b1e384f 380 tbufdata[MCP_EID0] = 0;
tecnosys 0:d8f50b1e384f 381 tbufdata[MCP_EID8] = 0;
tecnosys 0:d8f50b1e384f 382 }
tecnosys 0:d8f50b1e384f 383 setRegisterS( mcp_addr, tbufdata, 4 );
tecnosys 0:d8f50b1e384f 384 }
tecnosys 0:d8f50b1e384f 385
tecnosys 0:d8f50b1e384f 386 // Buffer can be MCP_TXBUF_0 MCP_TXBUF_1 or MCP_TXBUF_2
tecnosys 1:dbc44582f2f8 387 void mcp2515::write_canMsg( uint8_t buffer_sidh_addr,
tecnosys 1:dbc44582f2f8 388 CANMessage* msg) {
tecnosys 0:d8f50b1e384f 389 uint8_t mcp_addr, dlc;
tecnosys 0:d8f50b1e384f 390
tecnosys 0:d8f50b1e384f 391 mcp_addr = buffer_sidh_addr;
tecnosys 0:d8f50b1e384f 392 dlc = msg->len;
tecnosys 1:dbc44582f2f8 393
tecnosys 0:d8f50b1e384f 394 setRegisterS(mcp_addr+5, &(msg->data[0]), dlc ); // write data bytes
tecnosys 0:d8f50b1e384f 395 write_can_id( mcp_addr, msg->format,
tecnosys 1:dbc44582f2f8 396 msg->id ); // write CAN id
tecnosys 0:d8f50b1e384f 397 if ( msg->type == 1) dlc |= MCP_RTR_MASK; // if RTR set bit in byte
tecnosys 0:d8f50b1e384f 398 setRegister( (mcp_addr+4), dlc ); // write the RTR and DLC
tecnosys 0:d8f50b1e384f 399 }
tecnosys 0:d8f50b1e384f 400
tecnosys 1:dbc44582f2f8 401 void mcp2515::start_transmit( uint8_t buffer_sidh_addr) {
tecnosys 1:dbc44582f2f8 402 // TXBnCTRL_addr = TXBnSIDH_addr - 1
tecnosys 1:dbc44582f2f8 403 modifyRegister( buffer_sidh_addr-1 , MCP_TXB_TXREQ_M,
tecnosys 1:dbc44582f2f8 404 MCP_TXB_TXREQ_M );
tecnosys 0:d8f50b1e384f 405 }
tecnosys 0:d8f50b1e384f 406
tecnosys 1:dbc44582f2f8 407 uint8_t mcp2515::getNextFreeTXBuf(uint8_t *txbuf_n) {
tecnosys 1:dbc44582f2f8 408 uint8_t res, i, ctrlval;
tecnosys 1:dbc44582f2f8 409 uint8_t ctrlregs[MCP_N_TXBUFFERS] = { MCP_TXB0CTRL, MCP_TXB1CTRL, MCP_TXB2CTRL };
tecnosys 1:dbc44582f2f8 410
tecnosys 1:dbc44582f2f8 411 res = MCP_ALLTXBUSY;
tecnosys 1:dbc44582f2f8 412 *txbuf_n = 0x00;
tecnosys 0:d8f50b1e384f 413
tecnosys 1:dbc44582f2f8 414 // check all 3 TX-Buffers
tecnosys 1:dbc44582f2f8 415 for (i=0; i<MCP_N_TXBUFFERS; i++) {
tecnosys 1:dbc44582f2f8 416 ctrlval = readRegister( ctrlregs[i] );
tecnosys 1:dbc44582f2f8 417 if ( (ctrlval & MCP_TXB_TXREQ_M) == 0 ) {
tecnosys 1:dbc44582f2f8 418
tecnosys 1:dbc44582f2f8 419 *txbuf_n = ctrlregs[i]+1; // return SIDH-address of Buffer
tecnosys 1:dbc44582f2f8 420 res = MCP2515_OK;
tecnosys 1:dbc44582f2f8 421 return res; /* ! function exit */
tecnosys 1:dbc44582f2f8 422 }
tecnosys 1:dbc44582f2f8 423 }
tecnosys 1:dbc44582f2f8 424
tecnosys 1:dbc44582f2f8 425 return res;
tecnosys 0:d8f50b1e384f 426 }
tecnosys 0:d8f50b1e384f 427
tecnosys 1:dbc44582f2f8 428 void mcp2515::initCANBuffers(void) {
tecnosys 1:dbc44582f2f8 429 // uint8_t i, a1, a2, a3;
tecnosys 1:dbc44582f2f8 430
tecnosys 1:dbc44582f2f8 431 // TODO: check why this is needed to receive extended
tecnosys 0:d8f50b1e384f 432 // and standard frames
tecnosys 0:d8f50b1e384f 433 // Mark all filter bits as don't care:
tecnosys 0:d8f50b1e384f 434 write_can_id(MCP_RXM0SIDH, 0, 0);
tecnosys 0:d8f50b1e384f 435 write_can_id(MCP_RXM1SIDH, 0, 0);
tecnosys 0:d8f50b1e384f 436 // Anyway, set all filters to 0:
tecnosys 1:dbc44582f2f8 437 write_can_id(MCP_RXF0SIDH, 1, 0); // RXB0: extended
tecnosys 0:d8f50b1e384f 438 write_can_id(MCP_RXF1SIDH, 0, 0); // AND standard
tecnosys 1:dbc44582f2f8 439 write_can_id(MCP_RXF2SIDH, 1, 0); // RXB1: extended
tecnosys 0:d8f50b1e384f 440 write_can_id(MCP_RXF3SIDH, 0, 0); // AND standard
tecnosys 0:d8f50b1e384f 441 write_can_id(MCP_RXF4SIDH, 0, 0);
tecnosys 0:d8f50b1e384f 442 write_can_id(MCP_RXF5SIDH, 0, 0);
tecnosys 1:dbc44582f2f8 443 /*
tecnosys 0:d8f50b1e384f 444 // Clear, deactivate the three transmit buffers
tecnosys 0:d8f50b1e384f 445 // TXBnCTRL -> TXBnD7
tecnosys 0:d8f50b1e384f 446 a1 = MCP_TXB0CTRL;
tecnosys 0:d8f50b1e384f 447 a2 = MCP_TXB1CTRL;
tecnosys 0:d8f50b1e384f 448 a3 = MCP_TXB2CTRL;
tecnosys 0:d8f50b1e384f 449 for (i = 0; i < 14; i++) { // in-buffer loop
tecnosys 0:d8f50b1e384f 450 setRegister(a1, 0);
tecnosys 0:d8f50b1e384f 451 setRegister(a2, 0);
tecnosys 0:d8f50b1e384f 452 setRegister(a3, 0);
tecnosys 0:d8f50b1e384f 453 a1++;
tecnosys 0:d8f50b1e384f 454 a2++;
tecnosys 0:d8f50b1e384f 455 a3++;
tecnosys 0:d8f50b1e384f 456 }
tecnosys 1:dbc44582f2f8 457 */
tecnosys 0:d8f50b1e384f 458 // and clear, deactivate the two receive buffers.
tecnosys 1:dbc44582f2f8 459 // setRegister(MCP_RXB0CTRL, 0);
tecnosys 1:dbc44582f2f8 460 //setRegister(MCP_RXB1CTRL, 0);
tecnosys 0:d8f50b1e384f 461 }
tecnosys 0:d8f50b1e384f 462
driscoll85 13:ff12c7f532f9 463 uint8_t mcp2515::init(int canSpeed) {
tecnosys 0:d8f50b1e384f 464 uint8_t res;
tecnosys 1:dbc44582f2f8 465
tecnosys 0:d8f50b1e384f 466 _deselect();
tecnosys 0:d8f50b1e384f 467 //MCP_CS_DDR |= ( 1 << MCP_CS_BIT );
tecnosys 1:dbc44582f2f8 468
tecnosys 0:d8f50b1e384f 469 _reset();
tecnosys 1:dbc44582f2f8 470
tecnosys 0:d8f50b1e384f 471
tecnosys 0:d8f50b1e384f 472 res = setCANCTRL_Mode(MODE_CONFIG);
tecnosys 1:dbc44582f2f8 473
tecnosys 1:dbc44582f2f8 474 if ( res == MCP2515_FAIL ) {
tecnosys 1:dbc44582f2f8 475 printf("\r\nCAN init failed %d\n\r",&_ncs);
tecnosys 1:dbc44582f2f8 476 return res; /* function exit on error */
tecnosys 0:d8f50b1e384f 477 }
tecnosys 1:dbc44582f2f8 478 res = configRate2(canSpeed);
driscoll85 10:6d6fd99da044 479 //res = configRate(CAN_500KBPS_10MHz);
tecnosys 1:dbc44582f2f8 480
tecnosys 0:d8f50b1e384f 481 if ( res == MCP2515_OK ) {
tecnosys 0:d8f50b1e384f 482 initCANBuffers();
tecnosys 1:dbc44582f2f8 483
tecnosys 0:d8f50b1e384f 484 // enable both receive-buffers to receive messages
tecnosys 0:d8f50b1e384f 485 // with std. and ext. identifiers
tecnosys 0:d8f50b1e384f 486 // and enable rollover
tecnosys 1:dbc44582f2f8 487 modifyRegister(MCP_RXB0CTRL,
tecnosys 1:dbc44582f2f8 488 MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK,
tecnosys 1:dbc44582f2f8 489 MCP_RXB_RX_STDEXT | MCP_RXB_BUKT_MASK );
tecnosys 1:dbc44582f2f8 490 modifyRegister(MCP_RXB1CTRL, MCP_RXB_RX_MASK,
tecnosys 1:dbc44582f2f8 491 MCP_RXB_RX_STDEXT);
tecnosys 0:d8f50b1e384f 492
tecnosys 1:dbc44582f2f8 493 // Prescaler setting of the CLKOUT pin to zero
tecnosys 1:dbc44582f2f8 494 // => Spending clock frequency of the CLKOUT pin MCP2515
tecnosys 1:dbc44582f2f8 495 modifyRegister (MCP_CANCTRL, 0x07, CLKOUT_ENABLE);
tecnosys 0:d8f50b1e384f 496 }
tecnosys 1:dbc44582f2f8 497
tecnosys 0:d8f50b1e384f 498 return res;
tecnosys 0:d8f50b1e384f 499 }
tecnosys 0:d8f50b1e384f 500
tecnosys 0:d8f50b1e384f 501 /*
tecnosys 0:d8f50b1e384f 502 * Select function
tecnosys 0:d8f50b1e384f 503 */
tecnosys 1:dbc44582f2f8 504
tecnosys 0:d8f50b1e384f 505 void mcp2515::_select() {
tecnosys 0:d8f50b1e384f 506 //printf("{");
tecnosys 0:d8f50b1e384f 507 _ncs = 0;
tecnosys 0:d8f50b1e384f 508 }
tecnosys 0:d8f50b1e384f 509
tecnosys 0:d8f50b1e384f 510
tecnosys 0:d8f50b1e384f 511 /*
tecnosys 0:d8f50b1e384f 512 * Deselect function
tecnosys 0:d8f50b1e384f 513 */
tecnosys 0:d8f50b1e384f 514
tecnosys 0:d8f50b1e384f 515 void mcp2515::_deselect() {
tecnosys 0:d8f50b1e384f 516 _ncs = 1;
tecnosys 0:d8f50b1e384f 517 //printf("}");
tecnosys 0:d8f50b1e384f 518 }
tecnosys 0:d8f50b1e384f 519
tecnosys 0:d8f50b1e384f 520 int mcp2515::status() {
tecnosys 0:d8f50b1e384f 521 int status = 0;
tecnosys 0:d8f50b1e384f 522 _select();
tecnosys 1:dbc44582f2f8 523 spi.write(0xd7);
tecnosys 1:dbc44582f2f8 524 status = (spi.write(0x00) << 8 );
tecnosys 1:dbc44582f2f8 525 status |= spi.write(0x00);
tecnosys 0:d8f50b1e384f 526 _deselect();
tecnosys 0:d8f50b1e384f 527 return status;
tecnosys 0:d8f50b1e384f 528 }
tecnosys 0:d8f50b1e384f 529
tecnosys 0:d8f50b1e384f 530 void mcp2515::_pollbusy() {
tecnosys 0:d8f50b1e384f 531 volatile int busy = 1;
tecnosys 0:d8f50b1e384f 532 while (busy) {
tecnosys 0:d8f50b1e384f 533 // if bit 7 is set, we can proceed
tecnosys 0:d8f50b1e384f 534 if ( status() & 0x80 ) {
tecnosys 0:d8f50b1e384f 535 busy = 0;
tecnosys 0:d8f50b1e384f 536 }
tecnosys 0:d8f50b1e384f 537 }
tecnosys 0:d8f50b1e384f 538 }
tecnosys 0:d8f50b1e384f 539
tecnosys 0:d8f50b1e384f 540
tecnosys 1:dbc44582f2f8 541 uint8_t mcp2515::_spi_readwrite(uint8_t data) {
tecnosys 1:dbc44582f2f8 542 //printf("W0x%x ", data);
tecnosys 1:dbc44582f2f8 543 uint8_t ret = spi.write(data);
tecnosys 1:dbc44582f2f8 544 // printf("R0x%x,", ret);
tecnosys 0:d8f50b1e384f 545 return ret;
tecnosys 0:d8f50b1e384f 546 }
tecnosys 0:d8f50b1e384f 547
tecnosys 1:dbc44582f2f8 548 uint8_t mcp2515::_spi_read(void) {
tecnosys 0:d8f50b1e384f 549 return _spi_readwrite(SPI_NULL);
tecnosys 0:d8f50b1e384f 550 }
tecnosys 1:dbc44582f2f8 551
tecnosys 1:dbc44582f2f8 552 void mcp2515::dumpExtendedStatus(void) {
tecnosys 1:dbc44582f2f8 553 uint8_t tec, rec, eflg;
tecnosys 1:dbc44582f2f8 554
tecnosys 1:dbc44582f2f8 555 tec = readRegister(MCP_TEC);
tecnosys 1:dbc44582f2f8 556 rec = readRegister(MCP_REC);
tecnosys 1:dbc44582f2f8 557 eflg = readRegister(MCP_EFLG);
tecnosys 1:dbc44582f2f8 558
tecnosys 1:dbc44582f2f8 559 printf("MCP2515 Extended Status:\n\r");
tecnosys 1:dbc44582f2f8 560 printf("MCP Transmit Error Count %d \r\n", tec);
tecnosys 1:dbc44582f2f8 561 printf("MCP Receiver Error Count %d \n\r", rec);
tecnosys 1:dbc44582f2f8 562 printf("MCP Error Flag %d\n\r", eflg);
tecnosys 1:dbc44582f2f8 563
tecnosys 1:dbc44582f2f8 564 if ( (rec>127) || (tec>127) ) {
tecnosys 1:dbc44582f2f8 565 printf("Error-Passive or Bus-Off\n\r");
tecnosys 1:dbc44582f2f8 566 }
tecnosys 1:dbc44582f2f8 567
tecnosys 1:dbc44582f2f8 568 if (eflg & MCP_EFLG_RX1OVR)
tecnosys 1:dbc44582f2f8 569 printf("Receive Buffer 1 Overflow\r\n");
tecnosys 1:dbc44582f2f8 570 if (eflg & MCP_EFLG_RX0OVR)
tecnosys 1:dbc44582f2f8 571 printf("Receive Buffer 0 Overflow\n\r");
tecnosys 1:dbc44582f2f8 572 if (eflg & MCP_EFLG_TXBO)
tecnosys 1:dbc44582f2f8 573 printf("Bus-Off\n\r");
tecnosys 1:dbc44582f2f8 574 if (eflg & MCP_EFLG_TXEP)
tecnosys 1:dbc44582f2f8 575 printf("Receive Error Passive\n\r");
tecnosys 1:dbc44582f2f8 576 if (eflg & MCP_EFLG_TXWAR)
tecnosys 1:dbc44582f2f8 577 printf("Transmit Error Warning\n\r");
tecnosys 1:dbc44582f2f8 578 if (eflg & MCP_EFLG_RXWAR)
tecnosys 1:dbc44582f2f8 579 printf("Receive Error Warning\r\n");
tecnosys 1:dbc44582f2f8 580 if (eflg & MCP_EFLG_EWARN )
tecnosys 1:dbc44582f2f8 581 printf("Receive Error Warning\n\r");
tecnosys 1:dbc44582f2f8 582 }