你好,
我试着和传感器沟通。传感器数据表说我需要写一个测量的命令。它的值(12或14位)存储在内存中。为了得到这个数据,我必须读出2个字节。但每当我试图读取数据I2c_eeprom_read_data (uint8_t *rd_data_ptr, uint32_t address, uint32_t size)
“我被困住了”read_data_single ()
“在……”WAIT_FOR_RECEIVED_BYTE ();
”循环。似乎DA14580没有收到什么东西。
为* rd_data_ptr
我得到了一个指向值变量的指针uint32_t mes_val
.对于地址,我使用了theI2C_SLAVE_ADDRESS
由user_外围_setup.h配置。为大小
我用2表示两个字节。
我能做什么来接收两个字节?它是如何存储的?我需要将值存储在一个大小为2Bytes的变量中。发送“read”命令后,传感器发送“MOST_SIGNIFICANT_BYTE”_ACK_“LEAST_SIGNIFICANT_BYTE”_ACK_(可能是校验和)_NACK_ STOP_CONDITION。
为了更好地描述它,我也尝试了i2c_eeprom_read_byte
获取第一个字节。但这也行不通。另外,ble连接丢失了,我无法重新连接。整个系统只是处于“等待循环”中。我得取消,重置,重新启动系统才能让蓝牙重新工作。我想通过写1到一个特征值的ble命令触发测量。在将1写入char值时,应该触发用于测量的触发器命令(1字节长度)。之后,我想读出值(2字节),这将存储在另一个特征。
当一切工作时,我想使用通知更新我的手机上的值与传感器的新值。
谢谢!
1月
设备:
嗨JanFeld,
如果您被困在WAIT_FOR_RECEIVE_BYTE()中,那么580没有从另一边接收任何东西。我不认为这是由于代码实现,而是由于与580和传感器的连接,或者传感器出于某种原因从不响应您发送的命令。在这种情况下,捕获一个逻辑分析器会有很大帮助。
对于BLE, I2C驱动轮询I2C接口以获取一些数据,由于没有数据返回,驱动一直等待,由于M0粘在I2C轮询上,BLE连接丢失。您必须获取I2C总线的捕获,看看580在总线上发送了什么,是否正确(传感器获得了他想要的命令),以及是否有来自传感器的应答。
关于I2C驱动的读取过程,你可以使用read_data_single()函数设置你想要读取的传感器地址(一些传感器的内部地址),并设置大小为2。这将迫使驱动程序发送两个时钟周期,以便从您声明的指定地址读取数据。然后,驱动程序将把您接收到的数据作为参数传递到函数的指针中。
由于MT_dialog
谢谢你的回答。我没有任何关于传感器内部地址的信息。通过arduino,它工作得很好。我发送“测量CMD”到传感器,等待一些毫秒,而它正在测量,然后我发送读请求。之后我将读取两个字节的数据。没有传感器的内部地址。我认为是这样的:
µC: _____ S___ADDR + WR_BIT_____Meas_CMD_____ADDR + RD_BIT______ACK_____ACK ____________ NACK___P
传感器 :______________________ 消 ____________ 消 _________________ MSB______LSB_____CHECKSUM __________
这是传感器数据表中描述的。没有特定的指针指令地址可用。是否有其他方法来接收这些值?比如一个“听”功能?
我会尽快用示波器分析传输。但也许你知道我能做什么。
谢谢,
1月
嗨JanFeld,
似乎必须将Meas_CMD作为大小为2的read_data_single()中的地址参数发送,以便执行两次读取。为了i2c传感器提供一些值回它需要知道数据emmit和设备,或一般要做什么,所以你必须提供设备的i2c总线地址,您还想交流和写传感器(i2c的写命令)你要什么值(Meas_CMD)。因此,当您尝试使用read_data_single()函数访问总线时,I2C将自动提供从设备的地址,您应该在I2C模块初始化(在i2c_init()中)和写位中设置该地址。一旦i2c_send_address(Meas_CMD)被执行之后,总线上的从地址(Meas_CMD)就会跟上,然后I2C模块将提供时钟从传感器获取两个字节。我希望我说得够清楚了。
由于MT_dialog
你好,还是不能用。我试图将MEAS_CMD作为地址参数发送。
我附上了传感器数据表中的方案。它显示了传感器工作的通信顺序。到目前为止,我看不到i2c_eeprom文件中可以提供这种通信流的可能性。
在尝试接收字节时,我仍然会卡住。
在我的理解中,我必须发送与写函数的测量命令。我没有内存地址,只有传感器的I2C地址。在测量之后(20 -80µs之间),我可以发送一个读命令(i2c_address +读位)。然后传感器开始发送数据。首先是最高位字节。当收到它时,DA14580必须提供ACK。然后将发送第二个字节(LSB)(随后是DA14580的ACK)。校验和将最后发送。
是我对它的工作原理有错误的理解还是有其他我看不到的东西?
为了通信,两条通信线路都必须上拉。我使用内部拉我设置在“ConfigurePin(......INPUT_PULLUP.....)“这是错的吗?我也试过外引体向上。(
ConfigurePin(…输入……)
).也没有工作。谢谢,
1月
嗨JanFeld,
正如我所提到的,如果没有捕获,就没有简单的调试方法,您将不得不检查总线上的信号,仅凭推测我们无法跟踪问题的原因。你必须检查I2C总线上有什么输出。I2C功能当执行一个读将执行写第一次(最后一点I2C奴隶地址设置为0),为了写设备的内部地址,或者一个命令在你的情况中,然后将读取命令(奴隶地址最后位设置为1)为了从传感器开始阅读,您不会在写和读命令之间发出延迟。您可以检查的是传感器I2C的配置,如果它对应于初始化期间I2C模块的设置。但是为了解决这个问题你真的需要捕获总线。
由于MT_dialog
你好再次,
我用示波器检查了通信,发现
SEND_I2C_COMMAND
不正常工作。当我想写一个命令,它发送ADDR+WR_BIT后,该命令被移到右边一位。(大多数时候,不是所有时候…有时它的工作原理)例如:
SEND_I2C_COMMAND (0 xf3)
将发送:ADDR+WR_BIT和0x71作为命令。(1000'0000作为7位地址。+ wr位0和0111'1001而不是1111'0011)。地址是正确的,有时它能工作,传感器也能工作。但是大多数情况下它不会工作并且发送错误的值。我读东西的时候也是这样。我想发送
SEND_I2C_COMMAND (0 x0100)
.它发送:ADDR+WR_BIT(而不是RD_BIT),然后是一些随机值。有时它工作,它发送ADDR+RD_BIT。(10000001)但是大多数时候它不能正常工作。我的另一个问题是,是ACK后收到的字节自动设置或我必须手动设置它ACK的第一个字节,以便传感器可以发送第二个?
谢谢,
1月
嗨JanFeld,
关于SEND_I2C_COMMAND(),我不认为该命令必须做什么你所面临的,如果有时它工作,其他它不我认为它必须做一些与你的连接。
I2C控制器将生成ACK的时候,他收到的数据自动,你不需要做任何额外的代码。
由于MT_dialog
你好,
我有相同的问题,我卡住了当读取多字节在I2C总线。我已经从“i2c_eeprom.c”中的一个修改了I2C-Multi-read函数。功能描述如下。
而问题是,当我试图从传感器(加速计MMA8652)读取192个字节时,程序将停止在“WAIT_FOR_RECEIVED_BYTE();”,其中已经读取的数据的索引总是66(dec)。
并且我从逻辑信号分析仪上得到了通信图,看起来DA14580和加速度计之间的通信是正确的,信号持续了192个字节的周期!当我删除代码“WAIT_FOR_RECEIVED_BYTE”时,整个周期的时间是相同的。根据图表,甚至在I2C-STOP信号之前就有了可用的数据。
所以,似乎DA14580和加速度计之间的“连接问题”不是正确的原因。
希望你的帮助。
无效I2C_ReadMultiByte(uint8_t regAddr, uint8_t data[], uint8_t size)
{
uint8_t指数;
WAIT_UNTIL_I2C_FIFO_IS_EMPTY ();
WAIT_UNTIL_NO_MASTER_ACTIVITY ();
//注册地址
SEND_I2C_COMMAND (regAddr);
For (index = 0;指数<大小;指数+ +)
{
WAIT_WHILE_I2C_FIFO_IS_FULL ();//如果Tx FIFO已满,则等待
SEND_I2C_COMMAND (0 x0100);//设置读访问次数
}
//读取的数据
For (index = 0;指数<大小;指数+ +)
{
WAIT_FOR_RECEIVED_BYTE ();
数据[index] = (uint8_t)(GetWord16(I2C_DATA_CMD_REG) & 0xFF);
}
}
以及I2C控制器的初始化:
i2cInitParam_t参数;
参数。periAdrr = 0 x1d;
参数。addressMode = I2C_7BIT_ADDR;
参数。speedMode = I2C_FAST;
void I2C_Init(const i2cInitParam_t *param)
{
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, param - > speedMode);/ /设置速度
SetBits16 (I2C_CON_REG I2C_10BITADDR_MASTER, param - > addressMode);//设置寻址模式
SetWord16(I2C_TAR_REG, param->periAdrr & 0x3FF);//设置从设备地址
SetWord16 (I2C_ENABLE_REG 0 x1);//开启I2C控制器
while(GetWord16(I2C_STATUS_REG) & 0x20) != 0);//等待I2C主FSM处于IDLE状态
}
你好,
我有相同的问题,我卡住了当读取多字节在I2C总线。我已经从“i2c_eeprom.c”中的一个修改了I2C-Multi-read函数。功能描述如下。
而问题是,当我试图从传感器(加速计MMA8652)读取192个字节时,程序将停止在“WAIT_FOR_RECEIVED_BYTE();”,其中已经读取的数据的索引总是66(dec)。
并且我从逻辑信号分析仪上得到了通信图,看起来DA14580和加速度计之间的通信是正确的,信号持续了192个字节的周期!当我删除代码“WAIT_FOR_RECEIVED_BYTE”时,整个周期的时间是相同的。根据图表,甚至在I2C-STOP信号之前就有了可用的数据。
所以,似乎DA14580和加速度计之间的“连接问题”不是正确的原因。
希望你的帮助。
无效I2C_ReadMultiByte(uint8_t regAddr, uint8_t data[], uint8_t size)
{
uint8_t指数;
WAIT_UNTIL_I2C_FIFO_IS_EMPTY ();
WAIT_UNTIL_NO_MASTER_ACTIVITY ();
//注册地址
SEND_I2C_COMMAND (regAddr);
For (index = 0;指数<大小;指数+ +)
{
WAIT_WHILE_I2C_FIFO_IS_FULL ();//如果Tx FIFO已满,则等待
SEND_I2C_COMMAND (0 x0100);//设置读访问次数
}
//读取的数据
For (index = 0;指数<大小;指数+ +)
{
WAIT_FOR_RECEIVED_BYTE ();
数据[index] = (uint8_t)(GetWord16(I2C_DATA_CMD_REG) & 0xFF);
}
}
以及I2C控制器的初始化:
i2cInitParam_t参数;
参数。periAdrr = 0 x1d;
参数。addressMode = I2C_7BIT_ADDR;
参数。speedMode = I2C_FAST;
void I2C_Init(const i2cInitParam_t *param)
{
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, param - > speedMode);/ /设置速度
SetBits16 (I2C_CON_REG I2C_10BITADDR_MASTER, param - > addressMode);//设置寻址模式
SetWord16(I2C_TAR_REG, param->periAdrr & 0x3FF);//设置从设备地址
SetWord16 (I2C_ENABLE_REG 0 x1);//开启I2C控制器
while(GetWord16(I2C_STATUS_REG) & 0x20) != 0);//等待I2C主FSM处于IDLE状态
}
我有一个解决方案,为我工作,但我认为它可能不足够安全的许多字节在一行。但也许你可以试试…
我通过删除
WAIT_FOR_RECEIVED_BYTE ();
然后直接获取值并通过指针将其保存到数组中。我的函数现在是这样的:
空白i2c_cust_read_bytes (uint8_t * val_ptr)
{
val_ptr [0] = 0 x00;
val_ptr [1] = 0 x00;
WAIT_UNTIL_NO_MASTER_ACTIVITY ();
SEND_I2C_COMMAND (0 x0100);
WAIT_WHILE_I2C_FIFO_IS_FULL ();
val_ptr [1] = GetWord16 (I2C_DATA_CMD_REG);
SEND_I2C_COMMAND (0 x0100);
WAIT_WHILE_I2C_FIFO_IS_FULL ();
val_ptr[0] = GetWord16(I2C_DATA_CMD_REG) & 0xFC;
}
这对我很有效。我得到数组第二个元素的第一个值的原因只是我想让它在那里。您可以选择要指向哪个元素。
我想应该是这样的:
起初:没有大师活动。
然后发送“READ_CMD”. .等待FIFO为空接收新字节(当将地址+读位和0x00写入I2C_DATA_CMD_REG时被清除)。
然后保存到您想要的变量。再次发送一个READ_CMD,它将覆盖I2C_DATA_CMD_REG中保存的值,并对您希望在一行中接收的每个字节重复该操作。
对于两个值,它可能工作,但我不知道是否有可能和保存接收超过一个或两个字节在一行没有错误或改变位。
遗憾的是,我仍然不知道为什么WAIT_FOR_RECEIVED_BYTE()不为我工作。
希望我能帮到你。
欢呼,
1月
你好,
你是否试过使用I2C驱动程序(i2c_eeprom_read_data)。捕捉你的高度我看到没有停止条件从580年为了读取数据(FIFO满-32时钟周期emmited和32字节的数据已收到,所以proccessor应该开始阅读FIFO和把数据从I2C FIFO缓冲区),当FIFO满时,你正在读取数据吗?WAIT_FOR_RECEIVED_BYTE检查I2C_RX_FLR_REG,这个寄存器包含接收到的有效数据,并且位于FIFO中,如果在FIFO中没有数据,它将被卡在while中,因为它被指示读取。在代码中,输入的大小是多少?如果你调用的功能,你提到超过32,那么你的FIFO是满的,在FIFO的数据是重写的下一个传入的数据。如果你检查I2C_eeprom司机你会看到i2c_eeprom_read_data是阅读的数据使用read_data_single eepm在32的倍数()函数和当FIFO满32字节I2C模块将停止时钟读取32个字节的数据。
Thansk MT_dialog
嗨。
我遇到了同样的问题,也找到了解决办法。
你可以用这个代码读取两个字节。
关键是I2C_CON_REG的I2C_RESTART_EN位禁用。
空白init_i2c(空白)
{
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被禁用
SetWord16(I2C_CON_REG, I2C_MASTER_MODE | I2C_SLAVE_DISABLE);
SetBits16 (I2C_CON_REG I2C_SPEED I2C_STANDARD);/ /设置速度
SetBits16 (I2C_CON_REG I2C_10BITADDR_MASTER I2C_7BIT_ADDR);//设置寻址模式
// I2C设备地址设置。
SetWord16 (I2C_TAR_REG、地址);//设置从设备地址
SetWord16 (I2C_ENABLE_REG 0 x1);//开启I2C控制器
while(GetWord16(I2C_STATUS_REG) & 0x20) != 0);//等待I2C主FSM处于IDLE状态
}
无符号短readShortI2C(空白)
{
无符号短v, v1, v2;
WAIT_WHILE_I2C_FIFO_IS_FULL ();//设置R/W位为1 (read access)
SEND_I2C_COMMAND (0 x0100);//设置读访问次数。所以是2次调用
WAIT_WHILE_I2C_FIFO_IS_FULL ();
SEND_I2C_COMMAND (0 x0100);
WAIT_FOR_RECEIVED_BYTE ();//等待收到的数据
v1 = 0xFF & GetWord16(I2C_DATA_CMD_REG);//接收字节,MSB
WAIT_FOR_RECEIVED_BYTE ();//等待收到的数据
v2 = (0xFF & GetWord16(I2C_DATA_CMD_REG));//接收字节,LSB
V = v1<<8;
arch_printf(“04 x: \ r \ nV % % 04 x = % 04 x (% d)”,v1、v2, v, v);
返回v;
}
谢谢你!