/* * For internal use only. * A common TWIHS interrupt handler that is called for all TWIHS peripherals. */ static void local_twihs_handler(const portBASE_TYPE twihs_index) { portBASE_TYPE higher_priority_task_woken = pdFALSE; uint32_t twihs_status; Twihs *twihs_port; twihs_port = all_twihs_definitions[twihs_index].peripheral_base_address; twihs_status = twihs_get_interrupt_status(twihs_port); twihs_status &= twihs_get_interrupt_mask(twihs_port); /* Has the PDC completed a transmission? */ if ((twihs_status & TWIHS_SR_ENDTX) != 0UL) { /* Disable PDC */ pdc_disable_transfer(all_twihs_definitions[twihs_index].pdc_base_address, PERIPH_PTCR_TXTDIS); twihs_disable_interrupt(twihs_port, TWIHS_IDR_ENDTX); uint8_t status; uint32_t timeout_counter = 0; /* Wait for TX ready flag */ while (1) { status = twihs_port->TWIHS_SR; if (status & TWIHS_SR_TXRDY) { break; } /* Check timeout condition. */ if (++timeout_counter >= TWIHS_TIMEOUT_COUNTER) { status = ERR_TIMEOUT; break; } } /* Complete the transfer - stop and last byte */ twihs_port->TWIHS_CR = TWIHS_CR_STOP; twihs_port->TWIHS_THR = twihss[twihs_index].buffer[twihss[twihs_index].length-1]; /* Wait for TX complete flag */ while (1) { status = twihs_port->TWIHS_SR; if (status & TWIHS_SR_TXCOMP) { break; } /* Check timeout condition. */ if (++timeout_counter >= TWIHS_TIMEOUT_COUNTER) { status = ERR_TIMEOUT; break; } } /* If the driver is supporting multi-threading, then return the access mutex. */ if (tx_dma_control[twihs_index].peripheral_access_mutex != NULL) { xSemaphoreGiveFromISR( tx_dma_control[twihs_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 >= TWIHS_TIMEOUT_COUNTER)) { if (tx_dma_control[twihs_index]. transaction_complete_notification_semaphore != NULL) { xSemaphoreGiveFromISR( tx_dma_control[twihs_index].transaction_complete_notification_semaphore, &higher_priority_task_woken); } } } /* Has the PDC completed a reception? */ if ((twihs_status & TWIHS_SR_ENDRX) != 0UL) { uint32_t timeout_counter = 0; uint32_t status; /* Must handle the two last bytes */ /* Disable PDC */ pdc_disable_transfer(all_twihs_definitions[twihs_index].pdc_base_address, PERIPH_PTCR_RXTDIS); twihs_disable_interrupt(twihs_port, TWIHS_IDR_ENDRX); /* Wait for RX ready flag */ while (1) { status = twihs_port->TWIHS_SR; if (status & TWIHS_SR_RXRDY) { break; } /* Check timeout condition. */ if (++timeout_counter >= TWIHS_TIMEOUT_COUNTER) { break; } } /* Complete the transfer. */ twihs_port->TWIHS_CR = TWIHS_CR_STOP; /* Read second last data */ twihss[twihs_index].buffer[(twihss[twihs_index].length)-2] = twihs_port->TWIHS_RHR; /* Wait for RX ready flag */ while (1) { status = twihs_port->TWIHS_SR; if (status & TWIHS_SR_RXRDY) { break; } /* Check timeout condition. */ if (++timeout_counter >= TWIHS_TIMEOUT_COUNTER) { break; } } if (!(timeout_counter >= TWIHS_TIMEOUT_COUNTER)) { /* Read last data */ twihss[twihs_index].buffer[(twihss[twihs_index].length)-1] = twihs_port->TWIHS_RHR; timeout_counter = 0; /* Wait for TX complete flag before releasing semaphore */ while (1) { status = twihs_port->TWIHS_SR; if (status & TWIHS_SR_TXCOMP) { break; } /* Check timeout condition. */ if (++timeout_counter >= TWIHS_TIMEOUT_COUNTER) { status = ERR_TIMEOUT; 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[twihs_index].peripheral_access_mutex != NULL) { xSemaphoreGiveFromISR( tx_dma_control[twihs_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 >= TWIHS_TIMEOUT_COUNTER)) { if (rx_dma_control[twihs_index].transaction_complete_notification_semaphore != NULL) { xSemaphoreGiveFromISR( rx_dma_control[twihs_index].transaction_complete_notification_semaphore, &higher_priority_task_woken); } } } if ((twihs_status & SR_ERROR_INTERRUPTS) != 0) { /* 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_twihs_definitions[twihs_index].pdc_base_address, PERIPH_PTCR_TXTDIS | PERIPH_PTCR_RXTDIS); if (!(twihs_status & TWIHS_SR_NACK)) { /* Do not send stop if NACK received. Handled by hardware */ twihs_port->TWIHS_CR = TWIHS_CR_STOP; } twihs_disable_interrupt(twihs_port, TWIHS_IDR_ENDTX); twihs_disable_interrupt(twihs_port, TWIHS_IDR_ENDRX); if (tx_dma_control[twihs_index].peripheral_access_mutex != NULL) { xSemaphoreGiveFromISR( tx_dma_control[twihs_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); }
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++; } } } }