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); }
// ---------------------------------------------------------------------------- uint8_t mcp2515_get_message(tCAN *message) { // read status uint8_t status = mcp2515_read_status(SPI_RX_STATUS); uint8_t addr; uint8_t t; if (bit_is_set(status,6)) { // message in buffer 0 addr = SPI_READ_RX; } else if (bit_is_set(status,7)) { // message in buffer 1 addr = SPI_READ_RX | 0x04; } else { // Error: no message available return 0; } RESET(MCP2515_CS); spi_putc(addr); // read id message->raw_data[0] = spi_putc(0xff); message->raw_data[1] = spi_putc(0xff); message->raw_data[2] = spi_putc(0xff); message->raw_data[3] = spi_putc(0xff); message->raw_data[4] = spi_putc(0xff); message->id = (uint16_t)message->raw_data[0] << 3; message->id |= message->raw_data[1] >> 5; // read DLC uint8_t length = message->raw_data[4] & 0x0f; message->header.length = length; message->header.rtr = (bit_is_set(status, 3)) ? 1 : 0; // read data for (t=0;t<length;t++) { message->data[t] = spi_putc(0xff); message->raw_data[t + 5] = message->data[t]; } SET(MCP2515_CS); // clear interrupt flag if (bit_is_set(status, 6)) { mcp2515_bit_modify(CANINTF, (1<<RX0IF), 0); } else { mcp2515_bit_modify(CANINTF, (1<<RX1IF), 0); } return (status & 0x07) + 1; }
// ---------------------------------------------------------------------------- void mcp2515_wakeup(void) { // reset int enable and cancel the interrupt flag mcp2515_bit_modify(CANINTE, (1<<WAKIE), 0); mcp2515_bit_modify(CANINTF, (1<<WAKIF), 0); // re-enable the 2551 mcp2515_bit_modify(BFPCTRL, (1<<B1BFS), 0); // when we get up of sleep, we are in listen mode, return into normal mode mcp2515_set_mode(NORMAL_MODE); }
// ---------------------------------------------------------------------------- void mcp2515_sleep(void) { // put also the 2551 in standby mode // for this, connect RX1BF to the RS pin of the 2551 mcp2515_bit_modify(BFPCTRL, (1<<B1BFS), (1<<B1BFS)); // put the 2515 in sleep more mcp2515_set_mode(SLEEP_MODE); // enable generating an interrupt for wakeup when activity on bus mcp2515_bit_modify(CANINTE, (1<<WAKIE), (1<<WAKIE)); }
/** * Initialize the can controller */ void can_init(void) { mcp2515_init(); mcp2515_static_filter(can_filter); mcp2515_bit_modify(CANCTRL, (1<<REQOP2) | (1<<REQOP1) | (1<<REQOP0), 0); }
char CanbusClass::message_tx(void) { tCAN message; // some test values(???) [einige Testwerte ] message.id = 0x7DF; message.header.rtr = 0; message.header.length = 8; message.data[0] = 0x02; message.data[1] = 0x01; message.data[2] = 0x05; message.data[3] = 0x00; message.data[4] = 0x00; message.data[5] = 0x00; message.data[6] = 0x00; message.data[7] = 0x00; // mcp2515_bit_modify(CANCTRL, (1<<REQOP2)|(1<<REQOP1)|(1<<REQOP0), (1<<REQOP1)); mcp2515_bit_modify(CANCTRL, (1<<REQOP2)|(1<<REQOP1)|(1<<REQOP0), 0); if (mcp2515_send_message(&message)) { // SET(LED2_HIGH); return 1; } else { // PRINT("Error: Could not retrieve message\n\n"); return 0; } return 1; }
void can_test_loopback(void){ mcp2515_bit_modify(MCP_CANCTRL__SET_MODE_LOOPBACK); printf("MCP_CANCTRL: 0x%02x (should be 0x47)\n", mcp2515_read(MCP_CANCTRL)); printf("MCP_CANSTAT: 0x%02x (should be 0x40)\n", mcp2515_read(MCP_CANSTAT)); can_msg_t msg1; can_msg_t msg2; msg1.id = 9; msg1.length = 5; for(int i = 0; i < 8; i++){ msg1.data.bytes[i] = i*i; } while(1){ can_sendmsg(msg1); can_printmsg(msg1); msg2 = can_recvmsg(); can_printmsg(msg2); msg1.data.bytes[0]++; _delay_ms(1000); } }
char CanbusClass::message_tx(void) { tCAN message; // einige Testwerte message.id = 0x7DF; message.header.rtr = 0; message.header.length = 8; message.data[0] = 0x02; message.data[1] = 0x01; message.data[2] = 0x05; message.data[3] = 0x00; message.data[4] = 0x00; message.data[5] = 0x00; message.data[6] = 0x00; message.data[7] = 0x00; // mcp2515_bit_modify(CANCTRL, (1<<REQOP2)|(1<<REQOP1)|(1<<REQOP0), (1<<REQOP1)); mcp2515_bit_modify(CANCTRL, (1<<REQOP2)|(1<<REQOP1)|(1<<REQOP0), 0); if (mcp2515_send_message(&message)) { // SET(LED2_HIGH); return 1; } else { // PRINT("Fehler: konnte die Nachricht nicht auslesen\n\n"); return 0; } return 1; }
/** * Report errors * * MCP2515 does automatic error recovery when the it enters bus-off mode. * There is nothing we can do other than report to the user. */ static void report_error(void) { uint8_t flags; /* Read the error flag */ flags = mcp2515_read_reg(EFLG); if (flags & (EFLG_RX0OVR | EFLG_RX1OVR)) { #if DEBUG > 1 printf("CAN: Receive buffer overflow!\n"); #endif /* Overflow flags need to be cleared manually. */ mcp2515_bit_modify(EFLG, flags & (EFLG_RX0OVR | EFLG_RX1OVR), 0); } #if DEBUG > 0 if (flags & EFLG_TXBO) { printf("CAN: Enter Bus-off mode, too many errors.\n"); } if (flags & EFLG_RXEP) { printf("CAN: Enter receive error-passive mode.\n"); } if (flags & EFLG_TXEP) { printf("CAN: Enter transmit error-passive mode.\n"); } #endif #if DEBUG > 1 if (flags & EFLG_TXWAR) { printf("CAN: Transmit error warning.\n"); } if (flags & EFLG_RXWAR) { printf("CAN: Receive error warning.\n"); } #endif /* Clear interrupt flags */ mcp2515_bit_modify(CANINTF, CANINTF_ERRIF, 0); }
char CanbusClass::message_tx(tCAN *msg) { tCAN message; message = *msg; mcp2515_bit_modify(CANCTRL, (1<<REQOP2)|(1<<REQOP1)|(1<<REQOP0), 0); if (mcp2515_send_message(&message)) { return 1; } else { return 0; } }
/** * Message error * * This error is intended to be used for detecting baud rate in Listen-only * mode. */ static void report_message_error(void) { #if DEBUG > 0 printf("%s\n", __func__); #endif enum op_mode mode; mode = get_mode(); if (mode == REQOP_LISTEN) { set_mode(REQOP_CONFIG); /* Auto baud rate detection. */ set_mode(REQOP_LISTEN); } /* Clear interrupt flags */ mcp2515_bit_modify(CANINTF, CANINTE_MERRE, 0); }
// ---------------------------------------------------------------------------- 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 } }
/** * Put message queue into TXB. * * @tx: TXB bits(Bit 0 -- TXB0, Bit 1 -- TXB1, Bit 2 -- TXB2) */ static void transmit_message(uint8_t tx) { struct can_frame frame; uint8_t rts = 0; /* Clear interrupt flags */ mcp2515_bit_modify(CANINTF, tx << TXIF_SHF, 0); /* Load messages into empty TX buffers. */ for (int i = TXB_NUM - 1; i >= 0; i--) { if (tx & BIT(i)) { canid_clear_cache(i); switch (i) { case 0: txb0_ack_emit(); break; case 1: txb1_ack_emit(); break; case 2: txb2_ack_emit(); break; default: break; } if (tx_queue_pop(&frame)) { /* Make sure the previous message is sent. */ while (mcp2515_read_reg(TXBCTRL(i) & TXBCTRL_TXREQ)); load_txb(i, &frame); rts |= BIT(i); } else { /* The TX queue is empty, stop transmission. */ sync_spinlock_lock(&txb_lock); xmit_stopped = 1; sync_spinlock_unlock(&txb_lock); } } } /* Initiating transmission */ mcp2515_rts(rts); }
void CAN_init(){ clear_bit(INTERRUPT_DDR, INTERRUPT_BIT); //Input on the interrupt pin uint8_t value; SPI_init(); // Initialize SPI mcp2515_reset(); // Send reset-command _delay_us(20); // Self-test value = mcp2515_read(MCP_CANSTAT); if ((value & MODE_MASK) != MODE_CONFIG) { puts("MCP2515 is NOT in configuration mode after reset!\n"); } //Sets up RXBOCTRL //RXM = 01, activate filter, only short ID mcp2515_bit_modify(MCP_RXB0CTRL, MCP_RXB0RXM_MASK, 1 << 5); //BUKT: 1 -> transfers to RXB1 when RXB0 is full mcp2515_bit_modify(MCP_RXB0CTRL, MCP_RXB0BUKT_MASK, 1 << 2); //RXB1CTRL //RXM = 01, activate filter, only short ID mcp2515_bit_modify(MCP_RXB1CTRL, MCP_RXB1RXM_MASK, 1 << 5); //Set interrupt enable //MERRE = 0 Message error interrupt //WAKIE = 0 (We dont use sleep) //ERRIE = 1 Error interrupt //TX2IE = 0 Transmit 2 empty interrupt //TX1IE = 0 Transmit 1 empty interrupt //TX0IE = 0 Transmit 0 empty interrupt //RX1IE = 1 Interrupt when there is data RX1 //RX0IE = 1 Interrupt when there is data RX2 mcp2515_write(MCP_CANINTE, 0b00000011); //Filters: //Mask for RX0 mcp2515_write(MCP_RXM0SIDH, NODE2_CANID_H_MASK >> 3); mcp2515_bit_modify(MCP_RXM0SIDL, 0b11100000U, NODE2_CANID_H_MASK << 5); //Mask for RX1 mcp2515_write(MCP_RXM1SIDH, NODE2_CANID_L_MASK >> 3); mcp2515_bit_modify(MCP_RXM1SIDL, 0b11100000U, NODE2_CANID_L_MASK << 5); //Filter 0 (RX0, goes to RX1 if RX0 is full) mcp2515_write(MCP_RXF0SIDH, NODE2_CANID_HIGHPRIO_0 >> 3); mcp2515_bit_modify(MCP_RXF0SIDL, 0b11100000U, NODE2_CANID_HIGHPRIO_0 << 5); //Filter 1 (RX0, goes to RX1 if RX0 is full) mcp2515_write(MCP_RXF1SIDH, NODE2_CANID_HIGHPRIO_1 >> 3); mcp2515_bit_modify(MCP_RXF1SIDL, 0b11100000U, NODE2_CANID_HIGHPRIO_1 << 5); //Filter 2 (RX1) mcp2515_write(MCP_RXF2SIDH, NODE2_CANID_0 >> 3); mcp2515_bit_modify(MCP_RXF2SIDL, 0b11100000U, NODE2_CANID_0 << 5); //Filter 3 (RX1) mcp2515_write(MCP_RXF3SIDH, NODE2_CANID_1 >> 3); mcp2515_bit_modify(MCP_RXF3SIDL, 0b11100000U, NODE2_CANID_1 << 5); //Filter 4 (RX1) mcp2515_write(MCP_RXF4SIDH, NODE2_CANID_2 >> 3); mcp2515_bit_modify(MCP_RXF4SIDL, 0b11100000U, NODE2_CANID_2 << 5); //Filter 5 (RX1) mcp2515_write(MCP_RXF5SIDH, NODE2_CANID_3 >> 3); mcp2515_bit_modify(MCP_RXF5SIDL, 0b11100000U, NODE2_CANID_3 << 5); CAN_all_int_clear(); mcp2515_bit_modify(MCP_CANCTRL, MODE_MASK, MODE_NORMAL); }
char CanbusClass::ecu_req(unsigned char pid, char *buffer) { tCAN message; float engine_data; int timeout = 0; char message_ok = 0; // Prepair message message.id = PID_REQUEST; message.header.rtr = 0; message.header.length = 8; message.data[0] = 0x02; message.data[1] = 0x01; message.data[2] = pid; message.data[3] = 0x00; message.data[4] = 0x00; message.data[5] = 0x00; message.data[6] = 0x00; message.data[7] = 0x00; mcp2515_bit_modify(CANCTRL, (1<<REQOP2)|(1<<REQOP1)|(1<<REQOP0), 0); if (mcp2515_send_message(&message)) { } if (mcp2515_check_message()) { if (mcp2515_get_message(&message)) { switch(message.data[2]) { /* Details from http://en.wikipedia.org/wiki/OBD-II_PIDs */ case ENGINE_LOAD: // Throttle Position engine_data = (message.data[3]*100)/255; sprintf(buffer,"%d %% ",(int) engine_data); break; case ENGINE_RPM: // ((A*256)+B)/4 [RPM] engine_data = ((message.data[3]*256) + message.data[4])/4; sprintf(buffer,"%d rpm ",(int) engine_data); break; case ENGINE_COOLANT_TEMP: // A-40 [degree C] engine_data = message.data[3] - 40; sprintf(buffer,"%d degC",(int) engine_data); break; case VEHICLE_SPEED: // A [km] engine_data = message.data[3]; sprintf(buffer,"%d km ",(int) engine_data); break; case MAF_SENSOR: // ((256*A)+B) / 100 [g/s] engine_data = ((message.data[3]*256) + message.data[4])/100; sprintf(buffer,"%d g/s",(int) engine_data); break; case O2_VOLTAGE: // A * 0.005 (B-128) * 100/128 (if B==0xFF, sensor is not used in trim calc) engine_data = message.data[3]*0.005; sprintf(buffer,"%d V",(int) engine_data); break; case THROTTLE: // Throttle Position engine_data = (message.data[3]*100)/255; sprintf(buffer,"%d %% ",(int) engine_data); break; case INTAKE_AIR_TEMP: // A-40 [degree C] engine_data = message.data[3] - 40; sprintf(buffer,"%d degC",(int) engine_data); break; case FUEL_TAKE_LEVEL: // Fuel Tank Level engine_data = (message.data[3]*100)/255; sprintf(buffer,"%d %% ",(int) engine_data); break; case OBD_STANDARD: // OBD_STD sprintf(buffer,"%d ",(int) message.data[3]); break; } } } }
uint8_t mcp2515_get_message(can_t *msg) { uint8_t addr; #ifdef RXnBF_FUNKTION if (!IS_SET(MCP2515_RX0BF)) addr = SPI_READ_RX; else if (!IS_SET(MCP2515_RX1BF)) addr = SPI_READ_RX | 0x04; else return 0; #else // read status uint8_t status = mcp2515_read_status(SPI_RX_STATUS); if (_bit_is_set(status,6)) { // message in buffer 0 addr = SPI_READ_RX; } else if (_bit_is_set(status,7)) { // message in buffer 1 addr = SPI_READ_RX | 0x04; } else { // Error: no message available return 0; } #endif RESET(MCP2515_CS); spi_putc(addr); // CAN ID auslesen und ueberpruefen uint8_t tmp = mcp2515_read_id(&msg->id); #if SUPPORT_EXTENDED_CANID msg->flags.extended = tmp & 0x01; #else if (tmp & 0x01) { // Nachrichten mit extended ID verwerfen SET(MCP2515_CS); #ifdef RXnBF_FUNKTION if (!IS_SET(MCP2515_RX0BF)) #else if (_bit_is_set(status, 6)) #endif mcp2515_bit_modify(CANINTF, (1<<RX0IF), 0); else mcp2515_bit_modify(CANINTF, (1<<RX1IF), 0); return 0; } #endif // read DLC uint8_t length = spi_putc(0xff); #ifdef RXnBF_FUNKTION if (!(tmp & 0x01)) msg->flags.rtr = (tmp & 0x02) ? 1 : 0; else msg->flags.rtr = (length & (1<<RTR)) ? 1 : 0; #else msg->flags.rtr = (_bit_is_set(status, 3)) ? 1 : 0; #endif length &= 0x0f; msg->length = length; // read data for (uint8_t i=0;i<length;i++) { msg->data[i] = spi_putc(0xff); } SET(MCP2515_CS); // clear interrupt flag #ifdef RXnBF_FUNKTION if (!IS_SET(MCP2515_RX0BF)) #else if (_bit_is_set(status, 6)) #endif mcp2515_bit_modify(CANINTF, (1<<RX0IF), 0); else mcp2515_bit_modify(CANINTF, (1<<RX1IF), 0); CAN_INDICATE_RX_TRAFFIC_FUNCTION; #ifdef RXnBF_FUNKTION return 1; #else return (status & 0x07) + 1; #endif }
char CanbusClass::ecu_req(unsigned char pid, char *buffer) { tCAN message; float engine_data; int timeout = 0; char message_ok = 0; // Prepair message message.id = PID_REQUEST; message.header.rtr = 0; message.header.length = 8; message.data[0] = 0x02; message.data[1] = 0x01; message.data[2] = pid; message.data[3] = 0x00; message.data[4] = 0x00; message.data[5] = 0x00; message.data[6] = 0x00; message.data[7] = 0x00; mcp2515_bit_modify(CANCTRL, (1<<REQOP2)|(1<<REQOP1)|(1<<REQOP0), 0); // SET(LED2_HIGH); if (mcp2515_send_message(&message)) { } while(timeout < 4000) { timeout++; if (mcp2515_check_message()) { if (mcp2515_get_message(&message)) { if((message.id == PID_REPLY) && (message.data[2] == pid)) // Check message is the reply and its the right PID { switch(message.data[2]) { /* Details from http://en.wikipedia.org/wiki/OBD-II_PIDs */ case ENGINE_RPM: // ((A*256)+B)/4 [RPM] engine_data = ((message.data[3]*256) + message.data[4])/4; sprintf(buffer,"%d rpm ",(int) engine_data); break; case ENGINE_COOLANT_TEMP: // A-40 [degree C] engine_data = message.data[3] - 40; sprintf(buffer,"%d degC",(int) engine_data); break; case VEHICLE_SPEED: // A [km] engine_data = message.data[3]; sprintf(buffer,"%d km ",(int) engine_data); break; case MAF_SENSOR: // ((256*A)+B) / 100 [g/s] engine_data = ((message.data[3]*256) + message.data[4])/100; sprintf(buffer,"%d g/s",(int) engine_data); break; case O2_VOLTAGE: // A * 0.005 (B-128) * 100/128 (if B==0xFF, sensor is not used in trim calc) engine_data = message.data[3]*0.005; sprintf(buffer,"%d v",(int) engine_data); case THROTTLE: // Throttle Position engine_data = (message.data[3]*100)/255; sprintf(buffer,"%d %% ",(int) engine_data); break; } message_ok = 1; } } } if(message_ok == 1) return 1; } return 0; }
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); }; };
/** * 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); }
int main(void) { // Initialisiere die UART Schnittstelle uart_init(UART_BAUD_SELECT(9600UL, F_CPU)); // Aktiviere Interrupts sei(); // Umleiten der Standardausgabe => ab jetzt koennen wir printf() verwenden stdout = &mystdout; // Versuche den MCP2515 zu initilaisieren if (!mcp2515_init()) { PRINT("Fehler: kann den MCP2515 nicht ansprechen!\n"); for (;;); } else { PRINT("MCP2515 is aktiv\n\n"); } PRINT("Erzeuge Nachricht\n"); tCAN message; // einige Testwerte message.id = 0x123; message.header.rtr = 0; message.header.length = 2; message.data[0] = 0xab; message.data[1] = 0xcd; print_can_message(&message); PRINT("\nwechsle zum Loopback-Modus\n\n"); mcp2515_bit_modify(CANCTRL, (1<<REQOP2)|(1<<REQOP1)|(1<<REQOP0), (1<<REQOP1)); // Sende eine Nachricht if (mcp2515_send_message(&message)) { PRINT("Nachricht wurde in die Puffer geschrieben\n"); } else { PRINT("Fehler: konnte die Nachricht nicht senden\n"); } // warte ein bisschen _delay_ms(10); if (mcp2515_check_message()) { PRINT("Nachricht empfangen!\n"); // read the message from the buffers if (mcp2515_get_message(&message)) { print_can_message(&message); PRINT("\n"); } else { PRINT("Fehler: konnte die Nachricht nicht auslesen\n\n"); } } else { PRINT("Fehler: keine Nachricht empfangen\n\n"); } PRINT("zurueck zum normalen Modus\n\n"); mcp2515_bit_modify(CANCTRL, (1<<REQOP2)|(1<<REQOP1)|(1<<REQOP0), 0); // wir sind ab hier wieder mit dem CAN Bus verbunden PRINT("Versuche die Nachricht per CAN zu verschicken\n"); // Versuche nochmal die Nachricht zu verschicken, diesmal per CAN if (mcp2515_send_message(&message)) { PRINT("Nachricht wurde in die Puffer geschrieben\n\n"); } else { PRINT("Fehler: konnte die Nachricht nicht senden\n\n"); } PRINT("Warte auf den Empfang von Nachrichten\n\n"); while (1) { // warten bis wir eine Nachricht empfangen if (mcp2515_check_message()) { PRINT("Nachricht empfangen!\n"); // Lese die Nachricht aus dem Puffern des MCP2515 if (mcp2515_get_message(&message)) { print_can_message(&message); PRINT("\n"); } else { PRINT("Kann die Nachricht nicht auslesen\n\n"); } } } return 0; }