#define F_CPU 8000000 #include #include #include #include #include #include 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) { }