Ejemplo n.º 1
0
int main(void)
{
    char str[30];
    status_init();
    adc_init();
    
    status_set(false);
    
    uart_init(1);
    twi_init(0xC);
    twi_enable_interrupt();
    twi_register_get(get);
    
    measurement = 0;
    
    sei();
    
    while (1) {
        
        // VRef is 2.56V
        // at T = 0, VOut = 0V. VOut scales at 10mV / ºC
        // T = adc * (2.56 / 1024) * 100
        // T = adc * 256 / 1024
        // T = adc / 4
        uint16_t read = adc_read();
        measurement = read / 4;
        sprintf(str, "%dºC (raw = %d)", measurement, read);
        
        uart_send(str);
        _delay_ms(500);
    }
    
}
Ejemplo n.º 2
0
/**
 * \brief Application entry point for TWI Slave example.
 *
 * \return Unused (ANSI-C compatibility).
 */
int main(void)
{
	uint32_t i;

	/* Initialize the SAM system */
	sysclk_init();

#if (SAM4S || SAM4E)
	/* Select PB4 and PB5 function, this will cause JTAG discconnect */
	REG_CCFG_SYSIO |= CCFG_SYSIO_SYSIO4;
	REG_CCFG_SYSIO |= CCFG_SYSIO_SYSIO5;
#endif

	/* Initialize the board */
	board_init();

	/* Initialize the console UART */
	configure_console();

	/* Output example information */
	puts(STRING_HEADER);

#if (SAMG55)
	/* Enable the peripheral and set TWI mode. */
	flexcom_enable(BOARD_FLEXCOM_TWI);
	flexcom_set_opmode(BOARD_FLEXCOM_TWI, FLEXCOM_TWI);
#else
	/* Enable the peripheral clock for TWI */
	pmc_enable_periph_clk(BOARD_ID_TWI_SLAVE);
#endif

	for (i = 0; i < MEMORY_SIZE; i++) {
		emulate_driver.uc_memory[i] = 0;
	}
	emulate_driver.us_offset_memory = 0;
	emulate_driver.uc_acquire_address = 0;
	emulate_driver.us_page_address = 0;

	/* Configure TWI as slave */
	puts("-I- Configuring the TWI in slave mode\n\r");
	twi_slave_init(BOARD_BASE_TWI_SLAVE, SLAVE_ADDRESS);

	/* Clear receipt buffer */
	twi_read_byte(BOARD_BASE_TWI_SLAVE);

	/* Configure TWI interrupts */
	NVIC_DisableIRQ(BOARD_TWI_IRQn);
	NVIC_ClearPendingIRQ(BOARD_TWI_IRQn);
	NVIC_SetPriority(BOARD_TWI_IRQn, 0);
	NVIC_EnableIRQ(BOARD_TWI_IRQn);
	twi_enable_interrupt(BOARD_BASE_TWI_SLAVE, TWI_SR_SVACC);

	while (1) {
	}
}
Ejemplo n.º 3
0
void TwoWire::begin(uint8_t address) {
	if (onBeginCallback != nullptr)
	{
		onBeginCallback();
	}

	// Disable PDC channel
	twi->TWI_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;

	twi_slave_init(twi, address);
	status = SLAVE_IDLE;
	twi_enable_interrupt(twi, TWI_IER_SVACC);
	//| TWI_IER_RXRDY | TWI_IER_TXRDY	| TWI_IER_TXCOMP);
}
Ejemplo n.º 4
0
int
main() {
	led_on();
	blinds_init();
	
	// Register PUT and GET callbacks.

	twi_init(0x0E);
	twi_enable_interrupt();
	twi_register_get(blinds_do_get);
	twi_register_put(blinds_do_put);
	sei();
	while(1) {
		blinds_update_status();
	}
	return 0;
}
Ejemplo n.º 5
0
void BOARD_TWI_Handler(void)
{
	uint32_t status;

	status = twi_get_interrupt_status(BOARD_BASE_TWI_SLAVE);

	if (((status & TWI_SR_SVACC) == TWI_SR_SVACC)
			&& (emulate_driver.uc_acquire_address == 0)) {
		twi_disable_interrupt(BOARD_BASE_TWI_SLAVE, TWI_IDR_SVACC);
		twi_enable_interrupt(BOARD_BASE_TWI_SLAVE, TWI_IER_RXRDY | TWI_IER_GACC
				| TWI_IER_NACK | TWI_IER_EOSACC | TWI_IER_SCL_WS);
		emulate_driver.uc_acquire_address++;
		emulate_driver.us_page_address = 0;
		emulate_driver.us_offset_memory = 0;
	}

	if ((status & TWI_SR_GACC) == TWI_SR_GACC) {
		puts("General Call Treatment\n\r");
		puts("not treated");
	}

	if (((status & TWI_SR_SVACC) == TWI_SR_SVACC) && ((status & TWI_SR_GACC) == 0)
			&& ((status & TWI_SR_RXRDY) == TWI_SR_RXRDY)) {

		if (emulate_driver.uc_acquire_address == 1) {
			/* Acquire MSB address */
			emulate_driver.us_page_address =
					(twi_read_byte(BOARD_BASE_TWI_SLAVE) & 0xFF) << 8;
			emulate_driver.uc_acquire_address++;
		} else {
			if (emulate_driver.uc_acquire_address == 2) {
				/* Acquire LSB address */
				emulate_driver.us_page_address |=
						(twi_read_byte(BOARD_BASE_TWI_SLAVE) & 0xFF);
				emulate_driver.uc_acquire_address++;
			} else {
				/* Read one byte of data from master to slave device */
				emulate_driver.uc_memory[emulate_driver.us_page_address +
					emulate_driver.us_offset_memory] =
						(twi_read_byte(BOARD_BASE_TWI_SLAVE) & 0xFF);

				emulate_driver.us_offset_memory++;
			}
		}
	} else {
		if (((status & TWI_SR_TXRDY) == TWI_SR_TXRDY)
				&& ((status & TWI_SR_TXCOMP) == TWI_SR_TXCOMP)
				&& ((status & TWI_SR_EOSACC) == TWI_SR_EOSACC)) {
			/* End of transfer, end of slave access */
			emulate_driver.us_offset_memory = 0;
			emulate_driver.uc_acquire_address = 0;
			emulate_driver.us_page_address = 0;
			twi_enable_interrupt(BOARD_BASE_TWI_SLAVE, TWI_SR_SVACC);
			twi_disable_interrupt(BOARD_BASE_TWI_SLAVE,
					TWI_IDR_RXRDY | TWI_IDR_GACC |
					TWI_IDR_NACK | TWI_IDR_EOSACC | TWI_IDR_SCL_WS);
		} else {
			if (((status & TWI_SR_SVACC) == TWI_SR_SVACC)
					&& ((status & TWI_SR_GACC) == 0)
					&& (emulate_driver.uc_acquire_address == 3)
					&& ((status & TWI_SR_SVREAD) == TWI_SR_SVREAD)
					&& ((status & TWI_SR_NACK) == 0)) {
				/* Write one byte of data from slave to master device */
				twi_write_byte(BOARD_BASE_TWI_SLAVE,
						emulate_driver.uc_memory[emulate_driver.us_page_address
						+ emulate_driver.us_offset_memory]);
				emulate_driver.us_offset_memory++;
			}
		}
	}
}
Ejemplo n.º 6
0
/**
 * \ingroup freertos_twi_peripheral_control_group
 * \brief Initiate a completely asynchronous multi-byte read operation on an TWI
 * peripheral.
 *
 * freertos_twi_read_packet_async() is an ASF specific FreeRTOS driver function.
 * It configures the TWI peripheral DMA controller (PDC) to read data from the
 * TWI port, then returns.  freertos_twi_read_packet_async() does not wait for
 * the reception to complete before returning.
 *
 * The FreeRTOS ASF TWI driver is initialized using a call to
 * freertos_twi_master_init().  The freertos_driver_parameters.options_flags
 * parameter passed into the initialization function defines the driver behavior.
 * freertos_twi_read_packet_async() can only be used if the
 * freertos_driver_parameters.options_flags parameter passed to the initialization
 * function had the WAIT_RX_COMPLETE bit clear. The function can also only be used
 * if the length of the packet is more that two. If less, it will block until the
 * transfer is done.
 *
 * freertos_twi_read_packet_async() is an advanced function and readers are
 * recommended to also reference the application note and examples that
 * accompany the FreeRTOS ASF drivers.  freertos_twi_read_packet() is a version
 * that does not exit until the PDC transfer is complete, but still allows other
 * RTOS tasks to execute while the transmission is in progress.
 *
 * 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.
 *
 * \param p_twi    The handle to the TWI port returned by the
 *     freertos_twi_master_init() call used to initialise the port.
 * \param p_packet    Structure that defines the TWI transfer parameters, such
 *     as the I2C chip being addressed, the destination for the data being read,
 *     and the number of bytes to read.  twi_packet_t is a standard ASF type (it
 *     is not FreeRTOS specific).
 * \param block_time_ticks    The FreeRTOS ASF TWI driver is initialized using a
 *     call to freertos_twi_master_init().  The
 *     freertos_driver_parameters.options_flags parameter passed to the
 *     initialization function defines the driver behavior.  If
 *     freertos_driver_parameters.options_flags had the USE_RX_ACCESS_MUTEX bit
 *     set, then the driver will only read from the TWI peripheral if it has
 *     first gained exclusive access to it.  block_time_ticks specifies the
 *     maximum amount of time the driver will wait to get exclusive access
 *     before aborting the read operation.  Other tasks will execute during any
 *     waiting time.  block_time_ticks is specified in RTOS tick periods.  To
 *     specify a block time in milliseconds, divide the milliseconds value by
 *     portTICK_RATE_MS, and pass the result in block_time_ticks.
 *     portTICK_RATE_MS is defined by FreeRTOS.
 * \param notification_semaphore    The RTOS task that calls the receive
 *     function exits the receive function as soon as the reception starts.
 *     The data being received by the PDC cannot normally be processed until
 *     after the reception has completed.  The PDC interrupt (handled internally
 *     by the FreeRTOS ASF driver) 'gives' the semaphore when the PDC transfer
 *     completes.  The notification_semaphore therefore provides a mechanism for
 *     the calling task to know when the PDC has read the requested number of
 *     bytes.  The calling task can call standard FreeRTOS functions to block on
 *     the semaphore until the PDC interrupt occurs.  Other RTOS tasks will
 *     execute while the the calling task is in the Blocked state.  The
 *     semaphore must be created using the FreeRTOS vSemaphoreCreateBinary() API
 *     function before it is used as a parameter.
 *
 * \return     ERR_INVALID_ARG is returned if an input parameter is invalid.
 *     ERR_TIMEOUT is returned if block_time_ticks passed before exclusive
 *     access to the TWI peripheral could be obtained.  STATUS_OK is returned if
 *     the PDC was successfully configured to perform the TWI read operation.
 */
