mcp2515.c in AVR+mcp2515code.rar


MCP2515 using the CAN communications code, suitable for 8-bit, 16-bit AVR Single...Original Link
    Sponsored links

			
			/******************************************************************************
 * 
 * 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.
 *
 *****************************************************************************/

#include <inttypes.h>

#include "spi.h"
#include "delay.h"
#include "mcp2515.h"
#include "mcp2515_defs.h"
#include "mcp2515_bittime.h"

#include "can.h"

#if (MCPDEBUG)
#include "termio.h"
#include "debughelper.h"
#endif

void mcp2515_reset(void)
{
	MCP2515_SELECT();
	spi_readwrite(MCP_RESET);
	MCP2515_UNSELECT();
	delay_ms(10); // rough - but > 128 MCP clock-cycles
}

uint8_t mcp2515_readRegister(const uint8_t address)
{
	uint8_t ret;
	
	MCP2515_SELECT();
	spi_readwrite(MCP_READ);
	spi_readwrite(address);
	ret = spi_read();
	MCP2515_UNSELECT();
	
	return ret;
}

void mcp2515_readRegisterS(const uint8_t address, 
	uint8_t values[], const uint8_t n)
{
	uint8_t i;
	
	MCP2515_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();
	}
	MCP2515_UNSELECT();
}

void mcp2515_setRegister(const uint8_t address, const uint8_t value)
{
	MCP2515_SELECT();
	spi_readwrite(MCP_WRITE);
	spi_readwrite(address);
	spi_readwrite(value);
	MCP2515_UNSELECT();
}

void mcp2515_setRegisterS(const uint8_t address, 
	const uint8_t values[], const uint8_t n)
{
	uint8_t i;
	
	MCP2515_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]);
	}
	MCP2515_UNSELECT();
}

void mcp2515_modifyRegister(const uint8_t address, 
	const uint8_t mask, const uint8_t data)
{
	MCP2515_SELECT();
	spi_readwrite(MCP_BITMOD);
	spi_readwrite(address);
	spi_readwrite(mask);
	spi_readwrite(data);
	MCP2515_UNSELECT();
}

static uint8_t mcp2515_readXXStatus_helper(const uint8_t cmd)
{
	uint8_t i;
	
	MCP2515_SELECT();
	spi_readwrite(cmd);
	i = spi_read();
	MCP2515_UNSELECT();
	
	return i;
}
	
uint8_t mcp2515_readStatus(void)
{
	return mcp2515_readXXStatus_helper(MCP_READ_STATUS);
}

uint8_t mcp2515_RXStatus(void)
{
	return mcp2515_readXXStatus_helper(MCP_RX_STATUS);
}

uint8_t mcp2515_setCANCTRL_Mode(const uint8_t newmode)
{
	uint8_t i;
	
	mcp2515_modifyRegister(MCP_CANCTRL, MODE_MASK, newmode);
	
	// verify as advised in datasheet
	i = mcp2515_readRegister(MCP_CANCTRL);
	i &= MODE_MASK;
	
	if ( i == newmode ) {
		return MCP2515_OK; 
	}
	else {
		return MCP2515_FAIL;
	}
}


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) {
		mcp2515_setRegister(MCP_CNF1, cfg1);
		mcp2515_setRegister(MCP_CNF2, cfg2);
		mcp2515_setRegister(MCP_CNF3, cfg3);
		return MCP2515_OK;
	}
	else {
		return MCP2515_FAIL;
	}
} 

// ---

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;
    
	mcp2515_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;
	
    mcp2515_read_can_id( mcp_addr, &(msg->extended_identifier), 
		&(msg->identifier) );
    
	ctrl = mcp2515_readRegister( mcp_addr-1 );
    msg->dlc = mcp2515_readRegister( mcp_addr+4 );
    
	if (/*(*dlc & RTR_MASK) || */(ctrl & 0x08)) {
        msg->rtr = 1;
    } else {
        msg->rtr = 0;
    }
    
	msg->dlc &= MCP_DLC_MASK;
    mcp2515_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;
    }
	mcp2515_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, 
	const CanMessage* msg)
{
    uint8_t mcp_addr, dlc;

	mcp_addr = buffer_sidh_addr;
	dlc = msg->dlc;
	
    mcp2515_setRegisterS(mcp_addr+5, &(msg->dta[0]), dlc );  // write data bytes
    mcp2515_write_can_id( mcp_addr, msg->extended_identifier,
		msg->identifier );  // write CAN id
    if ( msg->rtr == 1)  dlc |= MCP_RTR_MASK;  // if RTR set bit in byte
    mcp2515_setRegister( (mcp_addr+4), dlc );  // write the RTR and DLC
}

