Exemplo n.º 1
0
/*
 * For internal use only.
 * A common TWI interrupt handler that is called for all TWI peripherals.
 */
static void local_twi_handler(const portBASE_TYPE twi_index)
{
	portBASE_TYPE higher_priority_task_woken = pdFALSE;
	uint32_t twi_status;
	Twi *twi_port;
	bool transfer_timeout = false;

	twi_port = all_twi_definitions[twi_index].peripheral_base_address;

	twi_status = twi_get_interrupt_status(twi_port);
	twi_status &= twi_get_interrupt_mask(twi_port);

	/* Has the PDC completed a transmission? */
	if ((twi_status & TWI_SR_ENDTX) != 0UL) {
		/* Disable PDC */
		pdc_disable_transfer(all_twi_definitions[twi_index].pdc_base_address, PERIPH_PTCR_TXTDIS);
		twi_disable_interrupt(twi_port, TWI_IDR_ENDTX);

		uint8_t status;
		uint32_t timeout_counter = 0;

		/* Wait for TX ready flag */
		while (1) {
			status = twi_port->TWI_SR;
			if (status & TWI_SR_TXRDY) {
				break;
			}
			/* Check timeout condition. */
			if (++timeout_counter >= TWI_TIMEOUT_COUNTER) {
				transfer_timeout = true;
				break;
			}
		}
		/* Complete the transfer - stop and last byte */
		twi_port->TWI_CR = TWI_CR_STOP;
		twi_port->TWI_THR = twis[twi_index].buffer[twis[twi_index].length-1];

		/* Wait for TX complete flag */
		while (1) {
			status = twi_port->TWI_SR;
			if (status & TWI_SR_TXCOMP) {
				break;
			}
			/* Check timeout condition. */
			if (++timeout_counter >= TWI_TIMEOUT_COUNTER) {
				transfer_timeout = true;
				break;
			}
		}
		/* If the driver is supporting multi-threading, then return the access
		mutex. */
		if (tx_dma_control[twi_index].peripheral_access_mutex != NULL) {
			xSemaphoreGiveFromISR(
					tx_dma_control[twi_index].peripheral_access_mutex,
					&higher_priority_task_woken);
		}

		/* if the sending task supplied a notification semaphore, then
		notify the task that the transmission has completed. */
		if (!(timeout_counter >= TWI_TIMEOUT_COUNTER)) {
			if (tx_dma_control[twi_index]. transaction_complete_notification_semaphore != NULL) {
				xSemaphoreGiveFromISR(
						tx_dma_control[twi_index].transaction_complete_notification_semaphore,
						&higher_priority_task_woken);
			}
		}
	}

	/* Has the PDC completed a reception? */
	if ((twi_status & TWI_SR_ENDRX) != 0UL) {
		uint32_t timeout_counter = 0;
		uint32_t status;
		/* Must handle the two last bytes */
		/* Disable PDC */
		pdc_disable_transfer(all_twi_definitions[twi_index].pdc_base_address, PERIPH_PTCR_RXTDIS);

		twi_disable_interrupt(twi_port, TWI_IDR_ENDRX);

		/* Wait for RX ready flag */
		while (1) {
			status = twi_port->TWI_SR;
			if (status & TWI_SR_RXRDY) {
				break;
			}
			/* Check timeout condition. */
			if (++timeout_counter >= TWI_TIMEOUT_COUNTER) {
				break;
			}
		}
		/* Complete the transfer. */
		twi_port->TWI_CR = TWI_CR_STOP;
		/* Read second last data */
		twis[twi_index].buffer[(twis[twi_index].length)-2] = twi_port->TWI_RHR;

		/* Wait for RX ready flag */
		while (1) {
			status = twi_port->TWI_SR;
			if (status & TWI_SR_RXRDY) {
				break;
			}
			/* Check timeout condition. */
			if (++timeout_counter >= TWI_TIMEOUT_COUNTER) {
				break;
			}
		}

		if (!(timeout_counter >= TWI_TIMEOUT_COUNTER)) {
			/* Read last data */
			twis[twi_index].buffer[(twis[twi_index].length)-1] = twi_port->TWI_RHR;
			timeout_counter = 0;
			/* Wait for TX complete flag before releasing semaphore */
			while (1) {
				status = twi_port->TWI_SR;
				if (status & TWI_SR_TXCOMP) {
					break;
				}
				/* Check timeout condition. */
				if (++timeout_counter >= TWI_TIMEOUT_COUNTER) {
					transfer_timeout = true;
					break;
				}
			}
		}

		/* If the driver is supporting multi-threading, then return the access
		mutex.  NOTE: As the peripheral is half duplex there is only one
		access mutex, and the reception uses the tx access muted. */
		if (tx_dma_control[twi_index].peripheral_access_mutex != NULL) {
			xSemaphoreGiveFromISR(
					tx_dma_control[twi_index].peripheral_access_mutex,
					&higher_priority_task_woken);
		}

		/* if the receiving task supplied a notification semaphore, then
		notify the task that the transmission has completed. */
		if  (!(timeout_counter >= TWI_TIMEOUT_COUNTER)) {
			if (rx_dma_control[twi_index].transaction_complete_notification_semaphore != NULL) {
				xSemaphoreGiveFromISR(
						rx_dma_control[twi_index].transaction_complete_notification_semaphore,
						&higher_priority_task_woken);
			}
		}
	}

	if (((twi_status & SR_ERROR_INTERRUPTS) != 0) || (transfer_timeout == true)) {
		/* An error occurred in either a transmission or reception.  Abort.
		Stop the transmission, disable interrupts used by the peripheral, and
		ensure the peripheral access mutex is made available to tasks.  As this
		peripheral is half duplex, only the Tx peripheral access mutex exits.*/

		/* Stop the PDC */
		pdc_disable_transfer(all_twi_definitions[twi_index].pdc_base_address, PERIPH_PTCR_TXTDIS | PERIPH_PTCR_RXTDIS);

		if (!(twi_status & TWI_SR_NACK)) {
			/* Do not send stop if NACK received. Handled by hardware */
			twi_port->TWI_CR = TWI_CR_STOP;
		}
		twi_disable_interrupt(twi_port, TWI_IDR_ENDTX);
		twi_disable_interrupt(twi_port, TWI_IDR_ENDRX);

		if (tx_dma_control[twi_index].peripheral_access_mutex != NULL) {
			xSemaphoreGiveFromISR(
					tx_dma_control[twi_index].peripheral_access_mutex,
					&higher_priority_task_woken);
		}
	}

	/* If giving a semaphore caused a task to unblock, and the unblocked task
	has a priority equal to or higher than the currently running task (the task
	this ISR interrupted), then higher_priority_task_woken will have
	automatically been set to pdTRUE within the semaphore function.
	portEND_SWITCHING_ISR() will then ensure that this ISR returns directly to
	the higher priority unblocked task. */
	portEND_SWITCHING_ISR(higher_priority_task_woken);
}
Exemplo n.º 2
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++;
			}
		}
	}
}
Exemplo n.º 3
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);
		}
	}
}