Dependents:   Kamal_CAN ReadFromSerial446 USNA-UMBC-KF-02_v3-noise USNA-UMBC-KF-01

Revision:
0:d8f50b1e384f
Child:
1:dbc44582f2f8
diff -r 000000000000 -r d8f50b1e384f mcp2515.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcp2515.cpp	Sat Jan 30 08:46:04 2010 +0000
@@ -0,0 +1,452 @@
+/******************************************************************************
+ * 
+ * Controller Area Network (CAN) Demo-Application
+ * Atmel AVR with Microchip MCP2515 
+ * 
+ * Copyright (C) 2005 Martin THOMAS, Kaiserslautern, Germany
+ * <eversmith@heizung-thomas.de>
+ * http://www.siwawi.arubi.uni-kl.de/avr_projects
+ *
+ *****************************************************************************
+ *
+ * File    : mcp2515.c
+ * Version : 0.9
+ * 
+ * Summary : MCP2515 "low-level" driver
+ *
+ * Parts of this code are adapted from a MCP2510 sample-application 
+ * by KVASER AB, http://www.kvaser.com (KVASER-code is marked as free)
+ *
+ * This code-module is free to use but you have to keep the copyright
+ * notice.
+ *
+ *
+ *****************************************************************************
+ *
+ * File    : mcp2515.cpp (mbed LPC1768 version)
+ * Version : 0.1
+ *
+ * All credits to the nerds above, this source has been adapted for the 
+ * LPC1768 platform by J.Engelman. And does'nt require and of the copyrighted
+ * SPI or AVR controller code that Martin or co have excluded copyright.
+ * This module remains free.
+ *
+ *
+ *****************************************************************************/
+
+#include "mcp2515.h"
+
+#include <mbed.h>
+#include "mcp2515_can.h"
+#include "mcp2515_defs.h"
+#include "mcp2515_bittime.h"
+
+#define SPI_NULL (0x00)
+
+
+
+mcp2515::mcp2515(PinName mosi, PinName miso, PinName clk, PinName ncs)
+        : _spi(mosi, miso, clk), _ncs(ncs) {
+
+     // _spi.format(8,0);
+     // _spi.frequency(10000000);
+    //_spi.frequency(5000000);
+
+}
+
+
+void mcp2515::_reset() {
+
+    _select();
+    _spi_readwrite(MCP_RESET);
+    _deselect();
+    wait(0.001);
+}
+
+void mcp2515::setRegister(const uint8_t address, const uint8_t value)
+{
+    _select();
+    _spi_readwrite(MCP_WRITE);
+    _spi_readwrite(address);
+    _spi_readwrite(value);
+    _deselect();
+}
+
+uint8_t mcp2515::configRate(const uint8_t canSpeed)
+{
+    uint8_t set, cfg1, cfg2, cfg3;
+    
+    set = 0;
+    
+    switch (canSpeed) {
+        case (CAN_125KBPS) :
+            cfg1 = MCP_4MHz_125kBPS_CFG1 ;
+            cfg2 = MCP_4MHz_125kBPS_CFG2 ;
+            cfg3 = MCP_4MHz_125kBPS_CFG3 ;
+            set = 1;
+            break;
+        case (CAN_20KBPS) :
+            cfg1 = MCP_4MHz_20kBPS_CFG1 ;
+            cfg2 = MCP_4MHz_20kBPS_CFG2 ;
+            cfg3 = MCP_4MHz_20kBPS_CFG3 ;
+            set = 1;
+            break;
+        default:
+            set = 0;
+            break;
+    }
+    
+    if (set) {
+        setRegister(MCP_CNF1, cfg1);
+        setRegister(MCP_CNF2, cfg2);
+        setRegister(MCP_CNF3, cfg3);
+        return MCP2515_OK;
+    }
+    else {
+        return MCP2515_FAIL;
+    }
+} 
+
+uint8_t mcp2515::readRegister(const uint8_t address)
+{
+    uint8_t ret;
+    
+    _select();
+    _spi_readwrite(MCP_READ);
+    _spi_readwrite(address);
+    ret = _spi_read();
+    _deselect();
+    
+    return ret;
+}
+
+void mcp2515::readRegisterS(const uint8_t address, 
+    uint8_t values[], const uint8_t n)
+{
+    uint8_t i;
+    
+    _select();
+    _spi_readwrite(MCP_READ);
+    _spi_readwrite(address);
+    // mcp2515 has auto-increment of address-pointer
+    for (i=0; i<n; i++) {
+        values[i] = _spi_read();
+    }
+    _deselect();
+}
+
+void mcp2515::modifyRegister(const uint8_t address, 
+    const uint8_t mask, const uint8_t data)
+{
+    _select();
+    _spi_readwrite(MCP_BITMOD);
+    _spi_readwrite(address);
+    _spi_readwrite(mask);
+    _spi_readwrite(data);
+    _deselect();
+}
+
+
+uint8_t mcp2515::readXXStatus_helper(const uint8_t cmd)
+{
+    uint8_t i;
+    
+    _select();
+    _spi_readwrite(cmd);
+    i = _spi_read();
+    _deselect();
+    
+    return i;
+}
+    
+uint8_t mcp2515::readStatus(void)
+{
+    return readXXStatus_helper(MCP_READ_STATUS);
+}
+
+uint8_t mcp2515::RXStatus(void)
+{
+    return readXXStatus_helper(MCP_RX_STATUS);
+}
+
+// read-modify-write - better: Bit Modify Instruction
+uint8_t mcp2515::setCANCTRL_Mode(uint8_t newmode)
+{
+    uint8_t i;
+    
+    i = readRegister(MCP_CANCTRL);
+    i &= ~(MODE_MASK);
+    i |= newmode;
+    setRegister(MCP_CANCTRL, i);
+    
+    // verify as advised in datasheet
+    i = readRegister(MCP_CANCTRL);
+    i &= MODE_MASK;
+    if ( i == newmode ) {
+        return MCP2515_OK; 
+    }
+    else {
+        return MCP2515_FAIL;
+    }
+}
+
+
+void mcp2515::setRegisterS(const uint8_t address, 
+    const uint8_t values[], const uint8_t n)
+{
+    uint8_t i;
+    
+    _select();
+    _spi_readwrite(MCP_WRITE);
+    _spi_readwrite(address);
+    // mcp2515 has auto-increment of address-pointer
+    for (i=0; i<n; i++) {
+        _spi_readwrite(values[i]);
+    }
+    _deselect();
+}
+
+void mcp2515::read_can_id( const uint8_t mcp_addr, 
+    uint8_t* ext, uint32_t* can_id )
+{
+    uint8_t tbufdata[4];
+    
+    *ext = 0;
+    *can_id = 0;
+    
+    readRegisterS( mcp_addr, tbufdata, 4 );
+    
+    *can_id = (tbufdata[MCP_SIDH]<<3) + (tbufdata[MCP_SIDL]>>5);
+    
+    if ( (tbufdata[MCP_SIDL] & MCP_TXB_EXIDE_M) ==  MCP_TXB_EXIDE_M ) {
+        // extended id
+        *can_id = (*can_id<<2) + (tbufdata[MCP_SIDL] & 0x03);
+        *can_id <<= 16;
+        *can_id = *can_id +(tbufdata[MCP_EID8]<<8) + tbufdata[MCP_EID0];
+        *ext = 1;
+    }
+}
+
+
+// Buffer can be MCP_RXBUF_0 or MCP_RXBUF_1
+void mcp2515::read_canMsg( const uint8_t buffer_sidh_addr,
+    CANMessage* msg)
+{
+/*
+    uint8_t mcp_addr, ctrl;
+
+    mcp_addr = buffer_sidh_addr;
+    
+    read_can_id( mcp_addr, &(msg->extended_identifier), 
+        &(msg->identifier) );
+    
+    ctrl = readRegister( mcp_addr-1 );
+    msg->dlc = readRegister( mcp_addr+4 );
+    
+    //if ((*dlc & RTR_MASK) || (ctrl & 0x08)) {
+    if ((ctrl & 0x08)) {
+        msg->rtr = 1;
+    } else {
+        msg->rtr = 0;
+    }
+    
+    msg->dlc &= MCP_DLC_MASK;
+    readRegisterS( mcp_addr+5, &(msg->dta[0]), msg->dlc );
+    */
+}
+
+
+void mcp2515::write_can_id( const uint8_t mcp_addr, 
+    const uint8_t ext, const uint32_t can_id )
+{
+    uint16_t canid;
+    uint8_t tbufdata[4];
+    
+    canid = (uint16_t)(can_id & 0x0FFFF);
+    
+    if ( ext == 1) {
+        tbufdata[MCP_EID0] = (uint8_t) (canid & 0xFF);
+        tbufdata[MCP_EID8] = (uint8_t) (canid / 256);
+        canid = (uint16_t)( can_id / 0x10000L );
+        tbufdata[MCP_SIDL] = (uint8_t) (canid & 0x03);
+        tbufdata[MCP_SIDL] += (uint8_t) ((canid & 0x1C )*8);
+        tbufdata[MCP_SIDL] |= MCP_TXB_EXIDE_M;
+        tbufdata[MCP_SIDH] = (uint8_t) (canid / 32 );
+    }
+    else {
+        tbufdata[MCP_SIDH] = (uint8_t) (canid / 8 );
+        tbufdata[MCP_SIDL] = (uint8_t) ((canid & 0x07 )*32);
+        tbufdata[MCP_EID0] = 0;
+        tbufdata[MCP_EID8] = 0;
+    }
+    setRegisterS( mcp_addr, tbufdata, 4 );
+}
+
+// Buffer can be MCP_TXBUF_0 MCP_TXBUF_1 or MCP_TXBUF_2
+void mcp2515::write_canMsg( const uint8_t buffer_sidh_addr, 
+     CANMessage* msg)
+{
+    uint8_t mcp_addr, dlc;
+
+    mcp_addr = buffer_sidh_addr;
+    dlc = msg->len;
+    
+    setRegisterS(mcp_addr+5, &(msg->data[0]), dlc );  // write data bytes
+    write_can_id( mcp_addr, msg->format,
+        msg->id );  // write CAN id
+    if ( msg->type == 1)  dlc |= MCP_RTR_MASK;  // if RTR set bit in byte
+    setRegister( (mcp_addr+4), dlc );  // write the RTR and DLC
+}
+
+void mcp2515::start_transmit(const uint8_t buffer_sidh_addr)
+{
+	// TXBnCTRL_addr = TXBnSIDH_addr - 1
+   modifyRegister( buffer_sidh_addr-1 , MCP_TXB_TXREQ_M, 
+		MCP_TXB_TXREQ_M );
+}
+
+uint8_t mcp2515::getNextFreeTXBuf(uint8_t *txbuf_n)
+{
+	uint8_t res, i, ctrlval;
+	uint8_t ctrlregs[MCP_N_TXBUFFERS] = { MCP_TXB0CTRL, MCP_TXB1CTRL, MCP_TXB2CTRL };
+	
+	res = MCP_ALLTXBUSY;
+	*txbuf_n = 0x00;
+	
+	// check all 3 TX-Buffers
+	for (i=0; i<MCP_N_TXBUFFERS; i++) {
+		ctrlval = readRegister( ctrlregs[i] );
+		if ( (ctrlval & MCP_TXB_TXREQ_M) == 0 ) {
+
+			*txbuf_n = ctrlregs[i]+1; // return SIDH-address of Buffer
+			res = MCP2515_OK;
+			return res; /* ! function exit */
+		}
+	}
+	
+	return res;
+}
+
+void mcp2515::initCANBuffers(void)
+{
+    uint8_t i, a1, a2, a3;
+    
+    // TODO: check why this is needed to receive extended 
+    //   and standard frames
+    // Mark all filter bits as don't care:
+    write_can_id(MCP_RXM0SIDH, 0, 0);
+    write_can_id(MCP_RXM1SIDH, 0, 0);
+    // Anyway, set all filters to 0:
+    write_can_id(MCP_RXF0SIDH, 1, 0); // RXB0: extended 
+    write_can_id(MCP_RXF1SIDH, 0, 0); //       AND standard
+    write_can_id(MCP_RXF2SIDH, 1, 0); // RXB1: extended 
+    write_can_id(MCP_RXF3SIDH, 0, 0); //       AND standard
+    write_can_id(MCP_RXF4SIDH, 0, 0);
+    write_can_id(MCP_RXF5SIDH, 0, 0);
+    
+    // Clear, deactivate the three transmit buffers
+    // TXBnCTRL -> TXBnD7
+    a1 = MCP_TXB0CTRL;
+    a2 = MCP_TXB1CTRL;
+    a3 = MCP_TXB2CTRL;
+    for (i = 0; i < 14; i++) { // in-buffer loop
+        setRegister(a1, 0);
+        setRegister(a2, 0);
+        setRegister(a3, 0);
+        a1++;
+        a2++;
+        a3++;
+    }
+    
+    // and clear, deactivate the two receive buffers.
+    setRegister(MCP_RXB0CTRL, 0);
+    setRegister(MCP_RXB1CTRL, 0);
+}
+
+uint8_t mcp2515::init(const uint8_t canSpeed)
+{
+    uint8_t res;
+    
+    _deselect();
+    //MCP_CS_DDR |= ( 1 << MCP_CS_BIT );
+    
+    _reset();
+    
+    res = setCANCTRL_Mode(MODE_CONFIG);
+    
+    if ( res == MCP2515_FAIL ){
+     printf("FAIL here");
+     return res;  /* function exit on error */
+    }
+    res = configRate(canSpeed);
+    
+    if ( res == MCP2515_OK ) {
+        initCANBuffers();
+        
+
+        // enable both receive-buffers to receive messages
+        // with std. and ext. identifiers
+        // and enable rollover
+        modifyRegister(MCP_RXB0CTRL, 
+            MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK, 
+            MCP_RXB_RX_STDEXT | MCP_RXB_BUKT_MASK );
+        modifyRegister(MCP_RXB1CTRL, MCP_RXB_RX_MASK, 
+            MCP_RXB_RX_STDEXT);
+
+    }
+    
+    return res;
+}
+
+/*
+ * Select function
+ */
+ 
+void mcp2515::_select() {
+//printf("{");
+    _ncs = 0;
+}
+
+
+/*
+ * Deselect function
+ */
+
+void mcp2515::_deselect() {
+    _ncs = 1;
+//printf("}");
+}
+
+int mcp2515::status() {
+    int status = 0;
+    _select();
+    _spi.write(0xd7);
+    status = (_spi.write(0x00) << 8 );
+    status |= _spi.write(0x00);
+    _deselect();
+    return status;
+}
+
+void mcp2515::_pollbusy() {
+    volatile int busy = 1;
+    while (busy) {
+        // if bit 7 is set, we can proceed
+        if ( status() & 0x80 ) {
+            busy = 0;
+        }
+    }
+}
+
+
+uint8_t mcp2515::_spi_readwrite(uint8_t data)
+{
+     //printf("W0x%x ", data);
+      uint8_t ret = _spi.write(data);
+       //     printf("R0x%x,", ret);
+    return ret;
+}
+
+uint8_t mcp2515::_spi_read(void)
+{
+    return _spi_readwrite(SPI_NULL);
+}