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'。只有Byte1填充了任何数据。
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!
代码:
//关键部分
global_int_disable();
i2c_send_address(address);
send_i2c_command(0x0100);//将R / W位设置为1(读取访问)
// End of critical section
GLOBAL_INT_RESTORE();
uint16_t byte1 = 0;
uint16_t byte2 = 0;
wait_for_received_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_actity();// wait until no master activity
return I2C_NO_ERROR;
你好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
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上的逻辑输出。
我相信我错过了一些简单的东西,所有人都有助于极大地赞赏。
你好Boydy1989,
那么,你已经使用的目标的地址是0xee?如果您在设备发出之前发送字节,则停止条件,I2C模块将继续发送其要与其通信的设备的地址。在代码段上,您只提供send_i2c_command(0x1e),如果您已正确初始化I2C模块,并且您只需使用send_i2c_command(0x1e)才能通过公共汽车发出字节字节(0x1e),我无法求出任何结论。然后,只要外部设备ACK的数据发送到58倍,就应该能够在总线上看到字节。如果您不想在I2C中使用SDK中的驱动程序,则可以将它们用作创建自己的驱动程序的引用。
Thanks MT_dialog
你好
I have based my code on the driver in the SDK.
init代码:(从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);//为i2c启用时钟
setword16(i2c_enable_reg,0x0);//禁用I2C控制器
SetWord16(I2C_CON_REG, I2C_MASTER_MODE | I2C_SLAVE_DISABLE | I2C_RESTART_EN); // Slave is disabled
setBits16(i2c_con_reg,i2c_speed,speed);//设置速度
#ifdef I2C_SS_FREQ_TRIM
setword16(i2c_ss_scl_hcnt_reg,i2c_ss_scl_hcnt_val);//设置标准速度的SCL时钟高周期计数
setword16(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_hs_freq_trim.
setbits16(i2c_con_reg,i2c_10bitaddr_master,address_mode);//设置寻址模式
setword16(i2c_tar_reg,dev_address&0x3ff);//设置从设备地址
SetWord16(I2C_ENABLE_REG, 0x1); // Enable the I2C controller
wait_until_no_master_actity();//等待i2c主fsm变得空闲
i2c_dev_address = dev_address;
wait_until_no_master_actity();// Wait 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.
我在做错了吗?我希望只需调用send_i2c_command(),并查看Start,地址,字节,停止在总线上。我得到的只是开始,地址,停止。
我已经顺序放置了几个send_i2c_command(),但仍未看任何数据。
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!
你好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
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.
我不得不替换wait_for_received_byte()宏(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.
我发现添加一个wait_for_received_byte();在send_i2c_command(0x0100)之间;调用为I2C控制器产生足够的等待时间,以在总线上生成停止条件。
另一个观察结果是,当端口配置为I2C时,在14586内部存在相当强的拉起/高状态驱动器 - 我使用的设备为其“低”状态具有相当薄弱的驱动力为了将外部拉动电阻值增加到大约47K,只是为了让设备将总线拉低,以便它的ACK。我注意到,即使没有拉出电阻,也没有被配置为没有上拉的端口,在未驱动时仍然在总线上存在高状态。这与我以前使用的其他MICRO,这与I2C的开放收集器驱动器不同。对对话框的一个澄清是I2C硬件结构的阐明。
再次感谢您的帮助,我希望这些信息有助于使用DA14585或DA14586设备使用I2C设备!
I2C_ERROR_CODE I2C_READ_INT16(UINT32_T地址,UINT16_T * DATA)
{
uint8_t byte1 = 0;
uint8_t byte2 = 0;
//关键部分
global_int_disable();
i2c_send_address(address);
send_i2c_command(0x0100);//将R / W位设置为1(读取访问)
send_i2c_command(0x0100);//将R / W位设置为1(读取访问)
而(getword16(i2c_rxflr_reg)!= 2);//等待收到的数据
byte1 = 0xFF & GetWord16(I2C_DATA_CMD_REG); // Get received byte
byte2 = 0xff&getword16(i2c_data_cmd_reg);//获得收到的字节
GLOBAL_INT_RESTORE();
wait_until_i2c_fifo_is_empty();//等到TX FIFO是空的
wait_until_no_master_actity();// wait until no master activity
*data = ((byte2 << 8) | byte1);
return I2C_NO_ERROR;
}
你好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.
Thanks MT_dialog
谢谢您的支持,所有评论都在船上服用!