status_code_t freertos_twi_read_packet_async(freertos_twi_if p_twi,
		twi_packet_t *p_packet, portTickType block_time_ticks,
		xSemaphoreHandle notification_semaphore)
{
	status_code_t return_value;
	portBASE_TYPE twi_index;
	Twi *twi_base;
	uint32_t internal_address = 0;

	twi_base = (Twi *) p_twi;
	twi_index = get_pdc_peripheral_details(all_twi_definitions, MAX_TWIS,
			(void *) twi_base);

	/* Don't do anything unless a valid TWI pointer was used. */
	if ((twi_index < MAX_TWIS) && (p_packet->length > 0)) {
		/* Because the peripheral is half duplex, there is only one access mutex
		and the rx uses the tx mutex. */
		return_value = freertos_obtain_peripheral_access_mutex(
				&(tx_dma_control[twi_index]), &block_time_ticks);

		if (return_value == STATUS_OK) {
			/* Ensure Rx is already empty. */
			twi_read_byte(twi_base);

			/* Set read mode and slave address. */
			twi_base->TWI_MMR = 0;
			twi_base->TWI_MMR = TWI_MMR_MREAD | TWI_MMR_DADR(
					p_packet->chip) |
					((p_packet->addr_length <<
					TWI_MMR_IADRSZ_Pos) &
					TWI_MMR_IADRSZ_Msk);

			/* Set internal address if any. */
			if (p_packet->addr_length) {
				internal_address = p_packet->addr [0];
				if (p_packet->addr_length > 1) {
					internal_address <<= 8;
					internal_address |= p_packet->addr[1];
				}

				if (p_packet->addr_length > 2) {
					internal_address <<= 8;
					internal_address |= p_packet->addr[2];
				}
			}
			twi_base->TWI_IADR = internal_address;

			if (p_packet->length <= 2) {
				/* Do not handle errors for short packets in interrupt handler */
				twi_disable_interrupt(
						all_twi_definitions[twi_index].peripheral_base_address,
						IER_ERROR_INTERRUPTS);

				/* Cannot use PDC transfer, use normal transfer */
				uint8_t stop_sent = 0;
				uint32_t cnt = p_packet->length;
				uint32_t status;
				uint8_t *buffer = p_packet->buffer;
				uint32_t timeout_counter = 0;

				/* Start the transfer. */
				if (cnt == 1) {
					twi_base->TWI_CR = TWI_CR_START | TWI_CR_STOP;
					stop_sent = 1;
				} else {
					twi_base->TWI_CR = TWI_CR_START;
				}

				while (cnt > 0) {
					status = twi_base->TWI_SR;
					if (status & TWI_SR_NACK) {
						/* Re-enable interrupts */
						twi_enable_interrupt(
								all_twi_definitions[twi_index].peripheral_base_address,
								IER_ERROR_INTERRUPTS);
						/* Release semaphore */
						xSemaphoreGive(tx_dma_control[twi_index].peripheral_access_mutex);
						return ERR_BUSY;
					}
					/* Last byte ? */
					if (cnt == 1 && !stop_sent) {
						twi_base->TWI_CR = TWI_CR_STOP;
						stop_sent = 1;
					}
					if (!(status & TWI_SR_RXRDY)) {
						if (++timeout_counter >= TWI_TIMEOUT_COUNTER) {
							return_value = ERR_TIMEOUT;
							break;
						}
						continue;
					}
					*buffer++ = twi_base->TWI_RHR;
					cnt--;
					timeout_counter = 0;
				}

				timeout_counter = 0;
				/* Wait for stop to be sent */
				while (!(twi_base->TWI_SR & TWI_SR_TXCOMP)) {
					/* Check timeout condition. */
					if (++timeout_counter >= TWI_TIMEOUT_COUNTER) {
						return_value = ERR_TIMEOUT;
						break;
					}
				}
				/* Re-enable interrupts */
				twi_enable_interrupt(
						all_twi_definitions[twi_index].peripheral_base_address,
						IER_ERROR_INTERRUPTS);
				/* Release semaphores */
				xSemaphoreGive(tx_dma_control[twi_index].peripheral_access_mutex);
				if (return_value != ERR_TIMEOUT) {
					if (rx_dma_control[twi_index].transaction_complete_notification_semaphore != NULL) {
						xSemaphoreGive(rx_dma_control[twi_index].transaction_complete_notification_semaphore);
					}
				}
			} else {
				/* Start the PDC reception. */
				twis[twi_index].buffer = p_packet->buffer;
				twis[twi_index].length = p_packet->length;
				freertos_start_pdc_rx(&(rx_dma_control[twi_index]),
						p_packet->buffer, (p_packet->length)-2,
						all_twi_definitions[twi_index].pdc_base_address,
						notification_semaphore);

				/* Start the transfer. */
				twi_base->TWI_CR = TWI_CR_START;

				/* Catch the end of reception so the access mutex can be returned,
				and the task notified (if it supplied a notification semaphore).
				The interrupt can be enabled here because the ENDRX	signal from the
				PDC to the peripheral will have been de-asserted when the next
				transfer was configured. */
				twi_enable_interrupt(twi_base, TWI_IER_ENDRX);

				return_value = freertos_optionally_wait_transfer_completion(
						&(rx_dma_control[twi_index]),
						notification_semaphore,
						block_time_ticks);
			}
		}
	} else {
		return_value = ERR_INVALID_ARG;
	}

	return return_value;
}
Ejemplo n.º 7
0
/**
 * \ingroup freertos_twi_peripheral_control_group
 * \brief Initiate a completely asynchronous multi-byte write operation on a TWI
 * peripheral.
 *
 * freertos_twi_write_packet_async() is an ASF specific FreeRTOS driver function.
 * It configures the TWI peripheral DMA controller (PDC) to transmit data on the
 * TWI port, then returns.  freertos_twi_write_packet_async() does not wait for
 * the transmission to complete before returning.
 *
 * The FreeRTOS TWI driver is initialized using a call to
 * freertos_twi_master_init().  The freertos_driver_parameters.options_flags
 * parameter passed into the initialization function defines the driver behavior.
 * freertos_twi_write_packet_async() can only be used if the
 * freertos_driver_parameters.options_flags parameter passed to the initialization
 * function had the WAIT_TX_COMPLETE bit clear. It can also only be used if packet
 * length is more than 1.
 *
 * freertos_twi_write_packet_async() is an advanced function and readers are
 * recommended to also reference the application note and examples that
 * accompany the FreeRTOS ASF drivers.  freertos_twi_write_packet() is a version
 * that does not exit until the PDC transfer is complete, but still allows other
 * RTOS tasks to execute while the transmission is in progress.
 *
 * 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.
 *
 * \param p_twi    The handle to the TWI peripheral returned by the
 *     freertos_twi_master_init() call used to initialise the peripheral.
 * \param p_packet    Structure that defines the TWI transfer parameters, such
 *     as the I2C chip being addressed, the source data location, and the number
 *     of bytes to transmit.  twi_packet_t is a standard ASF type (it is not
 *     FreeRTOS specific).
 * \param block_time_ticks    The FreeRTOS ASF TWI driver is initialized using a
 *     call to freertos_twi_master_init().  The
 *     freertos_driver_parameters.options_flags parameter passed to the
 *     initialization function defines the driver behavior.  If
 *     freertos_driver_parameters.options_flags had the USE_TX_ACCESS_MUTEX bit
 *     set, then the driver will only write to the TWI peripheral if it has
 *     first gained exclusive access to it.  block_time_ticks specifies the
 *     maximum amount of time the driver will wait to get exclusive access
 *     before aborting the write operation.  Other tasks will execute during any
 *     waiting time.  block_time_ticks is specified in RTOS tick periods.  To
 *     specify a block time in milliseconds, divide the milliseconds value by
 *     portTICK_RATE_MS, and pass the result in block_time_ticks.
 *     portTICK_RATE_MS is defined by FreeRTOS.
 * \param notification_semaphore    The RTOS task that calls the transmit
 *     function exits the transmit function as soon as the transmission starts.
 *     The data being transmitted by the PDC must not be modified until after
 *     the transmission has completed.  The PDC interrupt (handled internally by
 *     the FreeRTOS ASF driver) 'gives' the semaphore when the PDC transfer
 *     completes.  The notification_semaphore therefore provides a mechanism for
 *     the calling task to know when the PDC has finished accessing the data.
 *     The calling task can call standard FreeRTOS functions to block on the
 *     semaphore until the PDC interrupt occurs.  Other RTOS tasks will execute
 *     while the the calling task is in the Blocked state.  The semaphore must
 *     be created using the FreeRTOS vSemaphoreCreateBinary() API function
 *     before it is used as a parameter.
 *
 * \return     ERR_INVALID_ARG is returned if an input parameter is invalid.
 *     ERR_TIMEOUT is returned if block_time_ticks passed before exclusive
 *     access to the TWI peripheral could be obtained.  STATUS_OK is returned if
 *     the PDC was successfully configured to perform the TWI write operation.
 */
