具有2字节响应的I2C设备

⚠️
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个职位/0个新职位
Last post
boydy1989
Offline
Last seen:1 year 9 months ago
Joined:2017-10-18 16:11
具有2字节响应的I2C设备

Hello

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

我已经成功地将14586上的I2C设备与另一个不同的传感器一起使用。

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.

测试代码如下。我正在设置一个断点,并在调试器监视窗口中查看“byte1”和“byte2”。只有字节1被任何数据填充。
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:

//临界截面
GLOBAL_INT_DISABLE();

i2c_send_address(address);

发送I2C命令(0x0100);//将R/W位设置为1(读访问)
// End of critical section
GLOBAL_INT_RESTORE();
uint16字节1=0;
uint16字节2=0;

等待_收到_BYTE();//等待接收数据

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;

设备:
MT_dialog
Offline
Last seen:3个月3天前
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).

我不能发送任何数据。

代码段:
SEND_I2C_COMMAND(0x1E);

逻辑输出附在PDF上。

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

Attachment:
MT_dialog
Offline
Last seen:3个月3天前
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.

初始化代码:(从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
设置字16(I2C_SS_SCL_LCNT_REG,I2C_SS_SCL_LCNT_VAL);//为标准速度设置SCL时钟低周期计数
#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\U HS\U频率微调
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\u dev\u address=开发地址;
WAIT_UNTIL_NO_MASTER_ACTIVITY ();/ /等待until no 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个月3天前
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.希望Dialog能对I2C硬件的结构做些澄清。

再次感谢您的帮助,我希望此信息可以帮助其他使用带I2C设备的DA14585或DA14586设备的用户!

i2c_error_code i2c_read_int16(uint32_t address, uint16_t *data)
{
uint8_t byte1 = 0;
uint8_t byte2 = 0;
//临界截面
GLOBAL_INT_DISABLE();

i2c_send_address(address);

发送I2C命令(0x0100);//将R/W位设置为1(读访问)
发送I2C命令(0x0100);//将R/W位设置为1(读访问)
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();
等待_I2C _FIFO _为空();//等待Tx FIFO为空
WAIT_UNTIL_NO_MASTER_ACTIVITY ();// wait until no master activity
*data = ((byte2 << 8) | byte1);
return I2C_NO_ERROR;
}

MT_dialog
Offline
Last seen:3个月3天前
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.

  • 我看不出改变的理由,如果WAIT\u for\u接收到字节,宏用于停止代码并等待设备从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,

谢谢你的支持,所有的评论都带上了!