我有一个工作I2C,加速度计连接到DEV板。
Communication works after initialization.
After the unit goes to Extended_Sleep and wakes the I2C is no longer working. There is currently only the one device on the I2C. The Power is not disabled.
The task gets stuck at ad_i2c.c:284 OS_EVENT_WAIT(dev_config->bus_data->event, OS_EVENT_FOREVER);
The interrupt fires one time but I cannot clear it because I need to read an address to clear the pin from the accelerometer side. So the accelermeter appears to be still working.
I have one time init of I2C_BUS_INIT(I2C1) and I2C_DEVICE_INIT(ACCEL_KXCJB).
platform_devices.h包含
I2C_BUS(I2C1)
i2c_slave_device(i2c1,Accel_kxcjb,0x0e,
HW_I2C_ADDRESSING_7B, HW_I2C_SPEED_FAST);
I2C_BUS_END.
periph_init() contains (using the HW_GPIO_PINCONFIG macro so the names get extended properly)
hw_gpio_configure_pin(hw_gpio_port_3,hw_gpio_pin_0,输入,i2c_sda,false);// IC21数据
hw_gpio_configure_pin(HW_GPIO_PORT_4, HW_GPIO_PIN_7, OUTPUT, I2C_SCL, false); // I2C1 CLK
hw_gpio_configure_pin(HW_GPIO_PORT_4, HW_GPIO_PIN_3, INPUT, GPIO, false); // accel irq
After the wake up the examples say to reinit the lines. Is there anything else that needs to be done in periph_init() that I am missing for I2C communication to work after extended sleep.
感谢你的协助。
我已经探测了SCL线and there is no activity on the line after the extended sleep.
嗨Richard Legault,
I dont see anything missing from the configuration that you mention, how do you trigger the reading of the sensor memory etc from the system ? The part of the code that the device stalls is because it waits for an the complete event from the I2C module and apparently nothing occurs.
Also please have a look at the post below, perhaps this will help:
https://support.dialog-semiconductor.com/forums/post/dialog-smartbond-bl...
谢谢mt_dialog.
When it comes out of sleep the I2C status is 0 (disabled).
To get the I2C functional again it was not enough to do hw_i2c_enable(HW_I2C1) I had to also init the bus and set the target address.
Thus the code for the I2C periph_init is now:
=================.
hw_gpio_configure_pin(hw_gpio_port_3,hw_gpio_pin_0,输入,i2c_sda,false);// IC21数据
hw_gpio_configure_pin(HW_GPIO_PORT_4, HW_GPIO_PIN_7, OUTPUT, I2C_SCL, false); // I2C1 CLK
hw_gpio_configure_pin(HW_GPIO_PORT_4, HW_GPIO_PIN_3, INPUT, GPIO, false); // accel irq
static const i2c_config cfg = {
.speed = hw_i2c_speed_fast,
。mode = HW_I2C_MODE_MASTER,
。addr_mode = HW_I2C_ADDRESSING_7B,
};
hw_i2c_init(HW_I2C1, &cfg);
hw_i2c_set_target_address(hw_i2c1,0x0e);/ *出现适配器在公共汽车上只有一个I2C设备时,适配器不会设置地址?* /
hw_i2c_enable(HW_I2C1);
=================.===
它没有在示例或文档mention that these init steps needs to be done when coming out of sleep. I only discovered this from the link in the previous response.
The question is: is this initialization needed for proper behaviour after a deep sleep or is this a bug in the i2c adapter or hw_i2c code. Does the adapter update the device address even for busses with only one device.
为什么我要当广告设置TargetAddressapter is suppose to do this for me? If I don't set the address in init, then I get a value of 0x07 for all register reads from the device. Is this an artifact of only having one device on the bus.
嗨Richard Legault,
如上所述,由于之前的帖子上的直接答案不需要,因为您正在使用适配器才能与传感器进行交互,因此适配器将重新启用并为您配置I2C总线,您只需要放置PERIPH_SETUP()函数中的PIN配置。因此,如果您使用的适配器,您将只需使用ad_i2c_open()中声明的I2C设备“和”AD_I2C_TRANSACT()或AD_I2C_WRITE(),AD_I2C_READ()“开始”将打开“已声明的I2C设备”。等等,你如何触发交易?
谢谢mt_dialog.
是的,这是预期的behaviour but the observed behaviour is that I do need to do those 3 steps otherwise I2C does not respond when waking from extended sleep.
Hi Richard
Its the expected and how the system behaves indeed, if you invoke one the functions i ve mentioned above in order to start the interaction the I2C module, the
ad_i2c_bus_aquire() function is invoked and the ad_i2c_bus_apply_config() will configure the I2C module for the current transaction (hw_i2c_init() / hw_i2c_enable()
将为当前事务执行主目标地址,也将从HW_I2C_INIT()设置)。所以,如果这是你可以实现的唯一方式
I2C communication perhaps you dont use the adapter in order to trigger a I2C interaction. For example i read a sensor's value periodically from an RTOS timer, so
系统唤醒,使用以下功能,我可以读取传感器的名称。
/*Read from sensor with seperate read and write transactions*/
void read_mpu_reg_rw(uint8_t reg_addr)
{
static uint8_t who_i_am_rw = 0;
uint8_t addr = reg_addr;
MPU6050 = AD_I2C_OPEN(MPU_6050);
ad_i2c_write(mpu6050, ®_addr, 1);
ad_i2c_read(mpu6050, &who_i_am_rw, 1);
printf(“%02x \ n \ r”,who_i_am_rw);
}
谢谢mt_dialog.
Yes I do an open. The transact call never returns as it is waiting for an I2C to complete. I replaced the transact with write and read but the behaviour I have observed has remained the same. The SDK is 1.0.8.1050.1 for the DA14681
Thanks for keeping with this. I am confused as to why I am not seeing the expected behaviour after the extended sleep.
By the way when I do a hw_i2c_get_enable_status() it returns 0 after an extended sleep unless I have the 3 unnecessary steps in the periph_init.
In the I2C_Handler() call the value for i2c->intr_cb is NULL.
我没有改变任何保留设置,但它看起来像I2C的内存(状态)在延长睡眠期间丢失。
Could there be something there that is causing this behaviour?Do note that we have replaced the 8MBit winbond with a 64MBit winbond Flash part.We have created the new appropriate header file for it.
#define proj_configoptimal_retram(0)
#if!定义(Reford_Build)&&(proj_configoptimal_retram == 1)
/* WARNING: retRAM optimizations are disabled in DEBUG builds! */
#undef proj_configOPTIMAL_RETRAM
#define proj_configoptimal_retram(0)
#elif (dg_configEXEC_MODE != MODE_IS_CACHED)
/* WARNING: retRAM optimizations are not applicable in MIRRORED mode! */
#undef proj_configOPTIMAL_RETRAM
#define proj_configoptimal_retram(0)
#endif
#if (proj_configOPTIMAL_RETRAM == 0)
#define dg_configMEM_RETENTION_MODE (0x1F)
#define dg_configSHUFFLING_MODE (0x3)
Hi Richard,
你能告诉我,如何在代码中触发i2c事务的方式,您在哪里放置代码,以便设备启动交互?
谢谢mt_dialog.
It is within a task that is woken by an interrupt. I showed the call chain to kxcjbDevRegisterGet in a previous response.
Since interrupts cannot use adapters to interact with I2C, the task has to clear the interrupt when it reads the interrupt clearing register via I2C.
Here is the interrupt handler (The clearing of the HW GPIO is done by the WKUP handler I wrote. Tasks register with WKUP to have their handler called when a certain PORT/PIN interrupt is detected.
//这个想法是,这是中断的顶部,即它向稍后的时间运行的下半部分(任务)的信号。
static void kxcjbTapEventInterrupt(void* eventData)
{
//tp_interruptEventData p_eventData = (tp_interruptEventData) eventData;
baseType_t xhigherprioritytaskwoken = pdfalse;
xTaskNotifyFromISR( accelInterruptTaskHandle, ACCEL_INTR_NOTIFY, eSetBits,
&xHigherPriorityTaskWoken);
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
返回;
}
// HERE IS THE TASK //
//the idea is that this is the bottom Half of the interrupt that is scheduled to run at a later time.
static void accelTaskHL( void *pvParameters )
{
/* define variables static to get it off the stack */
static uint8_t accelSource[2];
t_errorcode错误码;
bool st;
bool datavalid = false;
UINT32_T NotifyValue;
uint8_t data;
const TimerHandle_t accelTimer = xTimerCreate( "accelTaskTimer",
pdMS_TO_TICKS(750),
pdFALSE,
(void *)0,
accelTimerCallback);
while (1)
{
xTaskNotifyWait(0x00, ULONG_MAX, ¬ifyValue, portMAX_DELAY); // WAIT here for the next signal: Interrupt, Timeout, or control message
kxcjbDevRegisterGet(NULL, WHOAMI_ADDR, &data);// Within this function I do the ad_i2c_transact()
if (notifyValue&ACCEL_ENABLE_NOTIFY) {
g_accelState=ACCEL_STATE_0;
kxcjbInterruptEnable();
i2c_device dev = ad_i2c_open(ACCEL_KXCJB);
errCode = kxcjbBitsSet( dev, CTRL_REG1_ADDR, CTRL_REG1_PC1_EN);
assert(errCode==ERRORCODE_OK);
ad_i2c_close(dev);
}
else if (notifyValue&ACCEL_DISABLE_NOTIFY) {
kxcjbInterruptDisable();
i2c_device dev = ad_i2c_open(ACCEL_KXCJB);
errcode = kxcjbbitleclear(dev,ctrl_reg1_addr,ctrl_reg1_pc1_en);
assert(errCode==ERRORCODE_OK);
ad_i2c_close(dev);
g_accelState=ACCEL_STATE_DISABLE;
}
else
{
switch (g_accelState) {
案例Accel_State_disable:
/* 没做什么 */
break;
case ACCEL_STATE_0:
if(notifyValue&Accel_Intr_Notify){
kxcjbInterruptSrc(NULL, &accelSource[ACCEL_STATE_0]);
/ *将处理计时器已经运行的情况,
*should not happen
* /
xTimerReset(accelTimer, 0);
g_accelState=ACCEL_STATE_1;
}
/* else we are ignoring the timer interrupt, should not happen */
break;
case ACCEL_STATE_1:
if(notifyValue&Accel_Intr_Notify){
kxcjbInterruptSrc(NULL, &accelSource[ACCEL_STATE_1]);
printf ("0=0x%02x\n\r1=0x%02x\n\r",accelSource[0],accelSource[1]);
fflush(stdout);
/ *测试是否在同一轴上有源中断
*as occurred in previous interrupt
* /
if(((Accelsource [Accel_State_0]&(int_source2_xpwu | Int_source2_xnwu))
&&(accelSource[ACCEL_STATE_1]&(INT_SOURCE2_XPWU|INT_SOURCE2_XNWU))
)||
( (accelSource[ACCEL_STATE_0]&(INT_SOURCE2_YPWU|INT_SOURCE2_YNWU))
&&(accelSource[ACCEL_STATE_1]&(INT_SOURCE2_YPWU|INT_SOURCE2_YNWU))
)||
( (accelSource[ACCEL_STATE_0]&(INT_SOURCE2_ZPWU|INT_SOURCE2_ZNWU))
&&(accelSource[ACCEL_STATE_1]&(INT_SOURCE2_ZPWU|INT_SOURCE2_ZNWU))
)
){
xTimerStop(accelTimer, 0);
if (ACCEL_TASK_DISABLE_ON_TAP_DETECT) {
g_accelState = ACCEL_STATE_DISABLE;
kxcjbInterruptDisable();
}
else {
g_accelstate = Accel_State_0;
}
if (gfp_tapEventCb) {
gfp_tapeventcb(g_appinfo);
}
}
else {
printf("AC:TO\n\r");
fflush(stdout);
xTimerReset(accelTimer, 0);
Accelsource [Accel_State_0] = Accelsource [Accel_State_1];
g_accelState = ACCEL_STATE_1; /* reenter the same state */
}
}
else if (notifyValue & ACCEL_TIMER_NOTIFY) {
g_accelState=ACCEL_STATE_0;
}
else {
断言(0 == 1);
}
}
}
}
}
// Here is the code that creates the task,
uint32_t status = OS_TASK_CREATE("AccelInterruptHL", /* The text name assigned to the task, for
debug only; not used by the kernel. */
accelTaskHL, /* The System Initialization task. */
( void * ) 0, /* The parameter passed to the task. */
configMINIMAL_STACK_SIZE * OS_STACK_WORD_SIZE * 2,
/* The number of bytes to allocate to the
stack of the task. */
OS_TASK_PRIORITY_HIGHEST,/ *分配给任务的优先级。* /
accelInterruptTaskHandle ); /* The task handle */
嗨Richard Legault,
因此,您已经配置了唤醒定时器,以便从附加的传感器触发传感器读数,每次传感器发出中断时,您通知触发读数的任务,并且您执行读取数据并清除中断清除。似乎好的,我不太得到的是唤醒中断的中断处理程序(我想这是KxcjbtapeventInterrupt,我是正确的),为什么处理程序有一个事件参数?此外,不建议调用portyield_from_isr(虽然我在睡眠模式下测试了它,并且至少在我的侧面时,它不会影响I2C交互),并且您不应该以最高优先级运行任务,因为这可能会影响其他任务(BLE任务,Power Manager任务等)。无论如何,我不认为那些会对I2C造成任何问题,所以我的推荐将调试它并检查代码是否通过I2C交互功能,我的意思是AD_I2C_READ / WRITE等,也,您提到的是配置的配置睡眠为零,一旦I2C交互功能被调用AD_I2C_READ / WRITE等,也可以应用I2C模块的配置。此外,您还可以编写更简单的代码,以测试与I2C中更简单的项目(您可以进行交互)通过简单的计时器或通过唤醒定时器使用传感器 - 从GPIO触发中断)并检查其在您的自定义设备上工作,然后与您现在的那个相比。最后一件事我注意到,您正在使用的I2C引脚的端口是Port4和Port 3,请注意,如果您使用的是WCSP包,则这些端口不可用。
谢谢mt_dialog.
It appears to be due to using gcc-arm-none-eabi-6-2017-q1-update ( with this tool chain I have to use the extra steps to get I2C to work).
With the provided gcc tool chain: 4_9-2015q3 the I2C works as advertised.
Thanks for your assistance and perseverance on this.
Hopefully this saves others time, knowing that the tool chain affects the documented behaviour.
Hi Richard,
感谢您的表明,很高兴您解决了您的问题。
Best Regards MT_dialog