TTK4155 Lab Node 1
Term project in the NTNU course TTK4155 Embedded and Industrial Computer Systems Design
Loading...
Searching...
No Matches
can.c
Go to the documentation of this file.
1#include <avr/interrupt.h>
2#include <avr/io.h>
3#include <stdint.h>
4#include <util/delay.h>
5
6#include "can.h"
7#include "log.h"
8#include "mcp.h"
9#include "spi.h"
10
12
15
16static volatile uint8_t rxq_head = 0, rxq_tail = 0;
18
19//------------------//
20// GENERAL CAN //
21//------------------//
22int8_t can_init(struct can_device *dev) {
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}
48
49int8_t can_write(struct can_device *dev, struct CAN_frame msg) {
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}
94
95int8_t can_read_rx0(struct can_device *dev, struct CAN_frame *out) {
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}
126
127int8_t can_read_rx1(struct can_device *dev, struct CAN_frame *out) {
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}
158
159int can_rxq_add(struct CAN_frame *msg) {
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}
169
170// Pull from RX buffer
171int can_rxq_pull(struct CAN_frame *out) {
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}
180
181//------------------//
182// MCP2515 Specific //
183//------------------//
184
185// External interrupt PE0, From MCP2515
186ISR(INT2_vect) {
187
188 // LOG_INF("External interrupt")
189 uint8_t status;
191 &status); // MCP2515_read_status(can_irq, &status);
192
193 if (status & MCP2515_RX0IF) {
196 LOG_INF("RX0 Full");
197 }
198
199 if (status & MCP2515_RX1IF) {
202 LOG_INF("RX1 Full");
203 }
204
205 if (status & tx_buff_0_busy) {
206 LOG_INF("TX0 Busy");
207 }
208
209 if (status & tx_buff_0_empty) {
210 LOG_INF("TX0 Empty");
211 }
212
213 // reset CANINTF / clear flag
215}
216
217int8_t MCP2515_init(struct can_device *dev) {
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}
316
317// Write data to register beginning at selected address.
318int8_t MCP2515_write(struct can_device *dev, uint8_t addr, uint8_t data) {
319
320 unsigned char frame[3] = {MCP2515_WRITE, addr, data};
321 spi_send_n(&dev->spi, frame, 3);
322
323 return 0;
324}
325
326int8_t MCP2515_write_n(struct can_device *dev, uint8_t addr, uint8_t *data) {
327
328 unsigned char frame[10] = {MCP2515_WRITE, addr, data[0], data[1], data[2],
329 data[3], data[4], data[5], data[6], data[7]};
330 spi_send_n(&dev->spi, frame, 2 + 8);
331
332 return 0;
333}
334
335// Read a specefic RX BUFFER see operation on pg 66 in CAN controller datasheet
336/*
337int8_t MCP2515_read(struct can_device *dev, uint8_t addr, uint8_t *out) {
338
339 // Make sure we are writing to somthing
340 if (!out) {
341 return -1;
342 }
343
344 unsigned char tx[3] = {MCP2515_READ, addr, 0xff};
345 unsigned char rx[3];
346 spi_duplex(&dev->spi, tx, rx, 3);
347 //spi_push(&dev->spi, tx[0], TRASHCAN);
348 //spi_push(&dev->spi, tx[1], TRASHCAN);
349 //spi_recieve(&dev->spi, out);
350
351 return 0;
352}*/
353
354int8_t MCP2515_read(struct can_device *dev, uint8_t addr, uint8_t *out) {
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}
368
369// Instructs controller to begin message transmission sequence for
370// any of the transmit buffers.
371int8_t MCP2515_request_to_send(struct can_device *dev, uint8_t buffer) {
372
373 spi_send(&dev->spi, buffer);
374
375 return 0;
376}
377
378// Set or clear individual bits in a particular register
379int8_t MCP2515_bit_modify(struct can_device *dev, uint8_t reg, uint8_t mask,
380 uint8_t set_val) {
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}
388
389// Resets internal registers to default state, this sets Config mode
390int8_t MCP2515_reset(struct can_device *dev) {
391
392 spi_send(&dev->spi, MCP2515_RESET);
393
394 return 0;
395}
396
397// Quick polling command that reads several status bits for transmit and receive
398// functions.
399int8_t MCP2515_read_status(struct can_device *dev, uint8_t *out) {
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}
static volatile uint8_t rxq_head
Definition can.c:16
ISR(INT2_vect)
Definition can.c:186
struct can_device * can_irq
Definition can.c:13
int8_t MCP2515_write_n(struct can_device *dev, uint8_t addr, uint8_t *data)
Definition can.c:326
struct CAN_frame new_message
Definition can.c:14
struct CAN_frame rxq[CAN_RXQ_SIZE]
Definition can.c:17
static volatile uint8_t rxq_tail
Definition can.c:16
CAN driver.
int can_rxq_add(struct CAN_frame *msg)
Add a CAN frame to the internal receive queue.
Definition can.c:159
int8_t can_write(struct can_device *dev, struct CAN_frame msg)
Write a CAN frame to the MCP2515 transmit buffer.
Definition can.c:49
int8_t MCP2515_read_status(struct can_device *dev, uint8_t *out)
Definition can.c:399
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_request_to_send(struct can_device *dev, uint8_t buffer)
Definition can.c:371
int8_t can_init(struct can_device *dev)
Initialize a CAN device.
Definition can.c:22
int8_t can_read_rx1(struct can_device *dev, struct CAN_frame *out)
Read a message from RX buffer 1.
Definition can.c:127
int8_t MCP2515_read(struct can_device *dev, uint8_t addr, uint8_t *out)
Definition can.c:354
#define CAN_RXQ_SIZE
Definition can.h:27
int8_t MCP2515_write(struct can_device *dev, uint8_t addr, uint8_t data)
Definition can.c:318
int8_t MCP2515_init(struct can_device *dev)
Definition can.c:217
int can_rxq_pull(struct CAN_frame *out)
Pull a CAN frame from the internal receive queue.
Definition can.c:171
int8_t MCP2515_reset(struct can_device *dev)
Definition can.c:390
int8_t can_read_rx0(struct can_device *dev, struct CAN_frame *out)
Read a message from RX buffer 0.
Definition can.c:95
#define LOG_INF(msg)
Definition log.h:59
#define LOG_ERR(msg, status)
Definition log.h:72
#define LOG_MODULE_DEFINE(name)
Definition log.h:39
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_duplex(enum spi_slave *slave, unsigned char *data, unsigned char *out, int length)
Full-duplex SPI transfer.
Definition spi.c:131
int spi_send(enum spi_slave *slave, unsigned char data)
Send a single byte to a slave.
Definition spi.c:86
int spi_init(void)
Initialize SPI in master mode.
Definition spi.c:9
#define TRASHCAN
Definition utils.h:19
Logging interface for debug messages.
#define MCP2515_RXB1SIDL
Definition mcp.h:55
#define MCP2515_CANINTE
Definition mcp.h:43
#define MCP2515_CANINTF
Definition mcp.h:44
#define MCP2515_TXB0SIDH
Definition mcp.h:154
#define MCP2515_RTS_TX0
Definition mcp.h:80
#define MCP2515_RXB0D0
Definition mcp.h:162
#define MCP2515_RXB1D0
Definition mcp.h:58
#define MODE_NORMAL
Definition mcp.h:103
#define MCP2515_CNF3
Definition mcp.h:40
#define MCP2515_VAL_CNF2
Definition mcp.h:99
#define MCP2515_TXB0EID8
Definition mcp.h:156
#define MCP2515_NO_IRQ
Definition mcp.h:64
#define MCP2515_RX_IRQ
Definition mcp.h:63
#define tx_buff_0_busy
Definition mcp.h:167
#define MCP2515_CANSTAT
Definition mcp.h:16
#define MCP2515_TXB0SIDL
Definition mcp.h:155
#define MODE_CONFIG
Definition mcp.h:107
#define MCP2515_RESET
Definition mcp.h:92
#define MCP2515_TXB0CTRL
Definition mcp.h:46
#define CAN_INTERRUPT_ISR_REGISTER
Definition mcp.h:177
#define MCP2515_CNF2
Definition mcp.h:41
#define MCP2515_RXB1DLC
Definition mcp.h:57
#define MCP2515_RXB0CTRL
Definition mcp.h:49
#define MCP2515_VAL_CNF1
Definition mcp.h:98
#define MCP2515_RX0IF
Definition mcp.h:141
#define MCP2515_READ
Definition mcp.h:72
#define MCP2515_CANCTRL
Definition mcp.h:17
#define MCP2515_TXRTS_CONF
Definition mcp.h:94
#define MCP2515_TXB0EID0
Definition mcp.h:56
#define TXB0DLC
Definition mcp.h:175
#define MCP2515_RXB0SIDL
Definition mcp.h:51
#define MCP2515_RXB1SIDH
Definition mcp.h:54
#define MCP2515_CNF1
Definition mcp.h:42
#define tx_buff_0_empty
Definition mcp.h:168
#define MCP2515_TXRTSCTRL
Definition mcp.h:151
#define MCP2515_READ_STATUS
Definition mcp.h:88
#define MODE_MASK
Definition mcp.h:109
#define MCP2515_TXB0D0
Definition mcp.h:159
#define MCP2515_RX1IF
Definition mcp.h:142
#define MCP2515_VAL_CNF3
Definition mcp.h:100
#define MCP2515_WRITE
Definition mcp.h:70
#define MCP2515_RXB0SIDH
Definition mcp.h:50
#define MCP2515_RXB1CTRL
Definition mcp.h:53
#define MCP2515_RXB0DLC
Definition mcp.h:52
#define MCP2515_BITMOD
Definition mcp.h:74
SPI driver.
Represents a full CAN frame for sending/receiving.
Definition can.h:53
uint8_t extended
Definition can.h:57
uint8_t dlc
Definition can.h:55
uint32_t id
Definition can.h:54
char data[8]
Definition can.h:56
Represents a CAN device, storing the SPI slave controlling the MCP2515.
Definition can.h:43
enum spi_slave spi
Definition can.h:44