/* addrs: SSSEEEEE * 8 -> extended addr * 14 -> unused */ #define CANA_TIME 0x10080000 #define CANA_DISCOVERY 0x4c080000 #define CANA_LIGHT 0xcc080000 #define CANA_LIGHT_F(src,dst) (CANA_LIGHT | (((src) << 12) & 0x3f) | ((dst) & 0xfff)) #define CANA_SENSOR 0xe6080000 #define CANA_SENSOR_F(src) (CANA_SENSOR | ((src) & 0xfff)) #ifndef R0KET #define spi_ss(x) PORTB = ((x) << B_SS) | 0x3; static volatile bool canint = false; ISR(INT0_vect) { canint = true; } static uint8_t spi_wrrd(uint8_t out) { SPDR = out; while (!(SPSR & (1 << SPIF))) ; return SPDR; } static void spi_performpgm(const uint8_t * PROGMEM cmds, uint8_t len) { const uint8_t * PROGMEM end = cmds + len; uint8_t c; spi_ss(0); while (cmds < end) { c = pgm_read_byte(cmds); spi_wrrd(c); cmds++; } spi_ss(1); } #endif #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 MCP2515_WRTXB 0x40 #define MCP2515_WRTXB_DATA 0x01 #define MCP2515_WRTXB_TXB0 0x00 #define MCP2515_WRTXB_TXB1 0x02 #define MCP2515_WRTXB_TXB2 0x04 #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 */ #ifdef R0KET #define CNF1 0x05 /* 8 MHz crystal, divide by 6 */ #else #define CNF1 0x0b /* 16 MHz crystal, divide by 12 */ #endif spi_perform(MCP2515_WRITE, A_CNF3, 0x01, /* CNF3 */ 0x81, /* CNF2 */ CNF1, /* CNF1 */ 0xa7 /* CANINTE: MERRE, ERRIE, TX0IE, RX1IE, RX0IE */ ); 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; } /* daddr: * 31-24 ID 10:3 * 23-16 ID 2:0, x, EXIDE, x, EID17:16 * 15- 8 EID 15:8 * 7- 0 EID 7:0 */ static void can_send(uint32_t daddr, uint8_t len, uint8_t *data) { spi_ss(0); spi_wrrd(MCP2515_WRTXB | MCP2515_WRTXB_TXB0); spi_wrrd((daddr >> 24) & 0xff); spi_wrrd((daddr >> 16) & 0xff); spi_wrrd((daddr >> 8) & 0xff); spi_wrrd((daddr >> 0) & 0xff); spi_wrrd(len); while (len--) spi_wrrd(*data++); spi_ss(1); spi_perform(MCP2515_RTS | 0x01); } #ifndef R0KET union { uint8_t b[4]; uint32_t u; } can_rx_addr; uint8_t can_rx_dlc, can_rx_data[8]; static void can_rxh(uint8_t buffer) { uint8_t c, byte; if (buffer) uart_puts("can: RX1IF\n"); else uart_puts("can: RX0IF\n"); spi_ss(0); spi_wrrd(0x90 + 0x04 * buffer); c = 0; #define rdaddr() byte = spi_wrrd(0xff); uart_puthex(byte); can_rx_addr.b[c++] = byte rdaddr(); rdaddr(); rdaddr(); rdaddr(); can_rx_dlc = spi_wrrd(0xff); uart_puthex(can_rx_dlc); uart_puts("\n"); for (c = 0; c < (can_rx_dlc & 0x0f); c++) { byte = spi_wrrd(0xff); can_rx_data[c] = byte; uart_puthex(byte); } uart_puts("\n"); spi_ss(1); } static void can_int(void) { uint8_t canintf, eflg, canstat; #ifdef HAVE_TICK uart_puttick(); #endif 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(MCP2515_READ); spi_wrrd(A_TXB0CTRL); txb0ctrl = spi_wrrd(0xff); spi_ss(1); /* clear RTS */ if (txb0ctrl & 0x08) { spi_ss(0); spi_wrrd(MCP2515_WRITE); spi_wrrd(A_TXB0CTRL); spi_wrrd(0x00); spi_ss(1); } } if (canintf & 0x01) can_rxh(0); if (canintf & 0x02) can_rxh(1); spi_perform(MCP2515_WRITE, A_CANINTF, 0x00, 0x00); } #endif static void can_preinit(void) { spi_ss(1); #ifndef R0KET 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); _delay_ms(5); #endif /* chip reset */ spi_ss(0); spi_wrrd(0xc0); spi_ss(1); _delay_ms(5); spi_ss(0); spi_wrrd(0xb0); uint8_t status = spi_wrrd(0xff); spi_ss(1); uart_puts("can: status "); uart_puthex(status); uart_puts("\n"); }