diff options
author | David Lamparter <equinox@diac24.net> | 2011-08-21 14:56:43 +0200 |
---|---|---|
committer | David Lamparter <equinox@diac24.net> | 2011-08-21 14:56:43 +0200 |
commit | aa0a617f957de3c42a217283b8cc35db669d270c (patch) | |
tree | a04f6e7ed604abfc0dad81d1230158aba9070528 /can.c |
initial commit
Diffstat (limited to 'can.c')
-rw-r--r-- | can.c | 222 |
1 files changed, 222 insertions, 0 deletions
@@ -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) { } + |