I2C device with 2 byte response

⚠️
Hi there.. thanks for coming to the forums. Exciting news! we’re now in the process of moving to our new forum platform that will offer better functionality and is contained within the main Dialog website. All posts and accounts have been migrated. We’re now accepting traffic on the new forum only - please POST any new threads at//www.wsdof.com/support. We’ll be fixing bugs / optimising the searching and tagging over the coming days.
9 posts / 0 new
Last post
boydy1989
Offline
Last seen:1 year 9 months ago
Joined:2017-10-18 16:11
I2C device with 2 byte response

Hello

I am trying to interface to an I2C sensor device (https://docs-emea.rs-online.com/webdocs/142c/0900766b8142cdd9.pdf)

I have already successfully used the I2C device on the 14586 with another different sensor.

This new sensor when sent a PROM or ADC read request replies with 2 or 3 bytes of data.

I have based the code on the I2C EEPROM example, and cannot get the system to read more than 1 byte from the reply.

The test code is below. I am setting a break point and looking at 'byte1' and 'byte2' in the debugger watch window. Only byte1 is populated with any data.
I have tried a few different approaches, but am stuck. I can see on my ocilloscope that the device is replying with 2 bytes of data, so I am happy that the basic communications are working OK.

Any input greatly appreciated!

Code:

// Critical section
GLOBAL_INT_DISABLE();

i2c_send_address(address);

SEND_I2C_COMMAND(0x0100); // Set R/W bit to 1 (read access)
// End of critical section
GLOBAL_INT_RESTORE();
uint16_t byte1 = 0;
uint16_t byte2 = 0;

WAIT_FOR_RECEIVED_BYTE(); // Wait for received data

byte1 = (GetWord16(I2C_DATA_CMD_REG) & 0xFF); // Get first received byte
byte2 = (GetWord16(I2C_DATA_CMD_REG) & 0xFF); // The problem seems to be around here...

WAIT_UNTIL_NO_MASTER_ACTIVITY ();// wait until no master activity

return I2C_NO_ERROR;

Device:
MT_dialog
Offline
Last seen:3 months 2 days ago
Staff
Joined:2015-06-08 11:34
Hi boydy1989,

Hi boydy1989,

You invoke the SEND_I2C_COMMAND(0x100) only one time, that means that the I2C module of the 58x will access to bus only for one read, so you actually read only once, you dont provide clock for the second data that you expect to get, and the slave needs the clock from the master in order to send the data out. For instance lets take as an example the read_data_single() function in the peripheral examples in the SDK that reads 32bytes of data at a time, so the function will send the address of the device that would like to communicate and the read indication, and then it will start filling the Tx FIFO with read commands 0x100 (the 0x100 is a dummy command that will just generate the clocks on the bus), as many read commands as the bytes the device would like to read (32 bytes which is also the FIFO), then all of the 32 bytes can be read from the receive FIFO.

Thanks MT_dialog

boydy1989
Offline
Last seen:1 year 9 months ago
Joined:2017-10-18 16:11
Hello

Hello

Thank you for the reply.

I am struggling a little more now though, any call to SEND_I2C_COMMAND only causes the device to send the I2C Device address (with an ACK received).

I cannot send any data out.

Code snippet:
SEND_I2C_COMMAND(0x1E);

Logic output attached on PDF.

I am sure that there is something simple I have missed, all help greatly appreciated.

Attachment:
MT_dialog
Offline
Last seen:3 months 2 days ago
Staff
Joined:2015-06-08 11:34
Hi boydy1989,

Hi boydy1989,

Well, the address of the target that you have been using is 0xEE? If you dont send a byte before the device issues a stop condition the I2C module will keep on sending the address of the device it would like to communicate with. On the code snippet you only provide a SEND_I2C_COMMAND(0x1E) and i am not able to make any conclusions out of this, if you have properly initialized the I2C module and you just issue bytes over bus using the SEND_I2C_COMMAND(0x1E); then you should be able to see the bytes over the bus as long as the external device ack's the data send by the 58x. If you dont want to use the drivers in the SDK for the I2C you can use them as a reference to create your own drivers.

Thanks MT_dialog

boydy1989
Offline
Last seen:1 year 9 months ago
Joined:2017-10-18 16:11
Hi

Hi

I have based my code on the driver in the SDK.

Init code: (copied from the SDK)

void i2c_init(uint16_t dev_address, uint8_t speed, uint8_t address_mode, uint8_t address_size)
{
SetBits16(CLK_PER_REG, I2C_ENABLE, 1); // enable clock for I2C
SetWord16(I2C_ENABLE_REG, 0x0); // Disable the I2C controller
SetWord16(I2C_CON_REG, I2C_MASTER_MODE | I2C_SLAVE_DISABLE | I2C_RESTART_EN); // Slave is disabled
SetBits16(I2C_CON_REG, I2C_SPEED, speed); // Set speed
#ifdef I2C_SS_FREQ_TRIM
SetWord16(I2C_SS_SCL_HCNT_REG, I2C_SS_SCL_HCNT_VAL); // Set the SCL clock high-period count for standard speed
SetWord16(I2C_SS_SCL_LCNT_REG, I2C_SS_SCL_LCNT_VAL); // Set the SCL clock low-period count for standard speed
#endif // I2C_SS_FREQ_TRIM
#ifdef I2C_FS_FREQ_TRIM
SetWord16(I2C_FS_SCL_HCNT_REG, I2C_FS_SCL_HCNT_VAL); // Set the SCL clock high-period count for fast speed
SetWord16(I2C_FS_SCL_LCNT_REG, I2C_FS_SCL_LCNT_VAL); // Set the SCL clock low-period count for fast speed
#endif // I2C_HS_FREQ_TRIM
SetBits16(I2C_CON_REG, I2C_10BITADDR_MASTER, address_mode); // Set addressing mode
SetWord16(I2C_TAR_REG, dev_address & 0x3FF); // Set Slave device address
SetWord16(I2C_ENABLE_REG, 0x1); // Enable the I2C controller
WAIT_UNTIL_NO_MASTER_ACTIVITY ();/ /等待for I2C master FSM to become IDLE
i2c_dev_address = dev_address;
WAIT_UNTIL_NO_MASTER_ACTIVITY ();/ /等待master activity
}

I have used the correct address for the device, as if I change the address I no longer see the Ack on my logic analyser.

Am I doing something wrong to issue bytes? I expect to just call the SEND_I2C_COMMAND(), and see the start, address, byte, stop on the bus. All I get is the start, address, stop.

I have placed several SEND_I2C_COMMAND() sequentially, but still do not see any data.

Is there a way of confirming receipt of the Ack by the 586? Or, is there something that would be preventing it receiving the Ack?

Thanks again!

MT_dialog
Offline
Last seen:3 months 2 days ago
Staff
Joined:2015-06-08 11:34
Hi boydy1989,

Hi boydy1989,

如果主(585)不会从th ACKe slave device in every attempt that you do to write something on the bus the master module will keep on sending the address and wait for an ACK, every SEND_I2C_COMMAND() will result the defined target address in an attempt of the master to communicate with the slave. If the master doesn't get an ACK from the slave then you wont see the bytes that you have instructed the device to send. If you dont get an ACK then something is wrong with the slave device attached. Regarding the checking if the ACK from the external device has been received, there is a function in the i2c_eeprom.c called i2c_wait_until_eeprom_ready(), the function will send out a dummy byte 0x08 and check if the ABRT_7B_ADDR_NOACK bit of the I2C_TX_ABRT_SOURCE_REG if there is no ACK from the slave that bit will be set to 1, that means that the device hasn't acked the address.

Thanks MT_dialog

boydy1989
Offline
Last seen:1 year 9 months ago
Joined:2017-10-18 16:11
Hello

Hello

I have made some more progress now, and am receiving the data correctly. Thank you for your help.

For completeness, and in the hope that it will help someone else in the future I will post my code extract here with an explanation - I found that the documentation for the I2C controller for this microprocessor was not very clear, however I think I am now understanding it.

The below code will transmit the following sequence on the I2C bus:
ADDR_WR | REG_ADDR | ADDR_RE | CLK | CLK

I had to replace the WAIT_FOR_RECEIVED_BYTE() macro with while(GetWord16(I2C_RXFLR_REG) != 2);

I found that trying to read the data from the FIFO immediately resulted in one of the bytes being lost. Maybe this is pipeline related, I'm not sure.

I found that adding a WAIT_FOR_RECEIVED_BYTE(); between the SEND_I2C_COMMAND(0x0100); calls generated enough wait time for the I2C controller to generate a STOP condition on the bus.

Another observation that I have made is that there is a fairly strong pull up/high state drive internal to the 14586 when the port is configured as I2C - the device I am using has quite a weak driver for its 'low' states, I had to increase the external pull up resistor value to around 47k, just to allow the device to pull the bus low for it's ACK. I noted that even with no pull up resistor, and with the port configured to no pull up, there is still a high state on the bus when undriven. This is different to other micros I have used before, which use an open collector drive for the I2C.Some clarification would be appreciated from Dialog as to the structure of the I2C hardware.

Thank you again for the help, and I hope this information helps someone else using the DA14585 or DA14586 devices with an I2C device!

i2c_error_code i2c_read_int16(uint32_t address, uint16_t *data)
{
uint8_t byte1 = 0;
uint8_t byte2 = 0;
// Critical section
GLOBAL_INT_DISABLE();

i2c_send_address(address);

SEND_I2C_COMMAND(0x0100); // Set R/W bit to 1 (read access)
SEND_I2C_COMMAND(0x0100); // Set R/W bit to 1 (read access)
while(GetWord16(I2C_RXFLR_REG) != 2); // Wait for received data

byte1 = 0xFF & GetWord16(I2C_DATA_CMD_REG); // Get received byte
byte2 = 0xFF & GetWord16(I2C_DATA_CMD_REG); // Get received byte

GLOBAL_INT_RESTORE();
WAIT_UNTIL_I2C_FIFO_IS_EMPTY(); // Wait until Tx FIFO is empty
WAIT_UNTIL_NO_MASTER_ACTIVITY ();// wait until no master activity
*data = ((byte2 << 8) | byte1);
return I2C_NO_ERROR;
}

MT_dialog
Offline
Last seen:3 months 2 days ago
Staff
Joined:2015-06-08 11:34
Hi boydy1989,

Hi boydy1989,

The driver used for the eeprom is quite complete and tested, so one should be based on the structure of that driver and use it as a reference, regarding your observations.

  • I dont see a reason for changing if the WAIT_FOR_RECEIVED_BYTE, the macro is used in order to halt the code and wait for the device to receive data from the FIFO.
  • Reading immidiatelly from the FIFO there are bytes lost, doesn't ring a bell.
  • Regarding the stop condition, as soon as the FIFO is empty the device will issue a stop condition automatically, so in order not to see a stop condition you will have to keep your FIFO full, that is why the driver executes the reads in bulks of 32 bytes (this is indicated from the datasheet in page 80 on the first paragraph of 14.2.1 START and STOP Generation Allowing the transmit FIFO to empty causes the I2C Controller to generate a STOP condition on the I2C bus).
  • Regarding your last observation, you are right, if you have configured the functionallity of the pin as an I2C then the internal pull ups will be activated automatically even if you dont explictly configure them (this is indicated from the datasheet on page 21, I2C Bus Interface The mapped Px pin is automatically configured with a pull up resistor (25kΩ) to the power supply configured by the register Px_PADPWR_CTRL_REG).

Thanks MT_dialog

boydy1989
Offline
Last seen:1 year 9 months ago
Joined:2017-10-18 16:11
Thank you for your support,

Thank you for your support, all comments taken on board!