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); } }
/** * \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) { } }
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); }
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; }
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++; } } } }
/** * \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; }
/** * \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; }
/** * \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; }
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); } } }