/* addrs: SSSEEEEE * 8 -> extended addr * 14 -> unused */ #define CANA_TIME 0x10080000 #define CANA_DISCOVERY 0x4c080000 #define CANA_DISCOVERY_F(pg,dst) (CANA_DISCOVERY | (((uint32_t)(pg) & 0xf) << 12) | ((dst) & 0xfff)) #define CANA_LIGHT 0xcc080000 #define CANA_LIGHT_F(src,dst) (CANA_LIGHT | (((src) & 0x3f) << 12) | ((dst) & 0xfff)) #define CANA_SENSOR 0xe6080000 #define CANA_SENSOR_F(src) (CANA_SENSOR | ((src) & 0xfff)) #define CANA_DEBUG 0xe7000000 #define CANA_PROTOCOL 0xffe80000 #define can_rx_isext() (can_rx_addr.b[1] & 0x08) #define can_rx_ext_rr() (can_rx_dlc & 0x40) #define can_rx_ext_rr2(cst) (cst.rx_dlc & 0x40) #define can_rx_len() (can_rx_dlc & 0x0f) #define can_rx_len2(cst) (cst.rx_dlc & 0x0f) #define can_rx_sublab_proto() (uint16_t)((can_rx_addr.b[0] << 8) | (can_rx_addr.b[1] & 0xe8)) #define can_rx_sublab_proto2(cst) (uint16_t)((cst.rx_addr.b[0] << 8) | (cst.rx_addr.b[1] & 0xe8)) #define can_rx_sublab_addr() (((can_rx_addr.b[2] & 0x0f) << 8) | can_rx_addr.b[3]) #define can_rx_sublab_addr2(cst) (((cst.rx_addr.b[2] & 0x0f) << 8) | cst.rx_addr.b[3]) #define can_rx_sublab_disco_page() ((can_rx_addr.b[2] & 0xf0) >> 4) #define can_rx_sublab_disco_page2(cst) ((cst.rx_addr.b[2] & 0xf0) >> 4) #ifndef R0KET #define spi_ss(x) PORTB = ((x) << B_SS) | 0x3; 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 MCP2515_RDSTAT 0xa0 #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; } #ifndef R0KET #define can_irq_cli() EIMSK &= ~(1 << INT0) #define can_irq_sei() EIMSK |= (1 << INT0) #else #define can_irq_cli() cli() #define can_irq_sei() sei() #endif /* 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, const uint8_t *data) { can_irq_cli(); 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); can_irq_sei(); } static bool can_tx_busy(void) { uint8_t status; can_irq_cli(); spi_ss(0); spi_wrrd(MCP2515_RDSTAT); status = spi_wrrd(0xff); spi_ss(1); can_irq_sei(); return status & 0x04; } #ifndef R0KET struct can { union can_rxa { uint8_t b[4]; uint32_t u; } rx_addr; uint8_t rx_dlc; uint8_t rx_data[8]; } can; #define can_rx_addr can.rx_addr #define can_rx_dlc can.rx_dlc #define can_rx_data can.rx_data #define can_rx_avail() (can_rx_addr.u) #define can_rx_pop() do { can_rx_addr.u = 0; } while (0) static void can_rxh(uint8_t buffer) { uint8_t c, byte; #ifdef CAN_DBG_IN_IRQ if (buffer) uart_puts("can: RX1IF\n"); else uart_puts("can: RX0IF\n"); #endif spi_ss(0); spi_wrrd(0x90 + 0x04 * buffer); if (can_rx_addr.u) { spi_wrrd(0xff); spi_ss(1); uart_puts("-- CAN RX overrun\n"); return; }; c = 0; #ifdef CAN_DBG_IN_IRQ #define rdaddr() byte = spi_wrrd(0xff); uart_puthex(byte); can_rx_addr.b[c++] = byte #else #define rdaddr() byte = spi_wrrd(0xff); can_rx_addr.b[c++] = byte #endif rdaddr(); rdaddr(); rdaddr(); rdaddr(); can_rx_dlc = spi_wrrd(0xff); #ifdef CAN_DBG_IN_IRQ 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"); #else for (c = 0; c < (can_rx_dlc & 0x0f); c++) can_rx_data[c] = spi_wrrd(0xff); #endif spi_ss(1); #ifdef CAN_USER_IRQH can_user_irqh(); #endif } ISR(INT0_vect) { uint8_t canintf, eflg, canstat; #ifdef CAN_DBG_IN_IRQ #ifdef HAVE_TICK uart_puttick(); #endif // dbg_dump_ret(); uart_puts("can: irqh<"); #endif 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); #ifdef CAN_DBG_IN_IRQ uart_puthex(canintf); uart_puthex(eflg); uart_puthex(canstat); uart_puts(">\n"); #endif 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 can_rx_addr.u = 0; 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); #if 0 uart_puts("can: status "); uart_puthex(status); uart_puts("\n"); #endif }