/* Function to write a byte at a specific address */ bool eeprom_write_byte(uint16_t address, uint8_t data) { bool success = true; /* send START and wait for completion */ i2c_send_start(I2C1); while ((I2C_SR1(I2C1) & I2C_SR1_SB) == 0); /* send device address, r/w request and wait for completion */ i2c_send_7bit_address(I2C1, ADDRESS_BYTE, I2C_WRITE); while ((I2C_SR1(I2C1) & I2C_SR1_ADDR) == 0); /* check SR2 and go on if OK */ if ((I2C_SR2(I2C1) & I2C_SR2_MSL) /* master mode */ && (I2C_SR2(I2C1) & I2C_SR2_BUSY)) { /* communication ongoing */ /* send memory address MSB */ i2c_send_data(I2C1, ((uint8_t)(address >> 8))); while ((I2C_SR1(I2C1) & I2C_SR1_TxE) == 0); /* send memory address LSB */ i2c_send_data(I2C1, ((uint8_t)address)); while ((I2C_SR1(I2C1) & I2C_SR1_TxE) == 0); /* send data byte */ i2c_send_data(I2C1, data); while ((I2C_SR1(I2C1) & I2C_SR1_TxE) == 0); /* send stop */ i2c_send_stop(I2C1); /* ATTENTION: consider to wait for a while */ } else {
int tda18219_write_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_TxE)); i2c_send_data(I2C1, value); while (!(I2C_SR1(I2C1) & (I2C_SR1_BTF | I2C_SR1_TxE))); i2c_send_stop(I2C1); return 0; }
void stts75_write_config(uint32_t i2c, uint8_t sensor) { uint32_t reg32 __attribute__((unused)); /* 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)))); /* Send destination address. */ 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); /* Sending the data. */ i2c_send_data(i2c, 0x1); /* stts75 config register */ while (!(I2C_SR1(i2c) & I2C_SR1_BTF)); /* Await ByteTransferedFlag. */ /* Polarity reverse - LED glows if temp is below Tos/Thyst. */ i2c_send_data(i2c, 0x4); while (!(I2C_SR1(i2c) & (I2C_SR1_BTF | I2C_SR1_TxE))); /* Send STOP condition. */ i2c_send_stop(i2c); }
void stts75_write_temp_hyst(uint32_t i2c, uint8_t sensor, uint16_t temp_hyst) { uint32_t reg32 __attribute__((unused)); /* Send START condition. */ i2c_send_start(i2c); /* Waiting for START is send and therefore 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_WRITE); /* Waiting for address is transferred. */ while (!(I2C_SR1(i2c) & I2C_SR1_ADDR)); /* Cleaning ADDR condition sequence. */ reg32 = I2C_SR2(i2c); /* Sending the data. */ i2c_send_data(i2c, 0x2); /* TemperatureHysteresis register */ while (!(I2C_SR1(i2c) & I2C_SR1_BTF)); i2c_send_data(i2c, (uint8_t)(temp_hyst >> 8)); /* MSB */ while (!(I2C_SR1(i2c) & I2C_SR1_BTF)); i2c_send_data(i2c, (uint8_t)(temp_hyst & 0xff00)); /* LSB */ /* After the last byte we have to wait for TxE too. */ while (!(I2C_SR1(i2c) & (I2C_SR1_BTF | I2C_SR1_TxE))); /* Send STOP condition. */ i2c_send_stop(i2c); }
void stts75_write_temp_os(uint32_t i2c, uint8_t sensor, uint16_t temp_os) { uint32_t reg32 __attribute__((unused)); /* 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)))); /* Send destination address. */ 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); /* Sending the data. */ i2c_send_data(i2c, 0x3); /* OvertemperatureShutdown register */ while (!(I2C_SR1(i2c) & I2C_SR1_BTF)); i2c_send_data(i2c, (uint8_t)(temp_os >> 8)); /* MSB */ while (!(I2C_SR1(i2c) & I2C_SR1_BTF)); i2c_send_data(i2c, (uint8_t)(temp_os & 0xff00)); /* LSB */ /* After the last byte we have to wait for TxE too. */ while (!(I2C_SR1(i2c) & (I2C_SR1_BTF | I2C_SR1_TxE))); /* Send STOP condition. */ i2c_send_stop(i2c); }
static int i2c_write(uint8_t reg, uint8_t val) { while ((I2C_SR2(I2C_PORT) & I2C_SR2_BUSY)) { } gpio_set(GPIOG, GPIO13); i2c_send_start(I2C_PORT); /* Wait for master mode selected */ while (!((I2C_SR1(I2C_PORT) & I2C_SR1_SB) & (I2C_SR2(I2C_PORT) & (I2C_SR2_MSL | I2C_SR2_BUSY)))); gpio_set(GPIOG, GPIO14); i2c_send_7bit_address(I2C_PORT, SLAVE_ADDRESS, I2C_WRITE); /* Waiting for address is transferred. */ while (!(I2C_SR1(I2C_PORT) & I2C_SR1_ADDR)); /* Cleaning ADDR condition sequence. */ uint32_t reg32 = I2C_SR2(I2C_PORT); (void) reg32; /* unused */ /* Common above here */ /* Sending the data. */ i2c_send_data(I2C_PORT, reg); while (!(I2C_SR1(I2C_PORT) & (I2C_SR1_BTF))); i2c_send_data(I2C_PORT, val); while (!(I2C_SR1(I2C_PORT) & (I2C_SR1_BTF | I2C_SR1_TxE))); /* Send STOP condition. */ i2c_send_stop(I2C_PORT); return 0; }
static inline void stmi2c_clear_pending_interrupts(uint32_t i2c) { uint16_t SR1 = I2C_SR1(i2c); // Certainly do not wait for buffer interrupts: // ------------------------------------------- i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN); // Disable TXE, RXNE // Error interrupts are handled separately: // --------------------------------------- // Clear Event interrupt conditions: // -------------------------------- // Start Condition Was Generated if (BIT_X_IS_SET_IN_REG( I2C_SR1_SB, SR1 ) ) { // SB: cleared by software when reading SR1 and writing to DR i2c_send_data(i2c, 0x00); } // Address Was Sent if (BIT_X_IS_SET_IN_REG(I2C_SR1_ADDR, SR1) ) { // ADDR: Cleared by software when reading SR1 and then SR2 uint16_t SR2 __attribute__ ((unused)) = I2C_SR2(i2c); } // Byte Transfer Finished if (BIT_X_IS_SET_IN_REG(I2C_SR1_BTF, SR1) ) { // SB: cleared by software when reading SR1 and reading/writing to DR uint8_t dummy __attribute__ ((unused)) = i2c_get_data(i2c); i2c_send_data(i2c, 0x00); } }
static uint8_t i2c_write(uint32_t i2c, uint8_t address, uint8_t reg, uint8_t data) { i2c_start(i2c, address, I2C_WRITE); i2c_send_data(i2c, reg); while (!(I2C_SR1(i2c) & (I2C_SR1_BTF))); i2c_send_data(i2c, data); while (!(I2C_SR1(i2c) & (I2C_SR1_BTF))); i2c_send_stop(i2c); return 0; }
// 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; }
static void com_send_start() { /* send start */ i2c_send_start(I2C1); while (!((I2C_SR1(I2C1) & I2C_SR1_SB) & (I2C_SR2(I2C1) & (I2C_SR2_MSL | I2C_SR2_BUSY)))) ; /* send address */ i2c_send_7bit_address(I2C1, current_address, I2C_WRITE); while (!(I2C_SR1(I2C1) & I2C_SR1_ADDR)) ; (void)I2C_SR2(I2C1); selected = true; }
static uint8_t i2c_start(uint32_t i2c, uint8_t address, uint8_t mode) { i2c_send_start(i2c); /* Wait for master mode selected */ while (!((I2C_SR1(i2c) & I2C_SR1_SB) & (I2C_SR2(i2c) & (I2C_SR2_MSL | I2C_SR2_BUSY)))); i2c_send_7bit_address(i2c, address, mode); /* Waiting for address is transferred. */ while (!(I2C_SR1(i2c) & I2C_SR1_ADDR)); /* Cleaning ADDR condition sequence. */ uint32_t reg32 = I2C_SR2(i2c); (void) reg32; /* unused */ return 0; }
static uint32_t i2c_read(uint32_t i2c, uint8_t address, uint8_t reg) { while ((I2C_SR2(i2c) & I2C_SR2_BUSY)); i2c_start(i2c, address, I2C_WRITE); i2c_send_data(i2c, reg); while (!(I2C_SR1(i2c) & (I2C_SR1_BTF))); i2c_start(i2c, address, I2C_READ); i2c_send_stop(i2c); while (!(I2C_SR1(i2c) & I2C_SR1_RxNE)); uint32_t result = i2c_get_data(i2c); I2C_SR1(i2c) &= ~I2C_SR1_AF; return result; }
static void com_send_data(uint8_t c) { // if (!selected) com_send_start(); i2c_send_data(I2C1, c); while (!(I2C_SR1(I2C1) & I2C_SR1_BTF)) ; com_send_stop(); }
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"); } }
static uint32_t i2c_read(uint8_t reg) { // while ((I2C_SR2(i2c) & I2C_SR2_BUSY)) { // } i2c_send_start(I2C_PORT); /* Wait for master mode selected */ while (!((I2C_SR1(I2C_PORT) & I2C_SR1_SB) & (I2C_SR2(I2C_PORT) & (I2C_SR2_MSL | I2C_SR2_BUSY)))); i2c_send_7bit_address(I2C_PORT, SLAVE_ADDRESS, I2C_WRITE); /* Waiting for address is transferred. */ while (!(I2C_SR1(I2C_PORT) & I2C_SR1_ADDR)); /* Cleaning ADDR condition sequence. */ uint32_t reg32 = I2C_SR2(I2C_PORT); (void) reg32; /* unused */ /* Common stuff ABOVE HERE */ i2c_send_data(I2C_PORT, reg); while (!(I2C_SR1(I2C_PORT) & (I2C_SR1_BTF))); i2c_send_start(I2C_PORT); /* Wait for master mode selected */ while (!((I2C_SR1(I2C_PORT) & I2C_SR1_SB) & (I2C_SR2(I2C_PORT) & (I2C_SR2_MSL | I2C_SR2_BUSY)))); i2c_send_7bit_address(I2C_PORT, SLAVE_ADDRESS, I2C_READ); /* Waiting for address is transferred. */ while (!(I2C_SR1(I2C_PORT) & I2C_SR1_ADDR)); i2c_disable_ack(I2C_PORT); /* Cleaning ADDR condition sequence. */ reg32 = I2C_SR2(I2C_PORT); (void) reg32; /* unused */ i2c_send_stop(I2C_PORT); while (!(I2C_SR1(I2C_PORT) & I2C_SR1_RxNE)); uint32_t result = i2c_get_data(I2C_PORT); i2c_enable_ack(I2C_PORT); I2C_SR1(I2C_PORT) &= ~I2C_SR1_AF; return result; }
// 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; }
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; }
static inline void i2c_irq(struct i2c_periph *periph) { /* There are 7 possible event reasons to get here + all errors If IT_EV_FEN ------------------------- We are always interested in all IT_EV_FEV: all are required. 1) SB // Start Condition Success in Master mode 2) ADDR // Address sent received Acknoledge [ADDR10] // -- 10bit address stuff: not used [STOPF] // -- only for slaves: master has no stop interrupt: not used 3) BTF // I2C has stopped working (it is waiting for new data, all buffers are tx_empty/rx_full) // Beware: using the buffered I2C has some interesting properties: - in master receive mode: BTF only occurs after the 2nd received byte: after the first byte is received it is in RD but the I2C can still receive a second byte. Only when the 2nd byte is received while the RxNE is 1 then a BTF occurs (I2C can not continue receiving bytes or they will get lost). During BTF I2C is halted (SCL held low) - in master transmit mode: when writing a byte to WD, you instantly get a new TxE interrupt while the first is not transmitted yet. The byte was pushed to the I2C shift register and the buffer is ready for more. You can already fill new data in the buffer while the first is still being transmitted for max performance transmission. // Beware: besides data buffering you can/must plan several consecutive actions. You can send 2 bytes to the buffer, ask for a stop and a new start in one go. - thanks to / because of this buffering and event sheduling there is not 1 interrupt per start / byte / stop This also means you must think more in advance and a transaction could be popped from the transaction stack even before it's stop condition is actually generated. // Beware: the order in which Status (and other register) is read determines how flags are cleared. You should NOT simply read SR1 & SR2 every time If IT_EV_FEN AND IT_EV_BUF -------------------------- Buffer event are not always wanted and are typically switched on during longer data transfers. Make sure to turn off in time. 4) RxNE 5) TxE -------------------------------------------------------------------------------------------------- The STM waits indefinately (holding SCL low) for user interaction: a) after a master-start (waiting for address) b) after an address (waiting for data) not during data sending when using buffered c) after the last byte is transmitted (waiting for either stop or restart) not during data receiving when using buffered not after the last byte is received - The STM I2C stalls indefinately when a stop condition was attempted that did not succeed. The BUSY flag remains on. - There is no STOP interrupt. Caution Reading the status: - Caution: this clears several flags and can start transmissions etc... - Certain flags like STOP / (N)ACK need to be guaranteed to be set before the transmission of the byte is finished. At higher clock rates that can be quite fast: so we allow no other interrupt to be triggered in between reading the status and setting all needed flags */ // Here we go ... // Apparently we got an I2C interrupt: EVT BUF or ERR #ifdef I2C_DEBUG_LED // Notify ISR is triggered LED1_ON(); LED1_OFF(); #endif // Save Some Direct Access to the I2C Registers ... uint32_t i2c = (uint32_t) periph->reg_addr; ///////////////////////////// // Check if we were ready ... if (periph->trans_extract_idx == periph->trans_insert_idx) { // Nothing Left To Do #ifdef I2C_DEBUG_LED LED2_ON(); LED1_ON(); LED2_OFF(); LED1_OFF(); // no transaction and also an error? LED_SHOW_ACTIVE_BITS(regs); #endif // If we still get an interrupt but there are no more things to do // (which can happen if an event was sheduled just before a bus error occurs) // (or can happen if both error and event interrupts were called together [the 2nd will then get this error]) // since there is nothing more to do: its easy: just stop: clear all interrupt generating bits // Count The Errors i2c_error(periph); // Clear Running Events stmi2c_clear_pending_interrupts(i2c); // Mark this as a special error periph->errors->last_unexpected_event++; // Document the current Status periph->status = I2CIdle; // There are no transactions anymore: return // further-on in this routine we need a transaction pointer: so we are not allowed to continue return; } // get the I2C transaction we were working on ... enum STMI2CSubTransactionStatus ret = 0; struct i2c_transaction* trans = periph->trans[periph->trans_extract_idx]; /////////////////////////// // If there was an error: if (( I2C_SR1(i2c) & I2C_SR1_ERR_MASK ) != 0x0000) { #ifdef I2C_DEBUG_LED LED1_ON(); LED2_ON(); LED1_OFF(); LED2_OFF(); LED_SHOW_ACTIVE_BITS(regs); #endif // Notify everyone about the error ... // Set result in transaction trans->status = I2CTransFailed; // Document the current Status periph->status = I2CFailed; // Make sure a TxRx does not Restart trans->type = I2CTransRx; // Count The Errors i2c_error(periph); // Clear Running Events stmi2c_clear_pending_interrupts(i2c); // Now continue as if everything was normal from now on ret = STMI2C_SubTra_Ready; } /////////////////////////// // Normal Event: else { /////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////// // // SUB-TRANSACTION HANDLER if (trans->type == I2CTransRx) // TxRx are converted to Rx after the Tx Part { switch (trans->len_r) { case 1: ret = stmi2c_read1(i2c,periph,trans); break; case 2: ret = stmi2c_read2(i2c,periph,trans); break; default: ret = stmi2c_readmany(i2c,periph,trans); break; } } else // TxRx or Tx { ret = stmi2c_send(i2c,periph,trans); } } ///////////////////////////////// // Sub-transaction has finished if (ret != STMI2C_SubTra_Busy) { // Ready or SubTraError // -ready: with or without stop already asked // In case of unexpected event condition during subtransaction handling: if (ret == STMI2C_SubTra_Error) { // Tell everyone about the subtransaction error: // this is the previously called SPURRIOUS INTERRUPT periph->status = I2CFailed; trans->type = I2CTransRx; // Avoid possible restart trans->status = I2CTransFailed; // Notify Ready periph->errors->unexpected_event_cnt++; // Error #ifdef I2C_DEBUG_LED LED2_ON(); LED1_ON(); LED2_OFF(); LED1_OFF(); LED_SHOW_ACTIVE_BITS(regs); #endif // Clear Running Events stmi2c_clear_pending_interrupts(i2c); } // RxTx -> Restart and do Rx part if (trans->type == I2CTransTxRx) { trans->type = I2CTransRx; periph->status = I2CStartRequested; i2c_send_start(i2c); // Silent any BTF that would occur before SB i2c_send_data(i2c, 0x00); } // If a restart is not needed: Rx part or Tx-only else { // Ready, no stop condition set yet if (ret == STMI2C_SubTra_Ready) { // Program a stop PPRZ_I2C_SEND_STOP(i2c); // Silent any BTF that would occur before STOP is executed i2c_send_data(i2c, 0x00); } // Jump to the next transaction periph->trans_extract_idx++; if (periph->trans_extract_idx >= I2C_TRANSACTION_QUEUE_LEN) periph->trans_extract_idx = 0; // Tell everyone we are ready periph->status = I2CIdle; // if we have no more transaction to process, stop here if (periph->trans_extract_idx == periph->trans_insert_idx) { periph->watchdog = -1; // stop watchdog #ifdef I2C_DEBUG_LED LED2_ON(); LED1_ON(); LED1_OFF(); LED1_ON(); LED1_OFF(); LED2_OFF(); #endif } // if not, start next transaction else { // Restart transaction doing the Rx part now // --- moved to idle function PPRZ_I2C_SEND_START(periph); // ------ } } } return; }
int8_t i2c_write(struct i2c_dev *i2c, uint8_t addr, uint8_t *data, uint32_t num) { if (!i2c || !i2c->ready || i2c->port < 1 || i2c->port > 3 || !data || !num) { return -1; } /* Check for bus error */ if (*I2C_SR1(i2c->port) & I2C_SR1_BERR) { printk("I2C: Bus error, reseting.\r\n"); /* Clear the error and reset I2C */ *I2C_SR1(i2c->port) &= ~(I2C_SR1_BERR); if (i2c_reset(i2c)) { /* Failed to reset */ return -1; } } /* Wait until BUSY is reset and previous transaction STOP is complete */ int count = 10000; while ((*I2C_SR2(i2c->port) & I2C_SR2_BUSY) || (*I2C_CR1(i2c->port) & I2C_CR1_STOP)) { if (--count == 0) { printk("I2C: Stalled, reseting.\r\n"); if (i2c_reset(i2c)) { /* Failed to reset */ return -1; } } else if (count < 0) { printk("I2C: Stalled, reset failed, force clearing busy.\r\n"); if (i2c_force_clear_busy(i2c)) { /* Failed to clear */ return -1; } } } *I2C_CR1(i2c->port) |= I2C_CR1_START; count = 10000; while (!(*I2C_SR1(i2c->port) & I2C_SR1_SB)) { if (!count--) { i2c_stop(i2c->port); return -1; } } *I2C_DR(i2c->port) = addr << 1; count = 10000; while (!(*I2C_SR1(i2c->port) & I2C_SR1_ADDR)) { if ((*I2C_SR1(i2c->port) & I2C_SR1_AF) || !count--) { i2c_stop(i2c->port); return -1; } } count = 10000; while (!(*I2C_SR2(i2c->port) & I2C_SR2_MSL)) { if (!count--) { i2c_stop(i2c->port); return -1; } } int total = 0; while (num--) { /* Make sure shift register is empty */ count = 10000; while (!(*I2C_SR1(i2c->port) & I2C_SR1_TXE)) { if (!count--) { i2c_stop(i2c->port); return -1; } } *I2C_DR(i2c->port) = *data++; count = 10000; while (!(*I2C_SR1(i2c->port) & I2C_SR1_TXE)) { if (!count--) { i2c_stop(i2c->port); return -1; } } total += 1; } i2c_stop(i2c->port); return total; }
static inline void i2c_error(struct i2c_periph *periph) { #ifdef I2C_DEBUG_LED uint8_t err_nr = 0; #endif periph->errors->er_irq_cnt; if ((I2C_SR1((uint32_t)periph->reg_addr) & I2C_SR1_AF) != 0) { /* Acknowledge failure */ periph->errors->ack_fail_cnt++; I2C_SR1((uint32_t)periph->reg_addr) &= ~I2C_SR1_AF; #ifdef I2C_DEBUG_LED err_nr = 1; #endif } if ((I2C_SR1((uint32_t)periph->reg_addr) & I2C_SR1_BERR) != 0) { /* Misplaced Start or Stop condition */ periph->errors->miss_start_stop_cnt++; I2C_SR1((uint32_t)periph->reg_addr) &= ~I2C_SR1_BERR; #ifdef I2C_DEBUG_LED err_nr = 2; #endif } if ((I2C_SR1((uint32_t)periph->reg_addr) & I2C_SR1_ARLO) != 0) { /* Arbitration lost */ periph->errors->arb_lost_cnt++; I2C_SR1((uint32_t)periph->reg_addr) &= ~I2C_SR1_ARLO; #ifdef I2C_DEBUG_LED err_nr = 3; #endif } if ((I2C_SR1((uint32_t)periph->reg_addr) & I2C_SR1_OVR) != 0) { /* Overrun/Underrun */ periph->errors->over_under_cnt++; I2C_SR1((uint32_t)periph->reg_addr) &= ~I2C_SR1_OVR; #ifdef I2C_DEBUG_LED err_nr = 4; #endif } if ((I2C_SR1((uint32_t)periph->reg_addr) & I2C_SR1_PECERR) != 0) { /* PEC Error in reception */ periph->errors->pec_recep_cnt++; I2C_SR1((uint32_t)periph->reg_addr) &= ~I2C_SR1_PECERR; #ifdef I2C_DEBUG_LED err_nr = 5; #endif } if ((I2C_SR1((uint32_t)periph->reg_addr) & I2C_SR1_TIMEOUT) != 0) { /* Timeout or Tlow error */ periph->errors->timeout_tlow_cnt++; I2C_SR1((uint32_t)periph->reg_addr) &= ~I2C_SR1_TIMEOUT; #ifdef I2C_DEBUG_LED err_nr = 6; #endif } if ((I2C_SR1((uint32_t)periph->reg_addr) & I2C_SR1_SMBALERT) != 0) { /* SMBus alert */ periph->errors->smbus_alert_cnt++; I2C_SR1((uint32_t)periph->reg_addr) &= ~I2C_SR1_SMBALERT; #ifdef I2C_DEBUG_LED err_nr = 7; #endif } #ifdef I2C_DEBUG_LED LED_ERROR(20, err_nr); #endif return; }
int i2c_read(struct i2c_dev *i2c, uint8_t addr, uint8_t *data, uint32_t num) { if (!i2c || !i2c->ready || i2c->port < 1 || i2c->port > 3 || !data || !num) { return -1; } /* Check for bus error */ if (*I2C_SR1(i2c->port) & I2C_SR1_BERR) { printk("I2C: Bus error, reseting.\r\n"); /* Clear the error and reset I2C */ *I2C_SR1(i2c->port) &= ~(I2C_SR1_BERR); if (i2c_reset(i2c)) { /* Failed to reset */ return -1; } } /* Wait until BUSY is reset and previous transaction STOP is complete */ int count = 10000; while ((*I2C_SR2(i2c->port) & I2C_SR2_BUSY) || (*I2C_CR1(i2c->port) & I2C_CR1_STOP)) { if (--count == 0) { printk("I2C: Stalled, reseting.\r\n"); if (i2c_reset(i2c)) { /* Failed to reset */ return -1; } } else if (count < 0) { printk("I2C: Stalled, reset failed, force clearing busy.\r\n"); if (i2c_force_clear_busy(i2c)) { /* Failed to clear */ return -1; } } } int total = 0; *I2C_CR1(i2c->port) |= I2C_CR1_START; count = 10000; while (!(*I2C_SR1(i2c->port) & I2C_SR1_SB)) { if (!count--) { i2c_stop(i2c->port); return -1; } } *I2C_DR(i2c->port) = (addr << 1) | 1; count = 10000; while (!(*I2C_SR1(i2c->port) & I2C_SR1_ADDR)) { if (*I2C_SR1(i2c->port) & I2C_SR1_AF || !count--) { i2c_stop(i2c->port); return -1; } } uint8_t single_byte = num == 1; if (!single_byte) { *I2C_CR1(i2c->port) |= I2C_CR1_ACK; } else { /* In single byte receive, never ACK */ *I2C_CR1(i2c->port) &= ~(I2C_CR1_ACK); } while (num--) { count = 10000; while (!(*I2C_SR2(i2c->port) & I2C_SR2_MSL)) { if (!count--) { i2c_stop(i2c->port); return -1; } } /* In single byte receive, stop after ADDR clear (SR1 and SR2 read) */ if (single_byte) { i2c_stop(i2c->port); } count = 10000; while (!(*I2C_SR1(i2c->port) & I2C_SR1_RXNE)) { if (!count--) { i2c_stop(i2c->port); return -1; } } *data++ = *I2C_DR(i2c->port); total++; /* NACK and STOP after second last receive */ if (num == 1) { *I2C_CR1(i2c->port) &= ~(I2C_CR1_ACK); i2c_stop(i2c->port); } } return total; }
// 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; }
// Doc ID 13902 Rev 11 p 713/1072 // Transfer Sequence Diagram for Master Receiver for N=2 static inline enum STMI2CSubTransactionStatus stmi2c_read2(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 ) ) { // according to the datasheet: instantly shedule a NAK on the second received byte: i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN); i2c_enable_ack(i2c); i2c_nack_next(i2c); 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) ) { // --- make absolutely sure this command is not delayed too much after the previous: // --- the NAK bits must be set before the first byte arrived: allow other interrupts here __I2C_REG_CRITICAL_ZONE_START; // if transfer of DR was finished already then we will get too many bytes // BEFORE clearing ACK, read SR2 to clear the ADDR (next byte will start arriving) // clearing ACK after the byte transfer has already started will NACK the next (2nd) uint16_t SR2 __attribute__ ((unused)) = I2C_SR2(i2c); // NOT First Clear the ACK bit but only AFTER clearing ADDR i2c_disable_ack(i2c); // Disable the RXNE and wait for BTF i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN); __I2C_REG_CRITICAL_ZONE_STOP; // --- end of critical zone ----------- // We do not set the RxE but wait for both bytes to arrive using BTF // Document the current Status periph->status = I2CReadingByte; } // Receive buffer if full, master is halted: BTF else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BTF, SR1) ) { // Stop condition MUST be set BEFORE reading the DR // otherwise since there is new buffer space a new byte will be read PPRZ_I2C_SEND_STOP(i2c); // Document the current Status periph->status = I2CStopRequested; trans->buf[0] = I2C_DR(i2c); trans->buf[1] = I2C_DR(i2c); // We got all the results trans->status = I2CTransSuccess; return STMI2C_SubTra_Ready_StopRequested; } else // Event Logic Error { return STMI2C_SubTra_Error; } return STMI2C_SubTra_Busy; }
void i2c_receive(const i2c_channel *cp, uint8_t *data, size_t count) { uint32_t base = cp->i_base_address; if (cp->i_is_master) { I2C_CR1(base) |= I2C_CR1_ACK; // 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"); printf("SR1 = %#lx\n", I2C_SR1(base)); 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; // Read each data byte; wait for BTF. for (size_t i = 0; i < count; i++) { if (i + 1 == count) I2C_CR1(base) &= ~I2C_CR1_ACK; t0 = system_millis; while (true) { uint32_t sr1 = I2C_SR1(base); if (sr1 & (I2C_SR1_OVR | I2C_SR1_BERR)) { fprintf(stderr, "i2c: receive error\n"); break; } if (sr1 & I2C_SR1_RxNE) break; if (system_millis >= t0 + TIMEOUT_MSEC) { fprintf(stderr, "i2c: timeout on receive\n"); } } data[i] = I2C_DR(base); I2C_DR(base) = data[i]; } printf("%lu: I2C receive complete\n", system_millis / 1000); } else { assert(false && "slave reception not implemented"); } }