How to execute debug print from within timer callback in ESP32? - timer

I started with ESP32 last week and currently I am trying to put together the example codes for the BLE iBeacon and a 1-sec-alarm timer. I receive the error abort() was called at PC 0x403774b7 on core 0 0x403774b7: lock_acquire_generic at /home/boko/esp/esp-idf/components/newlib/locks.c:130 when running the program. I have a single ESP_LOGI() statement within the timer callback timer_alarm_cb, which seems to cause the issue, but I don't know why and how (if I remove the statment, the program works fine). What I want to achieve with the code is to get a debug print every 1 second as a visual feedback in order to know how many and which iBeacons have been detected within a 1 sec interval.
So, my 2 questions are:
Why the ESP_LOGI() statement within the timer callback causes the program to abort ?
What is the otherwise correct way to get debug print every 1 sec using a timer in ESP32?
My code is:
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/****************************************************************************
*
* This file is for iBeacon demo. It supports both iBeacon sender and receiver
* which is distinguished by macros IBEACON_SENDER and IBEACON_RECEIVER,
*
* iBeacon is a trademark of Apple Inc. Before building devices which use iBeacon technology,
* visit https://developer.apple.com/ibeacon/ to obtain a license.
*
****************************************************************************/
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "nvs_flash.h"
#include "esp_bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gattc_api.h"
#include "esp_gatt_defs.h"
#include "esp_bt_main.h"
#include "esp_bt_defs.h"
#include "esp_ibeacon_api.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h" // If you include FreeRTOS.h before task.h then portmacro.h will be included for you (do not include portmacro.h manually, just include FreeRTOS.h). However, if you fail to include FreeRTOS.h before tasks.h, then your code will not build
// #include "freertos/task.h" // BaseType_t
#include "driver/gptimer.h"
static const char* PROGRAM_NAME = "iBeacon2Omnicomm" ; // "iBeacons-ESP32-Tracker-Server" ; // "IBEACON_DEMO";
extern esp_ble_ibeacon_vendor_t vendor_config;
///Declare static functions
static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
#if (IBEACON_MODE == IBEACON_RECEIVER)
static esp_ble_scan_params_t ble_scan_params = {
.scan_type = BLE_SCAN_TYPE_ACTIVE,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
.scan_interval = 0x50, // 50 ms scan interval, i.e. start scanning for BLE devices every 50 ms elapsed
.scan_window = 0x30, // 30 ms scan duration, i.e. whenever a scan interval starts, keep scanning for 30 ms
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE
};
#elif (IBEACON_MODE == IBEACON_SENDER)
static esp_ble_adv_params_t ble_adv_params = {
.adv_int_min = 0x20,
.adv_int_max = 0x40,
.adv_type = ADV_TYPE_NONCONN_IND,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};
#endif
static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
esp_err_t err;
switch (event) {
case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:{
#if (IBEACON_MODE == IBEACON_SENDER)
esp_ble_gap_start_advertising(&ble_adv_params);
#endif
break;
}
case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: {
#if (IBEACON_MODE == IBEACON_RECEIVER)
//the unit of the duration is second, 0 means scan permanently
uint32_t duration = 0;
ESP_LOGI(PROGRAM_NAME, "starting a scan == calling esp_ble_gap_start_scanning()");
esp_ble_gap_start_scanning(duration);
#endif
break;
}
case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT:
//scan start complete event to indicate scan start successfully or failed
if ((err = param->scan_start_cmpl.status) != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(PROGRAM_NAME, "Scan start failed: %s", esp_err_to_name(err));
} else {
ESP_LOGI(PROGRAM_NAME, "Scan start successful");
}
break;
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
//adv start complete event to indicate adv start successfully or failed
if ((err = param->adv_start_cmpl.status) != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(PROGRAM_NAME, "Adv start failed: %s", esp_err_to_name(err));
}
break;
case ESP_GAP_BLE_SCAN_RESULT_EVT: {
esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param; // make a local copy of the passed address of parameters
switch (scan_result->scan_rst.search_evt) {
case ESP_GAP_SEARCH_INQ_RES_EVT:
/* Search for BLE iBeacon Packet */
if (esp_ble_is_ibeacon_packet(scan_result->scan_rst.ble_adv, scan_result->scan_rst.adv_data_len)){
esp_ble_ibeacon_t *ibeacon_data = (esp_ble_ibeacon_t*)(scan_result->scan_rst.ble_adv);
// ESP_LOGI("iBeacon Found:"); // error: macro "ESP_LOGI" requires 3 arguments, but only 1 given
ESP_LOGI(PROGRAM_NAME, "iBeacon Found ==========");
esp_log_buffer_hex("MAC address:", scan_result->scan_rst.bda, ESP_BD_ADDR_LEN );
esp_log_buffer_hex("UUID:", ibeacon_data->ibeacon_vendor.proximity_uuid, ESP_UUID_LEN_128);
uint16_t major = ENDIAN_CHANGE_U16(ibeacon_data->ibeacon_vendor.major);
uint16_t minor = ENDIAN_CHANGE_U16(ibeacon_data->ibeacon_vendor.minor);
ESP_LOGI(PROGRAM_NAME, "Major: 0x%04x (%d)", major, major);
ESP_LOGI(PROGRAM_NAME, "Minor: 0x%04x (%d)", minor, minor);
//ESP_LOGI(PROGRAM_NAME, "Measured power (RSSI at a 1m distance):%d dbm", ibeacon_data->ibeacon_vendor.measured_power);
ESP_LOGI(PROGRAM_NAME, "RSSI:%d dbm", scan_result->scan_rst.rssi);
}
break;
default:
break;
}
break;
}
case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
if ((err = param->scan_stop_cmpl.status) != ESP_BT_STATUS_SUCCESS){
ESP_LOGE(PROGRAM_NAME, "Scan stop failed: %s", esp_err_to_name(err));
}
else {
ESP_LOGI(PROGRAM_NAME, "Stop scan successfully");
}
break;
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
if ((err = param->adv_stop_cmpl.status) != ESP_BT_STATUS_SUCCESS){
ESP_LOGE(PROGRAM_NAME, "Adv stop failed: %s", esp_err_to_name(err));
}
else {
ESP_LOGI(PROGRAM_NAME, "Stop adv successfully");
}
break;
default:
break;
}
}
void ble_ibeacon_appRegister(void)
{
esp_err_t status;
ESP_LOGI(PROGRAM_NAME, "registering callback == calling esp_ble_gap_register_callback()");
//register the scan callback function to the gap module:
if ((status = esp_ble_gap_register_callback(esp_gap_cb)) != ESP_OK) {
ESP_LOGE(PROGRAM_NAME, "gap register error: %s", esp_err_to_name(status));
return;
} else {
ESP_LOGI(PROGRAM_NAME, "successful");
}
}
void ble_ibeacon_init(void)
{
esp_bluedroid_init();
esp_bluedroid_enable();
ble_ibeacon_appRegister();
}
//## BaseType_t timerOverflow = pdFALSE;
// IRAM_ATTR: Forces code into IRAM instead of flash
static bool IRAM_ATTR timer_alarm_cb ( gptimer_handle_t timer, const gptimer_alarm_event_data_t * edata, void * user_data ) { // == ISR on timer overflow event
/*
BaseType_t high_task_awoken = pdFALSE;
QueueHandle_t queue = (QueueHandle_t) user_data;
// Retrieve count value and send to queue
example_queue_element_t ele = {
.event_count = edata->count_value
};
xQueueSendFromISR(queue, &ele, &high_task_awoken);
// return whether we need to yield at the end of ISR
return (high_task_awoken == pdTRUE);
*/
//## timerOverflow = pdTRUE ; // #define pdTRUE ( ( BaseType_t ) 1 ) --> typedef portBASE_TYPE BaseType_t; --> #define portBASE_TYPE int
ESP_LOGI(PROGRAM_NAME, "1 s elapsed");
// #return Whether a high priority task has been waken up by this function:
return pdFALSE ;
}
// if prototype declared as "static bool IRAM_ATTR ..." --> error: no return statement in function returning non-void [-Werror=return-type]
void app_main(void) {
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
esp_bt_controller_init(&bt_cfg);
esp_bt_controller_enable(ESP_BT_MODE_BLE);
ble_ibeacon_init();
/* set scan parameters */
#if (IBEACON_MODE == IBEACON_RECEIVER)
ESP_LOGI(PROGRAM_NAME, "setting RECEIVER scan parameters == calling esp_ble_gap_set_scan_params()");
esp_ble_gap_set_scan_params(&ble_scan_params);
#elif (IBEACON_MODE == IBEACON_SENDER)
esp_ble_ibeacon_t ibeacon_adv_data;
esp_err_t status = esp_ble_config_ibeacon_data (&vendor_config, &ibeacon_adv_data);
if (status == ESP_OK){
esp_ble_gap_config_adv_data_raw((uint8_t*)&ibeacon_adv_data, sizeof(ibeacon_adv_data));
}
else {
ESP_LOGE(PROGRAM_NAME, "Config iBeacon data failed: %s\n", esp_err_to_name(status));
}
#endif
// Creating a GPTimer Handle with Resolution (frequency) of 1 MHz:
ESP_LOGI(PROGRAM_NAME, "Creating new timer (handle)");
gptimer_handle_t gptimer = NULL;
gptimer_config_t timer_config = {
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
.direction = GPTIMER_COUNT_UP,
.resolution_hz = 1 * 1000 * 1000, // 1MHz, 1 tick = 1us
};
ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &gptimer));
// Prepare Triggering of Periodic Events (set up the alarm action before starting the timer !) every 1 sec:
ESP_LOGI(PROGRAM_NAME, "Setting alarm action");
gptimer_alarm_config_t alarm_config = {
.reload_count = 0, // counter will reload with 0 on alarm event
.alarm_count = 1000000, // period = 1s #resolution 1MHz
.flags.auto_reload_on_alarm = true, // enable auto-reload
};
ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config));
ESP_LOGI(PROGRAM_NAME, "Registering callback function to execute on alarm event");
gptimer_event_callbacks_t cbs = {
.on_alarm = timer_alarm_cb, // register user callback
};
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, NULL));
ESP_ERROR_CHECK(gptimer_enable(gptimer));
ESP_LOGI(PROGRAM_NAME, "Starting timer");
ESP_ERROR_CHECK(gptimer_start(gptimer));
/*
while ( 1 ) {
if ( timerOverflow ) {
timerOverflow = pdFALSE ;
ESP_LOGI(PROGRAM_NAME, "1 s elapsed");
}
}
*/
}
An example terminal output is:
/home/boko/.espressif/python_env/idf5.1_py3.10_envboko#boko-HP-EliteBook-850-G8-Notebook-PC:~/Desktop/ESP32/ble_ibeacon$ export IDF_PATH=/home/boko/esp/esp-idf
boko#boko-HP-EliteBook-850-G8-Notebook-PC:~/Desktop/ESP32/ble_ibeacon$ /home/boko/.espressif/python_env/idf5.1_py3.10_env/bin/python /home/boko/esp/esp-idf/tools/idf_monitor.py -p /dev/ttyUSB0 -b 115200 --toolchain-prefix xtensa-esp32s3-elf- --target esp32s3 /home/boko/Desktop/ESP32/ble_ibeacon/build/ble_ibeacon_demo.elf
--- idf_monitor on /dev/ttyUSB0 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
) UUID:: fd a5�ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3810,len:0x16ac
load:0x403c9700,len:0xbc8
load:0x403cc700,len:0x2d64
entry 0x403c98fc
I (25) boot: ESP-IDF v5.1-dev-1626-g4b6d9c8ad3 2nd stage bootloader
I (25) boot: compile time Nov 11 2022 16:57:52
I (25) boot: chip revision: V001
I (29) boot_comm: chip revision: 1, min. bootloader chip revision: 0
I (36) boot.esp32s3: Boot SPI Speed : 80MHz
I (41) boot.esp32s3: SPI Mode : DIO
I (46) boot.esp32s3: SPI Flash Size : 2MB
I (51) boot: Enabling RNG early entropy source...
I (56) boot: Partition Table:
I (60) boot: ## Label Usage Type ST Offset Length
I (67) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (74) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (82) boot: 2 factory factory app 00 00 00010000 00100000
I (89) boot: End of partition table
I (93) boot_comm: chip revision: 1, min. application chip revision: 0
I (101) esp_image: segment 0: paddr=00010020 vaddr=3c080020 size=1e524h (124196) map
I (131) esp_image: segment 1: paddr=0002e54c vaddr=3fc96a00 size=01acch ( 6860) load
I (133) esp_image: segment 2: paddr=00030020 vaddr=42000020 size=7514ch (479564) map
I (223) esp_image: segment 3: paddr=000a5174 vaddr=3fc984cc size=02484h ( 9348) load
I (225) esp_image: segment 4: paddr=000a7600 vaddr=40374000 size=12998h ( 76184) load
I (253) boot: Loaded app from partition at offset 0x10000
I (253) boot: Disabling RNG early entropy source...
I (265) cpu_start: Pro cpu up.
I (265) cpu_start: Starting app cpu, entry point is 0x403753cc
0x403753cc: call_start_cpu1 at /home/boko/esp/esp-idf/components/esp_system/port/cpu_start.c:146
I (0) cpu_start: App cpu up.
I (279) cpu_start: Pro cpu start user code
I (279) cpu_start: cpu freq: 160000000 Hz
I (280) cpu_start: Application information:
I (282) cpu_start: Project name: ble_ibeacon_demo
I (288) cpu_start: App version: 1
I (293) cpu_start: Compile time: Nov 11 2022 16:57:45
I (299) cpu_start: ELF file SHA256: 2432859c4fe13f02...
I (305) cpu_start: ESP-IDF: v5.1-dev-1626-g4b6d9c8ad3
I (311) heap_init: Initializing. RAM available for dynamic allocation:
I (318) heap_init: At 3FC9E8F8 len 0004AE18 (299 KiB): D/IRAM
I (325) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM
I (332) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (338) heap_init: At 600FE010 len 00001FF0 (7 KiB): RTCRAM
I (345) spi_flash: detected chip: generic
I (349) spi_flash: flash io: dio
W (353) spi_flash: Detected size(8192k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (366) coexist: coexist rom version e7ae62f
I (371) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (415) BT_INIT: BT controller compile version [76c24c9]
I (415) phy_init: phy_version 503,13653eb,Jun 1 2022,17:47:08
I (455) system_api: Base MAC address is not set
I (455) system_api: read default base MAC address from EFUSE
I (455) BT_INIT: Bluetooth MAC: 7c:df:a1:e3:55:fa
I (485) iBeacon2Omnicomm: registering callback == calling esp_ble_gap_register_callback()
I (485) iBeacon2Omnicomm: successful
I (485) iBeacon2Omnicomm: setting RECEIVER scan parameters == calling esp_ble_gap_set_scan_params()
I (495) iBeacon2Omnicomm: starting a scan == calling esp_ble_gap_start_scanning()
I (505) iBeacon2Omnicomm: Scan start successful
I (505) iBeacon2Omnicomm: Creating new timer (handle)
I (515) iBeacon2Omnicomm: Setting alarm action
I (515) iBeacon2Omnicomm: Registering callback function to execute on alarm event
I (525) iBeacon2Omnicomm: Starting timer
I (755) iBeacon2Omnicomm: iBeacon Found ==========
I (755) MAC address:: ac 23 3f a8 c3 a8
I (755) UUID:: fd a5 06 93 a4 e2 4f b1 af cf c6 eb 07 64 78 25
I (765) iBeacon2Omnicomm: Major: 0x08ae (2222)
I (765) iBeacon2Omnicomm: Minor: 0x08ae (2222)
I (775) iBeacon2Omnicomm: RSSI:-48 dbm
I (805) iBeacon2Omnicomm: iBeacon Found ==========
I (805) MAC address:: ac 23 3f a8 c3 a8
I (805) UUID:: fd a5 06 93 a4 e2 4f b1 af cf c6 eb 07 64 78 25
I (805) iBeacon2Omnicomm: Major: 0x04d2 (1234)
I (815) iBeacon2Omnicomm: Minor: 0x269e (9886)
I (815) iBeacon2Omnicomm: RSSI:-43 dbm
abort() was called at PC 0x403774b7 on core 0
0x403774b7: lock_acquire_generic at /home/boko/esp/esp-idf/components/newlib/locks.c:130
Backtrace: 0x40375ebe:0x3fc979f0 0x4037ec61:0x3fc97a10 0x403846a6:0x3fc97a30 0x403774b7:0x3fc97aa0 0x403775cd:0x3fc97ad0 0x4037769c:0x3fc97af0 0x420653c1:0x3fc97b20 0x42068505:0x3fc97e30 0x42075151:0x3fc97e60 0x40384555:0x3fc97e90 0x40377b75:0x3fc97ee0 0x40379d85:0x3fc97f00 0x40377295:0x3fc97f30 0x4037d8a7:0x3fcf3fb0 0x42003bc2:0x3fcf3fd0 0x40380151:0x3fcf3ff0 0x4038195d:0x3fcf4010
0x40375ebe: panic_abort at /home/boko/esp/esp-idf/components/esp_system/panic.c:423
0x4037ec61: esp_system_abort at /home/boko/esp/esp-idf/components/esp_system/esp_system.c:135
0x403846a6: abort at /home/boko/esp/esp-idf/components/newlib/abort.c:38
0x403774b7: lock_acquire_generic at /home/boko/esp/esp-idf/components/newlib/locks.c:130
0x403775cd: _lock_acquire_recursive at /home/boko/esp/esp-idf/components/newlib/locks.c:158
0x4037769c: __retarget_lock_acquire_recursive at /home/boko/esp/esp-idf/components/newlib/locks.c:314 (discriminator 3)
0x420653c1: _vfprintf_r at ??:?
0x42068505: vprintf at /builds/idf/crosstool-NG/.build/xtensa-esp32s3-elf/src/newlib/newlib/libc/stdio/vprintf.c:34 (discriminator 5)
0x42075151: esp_log_writev at /home/boko/esp/esp-idf/components/log/log.c:200
0x40384555: esp_log_write at /home/boko/esp/esp-idf/components/log/log.c:210
0x40377b75: timer_alarm_cb at /home/boko/Desktop/ESP32/ble_ibeacon/main/ibeacon_demo.c:200
0x40379d85: gptimer_default_isr at /home/boko/esp/esp-idf/components/driver/gptimer.c:512
0x40377295: _xt_lowint1 at /home/boko/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/xtensa_vectors.S:1118
0x4037d8a7: xt_utils_wait_for_intr at /home/boko/esp/esp-idf/components/xtensa/include/xt_utils.h:81
(inlined by) esp_cpu_wait_for_intr at /home/boko/esp/esp-idf/components/esp_hw_support/cpu.c:115
0x42003bc2: esp_vApplicationIdleHook at /home/boko/esp/esp-idf/components/esp_system/freertos_hooks.c:59
0x40380151: prvIdleTask at /home/boko/esp/esp-idf/components/freertos/FreeRTOS-Kernel/tasks.c:4273 (discriminator 1)
0x4038195d: vPortTaskWrapper at /home/boko/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:152
ELF file SHA256: 2432859c4fe13f02
Rebooting...
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x3 (RTC_SW_SYS_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
Saved PC:0x4037585c
0x4037585c: esp_restart_noos_dig at /home/boko/esp/esp-idf/components/esp_system/esp_system.c:46 (discriminator 1)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3810,len:0x16ac
load:0x403c9700,len:0xbc8
load:0x403cc700,len:0x2d64
entry 0x403c98fc
I (29) boot: ESP-IDF v5.1-dev-1626-g4b6d9c8ad3 2nd stage bootloader
I (29) boot: compile time Nov 11 2022 16:57:52
I (30) boot: chip revision: V001
I (34) boot_comm: chip revision: 1, min. bootloader chip revision: 0
I (41) boot.esp32s3: Boot SPI Speed : 80MHz
I (46) boot.esp32s3: SPI Mode : DIO
I (50) boot.esp32s3: SPI Flash Size : 2MB
I (55) boot: Enabling RNG early entropy source...
I (60) boot: Partition Table:
I (64) boot: ## Label Usage Type ST Offset Length
I (79) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (86) boot: 2 factory factory app 00 00 00010000 00100000
I (94) boot: End of partition table
I (98) boot_comm: chip revision: 1, min. application chip revision: 0
I (105) esp_image: segment 0: paddr=00010020 vaddr=3c080020 size=1e524h (124196) map
I (136) esp_image: segment 1: paddr=0002e54c vaddr=3fc96a00 size=01acch ( 6860) load
I (138) esp_image: segment 2: paddr=00030020 vaddr=42000020 size=7514ch (479564) map
I (228) esp_image: segment 3: paddr=000a5174 vaddr=3fc984cc size=02484h ( 9348) load
I (230) esp_image: segment 4: paddr=000a7600 vaddr=40374000 size=12998h ( 76184) load
I (258) boot: Loaded app from partition at offset 0x10000
I (258) boot: Disabling RNG early entropy source...
I (269) cpu_start: Pro cpu up.
I (269) cpu_start: Starting app cpu, entry point is 0x403753cc
0x403753cc: call_start_cpu1 at /home/boko/esp/esp-idf/components/esp_system/port/cpu_start.c:146
I (0) cpu_start: App cpu up.
I (284) cpu_start: Pro cpu start user code
I (284) cpu_start: cpu freq: 160000000 Hz
I (284) cpu_start: Application information:
I (287) cpu_start: Project name: ble_ibeacon_demo
I (293) cpu_start: App version: 1
I (297) cpu_start: Compile time: Nov 11 2022 16:57:45
I (303) cpu_start: ELF file SHA256: 2432859c4fe13f02...
I (309) cpu_start: ESP-IDF: v5.1-dev-1626-g4b6d9c8ad3
I (316) heap_init: Initializing. RAM available for dynamic allocation:
I (323) heap_init: At 3FC9E8F8 len 0004AE18 (299 KiB): D/IRAM
I (329) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM
I (336) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (342) heap_init: At 600FE010 len 00001FF0 (7 KiB): RTCRAM
I (349) spi_flash: detected chip: generic
I (353) spi_flash: flash io: dio
W (357) spi_flash: Detected size(8192k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (371) coexist: coexist rom version e7ae62f
I (375) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (420) BT_INIT: BT controller compile version [76c24c9]
I (420) phy_init: phy_version 503,13653eb,Jun 1 2022,17:47:08
I (460) system_api: Base MAC address is not set
I (460) system_api: read default base MAC address from EFUSE
I (460) BT_INIT: Bluetooth MAC: 7c:df:a1:e3:55:fa
I (490) iBeacon2Omnicomm: registering callback == calling esp_ble_gap_register_callback()
I (490) iBeacon2Omnicomm: successful
I (490) iBeacon2Omnicomm: setting RECEIVER scan parameters == calling esp_ble_gap_set_scan_params()
I (500) iBeacon2Omnicomm: starting a scan == calling esp_ble_gap_start_scanning()
I (510) iBeacon2Omnicomm: Scan start successful
I (510) iBeacon2Omnicomm: Creating new timer (handle)
I (520) iBeacon2Omnicomm: Setting alarm action
I (520) iBeacon2Omnicomm: Registering callback function to execute on alarm event
I (530) iBeacon2Omnicomm: Starting timer
I (580) iBeacon2Omnicomm: iBeacon Found ==========
I (580) MAC address:: ac 23 3f a8 c3 a8
I (580) UUID:: fd a5 06 93 a4 e2 4f b1 af cf c6 eb 07 64 78 25
I (590) iBeacon2Omnicomm: Major: 0x2711 (10001)
I (590) iBeacon2Omnicomm: Minor: 0x4cb9 (19641)
I (600) iBeacon2Omnicomm: RSSI:-37 dbm
I (1220) iBeacon2Omnicomm: iBeacon Found ==========
I (1220) MAC address:: ac 23 3f a8 c3 a8
I (1220) UUID:: fd a5 06 93 a4 e2 4f b1 af cf c6 eb 07 64 78 25
I (1230) iBeacon2Omnicomm: Major: 0x04d2 (1234)
I (1230) iBeacon2Omnicomm: Minor: 0x269e (9886)
I (1240) iBeacon2Omnicomm: RSSI:-51 dbm
abort() was called at PC 0x403774b7 on core 0
0x403774b7: lock_acquire_generic at /home/boko/esp/esp-idf/components/newlib/locks.c:130
Backtrace: 0x40375ebe:0x3fc979f0 0x4037ec61:0x3fc97a10 0x403846a6:0x3fc97a30 0x403774b7:0x3fc97aa0 0x403775cd:0x3fc97ad0 0x4037769c:0x3fc97af0 0x420653c1:0x3fc97b20 0x42068505:0x3fc97e30 0x42075151:0x3fc97e60 0x40384555:0x3fc97e90 0x40377b75:0x3fc97ee0 0x40379d85:0x3fc97f00 0x40377295:0x3fc97f30 0x4037d8a7:0x3fcf3fb0 0x42003bc2:0x3fcf3fd0 0x40380151:0x3fcf3ff0 0x4038195d:0x3fcf4010
0x40375ebe: panic_abort at /home/boko/esp/esp-idf/components/esp_system/panic.c:423
0x4037ec61: esp_system_abort at /home/boko/esp/esp-idf/components/esp_system/esp_system.c:135
0x403846a6: abort at /home/boko/esp/esp-idf/components/newlib/abort.c:38
0x403774b7: lock_acquire_generic at /home/boko/esp/esp-idf/components/newlib/locks.c:130
0x403775cd: _lock_acquire_recursive at /home/boko/esp/esp-idf/components/newlib/locks.c:158
0x4037769c: __retarget_lock_acquire_recursive at /home/boko/esp/esp-idf/components/newlib/locks.c:314 (discriminator 3)
0x420653c1: _vfprintf_r at ??:?
0x42068505: vprintf at /builds/idf/crosstool-NG/.build/xtensa-esp32s3-elf/src/newlib/newlib/libc/stdio/vprintf.c:34 (discriminator 5)
0x42075151: esp_log_writev at /home/boko/esp/esp-idf/components/log/log.c:200
0x40384555: esp_log_write at /home/boko/esp/esp-idf/components/log/log.c:210
0x40377b75: timer_alarm_cb at /home/boko/Desktop/ESP32/ble_ibeacon/main/ibeacon_demo.c:200
0x40379d85: gptimer_default_isr at /home/boko/esp/esp-idf/components/driver/gptimer.c:512
0x40377295: _xt_lowint1 at /home/boko/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/xtensa_vectors.S:1118
0x4037d8a7: xt_utils_wait_for_intr at /home/boko/esp/esp-idf/components/xtensa/include/xt_utils.h:81
(inlined by) esp_cpu_wait_for_intr at /home/boko/esp/esp-idf/components/esp_hw_support/cpu.c:115
0x42003bc2: esp_vApplicationIdleHook at /home/boko/esp/esp-idf/components/esp_system/freertos_hooks.c:59
0x40380151: prvIdleTask at /home/boko/esp/esp-idf/components/freertos/FreeRTOS-Kernel/tasks.c:4273 (discriminator 1)
0x4038195d: vPortTaskWrapper at /home/boko/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:152

You're trying to log from within a General Purpose Timer interrupt. Quoting from documentation for Logging library:
This function or these macros should not be used from an interrupt.
There's also a longer comment from an Espressif developer explaining why. There seems to be another macro ESP_DRAM_LOGE for printing from within an interrupt (which is usually not a good idea).
Anyway, for anything except the most stringent real-time criteria I'd recommend using the High Resolution Timer instead. It's still run on top of the hardware timer peripheral, but processing of callbacks is deferred to a dedicated timer task (yes, you have to wait for a short time until the scheduler gets around to executing that task). This means your callbacks run in a regular task and can call logging functions. Don't go overboard - you still want the deferred timer callbacks to be reasonably quick to avoid timing jittering.

Related

ESP IDF: Task never leaves vTaskDelay()

I am building a system that creates a WLAN AP over which the end user can Connect/disconnect the ESP to another AP ( For example a router) by posting a JSON String to a URL. In APSTA mode. When this is done a bool "_STA_START" is set to true. And the login parameters are saved in _STA_WIFI_SSID and _STA_WIFI_PASS.
I encounter a problem when writing the Task that manages the esp as Station. When the vTaskDelay() is called the code in the vTask_Manage_STA_Connection() just stops running. If I delete the statement. The code runs very fast until it casues a stack overflow and resets the esp.
start_Manage_STA_Connection() is called in main.c after I initialise the esp as Access Point.
Right now I see on the monitor that the loop in the vTask_Manage_STA_Connection runs a single time.
Below you can find my Tasks.c and Task.h
Task.h
#ifndef INCLUDE
#define INCLUDE
#include "config.h"
#endif
#ifndef INCLUDE_WLAN_STA
#define INCLUDE_WLAN_STA
#include "WLAN_STA.h"
#endif
// Dimensions the buffer that the task being created will use as its stack.
// NOTE: This is the number of words the stack will hold, not the number of
// bytes. For example, if each stack item is 32-bits, and this is set to 100,
// then 400 bytes (100 * 32-bits) will be allocated.
#define STACK_SIZE 2048
/// #brief Starts a Task to Manage the STA Connection
/// #param pvParameters
void vTask_Manage_STA_Connection( void * pvParameters );
/// #brief Calls vTask_Manage_STA_Connection in main.c
/// #param
void start_Manage_STA_Connection( void );
Tasks.c
#include "Tasks.h"
static const char *TAG_Manage_STA = "Manage STA Connection";
// Task to be created.
void vTask_Manage_STA_Connection(void *pvParameters)
{
for (;;)
{
// Task code goes here.
if (_STA_START == true)
{
ESP_LOGI(TAG_Manage_STA, "Connecting to Station...");
wifi_init_sta(
_STA_WIFI_SSID,
_STA_WIFI_PASS);
_STA_START = false;
}
ESP_LOGI(TAG_Manage_STA, "Managing STA Connection...");
vTaskDelay(100/portTICK_PERIOD_MS);
}
}
// Function that creates a task.
void start_Manage_STA_Connection(void)
{
static uint8_t ucParameterToPass;
TaskHandle_t xHandle = NULL;
// Create the task pinned to core 0, storing the handle. Note that the passed parameter ucParameterToPass
// must exist for the lifetime of the task, so in this case is declared static. If it was just an
// an automatic stack variable it might no longer exist, or at least have been corrupted, by the time
// the new task attempts to access it.
xTaskCreatePinnedToCore(vTask_Manage_STA_Connection,
"Manage_STA_Connection",
STACK_SIZE,
&ucParameterToPass,
(configMAX_PRIORITIES-1),
&xHandle, 0);
configASSERT(xHandle);
// Use the handle to delete the task.
if (xHandle != NULL)
{
vTaskDelete(xHandle);
}
}
The Monitor Output:
I (0) cpu_start: App cpu up.
I (388) cpu_start: Pro cpu start user code
I (388) cpu_start: cpu freq: 160000000
I (388) cpu_start: Application information:
I (392) cpu_start: Project name: wifi_softAP
I (398) cpu_start: App version: 1
I (402) cpu_start: Compile time: Dec 5 2022 11:50:36
I (408) cpu_start: ELF file SHA256: 3597702b82953470...
I (414) cpu_start: ESP-IDF: v4.4.2
I (419) heap_init: Initializing. RAM available for dynamic allocation:
I (426) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (432) heap_init: At 3FFB7508 len 00028AF8 (162 KiB): DRAM
I (438) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (445) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (451) heap_init: At 400944E0 len 0000BB20 (46 KiB): IRAM
I (459) spi_flash: detected chip: gd
I (462) spi_flash: flash io: dio
I (467) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (559) MAIN: ESP_WIFI_MODE_AP/STA
I (569) WLAN AP: Wifi Loop Started
I (579) wifi:wifi driver task: 3ffc0378, prio:23, stack:6656, core=0
I (579) system_api: Base MAC address is not set
I (579) system_api: read default base MAC address from EFUSE
I (609) wifi:wifi firmware version: eeaa27d
I (609) wifi:wifi certification version: v7.0
I (609) wifi:config NVS flash: enabled
I (609) wifi:config nano formating: disabled
I (609) wifi:Init data frame dynamic rx buffer num: 32
I (619) wifi:Init management frame dynamic rx buffer num: 32
I (619) wifi:Init management short buffer num: 32
I (629) wifi:Init dynamic tx buffer num: 32
I (629) wifi:Init static rx buffer size: 1600
I (629) wifi:Init static rx buffer num: 10
I (639) wifi:Init dynamic rx buffer num: 32
I (639) wifi_init: rx ba win: 6
I (649) wifi_init: tcpip mbox: 32
I (649) wifi_init: udp mbox: 6
I (649) wifi_init: tcp mbox: 6
I (659) wifi_init: tcp tx win: 5744
I (659) wifi_init: tcp rx win: 5744
I (669) wifi_init: tcp mss: 1440
I (669) wifi_init: WiFi IRAM OP enabled
I (669) wifi_init: WiFi RX IRAM OP enabled
I (689) phy_init: phy_version 4670,719f9f6,Feb 18 2021,17:07:07
I (789) wifi:mode : sta (30:ae:a4:80:4e:88) + softAP (30:ae:a4:80:4e:89)
I (789) wifi:enable tsf
I (789) wifi:Total power save buffer number: 16
I (789) wifi:Init max length of beacon: 752/752
I (789) wifi:Init max length of beacon: 752/752
I (799) WLAN AP: Error: Unknown AP Exception
I (799) WLAN AP: wifi_init_softap finished. SSID:myssid password:mypassword channel:4
I (799) WLAN AP: Access point started!
I (819) Manage STA Connection: Managing STA Connection...
I (91529) wifi:new:<1,1>, old:<1,1>, ap:<1,1>, sta:<0,0>, prof:1
I (91529) wifi:station: 1c:bf:ce:ca:79:de join, AID=1, bgn, 40U
I (91549) WLAN AP: station 1c:bf:ce:ca:79:de join, AID=1
I (91559) esp_netif_lwip: DHCP server assigned IP to a station, IP is: 192.168.5.2
I (91559) AP Webserver: Starting webserver
I (91559) AP Webserver: Starting server on port: '80'
I (91569) AP Webserver: Registering URI handlers
W (95189) wifi:<ba-add>idx:2 (ifx:1, 1c:bf:ce:ca:79:de), tid:0, ssn:190, winSize:64

Can't access gpio line with gpiod_line_request_output() on Adafruit FT232H

I am using an Adafruit Ft232H breakout to add GPIO ports to my Linux pc. Although I had some success to flash a led with libftdi and bitbang mode, I don't have the same luck with libgpiod because gpiod_line_request_output is failing.
Some gpio information of my system:
sudo gpiodetect
gpiochip0 [ftdi-cbus] (4 lines)
sudo gpioinfo
gpiochip0 - 4 lines:
line 0: unnamed unused input active-high
line 1: unnamed unused input active-high
line 2: unnamed unused input active-high
line 3: unnamed unused input active-high
This is the C program which tries to access the line 0.
#include <stdio.h>
#include <stdlib.h>
#include <gpiod.h>
#define LINE_NUM 0
void gpio_fatal(struct gpiod_chip* chip, const char msg[20]);
int main(int argc, char** argv)
{
struct gpiod_chip* chip;
struct gpiod_line* line;
const char path[] = "/dev/gpiochip0";
chip = gpiod_chip_open(path);
if(!chip)
{
fprintf(stderr, "Error opening path\n");
return EXIT_FAILURE;
}
line = gpiod_chip_get_line(chip, LINE_NUM);
if(!line)
{
fprintf(stderr, "error getting this line\n");
return EXIT_FAILURE;
}
int ret = gpiod_line_request_output(line,
"ftdi-cbus",
1);
if(ret != 0)
gpio_fatal(chip, "Request output failed");
for(;;)
{
gpiod_line_set_value(line, 1);
printf("On\n");
sleep(1);
gpiod_line_set_value(line, 0);
printf("Off\n");
sleep(1);
}
gpiod_line_release(line);
gpiod_chip_close(chip);
return EXIT_SUCCESS;
}
void gpio_fatal(struct gpiod_chip* chip, const char* msg)
{
fprintf(stderr, "%s\n", msg);
gpiod_chip_close(chip);
exit(EXIT_FAILURE);
}
Running the executable with sudo gives me:
sudo g_gpiod/build/g_gpiod
Password:
Request output failed
gpiod.h states for the failing function the following:
/**
* #brief Reserve a single line, set the direction to output.
* #param line GPIO line object.
* #param consumer Name of the consumer.
* #param default_val Initial line value.
* #return 0 if the line was properly reserved, -1 on failure.
*/
int gpiod_line_request_output(struct gpiod_line *line,
const char *consumer, int default_val) GPIOD_API;
The parameters seem to be correct, for what reason could this be failing? Other examples using libftdi or CircuitPython can access the ports and work correctly.
You need to flash the EEPROM to set the function of pin C5, e.g. using the ftdi_eeprom command from libftdi. First, unload the ftdi_sio module and save the original EEPROM:
$ sudo rmmod ftdi_sio
$ sudo ftdi_eeprom --verbose --device i:0x0403:0x6014 ft232h-orig.conf
FTDI eeprom generator v0.17
(c) Intra2net AG and the libftdi developers <opensource#intra2net.com>
FTDI read eeprom: 0
EEPROM size: 256
VID: 0x0403
PID: 0x6014
Release: 0x0900
Bus Powered: 100 mA
Manufacturer: ÿÿÿÿÿÿÿÿ
Product: ÿÿÿÿÿÿ
Serial: ÿÿÿÿÿÿÿÿ
Checksum : ffff
PNP: 1
Channel A has Mode UART
FT1284 Mode Clock is idle LOW, MSB first, No Flow Control
ACBUS has 4 mA drive
ADBUS has 4 mA drive
C0 Function: TRISTATE
C1 Function: TRISTATE
C2 Function: TRISTATE
C3 Function: TRISTATE
C4 Function: TRISTATE
C5 Function: TRISTATE
C6 Function: TRISTATE
C7 Function: TRISTATE
C8 Function: DRIVE_1
C9 Function: DRIVE_0
FTDI close: 0
The file ft232h-orig.conf contains just a single line filename="ft232h-orig.bin".
You can control 4 GPIO pins of the FT232H using the ftdi_sio module:
| line | pin | remarks |
==========================
| 0 | C5 | - |
| 1 | C6 | - |
| 2 | C8 | red led |
| 3 | C9 | green led |
The Adafruit board has the cathodes of two LEDs (red and green) connected to pins C8 and C9. The default EEPROM has C9 set to DRIVE_0 so that the green LED is "on" when the board is powered up.
Here is my config file for ftdi_eeprom:
$ cat ft232h-libgpiod.conf
vendor_id="0x0403"
product_id="0x6014"
manufacturer="Adafruit"
product="FT232H Breakout"
# whatever
serial="20211223"
use_serial=true
max_power=100
self_powered=false
remote_wakeup=false
cha_type=UART
cha_vcp=false
cbush5=IOMODE
cbush6=IOMODE
# red led
cbush8=IOMODE
# green led
cbush9=DRIVE_0 # power-on indicator
#cbush9=IOMODE
$ sudo ftdi_eeprom --verbose --device i:0x0403:0x6014 --flash-eeprom ft232h-libgpiod.conf
Your program now works fine with line 0 on pin C5. As a bonus, you can now control the red LED with the libgpiod commands:
# turn red LED on (low active)
sudo gpioset gpiochip0 2=0

LPC1788 microcontroller intermittently not sending USB messages

I'm developing code for the NXP LPC1788 microcontroller, and part of my work is making the product based on it USB-compatible. Most of the legwork is done and in general communication over USB works almost as well as over CAN.
However, one of the issues I've been encountering is that, when producing a constant output of USB messages from the microcontroller that are sent pretty close together, some of these messages are occasionally dropped.
I'm using a custom driver I wrote based on WinUSB to receive the messages on the PC side, and I originally suspected that the problem was on the receiving end of things. However, using USBLyzer I'm now confident that the problem is on the sending side - the USBLyzer logs perfectly match logs produced from what I get out of WinUsb_ReadPipe().
The LPC1788 uses USB 2.0 Full Speed protocol and I've confirmed that information is being sent and received at around 12 MHz using a probe, which is what it should be.
The device is configured to make use of two endpoints: logical endpoint 2 IN and logical endpoint 2 OUT. Both of these are configured for bulk transfer with a maximum packet size of 64 bytes.
I would think that messages are being sent around 500-600 microseconds apart at the least (I've introduced an artificial 500 us delay in the thread and message transmission should take a lot less time than that). This is about what I got last week; I can't check now as my debugging tools are acting up.
This is the USB initialisation code for the microcontroller:
void USBInit()
{
// Configure USB pins.
PINSEL_ConfigPin(0, 29, 1); // USB_D+1
PINSEL_ConfigPin(0, 30, 1); // USB_D-1
PINSEL_ConfigPin(1, 18, 1); // USB_UP_LED1
PINSEL_ConfigPin(2, 9, 1); // USB_CONNECT1
PINSEL_ConfigPin(1, 30, 2); // USB_VBUS
// Turn on power and clock
CLKPWR_ConfigPPWR(CLKPWR_PCONP_PCUSB, ENABLE);
PINSEL_SetPinMode(1, 30, PINSEL_BASICMODE_PLAINOUT);
// Set DEV_CLK_EN and AHB_CLK_EN.
LPC_USB->USBClkCtrl |= 0x12;
// Wait until change is reflected in clock status register.
while((LPC_USB->USBClkSt & 0x12) != 0x12);
// Enable NVIC USB interrupts.
NVIC_EnableIRQ(USB_IRQn);
// Reset the USB.
USBReset();
// Set device address to 0x0 and enable device & connection.
USBSetAddress(0);
}
This is the code used by the microcontroller to send messages via USB:
uint32_t USB_Send(uint32_t endpoint, uint8_t *pData, uint32_t count)
{
// Convert into a form that can be sent successfully using USB.
uint8_t data[USB_MAX_PACKET_SIZE];
for(int i=0; i < count; i++)
{
data[i*2] = hex[(pData[i] >> 4)];
data[(i*2)+1] = hex[(pData[i] & 0xF)];
}
return USBWriteEndpoint(endpoint, data, count*2);
}
uint32_t USBWriteEndpoint(uint32_t endpoint, uint8_t *pData, uint32_t count)
{
uint32_t i;
LPC_USB->Ctrl = ((endpoint & 0xF) << 2) | CTRL_WR_EN;
LPC_USB->TxPLen = count;
for(i=0; i < (count+3)/4; i++)
{
LPC_USB->TxData = *((__packed uint32_t *)pData);
pData += 4;
}
LPC_USB->Ctrl = 0;
USBValidateEndpoint(endpoint);
return count;
}
void USBValidateEndpoint(uint32_t endpoint)
{
writeSIEEndpointCommand(endpoint, CMD_VALID_BUF);
}
void writeSIECommandData(uint32_t cmd, uint32_t data)
{
LPC_USB->DevIntClr = CCEMTY_INT;
LPC_USB->CmdCode = cmd;
while((LPC_USB->DevIntSt & CCEMTY_INT) == 0);
LPC_USB->DevIntClr = CCEMTY_INT;
LPC_USB->CmdCode = data;
while((LPC_USB->DevIntSt & CCEMTY_INT) == 0);
}
EDIT
To give an idea of what's happening, this is a log file produced from my USB driver's receive function (the one from USBLyzer is practically identical):
0000030D000D
0000010D002D0004001B0024
0000000D0FFF001600310016
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000000D0FFF001600310016
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000000D0FFF001600310016
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000010D002D0004001F0028
I should be receiving messages in the following cycle:
0000000D...
0000010D...
0000020D...
0000030D...
You can see from this log that some of the messages in the cycle are getting skipped.
EDIT 2
Included below are excerpts from the raw and filtered capture logs produced by USBLyzer. The raw logs mostly consist of cancelled requests because my driver is poll-driven and uses a timeout.
Raw logs:
USBlyzer Report
Capture List
Type Seq Time Elapsed Duration Request Request Details Raw Data I/O C:I:E Device Object Device Name Driver Name IRP Status
START 0001 11:09:15.413
URB 0002 11:09:18.484 3.071197 s Bulk or Interrupt Transfer 10 bytes data 30 30 30 30 30 30 31 46... out 01:00:02 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA801142FAB0h
00000000 30 30 30 30 30 30 31 46 30 31 0000001F01
URB 0003 11:09:18.484 3.071212 s Bulk or Interrupt Transfer 64 bytes buffer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h
URB 0004-0002 11:09:18.484 3.071371 s 174 us Bulk or Interrupt Transfer 10 bytes buffer out 01:00:02 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA801142FAB0h Success (Success)
URB 0005-0003 11:09:18.485 3.071586 s 374 us Bulk or Interrupt Transfer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Cancelled (Canceled)
URB 0006 11:09:18.485 3.071608 s Bulk or Interrupt Transfer 64 bytes buffer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h
URB 0007-0006 11:09:18.486 3.072582 s 974 us Bulk or Interrupt Transfer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Cancelled (Canceled)
URB 0008 11:09:18.486 3.072603 s Bulk or Interrupt Transfer 64 bytes buffer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h
URB 0009-0008 11:09:18.487 3.073598 s 996 us Bulk or Interrupt Transfer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Cancelled (Canceled)
URB 0010 11:09:18.487 3.073630 s Bulk or Interrupt Transfer 64 bytes buffer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h
URB 0011-0010 11:09:18.488 3.074601 s 970 us Bulk or Interrupt Transfer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Cancelled (Canceled)
[...]
URB 2504-2501 11:09:19.734 4.320666 s 161 us Bulk or Interrupt Transfer 14 bytes buffer out 01:00:02 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA800CF662D0h Success (Success)
URB 2505-2503 11:09:19.734 4.320785 s 192 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 30 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 30 30 44 30 46 46 46 30 30 31 36 0000000D0FFF0016
00000010 30 30 33 31 30 30 31 42 0031001B
Filtered logs:
USBlyzer Report
Capture List
Type Seq Time Elapsed Duration Request Request Details Raw Data I/O C:I:E Device Object Device Name Driver Name IRP Status
URB 0004-0002 11:09:18.484 3.071371 s 174 us Bulk or Interrupt Transfer 10 bytes buffer out 01:00:02 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA801142FAB0h Success (Success)
URB 2504-2501 11:09:19.734 4.320666 s 161 us Bulk or Interrupt Transfer 14 bytes buffer out 01:00:02 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA800CF662D0h Success (Success)
URB 2505-2503 11:09:19.734 4.320785 s 192 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 30 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 30 30 44 30 46 46 46 30 30 31 36 0000000D0FFF0016
00000010 30 30 33 31 30 30 31 42 0031001B
URB 2507-2506 11:09:19.734 4.321309 s 459 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 31 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 31 30 44 30 30 32 44 30 30 30 34 0000010D002D0004
00000010 30 30 31 46 30 30 32 44 001F002D
URB 2511-2510 11:09:19.735 4.321931 s 311 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 32 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 32 30 44 30 30 32 38 30 30 32 38 0000020D00280028
00000010 30 30 31 42 30 30 33 31 001B0031
URB 2513-2512 11:09:19.735 4.322306 s 332 us Bulk or Interrupt Transfer 12 bytes data 30 30 30 30 30 33 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 33 30 44 30 30 30 44 0000030D000D
URB 2725-2724 11:09:19.840 4.426662 s 89 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 30 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 30 30 44 30 46 46 46 30 30 31 36 0000000D0FFF0016
00000010 30 30 33 31 30 30 31 42 0031001B
URB 2727-2726 11:09:19.840 4.427183 s 471 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 31 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 31 30 44 30 30 32 44 30 30 30 34 0000010D002D0004
00000010 30 30 31 46 30 30 32 44 001F002D
URB 2731-2730 11:09:19.841 4.427803 s 209 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 32 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 32 30 44 30 30 32 38 30 30 32 38 0000020D00280028
00000010 30 30 31 42 30 30 33 31 001B0031
Do you have a hardware USB analyzer available? I'm not sure how USBLyzer works but I presume it is still using the Windows USB subsystem at the lowest levels. My experience with Windows USB subsystem has been that it is extremely bug-riddled - one particular example was when transferring data that is an exact multiple of the max frame size, it doesn't work. I'm not saying this is your exact problem - we had different symptoms from what you are reporting - but in your shoes I would look at a) changing the max amount of data your transmitting end will send in one frame so it's not an exact multiple of the frame size, and b) getting a hardware USB analyzer to see what is actually on the wire.
The problem might be the USB_IRQHandler interrupting your write function. That would leave the USB unexpected in a different state, thus the write fails.
You can temporary disable the IRQ as a workaround:
uint32_t USBWriteEndpoint(uint32_t endpoint, uint8_t *pData, uint32_t count)
{
uint32_t i;
NVIC_DisableIRQ(USB_IRQn); // USB IRQ handlaer must not run ...
LPC_USB->Ctrl = ((endpoint & 0xF) << 2) | CTRL_WR_EN;
LPC_USB->TxPLen = count;
for(i=0; i < (count+3)/4; i++)
{
LPC_USB->TxData = *((__packed uint32_t *)pData);
pData += 4;
}
LPC_USB->Ctrl = 0;
USBValidateEndpoint(endpoint);
NVIC_EnableIRQ(USB_IRQn); // ... until we are here. Enable USB IRQ again
return count;
}
I think I've managed to make some significant improvements in the way that the microcontroller sends USB messages.
On page 400 of the LPC178x/7x user manual, I saw a description for how to properly handle sending data from the device to the host using a bulk IN endpoint. It was pretty lucky that I eventually stumbled across it since it was within the DMA section of the chapter (and I'm not using DMA so until now I've ignored it).
Based on what I read there, I added the following method:
// Params: endpoint - the logical endpoint number.
// Returns: TRUE if at least one write buffer is free,
// FALSE otherwise.
// Description: Checks that the IN endpoint has a free write buffer.
uint8_t USBCheckInEndpointFree(uint32_t endpoint)
{
uint16_t data;
uint32_t physicalEndpoint = getEndpointPhysicalAddress(endpoint);
writeSIECommand(CMD_SEL_EP(physicalEndpoint));
data = readSIECommandData(DAT_SEL_EP(physicalEndpoint));
return (data & 0x1) == 0;
}
I changed USBWriteEndpoint to the following:
uint32_t USBWriteEndpoint(uint32_t endpoint, uint8_t *pData, uint32_t count)
{
uint32_t i = 0;
NVIC_DisableIRQ(USB_IRQn);
if((endpoint & 0xF) != 0)
{
while(getSendMessageFlag(endpoint & 0xF) != 0);
setSendMessageFlag(endpoint & 0xF);
}
while(!USBCheckInEndpointFree(endpoint))
{
uint32_t physicalEndpoint = getEndpointPhysicalAddress(endpoint);
writeSIECommand(CMD_SEL_EP(physicalEndpoint));
ITM_EVENT32_WITH_PC(3, readSIECommandData(DAT_SEL_EP(physicalEndpoint)));
}
LPC_USB->Ctrl = ((endpoint & 0xF) << 2) | CTRL_WR_EN;
LPC_USB->TxPLen = count;
for(i=0; i < (count+3)/4; i++)
{
LPC_USB->TxData = *((__packed uint32_t *)(pData+i*4));
//pData += 4;
}
ITM_EVENT32_WITH_PC(4, (pData[4] << 24) | (pData[5] << 16) | (pData[6] << 8) | pData[7]);
LPC_USB->Ctrl = 0;
USBValidateEndpoint(endpoint);
NVIC_EnableIRQ(USB_IRQn);
return count;
}
The ITM_EVENT32_WITH_PC macro is used for debugging.
While sending USB messages at a high rate, I noticed this pattern in the event timeline:
In that image, the lines within the third channel show where the thread is caught within the while loop because none of the write buffers of the endpoint I'm using are free. The lines in the fourth channel are where a message is written to one of the endpoint's write buffers.
The LPC1788 uses double-buffering for bulk and isochronous endpoints, so what you're seeing in that image is the following:
The microcontroller tries to send a USB message to the host. Both write buffers are free, so it picks one and uses that.
The micro tries to send a second message. It uses the remaining free write buffer.
The micro tries to send a third message. Both buffers are in use so it has to wait. That produces the series of lines in the third channel while the micro polls the endpoint status.
Eventually one of the buffers (probably the first one used) becomes free, and the message is written to that.
The micro tries to send a fourth message. Both buffers are in use and the micro apparently has to wait a fair while before one of them becomes free.
Eventually one of the buffers becomes free and it writes the message to that.
Before adding in that additional check, I got behaviour like this:
Clearly without the check, the endpoint's buffers are getting overwritten!
To check how well this change resolved the problem, I created a Python script with a simple algorithm that I chose to evaluate performance by comparing how well the output from the USB logs (generated by one of my USB drivers on the PC end) conforms to a perfect cycle (which is what I'd ideally want).
I did three runs of my program with the additional check and three runs of my program without it, each time leaving it running long enough for 1000 USB messages to be received and recorded in a log file by the DLL.
The three logs with the additional check were USBLogGood1.txt ... USBLogGood3.txt. The three without the check were USBLogBad1.txt ... USBLogBad3.txt.
The Python code is given below:
# Checks how well the USB is performing by checking how
# closely the stream of USB messages returned by the DLL
# matches a perfect cyclical pattern.
from statistics import *
cycle = [1,2,3,4]
sampleSize = 1000
class Globals:
totalCount = 0
errorCount = 0
usbLogFile = "usbLog.txt"
usbGoodLogFiles = ["usbLogGood1.txt",
"usbLogGood2.txt",
"usbLogGood3.txt"]
usbBadLogFiles = ["usbLogBad1.txt",
"usbLogBad2.txt",
"usbLogBad3.txt"]
# Switch between sets of log files.
usbLogFiles = usbBadLogFiles
# Read log file.
def readLog(logFile):
with open(logFile) as fIn:
return fIn.readlines()
# Converts raw log data into a list of cycle values.
def processLog(log):
data = []
for line in log:
data.append(processLogLine(line))
return data
# Converts raw log line into a cycle value.
def processLogLine(logLine):
l = logLine.replace("Message ", "")
return int(l[5],16)+1
# Counts distance in one direction, so the distance
# will be high if i2 is behind i1.
def getListDistance(val1, val2):
cycleLen = len(cycle)
i1 = cycle.index(val1)
i2 = cycle.index(val2)
if i1 <= i2:
return i2 - i1
else:
return (cycleLen - i1) + i2
def getNextValueInCycle(val):
cycleLen = len(cycle)
i = cycle.index(val)
if i < cycleLen-1:
return cycle[i+1]
else:
return cycle[0]
def checkCycleValue(expected, value):
Globals.totalCount += 1
if value != expected:
Globals.errorCount += getListDistance(expected, value)
expected = getNextValueInCycle(value)
return expected
def getPerformance():
return 1-float(Globals.errorCount)/float(Globals.totalCount)
def printPerformance():
print("Sampled %d values. USB performance: %0.1f%%"
% (Globals.totalCount, getPerformance()*100))
# Read log file and evaluate performance.
def evaluatePerformance(logFile):
Globals.totalCount = 0
Globals.errorCount = 0
log = readLog(logFile)
data = processLog(log)
if not data:
print("No data available")
return
if len(data) < sampleSize:
print("Not enough data available to meet requirements")
return
else:
data = data[:sampleSize]
expected = data[0]
for value in data:
expected = checkCycleValue(expected, value)
return getPerformance()
def printAggregatePerformanceData(logFiles, performances):
performances = [100*p for p in performances]
for f, p in zip(logFiles, performances):
print("%s: %0.2f%%" % (f, p))
print("\nAverage performance: %0.2f%%" % mean(performances))
print("Standard deviation: %0.2f" % stdev(performances))
def main():
performances = []
for logFile in usbLogFiles:
performances.append(evaluatePerformance(logFile))
printAggregatePerformanceData(usbLogFiles, performances)
if __name__ == "__main__":
main()
With the good set of logs, I got the following output:
usbLogGood1.txt: 93.70%
usbLogGood2.txt: 92.50%
usbLogGood3.txt: 92.60%
Average performance: 92.93%
Standard deviation: 0.67
For the bad set, I got this:
usbLogBad1.txt: 16.60%
usbLogBad2.txt: 13.80%
usbLogBad3.txt: 14.10%
Average performance: 14.83%
Standard deviation: 1.54
By adding in the additional check to make sure a write buffer is free, I managed to increase the 'performance' of the USB by around 78.1% (100% means a perfect cycle of USB messages: 1,2,3,4,1,2,3,4,1,2,3,4...).
In addition to this, I found that the message throughput about doubled when I put the check in, despite the delays associated with waiting in while loops.
92.93% still isn't perfect, but the manual talks about checking for ACKS from the host as well as just free write endpoints. I tried to do that earlier (without apparent success), but this was before I tried this check. Hopefully, if I implement both together I can get the USB performance to rival that of CAN.
Edit: The wait for ACK thing didn't work, but if I force a 1ms delay in between sending messages, I can get a performance of ~99.99...%.
This is not an ideal solution since 1ms is quite a long time to be delaying for, so I'm leaving the question unresolved for now.
EDIT
I quite firmly believe at this point that the issue is mainly with the PC-side driver I wrote. It doesn't read fast enough.

BBB - Trouble getting second SPI chip select with device tree

I have trouble to get second chip select working on the Beaglebone Black.
I used the .dts given in /lib/firmware with my distribution (Angstrom, kernel 3.8.13) :
/*
* Copyright (C) 2013 CircuitCo
*
* Virtual cape for SPI1 on connector pins P9.29 P9.31 P9.30 P9.28
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/dts-v1/;
/plugin/;
/ {
compatible = "ti,beaglebone", "ti,beaglebone-black";
/* identification */
part-number = "BB-SPI1-01";
version = "00A0";
/* state the resources this cape uses */
exclusive-use =
/* the pin header uses */
"P9.31", /* spi1_sclk */
"P9.29", /* spi1_d0 */
"P9.30", /* spi1_d1 */
"P9.28", /* spi1_cs0 */
"P9.42", /* spi1_cs1 */
/* the hardware ip uses */
"spi1";
fragment#0 {
target = <&am33xx_pinmux>;
__overlay__ {
/* default state has all gpios released and mode set to uart1 */
bb_spi1_pins: pinmux_bb_spi1_pins {
pinctrl-single,pins = <
0x190 0x13 /* mcasp0_aclkx.spi1_sclk, OUTPUT_PULLUP | MODE3 */
0x194 0x33 /* mcasp0_fsx.spi1_d0, INPUT_PULLUP | MODE3 */
0x198 0x13 /* mcasp0_axr0.spi1_d1, OUTPUT_PULLUP | MODE3 */
0x19c 0x13 /* mcasp0_ahclkr.spi1_cs0, OUTPUT_PULLUP | MODE3 */
0x164 0x12 /* eCAP0_in_PWM0_out.spi1_cs1 OUTPUT_PULLUP | MODE2 */
>;
};
};
};
fragment#1 {
target = <&spi1>; /* spi1 is numbered correctly */
__overlay__ {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&bb_spi1_pins>;
#address-cells = <1>;
#size-cells = <0>;
cs-gpios = <&gpio4 17 0>, <&gpio1 7 0>;
spi1_0{
#address-cells = <1>;
#size-cells = <0>;
compatible = "spidev";
reg = <0>;
spi-max-frequency = <16000000>;
};
spi1_1{
#address-cells = <1>;
#size-cells = <0>;
compatible = "spidev";
reg = <1>;
spi-max-frequency = <16000000>;
};
};
};
};
I compiled it with dtc and activate it with uEnv.txt :
capemgr.enable_partno=BB-SPI1-01
(Both HDMI and HDMIN capes are disabled)
I have the twos SPI device shown in /dev/ :
/dev/spidev2.0 /dev/spidev2.1
and the pins are used by the spi interface as shown :
root#beaglebone:~# cat $PINS | grep spi1
pin 89 (44e10964): 481a0000.spi (GPIO UNCLAIMED) function pinmux_bb_spi1_pins group pinmux_bb_spi1_pins
pin 100 (44e10990): 481a0000.spi (GPIO UNCLAIMED) function pinmux_bb_spi1_pins group pinmux_bb_spi1_pins
pin 101 (44e10994): 481a0000.spi (GPIO UNCLAIMED) function pinmux_bb_spi1_pins group pinmux_bb_spi1_pins
pin 102 (44e10998): 481a0000.spi (GPIO UNCLAIMED) function pinmux_bb_spi1_pins group pinmux_bb_spi1_pins
pin 103 (44e1099c): 481a0000.spi (GPIO UNCLAIMED) function pinmux_bb_spi1_pins group pinmux_bb_spi1_pins
And the mode is good :
pin 89 (44e10964) 00000012 pinctrl-single
pin 100 (44e10990) 00000013 pinctrl-single
pin 101 (44e10994) 00000033 pinctrl-single
pin 102 (44e10998) 00000013 pinctrl-single
pin 103 (44e1099c) 00000013 pinctrl-single
I successfully use a programm in C which use the first spidev (spidev2.0) with the first chip select, but the there are nothing on pin 42 when I use spidev2.1 (MOSI,MISO and CLK are working though).
Any ideas ?
Thanks in advance
Well I found out the answer myself :
The pin 42 is special since it's connected to two I/O. So in order to use one of the I/O, you have to put the other one as input.
source : Beaglebone black system reference manual http://www.digikey.com/web%20export/supplier%20content/ti_296/mkt/boards/BBB_SRM.pdf?redirected=1 page 71.
But now i have an other issue really strange... I posted it here : Trouble with SPIDEV, device tree and .dtbo name with Beaglebone Black

PIC32 UART sends garbage characters after initialization

I'm writing code to configure the serial port on a pic32 family device. The initialization appears to work for the most part, but I get garbage data in place of the first 6 characters that I write. I noticed, however, that if I add an arbitrarily long wait at the end of the initialization function, this goes away. Is there some register flag that I need to be waiting on at the end of my initialization? My initialization code is below. If it helps, I am basing this initialization off of the UART section in the pic32 reference manual. I added the code below for my transmission function as well. My expected output string is "Hello from the bootloader code.\r\n" but the actual bytes I get are:
00000000 00 00 aa b1 b1 bd 81 66 72 6f 6d 20 74 68 65 20 |.......from the |
00000010 62 6f 6f 74 6c 6f 61 64 65 72 20 63 6f 64 65 2e |bootloader code.|
00000020 0d 0a
void initializeUART2()
{
uint32 counter;
initialized = TRUE;
U2MODE = 0;
U2STA = 0;
U2BRG = 0;
IEC1bits.U2TXIE = 0;
IEC1bits.U2RXIE = 0;
IEC1bits.U2EIE = 0;
//disable UART transmission before config
U2STA &= ~UART_TRANSMIT_ENABLED_STATUS_FLAG;
//disable UART before config
U2MODE &= ~UART_ENABLED_MODE_FLAG;
RS232_RS485_TRIS=0; //set to output
RS232_RS485=0; //select RS-232 mode on MAX3161
//set baudrate BAUDRATE = CLOCK_FREQUENCY/(16*(U2BRG + 1))
//solve for U2BRG value
U2BRG = (UINT16)(((PERIPHERAL_CLOCK_FREQUENCY/UART2_BAUDRATE)/16)-1);
//set mode to 8 bit no parity
U2MODE &= ~UART_PARITY_DATA_MODE_BITS;
//set number of stop bits to 1
U2MODE &= ~UART_EXTRA_STOP_MODE_BIT_FLAG;
//enable the UART port
U2MODE |= UART_ENABLED_MODE_FLAG;
//enable serial transmission
U2STA |= UART_TRANSMIT_ENABLED_STATUS_FLAG;
//without this loop, I get garbage in first 6 bytes of my first message
counter = 1000;
while(counter--);
}
void putUART2(uint32 value)
{
if(!initialized)
{
initializeUART2();
}
//make sure value is in range of writable values
value &= UINT32_MASK(8);
//clear transmit interrupt flag
IFS1bits.U2TXIF = 0;
//wait for the transmit buffer to be empty
while((U2STA & UART_TRANSMIT_STATUS_FLAG) == 0);
//set the data byte to be written in the write register
//also starts transmission
U2TXREG = value;
//wait for the transmit buffer to be empty
//both of these waits are necessary to avoid missing bytes
while((U2STA & UART_TRANSMIT_STATUS_FLAG) == 0);
}
The MAX3161 needs at least 100 ns to stabilize after switching modes to RS232.
Also, these lines:
RS232_RS485_TRIS=0; //set to output
RS232_RS485=0; //select RS-232 mode on MAX3161
should be reversed; set the output, then the direction register to avoid glitches.
Suspect the MAX3161 chip, which has charge pumps, needs the additional time to reach stable operating voltages.
It may be only for a bit time or 2, but if a message is sent too early, the serial output is messed until a quiet time occurs.
Lesser candidate: problem is an interaction between this and the unposted send routine.
Note: It's amazing how seeing using info like the unposted "garbage data" may help. Also knowing what the "good" first 6 bytes or so is useful.
[Edit] #Doug Currie is on the right track.
When RS232_RS485_TRIS1 is changed to output, a delay time as he suggest is needed before data is sent. This applies here as well as other place in code.
Further, before RS232_RS485_TRIS1 is changed to input, code needs to insure all the data is completely transmitted. This may be a 10/baud after the the PIC declares the xmit buffer empty. Or check the proper xmit status bit before turning the bus around. (Shift Register empty - names vary depending on compiler.)

Resources