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].

 

This entry was posted in Hardware, sigfox and tagged , , , , . Bookmark the permalink.

7 Responses to EFM32 – I2C for Telecom Design TD1204 / TD1208

  1. Léo says:

    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

    • Paul says:

      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. JM Roque says:

    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. JM Roque says:

    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 🙂

    • Paul says:

      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. JM Roque says:

    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 … !

Leave a Reply

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