TTK4155 Lab Node 1
Term project in the NTNU course TTK4155 Embedded and Industrial Computer Systems Design
Loading...
Searching...
No Matches
CAN

Data Structures

struct  can_msg
 Represents a simple CAN message with an address, data count, and a single byte of data. More...
struct  can_device
 Represents a CAN device, storing the SPI slave controlling the MCP2515. More...
struct  CAN_frame
 Represents a full CAN frame for sending/receiving. More...

Macros

#define CAN_ID_ERROR   0x01
#define CAN_ID_GAMEOVER   0x02
#define CAN_ID_GAMESTART   0x03
#define CAN_ID_JOYPOS   0x04
#define CAN_ID_RESET   0x05
#define CAN_ID_READY   0x06
#define CAN_ID_SCORE   0x07
#define CAN_ID_DEFAULT   0x08
#define CAN_RXQ_SIZE   8

Functions

int8_t can_init (struct can_device *dev)
 Initialize a CAN device.
int8_t can_write (struct can_device *dev, struct CAN_frame msg)
 Write a CAN frame to the MCP2515 transmit buffer.
int8_t can_read_rx0 (struct can_device *dev, struct CAN_frame *out)
 Read a message from RX buffer 0.
int8_t can_read_rx1 (struct can_device *dev, struct CAN_frame *out)
 Read a message from RX buffer 1.
int can_rxq_add (struct CAN_frame *msg)
 Add a CAN frame to the internal receive queue.
int can_rxq_pull (struct CAN_frame *out)
 Pull a CAN frame from the internal receive queue.
int8_t can_reset (struct can_device *dev, uint8_t address, struct CAN_frame data_frame)
int8_t MCP2515_init (struct can_device *dev)
int8_t MCP2515_read (struct can_device *dev, uint8_t rx_buf_num, uint8_t *out)
int8_t MCP2515_write (struct can_device *dev, uint8_t addr, uint8_t data)
int8_t MCP2515_request_to_send (struct can_device *dev, uint8_t tx_buf_num)
int8_t MCP2515_bit_modify (struct can_device *dev, uint8_t reg, uint8_t mask, uint8_t set_val)
int8_t MCP2515_reset (struct can_device *dev)
int8_t MCP2515_read_status (struct can_device *dev, uint8_t *out)

Detailed Description

Macro Definition Documentation

◆ CAN_ID_DEFAULT

#define CAN_ID_DEFAULT   0x08

#include <can.h>

Definition at line 25 of file can.h.

◆ CAN_ID_ERROR

#define CAN_ID_ERROR   0x01

#include <can.h>

Definition at line 18 of file can.h.

Referenced by tx_error().

◆ CAN_ID_GAMEOVER

#define CAN_ID_GAMEOVER   0x02

#include <can.h>

Definition at line 19 of file can.h.

Referenced by process_can_frame().

◆ CAN_ID_GAMESTART

#define CAN_ID_GAMESTART   0x03

#include <can.h>

Definition at line 20 of file can.h.

Referenced by tx_gamestart().

◆ CAN_ID_JOYPOS

#define CAN_ID_JOYPOS   0x04

#include <can.h>

Definition at line 21 of file can.h.

Referenced by tx_joy_btn().

◆ CAN_ID_READY

#define CAN_ID_READY   0x06

#include <can.h>

Definition at line 23 of file can.h.

◆ CAN_ID_RESET

#define CAN_ID_RESET   0x05

#include <can.h>

Definition at line 22 of file can.h.

Referenced by tx_reset().

◆ CAN_ID_SCORE

#define CAN_ID_SCORE   0x07

#include <can.h>

Definition at line 24 of file can.h.

◆ CAN_RXQ_SIZE

#define CAN_RXQ_SIZE   8

#include <can.h>

Definition at line 27 of file can.h.

Referenced by can_rxq_add(), and can_rxq_pull().

Function Documentation

◆ can_init()

int8_t can_init ( struct can_device * dev)

#include <can.h>

Initialize a CAN device.

