void mcp2515_static_filter(const prog_uint8_t *filter) { // change to configuration mode mcp2515_bit_modify(CANCTRL, 0xe0, (1<<REQOP2)); while ((mcp2515_read_register(CANSTAT) & 0xe0) != (1<<REQOP2)) ; mcp2515_write_register(RXB0CTRL, (1<<BUKT)); mcp2515_write_register(RXB1CTRL, 0); uint8_t i, j; for (i = 0; i < 0x30; i += 0x10) { RESET(MCP2515_CS); spi_putc(SPI_WRITE); spi_putc(i); for (j = 0; j < 12; j++) { if (i == 0x20 && j >= 0x08) break; spi_putc(pgm_read_byte(filter++)); } SET(MCP2515_CS); } mcp2515_bit_modify(CANCTRL, 0xe0, 0); }
void mcp2515_init(void) { // Aktivieren der Pins fuer das SPI Interface PORT_SPI &= ~((1 << PIN_NUM(P_SCK)) | (1 << PIN_NUM(P_MOSI))); DDR_SPI |= (1 << PIN_NUM(P_SCK)) | (1 << PIN_NUM(P_MOSI)); SET(MCP2515_CS); SET_OUTPUT(MCP2515_CS); // Aktivieren des SPI Master Interfaces SPCR = (1 << SPE) | (1 << MSTR) | R_SPCR; SPSR = R_SPSR; _delay_us(1); // MCP2515 per Software Reset zuruecksetzten, // danach ist er automatisch im Konfigurations Modus RESET(MCP2515_CS); spi_putc(SPI_RESET); SET(MCP2515_CS); // ein bisschen warten bis der MCP2515 sich neu gestartet hat _delay_ms(0.1); // Filter usw. setzen RESET(MCP2515_CS); spi_putc(SPI_WRITE); spi_putc(RXF0SIDH); for (uint8_t i = 0; i < sizeof(mcp2515_register_map); i++) { spi_putc(pgm_read_byte(&mcp2515_register_map[i])); } SET(MCP2515_CS); // nur Standard IDs, Message Rollover nach Puffer 1 mcp2515_write_register(RXB0CTRL, (0 << RXM1) | (1 << RXM0) | (1 << BUKT)); mcp2515_write_register(RXB1CTRL, (0 << RXM1) | (1 << RXM0)); // MCP2515 zurueck in den normalen Modus versetzten mcp2515_write_register(CANCTRL, CLKOUT_PRESCALER_); }
// ------------------------------------------------------------------------- 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; } }
/** * 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; }
void Speedo_CAN::init(){ // Interrupt for CAN Interface active, auf pk4, pcint20 can_missed_count=0; // Chipselect as output if(pConfig->get_hw_version()==7){ // Interrupt as Input with pull up CAN_DDR_CS_TILL_V7 &= ~(1<<CAN_INTERRUPT_PIN_V7); // input CAN_PORT_CS_TILL_V7 |= (1<<CAN_INTERRUPT_PIN_V7); // active low => pull up // CS as output CAN_DDR_CS_TILL_V7 |= (1<<CAN_PIN_CS_TILL_V7); PCMSK2|=(1<<PCINT20); // CAN interrupt pin v7 } else if(pConfig->get_hw_version()>7){ // CS Input with pull up CAN_DDR_CS_FROM_V8 &= ~(1<<CAN_INTERRUPT_PIN_FROM_V8); // input CAN_PORT_CS_FROM_V8 |= (1<<CAN_INTERRUPT_PIN_FROM_V8); // active low => pull up // CS as output CAN_DDR_CS_FROM_V8 |= (1<<CAN_PIN_CS_FROM_V8); PCMSK0|=(1<<PCINT4); // CAN interrupt pin v(>7) PCICR |=(1<<PCIE0); //new interrupt just for CAN }; /********************************************* MCP2515 SETUP ***********************************/ // MCP2515 per Software Reset zuruecksetzten, // danach ist der MCP2515 im Configuration Mode set_cs_high(false); //CS low spi_putc( SPI_CMD_RESET ); _delay_ms(1); set_cs_high(true); //CS high // etwas warten bis sich der MCP2515 zurueckgesetzt hat _delay_ms(10); /******************** BAUD Rate ************************************************ * Einstellen des Bit Timings * * Fosc = 16MHz * Bus Speed = 500 kHz * * Sync Seg = 1TQ * Prop Seg = (PRSEG + 1) * TQ = 1 TQ * Phase Seg1 = (PHSEG1 + 1) * TQ = 3 TQ * Phase Seg2 = (PHSEG2 + 1) * TQ = 3 TQ * * Bus speed = 1 / (Total # of TQ) * TQ * 500kHz= 1 / (8 * TQ) * TQ = 1/(500kHz*8) * TQ = 2 * (BRP + 1) / Fosc * 1/(500kHz*8) = 2 * (BRP + 1) / Fosc * 1/(500kHz*8) = 2 * (BRP + 1) / 16000kHz * 16000kHz/(500kHz*8*2) - 1 = BRP * * BRP = 1 ******************** BAUD Rate ************************************************/ // BRP = 1 mcp2515_write_register( CNF1, (1<<BRP0)); // Prop Seg und Phase Seg1 einstellen mcp2515_write_register( CNF2, (1<<BTLMODE)|(1<<PHSEG11) ); // Wake-up Filter deaktivieren, Phase Seg2 einstellen mcp2515_write_register( CNF3, (1<<PHSEG21) ); // Aktivieren der Rx Buffer Interrupts mcp2515_write_register( CANINTE, (1<<RX1IE)|(1<<RX0IE) ); /******************** FILTER ************************************************ * There are two input buffer: RXB0/1 * RXB0 has two Filters RXF0 / REF1 * RXB1 has four Filters RXF2 / REF3 / REF4 / REF5 * * BUKT * Additionally, the RXB0CTRL register can be configured * such that, if RXB0 contains a valid message and * another valid message is received, an overflow error * will not occur and the new message will be moved into * RXB1, regardless of the acceptance criteria of RXB1. * * RXBnCTRL.FILHITm determines if the Filter m is in use for buffer n * ******************** FILTER ************************************************/ // BUKT: RXB0 message will rollover and be written to RXB1 if RXB0 is full // RXM0: Only accept messages with standard identifiers that meet filter criteria mcp2515_write_register( RXB0CTRL, (1<<BUKT)|(1<<RXM0)); // use 11bit with filter + rollover mcp2515_write_register( RXB1CTRL, (1<<RXM0)); // use 11bit with filter /************************************************** Filter definition ************************************************** * CAN Filter: We have two Buffers. Each has a Mask RXM0SIDH/RXM0SIDL, RXM1SIDH/RXM1SIDL. * Buffer0 has two Filters RXF0 and RXF1 * Buffer1 has three addition Filters RXF2,RXF3,RXF4 and RXF5 * ***************************************************** TRIUMPH CAN ***************************************************** * If we are using the Triumph CAN, we have to Catch the IDs: 530,540,568,570 and avoid 518,519,550 * in addition 568 has a very high priority! Thus 568 should be accepted in buffer 0 to be rollover activ to buffer1 * * 568 = 0b 101 0110 1000 * Mask0 111 1111 1111 * Filter0 101 0110 1000 <- accept only 568 * Filter1 101 0110 1000 <- just a copy * * Buffer1 should catch 530,540,570 * 530 = 0b 101 0011 0000 * 570 = 0b 101 0111 0000 * 540 = 0b 101 0100 0000 * Mask 111 1111 1111 * Filter2 101 0011 0000 <- 530 RPM/Speed * Filter3 101 0111 0000 <- 570 Temp * Filter4 101 0100 0000 <- 540 Status * Filter5 101 0100 0000 <- just a copy * * ***************************************************** OBD2 ***************************************************** * We have to catch all IDs from 780-7FF, easy very low traffic compared to Triumph * * Mask0 111 1000 0000 * Mask1 111 1000 0000 * Filter0 111 1XXX XXXX * Filter1 111 1XXX XXXX * Filter2 111 1XXX XXXX * Filter3 111 1XXX XXXX * Filter4 111 1XXX XXXX * Filter5 111 1XXX XXXX * ************************************************** Filter definition **************************************************/ can_filter_t filter; if(can_bus_type==CAN_TYPE_TRIUMPH){ // Mask0 111 1111 1111 filter.id=0x568; filter.mask=0xffff; mcp2515_set_filter(0,&filter); mcp2515_set_filter(1,&filter); //Mask1 111 1000 1111 // Filter2 101 0011 0000 <- 530 // Filter3 101 0111 0000 <- 570 // Filter4 101 0100 0000 <- 540 // Filter5 101 0100 0000 <- just a copy filter.mask=0xffff; filter.id=0x530; mcp2515_set_filter(2,&filter); filter.id=0x540; mcp2515_set_filter(3,&filter); filter.id=0x570; mcp2515_set_filter(4,&filter); filter.id=0x570; mcp2515_set_filter(5,&filter); high_prio_processing=true; } else { // assume OBD2 as fallback // Mask0: 111 1000 0000 // Filter0 111 1000 0000 // Filter1 111 1000 0000 filter.mask=0b11110000000; filter.id=0b11110000000; mcp2515_set_filter(0,&filter); mcp2515_set_filter(1,&filter); // Mask1: 111 1000 0000 // Filter2 111 1000 0000 // Filter3 111 1000 0000 // Filter4 111 1000 0000 // Filter5 111 1000 0000 filter.mask=0b11110000000; filter.id=0b11110000000; mcp2515_set_filter(2,&filter); mcp2515_set_filter(3,&filter); mcp2515_set_filter(4,&filter); mcp2515_set_filter(5,&filter); high_prio_processing=false; } /* * Einstellen der Pin Funktionen */ // Deaktivieren der Pins RXnBF Pins (High Impedance State) mcp2515_write_register( BFPCTRL, 0 ); // TXnRTS Bits als Inputs schalten mcp2515_write_register( TXRTSCTRL, 0 ); // Device zurueck in den normalen Modus versetzten mcp2515_bit_modify( CANCTRL, 0xE0, 0); /********************************************* MCP2515 SETUP ***********************************/ _delay_ms(1); // to check if obd2 can is present, triumph talks alone if(can_bus_type==CAN_TYPE_OBD2){ request(CAN_CURRENT_INFO,CAN_RPM); }; };
uint8_t mcp2515_set_filter(uint8_t number, const can_filter_t *filter) { uint8_t mask_address = 0; if (number > 5) return false; // Konfiguration einschalten mcp2515_change_operation_mode( (1<<REQOP2) ); // Filtermaske setzen if (number == 0) { mask_address = RXM0SIDH; } else if (number == 2) { mask_address = RXM1SIDH; } if (mask_address) { RESET(MCP2515_CS); spi_putc(SPI_WRITE); spi_putc(mask_address); mcp2515_write_id(&filter->mask); asm volatile ("nop"); asm volatile ("nop"); SET(MCP2515_CS); asm volatile ("nop"); asm volatile ("nop"); } // Filter setzen 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)); mcp2515_write_id(&filter->id); asm volatile ("nop"); asm volatile ("nop"); SET(MCP2515_CS); asm volatile ("nop"); asm volatile ("nop"); if (number == 0) { mcp2515_write_register(RXB0CTRL, (1<<RXM1)); } else if (number==2) { mcp2515_write_register(RXB1CTRL, (1<<RXM1)); } ; // zurueck zum normalen modus mcp2515_write_register(CANCTRL, 0); return true; }