EFM32 – I2C for Telecom Design TD1204 / TD1208

A good way to expand Telecom Design system is to use I2C to connect external devices. As an example I had to add an extra Analog to Digital converter. I’m using a MCP3021Ax device. This I2C chip just return a 10bits value each time you send a READ at the expected address. This post contains the TD1204 code to configure I2C and get the data back

Here is the source code :

#include <efm32.h>
#include <em_cmu.h>
#include <em_rmu.h>
#include <em_i2c.h>

// Configure needed clock to have I2C working
CMU_ClockEnable(cmuClock_GPIO, true);
CMU_ClockEnable(cmuClock_I2C0, true);

// Configure I/O pins for working as I2C - Output Open Drain
GPIO_PinModeSet(SCL_PORT, SCL_BIT,gpioModeWiredAnd,1);
GPIO_PinModeSet(SDA_PORT, SDA_BIT,gpioModeWiredAnd,1);    
I2C0->ROUTE = I2C_ROUTE_SDAPEN | I2C_ROUTE_SCLPEN | _I2C_ROUTE_LOCATION_LOC0;

// Init the I2C with default param 100KHz
I2C_Init_TypeDef i2cInit = I2C_INIT_DEFAULT;
I2C_Init(I2C0, &i2cInit);

// Prepare for a read of 2 bytes
I2C_TransferSeq_TypeDef i2cTransfert;
uint8_t values[2] = {0,0};
i2cTransfert.addr = MCP3021_ADR_LOW;    // Chip address << 1
i2cTransfert.flags = I2C_FLAG_READ;     // READ Operation
i2cTransfert.buf[0].data = values;      // buffer
i2cTransfert.buf[0].len = 2;            // Read 2 bytes as the device is 16b

// Start I2C read   
int _status = I2C_TransferInit(I2C0, &i2cTransfert);
while ( _status == i2cTransferInProgress) {
      _status = I2C_Transfer(I2C0);
}

// Values have been received ! Status should be 0
tfp_printf("A - D0 %d D0 %d S %d\r\n",values[0],values[1],_status);

In case you need to execute a WRITE_WRITE command or WRITE_READ command to set/read internal register, you have to fill the i2cTransfert structure a different way :

    values[0] = _REGISTER_ADDRESS;
    values[1] = _REGISTER_VALUE;
    i2cTransfert.addr = I2C_ADDR;
    i2cTransfert.flags = I2C_FLAG_WRITE_WRITE;
    i2cTransfert.buf[0].len = 1;
    i2cTransfert.buf[0].data = &values[0];
    i2cTransfert.buf[1].len = 1;
    i2cTransfert.buf[1].data = &values[1];
    _status = I2C_TransferInit(I2C0, &i2cTransfert);
    while ( _status == i2cTransferInProgress) {
      _status = I2C_Transfer(I2C0);
    }

You indicate you want to transfer 2 bytes : the two of them are in WRITE mode. The first one is the address, the second one is the value to set. If you need to WRITE two registers you can change buf[1].len for 2.

When you need to WRITE then READ a register, use I2C_FLAG_WRITE_READ, the register to READ is in buf[0] and the result of the read will be in the buf[1].

 

