// 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_CR2(i2c) &= ~ I2C_CR2_ITBUFEN; I2C_DR(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_CR1(i2c) &= ~ I2C_CR1_POS; I2C_CR1(i2c) &= ~ I2C_CR1_ACK; // --- 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_CR2(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_CR2(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 i2c_transmit(const i2c_channel *cp, const uint8_t *data, size_t count) { uint32_t base = cp->i_base_address; if (cp->i_is_master) { // Send start condition. I2C_CR1(base) |= I2C_CR1_START; uint32_t t0 = system_millis; while (!(I2C_SR1(base) & I2C_SR1_SB)) { if (system_millis >= t0 + TIMEOUT_MSEC) { fprintf(stderr, "i2c: timeout on SB\n"); return; } } // Send slave address. I2C_DR(base) = cp->i_address & ~0x01; t0 = system_millis; while (!(I2C_SR1(base) & I2C_SR1_ADDR)) { if (I2C_SR1(base) & I2C_SR1_AF) { I2C_CR1(base) |= I2C_CR1_STOP; I2C_SR1(base) = ~I2C_SR1_AF; fprintf(stderr, "i2c @ %ld: ack failure on addr\n", system_millis / 1000); return; } if (system_millis >= t0 + TIMEOUT_MSEC) { fprintf(stderr, "i2c: timeout on ADDR\n"); return; } } // Clear ADDR flag by reading SR1 and SR2 registers. uint16_t unused; unused = I2C_SR1(base); unused = I2C_SR2(base); unused = unused; // Write each data byte; wait for BTF. for (size_t i = 0; i < count; i++) { I2C_DR(base) = data[i]; t0 = system_millis; while (!(I2C_SR1(base) & I2C_SR1_BTF)) { if (system_millis >= t0 + TIMEOUT_MSEC) { fprintf(stderr, "i2c: timeout on BTF\n"); return; } } } I2C_CR1(base) |= I2C_CR1_STOP; fprintf(stderr, "i2c @ %lu: transmit complete\n", system_millis / 1000); } else { assert(false && "slave transmission not implemented"); } }
void i2c_setup(void) { rcc_periph_clock_enable(RCC_I2C1); rcc_periph_clock_enable(RCC_GPIOB); //clock from 48 MHz RCC_CFGR3 |= RCC_CFGR3_I2C1SW; //i2c_reset(I2C_BUS); RCC_APB1RSTR |= RCC_APB1RSTR_I2C1RST; RCC_APB1RSTR &= ~RCC_APB1RSTR_I2C1RST; gpio_mode_setup(I2C_PIN_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, I2C_PINS); gpio_set_af(I2C_PIN_PORT, I2C_PIN_AF, I2C_PINS); //i2c_peripheral_disable(I2C_BUS); I2C_CR1(I2C_BUS) &= ~I2C_CR1_PE; //configure ANFOFF DNF[3:0] in CR1 //i2c_enable_analog_filter(I2C_BUS); I2C_CR1(I2C_BUS) &= ~I2C_CR1_ANFOFF; //i2c_set_digital_filter(I2C_BUS, I2C_CR1_DNF_DISABLED); //default is good //Configure PRESC[3:0] SDADEL[3:0] SCLDEL[3:0] SCLH[7:0] SCLL[7:0] // in TIMINGR //i2c_100khz_i2cclk8mhz(I2C_BUS); //let's assume this is good :) //I don't think the timing matters when we're slave I2C_TIMINGR(I2C_BUS) = 0; //configure No-Stretch CR1 (only relevant in slave mode) //i2c_enable_stretching(I2C_BUS); //addressing mode //i2c_set_7bit_addr_mode(I2C_BUS); //default is good //slave address I2C_OAR1(I2C_BUS) = I2C_OAR1_OA1EN + (I2C_SLAVE_ADDRESS << 1); //enable all interrupts I2C_CR1(I2C_BUS) |= 0xfe; //i2c_peripheral_enable(I2C_BUS); I2C_CR1(I2C_BUS) |= I2C_CR1_PE; nvic_enable_irq(NVIC_I2C1_IRQ); }
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_CR2(i2c) |= I2C_CR2_ITERREN; I2C_CR2(i2c) |= I2C_CR2_ITEVTEN; I2C_CR2(i2c) &= ~ I2C_CR2_ITBUFEN; // Issue a new start I2C_CR1(i2c) = (I2C_CR1_START | I2C_CR1_PE); periph->status = I2CStartRequested; }
/* In the event of a bus error (start or stop detected during data transfer), * the peripheral continues as normal, but the slave has likely cancelled * communication, leaving the peripheral expecting communication that won't * occur. The only solution is to reset the peripheral. */ static int i2c_reset(struct i2c_dev *i2c) { if (!i2c) { return -1; } i2c->ready = 0; /* Software reset */ *I2C_CR1(i2c->port) |= I2C_CR1_SWRST; /* Wait until peripheral is disabled */ while (*I2C_CR1(i2c->port) & I2C_CR1_PE); /* Re-enable */ *I2C_CR1(i2c->port) &= ~(I2C_CR1_SWRST); /* Re-initialize */ i2c->init(); return 0; }
static inline void PPRZ_I2C_SEND_STOP(uint32_t i2c) { // Man: p722: Stop generation after the current byte transfer or after the current Start condition is sent. I2C_CR1(i2c) |= I2C_CR1_STOP; #ifdef I2C_DEBUG_LED LED2_ON(); LED1_ON(); LED1_OFF(); LED2_OFF(); #endif }
void reset_i2c_pins(void) { // reseting I2C pins [errata_sheet CD00197763.pdf section 2.14.7] i2c_peripheral_disable(I2C_PORT); gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, I2C_SCL_PIN | I2C_SDA_PIN); gpio_set(GPIOB, I2C_SCL_PIN | I2C_SDA_PIN); while (!gpio_get(GPIOB, I2C_SCL_PIN | I2C_SDA_PIN)); gpio_clear(GPIOB, I2C_SCL_PIN | I2C_SDA_PIN); while (gpio_get(GPIOB, I2C_SCL_PIN | I2C_SDA_PIN)); gpio_set(GPIOB, I2C_SDA_PIN); while (!gpio_get(GPIOB, I2C_SDA_PIN)); gpio_clear(GPIOB, I2C_SDA_PIN); while (gpio_get(GPIOB, I2C_SDA_PIN)); gpio_set(GPIOB, I2C_SCL_PIN); while (!gpio_get(GPIOB, I2C_SCL_PIN)); gpio_clear(GPIOB, I2C_SCL_PIN); while (gpio_get(GPIOB, I2C_SCL_PIN)); gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, I2C_SCL_PIN | I2C_SDA_PIN); I2C_CR1(I2C_PORT) |= I2C_CR1_SWRST; I2C_CR1(I2C_PORT) &= ~I2C_CR1_SWRST; i2c_peripheral_enable(I2C_PORT); }
int tda18219_read_reg(uint8_t reg, uint8_t* value) { uint32_t __attribute__((unused)) reg32; /* Send START condition. */ i2c_send_start(I2C1); /* Waiting for START is send and switched to master mode. */ while (!((I2C_SR1(I2C1) & I2C_SR1_SB) & (I2C_SR2(I2C1) & (I2C_SR2_MSL | I2C_SR2_BUSY)))); /* Say to what address we want to talk to. */ /* Yes, WRITE is correct - for selecting register in STTS75. */ i2c_send_7bit_address(I2C1, TDA18219_I2C_ADDR, I2C_WRITE); /* Waiting for address is transferred. */ while (!(I2C_SR1(I2C1) & I2C_SR1_ADDR)); /* Cleaning ADDR condition sequence. */ reg32 = I2C_SR2(I2C1); i2c_send_data(I2C1, reg); while (!(I2C_SR1(I2C1) & (I2C_SR1_BTF | I2C_SR1_TxE))); /* Send re-START condition. */ i2c_send_start(I2C1); /* Waiting for START is send and switched to master mode. */ while (!((I2C_SR1(I2C1) & I2C_SR1_SB) & (I2C_SR2(I2C1) & (I2C_SR2_MSL | I2C_SR2_BUSY)))); /* Say to what address we want to talk to. */ i2c_send_7bit_address(I2C1, TDA18219_I2C_ADDR, I2C_READ); I2C_CR1(I2C1) &= ~I2C_CR1_ACK; /* Waiting for address is transferred. */ while (!(I2C_SR1(I2C1) & I2C_SR1_ADDR)); /* Cleaning ADDR condition sequence. */ reg32 = I2C_SR2(I2C1); i2c_send_stop(I2C1); while (!(I2C_SR1(I2C1) & I2C_SR1_RxNE)); *value = I2C_DR(I2C1); return 0; }
static void init_i2c2(void) { *RCC_APB1ENR |= RCC_APB1ENR_I2C2EN; /* Enable I2C2 Clock */ *RCC_AHB1ENR |= RCC_AHB1ENR_GPIOBEN; /* Enable GPIOB Clock */ /* Set PB8 and PB9 to alternative function I2C * See stm32f4_ref.pdf pg 141 and stm32f407.pdf pg 51 */ /* I2C2_SCL */ gpio_moder(GPIOB, I2C2_SCL, GPIO_MODER_ALT); gpio_afr(GPIOB, I2C2_SCL, GPIO_AF_I2C); gpio_otyper(GPIOB, I2C2_SCL, GPIO_OTYPER_OD); gpio_pupdr(GPIOB, I2C2_SCL, GPIO_PUPDR_NONE); gpio_ospeedr(GPIOB, I2C2_SCL, GPIO_OSPEEDR_50M); /* I2C2_SDA */ gpio_moder(GPIOB, I2C2_SDA, GPIO_MODER_ALT); gpio_afr(GPIOB, I2C2_SDA, GPIO_AF_I2C); gpio_otyper(GPIOB, I2C2_SDA, GPIO_OTYPER_OD); gpio_pupdr(GPIOB, I2C2_SDA, GPIO_PUPDR_NONE); gpio_ospeedr(GPIOB, I2C2_SDA, GPIO_OSPEEDR_50M); /* Configure peripheral */ *I2C_CR2(2) |= I2C_CR2_FREQ(42); /* Set I2C to 300kHz */ *I2C_CCR(2) |= I2C_CCR_CCR(140); *I2C_TRISE(2) = 43; /* Enable */ *I2C_CR1(2) |= I2C_CR1_PE; /* Pre-initialized */ //init_semaphore(&i2c2_semaphore); i2c2.ready = 1; }
void init_i2c(const i2c_config *ip) { // Enable periph clock. // Configure GPIO. // Reset I²C. uint32_t base = ip->i_base_address; enum rcc_periph_clken clken; switch (base) { case I2C1: clken = RCC_I2C1; break; case I2C2: clken = RCC_I2C2; break; default: assert(false && "unknown I2C base address"); } rcc_periph_clock_enable(clken); gpio_init_pins(ip->i_pins, (&ip->i_pins)[1] - ip->i_pins); uint32_t i2c_freq_mhz = rcc_apb1_frequency / 1000000; uint32_t ccr = rcc_apb1_frequency / I2C_BAUD / 2 + 1; if (ccr < 4) ccr = 4; i2c_peripheral_disable(base); i2c_set_clock_frequency(base, i2c_freq_mhz); i2c_set_trise(base, i2c_freq_mhz + 1); i2c_set_ccr(base, ccr); I2C_CR1(base) = 0; I2C_OAR1(base) = ip->i_own_address; i2c_peripheral_enable(base); }
/** @brief I2C NACK Next Byte Causes the I2C controller to NACK the reception of the current byte @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. */ void i2c_nack_current(uint32_t i2c) { I2C_CR1(i2c) &= ~I2C_CR1_POS; }
void i2c_enable_analog_filter(uint32_t i2c) { I2C_CR1(i2c) &= ~I2C_CR1_ANFOFF; }
/** @brief I2C NACK Next Byte Causes the I2C controller to NACK the reception of the next byte @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. */ void i2c_nack_next(uint32_t i2c) { I2C_CR1(i2c) |= I2C_CR1_POS; }
void i2c_peripheral_disable(uint32_t i2c) { I2C_CR1(i2c) &= ~I2C_CR1_PE; }
/** @brief I2C Disable transmission DMA * * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. */ void i2c_disable_txdma(uint32_t i2c) { I2C_CR1(i2c) &= ~I2C_CR1_TXDMAEN; }
/** @brief I2C Disable Interrupt * * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. * @param[in] interrupt Unsigned int32. Interrupt to disable. */ void i2c_disable_interrupt(uint32_t i2c, uint32_t interrupt) { I2C_CR1(i2c) &= ~interrupt; }
void i2c_disable_stretching(uint32_t i2c) { I2C_CR1(i2c) |= I2C_CR1_NOSTRETCH; }
void i2c_set_digital_filter(uint32_t i2c, uint8_t dnf_setting) { I2C_CR1(i2c) = (I2C_CR1(i2c) & ~I2C_CR1_DNF_MASK) | dnf_setting; }
void i2c_disable_analog_filter(uint32_t i2c) { I2C_CR1(i2c) |= I2C_CR1_ANFOFF; }
void i2c_send_start(u32 i2c) { I2C_CR1(i2c) |= I2C_CR1_START; }
void i2c_enable_stretching(uint32_t i2c) { I2C_CR1(i2c) &= ~I2C_CR1_NOSTRETCH; }
void i2c_send_start(uint32_t i2c) { I2C_CR1(i2c) |= I2C_CR1_START; }
/** @brief I2C Enable Interrupt * * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. * @param[in] interrupt Unsigned int32. Interrupt to enable. */ void i2c_enable_interrupt(uint32_t i2c, uint32_t interrupt) { I2C_CR1(i2c) |= interrupt; }
void i2c_send_stop(uint32_t i2c) { I2C_CR1(i2c) |= I2C_CR1_STOP; }
/** @brief I2C Enable transmission DMA * * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. */ void i2c_enable_txdma(uint32_t i2c) { I2C_CR1(i2c) |= I2C_CR1_TXDMAEN; }
/** @brief I2C Clear Stop Flag. Clear the "Send Stop" flag in the I2C config register @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. */ void i2c_clear_stop(uint32_t i2c) { I2C_CR1(i2c) &= ~I2C_CR1_STOP; }
void i2c_peripheral_enable(uint32_t i2c) { I2C_CR1(i2c) |= I2C_CR1_PE; }
/** @brief I2C Enable ACK Enables acking of own 7/10 bit address @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. */ void i2c_enable_ack(uint32_t i2c) { I2C_CR1(i2c) |= I2C_CR1_ACK; }
uint16_t stts75_read_temperature(uint32_t i2c, uint8_t sensor) { uint32_t reg32 __attribute__((unused)); uint16_t temperature; /* Send START condition. */ i2c_send_start(i2c); /* Waiting for START is send and switched to master mode. */ while (!((I2C_SR1(i2c) & I2C_SR1_SB) & (I2C_SR2(i2c) & (I2C_SR2_MSL | I2C_SR2_BUSY)))); /* Say to what address we want to talk to. */ /* Yes, WRITE is correct - for selecting register in STTS75. */ i2c_send_7bit_address(i2c, sensor, I2C_WRITE); /* Waiting for address is transferred. */ while (!(I2C_SR1(i2c) & I2C_SR1_ADDR)); /* Cleaning ADDR condition sequence. */ reg32 = I2C_SR2(i2c); i2c_send_data(i2c, 0x0); /* temperature register */ while (!(I2C_SR1(i2c) & (I2C_SR1_BTF | I2C_SR1_TxE))); /* * Now we transferred that we want to ACCESS the temperature register. * Now we send another START condition (repeated START) and then * transfer the destination but with flag READ. */ /* Send START condition. */ i2c_send_start(i2c); /* Waiting for START is send and switched to master mode. */ while (!((I2C_SR1(i2c) & I2C_SR1_SB) & (I2C_SR2(i2c) & (I2C_SR2_MSL | I2C_SR2_BUSY)))); /* Say to what address we want to talk to. */ i2c_send_7bit_address(i2c, sensor, I2C_READ); /* 2-byte receive is a special case. See datasheet POS bit. */ I2C_CR1(i2c) |= (I2C_CR1_POS | I2C_CR1_ACK); /* Waiting for address is transferred. */ while (!(I2C_SR1(i2c) & I2C_SR1_ADDR)); /* Cleaning ADDR condition sequence. */ reg32 = I2C_SR2(i2c); /* Cleaning I2C_SR1_ACK. */ I2C_CR1(i2c) &= ~I2C_CR1_ACK; /* Now the slave should begin to send us the first byte. Await BTF. */ while (!(I2C_SR1(i2c) & I2C_SR1_BTF)); temperature = (uint16_t)(I2C_DR(i2c) << 8); /* MSB */ /* * Yes they mean it: we have to generate the STOP condition before * saving the 1st byte. */ I2C_CR1(i2c) |= I2C_CR1_STOP; temperature |= I2C_DR(i2c); /* LSB */ /* Original state. */ I2C_CR1(i2c) &= ~I2C_CR1_POS; return temperature; }
/** @brief I2C Disable ACK Disables acking of own 7/10 bit address @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base. */ void i2c_disable_ack(uint32_t i2c) { I2C_CR1(i2c) &= ~I2C_CR1_ACK; }