Configures MCP2515 and sets up AVR external interrupt for CAN receive events.

Parameters
devPointer to the CAN device structure.
Returns
0 on success, negative on failure.

Definition at line 22 of file can.c.

22 {
23
24 can_irq = dev;
25 // struct CAN_frame new_message = {0x00, 0x01, '1', 0, 0}; <- Why did we add
26 // this, it does nothing
27
28 // Set PE0 as input
29 DDRE &= ~(1 << PE0);
30 PORTE |= (1 << PE0);
31
32 // Disable global interrupts
33 cli();
34 // Enable INT2
35 GICR |= (1 << CAN_INTERRUPT_ISR_REGISTER);
36
37 // Edge select, active-low interrupt from MCP2515
38 EMCUCR &= ~(1 << ISC2);
39
40 // Configure interrupt falling edge
41 // MCUCR |=(1<<ISC01);
42 // MCUCR &= ~(1<<ISC00);
43 // Enable global interrupts
44 sei();
45
46 return MCP2515_init(dev);
47}
struct can_device * can_irq
Definition can.c:13
int8_t MCP2515_init(struct can_device *dev)
Definition can.c:217
#define CAN_INTERRUPT_ISR_REGISTER
Definition mcp.h:177

Referenced by main().

◆ can_read_rx0()

int8_t can_read_rx0 ( struct can_device * dev,
struct CAN_frame * out )

#include <can.h>

Read a message from RX buffer 0.

Extracts identifier, data length, and payload from the MCP2515 RXB0 buffer.

Parameters
devPointer to the CAN device.
outPointer to CAN_frame to store the received message.
Returns
0 on success.

Definition at line 95 of file can.c.

95 {
96
97 uint8_t ID_MSB;
98 uint8_t ID_LSB;
99 uint8_t length;
100
101 MCP2515_read(dev, MCP2515_RXB0SIDH, &ID_MSB);
102 MCP2515_read(dev, MCP2515_RXB0SIDL, &ID_LSB);
103
104 /*
105 ID_LSB = (ID_LSB & 0xE0) >> 5;
106 out->id = ID_MSB << 3;
107 out->id |= (out->id & 0x7F8) | (ID_LSB & 0x7);
108 */
109
110 ID_LSB = (ID_LSB & 0xE0) >> 5;
111 out->id = (ID_MSB << 3) | (ID_LSB & 0x7);
112
113 MCP2515_read(dev, MCP2515_RXB0DLC, &length);
114 out->dlc = (length & 0xF);
115 if (out->dlc > 8) {
116 out->dlc = 8;
117 }
118
119 for (uint8_t i = 0; i < out->dlc; i++) {
120 MCP2515_read(dev, MCP2515_RXB0D0 + i, (uint8_t *)&out->data[i]);
121 }
122 // Clear RX1IF to clear buffer for next message
123 MCP2515_bit_modify(dev, MCP2515_CANINTF, MCP2515_RX0IF, 0x00); // RX0IF=bit0
124 return 0;
125}
int8_t MCP2515_bit_modify(struct can_device *dev, uint8_t reg, uint8_t mask, uint8_t set_val)
Definition can.c:379
int8_t MCP2515_read(struct can_device *dev, uint8_t addr, uint8_t *out)
Definition can.c:354
#define MCP2515_CANINTF
Definition mcp.h:44
#define MCP2515_RXB0D0
Definition mcp.h:162
#define MCP2515_RX0IF
Definition mcp.h:141
#define MCP2515_RXB0SIDL
Definition mcp.h:51
#define MCP2515_RXB0SIDH
Definition mcp.h:50
#define MCP2515_RXB0DLC
Definition mcp.h:52
uint8_t dlc
Definition can.h:55
uint32_t id
Definition can.h:54
char data[8]
Definition can.h:56

Referenced by ISR().

◆ can_read_rx1()

int8_t can_read_rx1 ( struct can_device * dev,
struct CAN_frame * out )

#include <can.h>

Read a message from RX buffer 1.

