Why my wiced smart tag download failed when I connect a I2C device?

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Anonymous
Not applicable

I have an I2C device, LM73 TEMP SENSOR. http://www.ti.com/product/lm73

I have connected it on I2C bus, multiplex with on-board EEPROM, they share the I2C bus together.

After connection established, download application firmware is failure.

After I remove LM73, downloading is ok.

Downloading log is enable, they are below.

0 Likes
1 Solution
MichaelF_56
Moderator
Moderator
Moderator
250 sign-ins 25 comments on blog 10 comments on blog
The firmware team has a similar setup available with an LM73 connected.

They are also using 0x48 << 1 as the slave address and it appears that everything is working correctly.

The debug trace shown below occurs when initializing and then reading the temperature once per second:

GPIO_WP:OFF=0

temperature_sensor_create()

GattDB:20b990, 20b9d4

hdl: perm:len:maxlen:uuid

0001:02:02:02:2800

01 18

0014:02:02:02:2800

00 18

0015:02:05:05:2803

02 16 00 00 2a

0016:02:10:10:2a00

54 65 6d 70 20 73 65 6e 73 6f 72 00 00 00 00 00

0017:02:05:05:2803

02 18 00 01 2a

0018:02:02:02:2a01

00 02

GattDB complete

Reading identification register...

Temperature sensor identified as Manuf: 1, Prod: 9, Rev: 0

&#8230;

temperature_sensor_read_temperature_data returned 3104

The current temperature is: 24 & 1/4 degrees C

Starting new temperature measurement.

Sensor read status returned E9

temperature_sensor_read_temperature_data returned 3156

The current temperature is: 24 & 21/32 degrees C

Starting new temperature measurement.

Sensor read status returned E9

temperature_sensor_read_temperature_data returned 3160

The current temperature is: 24 & 11/16 degrees C

Starting new temperature measurement.

Sensor read status returned E9

temperature_sensor_read_temperature_data returned 3156

The current temperature is: 24 & 21/32 degrees C

&#8230;

Per the last post, I confirmed also that the btp file is in Platforms/BCM920732TAG_Q32/ and that all GPIOs are input enabled by default. However, you cannot use GPIO to drive the sensor as you will need to use a transistor switch to control power to the sensor. Here, you want to use a transistor whose input is tied in such a way that it is turned off. Then, when the FW boots up, the app should drive its GPIO to turn on the switch, which will in turn power the temperature sensor.

We don&#8217;t have a TSL2550 to test, but have seen no problems with the LM73 temperature sensor during download to EEPROM. If the LM73 is not acking, then it could be that the address you are using in the code and the address configured for the LM73 are not the same. If the app uses 0x48, then the part has to be an LM73-0 part with the address pin left floating. The sensor has other address options that you can try (like tying the address pin to Vdd or GND).

Take a look at this latest setup of feedback and let me know if you are able to resolve the issue.

View solution in original post

0 Likes
11 Replies
MichaelF_56
Moderator
Moderator
Moderator
250 sign-ins 25 comments on blog 10 comments on blog
Firmware downloads occur over the HCI UART, so Im not sure why the I2C interface is causing problems with downloads.

Im assuming that physical pin 21 on the 20732S module is being used for SCL (I2C clock to ext. device) and pin 22 for SDA (I2C data to ext. device) and that there is no external termination (both pins are internal PUs on the module).

In addition: Transaction length of 16 bytes, maximum SCL speed of 4000 kbps, its the only master on the bus and the sensor supports a 7-bit slave address?

The following code snippet shows how to initialize I2C in the master role, and how to write, read and use the combo write-then-read transaction using the driver API available in the WICED SDK.

Are you using this code snippet provided within the WICED Smart Hardware Interfaces Guide thats available here on the website?

#include "cfa.h"

// Use slave address 0x1A = (7b0001101 << 1) | 1bR|W.

#define I2C_SLAVE_ADDRESS (0x1A)

// Read operation to the lower level driver is 0.

#define I2C_SLAVE_OPERATION_READ 0

// Write operation to the lower level driver is 1.

#define I2C_SLAVE_OPERATION_WRITE 1

