Garbled Data from I2C EEPROM using i2c_t3 with Teensy LC

Status
Not open for further replies.

vince.cimo

Well-known member
I'm stumped. I have this EEPROM device (https://datasheet.lcsc.com/szlcsc/Shanghai-Belling-BL24C04A-NTRC_C177778.pdf) hooked up to the SCL/SDA pins (18 & 19) on a Teensy LC using 4.7k external pullup resistors and am using the following test code to attempt a basic read/write operation. I can probe both the SCL and SDA pins and see that I'm getting signal on both pins, but my Serial monitor data coming back is super weird.

No errors are thrown, but sometimes the retrieved data is blank, sometimes it's garbled. I've tried numerous configurations and also tried a the basic example on the Wire library page (it hangs at while(Wire.read()) {
num = Wire.receive();
}). Where else should I look? I am at the end of the road with what I know to try.

Here's an example of the serial output from the included program:

Sending to Slave: 'Message #0' OK
Reading from Slave: '' OK
Sending to Slave: 'Message #1' OK
Reading from Slave: '' OK
Sending to Slave: 'Message #2' OK
Reading from Slave: '' OK
Sending to Slave: 'Message #3' OK
Reading from Slave: '' OK
Sending to Slave: 'Message #4' OK
Reading from Slave: '' OK
Sending to Slave: 'Message #5' OK
Reading from Slave: '' OK
Sending to Slave: 'Message #6' OK
Reading from Slave: '' OK
Sending to Slave: 'Message #7' OK
Reading from Slave: '' OK
Sending to Slave: 'Message #8' OK
Reading from Slave: '' OK
Sending to Slave: 'Message #9' OK
Reading from Slave: '' OK
Sending to Slave: 'Message #10' OK
Reading from Slave: 'Messaess���������>' OK
Sending to Slave: 'Message #11' OK
Reading from Slave: 'Messaess���������>' OK
Sending to Slave: 'Message #12' OK
Reading from Slave: 'Messaess���������>' OK
Sending to Slave: 'Message #13' OK
Reading from Slave: 'Messaess���������>' OK
Sending to Slave: 'Message #14' OK
Reading from Slave: 'Messaess���������>' OK
Sending to Slave: 'Message #15' OK
Reading from Slave: 'Messaess���������>' OK
Sending to Slave: 'Message #16' OK
Reading from Slave: 'Messaess���������>' OK
Sending to Slave: 'Message #17' OK
Reading from Slave: 'Messaess���������>' OK
Sending to Slave: 'Message #18' OK
Reading from Slave: 'Messaess���������>' OK
Sending to Slave: 'Message #19' OK
Reading from Slave: 'Messaess���������>' OK
Sending to Slave: 'Message #20' OK
Reading from Slave: 'Messaess���������>' OK
Sending to Slave: 'Message #21' OK
Reading from Slave: 'Messaess���������>' OK
Sending to Slave: 'Message #22' OK
Reading from Slave: 'Messaess���������>' OK
Sending to Slave: 'Message #23' OK
Reading from Slave: 'Messaess���������>' OK
Sending to Slave: 'Message #24' OK
Reading from Slave: 'Messaess���������>' OK
Sending to Slave: 'Message #25' OK


Code:
// -------------------------------------------------------------------------------------------
// Basic Master
// -------------------------------------------------------------------------------------------
//
// This creates a simple I2C Master device which when triggered will send/receive a text 
// string to/from a Slave device.  It is intended to pair with a Slave device running the 
// basic_slave sketch.
//
// Pull pin12 input low to send.
// Pull pin11 input low to receive.
//
// This example code is in the public domain.
//
// -------------------------------------------------------------------------------------------

#include <i2c_t3.h>

// Memory
#define MEM_LEN 16
char inbuf[MEM_LEN];
char outbuf[MEM_LEN];
int count;

void setup()
{
  // Setup for Master mode, pins 18/19, external pullups, 400kHz, 200ms default timeout
    Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);
    Wire.setDefaultTimeout(200000); // 200ms

    // Data init
    count = 0;

    Serial.begin(9600);
}

void loop()
{
    uint8_t target = 0x50; // target Slave address

    // Send string to Slave
    //

        // Construct data message
        memset(inbuf, 0, sizeof(inbuf));
        sprintf(inbuf, "Message #%d", count++);

        // Print message
        Serial.printf("Sending to Slave: '%s' ", inbuf);

        // Transmit to Slave
        Wire.beginTransmission(target);   // Slave address
        Wire.write(inbuf,strlen(inbuf)+1); // Write string to I2C Tx buffer (incl. string null at end)
        Wire.endTransmission();           // Transmit to Slave

        // Check if error occured
        if(Wire.getError())
            Serial.print("FAIL\n");
        else
            Serial.print("OK\n");

        delay(1000);                       // Delay to space out tests


    // Read string from Slave
    //

        // Print message
        Serial.print("Reading from Slave: ");

        memset(outbuf, 0, sizeof(outbuf));

        // Read from Slave
        Wire.requestFrom(target, (size_t)MEM_LEN); // Read from Slave (string len unknown, request full buffer)

        // Check if error occured
        if(Wire.getError())
            Serial.print("FAIL\n");
        else
        {
            // If no error then read Rx data into buffer and print
            Wire.read(outbuf, Wire.available());
            Serial.printf("'%s' OK\n",outbuf);


        }

        delay(1000);                       // Delay to space out tests

}
 