Extracts identifier, data length, and payload from the MCP2515 RXB1 buffer.

Parameters
devPointer to the CAN device.
outPointer to CAN_frame to store the received message.
Returns
0 on success.

Definition at line 127 of file can.c.

127 {
128
129 uint8_t ID_MSB;
130 uint8_t ID_LSB;
131 uint8_t length;
132
133 MCP2515_read(dev, MCP2515_RXB1SIDH, &ID_MSB);
134 MCP2515_read(dev, MCP2515_RXB1SIDL, &ID_LSB);
135
136 /*
137 ID_LSB = (ID_LSB & 0xE0) >> 5;
138 out->id = ID_MSB << 3;
139 out->id |= (out->id & 0x7F8) | (ID_LSB & 0x7);
140 */
141
142 ID_LSB = (ID_LSB & 0xE0) >> 5;
143 out->id = (ID_MSB << 3) | (ID_LSB & 0x7);
144
145 MCP2515_read(dev, MCP2515_RXB1DLC, &length);
146 out->dlc = (length & 0xF);
147 if (out->dlc > 8) {
148 out->dlc = 8;
149 }
150
151 for (uint8_t i = 0; i < out->dlc; i++) {
152 MCP2515_read(dev, MCP2515_RXB1D0 + i, (uint8_t *)&out->data[i]);
153 }
154 // Clear RX1IF to clear buffer for next message
155 MCP2515_bit_modify(dev, MCP2515_CANINTF, MCP2515_RX1IF, 0x00); // RX0IF=bit0
156 return 0;
157}
#define MCP2515_RXB1SIDL
Definition mcp.h:55
#define MCP2515_RXB1D0
Definition mcp.h:58
#define MCP2515_RXB1DLC
Definition mcp.h:57
#define MCP2515_RXB1SIDH
Definition mcp.h:54
#define MCP2515_RX1IF
Definition mcp.h:142

Referenced by ISR().

◆ can_reset()

int8_t can_reset ( struct can_device * dev,
uint8_t address,
struct CAN_frame data_frame )

#include <can.h>

◆ can_rxq_add()

int can_rxq_add ( struct CAN_frame * msg)

#include <can.h>

Add a CAN frame to the internal receive queue.

Used by interrupt routines to buffer incoming messages.

Parameters
msgPointer to the CAN_frame to enqueue.
Returns
1 on success, 0 if queue is full.

Definition at line 159 of file can.c.

159 {
160
161 uint8_t next = (uint8_t)((rxq_head + 1) & (CAN_RXQ_SIZE - 1));
162 if (next == rxq_tail) {
163 return 0;
164 }
165 rxq[rxq_head] = *msg;
166 rxq_head = next;
167 return 1;
168}
static volatile uint8_t rxq_head
Definition can.c:16
struct CAN_frame rxq[CAN_RXQ_SIZE]
Definition can.c:17
static volatile uint8_t rxq_tail
Definition can.c:16
#define CAN_RXQ_SIZE
Definition can.h:27

Referenced by ISR().

◆ can_rxq_pull()

int can_rxq_pull ( struct CAN_frame * out)

#include <can.h>

Pull a CAN frame from the internal receive queue.

Parameters
outPointer to the CAN_frame to fill with dequeued data.
Returns
1 on success, 0 if queue is empty.

Definition at line 171 of file can.c.

171 {
172 if (rxq_tail == rxq_head) {
173 return 0;
174 }
175 LOG_INF("Coconut 2!");
176 *out = rxq[rxq_tail];
177 rxq_tail = (uint8_t)((rxq_tail + 1) & (CAN_RXQ_SIZE - 1));
178 return 1;
179}
#define LOG_INF(msg)
Definition log.h:59

Referenced by process_can_frame().

◆ can_write()

int8_t can_write ( struct can_device * dev,
struct CAN_frame msg )

#include <can.h>

Write a CAN frame to the MCP2515 transmit buffer.

Handles standard and extended IDs and requests the controller to send the message.