// Reads data from the slave into the given buffer.

// buffer - The buffer into which to read. Should be allocated by caller.

// length - The number of bytes to read form the slave.

// slave_address - The address of the slave device. Valid bits are the

// upper 7 bits, bit 0 must be 1b0.

// Returns 1 if successful, else 0.

//

UINT8 i2cm_read_from_slave(BYTE* buffer, UINT32 length, UINT8 slave_address)

{

// Assume failure.

UINT8 return_value = 0;

// Invoke the lower level driver. Non-combo transaction, so set offset parameters to NULL/0.

CFA_BSC_STATUS read_status = cfa_bsc_OpExtended(buffer, length, NULL, 0, slave_address,

I2C_SLAVE_OPERATION_READ);

switch(read_status)

{

case CFA_BSC_STATUS_INCOMPLETE:

// Transaction did not go through. ERROR. Handle this case.

break;

case CFA_BSC_STATUS_SUCCESS:

// The read was successful.

return_value = 1;

break;

case CFA_BSC_STATUS_NO_ACK:

// No slave device with this address exists on the I2C bus. ERROR. Handle this.

default:

break;

}

return return_value;

}

// Writes data to the slave from the given buffer.

// buffer - The buffer that has the data to be written to the slave.

// length - The number of bytes to write to slave.

// slave_address - The address of the slave device. Valid bits are the

// upper 7 bits, bit 0 must be 1b0.

// Return 1 if successful, else 0.

//

UINT8 i2cm_write_to_slave(BYTE* buffer, UINT32 length, UINT8 slave_address)

{

// Assume failure.

UINT8 return_value = 0;

// Invoke the lower level driver. Non-combo transaction, so set offset parameters to NULL/0.

CFA_BSC_STATUS read_status = cfa_bsc_OpExtended(buffer, length, NULL, 0, slave_address, I2C_SLAVE_OPERATION_WRITE);

switch(read_status)

{

case CFA_BSC_STATUS_INCOMPLETE:

// Transaction did not go through. ERROR. Handle this case.

break;

case CFA_BSC_STATUS_SUCCESS:

// The read was successful.

return_value = 1;

break;

case CFA_BSC_STATUS_NO_ACK:

// No slave device with this address exists on the I2C bus. ERROR. Handle this.

default:

break;

}

return return_value;

}

// Combo write-then-read transaction. Writes some bytes to slave,

// then issues a repeated START followed by a read transaction.

// buffer_to_write - The buffer from which to write to the slave. If the number of

// bytes to read exceeds 16, the driver will update this value by the number

// of bytes read and start another new transaction until length_to_read number

// of bytes have been read. This API is available for devices that behave like

// EEPROMs, so the buffer has to point to an array of bytes with the offset

// address in big endian format. See any I2C EEPROM specification for details.

// length_of_write - The number of bytes that buffer_to_write pointes to. This is

// also the number of bytes in the first WRITE transaction before the repeated

// start. Note that length_of_write + length_to_read has to be <= 16, typically

// is 2 for EEPROMs because they use 16 bit offsets.

// buffer_to_read_into - The buffer into which the data is to be read during the READ

// part of the combo transaction (after the repeated START condition).

// length_to_read - The number of bytes to read during the READ portion of the combo

// transaction. Note that length_of_write + length_to_read has to be <= 16,

// typically is 2 for EEPROMs because they use 16 bit offsets.

// slave_address - The address of the slave device. Valid bits are the

// upper 7 bits, bit 0 must be 1b0.

// Returns 1 if successful, else 0.

//

UINT8 i2cm_write_then_read_from_slave(BYTE* buffer_to_write, UINT32 length_of_write,

BYTE* buffer_to_read_into, UINT32 length_to_read,

UINT8 slave_address)