you might study the data sheet. it looks like for write() and and read() you need to provide a "word" address to the EEPROM to tell it where you want to write/read. For debugging, you might print out Wire.available() before doing the Wire.read. Here is an Arduino example of I2C EEPROM (although the example's EEPROM uses 2-byte addresses)
https://playground.arduino.cc/code/I2CEEPROM

The Teensy LC also has 128 bytes of on-board EEPROM, https://www.pjrc.com/teensy/td_libs_EEPROM.html
 
Last edited:
you might study the data sheet. it looks like for write() and and read() you need to provide a "word" address to the EEPROM to tell it where you want to write/read. For debugging, you might print out Wire.available() before doing the Wire.read. Here is an Arduino example of I2C EEPROM (although the example's EEPROM uses 2-byte addresses)
https://playground.arduino.cc/code/I2CEEPROM

The Teensy LC also has 128 bytes of on-board EEPROM, https://www.pjrc.com/teensy/td_libs_EEPROM.html

Ok...I managed to kind of get it working, but still have a thorough lack of understanding of what's really going on. I see in the datasheet that there's a required word address before write/read operations, but I guess I just don't get where in code that address is being sent, even though this example is working.

Here's what I think is happening:

for the write:

Wire.beginTransmission(addr) is writing the device address,
then:
Wire.write((int)(eeaddress & 0xFF)); // LSB writes the r/w bit and the word address
then:
Wire.write(rdata); writes the actual data
then:
Wire.endTransmission(); sends the stop bit and the EEPROM chip performs the write internally.

What I don't get, is how to form that word address...does an increased address increase the page i'm addressing or the byte i'm addressing?
For example if I do:

Code:
    int rdata = data;
    int addr = deviceaddress | ((eeaddress & 0x70) >> 7 );
    Wire.beginTransmission(addr);
    Wire.write(2); // LSB
    Wire.write(rdata);
    Wire.endTransmission();
Code:
Am I writing to the second byte in the EEPROM chip or the second page? Any good resources on this?

/*
  *  Use the I2C bus with EEPROM 24LC64
  *  Sketch:    eeprom.ino
  *
  *  Author: hkhijhe
  *  Date: 01/10/2010
  *
  *
  */

#include <Wire.h>


void setup()
{
    char somedata[] = "123456789ABCDEFHIJKLMNOPQRSTUV"; // data to write

    Wire.begin(); // initialise the connection
    Wire.setClock(400000);
    Serial.begin(9600);
    i2c_eeprom_write_page(0x50, 0, (byte *)somedata, sizeof(somedata)); // write to EEPROM

    delay(100); //add a small delay

    Serial.println("Memory written");
}

void loop()
{
    int eeaddress=0; //first address
    byte b = i2c_eeprom_read_byte(0x50, 0); // access the first address from the memory

    while (b!=0)
    {
        Serial.print((char)b); //print content to serial port
        eeaddress++; //increase address
        b = i2c_eeprom_read_byte(0x50, eeaddress); //access an address from the memory
    }
    Serial.println(" ");
    delay(2000);
}
byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
    byte rdata = 0xFF;
    int daddr = deviceaddress | ((eeaddress & 0x70) >> 7 );

    Wire.beginTransmission(daddr);
    Wire.write((int)(eeaddress & 0xFF)); // LSB

    Wire.endTransmission();
    Wire.requestFrom(deviceaddress,1);
    if (Wire.available()) rdata = Wire.read();
    return rdata;
}

void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
    int rdata = data;
    int addr = deviceaddress | ((eeaddress & 0x70) >> 7 );
    Wire.beginTransmission(addr);
    Wire.write((int)(eeaddress & 0xFF)); // LSB
    Wire.write(rdata);
    Wire.endTransmission();
}

// WARNING: address is a page address, 6-bit end will wrap around
// also, data can be maximum of about 30 bytes, because the Wire library has a buffer of 32 bytes
void i2c_eeprom_write_page( int deviceaddress, unsigned int eeaddresspage, byte* data, byte length ) {
    
    Wire.beginTransmission(deviceaddress);
    Wire.write((int)(eeaddresspage & 0xFF)); // LSB
    byte c;
    for ( c = 0; c < length; c++)
        Wire.write(data[c]);
    Wire.endTransmission();
}


// maybe let's not read more than 30 or 32 bytes at a time!
void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length ) {
      int addr = deviceaddress | ((eeaddress & 0x70) >> 7 );

    Wire.beginTransmission(addr);
    Wire.write((int)(eeaddress & 0xFF)); // LSB
    Wire.endTransmission();
    Wire.requestFrom(deviceaddress,length);
    int c = 0;
    for ( c = 0; c < length; c++ )
        if (Wire.available()) buffer[c] = Wire.read();
}
Code:
 
Pages in this eeprom are organized as blocks of 16bytes...

I get that, I am just unsure how to read/write to specific pages.

Would this snipped write to block 1 on page 2 or is there some other bit message I need to send to switch the page i'm addressing.
Code:
int rdata = data;
    int addr = deviceaddress | ((eeaddress & 0x70) >> 7 );
    Wire.beginTransmission(addr);
    Wire.write(0x11); // LSB
    Wire.write(rdata);
    Wire.endTransmission();
 
Status
Not open for further replies.
Back
Top