// Supporting function implementation Accelerometer::Accelerometer() { // Initialize variables uint8_t value; // Configure VDDIO, SDA and SCL pins ioport_set_pin_dir(ACCELEROMETER_VDDIO_PIN, IOPORT_DIR_OUTPUT); ioport_set_pin_level(ACCELEROMETER_VDDIO_PIN, IOPORT_PIN_LEVEL_HIGH); ioport_set_pin_mode(ACCELEROMETER_SDA_PIN, IOPORT_MODE_WIREDANDPULL); ioport_set_pin_mode(ACCELEROMETER_SCL_PIN, IOPORT_MODE_WIREDANDPULL); // Configure interface twi_options_t options; options.speed = BUS_SPEED; options.chip = MASTER_ADDRESS; options.speed_reg = TWI_BAUD(sysclk_get_cpu_hz(), BUS_SPEED); // Initialize interface sysclk_enable_peripheral_clock(&TWI_MASTER); twi_master_init(&TWI_MASTER, &options); twi_master_enable(&TWI_MASTER); // Create packet twi_package_t packet; packet.addr[0] = WHO_AM_I; packet.addr_length = 1; packet.chip = ACCELEROMETER_ADDRESS; packet.buffer = &value; packet.length = 1; packet.no_wait = false; // Check if transmitting or receiving failed if(twi_master_read(&TWI_MASTER, &packet) != TWI_SUCCESS || value != DEVICE_ID) // Clear is working isWorking = false; // Otherwise else { // Reset the accelerometer writeValue(CTRL_REG2, CTRL_REG2_RST); // Wait enough time for accelerometer to initialize delay_ms(1); // Initialize settings initializeSettings(); // Calibrate //calibrate(); // Set is working isWorking = true; } }
/** * \internal * \brief This test sends a packet from the master, and checks * that the sending happens without errors. * * \param test Current test case. */ static void run_twi_master_send_test( const struct test_case *test) { status_code_t master_status; // Package to send twi_package_t packet = { // No address or command .addr_length = 0, // issue to slave .chip = TWI_SLAVE_ADDR, .buffer = (void *)test_pattern, .length = PATTERN_TEST_LENGTH, // Wait if bus is busy .no_wait = false }; // TWI master options twi_options_t m_options = { .speed = TWI_SPEED, .chip = TWI_MASTER_ADDR, .speed_reg = TWI_BAUD(sysclk_get_cpu_hz(), TWI_SPEED) }; irq_initialize_vectors(); // Initialize TWI_MASTER sysclk_enable_peripheral_clock(&TWI_MASTER); twi_master_init(&TWI_MASTER, &m_options); twi_master_enable(&TWI_MASTER); // Initialize TWI_SLAVE sysclk_enable_peripheral_clock(&TWI_SLAVE); TWI_SlaveInitializeDriver(&slave, &TWI_SLAVE, *slave_process); TWI_SlaveInitializeModule(&slave, TWI_SLAVE_ADDR, TWI_SLAVE_INTLVL_MED_gc); cpu_irq_enable(); // Send package to slave master_status = twi_master_write(&TWI_MASTER, &packet); test_assert_true(test, master_status == STATUS_OK, "Master write not ok"); } /** * \internal * \brief This test sends a packet from the master to the slave, * and checks that the correct packet is received. * * \param test Current test case. */ static void run_twi_slave_recv_test( const struct test_case *test) { uint8_t i = 0; // Package to send twi_package_t packet = { // No address or command to issue to slave .addr_length = 0, .chip = TWI_SLAVE_ADDR, .buffer = (void *)test_pattern, .length = PATTERN_TEST_LENGTH, // Wait if bus is busy .no_wait = false }; // TWI master options twi_options_t m_options = { .speed = TWI_SPEED, .chip = TWI_MASTER_ADDR, .speed_reg = TWI_BAUD(sysclk_get_cpu_hz(), TWI_SPEED) }; irq_initialize_vectors(); // Initialize TWI_MASTER sysclk_enable_peripheral_clock(&TWI_MASTER); twi_master_init(&TWI_MASTER, &m_options); twi_master_enable(&TWI_MASTER); // Initialize TWI_SLAVE for (i = 0; i < TWIS_SEND_BUFFER_SIZE; i++) { slave.receivedData[i] = 0; } sysclk_enable_peripheral_clock(&TWI_SLAVE); TWI_SlaveInitializeDriver(&slave, &TWI_SLAVE, *slave_process); TWI_SlaveInitializeModule(&slave, TWI_SLAVE_ADDR, TWI_SLAVE_INTLVL_MED_gc); cpu_irq_enable(); // Send package to slave twi_master_write(&TWI_MASTER, &packet); // Wait for slave to receive packet and check that packet is correct do {} while (slave.result != TWIS_RESULT_OK); for (i = 0; i < PATTERN_TEST_LENGTH; i++) { test_assert_true(test, slave.receivedData[i] == test_pattern[i], "Wrong data[%d] received, %d != %d", i, slave.receivedData[i], test_pattern[i]); } } /** * \internal * \brief This test requests a packet to be sent from the slave, * and checks that the correct packet is received by the master. * * \param test Current test case. */ static void run_twi_master_recv_test(const struct test_case *test) { uint8_t i = 0; uint8_t recv_pattern[TWIS_SEND_BUFFER_SIZE] = {0}; // Package to send twi_package_t packet = { // No address or command to issue to slave .addr_length = 0, .chip = TWI_SLAVE_ADDR, .buffer = (void *)recv_pattern, // Wait if bus is busy .length = PATTERN_TEST_LENGTH, .no_wait = false }; // TWI master options twi_options_t m_options = { .speed = TWI_SPEED, .chip = TWI_MASTER_ADDR, .speed_reg = TWI_BAUD(sysclk_get_cpu_hz(), TWI_SPEED) }; // Data for slave to send, same as test_pattern slave.sendData[0] = 0x55; slave.sendData[1] = 0xA5; slave.sendData[2] = 0x5A; slave.sendData[3] = 0x77; slave.sendData[4] = 0x99; irq_initialize_vectors(); // Initialize TWI_MASTER sysclk_enable_peripheral_clock(&TWI_MASTER); twi_master_init(&TWI_MASTER, &m_options); twi_master_enable(&TWI_MASTER); // Initialize TWI_SLAVE for (i = 0; i < TWIS_SEND_BUFFER_SIZE; i++) { slave.receivedData[i] = 0; } sysclk_enable_peripheral_clock(&TWI_SLAVE); TWI_SlaveInitializeDriver(&slave, &TWI_SLAVE, *slave_process); TWI_SlaveInitializeModule(&slave, TWI_SLAVE_ADDR, TWI_SLAVE_INTLVL_MED_gc); cpu_irq_enable(); // Send package to slave twi_master_read(&TWI_MASTER, &packet); // Wait for slave to send packet do {} while (slave.result != TWIS_RESULT_OK); for (i = 0; i < PATTERN_TEST_LENGTH; i++) { test_assert_true(test, recv_pattern[i] == test_pattern[i], "Wrong data[%d] received, %d != %d", i, recv_pattern[i], test_pattern[i]); } } //@} /** * \brief Run TWI unit tests * * Initializes the clock system, board and serial output, then sets up the * TWI unit test suite and runs it. */ int main(void) { const usart_serial_options_t usart_serial_options = { .baudrate = CONF_TEST_BAUDRATE, .charlength = CONF_TEST_CHARLENGTH, .paritytype = CONF_TEST_PARITY, .stopbits = CONF_TEST_STOPBITS, }; sysclk_init(); board_init(); stdio_serial_init(CONF_TEST_USART, &usart_serial_options); // Use the internal pullups for SDA and SCL TWI_MASTER_PORT.PIN0CTRL = PORT_OPC_WIREDANDPULL_gc; TWI_MASTER_PORT.PIN1CTRL = PORT_OPC_WIREDANDPULL_gc; // Define single ended conversion test cases DEFINE_TEST_CASE(twi_master_send_test, NULL, run_twi_master_send_test, NULL, "Sending packet from master test"); DEFINE_TEST_CASE(twi_slave_recv_test, NULL, run_twi_slave_recv_test, NULL, "Receiving packet from master test"); DEFINE_TEST_CASE(twi_master_recv_test, NULL, run_twi_master_recv_test, NULL, "Receiving packet from slave test"); // Put test case addresses in an array DEFINE_TEST_ARRAY(twi_tests) = { &twi_master_send_test, &twi_slave_recv_test, &twi_master_recv_test, }; // Define the test suite DEFINE_TEST_SUITE(twi_suite, twi_tests, "XMEGA TWI driver test suite"); // Run all tests in the suite test_suite_run(&twi_suite); while (1) { // Intentionally left empty. } }
ATCA_STATUS hal_i2c_discover_devices(int busNum, ATCAIfaceCfg cfg[], int *found ) { ATCAIfaceCfg *head = cfg; uint8_t slaveAddress = 0x01; ATCADevice device; ATCAIface discoverIface; ATCACommand command; ATCAPacket packet; uint32_t execution_time; ATCA_STATUS status; uint8_t revs508[1][4] = { { 0x00, 0x00, 0x50, 0x00 } }; uint8_t revs108[1][4] = { { 0x80, 0x00, 0x10, 0x01 } }; uint8_t revs204[2][4] = { { 0x00, 0x02, 0x00, 0x08 }, { 0x00, 0x04, 0x05, 0x00 } }; int i; /** \brief default configuration, to be reused during discovery process */ ATCAIfaceCfg discoverCfg = { .iface_type = ATCA_I2C_IFACE, .devtype = ATECC508A, .atcai2c.slave_address = 0x07, .atcai2c.bus = busNum, .atcai2c.baud = 400000, //.atcai2c.baud = 100000, .wake_delay = 800, .rx_retries = 3 }; // build an info command packet.param1 = INFO_MODE_REVISION; packet.param2 = 0; device = newATCADevice( &discoverCfg ); discoverIface = atGetIFace( device ); command = atGetCommands( device ); // iterate through all addresses on given i2c bus // all valid 7-bit addresses go from 0x07 to 0x78 for ( slaveAddress = 0x07; slaveAddress <= 0x78; slaveAddress++ ) { discoverCfg.atcai2c.slave_address = slaveAddress << 1; // turn it into an 8-bit address which is what the rest of the i2c HAL is expecting when a packet is sent // wake up device // If it wakes, send it a dev rev command. Based on that response, determine the device type // BTW - this will wake every cryptoauth device living on the same bus (ecc508a, sha204a) if ( hal_i2c_wake( discoverIface ) == ATCA_SUCCESS ) { (*found)++; memcpy( (uint8_t*)head, (uint8_t*)&discoverCfg, sizeof(ATCAIfaceCfg)); memset( packet.info, 0x00, sizeof(packet.info)); // get devrev info and set device type accordingly atInfo( command, &packet ); execution_time = atGetExecTime(command, CMD_INFO) + 1; // send the command if ( (status = atsend( discoverIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) { printf("packet send error\r\n"); continue; } // delay the appropriate amount of time for command to execute atca_delay_ms(execution_time); // receive the response if ( (status = atreceive( discoverIface, &(packet.info[0]), &(packet.rxsize) )) != ATCA_SUCCESS ) continue; if ( (status = isATCAError(packet.info)) != ATCA_SUCCESS ) { printf("command response error\r\n"); continue; } // determine device type from common info and dev rev response byte strings for ( i = 0; i < sizeof(revs508) / 4; i++ ) { if ( memcmp( &packet.info[1], &revs508[i], 4) == 0 ) { discoverCfg.devtype = ATECC508A; break; } } for ( i = 0; i < sizeof(revs204) / 4; i++ ) { if ( memcmp( &packet.info[1], &revs204[i], 4) == 0 ) { discoverCfg.devtype = ATSHA204A; break; } } for ( i = 0; i < sizeof(revs108) / 4; i++ ) { if ( memcmp( &packet.info[1], &revs108[i], 4) == 0 ) { discoverCfg.devtype = ATECC108A; break; } } atca_delay_ms(15); // now the device type is known, so update the caller's cfg array element with it head->devtype = discoverCfg.devtype; head++; } hal_i2c_idle(discoverIface); } deleteATCADevice(&device); return ATCA_SUCCESS; } /** \brief - this HAL implementation assumes you've included the ASF I2C libraries in your project, otherwise, the HAL layer will not compile because the ASF I2C drivers are a dependency * */ /** \brief hal_i2c_init manages requests to initialize a physical interface. it manages use counts so when an interface * has released the physical layer, it will disable the interface for some other use. * You can have multiple ATCAIFace instances using the same bus, and you can have multiple ATCAIFace instances on * multiple i2c buses, so hal_i2c_init manages these things and ATCAIFace is abstracted from the physical details. */ /** \brief initialize an I2C interface using given config * \param[in] hal - opaque ptr to HAL data * \param[in] cfg - interface configuration */ ATCA_STATUS hal_i2c_init(void *hal, ATCAIfaceCfg *cfg) { int bus = cfg->atcai2c.bus; // 0-based logical bus number ATCAHAL_t *phal = (ATCAHAL_t*)hal; if ( i2c_bus_ref_ct == 0 ) // power up state, no i2c buses will have been used for ( int i = 0; i < MAX_I2C_BUSES; i++ ) i2c_hal_data[i] = NULL; i2c_bus_ref_ct++; // total across buses if ( bus >= 0 && bus < MAX_I2C_BUSES ) { // if this is the first time this bus and interface has been created, do the physical work of enabling it if ( i2c_hal_data[bus] == NULL ) { i2c_hal_data[bus] = malloc( sizeof(ATCAI2CMaster_t) ); i2c_hal_data[bus]->ref_ct = 1; // buses are shared, this is the first instance config_i2c_master.speed = cfg->atcai2c.baud; config_i2c_master.chip = 0x50; config_i2c_master.speed_reg = TWI_BAUD(sysclk_get_cpu_hz(), cfg->atcai2c.baud); switch (bus) { case 0: i2c_hal_data[bus]->i2c_master_instance = &TWIC; break; //case 1: i2c_hal_data[bus]->i2c_master_instance = &TWID; break; // for XMEGA-A1 case 2: i2c_hal_data[bus]->i2c_master_instance = &TWIE; break; //case 3: i2c_hal_data[bus]->i2c_master_instance = &TWIF; break; // for XMEGA-A1 } twi_master_setup((i2c_hal_data[bus]->i2c_master_instance), &config_i2c_master); // store this for use during the release phase i2c_hal_data[bus]->bus_index = bus; twi_master_enable(i2c_hal_data[bus]->i2c_master_instance); } else{ // otherwise, another interface already initialized the bus, so this interface will share it and any different // cfg parameters will be ignored...first one to initialize this sets the configuration i2c_hal_data[bus]->ref_ct++; } phal->hal_data = i2c_hal_data[bus]; return ATCA_SUCCESS; } return ATCA_COMM_FAIL; }
ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t *txdata, int txlength) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; twi_package_t packet = { .addr_length = 0, // TWI slave memory address data size .chip = cfg->atcai2c.slave_address >> 1, // TWI slave bus address .buffer = txdata, // transfer data source buffer .length = txlength, // transfer data size (bytes) }; // for this implementation of I2C with CryptoAuth chips, txdata is assumed to have ATCAPacket format // other device types that don't require i/o tokens on the front end of a command need a different hal_i2c_send and wire it up instead of this one // this covers devices such as ATSHA204A and ATECCx08A that require a word address value pre-pended to the packet // txdata[0] is using _reserved byte of the ATCAPacket txdata[0] = 0x03; // insert the Word Address Value, Command token txlength++; // account for word address value byte. packet.length = txlength; if ( twi_master_write(i2c_hal_data[bus]->i2c_master_instance, &packet) != STATUS_OK ) return ATCA_COMM_FAIL; return ATCA_SUCCESS; } /** \brief HAL implementation of I2C receive function for ASF I2C * \param[in] iface instance * \param[in] rxdata pointer to space to receive the data * \param[in] rxlength ptr to expected number of receive bytes to request * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_receive( ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; int retries = cfg->rx_retries; int status = !STATUS_OK; twi_package_t packet = { .addr_length = 0, // TWI slave memory address data size .chip = cfg->atcai2c.slave_address >> 1, // TWI slave bus address .buffer = rxdata, // transfer data source buffer .length = *rxlength, // transfer data size (bytes) }; while ( retries-- > 0 && status != STATUS_OK ) status = twi_master_read(i2c_hal_data[bus]->i2c_master_instance, &packet); if ( status != STATUS_OK ) return ATCA_COMM_FAIL; return ATCA_SUCCESS; } /** \brief method to change the bus speec of I2C * \param[in] iface interface on which to change bus speed * \param[in] speed baud rate (typically 100000 or 400000) */ void change_i2c_speed( ATCAIface iface, uint32_t speed ) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; config_i2c_master.speed = speed; config_i2c_master.speed_reg = TWI_BAUD(sysclk_get_cpu_hz(), speed); twi_master_disable(i2c_hal_data[bus]->i2c_master_instance); switch (bus) { case 0: i2c_hal_data[bus]->i2c_master_instance = &TWIC; break; case 2: i2c_hal_data[bus]->i2c_master_instance = &TWIE; break; } twi_master_setup((i2c_hal_data[bus]->i2c_master_instance), &config_i2c_master); twi_master_enable(i2c_hal_data[bus]->i2c_master_instance); }