Search code examples
cstm32microcontrolleri2ceeprom

How to write serial data ino I2C EEPROM?


I'm really new about microcontroller and I want to ask if I want to read the values of three different sensors and store those values in succession in an I2C EEPROM, each value occupies 6 bytes in the address, how can I do that using the I2C bus? Especially I'm not sure about specifying high bytes and low bytes for each value. I found a sample code writing a value into EEPROM:

void eeprom_write(uint16_t data){ //Writes to the EEPROM
 LL_I2C_GenerateStartCondition(I2C1); //START
        while(!LL_I2C_IsActiveFlag_SB(I2C1));

        LL_I2C_TransmitData8(I2C1, EEPROMADR); //CONTROL BYTE (ADDRESS + WRITE)
        while(!LL_I2C_IsActiveFlag_ADDR(I2C1));
        LL_I2C_ClearFlag_ADDR(I2C1);

        LL_I2C_TransmitData8(I2C1, 0x00); //ADDRESS HIGH BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));

        LL_I2C_TransmitData8(I2C1, 0x00); //ADDRESS LOW BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));

        LL_I2C_TransmitData8(I2C1, (char)(data >> 8)); //DATA HIGH BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));

 LL_I2C_TransmitData8(I2C1, (char)(data & 0x00FF)); //DATA LOW BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));

        LL_I2C_GenerateStopCondition(I2C1); //STOP
  }

but I don't know how to write the remaining two in series with that. Can someone help me, please? Also, I programmed on Keil software and used the C language. Thank you!


Solution

  • The EEPROM device has a range of internal addresses where data can be stored. Your eeprom_write function uses the hardcoded address of 0x0000 such that every call to it will overwrite the previous data at address 0x0000. You should change the function prototype to pass in the address so you can write data throughout the EEPROM.

    void eeprom_write_word_at_addr(uint16_t data, uint16_t addr){ //Writes to the EEPROM
        LL_I2C_GenerateStartCondition(I2C1); //START
        while(!LL_I2C_IsActiveFlag_SB(I2C1));
    
        LL_I2C_TransmitData8(I2C1, EEPROMADR); //CONTROL BYTE (ADDRESS + WRITE)
        while(!LL_I2C_IsActiveFlag_ADDR(I2C1));
        LL_I2C_ClearFlag_ADDR(I2C1);
    
        LL_I2C_TransmitData8(I2C1, (char)(addr >> 8)); //ADDRESS HIGH BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));
    
        LL_I2C_TransmitData8(I2C1, (char)(addr & 0x00FF)); //ADDRESS LOW BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));
    
        LL_I2C_TransmitData8(I2C1, (char)(data >> 8)); //DATA HIGH BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));
    
        LL_I2C_TransmitData8(I2C1, (char)(data & 0x00FF)); //DATA LOW BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));
    
        LL_I2C_GenerateStopCondition(I2C1); //STOP
    }
    

    Also your function writes a 2-byte data value but I think you want to write three 2-byte values. So you could call the above function three times and update the address each call. Or you could write another function that accepts all three values and writes them all in one I2C transfer. The EEPROM's internal address auto-increments for each write so you only need to specify the beginning address. (Read the EEPROM's datasheet to confirm about auto-increment and see if there is any paging restrictions.)

    void eeprom_write_3words_at_addr(uint16_t data1, uint16_t data2, uint16_t data3, uint16_t addr){ //Writes to the EEPROM
        LL_I2C_GenerateStartCondition(I2C1); //START
        while(!LL_I2C_IsActiveFlag_SB(I2C1));
    
        LL_I2C_TransmitData8(I2C1, EEPROMADR); //CONTROL BYTE (ADDRESS + WRITE)
        while(!LL_I2C_IsActiveFlag_ADDR(I2C1));
        LL_I2C_ClearFlag_ADDR(I2C1);
    
        LL_I2C_TransmitData8(I2C1, (char)(addr >> 8)); //ADDRESS HIGH BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));
    
        LL_I2C_TransmitData8(I2C1, (char)(addr & 0x00FF)); //ADDRESS LOW BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));
    
        LL_I2C_TransmitData8(I2C1, (char)(data1 >> 8)); //DATA HIGH BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));
    
        LL_I2C_TransmitData8(I2C1, (char)(data1 & 0x00FF)); //DATA LOW BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));
    
        LL_I2C_TransmitData8(I2C1, (char)(data2 >> 8)); //DATA HIGH BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));
    
        LL_I2C_TransmitData8(I2C1, (char)(data2 & 0x00FF)); //DATA LOW BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));
    
        LL_I2C_TransmitData8(I2C1, (char)(data3 >> 8)); //DATA HIGH BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));
    
        LL_I2C_TransmitData8(I2C1, (char)(data3 & 0x00FF)); //DATA LOW BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));
    
        LL_I2C_GenerateStopCondition(I2C1); //STOP
    }
    

    Or if I'm wrong about three 2-byte data values then you could pass an array containing all the data to the function like this.

    void eeprom_write_words_at_addr(uint16_t *data, int num_words, uint16_t addr){ //Writes to the EEPROM
        LL_I2C_GenerateStartCondition(I2C1); //START
        while(!LL_I2C_IsActiveFlag_SB(I2C1));
    
        LL_I2C_TransmitData8(I2C1, EEPROMADR); //CONTROL BYTE (ADDRESS + WRITE)
        while(!LL_I2C_IsActiveFlag_ADDR(I2C1));
        LL_I2C_ClearFlag_ADDR(I2C1);
    
        LL_I2C_TransmitData8(I2C1, (char)(addr >> 8)); //ADDRESS HIGH BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));
    
        LL_I2C_TransmitData8(I2C1, (char)(addr & 0x00FF)); //ADDRESS LOW BYTE
        while(!LL_I2C_IsActiveFlag_TXE(I2C1));
    
        for (int index = 0; index < num_words; ++index) {        
            LL_I2C_TransmitData8(I2C1, (char)(data[index] >> 8)); //DATA HIGH BYTE
            while(!LL_I2C_IsActiveFlag_TXE(I2C1));
    
            LL_I2C_TransmitData8(I2C1, (char)(data[index] & 0x00FF)); //DATA LOW BYTE
            while(!LL_I2C_IsActiveFlag_TXE(I2C1));
        }
    
        LL_I2C_GenerateStopCondition(I2C1); //STOP
    }
    

    The high-byte/low-byte order (i.e., endianness) of the data is probably not important as long as the eeprom_read function uses the same order. However, the byte order of the address is important because the I2C EEPROM device expects the high-byte of the address first. See the EEPROM device's datasheet for confirmation.