/*
 ** Start the transmission from one of the tx buffers.
 */
// Buffer can be MCP_TXBUF_0 MCP_TXBUF_1 or MCP_TXBUF_2
void mcp2515_start_transmit(const uint8_t buffer_sidh_addr)
{
	// TXBnCTRL_addr = TXBnSIDH_addr - 1
    mcp2515_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 = mcp2515_readRegister( ctrlregs[i] );
		if ( (ctrlval & MCP_TXB_TXREQ_M) == 0 ) {
#if (MCPDEBUG_TXBUF)
			Debug_ByteToUart_P("Selected TX-Buffer", i+1);
#endif
			*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:
    mcp2515_write_can_id(MCP_RXM0SIDH, 0, 0);
    mcp2515_write_can_id(MCP_RXM1SIDH, 0, 0);
    // Anyway, set all filters to 0:
    mcp2515_write_can_id(MCP_RXF0SIDH, 1, 0); // RXB0: extended 
    mcp2515_write_can_id(MCP_RXF1SIDH, 0, 0); //       AND standard
    mcp2515_write_can_id(MCP_RXF2SIDH, 1, 0); // RXB1: extended 
    mcp2515_write_can_id(MCP_RXF3SIDH, 0, 0); //       AND standard
    mcp2515_write_can_id(MCP_RXF4SIDH, 0, 0);
    mcp2515_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
		mcp2515_setRegister(a1, 0);
		mcp2515_setRegister(a2, 0);
		mcp2515_setRegister(a3, 0);
        a1++;
		a2++;
		a3++;
    }
	
    // and clear, deactivate the two receive buffers.
    mcp2515_setRegister(MCP_RXB0CTRL, 0);
    mcp2515_setRegister(MCP_RXB1CTRL, 0);
}


// ---

uint8_t mcp2515_init(const uint8_t canSpeed)
{
	uint8_t res;
	
	MCP2515_UNSELECT();
	MCP_CS_DDR |= ( 1 << MCP_CS_BIT );
	
	mcp2515_reset();
	
	res = mcp2515_setCANCTRL_Mode(MODE_CONFIG);
	
	if ( res == MCP2515_FAIL ) return res;  /* function exit on error */
	
	res = mcp2515_configRate(canSpeed);
	
	if ( res == MCP2515_OK ) {
		mcp2515_initCANBuffers();
		
#if (DEBUG_RXANY==1)
		// enable both receive-buffers to receive any message
		// and enable rollover
		mcp2515_modifyRegister(MCP_RXB0CTRL, 
			MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK, 
			MCP_RXB_RX_ANY | MCP_RXB_BUKT_MASK);
		mcp2515_modifyRegister(MCP_RXB1CTRL, MCP_RXB_RX_MASK, 
			MCP_RXB_RX_ANY);
#else
		// enable both receive-buffers to receive messages
		// with std. and ext. identifiers
		// and enable rollover
		mcp2515_modifyRegister(MCP_RXB0CTRL, 
			MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK, 
			MCP_RXB_RX_STDEXT | MCP_RXB_BUKT_MASK );
		mcp2515_modifyRegister(MCP_RXB1CTRL, MCP_RXB_RX_MASK, 
			MCP_RXB_RX_STDEXT);
#endif
	}
	
	return res;
}