{

// Assume failure.

UINT8 return_value = 0;

// Invoke the lower level driver. This is a combo transaction.

CFA_BSC_STATUS read_status = cfa_bsc_OpExtended(buffer_to_read_into, length_to_read, buffer_to_write,

length_of_write, slave_address,

I2C_SLAVE_OPERATION_READ);

switch(read_status)

{

case CFA_BSC_STATUS_INCOMPLETE:

// Transaction did not go through. ERROR. Handle this case.

break;

case CFA_BSC_STATUS_SUCCESS:

// The read was successful.

return_value = 1;

break;

case CFA_BSC_STATUS_NO_ACK:

// No slave device with this address exists on the I2C bus. ERROR. Handle this.

default:

break;

}

return return_value;

}
0 Likes
MichaelF_56
Moderator
Moderator
Moderator
250 sign-ins 25 comments on blog 10 comments on blog
The HW team thinks that this may be an electrical issue.  They also looked at the DS for LM73 and confirmed that the I2C slave address does not collide with the slave address of the EEPROM. Can you measure the levels on SCL and SDA and see what the lines look like during the download?
0 Likes
Anonymous
Not applicable
Firmware downloads occur over the HCI UART, so Im not sure why the I2C interface is causing problems with downloads.

Im assuming that physical pin 21 on the 20732S module is being used for SCL (I2C clock to ext. device) and pin 22 for SDA (I2C data to ext. device) and that there is no external termination (both pins are internal PUs on the module).

In addition: Transaction length of 16 bytes, maximum SCL speed of 4000 kbps, its the only master on the bus and the sensor supports a 7-bit slave address?

The following code snippet shows how to initialize I2C in the master role, and how to write, read and use the combo write-then-read transaction using the driver API available in the WICED SDK.

Are you using this code snippet provided within the WICED Smart Hardware Interfaces Guide thats available here on the website?

#include "cfa.h"

// Use slave address 0x1A = (7b0001101 << 1) | 1bR|W.

#define I2C_SLAVE_ADDRESS (0x1A)

// Read operation to the lower level driver is 0.

#define I2C_SLAVE_OPERATION_READ 0

// Write operation to the lower level driver is 1.

#define I2C_SLAVE_OPERATION_WRITE 1

// Reads data from the slave into the given buffer.

// buffer - The buffer into which to read. Should be allocated by caller.

// length - The number of bytes to read form the slave.

// slave_address - The address of the slave device. Valid bits are the

// upper 7 bits, bit 0 must be 1b0.

// Returns 1 if successful, else 0.

//

UINT8 i2cm_read_from_slave(BYTE* buffer, UINT32 length, UINT8 slave_address)

{

// Assume failure.

UINT8 return_value = 0;

// Invoke the lower level driver. Non-combo transaction, so set offset parameters to NULL/0.

CFA_BSC_STATUS read_status = cfa_bsc_OpExtended(buffer, length, NULL, 0, slave_address,

I2C_SLAVE_OPERATION_READ);

switch(read_status)

{

case CFA_BSC_STATUS_INCOMPLETE:

// Transaction did not go through. ERROR. Handle this case.

break;

case CFA_BSC_STATUS_SUCCESS:

// The read was successful.

return_value = 1;

break;

case CFA_BSC_STATUS_NO_ACK:

// No slave device with this address exists on the I2C bus. ERROR. Handle this.

default:

break;

}

return return_value;

}

// Writes data to the slave from the given buffer.

// buffer - The buffer that has the data to be written to the slave.

// length - The number of bytes to write to slave.

// slave_address - The address of the slave device. Valid bits are the

// upper 7 bits, bit 0 must be 1b0.

// Return 1 if successful, else 0.

//

UINT8 i2cm_write_to_slave(BYTE* buffer, UINT32 length, UINT8 slave_address)

{

// Assume failure.

UINT8 return_value = 0;

// Invoke the lower level driver. Non-combo transaction, so set offset parameters to NULL/0.

CFA_BSC_STATUS read_status = cfa_bsc_OpExtended(buffer, length, NULL, 0, slave_address, I2C_SLAVE_OPERATION_WRITE);

switch(read_status)

{

case CFA_BSC_STATUS_INCOMPLETE:

// Transaction did not go through. ERROR. Handle this case.

break;

case CFA_BSC_STATUS_SUCCESS:

// The read was successful.

return_value = 1;

break;

case CFA_BSC_STATUS_NO_ACK:

// No slave device with this address exists on the I2C bus. ERROR. Handle this.

default:

break;

}

return return_value;

}