Parameters
devPointer to the CAN device structure.
msgThe CAN frame to send.
Returns
0 on success, negative on error.

Definition at line 49 of file can.c.

49 {
50
51 if (msg.extended) {
52 // 29bit ID
53 uint32_t id = msg.id & 0x1FFFFFFF;
54
55 uint8_t EID0 = id & 0xFF; // EID[7:0]
56 uint8_t EID8 = (id >> 8) & 0xFF; // EID[15:8]
57 uint8_t SIDL = ((id >> 16) & 0x03) // EID[17:16] -> SIDL<1:0>
58 | 0x08 // EXIDE=1 (bit3)
59 | ((id >> 18) & 0xE0); // SID[2:0] -> SIDL<7:5>
60 uint8_t SIDH = (id >> 21) & 0xFF; // SID[10:3] -> SIDH
61
66 } else { // 11bit ID
67 uint8_t ID_MSB = (0x7F8 & msg.id) >> 3;
68 uint8_t ID_LSB = (0x7 & msg.id) << 5;
69
70 MCP2515_write(dev, MCP2515_TXB0SIDH, ID_MSB);
71 MCP2515_write(dev, MCP2515_TXB0SIDL, ID_LSB);
72 }
73 MCP2515_write(dev, TXB0DLC, msg.dlc);
74
75 uint8_t buff0_status;
76 MCP2515_read(dev, MCP2515_TXB0CTRL, &buff0_status);
77 if ((buff0_status & 0x8) != 0x8) {
78 if (msg.dlc > 8) {
79 LOG_ERR("TX Buffer0 overflow, message too large", -2);
80 return -2;
81 }
82 for (uint8_t i = 0; i < msg.dlc; i++) {
83 MCP2515_write(dev, MCP2515_TXB0D0 + i, msg.data[i]);
84 }
85
87 return 0;
88
89 } else {
90 // printf("TX Buffer0 not avaliable\r\n");
91 return -2;
92 }
93}
int8_t MCP2515_request_to_send(struct can_device *dev, uint8_t buffer)
Definition can.c:371
int8_t MCP2515_write(struct can_device *dev, uint8_t addr, uint8_t data)
Definition can.c:318
#define LOG_ERR(msg, status)
Definition log.h:72
#define MCP2515_TXB0SIDH
Definition mcp.h:154
#define MCP2515_RTS_TX0
Definition mcp.h:80
#define MCP2515_TXB0EID8
Definition mcp.h:156
#define MCP2515_TXB0SIDL
Definition mcp.h:155
#define MCP2515_TXB0CTRL
Definition mcp.h:46
#define MCP2515_TXB0EID0
Definition mcp.h:56
#define TXB0DLC
Definition mcp.h:175
#define MCP2515_TXB0D0
Definition mcp.h:159
uint8_t extended
Definition can.h:57

Referenced by tx_error(), tx_gamestart(), tx_joy_btn(), and tx_reset().

◆ MCP2515_bit_modify()

int8_t MCP2515_bit_modify ( struct can_device * dev,
uint8_t reg,
uint8_t mask,
uint8_t set_val )

#include <can.h>

Definition at line 379 of file can.c.

380 {
381
382 unsigned char cmd[4] = {MCP2515_BITMOD, reg, mask, set_val};
383 spi_duplex(&dev->spi, cmd, TRASHCAN, 4);
384 // spi_send_n(&dev->spi, cmd, 4);
385
386 return 0;
387}
int spi_duplex(enum spi_slave *slave, unsigned char *data, unsigned char *out, int length)
Full-duplex SPI transfer.
Definition spi.c:131
#define TRASHCAN
Definition utils.h:19
#define MCP2515_BITMOD
Definition mcp.h:74
enum spi_slave spi
Definition can.h:44

Referenced by can_read_rx0(), can_read_rx1(), and MCP2515_init().

◆ MCP2515_init()

int8_t MCP2515_init ( struct can_device * dev)

#include <can.h>

Definition at line 217 of file can.c.