#ifdef MCPDEBUG
void mcp2515_dumpExtendedStatus(void)
{
	uint8_t tec, rec, eflg;
	
	tec  = mcp2515_readRegister(MCP_TEC);
	rec  = mcp2515_readRegister(MCP_REC);
	eflg = mcp2515_readRegister(MCP_EFLG);
	
	term_puts_P("MCP2515 Extended Status:\n");
	Debug_ByteToUart_p(PSTR("MCP Transmit Error Count"), tec);
	Debug_ByteToUart_p(PSTR("MCP Receiver Error Count"), rec);
	Debug_ByteToUart_p(PSTR("MCP Error Flag"), eflg);
	
	if ( (rec>127) || (tec>127) ) {
		term_puts_P("Error-Passive or Bus-Off\n");
	}

	if (eflg & MCP_EFLG_RX1OVR) 
		term_puts_P("Receive Buffer 1 Overflow\n");
	if (eflg & MCP_EFLG_RX0OVR) 
		term_puts_P("Receive Buffer 0 Overflow\n");
	if (eflg & MCP_EFLG_TXBO) 
		term_puts_P("Bus-Off\n");
	if (eflg & MCP_EFLG_TXEP) 
		term_puts_P("Receive Error Passive\n");
	if (eflg & MCP_EFLG_TXWAR) 
		term_puts_P("Transmit Error Warning\n");
	if (eflg & MCP_EFLG_RXWAR) 
		term_puts_P("Receive Error Warning\n");
	if (eflg & MCP_EFLG_EWARN ) 
		term_puts_P("Receive Error Warning\n");
}
#endif

#if 0 
// read-modify-write - better: Bit Modify Instruction
uint8_t mcp2515_setCANCTRL_Mode(uint8_t newmode)
{
	uint8_t i;
	
	i = mcp2515_readRegister(MCP_CANCTRL);
	i &= ~(MODE_MASK);
	i |= newmode;
	mcp2515_setRegister(MCP_CANCTRL, i);
	
	// verify as advised in datasheet
	i = mcp2515_readRegister(MCP_CANCTRL);
	i &= MODE_MASK;
	if ( i == newmode ) {
		return MCP2515_OK; 
	}
	else {
		return MCP2515_FAIL;
	}
}
#endif
			click here to download the whole source code package.

			
			


Project Files

    Sponsored links
NameSizeDate
 mcpcanavr.pnproj826.00 B03-02-05 04:01
 makefile10.98 kB17-03-05 03:52
 main.c5.71 kB19-04-05 16:38
 mcp2515_bittime.h3.36 kB24-03-05 02:15
 delay.c1.06 kB20-01-05 06:40
 delay.h1.70 kB20-01-05 06:38
 uart.c13.56 kB21-01-05 04:22
 uart.h6.64 kB21-01-05 02:14
 debughelper.h212.00 B01-08-08 16:22
 debughelper.c361.00 B22-01-05 17:42
 gpio.c408.00 B25-01-05 00:56
 gpio.h377.00 B03-02-05 00:48
 terminal.c6.92 kB19-04-05 16:33
 terminal.h349.00 B03-02-05 02:51
 termio.c1.55 kB19-04-05 16:34
 termio.h880.00 B22-01-05 17:42
 spi.c1.13 kB09-03-05 04:04
 spi.h681.00 B15-03-05 01:21
 timebase.h466.00 B03-02-05 02:46
 timebase.c1.25 kB19-04-05 16:35
 main_elf.aps6.88 kB18-02-05 18:16
 LICENSE.txt1.15 kB19-04-05 16:41
 mcp2515.c10.89 kB31-07-08 18:23
 mcp2515.h1.95 kB19-04-05 15:24
 mcp2515_defs.h4.93 kB19-04-05 15:59
 can.c5.74 kB19-04-05 16:04
 can.h1.59 kB19-04-05 15:50
 mcp2515.IMB12.00 kB27-06-08 17:33
 mcp2515.IMD448.00 B27-06-08 17:33
 mcp2515.IAB24.00 kB27-06-08 17:33
 mcp2515.IAD568.00 B27-06-08 17:33
 mcp2515.PR7.81 kB27-06-08 17:33
 mcp2515.PS71.89 kB29-08-08 21:43
 mcp2515.PFI96.00 B01-08-08 22:38
 mcp2515.PO776.00 B01-08-08 22:38
 mcp2515.PRI47.94 kB27-06-08 17:33
 mcp2515.WK351.18 kB29-08-08 21:43
 mcp2515.SearchResults150.00 B31-07-08 18:26
 <src>0.00 B25-08-08 19:56
 <AVR+mcp2515源码>0.00 B25-08-08 19:56
...

Related Items

    Sponsored links