/** * Detects stuck slaves (SDA = 0 and SCL = 1) and tries to clear the bus. * * @return * @retval false Bus is stuck. * @retval true Bus is clear. */ static bool twi_master_clear_bus(void) { bool bus_clear; TWI_SDA_HIGH() ; TWI_SCL_HIGH() ; TWI_DELAY(); if (TWI_SDA_READ() == 1 && TWI_SCL_READ() == 1) { bus_clear = true; } else { uint_fast8_t i; bus_clear = false; // Clock max 18 pulses worst case scenario(9 for master to send the rest of command and 9 for slave to respond) to SCL line and wait for SDA come high for (i = 18; i--;) { TWI_SCL_LOW() ; TWI_DELAY(); TWI_SCL_HIGH() ; TWI_DELAY(); if (TWI_SDA_READ() == 1) { bus_clear = true; break; } } } return bus_clear; }
/** * @brief Function for pulling SCL high and waits until it is high or timeout occurs. * * SCL is expected to be output before entering this function. * @note If TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE is set to zero, timeout functionality is not compiled in. * @return * @retval true SCL is now high. * @retval false Timeout occurred and SCL is still low. */ bool twi_master_wait_while_scl_low(void) { #if TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE != 0 uint32_t volatile timeout_counter = TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE; #endif // Pull SCL high just in case if something left it low TWI_SCL_HIGH(); TWI_DELAY(); while (TWI_SCL_READ() == 0) { // If SCL is low, one of the slaves is busy and we must wait // nrf_delay_us(1); #if TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE != 0 if (timeout_counter-- == 0) { // If timeout_detected, return false return false; } #endif } return true; }
void db_reset() { NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos; TWI_SCL_OUTPUT(); TWI_SCL_LOW(); delay_ms(30); TWI_SCL_HIGH(); TWI_SCL_INPUT(); /* Allow daughterboard time to boot */ delay_ms(5); }
bool twi_master_init(void) { // Configure both pins to output Standard 0, No-drive (open-drain) 1 TWI_SDA_STANDARD0_NODRIVE1(); /*lint !e416 "Creation of out of bounds pointer" */ TWI_SCL_STANDARD0_NODRIVE1(); /*lint !e416 "Creation of out of bounds pointer" */ // Configure SCL as output TWI_SCL_HIGH(); TWI_SCL_OUTPUT(); // Configure SDA as output TWI_SDA_HIGH(); TWI_SDA_OUTPUT(); return twi_master_clear_bus(); }
/** * @brief Function for detecting stuck slaves (SDA = 0 and SCL = 1) and tries to clear the bus. * * @return * @retval false Bus is stuck. * @retval true Bus is clear. */ static bool twi_master_clear_bus(void) { uint32_t twi_state; bool bus_clear; uint32_t clk_pin_config; uint32_t data_pin_config; // Save and disable TWI hardware so software can take control over the pins. twi_state = NRF_TWI1->ENABLE; NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos; clk_pin_config = \ NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER]; NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER] = \ (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \ | (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \ | (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) \ | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \ | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); data_pin_config = \ NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER]; NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER] = \ (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \ | (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \ | (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) \ | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \ | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); TWI_SDA_HIGH(); TWI_SCL_HIGH(); TWI_DELAY(); if ((TWI_SDA_READ() == 1) && (TWI_SCL_READ() == 1)) { bus_clear = true; } else { uint_fast8_t i; bus_clear = false; // Clock max 18 pulses worst case scenario(9 for master to send the rest of command and 9 // for slave to respond) to SCL line and wait for SDA come high. for (i=18; i--;) { TWI_SCL_LOW(); TWI_DELAY(); TWI_SCL_HIGH(); TWI_DELAY(); if (TWI_SDA_READ() == 1) { bus_clear = true; break; } } } NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER] = clk_pin_config; NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER] = data_pin_config; NRF_TWI1->ENABLE = twi_state; return bus_clear; }