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_write_register(uint8_t adress, uint8_t data ) { RESET(MCP2515_CS); spi_putc(SPI_WRITE); spi_putc(adress); spi_putc(data); SET(MCP2515_CS); }
// ------------------------------------------------------------------------- void mcp2515_bit_modify(uint8_t adress, uint8_t mask, uint8_t data) { RESET(MCP2515_CS); spi_putc(SPI_BIT_MODIFY); spi_putc(adress); spi_putc(mask); spi_putc(data); SET(MCP2515_CS); }
// ---------------------------------------------------------------------------- uint8_t mcp2515_read_status(uint8_t type) { uint8_t data; RESET(MCP2515_CS); spi_putc(type); data = spi_putc(0xff); SET(MCP2515_CS); return data; }
/** * \brief write to MCP2515 registers * * \param chip - select chip to use * \param address - register address of MCP2515 * \param data - data byte */ void write_register_mcp2515(eChipSelect chip, uint8_t address, uint8_t data) { // /CS of MCP2515 to Low unset_chip_select(chip); spi_putc(MCP2515_WRITE); spi_putc(address); spi_putc(data); // /CS of MCP2515 to High set_chip_select(chip); }
// ------------------------------------------------------------------------- uint8_t mcp2515_read_register(uint8_t adress) { uint8_t data; RESET(MCP2515_CS); spi_putc(SPI_READ); spi_putc(adress); data = spi_putc(0xff); SET(MCP2515_CS); return data; }
/* Configures the nRF2401 with the given number of bytes (1 - 15) of configuration data. */ static void nrf_configure (nrf_t nrf, uint8_t size) { nrf_obj_t *dev = nrf; uint8_t i; /* Put the nRF2401 into configuration mode. */ NRF_CE_LOW_SET (dev); NRF_CS_HIGH_SET (dev); DELAY_US (NRF_LINE_TIME_ENABLE_US); /* Decrementing logic is to ensure data is clocked out MSB first. */ for (i = size; i > 0; i--) { /* Write to the SPI port. */ spi_putc (dev->spi, dev->config.bytes[i - 1]); } DELAY_US (NRF_CONFIG_DELAY_US); /* Put the chip into standby mode. */ NRF_CS_LOW_SET (dev); DELAY_US (NRF_LINE_TIME_ENABLE_US); }
/** * \brief write masked bits to MCP2515 registers * * Note: Not all registers are able to provide this functionality. Mostly * configuration registers do. Read the datasheet for details. * * \param chip - select chip to use * \param address - register address of MCP2515 * \param mask - bit mask for modify * \param data - data byte */ void bit_modify_mcp2515(eChipSelect chip, uint8_t address, uint8_t mask, uint8_t data) { // /CS of MCP2515 to Low unset_chip_select(chip); spi_putc(MCP2515_BITMODIFY); spi_putc(address); spi_putc(mask); spi_putc(data); // /CS of MCP2515 to High set_chip_select(chip); }
uint8_t mcp2515_read_id(uint32_t *id) { uint8_t first; uint8_t tmp; first = spi_putc(0xff); tmp = spi_putc(0xff); if (tmp & (1 << IDE)) { // Nur Extended IDs empfangen *((uint16_t *) id + 1) = (uint16_t) first << 5; *((uint8_t *) id + 1) = spi_putc(0xff); *((uint8_t *) id + 2) |= (tmp >> 3) & 0x1C; *((uint8_t *) id + 2) |= tmp & 0x03; *((uint8_t *) id) = spi_putc(0xff); return TRUE; } else {
/** * \brief reads MCP2515 status registers * * \param chip - select chip to use * \param command - read quick status command of MCP2515 * \return value of status register */ uint8_t read_status_mcp2515(eChipSelect chip, uint8_t command) { uint8_t data; // /CS of MCP2515 to Low unset_chip_select(chip); // status commend to use spi_putc(command); // write something to SPI, so the byte can be read from SPI data = spi_putc(0xFF); // /CS of MCP2515 to High set_chip_select(chip); return (data); }
/** * \brief read from MCP2515 registers * * \param chip - select chip to use * \param address - register address of MCP2515 * \return data - data byte */ uint8_t read_register_mcp2515(eChipSelect chip, uint8_t address) { uint8_t data; // /CS of MCP2515 to Low unset_chip_select(chip); spi_putc(MCP2515_READ); spi_putc(address); // write something to SPI, so the byte can be read from SPI data = spi_putc(0xFF); // /CS of MCP2515 to High set_chip_select(chip); return (data); }
/** * \brief write sequential to MCP2515 registers * * \param chip - select chip to use * \param length - length of buffer * \param address - register address of MCP2515 (start) * \param data - data buffer */ void write_multi_registers_mcp2515(eChipSelect chip, uint8_t length, uint8_t address, uint8_t* data) { uint8_t i; // /CS of MCP2515 to Low unset_chip_select(chip); spi_putc(MCP2515_WRITE); spi_putc(address); for(i = 0; i < length; ++i) { spi_putc(data[i]); } // /CS of MCP2515 to High set_chip_select(chip); }
void mcp2515_write_id(const uint32_t *id, uint8_t extended) { uint8_t tmp; if (extended) { spi_start(*((uint16_t *) id + 1) >> 5); // naechsten Werte berechnen tmp = (*((uint8_t *) id + 2) << 3) & 0xe0; tmp |= (1 << IDE); tmp |= (*((uint8_t *) id + 2)) & 0x03; // warten bis der vorherige Werte geschrieben wurde spi_wait(); // restliche Werte schreiben spi_putc(tmp); spi_putc(*((uint8_t *) id + 1)); spi_putc(*((uint8_t *) id)); } else {
// ---------------------------------------------------------------------------- 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_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_read_id(uint32_t *id) { uint8_t first; uint8_t tmp; first = spi_putc(0xff); tmp = spi_putc(0xff); if (tmp & (1 << IDE)) { spi_start(0xff); *((uint16_t *) id + 1) = (uint16_t) first << 5; *((uint8_t *) id + 1) = spi_wait(); spi_start(0xff); *((uint8_t *) id + 2) |= (tmp >> 3) & 0x1C; *((uint8_t *) id + 2) |= tmp & 0x03; *((uint8_t *) id) = spi_wait(); return TRUE; }
uint8_t mcp2515_read_id(uint32_t *id) { uint8_t first; uint8_t tmp; uint8_t spi_temp; first = spi_putc(0xff); tmp = spi_putc(0xff); if (tmp & (1 << IDE)) { spi_temp = spi_putc(0xff); *((uint16_t *) id + 1) = (uint16_t) first << 5; *((uint8_t *) id + 1) = spi_temp; spi_temp = spi_putc(0xff); *((uint8_t *) id + 2) |= (tmp >> 3) & 0x1C; *((uint8_t *) id + 2) |= tmp & 0x03; *((uint8_t *) id) = spi_temp; return (1); }
// ---------------------------------------------------------------------------- uint8_t mcp2515_send_message(tCAN *message) { uint8_t status = mcp2515_read_status(SPI_READ_STATUS); /* Statusbyte: * * Bit Function * 2 TXB0CNTRL.TXREQ * 4 TXB1CNTRL.TXREQ * 6 TXB2CNTRL.TXREQ */ uint8_t address; uint8_t t; // SET(LED2_HIGH); if (bit_is_clear(status, 2)) { address = 0x00; } else if (bit_is_clear(status, 4)) { address = 0x02; } else if (bit_is_clear(status, 6)) { address = 0x04; } else { // all buffer used => could not send message return 0; } RESET(MCP2515_CS); spi_putc(SPI_WRITE_TX | address); spi_putc(message->id >> 3); spi_putc(message->id << 5); spi_putc(0); spi_putc(0); uint8_t length = message->header.length & 0x0f; if (message->header.rtr) { // a rtr-frame has a length, but contains no data spi_putc((1<<RTR) | length); } else { // set message length spi_putc(length); // data for (t=0;t<length;t++) { spi_putc(message->data[t]); } } SET(MCP2515_CS); _delay_us(1); // send message RESET(MCP2515_CS); address = (address == 0) ? 1 : address; spi_putc(SPI_RTS | address); SET(MCP2515_CS); return address; }
/* Transmit a packet in ShockBurst mode without any retransmission. */ uint8_t nrf_transmit (nrf_t nrf, nrf_node_t *node, void *buffer, uint8_t len) { nrf_obj_t *dev = nrf; uint8_t i; uint8_t length; uint16_t packet_length; uint8_t *data = buffer; uint8_t delay; /* Changing channel requires a one byte configure. */ nrf_channel_set (dev, node->tx.channel); /* Changing direction requires a one byte configure. */ nrf_dir_set (dev, NRF_TX_MODE); nrf_configure (dev, 1); /* Clock out a packet to the nRF chip, with zero-padding if len is less than the packet length. */ /* Set the chip enable pin high to begin clocking in data. */ NRF_CE_HIGH_SET (dev); DELAY_US (NRF_LINE_TIME_ENABLE_US); /* Set length to address length in bytes. */ length = (dev->config.bits.addr_w / CHAR_BIT); /* Clock out address. */ for (i = length; i > 0; i--) spi_putc (dev->spi, node->tx.address.bytes[i - 1]); /* Set length to payload length in bytes. */ length = (dev->config.bits.data1_w / CHAR_BIT); /* Clock out data. */ for (i = 0; i < len; i++) spi_putc (dev->spi, data[i]); /* If size is smaller than the payload length, append zeros. */ if (len < length) { for (i = 0; i < (length - len); i++) spi_putc (dev->spi, 0); } /* Set the chip enable pin low to transmit data and return to standby mode. */ NRF_CE_LOW_SET (dev); /* Delay to allow chip to enter ShockBurst mode. */ DELAY_US (NRF_T_SB_ACTIVE); /* Delay to allow for transmission time. */ /* Transmission delay time depends on many factors. */ /* The packet length = address length + data length + crc. */ packet_length = ((dev->config.bits.addr_w) + (dev->config.bits.data1_w)); /* If CRC is enabled, add its length on. */ if (dev->config.bits.crc_en == NRF_CRC_ENABLED) { if (dev->config.bits.crc_l == NRF_CRC_8) /* 8-bit CRC enabled. */ { packet_length += 8; } else /* 16-bit CRC enabled. */ { packet_length += 16; } } /* If data rate = 1Mbit/s, delay for a number of microseconds equal to the packet length. Otherwise, if data rate = 250kbps, delay for 4 times as long. Now we don't want to calculate microsecond delays since this requires floating point arithmetic. */ delay = packet_length; if (dev->config.bits.rfdr_sb != NRF_DATA_1M) delay <<= 2; while (delay) { DELAY_US (1); delay--; } /* The chip automatically returns to standby mode after transmission. */ return len; }
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 }
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; }
// ---------------------------------------------------------------------------- uint8_t mcp2515_send_message(const can_t *msg) { // Status des MCP2515 auslesen uint8_t status = mcp2515_read_status(SPI_READ_STATUS); /* Statusbyte: * * Bit Funktion * 2 TXB0CNTRL.TXREQ * 4 TXB1CNTRL.TXREQ * 6 TXB2CNTRL.TXREQ */ uint8_t address; if (_bit_is_clear(status, 2)) { address = 0x00; } else { // Alle Puffer sind belegt, // Nachricht kann nicht verschickt werden return 0; } RESET(MCP2515_CS); spi_putc(SPI_WRITE_TX | address); #if SUPPORT_EXTENDED_CANID mcp2515_write_id(&msg->id, msg->flags.extended); #else mcp2515_write_id(&msg->id); #endif uint8_t length = msg->length & 0x0f; // Ist die Nachricht ein "Remote Transmit Request" ? if (msg->flags.rtr) { // Ein RTR hat zwar eine Laenge, // enthaelt aber keine Daten // Nachrichten Laenge + RTR einstellen spi_putc((1<<RTR) | length); } else { // Nachrichten Laenge einstellen spi_putc(length); // Daten for (uint8_t i=0;i<length;i++) { spi_putc(msg->data[i]); } } SET(MCP2515_CS); _delay_us(1); // CAN Nachricht verschicken // die letzten drei Bit im RTS Kommando geben an welcher // Puffer gesendet werden soll. RESET(MCP2515_CS); address = (address == 0) ? 1 : address; spi_putc(SPI_RTS | address); SET(MCP2515_CS); CAN_INDICATE_TX_TRAFFIC_FUNCTION; return address; }
/** * \brief initializes MCP2515 selected * * \par Clock Speed * All MCP2515 connected to AVR need to have the same clock speed when * using the same bitrate! See array in can_init_mcp2515.c. * * \par SPI * MCP2515 init routine does NOT initializes SPI. This has to be done before. * * \par Filters * The filters are cleared here, to allow simply every CAN message to be * received, which is for testing purposes the right choice. Any special * filter needs to be set up by the main program. The mode of operation needs * to be the configuration mode for that. * * \param chip - select chip to use * \param bitrate - CAN bitrate of chip selected * \param mode - mode of operation of MCP2515 after init * \return true if ok, false if error */ bool can_init_mcp2515(eChipSelect chip, eCanBitRate bitrate, uint8_t mode) { bool retVal = false; uint8_t *cnf = 0; if ((bitrate < NUM_OF_CAN_BITRATES) && (chip < NUM_OF_MCP2515)) { cnf = getCanConfiguration(bitrate); // set interrupt pins setup_interrupt_pins(chip); // set chip select pins setup_cs_pins(chip); // wait for MCP2515 to get pin status _delay_ms(10); // software reset MCP2515 to change it to configuration mode unset_chip_select(chip); spi_putc(MCP2515_RESET); _delay_ms(1); // wait a little bit set_chip_select(chip); // wait for MCP2515 to reset itself _delay_ms(10); // setup configuration registers write_register_mcp2515(chip, CNF1, cnf[0]); write_register_mcp2515(chip, CNF2, cnf[1]); write_register_mcp2515(chip, CNF3, cnf[2]); // test if MCP2515 is accessible and CNF set up correctly if(read_register_mcp2515(chip, CNF1) != cnf[0]) { return false; } // assume it works retVal = true; // initialize RX interrupts write_register_mcp2515(chip, CANINTE, (1<<RX1IE) | (1<<RX0IE)); #ifdef ___MASTER_CAN_CLKOUT_ENABLE___ // init CLKOUT on master CAN if(CAN_CHIP1 == chip) { // prescaler is CLKPREx = 00 -> fosc/1 bit_modify_mcp2515(chip, CANCTRL(0), (1 << CLKEN), (1 << CLKEN)); } #endif // clear filters: Now all messages are received. Any other filters need // to be set up by main program. clear_filters(chip); // setup PIN functions // deactivate RX0BF pin and set to high impedance state; // set RX1BF to digital output (0) for MCP2551 sleep mode control write_register_mcp2515(chip, BFPCTRL, (1 << B1BFE)); // setup TXnRTS pins as input write_register_mcp2515(chip, TXRTSCTRL, 0); // set MCP2515 into normal operations mode (no longer configurable) set_mode_mcp2515(chip, mode); } return(retVal); }
// ------------------------------------------------------------------------- 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; }
static void spi_start(uint8_t data) { usi_interface_spi_temp = spi_putc(data); }
// ------------------------------------------------------------------------- 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; } }
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_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; }
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; }