/** * \brief Initialize TWI master mode. * * \param p_twi Pointer to a TWI instance. * \param p_opt Options for initializing the TWI module (see \ref twi_options_t). * * \return TWI_SUCCESS if initialization is complete, error code otherwise. */ uint32_t twi_master_init(Twi *p_twi, const twi_options_t *p_opt) { uint32_t status = TWI_SUCCESS; /* Disable TWI interrupts */ p_twi->TWI_IDR = ~0UL; /* Dummy read in status register */ p_twi->TWI_SR; /* Reset TWI peripheral */ twi_reset(p_twi); twi_enable_master_mode(p_twi); /* Select the speed */ if (twi_set_speed(p_twi, p_opt->speed, p_opt->master_clk) == FAIL) { /* The desired speed setting is rejected */ status = TWI_INVALID_ARGUMENT; } if (p_opt->smbus == 1) { p_twi->TWI_CR = TWI_CR_QUICK; } return status; }
static always_inline void twi_init(void) { #if defined(USIPP) #if defined(USI_ON_PORT_A) USIPP |= _BV(USIPOS); #else USIPP &= ~_BV(USIPOS); # endif #endif twi_reset(); }
/** * \brief Initialize TWI slave mode. * * \param p_twi Pointer to a TWI instance. * \param ul_device_addr Device address of the SAM slave device on the I2C bus. */ void twi_slave_init(Twi *p_twi, uint32_t ul_device_addr) { /* Disable TWI interrupts */ p_twi->TWI_IDR = ~0UL; p_twi->TWI_SR; /* Reset TWI */ twi_reset(p_twi); /* Set slave address in slave mode */ p_twi->TWI_SMR = TWI_SMR_SADR(ul_device_addr); /* Enable slave mode */ twi_enable_slave_mode(p_twi); }
/** * \ingroup freertos_twi_peripheral_control_group * \brief Initializes the FreeRTOS ASF TWI (I2C) master driver for the specified * TWI port. * * freertos_twi_master_init() is an ASF specific FreeRTOS driver function. It * must be called before any other ASF specific FreeRTOS driver functions * attempt to access the same TWI port. * * If freertos_driver_parameters->operation_mode equals TWI_I2C_MASTER then * freertos_twi_master_init() will configure the TWI port for master mode * operation and enable the peripheral. If * freertos_driver_parameters->operation_mode equals any other value then * freertos_twi_master_init() will not take any action. * * Other ASF TWI functions can be called after freertos_twi_master_init() has * completed successfully. * * The FreeRTOS ASF driver both installs and handles the TWI PDC interrupts. * Users do not need to concern themselves with interrupt handling, and must * not install their own interrupt handler. * * This driver is provided with an application note, and an example project that * demonstrates the use of this function. * * \param p_twi The twi peripheral being initialized. * \param freertos_driver_parameters Defines the driver behavior. See the * freertos_peripheral_options_t documentation, and the application note that * accompanies the ASF specific FreeRTOS functions. * * \return If the initialization completes successfully then a handle that can * be used with FreeRTOS TWI read and write functions is returned. If * the initialisation fails then NULL is returned. */ freertos_twi_if freertos_twi_master_init(Twi *p_twi, const freertos_peripheral_options_t *const freertos_driver_parameters) { portBASE_TYPE twi_index; bool is_valid_operating_mode; freertos_twi_if return_value; const enum peripheral_operation_mode valid_operating_modes[] = {TWI_I2C_MASTER}; /* Find the index into the all_twi_definitions array that holds details of the p_twi peripheral. */ twi_index = get_pdc_peripheral_details(all_twi_definitions, MAX_TWIS, (void *) p_twi); /* Check the requested operating mode is valid for the peripheral. */ is_valid_operating_mode = check_requested_operating_mode( freertos_driver_parameters->operation_mode, valid_operating_modes, sizeof(valid_operating_modes) / sizeof(enum peripheral_operation_mode)); /* Don't do anything unless a valid p_twi pointer was used, and a valid operating mode was requested. */ if ((twi_index < MAX_TWIS) && (is_valid_operating_mode == true)) { /* This function must be called exactly once per supported twi. Check it has not been called before. */ configASSERT(memcmp((void *)&(tx_dma_control[twi_index]), &null_dma_control, sizeof(null_dma_control)) == 0); configASSERT(memcmp((void *)&(rx_dma_control[twi_index]), &null_dma_control, sizeof(null_dma_control)) == 0); /* Enable the peripheral's clock. */ pmc_enable_periph_clk( all_twi_definitions[twi_index].peripheral_id); /* Ensure everything is disabled before configuration. */ pdc_disable_transfer( all_twi_definitions[twi_index].pdc_base_address, (PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS)); twi_disable_interrupt( all_twi_definitions[twi_index].peripheral_base_address, MASK_ALL_INTERRUPTS); twi_reset( all_twi_definitions[twi_index].peripheral_base_address); switch (freertos_driver_parameters->operation_mode) { case TWI_I2C_MASTER: /* Call the standard ASF init function. */ twi_enable_master_mode( all_twi_definitions[twi_index].peripheral_base_address); break; default: /* No other modes are currently supported. */ break; } /* Create any required peripheral access mutexes and transaction complete semaphores. This peripheral is half duplex so only a single access mutex is required. */ create_peripheral_control_semaphores( freertos_driver_parameters->options_flags, &(tx_dma_control[twi_index]), &(rx_dma_control[twi_index])); /* Error interrupts are always enabled. */ twi_enable_interrupt( all_twi_definitions[twi_index].peripheral_base_address, IER_ERROR_INTERRUPTS); /* Configure and enable the TWI interrupt in the interrupt controller. */ configure_interrupt_controller( all_twi_definitions[twi_index].peripheral_irq, freertos_driver_parameters->interrupt_priority); return_value = (freertos_twi_if) p_twi; } else { return_value = NULL; } return return_value; }
void usi_twi_slave(uint8_t slave_address_in, uint8_t use_sleep, void (*data_callback_in)(uint8_t buffer_size, volatile uint8_t input_buffer_length, volatile const uint8_t *input_buffer, volatile uint8_t *output_buffer_length, volatile uint8_t *output_buffer), void (*idle_callback_in)(void)) { slave_address = slave_address_in; data_callback = data_callback_in; idle_callback = idle_callback_in; input_buffer_length = 0; output_buffer_length = 0; output_buffer_current = 0; ss_state = ss_state_before_start; if(use_sleep) set_sleep_mode(SLEEP_MODE_IDLE); twi_init(); sei(); for(;;) { if(use_sleep && (ss_state == ss_state_before_start)) sleep_mode(); if(USISR & _BV(USIPF)) { cli(); #ifdef USE_STATS if(stats_enabled)stop_conditions_count++; #endif USISR |= _BV(USIPF); // clear stop condition flag switch(ss_state) { case(ss_state_after_start): { twi_reset(); break; } case(ss_state_data_processed): { #ifdef USE_STATS if(stats_enabled)local_frames_count++; #endif output_buffer_length = 0; output_buffer_current = 0; data_callback(buffer_size, input_buffer_length, input_buffer, &output_buffer_length, output_buffer); input_buffer_length = 0; break; } } ss_state = ss_state_before_start; sei(); } if(idle_callback) { idle_callback(); #ifdef USE_STATS if(stats_enabled)idle_call_count++; #endif } } }
/** * \brief wake up CryptoAuth device using I2C bus * * \param[in] iface interface to logical device to wakeup * * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_wake(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); // set to default i2c bus if (cfg->atcai2c.bus > MAX_I2C_BUSES - 1) cfg->atcai2c.bus = 0; int bus = cfg->atcai2c.bus; int retries = cfg->rx_retries; uint32_t bdrt = cfg->atcai2c.baud; int status = !TWI_SUCCESS; uint8_t data[4], expected[4] = { 0x04, 0x11, 0x33, 0x43 }; // if not already at 100kHz, change it if (bdrt != 100000) change_i2c_speed(iface, 100000); // Send 0x00 as wake pulse twi_write_byte(i2c_hal_data[bus]->twi_master_instance, 0x00); // rounded up to the nearest ms atca_delay_ms(((uint32_t)cfg->wake_delay + (1000 - 1)) / 1000); // wait tWHI + tWLO which is configured based on device type and configuration structure twi_package_t packet = { .chip = cfg->atcai2c.slave_address >> 1, .addr[0] = NULL, .addr_length = 0, .buffer = (void*)data, .length = 4 }; // if necessary, revert baud rate to what came in. if (bdrt != 100000) change_i2c_speed(iface, bdrt); while (retries-- > 0 && status != TWI_SUCCESS) status = twi_master_read(i2c_hal_data[bus]->twi_master_instance, &packet); if (status != TWI_SUCCESS) 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 * * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_idle(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); // set to default i2c bus if (cfg->atcai2c.bus > MAX_I2C_BUSES - 1) cfg->atcai2c.bus = 0; int bus = cfg->atcai2c.bus; uint8_t data[4]; data[0] = 0x02; // idle word address value twi_package_t packet = { .chip = cfg->atcai2c.slave_address >> 1, .addr[0] = NULL, .addr_length = 0, .buffer = (void*)data, .length = 1 }; if (twi_master_write(i2c_hal_data[bus]->twi_master_instance, &packet) != TWI_SUCCESS) return ATCA_COMM_FAIL; return ATCA_SUCCESS; } /** * \brief sleep CryptoAuth device using I2C bus * * \param[in] iface interface to logical device to sleep * * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_sleep(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); // set to default i2c bus if (cfg->atcai2c.bus > MAX_I2C_BUSES - 1) cfg->atcai2c.bus = 0; int bus = cfg->atcai2c.bus; uint8_t data[4]; data[0] = 0x01; // sleep word address value twi_package_t packet = { .chip = cfg->atcai2c.slave_address >> 1, .addr[0] = NULL, .addr_length = 0, .buffer = (void*)data, .length = 1 }; if (twi_master_write(i2c_hal_data[bus]->twi_master_instance, &packet) != TWI_SUCCESS) 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 * * \return ATCA_STATUS */ ATCA_STATUS hal_i2c_release(void *hal_data) { ATCAI2CMaster_t *hal = (ATCAI2CMaster_t*)hal_data; // set to default i2c bus if (hal->bus_index > MAX_I2C_BUSES - 1) hal->bus_index = 0; 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) { twi_reset(hal->twi_master_instance); free(i2c_hal_data[hal->bus_index]); i2c_hal_data[hal->bus_index] = NULL; } return ATCA_SUCCESS; }
/** * \brief Reset TWI bus * * \param none. */ static void twi_slave_bus_reset(void) { slave_transfer.state = TWI_IDLE; twi_reset(); }
/** * \brief Reset TWI bus * * \param none. */ static void twi_master_bus_reset(void) { master_transfer.state = TWI_IDLE; twi_master_busy = false; twi_reset(); }
/** \brief wake up CryptoAuth device using I2C bus * \param[in] interface to logical device to wakeup */ ATCA_STATUS hal_i2c_wake(ATCAIface iface) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); int bus = cfg->atcai2c.bus; int retries = cfg->rx_retries; uint32_t bdrt = cfg->atcai2c.baud; uint8_t data[4], expected[4] = { 0x04,0x11,0x33,0x43 }; int status = !TWI_SUCCESS; // if not already at 100KHz, change it if (bdrt != 100000) { change_i2c_speed(iface, 100000); } // Send 0x00 as wake pulse switch(bus) { //case 0: twi_write_byte(TWI0, 0x00); break; case 0: twi_write_byte(TWI_Channel0,0);break; case 1: twi_write_byte(TWI_Channel1,0); break; } atca_delay_us(cfg->wake_delay); // wait tWHI + tWLO which is configured based on device type and configuration structure //twi_package_t packet = { twi_packet_t packet = { .chip = cfg->atcai2c.slave_address >> 1, .addr[0] = NULL, .addr_length = 0, .buffer = (void *)data, .length = 4 }; // if necessary, revert baud rate to what came in. if (bdrt != 100000) { change_i2c_speed(iface, bdrt); } switch(bus) { case 0: //if (twi_master_read(TWI0, &packet) != TWI_SUCCESS) while (retries-- > 0 && status != TWI_SUCCESS) status = twi_master_read(TWI_Channel0, &packet); /*if (twi_master_read(TWI_Channel0, &packet) != TWI_SUCCESS) { return ATCA_COMM_FAIL; }*/ break; case 1: /* if (twi_master_read(TWI_Channel1, &packet) != TWI_SUCCESS) { return ATCA_COMM_FAIL; }*/ break; } if (memcmp(data, expected, 4) == 0) { return ATCA_SUCCESS; } return ATCA_COMM_FAIL; } /** \brief idle CryptoAuth device using I2C bus * \param[in] 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]; data[0] = 0x02; // idle word address value //twi_package_t packet = { twi_packet_t packet = { .chip = cfg->atcai2c.slave_address >> 1, .addr[0] = NULL, .addr_length = 0, .buffer = (void *)data, .length = 1 }; switch(bus) { case 0: //if (twi_master_write(TWI0, &packet) != TWI_SUCCESS) if (twi_master_write(TWI_Channel0, &packet) != TWI_SUCCESS) { return ATCA_COMM_FAIL; } break; case 1: if (twi_master_write(TWI_Channel1, &packet) != TWI_SUCCESS) { return ATCA_COMM_FAIL; } break; } return ATCA_SUCCESS; } /** \brief sleep CryptoAuth device using I2C bus * \param[in] 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]; data[0] = 0x01; // sleep word address value //twi_package_t packet = { twi_packet_t packet = { .chip = cfg->atcai2c.slave_address >> 1, .addr[0] = NULL, .addr_length = 0, .buffer = (void *)data, .length = 1 }; switch(bus) { case 0: //if (twi_master_write(TWI0, &packet) != TWI_SUCCESS) if (twi_master_write(TWI_Channel0, &packet) != TWI_SUCCESS) { return ATCA_COMM_FAIL; } break; case 1: if (twi_master_write(TWI_Channel1, &packet) != TWI_SUCCESS) { return ATCA_COMM_FAIL; } break; } 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) { switch(hal->bus_index) { //case 0: twi_reset(TWI0); break; case 0: twi_reset(TWI_Channel0);break; case 1: twi_reset(TWI_Channel1);break; } free(i2c_hal_data[hal->bus_index]); i2c_hal_data[hal->bus_index] = NULL; } return ATCA_SUCCESS; }