你好
我正在尝试接口I2C传感器设备(https://docs-emea.rs-online.com/webdocs/142c/0900766b8142cdd9.pdf.)
我已经在14586上使用另一个不同的传感器成功使用了I2C设备。
发送PROM或ADC读取请求后,此新传感器用2或3个字节的数据回复。
我基于I2C EEPROM示例的代码,无法让系统从回复中读取超过1个字节。
测试代码如下。我正在设置一个休息点,并在调试器看窗口中查看'byte1'和'byte2'。只有Byte1填充了任何数据。
我尝试了一些不同的方法,但仍然存在。我可以在我的Ocilloscope上看到,设备正在回复2个字节的数据,因此我很高兴基本通信正常工作。
任何投入都非常感谢!
代码:
//关键部分
global_int_disable();
i2c_send_address(地址);
send_i2c_command(0x0100);//将R / W位设置为1(读取访问)
//关键部分结束
global_int_restore();
uint16_t byte1 = 0;
uint16_t byte2 = 0;
wait_for_received_byte();//等待收到的数据
byte1 =(getword16(i2c_data_cmd_reg)&0xff);//获得第一个收到的字节
byte2 =(getword16(i2c_data_cmd_reg)&0xff);//问题似乎在这里......
wait_until_no_master_actity();//等到没有主活动
返回i2c_no_error;
设备:
嗨Boydy1989,
您只有一次调用send_i2c_command(0x100),这意味着58x的I2C模块只能访问一只读取的总线,因此您实际上只读一次,您就不会为您期望获得的第二个数据提供时钟,奴隶需要来自主站的时钟,以便将数据发送出来。例如,允许作为示例在SDK中的外围示例中的read_data_single()函数一次一次读取32字节的数据,因此该功能将发送想要通信的设备的地址和读取指示,然后它将开始使用读取命令0x100填充TX FIFO(0x100是一个凹陷的命令,该命令只会在总线上生成时钟),就像设备想要读取的字节一样多的读命令(32个字节也是FIFO。),然后可以从接收FIFO读取所有32个字节。
谢谢mt_dialog.
你好
感谢您的答复。
我现在正在努力努力,呼叫Send_i2c_command只会导致设备发送I2C设备地址(通过收到ACK)。
我无法发送任何数据。
代码片段:
send_i2c_command(0x1e);
连接在PDF上的逻辑输出。
我相信我错过了一些简单的东西,所有人都有助于极大地赞赏。
嗨Boydy1989,
那么,你已经使用的目标的地址是0xee?如果您在设备发出之前发送字节,则停止条件,I2C模块将继续发送其要与其通信的设备的地址。在代码段上,您只提供send_i2c_command(0x1e),如果您已正确初始化I2C模块,并且您只需使用send_i2c_command(0x1e)才能通过公共汽车发出字节字节(0x1e),我无法求出任何结论。然后,只要外部设备ACK的数据发送到58倍,就应该能够在总线上看到字节。如果您不想在I2C中使用SDK中的驱动程序,则可以将它们用作创建自己的驱动程序的引用。
谢谢mt_dialog.
你好
我在SDK的驱动程序上基于我的代码。
init代码:(从SDK复制)
void i2c_init(uint16_t dev_address,uint8_t speed,uint8_t地址_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);//从站被禁用
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);//将SCL时钟高周期计数设置为快速速度
setword16(i2c_fs_scl_lcnt_reg,i2c_fs_scl_lcnt_val);//设置快速速度的SCL时钟低周期计数
#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);//启用I2C控制器
wait_until_no_master_actity();//等待i2c主fsm变得空闲
i2c_dev_address = dev_address;
wait_until_no_master_actity();//等到没有主活动
}
我已经使用了设备的正确地址,好像我更改了地址,我不再看到我的逻辑分析仪上的ACK。
我在做错了吗?我希望只需调用send_i2c_command(),并查看Start,地址,字节,停止在总线上。我得到的只是开始,地址,停止。
我已经顺序放置了几个send_i2c_command(),但仍未看任何数据。
有没有办法通过586确认收到ACK的方法?或者,有些东西会阻止它收到Ack吗?
再次感谢!
嗨Boydy1989,
如果主机(585)在从从设备中获取ACK,则在每次尝试中为在总线上写入内容时,主模块将继续发送地址并等待ACK,每个SEND_I2C_COMMAND()将结果定义的目标地址以主机与从站通信。如果主设备没有从从机获得ACK,那么您不会看到您指示设备发送的字节。如果你没有得到一个ACK,那么附加的从设备有问题。关于检查是否已接收到外部设备的ACK,I2C_EEPROM.C中有一个名为i2c_wait_until_eeprom_ready()的函数,该函数将发送一个虚拟字节0x08,并检查i2c_tx_abrt_source_reg的abrt_7b_addr_noack位置,如果没有来自从站的ACK该位将设置为1,这意味着设备没有连接到地址。
谢谢mt_dialog.
你好
我现在已经取得了一些进步,并且正在正确接收数据。感谢您的帮助。
为了完整性,希望它将帮助别人在未来我将通过解释发布我的代码提取物 - 我发现这种微处理器的I2C控制器的文档不是很清楚,但我想我现在了解它。
以下代码将在I2C总线上传输以下序列:
addr_wr |reg_addr |addr_re |CLK |CLK.
我不得不替换wait_for_received_byte()宏(getword16(i2c_rxflr_reg)!= 2);
我发现尝试从FIFO读取数据,立即导致其中一个字节丢失。也许这是管道相关的,我不确定。
我发现添加一个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(地址);
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);//获得收到的字节
byte2 = 0xff&getword16(i2c_data_cmd_reg);//获得收到的字节
global_int_restore();
wait_until_i2c_fifo_is_empty();//等到TX FIFO是空的
wait_until_no_master_actity();//等到没有主活动
* data =((byte2 << 8)| byte1);
返回i2c_no_error;
}
嗨Boydy1989,
用于EEPROM的驱动程序非常完整和测试,因此应该基于该驱动程序的结构并将其作为参考,以及您的观察。
谢谢mt_dialog.
谢谢您的支持,所有评论都在船上服用!