// Combo write-then-read transaction. Writes some bytes to slave,

// then issues a repeated START followed by a read transaction.

// buffer_to_write - The buffer from which to write to the slave. If the number of

// bytes to read exceeds 16, the driver will update this value by the number

// of bytes read and start another new transaction until length_to_read number

// of bytes have been read. This API is available for devices that behave like

// EEPROMs, so the buffer has to point to an array of bytes with the offset

// address in big endian format. See any I2C EEPROM specification for details.

// length_of_write - The number of bytes that buffer_to_write pointes to. This is

// also the number of bytes in the first WRITE transaction before the repeated

// start. Note that length_of_write + length_to_read has to be <= 16, typically

// is 2 for EEPROMs because they use 16 bit offsets.

// buffer_to_read_into - The buffer into which the data is to be read during the READ

// part of the combo transaction (after the repeated START condition).

// length_to_read - The number of bytes to read during the READ portion of the combo

// transaction. Note that length_of_write + length_to_read has to be <= 16,

// typically is 2 for EEPROMs because they use 16 bit offsets.

// slave_address - The address of the slave device. Valid bits are the

// upper 7 bits, bit 0 must be 1b0.

// Returns 1 if successful, else 0.

//

UINT8 i2cm_write_then_read_from_slave(BYTE* buffer_to_write, UINT32 length_of_write,

BYTE* buffer_to_read_into, UINT32 length_to_read,

UINT8 slave_address)

{

// Assume failure.

UINT8 return_value = 0;

// Invoke the lower level driver. This is a combo transaction.

CFA_BSC_STATUS read_status = cfa_bsc_OpExtended(buffer_to_read_into, length_to_read, buffer_to_write,

length_of_write, slave_address,

I2C_SLAVE_OPERATION_READ);

switch(read_status)

{

case CFA_BSC_STATUS_INCOMPLETE:

// Transaction did not go through. ERROR. Handle this case.

break;

case CFA_BSC_STATUS_SUCCESS:

// The read was successful.

return_value = 1;

break;

case CFA_BSC_STATUS_NO_ACK:

// No slave device with this address exists on the I2C bus. ERROR. Handle this.

default:

break;

}

return return_value;

}

I use 920732SPI-AN100-RDS.pdf to initial I2C bus. I connect two I2C device on bus, one is LM73, the other is TSL2550, light sensor.

I can read ADC value from TSL2550, but I cant read value from LM73 because LM73 need a write_then_read operation, the writing operation always get return of CFA_BSC_STATUS_NO_ACK.

I can provide oscilloscope screen shot if you want.
0 Likes
Anonymous
Not applicable
The HW team thinks that this may be an electrical issue.  They also looked at the DS for LM73 and confirmed that the I2C slave address does not collide with the slave address of the EEPROM. Can you measure the levels on SCL and SDA and see what the lines look like during the download?

Mike,

The TAG can be detected and found, the downloading operation can be started. But after a while, downloading is failure and eclipse show that need reset and retry again.

I have watched the SCL and SDA state when downloading, I think that bootloader should write something when downloading. The level on SCL and SDA is ok.

I enable the downloading log, but forum dont permit to upload it, I will send them using email.
MichaelF_56
Moderator
Moderator
Moderator
250 sign-ins 25 comments on blog 10 comments on blog
I will look into this with the firmware team and see if they can provide some direction.
0 Likes
MichaelF_56
Moderator
Moderator
Moderator
250 sign-ins 25 comments on blog 10 comments on blog
I spoke to the firmware team and heres the feedback they provided based on the files you provided.

