/** * \brief Set the I2C bus speed in conjunction with the clock frequency. * * \param p_twihs Pointer to a TWIHS instance. * \param ul_speed The desired I2C bus speed (in Hz). * \param ul_mck Main clock of the device (in Hz). * * \retval PASS New speed setting is accepted. * \retval FAIL New speed setting is rejected. */ uint32_t twihs_set_speed(Twihs *p_twihs, uint32_t ul_speed, uint32_t ul_mck) { uint32_t ckdiv = 0; uint32_t c_lh_div; uint32_t cldiv, chdiv; /* High-Speed can be only used in slave mode, 400k is the max speed allowed for master */ if (ul_speed > I2C_FAST_MODE_SPEED) { return FAIL; } /* Low level time not less than 1.3us of I2C Fast Mode. */ if (ul_speed > LOW_LEVEL_TIME_LIMIT) { /* Low level of time fixed for 1.3us. */ cldiv = ul_mck / (LOW_LEVEL_TIME_LIMIT * TWIHS_CLK_DIVIDER) - TWIHS_CLK_CALC_ARGU; chdiv = ul_mck / ((ul_speed + (ul_speed - LOW_LEVEL_TIME_LIMIT)) * TWIHS_CLK_DIVIDER) - TWIHS_CLK_CALC_ARGU; /* cldiv must fit in 8 bits, ckdiv must fit in 3 bits */ while ((cldiv > TWIHS_CLK_DIV_MAX) && (ckdiv < TWIHS_CLK_DIV_MIN)) { /* Increase clock divider */ ckdiv++; /* Divide cldiv value */ cldiv /= TWIHS_CLK_DIVIDER; } /* chdiv must fit in 8 bits, ckdiv must fit in 3 bits */ while ((chdiv > TWIHS_CLK_DIV_MAX) && (ckdiv < TWIHS_CLK_DIV_MIN)) { /* Increase clock divider */ ckdiv++; /* Divide cldiv value */ chdiv /= TWIHS_CLK_DIVIDER; } /* set clock waveform generator register */ p_twihs->TWIHS_CWGR = TWIHS_CWGR_CLDIV(cldiv) | TWIHS_CWGR_CHDIV(chdiv) | TWIHS_CWGR_CKDIV(ckdiv); } else { c_lh_div = ul_mck / (ul_speed * TWIHS_CLK_DIVIDER) - TWIHS_CLK_CALC_ARGU; /* cldiv must fit in 8 bits, ckdiv must fit in 3 bits */ while ((c_lh_div > TWIHS_CLK_DIV_MAX) && (ckdiv < TWIHS_CLK_DIV_MIN)) { /* Increase clock divider */ ckdiv++; /* Divide cldiv value */ c_lh_div /= TWIHS_CLK_DIVIDER; } /* set clock waveform generator register */ p_twihs->TWIHS_CWGR = TWIHS_CWGR_CLDIV(c_lh_div) | TWIHS_CWGR_CHDIV(c_lh_div) | TWIHS_CWGR_CKDIV(ckdiv); } return PASS; }
/** * \brief Set the I2C bus speed in conjunction with the clock frequency. * * \param p_twihs Pointer to a TWIHS instance. * \param ul_speed The desired I2C bus speed (in Hz). * \param ul_mck Main clock of the device (in Hz). * * \retval PASS New speed setting is accepted. * \retval FAIL New speed setting is rejected. */ uint32_t twihs_set_speed(Twihs *p_twihs, uint32_t ul_speed, uint32_t ul_mck) { uint32_t ckdiv = 0; uint32_t c_lh_div; /* High-Speed can be only used in slave mode, 400k is the max speed allowed for master */ if (ul_speed > I2C_FAST_MODE_SPEED) { return FAIL; } c_lh_div = ul_mck / (ul_speed * TWIHS_CLK_DIVIDER) - TWIHS_CLK_CALC_ARGU; /* cldiv must fit in 8 bits, ckdiv must fit in 3 bits */ while ((c_lh_div > TWIHS_CLK_DIV_MAX) && (ckdiv < TWIHS_CLK_DIV_MIN)) { /* Increase clock divider */ ckdiv++; /* Divide cldiv value */ c_lh_div /= TWIHS_CLK_DIVIDER; } /* set clock waveform generator register */ p_twihs->TWIHS_CWGR = TWIHS_CWGR_CLDIV(c_lh_div) | TWIHS_CWGR_CHDIV(c_lh_div) | TWIHS_CWGR_CKDIV(ckdiv); return PASS; }
bool i2c_init(void *i2c) { Twihs *twi = (Twihs *)i2c; if (twi != TWIHS0) { printf("ahh unknown TWI peripheral\r\n"); return false; } PMC->PMC_PCER0 |= (1 << ID_TWIHS0); pin_set_mux(PIOA, 3, PERIPH_A); // sdc0 pin_set_mux(PIOA, 4, PERIPH_A); // sda0 // set up 400 kHz i2c timing on our 144 MHz system clock //twi->TWIHS_CWGR = TWIHS_CWGR_CHDIV(86) | TWIHS_CWGR_CLDIV(187) | TWIHS_CWGR_CKDIV(2); // hmm...this board doesn't have any i2c pullups, so let's do 100 kHz i2c twi->TWIHS_CWGR = TWIHS_CWGR_CHDIV(170) | TWIHS_CWGR_CLDIV(170) | TWIHS_CWGR_HOLD(0x1f) | // todo: need to solder on physical pullups TWIHS_CWGR_CKDIV(2); twi->TWIHS_CR = TWIHS_CR_SVDIS; // disable slave mode. ONCE I WAS THE LEARNER twi->TWIHS_CR = TWIHS_CR_MSEN; // enable master mode. NOW I AM THE MASTER printf("twi init complete\r\n"); return true; }