217 {
218
219 while (spi_ready()) { // Confirm SPI Initialized
220 uint8_t status = spi_init();
221 }
222
223 MCP2515_reset(dev); // Send reset - command
224 uint8_t value = 0;
225 _delay_ms(10);
226
227 // Confirm that we are in correct mode after boot, and that there are no
228 // pending messages.
229 MCP2515_read(dev, 0x0E, &value);
230
231 // Ensure config mode after reset
232 if ((value & MODE_MASK) != (MODE_CONFIG)) {
233 LOG_ERR("SPI to CAN controller is not in configuration mode after reset!",
234 -1);
235 return -1;
236 }
237
238 // MCP2515_read_status(dev, &value);
239 if ((value & 0x0E) != (MCP2515_NO_IRQ)) {
240 LOG_ERR("There is an interrupt request when booting the SPI-CAN controller",
241 -2);
242 return -2;
243 }
244
245 // RTS control
246 unsigned char tx[3] = {MCP2515_WRITE, MCP2515_TXRTSCTRL, MCP2515_TXRTS_CONF};
247 spi_send_n(&dev->spi, tx, 3);
248
249 // Receive buffer0 config. Receive all, no overflow
250 MCP2515_bit_modify(dev, MCP2515_RXB0CTRL, 0x60, 0x60);
251 MCP2515_read(dev, MCP2515_RXB0CTRL, &value);
252 if (value != 0x60) {
253 LOG_ERR("Couldnt configure MCP2515 RX0 Buffer", -3);
254 return -3;
255 }
256
257 // Receive buffer1 config. Receive all
258 MCP2515_bit_modify(dev, MCP2515_RXB1CTRL, 0x60, 0x60);
259 MCP2515_read(dev, MCP2515_RXB1CTRL, &value);
260 if (value != 0x60) {
261 LOG_ERR("Couldnt configure MCP2515 RX1", -4);
262 return -4;
263 }
264
265 // Set PE0 as input
266 DDRE &= ~(1 << PE0);
267 PORTE |= (1 << PE0);
268
269 // Enable INT2
270 GICR |= (1 << INT2);
271
272 // Edge select, active-low interrupt from MCP2515
273 EMCUCR &= ~(1 << ISC2);
274
275 // Interrupt config: msg error, error flag change, TX0 empty, RX0 full
277 MCP2515_read(dev, MCP2515_CANINTE, &value);
278 if ((value & MCP2515_RX_IRQ) != MCP2515_RX_IRQ) {
279 LOG_ERR("Couldnt set IRQ config for MCP2515", -5);
280 return -5;
281 }
282
283 // BRP and CAN timing config
287
288 MCP2515_read(dev, MCP2515_CNF1, &value);
289 if (value != MCP2515_VAL_CNF1) {
290 LOG_ERR("Couldnt configure BRP for MCP2515", -6);
291 return -6;
292 }
293
294 MCP2515_read(dev, MCP2515_CNF2, &value);
295 if (value != MCP2515_VAL_CNF2) {
296 LOG_ERR("CNF2 not set", -7);
297 return -7;
298 }
299
300 MCP2515_read(dev, MCP2515_CNF3, &value);
301 if (value != MCP2515_VAL_CNF3) {
302 LOG_ERR("CNF3 not set", -8);
303 return -8;
304 }
305
306 // Set the controller to normal mode !!!THIS HAS TO BE LAST IN INIT!!!
308 MCP2515_read(dev, MCP2515_CANSTAT, &value);
309 if ((value & MODE_MASK) != MODE_NORMAL) {
310 LOG_ERR("MCP2515 could not be set to NORMAL mode when init completed", -9);
311 return -9;
312 }
313
314 return 0;
315}
int8_t MCP2515_reset(struct can_device *dev)
Definition can.c:390
int spi_send_n(enum spi_slave *slave, unsigned char *data, int length)
Send a sequence of bytes to a slave without reading response.
Definition spi.c:81
int spi_ready(void)
Check if the SPI subsystem is initialized.
Definition spi.c:41
int spi_init(void)
Initialize SPI in master mode.
Definition spi.c:9
#define MCP2515_CANINTE
Definition mcp.h:43
#define MODE_NORMAL
Definition mcp.h:103
#define MCP2515_CNF3
Definition mcp.h:40
#define MCP2515_VAL_CNF2
Definition mcp.h:99
#define MCP2515_NO_IRQ
Definition mcp.h:64
#define MCP2515_RX_IRQ
Definition mcp.h:63
#define MCP2515_CANSTAT
Definition mcp.h:16
#define MODE_CONFIG
Definition mcp.h:107
#define MCP2515_CNF2
Definition mcp.h:41
#define MCP2515_RXB0CTRL
Definition mcp.h:49
#define MCP2515_VAL_CNF1
Definition mcp.h:98
#define MCP2515_CANCTRL
Definition mcp.h:17
#define MCP2515_TXRTS_CONF
Definition mcp.h:94
#define MCP2515_CNF1
Definition mcp.h:42
#define MCP2515_TXRTSCTRL
Definition mcp.h:151
#define MODE_MASK
Definition mcp.h:109
#define MCP2515_VAL_CNF3
Definition mcp.h:100
#define MCP2515_WRITE
Definition mcp.h:70
#define MCP2515_RXB1CTRL
Definition mcp.h:53

