summaryrefslogtreecommitdiff
path: root/can.c
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@diac24.net>2011-08-21 14:56:43 +0200
committerDavid Lamparter <equinox@diac24.net>2011-08-21 14:56:43 +0200
commitaa0a617f957de3c42a217283b8cc35db669d270c (patch)
treea04f6e7ed604abfc0dad81d1230158aba9070528 /can.c
initial commit
Diffstat (limited to 'can.c')
-rw-r--r--can.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/can.c b/can.c
new file mode 100644
index 0000000..6120d51
--- /dev/null
+++ b/can.c
@@ -0,0 +1,222 @@
+#define F_CPU 8000000
+#include <stdint.h>
+#include <stdbool.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/pgmspace.h>
+#include <util/delay.h>
+
+const uint8_t __signature[3] __attribute__((section (".signature"), used)) =
+ { SIGNATURE_2, SIGNATURE_1, SIGNATURE_0 };
+
+#include "uart.c"
+
+#define B_SCK 5
+#define B_MISO 4
+#define B_MOSI 3
+#define B_SS 2
+
+#define spi_ss(x) PORTB = ((x) << B_SS) | 0x3;
+
+static volatile bool canint = false;
+
+ISR(INT0_vect)
+{
+ uart_puts("can: interrupt\n");
+ canint = true;
+}
+
+static uint8_t spi_wrrd(uint8_t out)
+{
+ SPDR = out;
+ while (!(SPSR & (1 << SPIF)))
+ ;
+ return SPDR;
+}
+
+static void spi_performpgm(const prog_uint8_t *cmds, uint8_t len)
+{
+ const prog_uint8_t *end = cmds + len;
+ uint8_t c;
+
+ spi_ss(0);
+ while (cmds < end) {
+ c = pgm_read_byte(cmds);
+ spi_wrrd(c);
+ cmds++;
+ }
+ spi_ss(1);
+}
+#define spi_perform(...) do { \
+ static const uint8_t _mycmds[] PROGMEM = { __VA_ARGS__ }; \
+ spi_performpgm(_mycmds, sizeof(_mycmds)); } while (0)
+
+/* CAN configuration:
+ *
+ * CNF1 SJW = 1TQ 00xxxxxx
+ * BRP = /12 xx001011 (16 MHz assumed)
+ * = 0x0b
+ * CNF2 BTLMODE = cfg 1xxxxxxx
+ * SAM = once x0xxxxxx
+ * PS1 = 1TQ xx000xxx
+ * prop = 2TQ xxxxx001
+ * = 0x81
+ * CNF3 WAKFIL = off x0xxxxxx
+ * PS2 = 2TQ xxxxx001
+ * = 0x01
+ */
+
+#define MCP2515_WRITE 0x02
+#define MCP2515_READ 0x03
+#define MCP2515_RTS 0x80
+
+#define A_CNF3 0x28
+#define A_CANINTF 0x2c
+#define A_CANCTRL 0x2f
+#define A_TXB0CTRL 0x30
+#define A_TXB0SIDH 0x31
+#define A_RXB1CTRL 0x70
+
+static void can_init(void)
+{
+ spi_perform(MCP2515_WRITE, A_CANCTRL,
+ 0x80); /* CANCTRL: config mode */
+ spi_perform(MCP2515_WRITE, A_CNF3,
+ 0x01, /* CNF3 */
+ 0x81, /* CNF2 */
+ 0x0b, /* CNF1 */
+ 0xa4 /* CANINTE: MERRE, ERRIE, TX0IE */
+ );
+ spi_perform(MCP2515_WRITE, A_RXB1CTRL,
+ 0x60); /* x, RXM, x, RXRTR, FILHIT */
+ spi_perform(MCP2515_WRITE, A_CANCTRL,
+ 0x00); /* CANCTRL: normal mode */
+}
+
+static uint8_t can_CANSTAT(void)
+{
+ uint8_t canstat;
+
+ spi_ss(0);
+ spi_wrrd(0x03);
+ spi_wrrd(0x2e); /* addr(CANCTRL) */
+ canstat = spi_wrrd(0xff); /* CANSTAT */
+ spi_ss(1);
+ uart_puts("can: CANSTAT ");
+ uart_puthex(canstat);
+ uart_puts("\n");
+ return canstat;
+}
+
+static void can_send(void)
+{
+ uart_puts("can: transmit\n");
+ spi_perform(MCP2515_WRITE, A_TXB0SIDH,
+ 0x55, /* ID 10:3 */
+ 0x40, /* ID 2:0, x, EXIDE, x, EID 17:16 */
+ 0x00, /* EID 15:8 */
+ 0x00, /* EID 7:0 */
+ 0x00); /* x, RTR, xx, DLC */
+ spi_perform(MCP2515_RTS | 0x01);
+}
+
+static void can_int(void)
+{
+ uint8_t canintf, eflg, canstat;
+
+ uart_puts("can: irqh<");
+
+ spi_ss(0);
+ spi_wrrd(MCP2515_READ);
+ spi_wrrd(A_CANINTF);
+ canintf = spi_wrrd(0xff);
+ eflg = spi_wrrd(0xff);
+ canstat = spi_wrrd(0xff);
+ spi_ss(1);
+
+ uart_puthex(canintf);
+ uart_puthex(eflg);
+ uart_puthex(canstat);
+ uart_puts(">\n");
+
+ if (canintf & 0x80 || canintf & 0x04) {
+ uint8_t txb0ctrl;
+ spi_ss(0);
+ spi_wrrd(0x03);
+ spi_wrrd(0x30);
+ txb0ctrl = spi_wrrd(0xff);
+ spi_ss(1);
+ uart_puts("can: TXB0CTRL ");
+ uart_puthex(txb0ctrl);
+ uart_puts("\n");
+ }
+ if (canintf & 0x02) {
+ uint8_t rxb1dlc, c;
+ uart_puts("can: RX1IF\n");
+ spi_ss(0);
+ spi_wrrd(0x94);
+ uart_puthex(spi_wrrd(0xff));
+ uart_puthex(spi_wrrd(0xff));
+ uart_puthex(spi_wrrd(0xff));
+ uart_puthex(spi_wrrd(0xff));
+ rxb1dlc = spi_wrrd(0xff);
+ uart_puthex(rxb1dlc);
+ uart_puts("\n");
+ for (c = 0; c < rxb1dlc; c++)
+ uart_puthex(spi_wrrd(0xff));
+ uart_puts("\n");
+ spi_ss(1);
+ }
+
+ spi_perform(MCP2515_WRITE, A_CANINTF, 0x00);
+}
+
+int main(void)
+{
+ uint8_t status;
+
+ uart_init();
+
+ spi_ss(1);
+ DDRB = (1 << B_SCK) | (1 << B_MOSI) | (1 << B_SS);
+
+ /* divisor: 0 0 0 = fosc / 4 = 2 MHz */
+ SPCR = (1 << SPE) | (1 << MSTR);
+
+ /* INT0 */
+ EICRA = (1 << ISC01);
+ EIMSK = (1 << INT0);
+
+ sei();
+
+ uart_puts("\nspi: init ok\n");
+ _delay_ms(50);
+
+ spi_ss(0);
+ spi_wrrd(0xc0);
+ spi_ss(1);
+
+ _delay_ms(50);
+ spi_ss(0);
+ spi_wrrd(0xb0);
+ status = spi_wrrd(0xff);
+ spi_ss(1);
+ uart_puts("can: status ");
+ uart_puthex(status);
+ uart_puts("\n");
+
+ can_init();
+ can_CANSTAT();
+
+ while (1) {
+ if (canint) {
+ canint = false;
+ can_int();
+ }
+ _delay_ms(25);
+ }
+}
+
+void __do_copy_data(void) __attribute__((naked, section (".init4"), used));
+void __do_copy_data(void) { }
+