嗨,对话框,
I build a app based on px reporter, add a timer to read data from I2C bus through adapter when connected to a central device.
the most strange thing was, it worked well when in jlink jtag mode, but halted after connected and send several packets of data when work alone. I used attach function and found it ended in the loop of hw_hard_fault.c.
What would be the reason?
Thanks a lot.
问候。
Duan
Device:
嗨段,
The hard fault hander (the functionHardFault_HandlerC in the file hw_hard_fault.c) copies the stack frame to a fixed location in memory. This stack frame contains a number of parameters that will help you find the source of the hard fault. The first one to start with is the PC - this is the value of the program counter at the time the hard fault occured i.e. it will point to the instruction that was being executed and that caused the hard fault. You can access the value of the PC using the debugger. After you have attached and find the code executing the while(1) loop in the hardfault handler examine memory location STATUS_BASE + 0x18 - this will contain the value of the PC. The value of STATUS_BASE can be found in the hw_hard_fault.c file. Once you have the PC you can find out which instruction (and therefore whch line of C code) is causing the hard fault.
IM_Dialog
Thank you for you help. Follow your instructions, I found the pc of the hardware fault cause was 0x7fd11e0 .
Is it helpful to find out what happened?
嗨,对话框,
I did a series of tests this weekend:
1. simplified my code only included one init function, to init gpio and I2C async transact, one read function, read registers from IMU, and print it to uart.
2. move my driver code to a "clean" ble_peripheral project, add init at beginning of task start, add a timer to ble_peripheral_task and start it before for(;;) loop, and read data from I2C when task receive timer notify.
void ble_peripheral_task(void *params)
{
int8_t wdog_id;
ble_service_t *svc;
OS_TASK handle = NULL;
my_peripheral_init();
...
sns_timer = OS_TIMER_CREATE(“社交”,portCONVERT_MS_2_TICKS(100), OS_TIMER_SUCCESS,
(void *) OS_GET_CURRENT_TASK(), sns_timer_cb);
OS_ASSERT(sns_timer);
OS_TIMER_START(sns_timer, OS_TIMER_FOREVER);
...
if (notif & SNS_TIMER_NOTIF) {
refresh_sensor();
}
...
but after several seconds, the uart print stopped. when ATTCH, I found the program ran at line 2132 of sys_power_mgr.c:
// Suspend any ongoing QSPI program / erase operations.
if (op != NULL) { //2132
DBG_SET_HIGH(FLASH_DEBUG, FLASHDBG_SUSPEND);
if (qspi_check_and_suspend()) {
op->suspended = true;
}
DBG_SET_LOW(FLASH_DEBUG, FLASHDBG_SUSPEND);
}
}
3. And I tried another way, delete the sns_timer, and a endless loop before for(;;), after ble services started.:
while(1){
refresh_sensor();
OS_DELAY(50);
}
just like before, after several seconds, the uart print stopped. When ATTCH, I found the program ran at line1513 of sys_power_mgr.c:
/ *
* Sleep
*/
__WFI();
/ *Make sure that the code will be executed at the fastest possible speed. */
if (!allow_entering_sleep) { //1513
hw_cpm_set_hclk_div(ahb_div1);
}
4. I created a new task, lower priority than ble_peripheral_task. do nothing but the while loop:
while(1){
refresh_sensor();
OS_DELAY(50);
}
I get the same result as 3.
all tests of 2,3,4 I tried pm_stay_alive() function, or don't enable watchdog, but got the same result.
5. The last test, I put the while loop at the next line of init, before all ble sevices started. this time the I2C data read VERY WELL!
void ble_peripheral_task(void *params)
{
int8_t wdog_id;
ble_service_t *svc;
OS_TASK handle = NULL;
my_peripheral_init();
while(1){
refresh_sensor();
OS_DELAY(50);
}
.....
它似乎读取I2C经常无法与BLE堆叠共存。什么是问题?
Loop forward for your reply.
Thank you.
You should be able to read a device via I2C and still perform BLE operations. Can you post the code you are using to both initialize the I2C interface and read the sensor.
Hi IM_Dialog,
Thank you vour kindly replay. Here's the init code:
bool i2c_devices_async_init(void)
{
bool ret1, ret2;
静态const i2c_config cfg = {
.speed = HW_I2C_SPEED_STANDARD,
.mode = HW_I2C_MODE_MASTER,
.addr_mode = HW_I2C_ADDRESSING_7B,
};
hw_i2c_init(HW_I2C1, &cfg);
srand(OS_GET_TICK_COUNT());
/ *
* Get handle to temperature sensor device.
* This call does not configure I2C controller yet.
*/
// tpdev = ad_i2c_open(TP_MMS427);
imudev = ad_i2c_open(IMU_LSM6DS3);
// magdev = ad_i2c_open(mag_ak09915);
/ *
* Create event that will be used by GUI to wait for I2C transactions to finish.
* This event will be used for access temperature sensor or EEPROM from GUI task.
*/
init_event(&i2c_signal);
// ret1 = tp_device_init();
ret2 = imu_6axes_init();
/ *ret1 = ret1 && ret2;
ret2 = mag_device_init();
ret1 = ret1 && ret2;
//for test only
mag_set_power_mode(4); //100hz refresh
*/ return (ret2);
}
And the refresh sensor code, which excute in timer notify :
静电void refresh_sensor(void)
{
int32_t imudata[6];
int16_t magdata[3];
uint8_t k1status, tpirqstatus;
uint8_t xy[2];
// pm_stay_alive();
k1status =(uint8_t)hw_gpio_get_pin_status(app_button_gpio_port,app_button_gpio_pin);
tpirqstatus = (uint8_t)hw_gpio_get_pin_status(TP_IRQ_GPIO_PORT, TP_IRQ_GPIO_PIN);
if (imu_6axes_read_data(imudata)) {
printf("IO:%d|%d Acc:%d,%d,%d, ", k1status, tpirqstatus, (int)imudata[0], (int)imudata[1], (int)imudata[2]);
printf("Gyro:%d,%d,%d\r\n", (int)imudata[3], (int)imudata[4], (int)imudata[5]);
}
/ * if(tp_drv_read_coorder(xy)){
printf("TP:%u,%u ", xy[0], xy[1]);
}
if (mag_device_read(magdata)) {
printf("mag:%d,%d,%d\r\n", magdata[0], magdata[1], magdata[2]);
}*/
// pm_resume_sleep();
}
the function imu_6axes_read_data use imu_i2c_read function read several registers from IMU and calculate values:
bool imu_i2c_read(uint8_t* pBuffer, uint8_t DeviceAddr, uint8_t RegisterAddr,
uint16_t NumByteToRead)
{
bool ret = false;
ad_i2c_device_acquire(imudev);
if(HW_I2C_ABORT_NONE != i2c_device_read_async(imudev, &RegisterAddr, pBuffer, 1, NumByteToRead, &i2c_signal))
goto exit;
ret = true;
exit:
ad_i2c_device_release(imudev);
return ret;
}
the I2C read registers function: the signal related funtions are the same as in i2c_demo.c.
static HW_I2C_ABORT_SOURCE i2c_device_read_async(i2c_device dev, uint8_t* reg, const uint8_t *buf, uint8_t reglen,
uint8_t buflen, i2c_event *event)
{
/ *
* Make sure event is not in signal state yet;
*/
reset_event(event);
/ *
* Writing sensor register, use callback that will signal event for synchronization.
*/
ad_i2c_async_transact(dev, I2C_SND(reg, reglen), I2C_RCV(buf, buflen),
I2C_CB1(signal_event, event), I2C_END);
/ *
* Wait for transaction to complete.
*/
wait_for_event(event);
/ *
* Error code if any is stored in event, return it.
*/
return event->error;
}
I need to emphasize that I can successfully init and read the IMU data for dozens of times before the system halt. the printf output like this:
2017/1/11 10:08:05.658 [RX] -
IMU XG_ID:0x69
Advertise started!
IO:1|1 Acc:-38,16,1043, Gyro:1680,-10710,-7630
IO:1|1 Acc:-38,16,1041, Gyro:1610,-10570,-7630
IO:1|1 Acc:-38,16,1041, Gyro:1680,-10640,-7630
IO:1 | 1 ACC:-38,17,1040,陀螺仪:1750,-10640,-7560
IO:1|1 Acc:-38,16,1041, Gyro:1680,-10640,-7630
IO:1|1 Acc:-38,16,1041, Gyro:1680,-10640,-7630
...
问候,
Duan
When using the I2C adapter you need to configure your devices and the I2C bus by adding something like the following to a file called platform_devices.h that you place in your config folder:
When you then want to initialize the port you make the following calls:
I can't see these calls in your code so i'm not sure if you are using this mechanism, if not then i suggest you change your code accordingly. You can find a good example of how to use the I2C adapter in the following:
DA1468x_SDK_BTLE_v_1.0.8.1050.1\projects\dk_apps\demos\peripherals_demo\demos\demo_i2c_async.c
Thank you for your replay.
I followed the demo demo_i2c_async.c exactly. the declare of devices were made in a copy of platform_devices.h in config foler like the demo:
I2C_BUS(I2C1)
#ifdef CONFIG_IMU_LSM6DS3
/ *Example temperature sensor FM75 */
I2C_SLAVE_DEVICE(I2C1, IMU_LSM6DS3, 0x6A, HW_I2C_ADDRESSING_7B, HW_I2C_SPEED_STANDARD);
#endif
#ifdef CONFIG_MAG_AK09915
/ *Example temperature sensor FM75 */
I2C_SLAVE_DEVICE(I2C1, MAG_AK09915, 0x0c, HW_I2C_ADDRESSING_7B, HW_I2C_SPEED_STANDARD);
#endif
but I can't find any initialize like I2C_BUS_INIT(I2C1); in the demo. So I didn't add them in previous code.
And I add the macro in init between hardware init and devices open:
hw_i2c_init(HW_I2C1, &cfg);
srand(OS_GET_TICK_COUNT());
I2C_BUS_INIT(I2C1);
I2C_DEVICE_INIT(IMU_LSM6DS3);
I2C_DEVICE_INIT(MAG_AK09915);
/ *
* Get handle to temperature sensor device.
* This call does not configure I2C controller yet.
*/
// tpdev = ad_i2c_open(TP_MMS427);
imudev = ad_i2c_open(IMU_LSM6DS3);
magdev = ad_i2c_open(MAG_AK09915);
But get the same result. What should I try next? Thank you!
Hi Neil.duan,
你提到代码卡住的点,它没有卡住,(没有(1)或任何断言使您的代码卡住),代码仍然执行(可以检查您是否能够查看任何广告代码摊位的空气)。当您附加并且您在这些点处找到代码是因为代码经常或在__wfi()案例中浏览这些点,它只等待发生中断。您提到的硬盘是一种不同的原因,它不是一个BLE或适配器的原因,HardFaults发生在内存中未alalign的访问,对空指针函数,记忆损坏等的调用。我建议做的是检查FW通过系统查看器或臭氧调试器,检查任务和使用的适配器会发生什么,也可以轮询传感器并以较小的频率打印并检查系统是否无法打印。我们非常困难地假设代码可能出现问题,但由于您使用的适配器,SDK应该正确处理BLE事件和I2C交易。
Thanks MT_dialog
我也有同样的硬故障问题。但它is only happeneing on one of the boards. I have total of 2 boards. Other is working perfectly fine.
I M还使用I2C适配器进行I2C传感器读取温度。这个问题的解决方案是什么,,,,?任何人都可以帮助我吗?
Hi mahmed106,
Thanks for your comment. I have already replied you in this following forum thread:
https://support.dialog-semiconductor.com/forums/post/dialog-smartbond-bluetooth-low-energy-%E2%80%93-software/da14681-hardfault-when-reading-i2c
Thanks, PM_Dialog