你好
我正在尝试接口到一个I2C传感器设备(https://docs-emea.rs-online.com/webdocs/142c/0900766b8142cdd9.pdf)
我已经成功地用另一个不同的传感器在14586上使用I2C设备。
这种新的传感器在发送PROM或ADC读请求时响应2或3字节的数据。
我已经基于I2C EEPROM示例编写了代码,并且无法让系统从应答中读取超过1个字节。
测试代码如下。我正在设置一个断点,并在调试器监视窗口中查看'byte1'和'byte2'。只有byte1填充了任何数据。
我尝试了一些不同的方法,但还是卡住了。我可以在我的示波器上看到设备正在回复2字节的数据,所以我很高兴基本的通信工作正常。
任何输入都非常感谢!
代码:
/ /关键部分
GLOBAL_INT_DISABLE ();
i2c_send_address(地址);
SEND_I2C_COMMAND (0 x0100);//设置R/W位为1 (read access)
//临界区结束
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_ACTIVITY ();//等待直到没有主活动
返回I2C_NO_ERROR;
设备:
嗨boydy1989,
你调用SEND_I2C_COMMAND (0 x100)只有一个时间,这意味着58 x的I2C模块只能访问总线一读,所以实际上你只读一次,你不提供时钟你期望得到第二个数据,和奴隶需要时钟从主为了发送数据。例如,让我们以read_data_single()函数为例,在SDK的外围例子中,它一次读取32字节的数据,因此该函数将发送想要通信的设备的地址和读取指示,然后它将开始填充Tx FIFO读命令0 x100 (0 x100是一个虚拟的命令,只会生成时钟总线),尽可能多的读命令字节设备想读也是FIFO)(32字节,那么所有的32个字节可以读取接收FIFO。
由于MT_dialog
你好
谢谢你的回复。
不过,我现在有点纠结,对SEND_I2C_COMMAND的任何调用都只会导致设备发送I2C设备地址(接收到一个ACK)。
我不能发送任何数据。
代码片段:
SEND_I2C_COMMAND (0 x1e);
逻辑输出附在PDF上。
我确信有一些简单的东西我错过了,所有的帮助非常感激。
嗨boydy1989,
您一直使用的目标地址是0xEE吗?如果在设备发出停止条件之前不发送一个字节,I2C模块将继续发送它想要通信的设备的地址。在代码片段中,您只提供了一个SEND_I2C_COMMAND(0x1E),如果您已经正确地初始化了I2C模块,并且您只是使用SEND_I2C_COMMAND(0x1E)通过总线发出字节,那么我无法从中得出任何结论;然后你应该能够看到通过总线的字节,只要外部设备ack的数据由58x发送。如果你不想使用I2C SDK中的驱动程序,你可以使用它们作为参考来创建你自己的驱动程序。
由于MT_dialog
嗨
我的代码基于SDK中的驱动程序。
初始化代码:(从SDK中复制)
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 0 x0);//关闭I2C控制器
SetWord16(I2C_CON_REG, I2C_MASTER_MODE | I2C_SLAVE_DISABLE | I2C_RESTART_EN);// Slave被禁用
SetBits16 (I2C_CON_REG, I2C_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 0 x1);//开启I2C控制器
WAIT_UNTIL_NO_MASTER_ACTIVITY ();//等待I2C主FSM变为IDLE状态
i2c_dev_address = dev_address;
WAIT_UNTIL_NO_MASTER_ACTIVITY ();//等待没有主活动
}
我已经为设备使用了正确的地址,就好像我改变了地址,我就不再在我的逻辑分析器上看到Ack。
我是否错误地发出字节?我希望只调用SEND_I2C_COMMAND(),并看到总线上的开始、地址、字节和停止。我只知道起点,地址,终点。
我已经连续放置了几个SEND_I2C_COMMAND(),但是仍然没有看到任何数据。
有没有办法确认586号收到Ack ?或者,有什么东西会阻止它接收Ack?
再次感谢!
嗨boydy1989,
如果主(585)不会ACK从奴隶设备在每一个尝试,你写一些在公共汽车上主模块将继续发送地址,等待ACK,每个SEND_I2C_COMMAND()将导致试图定义的目标地址的主人与奴隶。如果主服务器没有从从服务器获得ACK,那么你将看不到你指示设备发送的字节。如果你没有得到一个ACK,那么附属的从设备有问题。关于检查如果ACK从外部设备已经收到,有一个函数i2c_eeprom.c叫i2c_wait_until_eeprom_ready()函数会发送一个虚拟字节(和检查ABRT_7B_ADDR_NOACK I2C_TX_ABRT_SOURCE_REG的如果没有ACK的奴隶将被设置为1,也就是说这个装置还没有破解这个地址。
由于MT_dialog
你好
我现在有了一些进展,正在正确接收数据。谢谢你的帮助。
出于完整性的考虑,希望它能帮助别人在未来我将我的代码提取一个解释——我发现I2C控制器的微处理器的文档不是很清楚,不过我想我现在了解它。
下面的代码将在I2C总线上传输以下序列:
Addr_wr | reg_addr | addr_re | CLK | CLK
我必须替换WAIT_FOR_RECEIVED_BYTE()宏与while(GetWord16(I2C_RXFLR_REG) != 2);
我发现试图从FIFO读取数据会立即导致一个字节丢失。也许这和管道有关,我不确定。
我发现添加一个WAIT_FOR_RECEIVED_BYTE();SEND_I2C_COMMAND之间(0 x0100);调用产生足够的等待时间,使I2C控制器在总线上生成一个STOP条件。
另一个观察,我已经是一个相当强大的拉起/高14586年国家推动内部端口配置为I2C——我使用的设备已经相当薄弱的司机为其“低”,我不得不增加外部拉电阻器价值约47 k,只允许设备把总线低ACK。我注意到,即使没有上拉电阻,端口配置为没有上拉,当未驱动时,总线上仍然有一个高状态。这与我以前使用过的其他微处理器不同,后者对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(地址);
SEND_I2C_COMMAND (0 x0100);//设置R/W位为1 (read access)
SEND_I2C_COMMAND (0 x0100);//设置R/W位为1 (read access)
而(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_ACTIVITY ();//等待直到没有主活动
*数据= ((byte2 << 8) | byte1);
返回I2C_NO_ERROR;
}
嗨boydy1989,
用于eeprom的驱动程序是相当完整和测试的,所以应该基于该驱动程序的结构,并使用它作为参考,根据您的观察。
由于MT_dialog
谢谢你的支持,所有的意见都被采纳了!