522 lines
12 KiB
C
522 lines
12 KiB
C
|
|
#ifndef __C64__
|
|
#ifdef __AVR__
|
|
#include <avr/io.h>
|
|
#include <avr/interrupt.h>
|
|
#endif
|
|
#define asm asm volatile
|
|
#endif
|
|
|
|
#include "can.h"
|
|
#include "spi.h"
|
|
|
|
#define spi_clear_ss() SPI_PORT |= (1<<SPI_PIN_SS)
|
|
#define spi_set_ss() SPI_PORT &= ~(1<<SPI_PIN_SS)
|
|
|
|
//Registers
|
|
#define RXF0SIDH 0x00
|
|
#define RXF0SIDL 0x01
|
|
#define RXF0EID8 0x02
|
|
#define RXF0EID0 0x03
|
|
#define RXF1SIDH 0x04
|
|
#define RXF1SIDL 0x05
|
|
#define RXF1EID8 0x06
|
|
#define RXF1EID0 0x07
|
|
#define RXF2SIDH 0x08
|
|
#define RXF2SIDL 0x09
|
|
#define RXF2EID8 0x0A
|
|
#define RXF2EID0 0x0B
|
|
#define BFPCTRL 0x0C
|
|
#define TXRTSCTRL 0x0D
|
|
#define CANSTAT 0x0E
|
|
#define CANCTRL 0x0F
|
|
#define RXF3SIDH 0x10
|
|
#define RXF3SIDL 0x11
|
|
#define RXF3EID8 0x12
|
|
#define RXF3EID0 0x13
|
|
#define RXF4SIDH 0x14
|
|
#define RXF4SIDL 0x15
|
|
#define RXF4EID8 0x16
|
|
#define RXF4EID0 0x17
|
|
#define RXF5SIDH 0x18
|
|
#define RXF5SIDL 0x19
|
|
#define RXF5EID8 0x1A
|
|
#define RXF5EID0 0x1B
|
|
#define TEC 0x1C
|
|
#define REC 0x1D
|
|
#define RXM0SIDH 0x20
|
|
#define RXM0SIDL 0x21
|
|
#define RXM0EID8 0x22
|
|
#define RXM0EID0 0x23
|
|
#define RXM1SIDH 0x24
|
|
#define RXM1SIDL 0x25
|
|
#define RXM1EID8 0x26
|
|
#define RXM1EID0 0x27
|
|
#define CNF3 0x28
|
|
#define CNF2 0x29
|
|
#define CNF1 0x2A
|
|
#define CANINTE 0x2B
|
|
#define MERRE 7
|
|
#define WAKIE 6
|
|
#define ERRIE 5
|
|
#define TX2IE 4
|
|
#define TX1IE 3
|
|
#define TX0IE 2
|
|
#define RX1IE 1
|
|
#define RX0IE 0
|
|
#define CANINTF 0x2C
|
|
#define MERRF 7
|
|
#define WAKIF 6
|
|
#define ERRIF 5
|
|
#define TX2IF 4
|
|
#define TX1IF 3
|
|
#define TX0IF 2
|
|
#define RX1IF 1
|
|
#define RX0IF 0
|
|
#define EFLG 0x2D
|
|
#define TXB0CTRL 0x30
|
|
#define TXREQ 3
|
|
#define TXB0SIDH 0x31
|
|
#define TXB0SIDL 0x32
|
|
#define EXIDE 3
|
|
#define TXB0EID8 0x33
|
|
#define TXB0EID0 0x34
|
|
#define TXB0DLC 0x35
|
|
#define TXB0D0 0x36
|
|
|
|
#define RXB0CTRL 0x60
|
|
#define RXM1 6
|
|
#define RXM0 5
|
|
#define RXRTR 3
|
|
// Bits 2:0 FILHIT2:0
|
|
#define RXB0SIDH 0x61
|
|
#define RXB0SIDL 0x62
|
|
#define RXB0EID8 0x63
|
|
#define RXB0EID0 0x64
|
|
#define RXB0DLC 0x65
|
|
#define RXB0D0 0x66
|
|
|
|
//Command Bytes
|
|
#define RESET 0xC0
|
|
#define READ 0x03
|
|
#define READ_RX_BUFFER 0x90
|
|
#define WRITE 0x02
|
|
#define LOAD_TX_BUFFER 0x40
|
|
#define RTS 0x80
|
|
#define READ_STATUS 0xA0
|
|
#define RX_STATUS 0xB0
|
|
#define BIT_MODIFY 0x05
|
|
|
|
typedef struct{
|
|
can_message msg;
|
|
volatile unsigned char flags;
|
|
}can_message_x;
|
|
|
|
|
|
/* MCP */
|
|
void mcp_reset();
|
|
void mcp_write(unsigned char reg, unsigned char data);
|
|
//void mcp_write_b(unsigned char reg, unsigned char *buf, unsigned char len);
|
|
unsigned char mcp_read(unsigned char reg);
|
|
//void mcp_read_b(unsigned char reg, unsigned char *buf, unsigned char len);
|
|
void mcp_bitmod(unsigned char reg, unsigned char mask, unsigned char val);
|
|
unsigned char mcp_status();
|
|
//unsigned char mcp_rx_status();
|
|
|
|
#ifdef __AVR__
|
|
// Functions
|
|
/*
|
|
unsigned char mcp_rx_status() {
|
|
unsigned char d;
|
|
spi_set_ss();
|
|
spi_data(RX_STATUS);
|
|
d = spi_data(0);
|
|
spi_clear_ss();
|
|
return d;
|
|
}
|
|
*/
|
|
|
|
unsigned char mcp_status() {
|
|
unsigned char d;
|
|
spi_set_ss();
|
|
spi_data(READ_STATUS);
|
|
d = spi_data(0);
|
|
spi_clear_ss();
|
|
return d;
|
|
}
|
|
|
|
void mcp_bitmod(unsigned char reg, unsigned char mask, unsigned char val) {
|
|
spi_set_ss();
|
|
spi_data(BIT_MODIFY);
|
|
spi_data(reg);
|
|
spi_data(mask);
|
|
spi_data(val);
|
|
spi_clear_ss();
|
|
}
|
|
|
|
//load a message to mcp2515 and start transmission
|
|
void message_load(can_message_x * msg) {
|
|
unsigned char x;
|
|
|
|
spi_set_ss();
|
|
spi_data(WRITE);
|
|
spi_data(TXB0SIDH);
|
|
|
|
spi_data(((unsigned char)(msg->msg.port_src << 2)) |
|
|
(msg->msg.port_dst >> 4));
|
|
spi_data((unsigned char)((msg->msg.port_dst & 0x0C) << 3) |
|
|
(1<<EXIDE) | (msg->msg.port_dst & 0x03));
|
|
spi_data(msg->msg.addr_src);
|
|
spi_data(msg->msg.addr_dst);
|
|
spi_data(msg->msg.dlc);
|
|
for(x=0;x<msg->msg.dlc;x++) {
|
|
spi_data(msg->msg.data[x]);
|
|
}
|
|
spi_clear_ss();
|
|
spi_set_ss();
|
|
spi_data(WRITE);
|
|
spi_data(TXB0CTRL);
|
|
spi_data((1<<TXREQ));
|
|
spi_clear_ss();
|
|
}
|
|
|
|
//get a message from mcp2515 and disable RX interrupt Condition
|
|
void message_fetch(can_message_x * msg) {
|
|
unsigned char tmp1, tmp2, tmp3;
|
|
unsigned char x;
|
|
|
|
spi_set_ss();
|
|
spi_data(READ);
|
|
spi_data(RXB0SIDH);
|
|
tmp1 = spi_data(0);
|
|
msg->msg.port_src = tmp1 >> 2;
|
|
tmp2 = spi_data(0);
|
|
tmp3 = (unsigned char)((unsigned char)(tmp2 >> 3) & 0x0C);
|
|
msg->msg.port_dst = ((unsigned char)(tmp1 <<4 ) & 0x30) | tmp3 |
|
|
(unsigned char)(tmp2 & 0x03);
|
|
msg->msg.addr_src = spi_data(0);
|
|
msg->msg.addr_dst = spi_data(0);
|
|
msg->msg.dlc = spi_data(0) & 0x0F;
|
|
for(x=0;x<msg->msg.dlc;x++) {
|
|
msg->msg.data[x] = spi_data(0);
|
|
}
|
|
spi_clear_ss();
|
|
|
|
mcp_bitmod(CANINTF, (1<<RX0IF), 0x00);
|
|
}
|
|
|
|
#ifdef CAN_INTERRUPT
|
|
static can_message_x RX_BUFFER[CAN_RX_BUFFER_SIZE],
|
|
TX_BUFFER[CAN_TX_BUFFER_SIZE];
|
|
unsigned char RX_HEAD=0;volatile unsigned char RX_TAIL=0;
|
|
unsigned char TX_HEAD= 0;volatile unsigned char TX_TAIL=0;
|
|
static volatile unsigned char TX_INT;
|
|
|
|
ISR(INT0_vect) {
|
|
unsigned char status = mcp_status();
|
|
|
|
if ( status & 0x01 ) { // Message in RX0
|
|
if ( !(((can_message_x*)&RX_BUFFER[RX_HEAD])->flags & 0x01) ) {
|
|
message_fetch(&RX_BUFFER[RX_HEAD]);
|
|
RX_BUFFER[RX_HEAD].flags |= 0x01;//mark buffer as used
|
|
if( ++RX_HEAD == CAN_RX_BUFFER_SIZE) RX_HEAD = 0;
|
|
}else{
|
|
//buffer overflow
|
|
//just clear the Interrupt condition, and lose the message
|
|
mcp_bitmod(CANINTF, (1<<RX0IF), 0x00);
|
|
}
|
|
} else if ( status & 0x08 ) { // TX1 empty
|
|
if(((can_message_x*)&TX_BUFFER[TX_TAIL])->flags & 0x01) {
|
|
((can_message_x*)&TX_BUFFER[TX_TAIL])->flags &= ~0x01;
|
|
TX_INT = 1;
|
|
message_load(&TX_BUFFER[TX_TAIL]);
|
|
if(++TX_TAIL == CAN_TX_BUFFER_SIZE) TX_TAIL = 0;
|
|
}else{
|
|
TX_INT = 0;
|
|
}
|
|
mcp_bitmod(CANINTF, (1<<TX0IF), 0x00);
|
|
} else {
|
|
#ifdef CAN_HANDLEERROR
|
|
status = mcp_read(EFLG);
|
|
|
|
if(status) { // we've got a error condition
|
|
can_error = status;
|
|
|
|
mcp_write(EFLG, 0);
|
|
}
|
|
#endif // CAN_HANDLEERROR
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
void mcp_reset() {
|
|
spi_set_ss();
|
|
spi_data(RESET);
|
|
spi_clear_ss();
|
|
}
|
|
|
|
void mcp_write(unsigned char reg, unsigned char data) {
|
|
spi_set_ss();
|
|
spi_data(WRITE);
|
|
spi_data(reg);
|
|
spi_data(data);
|
|
spi_clear_ss();
|
|
}
|
|
|
|
/*
|
|
void mcp_write_b(unsigned char reg, unsigned char *buf, unsigned char len) {
|
|
unsigned char x;
|
|
spi_set_ss();
|
|
spi_data(WRITE);
|
|
spi_data(reg);
|
|
for(x=0;x<len;x++) {
|
|
spi_data(buf[x]);
|
|
}
|
|
spi_clear_ss();
|
|
}
|
|
*/
|
|
|
|
unsigned char mcp_read(unsigned char reg) {
|
|
unsigned char d;
|
|
spi_set_ss();
|
|
spi_data(READ);
|
|
spi_data(reg);
|
|
d = spi_data(0);
|
|
spi_clear_ss();
|
|
return d;
|
|
}
|
|
|
|
/*
|
|
void mcp_read_b(unsigned char reg, unsigned char *buf, unsigned char len) {
|
|
unsigned char x;
|
|
spi_set_ss();
|
|
spi_data(READ);
|
|
spi_data(reg);
|
|
for(x=0;x<len;x++) {
|
|
buf[x] = spi_data(0);
|
|
}
|
|
spi_clear_ss();
|
|
}
|
|
*/
|
|
|
|
|
|
/* Management */
|
|
void can_setmode(can_mode_t mode) {
|
|
unsigned char val = mode << 5;
|
|
val |= 0x04; // CLKEN
|
|
|
|
mcp_write( CANCTRL, val );
|
|
}
|
|
|
|
void can_setfilter() {
|
|
//RXM1 RXM0
|
|
// 0 0 receive matching filter
|
|
// 0 1 " only 11bit Identifier
|
|
// 1 0 " only 29bit Identifier
|
|
// 1 1 any
|
|
mcp_write(RXB0CTRL, (1<<RXM1) | (1<<RXM0));
|
|
}
|
|
|
|
void can_setled(unsigned char led, unsigned char state) {
|
|
mcp_bitmod(BFPCTRL, 0x10<<led, state?0xff:0);
|
|
}
|
|
|
|
/*******************************************************************/
|
|
void delayloop(){
|
|
unsigned char x;
|
|
for(x=0;x<255;x++){
|
|
asm ("nop");
|
|
}
|
|
|
|
}
|
|
|
|
void can_init(){
|
|
//set Slave select high
|
|
SPI_PORT |= (1<<SPI_PIN_SS);
|
|
|
|
#ifdef CAN_INTERRUPT
|
|
unsigned char x;
|
|
for(x=0;x<CAN_RX_BUFFER_SIZE;x++){
|
|
RX_BUFFER[x].flags = 0;
|
|
}
|
|
for(x=0;x<CAN_TX_BUFFER_SIZE;x++){
|
|
TX_BUFFER[x].flags = 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef CAN_HANDLEERROR
|
|
can_error = 0;
|
|
#endif
|
|
|
|
mcp_reset();
|
|
|
|
delayloop();
|
|
|
|
mcp_write(BFPCTRL,0x0C);//RXBF Pins to Output
|
|
|
|
// 0x01 : 125kbit/8MHz
|
|
// 0x03 : 125kbit/16MHz
|
|
// 0x04 : 125kbit/20MHz
|
|
|
|
#if FREQ == 16000000
|
|
#define CNF1_T 0x03
|
|
#elif FREQ == 8000000
|
|
#define CNF1_T 0x01
|
|
#elif FREQ == 20000000
|
|
#define CNF1_T 0x04
|
|
#else
|
|
#error Can Baudrate is only defined for 8, 16 and 20 MHz
|
|
#endif
|
|
|
|
mcp_write( CNF1, 0x40 | CNF1_T );
|
|
mcp_write( CNF2, 0xf1 );
|
|
mcp_write( CNF3, 0x05 );
|
|
|
|
// configure IRQ: this only configures the INT Output of the mcp2515, not
|
|
// the int on the Atmel
|
|
mcp_write( CANINTE, (1<<RX0IE) | (1<<TX0IE) );
|
|
|
|
can_setfilter();
|
|
can_setmode(normal);
|
|
|
|
#ifdef CAN_INTERRUPT
|
|
|
|
// configure IRQ: this only configures the INT Output of the mcp2515,
|
|
// not the int on the Atmel
|
|
mcp_write( CANINTE, (1<<RX0IE) | (1<<TX0IE) );
|
|
|
|
#ifdef __C64__
|
|
#error not implemented yet
|
|
#elif ATMEGA
|
|
//this turns on INT0 on the Atmega
|
|
GICR |= (1<<INT0);
|
|
#else
|
|
//this turns on INT0 on the Atmel
|
|
MCUCR |= (1<<ISC01);
|
|
#ifdef EIMSK
|
|
EIMSK |= (1<<INT0);
|
|
#elif defined(GIMSK)
|
|
GIMSK |= (1<<INT0);
|
|
#else
|
|
GICR |= (1<<INT0);
|
|
#endif
|
|
#endif //ATMEGA
|
|
#else //CAN_INTERRUPT
|
|
// configure IRQ: this only configures the INT Output of the mcp2515,
|
|
// not the int on the Atmel
|
|
mcp_write( CANINTE, (1<<RX0IE) ); //only turn RX int on
|
|
#endif //CAN_INTERRUPT
|
|
}
|
|
|
|
#ifdef CAN_INTERRUPT
|
|
//returns next can message in buffer, or 0 Pointer if buffer is empty
|
|
can_message * can_get_nb() {
|
|
can_message_x *p;
|
|
if(RX_HEAD == RX_TAIL) {
|
|
return 0;
|
|
} else {
|
|
p = &RX_BUFFER[RX_TAIL];
|
|
if(++RX_TAIL == CAN_RX_BUFFER_SIZE) RX_TAIL = 0;
|
|
return &(p->msg);
|
|
}
|
|
}
|
|
|
|
can_message * can_get() {
|
|
can_message_x *p;
|
|
|
|
while(RX_HEAD == RX_TAIL) {};
|
|
|
|
p = &RX_BUFFER[RX_TAIL];
|
|
if(++RX_TAIL == CAN_RX_BUFFER_SIZE) RX_TAIL = 0;
|
|
|
|
return &(p->msg);
|
|
}
|
|
|
|
//marks a receive buffer as unused again so it can be overwritten in Interrupt
|
|
void can_free(can_message * msg) {
|
|
can_message_x * msg_x = (can_message_x *) msg;
|
|
msg_x->flags = 0;
|
|
}
|
|
|
|
//returns pointer to the next can TX buffer
|
|
can_message * can_buffer_get() {
|
|
can_message_x *p;
|
|
p = &TX_BUFFER[TX_HEAD];
|
|
while (p->flags&0x01); //wait until buffer is free
|
|
if(++TX_HEAD == CAN_TX_BUFFER_SIZE) TX_HEAD = 0;
|
|
return &(p->msg);
|
|
}
|
|
|
|
//start transmitting can messages, and mark message msg as transmittable
|
|
void can_transmit(can_message* msg2) {
|
|
can_message_x* msg=(can_message_x*) msg2;
|
|
if(msg) {
|
|
msg->flags |= 0x01;
|
|
}
|
|
if(!TX_INT) {
|
|
if(((can_message_x*)&TX_BUFFER[TX_TAIL])->flags & 0x01) {
|
|
((can_message_x*)&TX_BUFFER[TX_TAIL])->flags &= ~0x01;
|
|
TX_INT = 1;
|
|
message_load(&TX_BUFFER[TX_TAIL]);
|
|
if(++TX_TAIL == CAN_TX_BUFFER_SIZE) TX_TAIL = 0;
|
|
}
|
|
}
|
|
}
|
|
#else // NON INTERRUPT VERSION
|
|
can_message_x RX_MESSAGE, TX_MESSAGE;
|
|
|
|
can_message * can_get_nb() {
|
|
//check the pin, that the MCP's interrupt output connects to
|
|
if(SPI_REG_PIN_MCP_INT & (1<<SPI_PIN_MCP_INT)) {
|
|
return 0;
|
|
} else {
|
|
//So the MCP Generates an RX Interrupt
|
|
message_fetch(&RX_MESSAGE);
|
|
return &(RX_MESSAGE.msg);
|
|
}
|
|
}
|
|
|
|
can_message * can_get() {
|
|
//wait while the MCP doesn't generate an RX Interrupt
|
|
while(SPI_REG_PIN_MCP_INT & (1<<SPI_PIN_MCP_INT)) {};
|
|
|
|
message_fetch(&RX_MESSAGE);
|
|
return &(RX_MESSAGE.msg);
|
|
}
|
|
|
|
//only for compatibility with Interrupt driven Version
|
|
can_message * can_buffer_get() {
|
|
return &(TX_MESSAGE.msg);
|
|
}
|
|
|
|
void can_transmit(can_message * msg) {
|
|
message_load((can_message_x*)msg);
|
|
}
|
|
|
|
void can_free(can_message * msg) {
|
|
}
|
|
#endif /* CAN_INTERRUPT */
|
|
#else /* ifdef __AVR__ */
|
|
/* stubs for simulator */
|
|
static can_message null_msg = {0};
|
|
unsigned char mcp_status() {return 0;}
|
|
void mcp_bitmod(unsigned char reg, unsigned char mask, unsigned char val){}
|
|
void message_load(can_message_x * msg){}
|
|
void message_fetch(can_message_x * msg){}
|
|
void mcp_reset(){}
|
|
void mcp_write(unsigned char reg, unsigned char data){}
|
|
unsigned char mcp_read(unsigned char reg){return 0;}
|
|
void can_setmode(can_mode_t mode) {}
|
|
void can_setfilter() {}
|
|
void can_setled(unsigned char led, unsigned char state){}
|
|
void delayloop(){}
|
|
void can_init(){}
|
|
can_message * can_get_nb(){return &null_msg;}
|
|
can_message * can_get(){return &null_msg;}
|
|
can_message * can_buffer_get(){return &null_msg;}
|
|
void can_transmit(can_message * msg){}
|
|
void can_free(can_message * msg){}
|
|
#endif
|