Commit 8841bd51 authored by Øystein Smith's avatar Øystein Smith

integrated can

parent fd32148a
#ifndef BOARD_H_
#define BOARD_H_
#define F_CPU 16000000UL
#define MCP_SPI_port PORTB
#define MCP_SPI_dir DDRB
#define MCP_SPI_SCK_pin 1
#define MCP_SPI_MISO_pin 3
#define MCP_SPI_MOSI_pin 2
#define MCP_SPI_SS_port PORTF
#define MCP_SPI_SS_dir DDRF
#define MCP_SPI_MCP_SS_pin 7
#define MCP_INT_port PORTB
#define MCP_INT_dir DDRB
#define MCP_INT_in PINB
#define MCP_INT_pin 6
#define MCP_INT_vect PCINT0_vect //PCINT6 => Pin change interrupt group 0
#define DEBUG_LED_PORT_0 PORTB
#define DEBUG_LED_PORT_1 PORTD
#define DEBUG_LED_dir_0 DDRB
#define DEBUG_LED_dir_1 DDRD
#define DEBUG_LED0_pin 0
#define DEBUG_LED1_pin 5
#define LED0 0
#define LED1 1
#define ON 1
#define OFF 0
#include <avr/io.h>
#include <avr/interrupt.h>
void board_init ( void );
void board_setLed(uint8_t led, uint8_t on);
void board_toggleLed(uint8_t led);
#endif /* BOARD_H_ */
\ No newline at end of file
#include "can.h"
#include "mcp2515.h"
volatile static can_msg_t CAN_buffer[BUFFER_SIZE];
volatile static uint8_t CAN_in=0, CAN_out=0, CAN_count=0;
uint8_t CAN_init(){
#ifdef MCP2515
SPI_init();
CAN_initbuffer();
return MCP2515_init();
#endif /* MCP2515 */
}
void CAN_send(can_msg_t *msg){
#ifdef MCP2515
MCP2515_write_tx(msg);
MCP2515_rts_all();
#endif /* MCP2515 */
}
void CAN_receive(can_msg_t *msg){
#ifdef MCP2515
MCP2515_read_rx(msg);
#endif /* MCP2515 */
}
void CAN_init_message_struct(can_msg_t *msg)
{
memset(msg,0,sizeof(can_msg_t));
}
void CAN_get_buffermsg(can_msg_t *msg){
if (CAN_get_buffercount() > 0){
*msg = CANBuffer_Remove();
}
else{
CAN_init_message_struct(msg);
}
return;
}
uint8_t CAN_get_buffercount(void){
uint8_t temp=0;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
temp=CAN_count;
}
return temp;
}
void CAN_initbuffer(void){
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
CAN_in=0;
CAN_out=0;
CAN_count=0;
}
}
void CANBuffer_Insert(can_msg_t* data){
CAN_buffer[CAN_in] = *data;
if (++CAN_in == BUFFER_SIZE){
CAN_in = 0;
}
if(CAN_count >= BUFFER_SIZE){
CAN_out = CAN_in;
}
else{
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
CAN_count++;
}
}
}
can_msg_t CANBuffer_Remove(void){
can_msg_t temp = CAN_buffer[CAN_out];
if (++CAN_out == BUFFER_SIZE){
CAN_out = 0;
}
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
CAN_count--;
}
return temp;
}
#ifdef MCP2515
ISR(MCP_INT_vect){
if (!(MCP_INT_in & (1<<MCP_INT_pin))){
static can_msg_t candata;
CAN_receive(&candata);
CANBuffer_Insert(&candata);
}
}
#endif /* MCP2515 */
\ No newline at end of file
#ifndef CAN_H_
#define CAN_H_
#include <avr/io.h> //Include avr io file
#include <string.h> //Need to memset
#include <util/atomic.h> //Need to atomic lock counter use
#define MCP2515 1 //Define controller type
//CAN message struct
typedef struct{
uint16_t identifier;
uint8_t length;
uint8_t data[8];
}can_msg_t;
/** Size of each ring buffer, in data elements - must be between 1 and 255. */
#define BUFFER_SIZE 50
//Prototypes
uint8_t CAN_init(void);
void CAN_send(can_msg_t *msg);
void CAN_receive(can_msg_t *msg);
void CAN_init_message_struct(can_msg_t *msg);
void CAN_get_buffermsg(can_msg_t *msg);
uint8_t CAN_get_buffercount(void);
void CAN_initbuffer(void);
void CANBuffer_Insert(can_msg_t* data);
can_msg_t CANBuffer_Remove(void);
#ifdef MCP2515
#include "mcp2515.h" //Include MCP2515 header file if MCP2515 is going to be used
#endif /* MCP2515 */
#endif /* CAN_H_ d*/
\ No newline at end of file
/* Structure of CAN-message:
11bits 1 databyte 1-7 databytes
ID | MESSAGE TYPE | DATA/STATUS |
Message type is divided into two types:
DATA
STATUS
*/
/* Message types */
#define CAN_BROADCAST_ID 0
#define CAN_TABLE 1
#define CAN_ROBOT_SENSOR 2
/* Node ids*/
#define CAN_NODE_0 0
#define CAN_NODE_1 1
#define CAN_NODE_2 2
#define CAN_NODE_3 3
#define CAN_NODE_4 4
/* Statuses */
#define CAN_RESET 0
#define CAN_ARM 1
#define CAN_COUNTDOWN 2
#define CAN_TRIGGER 3
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#include "mcp2515.h"
#include <util/delay.h>
uint8_t MCP2515_init(void){
//Enable PCINT0 vector
PCICR |= (1<<PCIE0);
//Enable correct pin in mask register
PCMSK0 = (1<< MCP_INT_pin);
MCP_INT_dir &= ~(1<<MCP_INT_pin);
MCP2515_reset(); //Reset MCP controller
if(!(MCP2515_set_mode(MCP_MODE_CONFIG))){
return 0;
}
/*
* Setting the bit timing
*
* Fosc = 16MHz
* BRP = 7 (divide by 8)
* TQ = 2 * (BRP +1) / Fosc (=> 1 uS)
*
* Sync Seg = 1 * TQ
* Prop Seg = (PRSEG + 1) * 1 =1 * TQ
* Phase Seg1 = (PHSEG1 + 1) = 3 * TQ
* Phase Seg2 = (PHSEG2 + 1) = 3 * TQ
*
* Bus speed = 1 / ((Total # of TQ) TQ * TQ)
* = 1/(8 * TQ) = 125 kHz
*
* With 16MHz running speed:
*
* // CAN bit rate of 125 kbps BRP = 7
* CNF1: (1 << BRP2) | (1 << BRP1) | (1 << BRP0)
* CNF2: (1 << BTLMODE) | (1 << PHSEG11)
* CNF3: (1 << PHSEG21)
*
* // CAN bit rate of 250 kbps BRP = 3
* CNF1: (1 << BRP1) | (1 << BRP0)
* CNF2: (1 << BTLMODE) | (1 << PHSEG11)
* CNF3: (1 << PHSEG21)
*
* // CAN bit rate of 500 kbps BRP = 1
* CNF2: (1 << BRP0)
* CNF2: (1 << BTLMODE) | (1 << PHSEG11)
* CNF3: (1 << PHSEG21)
*
*
* Formula:
*
* BRP = ((TQ*FOSC)/2)-1
* TQ = 1 / ( (Number of # TQ (8 over)) * Baud speed ) == > Baud speed = 1 / ( (Number of # TQ (8 over)) * TQ )
*
* Number of TQ is the total time of all parts:
* Sync Seg = 1 * TQ
* Prop Seg = (PRSEG + 1) * 1 =1 * TQ
* Phase Seg1 = (PHSEG1 + 1) = 3 * TQ
* Phase Seg2 = (PHSEG2 + 1) = 3 * TQ
* THIS IS 8 TQ (1+1+3+3)
*
*
* Total formula
*
* BRP = ((F_OSC/(8*Baud))*(1/2))-1 == > Baud = (F_OSC/(8*(BRP+1)))*(1/2)
*/
//Set Bit timing on MCP
MCP2515_write(MCP_CNF1,(MCP_BRP0_bm | MCP_BRP1_bm)); //Set BRP (se formula over)
MCP2515_write(MCP_CNF2,(MCP_SAM_bm | MCP_BTLMODE_bm | MCP_PHSEG11_bm)); //Enable SAM (Sample bus three times), Enable BTLMODE (It enables PHSEG2 configuration), Set PHSEG1 to 2
MCP2515_write(MCP_CNF3,MCP_PHSEG21_bm); //Set PHSEG2 to 2
//Enable all receive interrupts
MCP2515_write(MCP_CANINTE,MCP_RX_INT);
//Set normal mode
return MCP2515_set_mode(MCP_MODE_NORMAL);
}
void MCP2515_reset(void){ //Function to reset MCP2515
SPI_slave_select(MCP2515);
SPI_write(MCP_RESET); //Send reset byte
SPI_slave_deselect();
_delay_ms(25); //Wait....
}
uint8_t MCP2515_set_mode(uint8_t mode){
MCP2515_bit_modify(MCP_CANCTRL, MCP_MODE_MASK, mode);
// verify as advised in datasheet
uint8_t i = MCP2515_read(MCP_CANCTRL);
i &= MCP_MODE_MASK;
if ( i == mode ) {
return 1;
}
else {
return 0;
}
}
uint8_t MCP2515_read(uint8_t address){
SPI_slave_select(MCP2515);
SPI_write(MCP_READ);
SPI_write(address);
uint8_t data = SPI_read();
SPI_slave_deselect();
return data;
}
void MCP2515_write(uint8_t address, uint8_t data){
SPI_slave_select(MCP2515);
SPI_write(MCP_WRITE);
SPI_write(address);
SPI_write(data);
SPI_slave_deselect();
}
void MCP2515_bit_modify(uint8_t address, uint8_t mask, uint8_t data){
SPI_slave_select(MCP2515);
SPI_write(MCP_BITMOD);
SPI_write(address);
SPI_write(mask);
SPI_write(data);
SPI_slave_deselect();
}
void MCP2515_rts_all(){
SPI_slave_select(MCP2515);
SPI_write(MCP_RTS_TX0);
SPI_slave_deselect();
}
uint8_t MCP2515_read_status(){
SPI_slave_select(MCP2515);
SPI_write(MCP_READ_STATUS);
uint8_t data = SPI_read();
SPI_slave_deselect();
return data;
}
uint8_t MCP2515_read_rx_status(){
SPI_slave_select(MCP2515);
SPI_write(MCP_RX_STATUS);
uint8_t data = SPI_read();
SPI_slave_deselect();
return data;
}
void MCP2515_write_tx(can_msg_t *msg){
SPI_slave_select(MCP2515);
SPI_write(MCP_LOAD_TX0);
SPI_write((msg->identifier)>>3); // TXB0SIDH
SPI_write((msg->identifier)<<5); // TXB0SIDL
SPI_write(0); // TXB0EID8
SPI_write(0); // TXB0EID0
SPI_write((msg->length) & MCP_DLC_MASK ); // TXB0DLC data length
SPI_write(msg->data[0]); // TXB0D0
SPI_write(msg->data[1]); // TXB0D1
SPI_write(msg->data[2]); // TXB0D2
SPI_write(msg->data[3]); // TXB0D3
SPI_write(msg->data[4]); // TXB0D4
SPI_write(msg->data[5]); // TXB0D5
SPI_write(msg->data[6]); // TXB0D6
SPI_write(msg->data[7]); // TXB0D7
SPI_slave_deselect();
}
void MCP2515_read_rx(can_msg_t *msg){
SPI_slave_select(MCP2515);
SPI_write(MCP_READ_RX0);
msg->identifier = SPI_read(); // RXB0SIDH
msg->identifier = (msg->identifier) << 3;
uint8_t temp = SPI_read(); // RXB0SIDL
temp = temp >> 5;
msg->identifier |= temp;
SPI_read(); // RXB0EID8
SPI_read(); // RXB0EID0
temp = SPI_read(); // RXB0DLC
temp &= MCP_DLC_MASK;
msg->length = temp;
msg->data[0] = SPI_read(); // RXB0D0
msg->data[1] = SPI_read(); // RXB0D1
msg->data[2] = SPI_read(); // RXB0D2
msg->data[3] = SPI_read(); // RXB0D3
msg->data[4] = SPI_read(); // RXB0D4
msg->data[5] = SPI_read(); // RXB0D5
msg->data[6] = SPI_read(); // RXB0D6
msg->data[7] = SPI_read(); // RXB0D7
SPI_slave_deselect(); // CLEARS INTR.
}
#ifndef MCP2515_H_
#define MCP2515_H_
#include "board.h" //Include board file (must include AVR libs & PIN defines)
#include "can.h" //Need can-message struct
#include "spi.h"
#include <avr/interrupt.h>
//#define MCP2515 1
//Prototypes
uint8_t MCP2515_init(void);
void MCP2515_reset(void);
uint8_t MCP2515_set_mode(uint8_t mode);
uint8_t MCP2515_read(uint8_t address);
void MCP2515_write(uint8_t address, uint8_t data);
void MCP2515_write_tx(can_msg_t *msg);
void MCP2515_read_rx(can_msg_t *msg);
void MCP2515_bit_modify(uint8_t address, uint8_t mask, uint8_t data);
void MCP2515_rts_all(void);
uint8_t MCP2515_read_status(void);
uint8_t MCP2515_read_rx_status(void);
// Begin mt
#define MCP_SIDH 0
#define MCP_SIDL 1
#define MCP_EID8 2
#define MCP_EID0 3
#define MCP_TXB_EXIDE_M 0x08 /* In TXBnSIDL */
#define MCP_DLC_MASK 0x0F /* 4 LSBits */
#define MCP_RTR_MASK 0x40 /* (1<<6) Bit 6 */
#define MCP_RXB_RX_ANY 0x60
#define MCP_RXB_RX_EXT 0x40
#define MCP_RXB_RX_STD 0x20
#define MCP_RXB_RX_STDEXT 0x00
#define MCP_RXB_RX_MASK 0x60
#define MCP_RXB_BUKT_MASK (1<<2)
// Bits in the TXBnCTRL registers.
#define MCP_TXB_TXBUFE_M 0x80
#define MCP_TXB_ABTF_M 0x40
#define MCP_TXB_MLOA_M 0x20
#define MCP_TXB_TXERR_M 0x10
#define MCP_TXB_TXREQ_M 0x08
#define MCP_TXB_TXIE_M 0x04
#define MCP_TXB_TXP10_M 0x03
#define MCP_TXB_RTR_M 0x40 // In TXBnDLC
#define MCP_RXB_IDE_M 0x08 // In RXBnSIDL
#define MCP_RXB_RTR_M 0x40 // In RXBnDLC
#define MCP_STAT_RXIF_MASK (0x03)
#define MCP_STAT_RX0IF (1<<0)
#define MCP_STAT_RX1IF (1<<1)
#define MCP_EFLG_RX1OVR (1<<7)
#define MCP_EFLG_RX0OVR (1<<6)
#define MCP_EFLG_TXBO (1<<5)
#define MCP_EFLG_TXEP (1<<4)
#define MCP_EFLG_RXEP (1<<3)
#define MCP_EFLG_TXWAR (1<<2)
#define MCP_EFLG_RXWAR (1<<1)
#define MCP_EFLG_EWARN (1<<0)
#define MCP_EFLG_ERRORMASK (0xF8) /* 5 MS-Bits */
// End mt
// Define MCP2515 register addresses
#define MCP_RXF0SIDH 0x00
#define MCP_RXF0SIDL 0x01
#define MCP_RXF0EID8 0x02
#define MCP_RXF0EID0 0x03
#define MCP_RXF1SIDH 0x04
#define MCP_RXF1SIDL 0x05
#define MCP_RXF1EID8 0x06
#define MCP_RXF1EID0 0x07
#define MCP_RXF2SIDH 0x08
#define MCP_RXF2SIDL 0x09
#define MCP_RXF2EID8 0x0A
#define MCP_RXF2EID0 0x0B
#define MCP_CANSTAT 0x0E
#define MCP_CANCTRL 0x0F
#define MCP_RXF3SIDH 0x10
#define MCP_RXF3SIDL 0x11
#define MCP_RXF3EID8 0x12
#define MCP_RXF3EID0 0x13
#define MCP_RXF4SIDH 0x14
#define MCP_RXF4SIDL 0x15
#define MCP_RXF4EID8 0x16
#define MCP_RXF4EID0 0x17
#define MCP_RXF5SIDH 0x18
#define MCP_RXF5SIDL 0x19
#define MCP_RXF5EID8 0x1A
#define MCP_RXF5EID0 0x1B
#define MCP_TEC 0x1C
#define MCP_REC 0x1D
#define MCP_RXM0SIDH 0x20
#define MCP_RXM0SIDL 0x21
#define MCP_RXM0EID8 0x22
#define MCP_RXM0EID0 0x23
#define MCP_RXM1SIDH 0x24
#define MCP_RXM1SIDL 0x25
#define MCP_RXM1EID8 0x26
#define MCP_RXM1EID0 0x27
#define MCP_CNF3 0x28
#define MCP_CNF2 0x29
#define MCP_CNF1 0x2A
#define MCP_CANINTE 0x2B
#define MCP_CANINTF 0x2C
#define MCP_EFLG 0x2D
#define MCP_TXB0CTRL 0x30
#define MCP_TXB1CTRL 0x40
#define MCP_TXB2CTRL 0x50
#define MCP_RXB0CTRL 0x60
#define MCP_RXB0SIDH 0x61
#define MCP_RXB1CTRL 0x70
#define MCP_RXB1SIDH 0x71
#define MCP_TX_INT 0x1C // Enable all transmit interrupts
#define MCP_TX01_INT 0x0C // Enable TXB0 and TXB1 interrupts
#define MCP_RX_INT 0x03 // Enable receive interrupts
#define MCP_NO_INT 0x00 // Disable all interrupts
#define MCP_TX01_MASK 0x14
#define MCP_TX_MASK 0x54
// Define SPI Instruction Set
#define MCP_WRITE 0x02
#define MCP_READ 0x03
#define MCP_BITMOD 0x05
#define MCP_LOAD_TX0 0x40
#define MCP_LOAD_TX1 0x42
#define MCP_LOAD_TX2 0x44
#define MCP_RTS_TX0 0x81
#define MCP_RTS_TX1 0x82
#define MCP_RTS_TX2 0x84
#define MCP_RTS_ALL 0x87
#define MCP_READ_RX0 0x90
#define MCP_READ_RX1 0x94
#define MCP_READ_STATUS 0xA0
#define MCP_RX_STATUS 0xB0
#define MCP_RESET 0xC0
// CANCTRL Register Values
#define MCP_MODE_NORMAL 0x00
#define MCP_MODE_SLEEP 0x20
#define MCP_MODE_LOOPBACK 0x40
#define MCP_MODE_LISTENONLY 0x60
#define MCP_MODE_CONFIG 0x80
#define MCP_MODE_POWERUP 0xE0
#define MCP_MODE_MASK 0xE0
#define MCP_ABORT_TX 0x10
#define MCP_MODE_ONESHOT 0x08
#define MCP_CLKOUT_ENABLE 0x04
#define MCP_CLKOUT_DISABLE 0x00
#define MCP_CLKOUT_PS1 0x00
#define MCP_CLKOUT_PS2 0x01
#define MCP_CLKOUT_PS4 0x02
#define MCP_CLKOUT_PS8 0x03
// CNF1 Register Values
#define MCP_SJW1_gc 0x00
#define MCP_SJW2_gc 0x40
#define MCP_SJW3_gc 0x80
#define MCP_SJW4_gc 0xC0
#define MCP_BRP0_bm 0x01
#define MCP_BRP1_bm 0x02
#define MCP_BRP2_bm 0x04
#define MCP_BRP3_bm 0x08
#define MCP_BRP4_bm 0x10
#define MCP_BRP5_bm 0x20
// CNF2 Register Values
#define MCP_BTLMODE_bm 0x80
#define MCP_SAM_bm 0x40
#define MCP_PHSEG12_bm 0x20
#define MCP_PHSEG11_bm 0x10
#define MCP_PHSEG10_bm 0x08
#define MCP_PRSEG2_bm 0x04
#define MCP_PRSEG1_bm 0x02
#define MCP_PRSEG0_bm 0x01
// CNF3 Register Values
#define MCP_SOF_bm 0x80
#define MCP_WAKFIL_bm 0x40
#define MCP_PHSEG22_bm 0x04
#define MCP_PHSEG21_bm 0x02
#define MCP_PHSEG20_bm 0x01
// CANINTF Register Bits
#define MCP_RX0IF 0x01
#define MCP_RX1IF 0x02
#define MCP_TX0IF 0x04
#define MCP_TX1IF 0x08
#define MCP_TX2IF 0x10
#define MCP_ERRIF 0x20
#define MCP_WAKIF 0x40
#define MCP_MERRF 0x80
#endif /* MCP2515_H_ */
\ No newline at end of file
/**** A P P L I C A T I O N N O T E ************************************
*
* Title : SPI hardware module on ATmega
* Version : beta
* Last updated : 01.10.14
* Target : Node1
* Clock : 16MHz
* Pinout : See bottom of board.h
*
* written by GNR
***************************************************************************
*/
#include "board.h" //Include board file (must include AVR libs & PIN defines)
#include "spi.h"
#include "can.h" //Need MCP2515 define (controller type)
#define JIBBERISH 0xCE
void SPI_init()
{
// Set MOSI, SCK and SS to output
MCP_SPI_dir |= (1 << MCP_SPI_MOSI_pin) | (1 << MCP_SPI_SCK_pin);
MCP_SPI_SS_dir |= (1 << MCP_SPI_MCP_SS_pin);
//Ensure MISO is input
MCP_SPI_dir &= ~(1 << MCP_SPI_MISO_pin);
// Enable SPI, Master, set clock rate fck/4
SPCR = (1 << SPE) | (1 << MSTR);
// Set MCP2515 CS output and high (not selected)
MCP_SPI_SS_port |= (1 << MCP_SPI_MCP_SS_pin);
}
uint8_t SPI_transmit(uint8_t byte)
{
// Start transmission
SPDR = byte;
// Wait for transmission complete
while(!(SPSR & (1<<SPIF)));
// Return the received byte
return SPDR;
}
uint8_t SPI_read(void)
{
return SPI_transmit(0);
}
void SPI_write(uint8_t byte){
SPI_transmit(byte);
}
void SPI_slave_select(uint8_t slave)
{
// Set CS low
if (slave == MCP2515){
MCP_SPI_SS_port &= ~(1 << MCP_SPI_MCP_SS_pin);
}
}
void SPI_slave_deselect(){
// De select all SPI slaves
//MCP 2515
MCP_SPI_SS_port |= (1 << MCP_SPI_MCP_SS_pin);
}
/**** A P P L I C A T I O N N O T E ************************************
*
* Title : SPI hardware module on ATmega
* Version : beta
* Last updated : 01.10.14
* Target : Node1
* Clock : 16MHz
* Pinout : See bottom of board.h
*
* written by GNR
***************************************************************************
*/
#ifndef SPI_H
#define SPI_H
void SPI_init();
uint8_t SPI_transmit(uint8_t byte);
uint8_t SPI_read(void);
void SPI_write(uint8_t byte);
void SPI_slave_select(uint8_t slave);
void SPI_slave_deselect();
#endif // SPI_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment