// ----------------------------------------------------------------------------- void mcp2515_regdump(void) { uint8_t mode = mcp2515_read_register( CANSTAT ); // change to configuration mode mcp2515_change_operation_mode( (1<<REQOP2) ); printf_P("MCP2515 Regdump:\n"); uint8_t i; for (i=0; i < 16; i++) { printf_P("%3i: %02x ", i, mcp2515_read_register(i)); printf_P("%3i: %02x ", i+16*1, mcp2515_read_register(i+16*1)); printf_P("%3i: %02x ", i+16*2, mcp2515_read_register(i+16*2)); printf_P("%3i: %02x ", i+16*3, mcp2515_read_register(i+16*3)); printf_P("%3i: %02x ", i+16*4, mcp2515_read_register(i+16*4)); printf_P("%3i: %02x ", i+16*5, mcp2515_read_register(i+16*5)); printf_P("%3i: %02x ", i+16*6, mcp2515_read_register(i+16*6)); printf_P("%3i: %02x\n", i+16*7, mcp2515_read_register(i+16*7)); } mcp2515_change_operation_mode( mode ); }
// ---------------------------------------------------------------------------- void mcp2515_set_mode(uint8_t IF, can_mode_t mode) { uint8_t reg = 0; if (mode == LISTEN_ONLY_MODE) { reg = (1<<REQOP1)|(1<<REQOP0); } else if (mode == LOOPBACK_MODE) { reg = (1<<REQOP1); } // set the new mode mcp2515_bit_modify(IF, CANCTRL, (1<<REQOP2)|(1<<REQOP1)|(1<<REQOP0), reg); while ((mcp2515_read_register(IF, CANSTAT) & 0xe0) != reg) { // wait for the new mode to become active } }
// ------------------------------------------------------------------------- uint8_t mcp2515_init(uint8_t speed) { SET(MCP2515_CS); SET_OUTPUT(MCP2515_CS); RESET(P_SCK); RESET(P_MOSI); RESET(P_MISO); SET_OUTPUT(P_SCK); SET_OUTPUT(P_MOSI); SET_INPUT(P_MISO); SET_INPUT(MCP2515_INT); SET(MCP2515_INT); // active SPI master interface SPCR = (1<<SPE)|(1<<MSTR) | (0<<SPR1)|(1<<SPR0); SPSR = 0; // reset MCP2515 by software reset. // After this he is in configuration mode. RESET(MCP2515_CS); spi_putc(SPI_RESET); SET(MCP2515_CS); // wait a little bit until the MCP2515 has restarted _delay_us(10); // load CNF1..3 Register RESET(MCP2515_CS); spi_putc(SPI_WRITE); spi_putc(CNF3); /* spi_putc((1<<PHSEG21)); // Bitrate 125 kbps at 16 MHz spi_putc((1<<BTLMODE)|(1<<PHSEG11)); spi_putc((1<<BRP2)|(1<<BRP1)|(1<<BRP0)); */ /* spi_putc((1<<PHSEG21)); // Bitrate 250 kbps at 16 MHz spi_putc((1<<BTLMODE)|(1<<PHSEG11)); spi_putc((1<<BRP1)|(1<<BRP0)); */ spi_putc((1<<PHSEG21)); // Bitrate 250 kbps at 16 MHz spi_putc((1<<BTLMODE)|(1<<PHSEG11)); //spi_putc(1<<BRP0); spi_putc(speed); // activate interrupts spi_putc((1<<RX1IE)|(1<<RX0IE)); SET(MCP2515_CS); // test if we could read back the value => is the chip accessible? if (mcp2515_read_register(CNF1) != speed) { SET(LED2_HIGH); return false; } // deaktivate the RXnBF Pins (High Impedance State) mcp2515_write_register(BFPCTRL, 0); // set TXnRTS as inputs mcp2515_write_register(TXRTSCTRL, 0); // turn off filters => receive any message mcp2515_write_register(RXB0CTRL, (1<<RXM1)|(1<<RXM0)); mcp2515_write_register(RXB1CTRL, (1<<RXM1)|(1<<RXM0)); // reset device to normal mode mcp2515_write_register(CANCTRL, 0); // SET(LED2_HIGH); return true; }
// ------------------------------------------------------------------------- bool mcp2515_init(can_bitrate_t bitrate) { if (bitrate >= 8) return false; SET(MCP2515_CS); SET_OUTPUT(MCP2515_CS); // Aktivieren der Pins fuer das SPI Interface RESET(P_SCK); RESET(P_MOSI); RESET(P_MISO); SET_OUTPUT(P_SCK); SET_OUTPUT(P_MOSI); SET_INPUT(P_MISO); // SPI Einstellung setzen mcp2515_spi_init(); // MCP2515 per Software Reset zuruecksetzten, // danach ist er automatisch im Konfigurations Modus RESET(MCP2515_CS); spi_putc(SPI_RESET); _delay_ms(1); SET(MCP2515_CS); // ein bisschen warten bis der MCP2515 sich neu gestartet hat _delay_ms(10); // CNF1..3 Register laden (Bittiming) RESET(MCP2515_CS); spi_putc(SPI_WRITE); spi_putc(CNF3); for (uint8_t i=0; i<3 ;i++ ) { spi_putc(pgm_read_byte(&_mcp2515_cnf[bitrate][i])); } // aktivieren/deaktivieren der Interrupts spi_putc(MCP2515_INTERRUPTS); SET(MCP2515_CS); // TXnRTS Bits als Inputs schalten mcp2515_write_register(TXRTSCTRL, 0); #if defined(MCP2515_INT) SET_INPUT(MCP2515_INT); SET(MCP2515_INT); #endif #ifdef RXnBF_FUNKTION SET_INPUT(MCP2515_RX0BF); SET_INPUT(MCP2515_RX1BF); SET(MCP2515_RX0BF); SET(MCP2515_RX1BF); // Aktivieren der Pin-Funktionen fuer RX0BF und RX1BF mcp2515_write_register(BFPCTRL, (1<<B0BFE)|(1<<B1BFE)|(1<<B0BFM)|(1<<B1BFM)); #else #ifdef MCP2515_TRANSCEIVER_SLEEP // activate the pin RX1BF as GPIO which is connected // to RS of MCP2551 and set it to 0 mcp2515_write_register(BFPCTRL, (1<<B1BFE)); #else // Deaktivieren der Pins RXnBF Pins (High Impedance State) mcp2515_write_register(BFPCTRL, 0); #endif #endif // Testen ob das auf die beschreibenen Register zugegriffen werden kann // (=> ist der Chip ueberhaupt ansprechbar?) bool error = false; if (mcp2515_read_register(CNF2) != pgm_read_byte(&_mcp2515_cnf[bitrate][1])) { error = true; } // Device zurueck in den normalen Modus versetzten // und aktivieren/deaktivieren des Clkout-Pins mcp2515_write_register(CANCTRL, CLKOUT_PRESCALER_); if (error) { return false; } else { while ((mcp2515_read_register(CANSTAT) & 0xe0) != 0) { // warten bis der neue Modus uebernommen wurde } return true; } }
uint8_t mcp2515_get_filter(uint8_t number, can_filter_t *filter) { uint8_t mask_address; uint8_t filter_address; uint8_t temp; uint8_t mode = mcp2515_read_register(CANSTAT); if (number > 5) return 0; // change to configuration mode mcp2515_change_operation_mode( (1<<REQOP2) ); if (number <= 1) { mask_address = RXM0SIDH; temp = mcp2515_read_register(RXB0CTRL); } else { mask_address = RXM1SIDH; temp = mcp2515_read_register(RXB1CTRL); } temp &= (1<<RXM1)|(1<<RXM0); if (temp == 0) { // filter and masks are disabled #if SUPPORT_EXTENDED_CANID filter->flags.extended = 0; #endif filter->flags.rtr = 0; filter->mask = 0; filter->id = 0; return 1; } #if SUPPORT_EXTENDED_CANID // transform bits so that they match the format from can.h temp >>= 5; temp = ~temp; if (temp & 1) temp = 0x3; filter->flags.extended = temp; #endif // read mask RESET(MCP2515_CS); spi_putc(SPI_READ); spi_putc(mask_address); mcp2515_read_id(&filter->mask); SET(MCP2515_CS); if (number <= 2) { filter_address = RXF0SIDH + number * 4; } else { filter_address = RXF3SIDH + (number - 3) * 4; } // read filter RESET(MCP2515_CS); spi_putc(SPI_READ); spi_putc(filter_address); mcp2515_read_id(&filter->id); SET(MCP2515_CS); // restore previous mode mcp2515_change_operation_mode( mode ); return 1; }
/** * Parse given command line * * @param line Line string to parse */ void parseLine(char * line) { unsigned char result = BELL; switch (line[0]) { case 'S': // Setup with standard CAN bitrates if (state == STATE_CONFIG) { switch (line[1]) { case '0': mcp2515_set_bittiming(MCP2515_TIMINGS_10K); result = CR; break; case '1': mcp2515_set_bittiming(MCP2515_TIMINGS_20K); result = CR; break; case '2': mcp2515_set_bittiming(MCP2515_TIMINGS_50K); result = CR; break; case '3': mcp2515_set_bittiming(MCP2515_TIMINGS_100K); result = CR; break; case '4': mcp2515_set_bittiming(MCP2515_TIMINGS_125K); result = CR; break; case '5': mcp2515_set_bittiming(MCP2515_TIMINGS_250K); result = CR; break; case '6': mcp2515_set_bittiming(MCP2515_TIMINGS_500K); result = CR; break; case '7': mcp2515_set_bittiming(MCP2515_TIMINGS_800K); result = CR; break; case '8': mcp2515_set_bittiming(MCP2515_TIMINGS_1M); result = CR; break; } } break; case 's': // Setup with user defined timing settings for CNF1/CNF2/CNF3 if (state == STATE_CONFIG) { unsigned long cnf1, cnf2, cnf3; if (parseHex(&line[1], 2, &cnf1) && parseHex(&line[3], 2, &cnf2) && parseHex(&line[5], 2, &cnf3)) { mcp2515_set_bittiming(cnf1, cnf2, cnf3); result = CR; } } break; case 'G': // Read given MCP2515 register { unsigned long address; if (parseHex(&line[1], 2, &address)) { unsigned char value = mcp2515_read_register(address); sendByteHex(value); result = CR; } } break; case 'W': // Write given MCP2515 register { unsigned long address, data; if (parseHex(&line[1], 2, &address) && parseHex(&line[3], 2, &data)) { mcp2515_write_register(address, data); result = CR; } } break; case 'V': // Get versions { usb_putch('V'); sendByteHex(VERSION_HARDWARE); sendByteHex(VERSION_FIRMWARE_MAJOR); result = CR; } break; case 'v': // Get firmware version { usb_putch('v'); sendByteHex(VERSION_FIRMWARE_MAJOR); sendByteHex(VERSION_FIRMWARE_MINOR); result = CR; } break; case 'N': // Get serial number { usb_putch('N'); sendHex(0xFFFF, 4); result = CR; } break; case 'O': // Open CAN channel if (state == STATE_CONFIG) { mcp2515_bit_modify(MCP2515_REG_CANCTRL, 0xE0, 0x00); // set normal operating mode clock_reset(); state = STATE_OPEN; result = CR; } break; case 'l': // Loop-back mode if (state == STATE_CONFIG) { mcp2515_bit_modify(MCP2515_REG_CANCTRL, 0xE0, 0x40); // set loop-back state = STATE_OPEN; result = CR; } break; case 'L': // Open CAN channel in listen-only mode if (state == STATE_CONFIG) { mcp2515_bit_modify(MCP2515_REG_CANCTRL, 0xE0, 0x60); // set listen-only mode state = STATE_LISTEN; result = CR; } break; case 'C': // Close CAN channel if (state != STATE_CONFIG) { mcp2515_bit_modify(MCP2515_REG_CANCTRL, 0xE0, 0x80); // set configuration mode state = STATE_CONFIG; result = CR; } break; case 'r': // Transmit standard RTR (11 bit) frame case 'R': // Transmit extended RTR (29 bit) frame case 't': // Transmit standard (11 bit) frame case 'T': // Transmit extended (29 bit) frame if (state == STATE_OPEN) { if (transmitStd(line)) { if (line[0] < 'Z') usb_putch('Z'); else usb_putch('z'); result = CR; } } break; case 'F': // Read status flags { unsigned char flags = mcp2515_read_register(MCP2515_REG_EFLG); unsigned char status = 0; if (flags & 0x01) status |= 0x04; // error warning if (flags & 0xC0) status |= 0x08; // data overrun if (flags & 0x18) status |= 0x20; // passive error if (flags & 0x20) status |= 0x80; // bus error usb_putch('F'); sendByteHex(status); result = CR; } break; case 'Z': // Set time stamping { unsigned long stamping; if (parseHex(&line[1], 1, &stamping)) { timestamping = (stamping != 0); result = CR; } } break; case 'm': // Set accpetance filter mask if (state == STATE_CONFIG) { unsigned long am0, am1, am2, am3; if (parseHex(&line[1], 2, &am0) && parseHex(&line[3], 2, &am1) && parseHex(&line[5], 2, &am2) && parseHex(&line[7], 2, &am3)) { mcp2515_set_SJA1000_filter_mask(am0, am1, am2, am3); result = CR; } } break; case 'M': // Set accpetance filter code if (state == STATE_CONFIG) { unsigned long ac0, ac1, ac2, ac3; if (parseHex(&line[1], 2, &ac0) && parseHex(&line[3], 2, &ac1) && parseHex(&line[5], 2, &ac2) && parseHex(&line[7], 2, &ac3)) { mcp2515_set_SJA1000_filter_code(ac0, ac1, ac2, ac3); result = CR; } } break; } usb_putch(result); }
bool mcp2515_set_filter(uint8_t number, const can_filter_t *filter) { uint8_t mask_address = 0; uint8_t mode = mcp2515_read_register(CANSTAT); if (number > 5) return false; // change to configuration mode mcp2515_change_operation_mode( (1<<REQOP2) ); // set filter mask if (number == 0) { mask_address = RXM0SIDH; #if SUPPORT_EXTENDED_CANID if (filter->flags.extended == 0x3) { // only extended identifier mcp2515_write_register(RXB0CTRL, (1<<RXM1)); } else if (filter->flags.extended == 0x2) { // only standard identifier mcp2515_write_register(RXB0CTRL, (1<<RXM0)); } else { // receive all messages mcp2515_write_register(RXB0CTRL, 0); } #else // Buffer 0: Empfangen aller Nachrichten mit Standard Identifier // die den Filter Kriterien gengen mcp2515_write_register(RXB0CTRL, (1<<RXM0)); #endif } else if (number == 2) { mask_address = RXM1SIDH; #if SUPPORT_EXTENDED_CANID if (filter->flags.extended == 0x3) { // only extended identifier mcp2515_write_register(RXB1CTRL, (1<<RXM1)); } else if (filter->flags.extended == 0x2) { // only standard identifier mcp2515_write_register(RXB1CTRL, (1<<RXM0)); } else { mcp2515_write_register(RXB1CTRL, 0); } #else // Buffer 1: Empfangen aller Nachrichten mit Standard Identifier // die den Filter Kriterien gengen mcp2515_write_register(RXB1CTRL, (1<<RXM0)); #endif } if (mask_address) { RESET(MCP2515_CS); spi_putc(SPI_WRITE); spi_putc(mask_address); #if SUPPORT_EXTENDED_CANID mcp2515_write_id(&filter->mask, (filter->flags.extended == 0x2) ? 0 : 1); #else mcp2515_write_id(&filter->mask); #endif SET(MCP2515_CS); _delay_us(1); } // write filter uint8_t filter_address; if (number >= 3) { number -= 3; filter_address = RXF3SIDH; } else { filter_address = RXF0SIDH; } RESET(MCP2515_CS); spi_putc(SPI_WRITE); spi_putc(filter_address | (number * 4)); #if SUPPORT_EXTENDED_CANID mcp2515_write_id(&filter->id, (filter->flags.extended == 0x2) ? 0 : 1); #else mcp2515_write_id(&filter->id); #endif SET(MCP2515_CS); _delay_us(1); // restore previous mode mcp2515_change_operation_mode( mode ); return true; }