status_code_t freertos_twi_write_packet_async(freertos_twi_if p_twi,
		twi_packet_t *p_packet, portTickType block_time_ticks,
		xSemaphoreHandle notification_semaphore)
{
	status_code_t return_value;
	portBASE_TYPE twi_index;
	Twi *twi_base;
	uint32_t internal_address = 0;

	twi_base = (Twi *) p_twi;
	twi_index = get_pdc_peripheral_details(all_twi_definitions, MAX_TWIS,
			(void *) twi_base);

	/* Don't do anything unless a valid TWI pointer was used. */
	if ((twi_index < MAX_TWIS) && (p_packet->length > 0)) {
		return_value = freertos_obtain_peripheral_access_mutex(
				&(tx_dma_control[twi_index]), &block_time_ticks);

		if (return_value == STATUS_OK) {
			/* Set write mode and slave address. */
			twi_base->TWI_MMR = 0;
			twi_base->TWI_MMR = TWI_MMR_DADR(p_packet->chip) |
					((p_packet->addr_length <<
					TWI_MMR_IADRSZ_Pos) &
					TWI_MMR_IADRSZ_Msk);

			/* Set internal address if any. */
			if (p_packet->addr_length > 0) {
				internal_address = p_packet->addr[0];
				if (p_packet->addr_length > 1) {
					internal_address <<= 8;
					internal_address |= p_packet->addr[1];
				}

				if (p_packet->addr_length > 2) {
					internal_address <<= 8;
					internal_address |= p_packet->addr[2];
				}
			}
			twi_base->TWI_IADR = internal_address;

			if (p_packet->length == 1) {
				uint32_t status;
				uint32_t timeout_counter = 0;
				/* Do not handle errors for short packets in interrupt handler */
				twi_disable_interrupt(
						all_twi_definitions[twi_index].peripheral_base_address,
						IER_ERROR_INTERRUPTS);
				/* Send start condition */
				twi_base->TWI_THR = *((uint8_t*)(p_packet->buffer));
				while (1) {
					status = twi_base->TWI_SR;
					if (status & TWI_SR_NACK) {
						/* Re-enable interrupts */
						twi_enable_interrupt(
								all_twi_definitions[twi_index].peripheral_base_address,
								IER_ERROR_INTERRUPTS);
						/* Release semaphore */
						xSemaphoreGive(tx_dma_control[twi_index].peripheral_access_mutex);
						return ERR_BUSY;
					}
					if (status & TWI_SR_TXRDY) {
						break;
					}
					/* Check timeout condition. */
					if (++timeout_counter >= TWI_TIMEOUT_COUNTER) {
						return_value = ERR_TIMEOUT;
						break;
					}
				}
				twi_base->TWI_CR = TWI_CR_STOP;
				/* Wait for TX complete */
				while (!(twi_base->TWI_SR & TWI_SR_TXCOMP)) {
					/* Check timeout condition. */
					if (++timeout_counter >= TWI_TIMEOUT_COUNTER) {
						return_value = ERR_TIMEOUT;
						break;
					}
				}

				/* Re-enable interrupts */
				twi_enable_interrupt(
						all_twi_definitions[twi_index].peripheral_base_address,
						IER_ERROR_INTERRUPTS);
				/* Release semaphores */
				xSemaphoreGive(tx_dma_control[twi_index].peripheral_access_mutex);
				if (return_value != ERR_TIMEOUT) {
					if (tx_dma_control[twi_index].transaction_complete_notification_semaphore != NULL) {
						xSemaphoreGive(tx_dma_control[twi_index].transaction_complete_notification_semaphore);
					}
				}

			} else {

				twis[twi_index].buffer = p_packet->buffer;
				twis[twi_index].length = p_packet->length;

				freertos_start_pdc_tx(&(tx_dma_control[twi_index]),
						p_packet->buffer, p_packet->length - 1,
						all_twi_definitions[twi_index].pdc_base_address,
						notification_semaphore);

				/* Catch the end of transmission so the access mutex can be
				returned, and the task notified (if it supplied a notification
				semaphore).  The interrupt can be enabled here because the ENDTX
				signal from the PDC to the peripheral will have been de-asserted when
				the next transfer was configured. */
				twi_enable_interrupt(twi_base, TWI_IER_ENDTX);

				return_value = freertos_optionally_wait_transfer_completion(
						&(tx_dma_control[twi_index]),
						notification_semaphore,
						block_time_ticks);
			}
		}
	} else {
		return_value = ERR_INVALID_ARG;
	}

	return return_value;
}
Ejemplo n.º 8
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;
}
Ejemplo n.º 9
0
void TwoWire::onService(void) {
	// Retrieve interrupt status
	uint32_t sr = twi_get_interrupt_status(twi);

	if (status == SLAVE_IDLE && TWI_STATUS_SVACC(sr)) {
		twi_disable_interrupt(twi, TWI_IDR_SVACC);
		twi_enable_interrupt(twi, TWI_IER_RXRDY | TWI_IER_GACC | TWI_IER_NACK
				| TWI_IER_EOSACC | TWI_IER_SCL_WS | TWI_IER_TXCOMP);

		srvBufferLength = 0;
		srvBufferIndex = 0;

		// Detect if we should go into RECV or SEND status
		// SVREAD==1 means *master* reading -> SLAVE_SEND
		if (!TWI_STATUS_SVREAD(sr)) {
			status = SLAVE_RECV;
		} else {
			status = SLAVE_SEND;

			// Alert calling program to generate a response ASAP
			if (onRequestCallback)
				onRequestCallback();
			else
				// create a default 1-byte response
				write((uint8_t) 0);
		}
	}

	if (status != SLAVE_IDLE) {
		if (TWI_STATUS_TXCOMP(sr) && TWI_STATUS_EOSACC(sr)) {
			if (status == SLAVE_RECV && onReceiveCallback) {
				// Copy data into rxBuffer
				// (allows to receive another packet while the
				// user program reads actual data)
				for (uint8_t i = 0; i < srvBufferLength; ++i)
					rxBuffer[i] = srvBuffer[i];
				rxBufferIndex = 0;
				rxBufferLength = srvBufferLength;

				// Alert calling program
				onReceiveCallback( rxBufferLength);
			}

			// Transfer completed
			twi_enable_interrupt(twi, TWI_SR_SVACC);
			twi_disable_interrupt(twi, TWI_IDR_RXRDY | TWI_IDR_GACC | TWI_IDR_NACK
					| TWI_IDR_EOSACC | TWI_IDR_SCL_WS | TWI_IER_TXCOMP);
			status = SLAVE_IDLE;
		}
	}

	if (status == SLAVE_RECV) {
		if (TWI_STATUS_RXRDY(sr)) {
			if (srvBufferLength < BUFFER_LENGTH)
			{
				srvBuffer[srvBufferLength++] = twi_read_byte(twi);
			}
		}
	}

	if (status == SLAVE_SEND) {
		if (TWI_STATUS_TXRDY(sr) && !TWI_STATUS_NACK(sr)) {
			uint8_t c = 'x';
			if (srvBufferIndex < srvBufferLength)
			{
				c = srvBuffer[srvBufferIndex++];
			}
			twi_write_byte(twi, c);
		}
	}
}