static inline void PPRZ_I2C_SEND_START(struct i2c_periph *periph) { uint32_t i2c = (uint32_t) periph->reg_addr; // Reset the buffer pointer to the first byte periph->idx_buf = 0; #ifdef I2C_DEBUG_LED LED_SHOW_ACTIVE_BITS(regs); LED2_ON(); LED1_ON(); LED1_OFF(); LED1_ON(); LED1_OFF(); LED1_ON(); LED1_OFF(); LED2_OFF(); #endif // Enable Error IRQ, Event IRQ but disable Buffer IRQ i2c_enable_interrupt(i2c, I2C_CR2_ITERREN); i2c_enable_interrupt(i2c, I2C_CR2_ITEVTEN); i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN); // Issue a new start i2c_nack_current(i2c); i2c_disable_ack(i2c); i2c_clear_stop(i2c); i2c_peripheral_enable(i2c); i2c_send_start(i2c); periph->status = I2CStartRequested; }
/** Start i2c asynchronous transfer. * @param obj The I2C object * @param tx The buffer to send * @param tx_length The number of words to transmit * @param rx The buffer to receive * @param rx_length The number of words to receive * @param address The address to be set - 7bit or 9 bit * @param stop If true, stop will be generated after the transfer is done * @param handler The I2C IRQ handler to be set * @param hint DMA hint usage */ void i2c_transfer_asynch(i2c_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint32_t address, uint32_t stop, uint32_t handler, uint32_t event, DMAUsage hint) { I2C_TransferReturn_TypeDef retval; if(i2c_active(obj)) return; if((tx_length == 0) && (rx_length == 0)) return; // For now, we are assuming a solely interrupt-driven implementation. // Store transfer config obj->i2c.xfer.addr = address; // Some combination of tx_length and rx_length will tell us what to do if((tx_length > 0) && (rx_length == 0)) { obj->i2c.xfer.flags = I2C_FLAG_WRITE; //Store buffer info obj->i2c.xfer.buf[0].data = (void *)tx; obj->i2c.xfer.buf[0].len = (uint16_t) tx_length; } else if ((tx_length == 0) && (rx_length > 0)) { obj->i2c.xfer.flags = I2C_FLAG_READ; //Store buffer info obj->i2c.xfer.buf[0].data = rx; obj->i2c.xfer.buf[0].len = (uint16_t) rx_length; } else if ((tx_length > 0) && (rx_length > 0)) { obj->i2c.xfer.flags = I2C_FLAG_WRITE_READ; //Store buffer info obj->i2c.xfer.buf[0].data = (void *)tx; obj->i2c.xfer.buf[0].len = (uint16_t) tx_length; obj->i2c.xfer.buf[1].data = rx; obj->i2c.xfer.buf[1].len = (uint16_t) rx_length; } if(address > 255) obj->i2c.xfer.flags |= I2C_FLAG_10BIT_ADDR; // Store event flags obj->i2c.events = event; // Enable interrupt i2c_enable_interrupt(obj, handler, true); // Kick off the transfer retval = I2C_TransferInit(obj->i2c.i2c, &(obj->i2c.xfer)); if(retval == i2cTransferInProgress) { blockSleepMode(EM1); } else { // something happened, and the transfer did not go through // So, we need to clean up // Disable interrupt i2c_enable_interrupt(obj, 0, false); // Block until free while(i2c_active(obj)); } }
// Doc ID 13902 Rev 11 p 714/1072 // Transfer Sequence Diagram for Master Receiver for N=1 static inline enum STMI2CSubTransactionStatus stmi2c_read1(uint32_t i2c, struct i2c_periph *periph, struct i2c_transaction *trans) { uint16_t SR1 = I2C_SR1(i2c); // Start Condition Was Just Generated if (BIT_X_IS_SET_IN_REG( I2C_SR1_SB, SR1 ) ) { i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN); i2c_send_data(i2c, trans->slave_addr | 0x01); // Document the current Status periph->status = I2CAddrRdSent; } // Address Was Sent else if (BIT_X_IS_SET_IN_REG(I2C_SR1_ADDR, SR1) ) { // First Clear the ACK bit: after the next byte we do not want new bytes i2c_nack_current(i2c); i2c_disable_ack(i2c); // --- next to steps MUST be executed together to avoid missing the stop __I2C_REG_CRITICAL_ZONE_START; // Only after setting ACK, read SR2 to clear the ADDR (next byte will start arriving) uint16_t SR2 __attribute__ ((unused)) = I2C_SR2(i2c); // Schedule a Stop PPRZ_I2C_SEND_STOP(i2c); __I2C_REG_CRITICAL_ZONE_STOP; // --- end of critical zone ----------- // Enable the RXNE: it will trigger as soon as the 1 byte is received to get the result i2c_enable_interrupt(i2c, I2C_CR2_ITBUFEN); // Document the current Status periph->status = I2CReadingLastByte; } // As soon as there is 1 byte ready to read, we have our byte else if (BIT_X_IS_SET_IN_REG(I2C_SR1_RxNE, SR1) ) { i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN); trans->buf[0] = I2C_DR(i2c); // We got all the results (stop condition might still be in progress but this is the last interrupt) trans->status = I2CTransSuccess; // Document the current Status: // -the stop was actually already requested in the previous step periph->status = I2CStopRequested; return STMI2C_SubTra_Ready_StopRequested; } else // Event Logic Error { return STMI2C_SubTra_Error; } return STMI2C_SubTra_Busy; }
void i2c3_ev_isr(void) { uint32_t i2c = (uint32_t) i2c3.reg_addr; i2c_disable_interrupt(i2c, I2C_CR2_ITERREN); i2c3.watchdog = 0; // restart watchdog i2c_irq(&i2c3); i2c_enable_interrupt(i2c, I2C_CR2_ITERREN); }
void i2c2_er_isr(void) { uint32_t i2c = (uint32_t) i2c2.reg_addr; i2c_disable_interrupt(i2c, I2C_CR2_ITEVTEN); i2c2.watchdog = 0; // restart watchdog i2c_irq(&i2c2); i2c_enable_interrupt(i2c, I2C_CR2_ITEVTEN); }
/* Function to init EEPROM driver and I2C peripheral */ void eeprom_init(void) { /* Enable GPIOB clock. */ rcc_periph_clock_enable(RCC_GPIOB); /* set I2C1_SCL and I2C1_SDA, external pull-up resistors */ gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO6 | GPIO7); /* Open Drain, Speed 100 MHz */ gpio_set_output_options(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_100MHZ, GPIO6 | GPIO7); /* Alternate Function: I2C1 */ gpio_set_af(GPIOB, GPIO_AF4, GPIO6 | GPIO7); /* Enable I2C1 clock. */ rcc_periph_clock_enable(RCC_I2C1); /* Enable I2C1 interrupt. */ nvic_enable_irq(NVIC_I2C1_EV_IRQ); /* reset I2C1 */ i2c_reset(I2C1); /* standard mode */ i2c_set_standard_mode(I2C1); /* clock and bus frequencies */ i2c_set_clock_frequency(I2C1, I2C_CR2_FREQ_2MHZ); i2c_set_ccr(I2C1, 20); /* enable error event interrupt only */ i2c_enable_interrupt(I2C1, I2C_CR2_ITERREN); /* enable I2C */ i2c_peripheral_enable(I2C1); }
/** The asynchronous IRQ handler * @param obj The I2C object which holds the transfer information * @return Returns event flags if a transfer termination condition was met or 0 otherwise. */ uint32_t i2c_irq_handler_asynch(i2c_t *obj) { // For now, we are assuming a solely interrupt-driven implementation. I2C_TransferReturn_TypeDef status = I2C_Transfer(obj->i2c.i2c); switch(status) { case i2cTransferInProgress: // Still busy transferring, so let it. return 0; case i2cTransferDone: // Transfer has completed // Disable interrupt i2c_enable_interrupt(obj, 0, false); unblockSleepMode(EM1); return I2C_EVENT_TRANSFER_COMPLETE & obj->i2c.events; case i2cTransferNack: // A NACK has been received while an ACK was expected. This is usually because the slave did not respond to the address. // Disable interrupt i2c_enable_interrupt(obj, 0, false); unblockSleepMode(EM1); return I2C_EVENT_ERROR_NO_SLAVE & obj->i2c.events; default: // An error situation has arisen. // Disable interrupt i2c_enable_interrupt(obj, 0, false); unblockSleepMode(EM1); // return error return I2C_EVENT_ERROR & obj->i2c.events; } }
void i2c1_hw_init(void) { i2c1.reg_addr = (void *)I2C1; i2c1.init_struct = NULL; i2c1.errors = &i2c1_errors; i2c1.watchdog = -1; /* zeros error counter */ ZEROS_ERR_COUNTER(i2c1_errors); // Extra #ifdef I2C_DEBUG_LED LED_INIT(); #else /* reset peripheral to default state ( sometimes not achieved on reset :( ) */ //rcc_periph_reset_pulse(RST_I2C1); /* Configure and enable I2C1 event interrupt --------------------------------*/ nvic_set_priority(NVIC_I2C1_EV_IRQ, NVIC_I2C1_IRQ_PRIO); nvic_enable_irq(NVIC_I2C1_EV_IRQ); /* Configure and enable I2C1 err interrupt ----------------------------------*/ nvic_set_priority(NVIC_I2C1_ER_IRQ, NVIC_I2C1_IRQ_PRIO+1); nvic_enable_irq(NVIC_I2C1_ER_IRQ); /* Enable peripheral clocks -------------------------------------------------*/ /* Enable I2C1 clock */ rcc_periph_clock_enable(RCC_I2C1); /* setup gpio clock and pins */ i2c_setup_gpio(I2C1); rcc_periph_reset_pulse(RST_I2C1); // enable peripheral i2c_peripheral_enable(I2C1); /* * XXX: there is a function to do that already in libopencm3 but I am not * sure if it is correct, using direct register instead (esden) */ //i2c_set_own_7bit_slave_address(I2C1, 0); I2C_OAR1(I2C1) = 0 | 0x4000; // enable error interrupts i2c_enable_interrupt(I2C1, I2C_CR2_ITERREN); i2c_setbitrate(&i2c1, I2C1_CLOCK_SPEED); #endif }
/** Abort ongoing asynchronous transaction. * @param obj The I2C object */ void i2c_abort_asynch(i2c_t *obj) { // Do not deactivate I2C twice if (!i2c_active(obj)) return; // Disable interrupt i2c_enable_interrupt(obj, 0, false); // Abort obj->i2c.i2c->CMD = I2C_CMD_STOP | I2C_CMD_ABORT; // Block until free while(i2c_active(obj)); unblockSleepMode(EM1); }
// Doc ID 13902 Rev 11 p 712/1072 // Transfer Sequence Diagram for Master Receiver for N>2 static inline enum STMI2CSubTransactionStatus stmi2c_readmany(uint32_t i2c, struct i2c_periph *periph, struct i2c_transaction *trans) { uint16_t SR1 = I2C_SR1(i2c); // Start Condition Was Just Generated if (BIT_X_IS_SET_IN_REG( I2C_SR1_SB, SR1 ) ) { i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN); // The first data byte will be acked in read many so the slave knows it should send more i2c_nack_current(i2c); i2c_enable_ack(i2c); // Clear the SB flag i2c_send_data(i2c, trans->slave_addr | 0x01); // Document the current Status periph->status = I2CAddrRdSent; } // Address Was Sent else if (BIT_X_IS_SET_IN_REG(I2C_SR1_ADDR, SR1) ) { periph->idx_buf = 0; // Enable RXNE: receive an interrupt any time a byte is available // only enable if MORE than 3 bytes need to be read if (periph->idx_buf < (trans->len_r - 3)) { i2c_enable_interrupt(i2c, I2C_CR2_ITBUFEN); } // ACK is still on to get more DATA // Read SR2 to clear the ADDR (next byte will start arriving) uint16_t SR2 __attribute__ ((unused)) = I2C_SR2(i2c); // Document the current Status periph->status = I2CReadingByte; } // one or more bytes are available AND we were interested in Buffer interrupts else if ( (BIT_X_IS_SET_IN_REG(I2C_SR1_RxNE, SR1) ) && (BIT_X_IS_SET_IN_REG(I2C_CR2_ITBUFEN, I2C_CR2(i2c))) ) { // read byte until 3 bytes remain to be read (e.g. len_r = 6, -> idx=3 means idx 3,4,5 = 3 remain to be read if (periph->idx_buf < (trans->len_r - 3)) { trans->buf[periph->idx_buf] = I2C_DR(i2c); periph->idx_buf ++; } // from : 3bytes -> last byte: do nothing // // finally: this was the last byte else if (periph->idx_buf >= (trans->len_r - 1)) { i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN); // Last Value trans->buf[periph->idx_buf] = i2c_get_data(i2c); periph->idx_buf ++; // We got all the results trans->status = I2CTransSuccess; return STMI2C_SubTra_Ready_StopRequested; } // Check for end of transaction: start waiting for BTF instead of RXNE if (periph->idx_buf < (trans->len_r - 3)) { i2c_enable_interrupt(i2c, I2C_CR2_ITBUFEN); } else // idx >= len-3: there are 3 bytes to be read { // We want to halt I2C to have sufficient time to clear ACK, so: // Stop listening to RXNE as it will be triggered infinitely since we did not empty the buffer // on the next (second in buffer) received byte BTF will be set (buffer full and I2C halted) i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN); } } // Buffer is full while this was not a RXNE interrupt else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BTF, SR1) ) { // Now the shift register and data register contain data(n-2) and data(n-1) // And I2C is halted so we have time // --- Make absolutely sure the next 2 I2C actions are performed with no delay __I2C_REG_CRITICAL_ZONE_START; // First we clear the ACK while the SCL is held low by BTF i2c_disable_ack(i2c); // Now that ACK is cleared we read one byte: instantly the last byte is being clocked in... trans->buf[periph->idx_buf] = i2c_get_data(i2c); periph->idx_buf ++; // Now the last byte is being clocked. Stop in MUST be set BEFORE the transfer of the last byte is complete PPRZ_I2C_SEND_STOP(i2c); __I2C_REG_CRITICAL_ZONE_STOP; // --- end of critical zone ----------- // Document the current Status periph->status = I2CStopRequested; // read the byte2 we had in the buffer (BTF means 2 bytes available) trans->buf[periph->idx_buf] = i2c_get_data(i2c); periph->idx_buf ++; // Ask for an interrupt to read the last byte (which is normally still busy now) // The last byte will be received with RXNE i2c_enable_interrupt(i2c, I2C_CR2_ITBUFEN); } else // Event Logic Error { return STMI2C_SubTra_Error; } return STMI2C_SubTra_Busy; }
// Doc ID 13902 Rev 11 p 710/1072 // Transfer Sequence Diagram for Master Transmitter static inline enum STMI2CSubTransactionStatus stmi2c_send(uint32_t i2c, struct i2c_periph *periph, struct i2c_transaction *trans) { uint16_t SR1 = I2C_SR1(i2c); // Start Condition Was Just Generated if (BIT_X_IS_SET_IN_REG( I2C_SR1_SB, SR1 ) ) { // Disable buffer interrupt i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN); // Send Slave address and wait for ADDR interrupt i2c_send_data(i2c, trans->slave_addr); // Document the current Status periph->status = I2CAddrWrSent; } // Address Was Sent else if (BIT_X_IS_SET_IN_REG(I2C_SR1_ADDR, SR1) ) { // Now read SR2 to clear the ADDR status Bit uint16_t SR2 __attribute__ ((unused)) = I2C_SR2(i2c); // Maybe check we are transmitting (did not loose arbitration for instance) // if (! BIT_X_IS_SET_IN_REG(I2C_SR2_TRA, SR2)) { } // update: this should be caught by the ARLO error: so we will not arrive here // Send First max 2 bytes i2c_send_data(i2c, trans->buf[0]); if (trans->len_w > 1) { i2c_send_data(i2c, trans->buf[1]); periph->idx_buf = 2; } else { periph->idx_buf = 1; } // Enable buffer-space available interrupt // only if there is more to send: wait for TXE, no more to send: wait for BTF if ( periph->idx_buf < trans->len_w) i2c_enable_interrupt(i2c, I2C_CR2_ITBUFEN); // Document the current Status periph->status = I2CSendingByte; } // The buffer is not full anymore AND we were not waiting for BTF else if ((BIT_X_IS_SET_IN_REG(I2C_SR1_TxE, SR1) ) && (BIT_X_IS_SET_IN_REG(I2C_CR2_ITBUFEN, I2C_CR2(i2c))) ) { // Send the next byte i2c_send_data(i2c, trans->buf[periph->idx_buf]); periph->idx_buf++; // All bytes Sent? Then wait for BTF instead if ( periph->idx_buf >= trans->len_w) { // Not interested anymore to know the buffer has space left i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN); // Next interrupt will be BTF (or error) } } // BTF: means last byte was sent else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BTF, SR1) ) { if (trans->type == I2CTransTx) { // Tell the driver we are ready trans->status = I2CTransSuccess; } // Otherwise we still need to do the receiving part return STMI2C_SubTra_Ready; } else // Event Logic Error { return STMI2C_SubTra_Error; } return STMI2C_SubTra_Busy; }
static void i2c_wd_check(struct i2c_periph *periph) { uint32_t i2c = (uint32_t) periph->reg_addr; if (periph->watchdog > WD_DELAY) { if (periph->watchdog == WD_DELAY + 1) { i2c_disable_interrupt(i2c, I2C_CR2_ITEVTEN); i2c_disable_interrupt(i2c, I2C_CR2_ITERREN); i2c_peripheral_disable(i2c); #if USE_I2C1 if (i2c == I2C1) { gpio_setup_output(I2C1_GPIO_PORT, I2C1_GPIO_SCL); gpio_setup_input(I2C1_GPIO_PORT, I2C1_GPIO_SDA); } #endif #if USE_I2C2 if (i2c == I2C2) { gpio_setup_output(I2C2_GPIO_PORT, I2C2_GPIO_SCL); gpio_setup_input(I2C2_GPIO_PORT, I2C2_GPIO_SDA); } #endif #if USE_I2C3 if (i2c == I2C3) { gpio_setup_output(I2C3_GPIO_PORT_SCL, I2C3_GPIO_SCL); gpio_setup_input(I2C3_GPIO_PORT_SDA,I2C3_GPIO_SDA); } #endif i2c_scl_clear(i2c); } else if (periph->watchdog < WD_DELAY + WD_RECOVERY_TICKS) { if ((periph->watchdog - WD_DELAY) % 2) i2c_scl_clear(i2c); else i2c_scl_set(i2c); } else { i2c_scl_set(i2c); /* setup gpios for normal i2c operation again */ i2c_setup_gpio(i2c); periph->trans_insert_idx = 0; periph->trans_extract_idx = 0; periph->status = I2CIdle; i2c_enable_interrupt(i2c, I2C_CR2_ITEVTEN); i2c_enable_interrupt(i2c, I2C_CR2_ITERREN); i2c_peripheral_enable(i2c); periph->watchdog = 0; // restart watchdog periph->errors->timeout_tlow_cnt++; return; } } if (periph->watchdog >= 0) periph->watchdog++; }
static void setup_i2c_port(enum I2C_FREQ I2C_speed) { // Disable I2C if it happens to be enabled i2c_peripheral_disable(I2C_PORT); dma_channel_reset(I2C_TX_DMA, I2C_TX_DMA_CHANNEL); i2c_disable_interrupt(I2C_PORT, (I2C_CR2_ITEVTEN | I2C_CR2_ITERREN)); DISABLE_I2C_INTERRUPT(); reset_i2c_pins(); // set: Source, Destination, and Amount (DMA channel must be disabled) dma_set_peripheral_address(I2C_TX_DMA, I2C_TX_DMA_CHANNEL, (uint32_t)&I2C_DR(I2C_PORT)); dma_set_memory_address(I2C_TX_DMA, I2C_TX_DMA_CHANNEL, 0); dma_set_number_of_data(I2C_TX_DMA, I2C_TX_DMA_CHANNEL, 0); // set the DMA Configuration (DMA_CCRx) // (BIT 14) mem2mem_mode disabled dma_set_priority(I2C_TX_DMA, I2C_TX_DMA_CHANNEL, DMA_CCR_PL_HIGH); // (BIT 12:13) dma_set_memory_size(I2C_TX_DMA, I2C_TX_DMA_CHANNEL, DMA_CCR_MSIZE_8BIT); // (BIT 10:11) dma_set_peripheral_size(I2C_TX_DMA, I2C_TX_DMA_CHANNEL, DMA_CCR_PSIZE_8BIT); // (BIT 8:9) dma_enable_memory_increment_mode(I2C_TX_DMA, I2C_TX_DMA_CHANNEL); // (BIT 7) dma_disable_peripheral_increment_mode(I2C_TX_DMA, I2C_TX_DMA_CHANNEL); // (BIT 6) // (BIT 5) Circular mode is disabled dma_set_read_from_memory(I2C_TX_DMA, I2C_TX_DMA_CHANNEL); // (BIT 4) dma_enable_transfer_error_interrupt(I2C_TX_DMA, I2C_TX_DMA_CHANNEL); // (BIT 3) dma_disable_half_transfer_interrupt(I2C_TX_DMA, I2C_TX_DMA_CHANNEL); // (BIT 2) dma_enable_transfer_complete_interrupt(I2C_TX_DMA, I2C_TX_DMA_CHANNEL); // (BIT 1) // This is the slave address when not transmitting data i2c_set_own_7bit_slave_address(I2C_PORT, 0x32); // do not respond to the specified slave address i2c_disable_ack(I2C_PORT); // Use DMA to send I2C data i2c_enable_dma(I2C_PORT); // set which interrupts I2C uses i2c_enable_interrupt(I2C_PORT, (I2C_CR2_ITEVTEN | I2C_CR2_ITERREN)); // APB1 is running at 36MHz = T(PCLK1) = 1/36000000 sec. i2c_set_clock_frequency(I2C_PORT, I2C_CR2_FREQ_36MHZ); // Set up the hardware for the particular speed switch (I2C_speed) { // Values found on Internet for the I2C standard // STANDARD : SCL max rise time = 1000ns = 1000/1000000000 sec // FAST : SCL max rise time = 300ns = 300/1000000000 sec // // DATASHEET Function: // TRISE = (T(MAX_SCL_RISE) / T(PCLK1)) + 1 // // DATASHEET Functions: // STANDARD : // T(high) = CCR * T(PCLK1) // T(low) = CCR * T(PCLK1) // FAST (DUTY=I2C_CCR_DUTY_DIV2) // T(high) = CCR * T(PCLK1) // T(low) = 2 * CCR * T(PCLK1) // FAST (DUTY=I2C_CCR_DUTY_16_DIV_9) [To reach 400KHz] // T(high) = 9 * CCR * T(PCLK1) // T(low) = 16 * CCR * T(PCLK1) // // I2C PERIOD: // STANDARD // PERIOD = T(high) + T(low) = (2 * CCR * T(PCLK1)) // FAST (DUTY=I2C_CCR_DUTY_DIV2) // PERIOD = T(high) + T(low) = (3 * CCR * T(PCLK1)) // FAST (DUTY=I2C_CCR_DUTY_16_DIV_9) // PERIOD = T(high) + T(low) = (25 * CCR * T(PCLK1)) case I2C_400KHz: // I2C PERIOD: 400KHz = 400000Hz = 1/400000 sec. i2c_set_fast_mode(I2C_PORT); // I2C_CCR_DUTY_DIV2 or I2C_CCR_DUTY_16_DIV_9 i2c_set_dutycycle(I2C_PORT, I2C_CCR_DUTY_16_DIV_9); // CCR = PERIOD / (25 * T(PCLK1)) // CCR = (1/400000) / (25/36000000) = 18/5 = 3.6 // CCR = 4 => I2C PERIOD = 360kHz // CCR = 3 => I2C PERIOD = 480kHz i2c_set_ccr(I2C_PORT, 4); // Only fast mode can have a value less than 0x04 // TRISE = ( (300/1000000000) / (1/36000000) ) + 1 = 59/5 = 11.8 // TRISE = 12 => SCL max rise time ~= 305.555ns // TRISE = 11 => SCL max rise time ~= 277.777ns i2c_set_trise(I2C_PORT, 11); break; case I2C_100KHz: // I2C PERIOD: 100KHz = 100000Hz = 1/100000 sec. i2c_set_standard_mode(I2C_PORT); // I2C_CCR_DUTY_DIV2 or I2C_CCR_DUTY_16_DIV_9 i2c_set_dutycycle(I2C_PORT, I2C_CCR_DUTY_DIV2); // CCR = PERIOD / (2 * T(PCLK1)) // CCR = (1/100000) / (2/36000000) = 180 i2c_set_ccr(I2C_PORT, 180); // TRISE = ( (1000/1000000000) / (1/36000000) ) + 1 = 37 i2c_set_trise(I2C_PORT, 37); break; case I2C_53KHz: // ~= 52.91kHz is the slowest I could get to work // CCR value of 341 works but not 342 or higher case I2C_50KHz: default: // I2C PERIOD: 50KHz = 50000Hz = 1/50000 sec. i2c_set_standard_mode(I2C_PORT); // I2C_CCR_DUTY_DIV2 or I2C_CCR_DUTY_16_DIV_9 i2c_set_dutycycle(I2C_PORT, I2C_CCR_DUTY_DIV2); // CCR = PERIOD / (2 * T(PCLK1)) // CCR = (1/50000) / (2/36000000) = 360 // (341 works but not 342 or higher) i2c_set_ccr(I2C_PORT, 341); // TRISE = ( (1000/1000000000) / (1/36000000) ) + 1 = 37 i2c_set_trise(I2C_PORT, 37); break; } i2c_peripheral_enable(I2C_PORT); // set the priorities for the interrupts nvic_set_priority(I2C_EV_IRQ, IRQ_PRI_I2C); nvic_set_priority(I2C_ER_IRQ, IRQ_PRI_ER_I2C); nvic_set_priority(I2C_DMA_IRQ, IRQ_PRI_DMA_I2C); }