Referenced by can_init().

◆ MCP2515_read()

int8_t MCP2515_read ( struct can_device * dev,
uint8_t rx_buf_num,
uint8_t * out )

#include <can.h>

Definition at line 354 of file can.c.

354 {
355
356 if (!out) {
357 return -1;
358 }
359
360 unsigned char tx[3] = {MCP2515_READ, addr, 0xFF};
361 unsigned char rx[3];
362
363 spi_duplex(&dev->spi, tx, rx, 3);
364
365 *out = rx[2]; // ? third byte is the register value
366 return 0;
367}
#define MCP2515_READ
Definition mcp.h:72

Referenced by can_read_rx0(), can_read_rx1(), can_write(), ISR(), and MCP2515_init().

◆ MCP2515_read_status()

int8_t MCP2515_read_status ( struct can_device * dev,
uint8_t * out )

#include <can.h>

Definition at line 399 of file can.c.

399 {
400
401 // uint8_t *status;
402
403 // spi_push(&dev->spi, MCP2515_READ_STATUS, TRASHCAN);
404 // spi_recieve(&dev->spi, out);
405
406 if (!out)
407 return -1;
408
409 unsigned char tx[2] = {MCP2515_READ_STATUS, 0xFF};
410 unsigned char rx[2];
411
412 spi_duplex(&dev->spi, tx, rx, 2);
413
414 *out = rx[1];
415
416 return 0;
417}
#define MCP2515_READ_STATUS
Definition mcp.h:88

◆ MCP2515_request_to_send()

int8_t MCP2515_request_to_send ( struct can_device * dev,
uint8_t tx_buf_num )

#include <can.h>

Definition at line 371 of file can.c.

371 {
372
373 spi_send(&dev->spi, buffer);
374
375 return 0;
376}
int spi_send(enum spi_slave *slave, unsigned char data)
Send a single byte to a slave.
Definition spi.c:86

Referenced by can_write().

◆ MCP2515_reset()

int8_t MCP2515_reset ( struct can_device * dev)

#include <can.h>

Definition at line 390 of file can.c.

390 {
391
392 spi_send(&dev->spi, MCP2515_RESET);
393
394 return 0;
395}
#define MCP2515_RESET
Definition mcp.h:92

Referenced by MCP2515_init().

◆ MCP2515_write()

int8_t MCP2515_write ( struct can_device * dev,
uint8_t addr,
uint8_t data )

#include <can.h>

Definition at line 318 of file can.c.

318 {
319
320 unsigned char frame[3] = {MCP2515_WRITE, addr, data};
321 spi_send_n(&dev->spi, frame, 3);
322
323 return 0;
324}

Referenced by can_write(), ISR(), and MCP2515_init().