10 thoughts on “EFM32 – I2C for Telecom Design TD1204 / TD1208

  1. Hi Paul,

    Thanks for this great I2C base.
    Do you have an idea of how to implement a timeout feature in the I2C ? Just to avoid the chip to block in case of not responding I2C device.

    I can do something simple by using a counter but the delay will be approximate.

    Thanks again,

    Léo

    • I did not take a look to this. As I2C code is not specific to TD but common with all efm32 you can check what google propose 😉

  2. Hello Paul,

    I have been trying for several days to interface my TD1208 to a HTU21D temperature/humidity sensor using I2C.
    But I cannot succeed.

    I tried to use your example code but it is not working.

    I2C_Transfer() function always return -1.

    I have put my oscilloscope on the SCL output of the TD1208 and it seems the output is always +3.3v.
    I am using two 12kOhms resistors.

    Here is my code :

    // Configure needed clock to have I2C working
    CMU_ClockEnable(cmuClock_I2C0, true);
    CMU_ClockEnable(cmuClock_GPIO, true);

    // Configure I/O pins for working as I2C – Output Open Drain
    GPIO_PinModeSet(SCL_PORT, SCL_BIT, gpioModeWiredAnd, 1);
    GPIO_PinModeSet(SDA_PORT, SDA_BIT, gpioModeWiredAnd, 1);
    I2C0->ROUTE = I2C_ROUTE_SDAPEN | I2C_ROUTE_SCLPEN | _I2C_ROUTE_LOCATION_LOC0;

    // Init the I2C with default param 100KHz
    I2C_Init_TypeDef i2cInit = I2C_INIT_DEFAULT;
    I2C_Init(I2C0, &i2cInit);

    // Prepare for the transaction
    I2C_TransferSeq_TypeDef i2cTransfert;
    uint8_t command[1] = {0};
    uint8_t values[3] = {0,0,0};
    i2cTransfert.addr = HTU21D_ADDRESS;

    // Send HUMD MEASURE command to HTU21D
    i2cTransfert.flags = I2C_FLAG_WRITE;
    command[0] = TRIGGER_HUMD_MEASURE_NOHOLD;
    i2cTransfert.buf[0].len = 1;
    i2cTransfert.buf[0].data = command;
    int _status = I2C_TransferInit(I2C0, &i2cTransfert);
    while ( _status == i2cTransferInProgress) {
    _status = I2C_Transfer(I2C0);
    }
    // ===> At this point _status is -1

    // Get the HUMD MEASURE data from HTU21D
    i2cTransfert.flags = I2C_FLAG_READ;
    i2cTransfert.buf[0].len = 3;
    i2cTransfert.buf[0].data = values;
    _status = I2C_TransferInit(I2C0, &i2cTransfert);
    while ( _status == i2cTransferInProgress) {
    _status = I2C_Transfer(I2C0);
    }
    // ===> At this point _status is -1

    Do you know what is wrong or what I am missing ?
    My feeling is that SCL and SDA are not welle initiated.

    Best regards,
    JM Roque

  3. Hello Paul,

    The technial documentation of the HTU21D (see link hereafter) says that the I2C address is : 0x40 which is 0100 0000.

    They also give an example of the I2C communication sequence (page 11/21).
    S 1 0 0 0 0 0 0 0 ACK 1 1 1 0 0 1 0 1 ACK … continued .
    So the address is shifted by << 1 in their example to keep the LSB bits for WRITE (=1) or READ (=0) command of I2C (in the above example, we are sending a WRITE command).

    The value of HTU21D_ADDRESS I use is 0x40, I didn't shift it by << 1.
    I assumed I2C_TransferInit() would do it for me …. (It is the first time I use the EMLIB API).
    So from what you say, I undertsand the API doesn't shift the address.

    I will try to do the shift before the call to I2C_TransferInit() .

    Could you also tell me what pull-up resistor you are using ?

    The sensor and the TD1208 are few cm far from each other. I assumed that my problem could also be linked to the resistor value. I tried 3.8kOhms and 12kOhms. I never saw a signal on the oscilloscope.

    Thanks again for your precious help that will avoir me tear my hair anymore 🙂

    • I2C_TransferInit() is not doing it … just do it 😉
      3K – 12K my be good …

      Playing with I2C is a hard time many times … usually I solve my problem using a digital analyzer like dreamsourcelab or salae or salae clone you can get for a couple of euros …

  4. Hi Paul,

    You were right, I needed to left shif HTU21D_ADDRESS.

    Thank you so much for your help and a big bravo for blog which I think is the best on IOTs!

    Thumbs up to you … !

  5. I hope you can help me.
    I’m trying to duplicate this for module TD1205P

    I notice that for this module it is I2C port 1 that is wired to the external pins.

    When I try to specify that it is I2C1 I get the error that the symbol could not be resolved.
    “cmuClock_I2C1” can also not be resolved.
    Anyhow I need this to be resolved.

    I can’t find where HFPERCLKEN0_I2C0 is set as the configuration to go for.

    • Hi Gwen,

      I am in the same situation as you, I am trying to use the I2c port of the TD1205P module and it is impossible.

      I never saw a signal on the oscilloscope.

      Were you able to get the i2C module to work at some point?

      Thank you very much in advance

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.