/** * \brief Application entry point for TWIHS Slave example. * * \return Unused (ANSI-C compatibility). */ int main(void) { uint32_t i; /* Initialize the SAM system */ sysclk_init(); /* Initialize the board */ board_init(); /* Initialize the console UART */ configure_console(); /* Output example information */ puts(STRING_HEADER); /* Enable the peripheral clock for TWIHS */ pmc_enable_periph_clk(BOARD_ID_TWIHS_SLAVE); 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 TWIHS as slave */ puts("-I- Configuring the TWIHS in slave mode\n\r"); twihs_slave_init(BOARD_BASE_TWIHS_SLAVE, SLAVE_ADDRESS); /* Clear receipt buffer */ twihs_read_byte(BOARD_BASE_TWIHS_SLAVE); /* Configure TWIHS interrupts */ NVIC_DisableIRQ(BOARD_TWIHS_IRQn); NVIC_ClearPendingIRQ(BOARD_TWIHS_IRQn); NVIC_SetPriority(BOARD_TWIHS_IRQn, 0); NVIC_EnableIRQ(BOARD_TWIHS_IRQn); twihs_enable_interrupt(BOARD_BASE_TWIHS_SLAVE, TWIHS_SR_SVACC); while (1) { } }
/** * \ingroup freertos_twihs_peripheral_control_group * \brief Initiate a completely asynchronous multi-byte read operation on an TWIHS * peripheral. * * freertos_twihs_read_packet_async() is an ASF specific FreeRTOS driver function. * It configures the TWIHS peripheral DMA controller (PDC) to read data from the * TWIHS port, then returns. freertos_twihs_read_packet_async() does not wait for * the reception to complete before returning. * * The FreeRTOS ASF TWIHS driver is initialized using a call to * freertos_twihs_master_init(). The freertos_driver_parameters.options_flags * parameter passed into the initialization function defines the driver behavior. * freertos_twihs_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. * * freertos_twihs_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_twihs_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 TWIHS PDC interrupts. * Users do not need to concern themselves with interrupt handling, and must * not install their own interrupt handler. * * \param p_twihs The handle to the TWIHS port returned by the * freertos_twihs_master_init() call used to initialise the port. * \param p_packet Structure that defines the TWIHS transfer parameters, such * as the I2C chip being addressed, the destination for the data being read, * and the number of bytes to read. twihs_packet_t is a standard ASF type (it * is not FreeRTOS specific). * \param block_time_ticks The FreeRTOS ASF TWIHS driver is initialized using a * call to freertos_twihs_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 TWIHS 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 TWIHS peripheral could be obtained. STATUS_OK is returned if * the PDC was successfully configured to perform the TWIHS read operation. */ status_code_t freertos_twihs_read_packet_async(freertos_twihs_if p_twihs, twihs_packet_t *p_packet, portTickType block_time_ticks, xSemaphoreHandle notification_semaphore) { status_code_t return_value; portBASE_TYPE twihs_index; Twihs *twihs_base; uint32_t internal_address = 0; twihs_base = (Twihs *) p_twihs; twihs_index = get_pdc_peripheral_details(all_twihs_definitions, MAX_TWIHS, (void *) twihs_base); /* Don't do anything unless a valid TWIHS pointer was used. */ if ((twihs_index < MAX_TWIHS) && (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[twihs_index]), &block_time_ticks); if (return_value == STATUS_OK) { /* Ensure Rx is already empty. */ twihs_read_byte(twihs_base); /* Set read mode and slave address. */ twihs_base->TWIHS_MMR = 0; twihs_base->TWIHS_MMR = TWIHS_MMR_MREAD | TWIHS_MMR_DADR( p_packet->chip) | ((p_packet->addr_length << TWIHS_MMR_IADRSZ_Pos) & TWIHS_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]; } } twihs_base->TWIHS_IADR = internal_address; if (p_packet->length <= 2) { /* Do not handle errors for short packets in interrupt handler */ twihs_disable_interrupt( all_twihs_definitions[twihs_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) { twihs_base->TWIHS_CR = TWIHS_CR_START | TWIHS_CR_STOP; stop_sent = 1; } else { twihs_base->TWIHS_CR = TWIHS_CR_START; } while (cnt > 0) { status = twihs_base->TWIHS_SR; if (status & TWIHS_SR_NACK) { /* Re-enable interrupts */ twihs_enable_interrupt( all_twihs_definitions[twihs_index].peripheral_base_address, IER_ERROR_INTERRUPTS); /* Release semaphore */ xSemaphoreGive(tx_dma_control[twihs_index].peripheral_access_mutex); return TWIHS_RECEIVE_NACK; } /* Last byte ? */ if (cnt == 1 && !stop_sent) { twihs_base->TWIHS_CR = TWIHS_CR_STOP; stop_sent = 1; } if (!(status & TWIHS_SR_RXRDY)) { if (++timeout_counter >= TWIHS_TIMEOUT_COUNTER) { return_value = ERR_TIMEOUT; break; } continue; } *buffer++ = twihs_base->TWIHS_RHR; cnt--; timeout_counter = 0; } timeout_counter = 0; /* Wait for stop to be sent */ while (!(twihs_base->TWIHS_SR & TWIHS_SR_TXCOMP)) { /* Check timeout condition. */ if (++timeout_counter >= TWIHS_TIMEOUT_COUNTER) { return_value = ERR_TIMEOUT; break; } } /* Re-enable interrupts */ twihs_enable_interrupt( all_twihs_definitions[twihs_index].peripheral_base_address, IER_ERROR_INTERRUPTS); /* Release semaphores */ xSemaphoreGive(tx_dma_control[twihs_index].peripheral_access_mutex); } else { /* Start the PDC reception. */ twihss[twihs_index].buffer = p_packet->buffer; twihss[twihs_index].length = p_packet->length; freertos_start_pdc_rx(&(rx_dma_control[twihs_index]), p_packet->buffer, p_packet->length, all_twihs_definitions[twihs_index].pdc_base_address, notification_semaphore); /* Start the transfer. */ twihs_base->TWIHS_CR = TWIHS_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. */ twihs_enable_interrupt(twihs_base, TWIHS_IER_ENDRX); return_value = freertos_optionally_wait_transfer_completion( &(rx_dma_control[twihs_index]), notification_semaphore, block_time_ticks); } } } else { return_value = ERR_INVALID_ARG; } return return_value; }
void BOARD_TWIHS_Handler(void) { uint32_t status; status = twihs_get_interrupt_status(BOARD_BASE_TWIHS_SLAVE); if (((status & TWIHS_SR_SVACC) == TWIHS_SR_SVACC) && (emulate_driver.uc_acquire_address == 0)) { twihs_disable_interrupt(BOARD_BASE_TWIHS_SLAVE, TWIHS_IDR_SVACC); twihs_enable_interrupt(BOARD_BASE_TWIHS_SLAVE, TWIHS_IER_RXRDY | TWIHS_IER_GACC | TWIHS_IER_NACK | TWIHS_IER_EOSACC | TWIHS_IER_SCL_WS); emulate_driver.uc_acquire_address++; emulate_driver.us_page_address = 0; emulate_driver.us_offset_memory = 0; } if ((status & TWIHS_SR_GACC) == TWIHS_SR_GACC) { puts("General Call Treatment\n\r"); puts("not treated"); } if (((status & TWIHS_SR_SVACC) == TWIHS_SR_SVACC) && ((status & TWIHS_SR_GACC) == 0) && ((status & TWIHS_SR_RXRDY) == TWIHS_SR_RXRDY)) { if (emulate_driver.uc_acquire_address == 1) { /* Acquire MSB address */ emulate_driver.us_page_address = (twihs_read_byte(BOARD_BASE_TWIHS_SLAVE) & 0xFF) << 8; emulate_driver.uc_acquire_address++; } else { if (emulate_driver.uc_acquire_address == 2) { /* Acquire LSB address */ emulate_driver.us_page_address |= (twihs_read_byte(BOARD_BASE_TWIHS_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] = (twihs_read_byte(BOARD_BASE_TWIHS_SLAVE) & 0xFF); emulate_driver.us_offset_memory++; } } } else { if (((status & TWIHS_SR_TXRDY) == TWIHS_SR_TXRDY) && ((status & TWIHS_SR_TXCOMP) == TWIHS_SR_TXCOMP) && ((status & TWIHS_SR_EOSACC) == TWIHS_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; twihs_enable_interrupt(BOARD_BASE_TWIHS_SLAVE, TWIHS_SR_SVACC); twihs_disable_interrupt(BOARD_BASE_TWIHS_SLAVE, TWIHS_IDR_RXRDY | TWIHS_IDR_GACC | TWIHS_IDR_NACK | TWIHS_IDR_EOSACC | TWIHS_IDR_SCL_WS); } else { if (((status & TWIHS_SR_SVACC) == TWIHS_SR_SVACC) && ((status & TWIHS_SR_GACC) == 0) && (emulate_driver.uc_acquire_address == 3) && ((status & TWIHS_SR_SVREAD) == TWIHS_SR_SVREAD) && ((status & TWIHS_SR_NACK) == 0)) { /* Write one byte of data from slave to master device */ twihs_write_byte(BOARD_BASE_TWIHS_SLAVE, emulate_driver.uc_memory[emulate_driver.us_page_address + emulate_driver.us_offset_memory]); emulate_driver.us_offset_memory++; } } } }