NCS 2.7.0
NRF52840 DK
I am trying to trigger an advertising sent callback to indicate advertising timeout or a maximum number of events. I have tried increasing the workqueue and main thread stack sizes but still get a usage fault error.
Here is my code for a simple Bluetooth paging service.
#include <zephyr/kernel.h> #include <zephyr/types.h> #include <stddef.h> #include <string.h> #include <errno.h> #include <zephyr/sys/printk.h> #include <zephyr/sys/byteorder.h> #include <zephyr/drivers/gpio.h> #include <zephyr/device.h> #include <zephyr/drivers/pwm.h> #include <soc.h> // For power manager #include <zephyr/init.h> #include <zephyr/pm/pm.h> #include <zephyr/pm/device.h> #include <zephyr/pm/policy.h> #include <zephyr/sys/poweroff.h> #include <zephyr/sys/util.h> // Devicetree + GPIO includes #include <nrfx_gpiote.h> #include <helpers/nrfx_gppi.h> #include <nrfx_ppi.h> #include <zephyr/irq.h> // Bluetooth include files #include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/gatt.h> #include <zephyr/bluetooth/conn.h> #include <zephyr/bluetooth/uuid.h> #include <zephyr/bluetooth/services/bas.h> const struct device *const cons = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); #define GREEN_LED_NODE DT_ALIAS(led1) #define BLUE_LED_NODE DT_ALIAS(led2) #define RED_LED_NODE DT_ALIAS(led0) #define BUTTON_NODE DT_ALIAS(sw0) #if CONFIG_BOARD_PRO_FLAG #define HAPTIC_PWM_NODE DT_ALIAS(pwm_buzz) #define HAPTIC_PIN_NODE DT_ALIAS(buzz_en) #define PWM_RED_LED_NODE DT_ALIAS(pwm_led0) #define PWM_GREEN_LED_NODE DT_ALIAS(pwm_led1) #define PWM_BLUE_LED_NODE DT_ALIAS(pwm_led2) #define USB_DETECT_NODE DT_ALIAS(usb_dt) #define USB_STAT_NODE DT_ALIAS(chrg) #define FACTORY_ENABLE_NODE DT_ALIAS(pwron) #else #define HAPTIC_PWM_NODE DT_ALIAS(pwm_led0) #define HAPTIC_PIN_NODE DT_ALIAS(led3) #endif static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET(BUTTON_NODE, gpios); //static const struct gpio_dt_spec r_led = GPIO_DT_SPEC_GET(RED_LED_NODE, gpios); static const struct gpio_dt_spec g_led = GPIO_DT_SPEC_GET(GREEN_LED_NODE, gpios); static const struct gpio_dt_spec b_led = GPIO_DT_SPEC_GET(BLUE_LED_NODE, gpios); #if CONFIG_BOARD_PRO_FLAG static const struct pwm_dt_spec pwm_ledr = PWM_DT_SPEC_GET(PWM_RED_LED_NODE); static const struct pwm_dt_spec pwm_ledg = PWM_DT_SPEC_GET(PWM_GREEN_LED_NODE); //static const struct pwm_dt_spec pwm_ledb = PWM_DT_SPEC_GET(PWM_BLUE_LED_NODE); static const struct gpio_dt_spec usb_detect = GPIO_DT_SPEC_GET(USB_DETECT_NODE, gpios); static const struct gpio_dt_spec stat_pin = GPIO_DT_SPEC_GET(USB_STAT_NODE, gpios); static const struct gpio_dt_spec bat_en = GPIO_DT_SPEC_GET(FACTORY_ENABLE_NODE, gpios); #else static const struct pwm_dt_spec pwm_ledr = PWM_DT_SPEC_GET(HAPTIC_PWM_NODE); static const struct pwm_dt_spec pwm_ledg = PWM_DT_SPEC_GET(HAPTIC_PWM_NODE); static const struct pwm_dt_spec pwm_ledb = PWM_DT_SPEC_GET(HAPTIC_PWM_NODE); #endif static const struct pwm_dt_spec pwm_buzz = PWM_DT_SPEC_GET(HAPTIC_PWM_NODE); static const struct gpio_dt_spec buzz_en = GPIO_DT_SPEC_GET(HAPTIC_PIN_NODE, gpios); //Total fade up time is DELAY * PWM_STEPS #define HAPTIC_PWM_PERIOD_NS 500000 #define HAPTIC_FADE_DELAY_MS 1 #define HAPTIC_PWM_STEPS 1000 #define POWERON_PWM_PERIOD_NS 500000 #define POWERON_FADE_UP_DELAY_MS 1 #define POWERON_PWM_STEPS 3000 #define DEVICE_NAME "rareBit PRO Flag" #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) #define MAX_TRANSMIT_SIZE 240//TODO figure this out // Define the custom services and characteristics #define PAGING_SERVICE_UUID 0x6d, 0x1b, 0xee, 0x1e, 0xee, 0x7d, 0xd0, 0xba, 0x7b, \ 0x4b, 0xd5, 0x28, 0x01, 0x00, 0x21, 0x23 // Characteristic: Paging Characteristic UUID 23210002-28D5-4B7B-BA0F-7DEE1EEE1B6D #define PAGE_ALERT_CHARACTERISTIC_UUID 0x6d, 0x1b, 0xee, 0x1e, 0xee, 0x7d, 0xd0, 0xba, 0x7b, \ 0x4b, 0xd5, 0x28, 0x02, 0x00, 0x21, 0x23 #define BT_UUID_PAGING_SERVICE BT_UUID_DECLARE_128(PAGING_SERVICE_UUID) #define BT_UUID_PAGE_ALERT_CHARACTERISTIC BT_UUID_DECLARE_128(PAGE_ALERT_CHARACTERISTIC_UUID) //Advertising Timeout period ranges from EVENTS * MIN_INTERVAL to EVENTS * MAX_INTERVAL #define ADVERTISNG_TIMEOUT_EVENTS 200 #define WORQ_THREAD_STACK_SIZE 8192 #define WORKQ_PRIORITY 5 static bool app_button_state = false; // Define stack area used by workqueue thread static K_THREAD_STACK_DEFINE(my_stack_area, WORQ_THREAD_STACK_SIZE); // Define queue structure static struct k_work_q offload_work_q = {0}; struct work_info { struct k_work work; char name[25]; } radio_work; struct usb_work_info { struct k_work work; char name[50]; } usb_work; uint8_t data_tx[MAX_TRANSMIT_SIZE]; bool debounce_check = false; static struct bt_le_ext_adv *adv; struct bt_conn *conn_handle = NULL; const struct bt_gatt_attr *page_alert_attr = NULL; bool page_flag = false; int my_service_init(void) { int err = 0; memset(&data_tx, 0, MAX_TRANSMIT_SIZE); return err; } // Bluetooth advertising data static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), BT_DATA_BYTES(BT_DATA_UUID128_ALL, 0x84, 0xaa, 0x60, 0x74, 0x52, 0x8a, 0x8b, 0x86, 0xd3, 0x4c, 0xb7, 0x1d, 0x1d, 0xdc, 0x53, 0x8d), BT_DATA_BYTES(BT_DATA_UUID128_ALL, PAGING_SERVICE_UUID) }; static void advertising_max_events(struct bt_le_ext_adv *adv, struct bt_le_ext_adv_sent_info *info) { uint8_t adv_events = 200;//info->num_sent; printk("Adertising finished with %d events.\n", adv_events); //Giving time for the print buffer. //We need this under every print that occurs before PM_DEVICE_ACTION_SUSPEND. k_msleep(1000); gpio_pin_set_dt(&b_led, 0); //Effectively the timeout condition, but it's not a precise interval if (adv_events >= ADVERTISNG_TIMEOUT_EVENTS) { printk("Advertising timed out. Shutting down... \n"); } else { //Else is effectively the connected condition (which we already have a callback for... idk) printk("Probably connected.\n"); } } static void create_advertising_coded(void) { int err; struct bt_le_adv_param params = BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_CODED | BT_LE_ADV_OPT_EXT_ADV, BT_GAP_ADV_FAST_INT_MIN_2, BT_GAP_ADV_FAST_INT_MAX_2, NULL); struct bt_le_ext_adv_cb advertising_cb = { .sent = advertising_max_events }; err = bt_le_ext_adv_create(¶ms, &advertising_cb, &adv); if(err) { printk("Error %d could not create ext_adv.\n", err); } else printk("CODED PHY Advertising Configured.\n"); err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0); if(err) { printk("Error %d could not set_data.\n", err); } else printk("CODED PHY adv data set.\n"); } void start_advertising_coded(void) { int err; //timeout value doesn't seem to work here, the advertising sent function gets triggered even when the timeout doesn't occur struct bt_le_ext_adv_start_param start_params; //Minimum advertising intverval is 100ms, thus a timeout period of AT LEAST num_events*100ms start_params.num_events = ADVERTISNG_TIMEOUT_EVENTS; err = bt_le_ext_adv_start(adv, &start_params); if(err) { printk("Error: Advertising NOT started. return %d\n", err); } else { printk("Bluetooth advertising started!\n"); gpio_pin_set_dt(&b_led, 1); } } // Instantiate the service and its characteristics BT_GATT_SERVICE_DEFINE( paging_service, // Simple Service BT_GATT_PRIMARY_SERVICE(BT_UUID_PAGING_SERVICE), // Page Alert Characteristic BT_GATT_CHARACTERISTIC(BT_UUID_PAGE_ALERT_CHARACTERISTIC, BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_NONE, NULL, NULL, NULL), BT_GATT_CCC(NULL, BT_GATT_PERM_WRITE | BT_GATT_PERM_READ) ); // Connected callback function static void connected_cb(struct bt_conn *conn, uint8_t err) { struct bt_conn_info info; char addr[BT_ADDR_LE_STR_LEN]; conn_handle = conn; page_alert_attr = &paging_service.attrs[2]; if (err) { printk("Connection failed (err %u)\n", err); return; } else if(bt_conn_get_info(conn, &info)) { printk("Could not parse connection info\n"); } else { bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); printk("\n \n Connection established!\n\ Connected to: %s \n\ Role: %u \n\ Connection interval: %u \n\ Slave latency: %u \n\ Connection supervisory timeout: %u \n" , addr, info.role, info.le.interval, info.le.latency, info.le.timeout); } } // Disconnected callback function static void disconnected_cb(struct bt_conn *conn, uint8_t reason) { printk("Disconnected with reason %d\n", reason); k_sleep(K_MSEC(100)); conn_handle = NULL; gpio_pin_set_dt(&b_led, 0); start_advertising_coded(); gpio_pin_set_dt(&g_led, 0); } #if LE_PARAMETER_REQUESTS_ENABLED static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param) { //If acceptable params, return true, otherwise return false. return true; } static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, uint16_t timeout) { struct bt_conn_info info; char addr[BT_ADDR_LE_STR_LEN]; if(bt_conn_get_info(conn, &info)) { printk("Could not parse connection info\n"); } else { bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); printk("Connection parameters updated! \n\ Connected to: %s \n\ New Connection Interval: %u \n\ New Slave Latency: %u \n\ New Connection Supervisory Timeout: %u \n" , addr, info.le.interval, info.le.latency, info.le.timeout); } } #endif // Connection callback structure static struct bt_conn_cb conn_callbacks = { .connected = connected_cb, .disconnected = disconnected_cb #if LE_PARAMETER_REQUESTS_ENABLED , .le_param_req = le_param_req, .le_param_updated = le_param_updated #endif }; void bt_pageAlert(struct bt_conn *conn, const uint8_t *data, uint16_t len) { // Send the notification if(bt_gatt_notify(conn, page_alert_attr, &data, len)) { printk("Error, unable to send notification\n"); } else { printk("Notified Peer of %d\n", (int) &data); } } void offload_function(struct k_work *work_tem) { app_button_state = !app_button_state; uint8_t page_d[] = {0x01}; uint8_t * page_p = page_d; if ((conn_handle != NULL) & app_button_state) { bt_pageAlert(conn_handle, page_p, 1); } printk("Work thread executed. \n"); k_yield(); } static void button_changed(const struct device *dev, struct gpio_callback *cb, uint32_t pins) { k_work_submit_to_queue(&offload_work_q, &radio_work.work); k_yield(); } static void init_interrupts(void) { int err; err = gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_BOTH); if (err < 0) { printk("Button pin interrupt configure failed with err %d\n", err); } else { printk("Button pin interrupt configured.\n"); } static struct gpio_callback button_cb_data; gpio_init_callback(&button_cb_data, button_changed, BIT(button.pin)); err = gpio_add_callback(button.port, &button_cb_data); if (err < 0) { printk("Button pin interrupt callback add failed with err %d\n", err); } else { printk("Button pin interrupt callback added.\n"); } } static void init_pins(void) { int err; err = gpio_pin_configure_dt(&button, GPIO_INPUT); if (err < 0) { printk("GPIO Input Button failed (err %d)\n", err); } else printk("Button input configured\n"); } int main(void) { init_pins(); init_interrupts(); k_work_queue_start(&offload_work_q, my_stack_area, K_THREAD_STACK_SIZEOF(my_stack_area), WORKQ_PRIORITY, NULL); strcpy(radio_work.name, "Bluetooth Notify thread"); k_work_init(&radio_work.work, offload_function); int err; err = bt_enable(NULL); if (err) { printk("Bluetooth init failed (err %d)\n", err); } err = my_service_init(); if (err) { printk("Could not initialize simple service \n"); } // Register for connection callbacks bt_conn_cb_register(&conn_callbacks); // Create the Extended Advertising create_advertising_coded(); // Start advertising start_advertising_coded(); return 0; }
Error Message:
[00:00:20.874,969] <err> os: ***** USAGE FAULT ***** [00:00:20.875,000] <err> os: Illegal use of the EPSR [00:00:20.875,000] <err> os: r0/a1: 0x200025c8 r1/a2: 0x2000685c r2/a3: 0x000000c8 [00:00:20.875,030] <err> os: r3/a4: 0x000185e0 r12/ip: 0x00001407 r14/lr: 0x0001bd0f [00:00:20.875,030] <err> os: xpsr: 0x20000000 [00:00:20.875,030] <err> os: Faulting instruction address (r15/pc): 0x000185e0 [00:00:20.875,091] <err> os: >>> ZEPHYR FATAL ERROR 35: Unknown error on CPU 0 [00:00:20.875,122] <err> os: Current thread: 0x200024f0 (BT RX WQ) [00:00:20.953,125] <err> os: Halting system