I have a working I2C with an accelerometer connected to the dev board.
初始化后的通信工作。
在该单元转到Extended_sleep之后并唤醒I2C不再工作。目前只有I2C上的一个设备。电源未禁用。
这task gets stuck at ad_i2c.c:284 OS_EVENT_WAIT(dev_config->bus_data->event, OS_EVENT_FOREVER);
这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 contains
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, INPUT, I2C_SDA, false); //IC21 Data
hw_gpio_configure_pin(hw_gpio_port_4,hw_gpio_pin_7,输出,i2c_scl,false);// i2c1 clk.
hw_gpio_configure_pin (HW_GPIO_PORT_4, HW_GPIO_PIN_3, INPUT, GPIO, false); // accel irq
醒来后,示例说要改变线条。在Periph_init()中是否需要在延长睡眠后缺少I2C通信的情况下进行任何其他需要完成。
Thanks for your assistance.
I have probed the SCL line and there is no activity on the line after the extended sleep.
Hi 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-semicondiondiondum/forums/post/dialog-smartbond-bl ...
Thanks MT_dialog
当它出来的睡眠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.
因此,I2C Periph_Init的代码现在:
=================
hw_gpio_configure_pin (HW_GPIO_PORT_3, HW_GPIO_PIN_0, INPUT, I2C_SDA, false); //IC21 Data
hw_gpio_configure_pin(hw_gpio_port_4,hw_gpio_pin_7,输出,i2c_scl,false);// i2c1 clk.
hw_gpio_configure_pin (HW_GPIO_PORT_4, HW_GPIO_PIN_3, INPUT, GPIO, false); // accel irq
静态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); /* appears the adapter does not set the address when only one I2C device is on the bus?? */
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.
这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.
为什么当适配器假设为我这样做时,我必须设置目标Address?如果我没有在init中设置地址,那么我可以为设备读取所有寄存器的值0x07。这是仅在总线上具有一个设备的工件。
Hi Richard Legault,
As mentioned as a direct answer on the previous post those initialization are not necessary, since you are using the adapters in order to interact with the sensor, the adapter will re-enable and configure the I2C bus for you, you will just have to place the configuration of your pins in the periph_setup() function. So if you are using the adapters, you will just have to open the connection with the I2C device that you have declared in the platform_devices.h with ad_i2c_open() and start a transaction, with ad_i2c_transact() or ad_i2c_write(), ad_i2c_read() etc. So how do you trigger the transaction ?
Thanks MT_dialog
是的,这是预期的行为,但观察到的行为是我确实需要做那些3个步骤,否则I2C在延长睡眠时醒来时没有响应。
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()函数,ad_i2c_bus_apply_config()将为当前事务配置I2C模块(HW_I2C_INIT()/ hw_i2c_enable()
will be executed for the current transaction the master target address will be also set from the hw_i2c_init()). So if this is the only way that you can achieve
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
the system wakes up and with the below function i can read the name of the sensor.
/ *从传感器读取单独的阅读和写交易* /
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);
}
Thanks MT_dialog
是的,我开了一个开放。交易呼叫永远不会返回,因为它正在等待I2C完成。我用书写和读数替换了交易,但观察到的行为仍然是相同的。SDK为DA14681为1.0.8.1050.1
谢谢你与此保持一致。我很困惑为什么我在延长睡眠后没有看到预期的行为。
顺便说一下,当我执行HW_I2C_GET_ENABLE_STATUS_STATUS_STATUS()后,延长睡眠后返回0,除非我在PERIPH_INIT中有3个不必要的步骤。
在I2C_Handler()调用I2C-> Intr_CB的值为null。
I have not changed any of the retention settings but it looks like the memory (state) for the I2C is being lost during extended sleep.
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.我们为此创建了新的适当标题文件。
#define proj_configOPTIMAL_RETRAM (0)
#if !defined(RELEASE_BUILD) && (proj_configOPTIMAL_RETRAM == 1)
/ *警告:在调试版本中禁用了鼠尾优化!* /
#undef proj_configoptimal_retram.
#define proj_configOPTIMAL_RETRAM (0)
#elif(dg_configexec_mode!= mode_is_cached)
/ *警告:对镜像模式不适用于逆流优化!* /
#undef proj_configoptimal_retram.
#define proj_configOPTIMAL_RETRAM (0)
#万一
#if (proj_configOPTIMAL_RETRAM == 0)
#define dg_configMEM_RETENTION_MODE (0x1F)
#define dg_configSHUFFLING_MODE (0x3)
Hi Richard,
Can you please let me know, how do you trigger the I2C transaction in the code, where do you place the code in order for the device to start the interaction ?
Thanks MT_dialog
它是一项任务woken by an interrupt. I showed the call chain to kxcjbDevRegisterGet in a previous response.
由于中断不能使用适配器与I2C交互,因此当通过I2C读取中断清除寄存器时,任务必须清除中断。
这是中断处理程序(HW GPIO的清除由我写的WKUP处理程序完成。任务在检测到某个端口/引脚中断时,使用WKUP寄存器。
//the idea is that this is the top Half of the interrupt that it signals to have the bottom half (task) scheduled to run at a later time.
静态void kxcjbtapeventintr>(void * enceData)
{
// tp_interrupteventdata p_eventdata =(tp_interrupteventdata)eventData;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xtasknotifyfromisr(AccelIntractTaskHandle,Accel_Intr_Notify,Esetbits,
&xHigherPriorityTaskWoken);
portyield_from_isr(xhigherprioritytaskwoken);
return;
}
// 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 errCode;
bool st;
bool dataValid = false;
uint32_t notifyValue;
UINT8_T数据;
const timerhandle_t acceltimer = xtimercreate(“AcceltaskTimer”,
pdMS_TO_TICKS(750),
pdfalse,
(void *)0,
acceltimercallback);
而(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);
断言(errcode == errercode_ok);
ad_i2c_close(dev);
}
else if (notifyValue&ACCEL_DISABLE_NOTIFY) {
kxcjbinterruptdisable();
i2c_device dev = ad_i2c_open(Accel_kxcjb);
errCode =kxcjbBitsClear( dev, CTRL_REG1_ADDR, CTRL_REG1_PC1_EN);
断言(errcode == errercode_ok);
ad_i2c_close(dev);
g_accelState=ACCEL_STATE_DISABLE;
}
else
{
switch (g_accelState) {
case ACCEL_STATE_DISABLE:
/* do nothing */
break;
case ACCEL_STATE_0:
if (notifyValue & ACCEL_INTR_NOTIFY) {
kxcjbinterruptsrc(null,&accelsource [Accel_State_0]);
/* will handle the case where the timer is already running,
*不应该发生
* /
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);
/* test if we got source interrupt on the same axis
* 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();
}
别的 {
g_accelState = ACCEL_STATE_0;
}
if(gfp_tapeventcb){
gfp_tapEventCb(g_appInfo);
}
}
别的 {
printf("AC:TO\n\r");
fflush(stdout);
Xtimerreset(Acceltimer,0);
accelSource[ACCEL_STATE_0]=accelSource[ACCEL_STATE_1];
g_accelstate = Accel_State_1;/ *重新输入相同的状态* /
}
}
else if (notifyValue & ACCEL_TIMER_NOTIFY) {
g_accelState=ACCEL_STATE_0;
}
别的 {
assert (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
只调试;内核不使用。* /
accelTaskHL, /* The System Initialization task. */
( void * ) 0, /* The parameter passed to the task. */
configminimal_stack_size * os_stack_word_size * 2,
/ *分配给的字节数
stack of the task. */
OS_TASK_PRIORITY_HIGHEST, /* The priority assigned to the task. */
AccelInterractTaskHandle);/ *任务句柄* /
Hi Richard Legault,
So, you have configured the wake up timer in order to trigger sensor readings from the attached sensor, every time the sensor issues an interrupt you notify the task that triggers the reading, and you perform the read of data and clearing of the interrupt. Seems ok, what i dont quite get is the interrupt handler of the wakeup interrupt (i suppose that this is the kxcjbTapEventInterrupt, am i correct), why the handler has an event parameter ? Also its not recommended invoke the portYIELD_FROM_ISR (although i ve tested it and at least on my side it doesn't affect the I2C interaction when you are in sleep mode) and you should not run a task with a highest priority since this might affect other tasks (BLE task, power manager task etc). Anyway i dont think that those will cause any issues to the I2C, so my recomendation would be debug this and check if the code goes through the I2C interaction function, i mean the ad_i2c_read/write etc, also, you ve mentioned that the configuration after sleep is zero, the configuration for the I2C module is applied as soon as the i2c interaction functions are invoked ad_i2c_read/write etc. Also you could write a simpler code in order to test if the interaction with the i2c in simpler project (you could interact with the sensor via a simple timer or via the wake up timer - trigger the interrupt from a gpio) and check if that is working on your custom device then compare with the one that you have now. One last thing i 've noticed that the port that you are using for the I2C pins is PORT4 and PORT 3, be aware that if you are using the WCSP package those ports are not available.
Thanks MT_dialog
它似乎是由于使用gcc-arm-none-eabi-6-2017-q1-update(使用这个刀具链,我必须使用额外的步骤来获得I2c工作)。
随着提供的GCC工具链:4_9-2015Q3 I2C为广告工作。
感谢您的帮助和坚持不懈。
希望这可以节省他人的时间,知道工具链会影响文档的行为。
Hi Richard,
Thanks for indicating this, glad you have resolved your issue.
Best Regards MT_dialog