Hi, Dialog,
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.
Regards.
Duan
Device:
Hi Duan,
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?
Hi, Dialog,
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);
}
.....
It seems reading I2C frequently cannot coexist with ble stack. What would be the problem?
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;
static 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 :
static 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_coordinate(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, Gyro: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
...
Regards,
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,
困,你提到你的代码,its not stuck, (there is no while(1) or any assertion to make your code stuck), the code still executes (can you please check if you are able to see any advertising on air when the code stalls). When you attach and you find the code at those points is because the code goes through those points more often or in the __WFI() case it just waits for an interrupt to occur. The hardfault that you mentioned is a different reason and its not a BLE or adapter reason, hardfaults occur either from a misaligned access in memory, invokation of null pointer function, memory corruption etc. What i would suggest to do is to check the fw either with the System Viewer or the Ozone debugger in order check what happens with the task and the adapters used, also you could poll the sensors and print in a smaller frequency and check if the system fails to print. Its quite difficult for us to assume what might go wrong with the code but since you are using the adapters the SDK should handle BLE events and the I2C transaction properly.
Thanks MT_dialog
我也有同样的硬故障问题。但它is only happeneing on one of the boards. I have total of 2 boards. Other is working perfectly fine.
I m also using I2C adapter for reading temperature from i2C sensor. What is the solution of this problem,,,, ? Can anyone help me in this regard?
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