/** * \brief Initialize TWIHS master mode. * * \param p_twihs Pointer to a TWIHS instance. * \param p_opt Options for initializing the TWIHS module (see \ref twihs_options_t). * * \return TWIHS_SUCCESS if initialization is complete, error code otherwise. */ uint32_t twihs_master_init(Twihs *p_twihs, const twihs_options_t *p_opt) { uint32_t status = TWIHS_SUCCESS; /* Disable TWIHS interrupts */ p_twihs->TWIHS_IDR = ~0UL; /* Dummy read in status register */ p_twihs->TWIHS_SR; /* Reset TWIHS peripheral */ twihs_reset(p_twihs); twihs_enable_master_mode(p_twihs); /* Select the speed */ if (twihs_set_speed(p_twihs, p_opt->speed, p_opt->master_clk) == FAIL) { /* The desired speed setting is rejected */ status = TWIHS_INVALID_ARGUMENT; } return status; }
ATCA_STATUS hal_i2c_wake(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; int retries = cfg->rx_retries, rxlength; uint32_t bdrt = cfg->atcai2c.baud; int status = !STATUS_OK; uint8_t data[4], expected[4] = { 0x04, 0x11, 0x33, 0x43 }; volatile Twihs * twihs_device; twihs_device = i2c_hal_data[bus]->twi_module; if ( bdrt != 100000 ) // if not already at 100KHz, change it if (twihs_set_speed(twihs_device, 100000, sysclk_get_cpu_hz() / CONFIG_SYSCLK_DIV) == FAIL) return ATCA_COMM_FAIL; twihs_packet_t packet = { .addr[0] = 0, .addr[1] = 0, .addr_length = 0, //very important, since cryptoauthdevices do not require addressing; .chip = cfg->atcai2c.slave_address >> 1, .buffer = &data[0], .length = 1 }; twihs_master_write(twihs_device, &packet); atca_delay_us(cfg->wake_delay); // wait tWHI + tWLO which is configured based on device type and configuration structure // look for wake response rxlength = 4; memset(data, 0x00, rxlength); status = hal_i2c_receive(iface, data, &rxlength ); // if necessary, revert baud rate to what came in. if ( bdrt != 100000) if (twihs_set_speed(twihs_device, bdrt, sysclk_get_cpu_hz() / CONFIG_SYSCLK_DIV) == FAIL) return ATCA_COMM_FAIL; if ( status != STATUS_OK ) return ATCA_COMM_FAIL; if ( memcmp( data, expected, 4 ) == 0 ) return ATCA_SUCCESS; return ATCA_COMM_FAIL; } /** \brief idle CryptoAuth device using I2C bus * \param[in] iface interface to logical device to idle */ ATCA_STATUS hal_i2c_idle(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; uint8_t data[4]; int length; uint32_t twihs_device; uint16_t status; data[0] = 0x02; // idle word address value twihs_device = i2c_hal_data[bus]->twi_module; twihs_packet_t packet = { .addr[0] = 0, .addr[1] = 0, .addr_length = 0, //very important, since cryptoauthdevices do not require addressing; .chip = cfg->atcai2c.slave_address >> 1, .buffer = data, }; packet.length = 1; if (twihs_master_write( twihs_device, &packet) != STATUS_OK) return ATCA_COMM_FAIL; return ATCA_SUCCESS; } /** \brief sleep CryptoAuth device using I2C bus * \param[in] iface interface to logical device to sleep */ ATCA_STATUS hal_i2c_sleep(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; uint8_t data[4]; int length; uint32_t twihs_device; uint16_t status; data[0] = 0x01; // sleep word address value twihs_device = i2c_hal_data[bus]->twi_module; twihs_packet_t packet = { .addr[0] = 0, .addr[1] = 0, .addr_length = 0, //very important, since cryptoauthdevices do not require addressing; .chip = cfg->atcai2c.slave_address >> 1, .buffer = data, }; packet.length = 1; if (twihs_master_write( twihs_device, &packet) != STATUS_OK) return ATCA_COMM_FAIL; return ATCA_SUCCESS; } /** \brief manages reference count on given bus and releases resource if no more refences exist * \param[in] hal_data - opaque pointer to hal data structure - known only to the HAL implementation */ ATCA_STATUS hal_i2c_release( void *hal_data ) { ATCAI2CMaster_t *hal = (ATCAI2CMaster_t*)hal_data; i2c_bus_ref_ct--; // track total i2c bus interface instances for consistency checking and debugging // if the use count for this bus has gone to 0 references, disable it. protect against an unbracketed release if ( hal && --(hal->ref_ct) <= 0 && i2c_hal_data[hal->bus_index] != NULL ) { twihs_disable_master_mode( i2c_hal_data[hal->bus_index]->twi_module ); free(i2c_hal_data[hal->bus_index]); i2c_hal_data[hal->bus_index] = NULL; } return ATCA_SUCCESS; }
ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t *txdata, int txlength) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; uint32_t twihs_device; uint16_t status; twihs_device = i2c_hal_data[bus]->twi_module; twihs_packet_t packet = { .addr[0] = 0, .addr[1] = 0, .addr_length = 0, //very important, since cryptoauthdevices do not require addressing; .chip = cfg->atcai2c.slave_address >> 1, .buffer = txdata, }; // 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 (twihs_master_write( twihs_device, &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; Twihs *twihs_device; twihs_packet_t packet = { .chip = cfg->atcai2c.slave_address >> 1, // use 7-bit address .buffer = rxdata, .length = *rxlength }; twihs_device = i2c_hal_data[bus]->twi_module; while ( retries-- > 0 && status != STATUS_OK ) { if ( twihs_master_read(twihs_device, &packet) != TWIHS_SUCCESS ) status = ATCA_COMM_FAIL; else status = ATCA_SUCCESS; } if ( status != STATUS_OK ) return ATCA_COMM_FAIL; return ATCA_SUCCESS; } /** \brief method to change the bus speed of I2C * \param[in] iface interface on which to change bus speed * \param[in] speed baud rate (typically 100000 or 400000) */ ATCA_STATUS change_i2c_speed( ATCAIface iface, uint32_t speed ) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; // if necessary, revert baud rate to what came in. if (twihs_set_speed(i2c_hal_data[bus]->twi_module, speed, sysclk_get_cpu_hz() / CONFIG_SYSCLK_DIV) == FAIL) return ATCA_COMM_FAIL; }