In the failure case, there is a 1 bit error (0x06 was seen when 0x46 was expected
0 Likes
Anonymous
Not applicable
#if 0 //LM73

buff[0] = 0x07;  // write command register of LM73, CHIP_ID register

status = i2cm_write_to_slave( buff, 1, I2C_LM73_SLAVE_ADDRESS);

ble_trace1( "S0:0x%02X  ", status );

ble_trace1( "W0:0x%02X  ", buff[0] );

// Then, read CHIP_ID register

status = i2cm_read_from_slave(buff, 2, I2C_LM73_SLAVE_ADDRESS );

ble_trace1( "S0:0x%02X  ", status );

ble_trace1( "R0:0x%02X  ", buff[0] );

ble_trace1( "R1:0x%02X  ", buff[1] );

// write command register, CHIP_ID register, then perform write_then_read, one shot mode

wb = 0x07;

status = i2cm_write_then_read_from_slave(&wb, sizeof(UINT8), rb, 2, I2C_LM73_SLAVE_ADDRESS);

ble_trace1( "S0:0x%02X  ", status );

ble_trace1( "rb0:0x%02X  ", rb[0] );

ble_trace1( "rb1:0x%02X  ", rb[1] );

#else //TSL2550

buff[0] = 0x43; // select ADC0 register of TSL2550

status = i2cm_write_to_slave( buff, 1, I2C_TSL2550_SLAVE_ADDRESS);

ble_trace1( "S0:0x%02X  ", status );

ble_trace1( "W0:0x%02X  ", buff[0] );

// Then, read ADC0 register

status = i2cm_read_from_slave(buff, 2, I2C_TSL2550_SLAVE_ADDRESS );

ble_trace1( "S0:0x%02X  ", status );

ble_trace1( "R0:0x%02X  ", buff[0] );

ble_trace1( "R1:0x%02X  ", buff[1] );

// select ADC1 register of TSL2550, then perform write_then_read, one shot mode

wb = 0x83;

status = i2cm_write_then_read_from_slave(&wb, sizeof(UINT8), rb, 2, I2C_TSL2550_SLAVE_ADDRESS);

ble_trace1( "S0:0x%02X  ", status );

ble_trace1( "rb0:0x%02X  ", rb[0] );

ble_trace1( "rb1:0x%02X  ", rb[1] );

#endif
0 Likes
Anonymous
Not applicable
#if 0 //LM73

buff[0] = 0x07;  // write command register of LM73, CHIP_ID register

status = i2cm_write_to_slave( buff, 1, I2C_LM73_SLAVE_ADDRESS);

ble_trace1( "S0:0x%02X  ", status );

ble_trace1( "W0:0x%02X  ", buff[0] );

// Then, read CHIP_ID register

status = i2cm_read_from_slave(buff, 2, I2C_LM73_SLAVE_ADDRESS );

ble_trace1( "S0:0x%02X  ", status );

ble_trace1( "R0:0x%02X  ", buff[0] );

ble_trace1( "R1:0x%02X  ", buff[1] );

// write command register, CHIP_ID register, then perform write_then_read, one shot mode

wb = 0x07;

status = i2cm_write_then_read_from_slave(&wb, sizeof(UINT8), rb, 2, I2C_LM73_SLAVE_ADDRESS);

ble_trace1( "S0:0x%02X  ", status );

ble_trace1( "rb0:0x%02X  ", rb[0] );

ble_trace1( "rb1:0x%02X  ", rb[1] );

#else //TSL2550

buff[0] = 0x43; // select ADC0 register of TSL2550

status = i2cm_write_to_slave( buff, 1, I2C_TSL2550_SLAVE_ADDRESS);

ble_trace1( "S0:0x%02X  ", status );

ble_trace1( "W0:0x%02X  ", buff[0] );

// Then, read ADC0 register

status = i2cm_read_from_slave(buff, 2, I2C_TSL2550_SLAVE_ADDRESS );

ble_trace1( "S0:0x%02X  ", status );

ble_trace1( "R0:0x%02X  ", buff[0] );

ble_trace1( "R1:0x%02X  ", buff[1] );

// select ADC1 register of TSL2550, then perform write_then_read, one shot mode

wb = 0x83;

status = i2cm_write_then_read_from_slave(&wb, sizeof(UINT8), rb, 2, I2C_TSL2550_SLAVE_ADDRESS);

ble_trace1( "S0:0x%02X  ", status );

ble_trace1( "rb0:0x%02X  ", rb[0] );

ble_trace1( "rb1:0x%02X  ", rb[1] );

#endif

These are the address of two I2C sensor devices.

#define I2C_LM73_SLAVE_ADDRESS (0x48 << 1)

#define I2C_TSL2550_SLAVE_ADDRESS (0x39 << 1)

I have posted the code snippet for you. I used condition compile switch "#if 0" to read two sensor separately.

When I read the ADC value of TSL2550 light sensor, everything was ok. i2cm_write_to_slave(), i2cm_read_from_slave() and i2cm_write_then_read_from_slave() returned 0x01, CFA_BSC_STATUS_SUCCESS.

When I read the LM73s chip id, issue occur. Writing operation always returned CFA_BSC_STATUS_NO_ACK.

Reference:

LM73 datasheet: http://www.ti.com/lit/ds/symlink/lm73.pdf

TSL2550 datasheet: http://datasheet.octopart.com/TSL2550D-TAOS-datasheet-578390.pdf
0 Likes
Anonymous
Not applicable
I spoke to the firmware team and heres the feedback they provided based on the files you provided.

In the failure case, there is a 1 bit error (0x06 was seen when 0x46 was expected
0 Likes
MichaelF_56
Moderator
Moderator
Moderator
250 sign-ins 25 comments on blog 10 comments on blog
I believe the btp file my firmware team referred to is the one in the platforms/ BCM920732TAG_Q32 directory

Regarding holding the two devices in reset till the app initializes, I understand that you want to know the GPIO state when the BCM20732 is booting because you believe that you can use the GPIO state to reset the I2C devices and then toggle the GPIO when the application running.

I am checking with the team to see if this is a valid approach.
0 Likes
MichaelF_56
Moderator
Moderator
Moderator
250 sign-ins 25 comments on blog 10 comments on blog
The firmware team has a similar setup available with an LM73 connected.

They are also using 0x48 << 1 as the slave address and it appears that everything is working correctly.

The debug trace shown below occurs when initializing and then reading the temperature once per second:

GPIO_WP:OFF=0

temperature_sensor_create()

GattDB:20b990, 20b9d4

hdl: perm:len:maxlen:uuid

0001:02:02:02:2800

01 18

0014:02:02:02:2800

00 18

0015:02:05:05:2803

02 16 00 00 2a

0016:02:10:10:2a00

54 65 6d 70 20 73 65 6e 73 6f 72 00 00 00 00 00

0017:02:05:05:2803

02 18 00 01 2a

0018:02:02:02:2a01

00 02

GattDB complete

Reading identification register...

Temperature sensor identified as Manuf: 1, Prod: 9, Rev: 0

&#8230;

temperature_sensor_read_temperature_data returned 3104

The current temperature is: 24 & 1/4 degrees C

Starting new temperature measurement.

Sensor read status returned E9

temperature_sensor_read_temperature_data returned 3156

The current temperature is: 24 & 21/32 degrees C

Starting new temperature measurement.

Sensor read status returned E9

temperature_sensor_read_temperature_data returned 3160

The current temperature is: 24 & 11/16 degrees C

Starting new temperature measurement.

Sensor read status returned E9

temperature_sensor_read_temperature_data returned 3156

The current temperature is: 24 & 21/32 degrees C

&#8230;

Per the last post, I confirmed also that the btp file is in Platforms/BCM920732TAG_Q32/ and that all GPIOs are input enabled by default. However, you cannot use GPIO to drive the sensor as you will need to use a transistor switch to control power to the sensor. Here, you want to use a transistor whose input is tied in such a way that it is turned off. Then, when the FW boots up, the app should drive its GPIO to turn on the switch, which will in turn power the temperature sensor.

We don&#8217;t have a TSL2550 to test, but have seen no problems with the LM73 temperature sensor during download to EEPROM. If the LM73 is not acking, then it could be that the address you are using in the code and the address configured for the LM73 are not the same. If the app uses 0x48, then the part has to be an LM73-0 part with the address pin left floating. The sensor has other address options that you can try (like tying the address pin to Vdd or GND).

Take a look at this latest setup of feedback and let me know if you are able to resolve the issue.
0 Likes