Пример #1
0
/**
 * \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;
}
Пример #2
0
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();
}
Пример #3
0
/**
 * \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);
}
Пример #4
0
/**
 * \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;
}
Пример #5
0
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
		}
	}
}
Пример #6
0
/**
 * \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;
}
Пример #7
0
/**
 * \brief Reset TWI bus
 *
 * \param none.
 */
static void twi_slave_bus_reset(void)
{
	slave_transfer.state = TWI_IDLE;
	twi_reset();
}
Пример #8
0
/**
 * \brief Reset TWI bus
 *
 * \param none.
 */
static void twi_master_bus_reset(void)
{
	master_transfer.state = TWI_IDLE;
	twi_master_busy      = false;
	twi_reset();
}
Пример #9
0
/** \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;
}