ZBUS subscriber thread throws Illegal use of EPSR error when work queue publishes data

Using the nRF52840, nrf Connect SDK 2.3 with VS Code.

I am trying to use a work queue to publish data from a GPIO button interrupt to a ZBUS channel.

  • The ZBUS channel has two subscribers (a listener function and a subscriber thread) and a validator. These are all defined in main.c
  • There are two GPIO interrupts that can happen, one from pos_a and one from pos_b (it's a momentary switch that can trigger only one of the two), defined in peripheral.c
  • The callback functions from the GPIO interrupt submit a work item to the work queue. The work queue is defined in peripheral.c, but the initialize function is called from main().
  • The work queue publishes data to the zbus, this work function is defined in peripheral.c
  • After the work queue publishes the data both the validator and the listener run fine, but the subscriber thread throws an "Illegal use of the EPSR" when it is activated

Any advice on how to parse this error would be appreciated. Did I just miss a const or a static somewhere?

The code I'm running is as follows, although I tried to trim out code that I thought was irrelevant to the discussion:

main.c

#include <zephyr/zbus/zbus.h>
#include <zephyr/logging/log.h>
#include <stdint.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include "zbus_messages.h"
#include "peripherals.h"

LOG_MODULE_REGISTER(main);

static bool mybutton_validator(const void *msg, size_t msg_size)
{
	ARG_UNUSED(msg_size);

	const struct mybutton_msg *msg_data = msg;
	bool is_valid = 0;
	LOG_INF("Validator info: pos_a %d, pos_b %d, off %d", msg_data->pos_a, msg_data->pos_b, msg_data->off);

	if (msg_data->pos_a && msg_data->pos_b)
	{
		is_valid = 0;
	} else {
		is_valid = msg_data->pos_a ^ msg_data->pos_b ^ msg_data->off;
	}

	if (is_valid == 0) {
		LOG_INF("Button State Data Invalid");
	}

	return is_valid;
}

ZBUS_CHAN_DEFINE(mybutton_chan,
	struct mybutton_msg,
	mybutton_validator,
	NULL,
	ZBUS_OBSERVERS(mybutton_lis, thread_buttoncontrol_sub),
	ZBUS_MSG_INIT(.pos_a=0,
				.pos_b=0,
				.off=1)
);

static void mybutton_cb(const struct zbus_channel *chan)
{
	const struct mybutton_msg *btn_data = zbus_chan_const_msg(chan);

	LOG_INF("Zbus Listener mybutton_data = pos_a %d, pos_b %d, off %d", btn_data->pos_a, btn_data->pos_b, btn_data->off);
}

ZBUS_LISTENER_DEFINE(mybutton_lis, mybutton_cb);

void main(void)
{
	LOG_INF("Starting Main...");
	int ret;
	ret = init_gpio();
	init_periph_zbus_wq();

	while (1) {
			ret = toggle_leds();
			k_msleep(SLEEP_TIME_MS);
	}
}

ZBUS_SUBSCRIBER_DEFINE(thread_buttoncontrol_sub, 4);

static void thread_Buttoncontrol_task(void)
{
    const struct zbus_channel *chan;

    LOG_INF("Button Control Thread Init, pre loop");

    while (!zbus_sub_wait(&thread_buttoncontrol_sub, &chan, K_FOREVER)) {
        LOG_INF("ZBUS sub wait triggered");
        struct mybutton_msg btn_data;

        zbus_chan_read(chan, &btn_data, K_MSEC(250));

        LOG_INF("Button Control Thread: pos_b %d, pos_a %d, off %d", 
                btn_data.pos_b,
                btn_data.pos_a,
                btn_data.off);
    }
}

K_THREAD_DEFINE(thread_Buttoncontrol_id, 
                1024, 
                thread_Buttoncontrol_task, 
                NULL, 
                NULL, 
                NULL, 
                3, 
                0, 
                0);

zbus_messages.h

#ifndef zbus_messages
    #define zbus_messages
    #include <stdint.h>

    /**
     * @brief ZBUS - struct for transition activation switch data
     * 
     */
    struct mybutton_msg {
        uint8_t pos_b;
        uint8_t pos_a;
        uint8_t off;
    };

#endif

peripheral.c

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
#include <zephyr/zbus/zbus.h>
#include "peripherals.h"
#include "zbus_messages.h"

LOG_MODULE_REGISTER(btn_periph);

/* Work Queue Definitions for publishing to ZBUS*/
#define WORQ_THREAD_STACK_SIZE  512
#define WORKQ_PRIORITY   4

K_THREAD_STACK_DEFINE(wq_zbuspub_stack_area, WORQ_THREAD_STACK_SIZE);

/* queue for work queue */
struct k_work_q zbuspub_wq = {0};

/* zbus work handler */
struct zbuspub_wq_info {
	struct k_work work;
	struct transitionstate_msg msg;
} zbuspub_wq_handler;

/* ZBUS CHANNEL Declare */
ZBUS_CHAN_DECLARE(transitionstate_chan);

/**
 * @brief Function to perform work queue work - publish to ZBUS button state
 * 
 * @param work_item 
 */
void zbus_publisher(struct k_work *work_item)
{
	LOG_INF("In ZBUS publisher");

	const struct zbuspub_wq_info *info = CONTAINER_OF(work_item, struct zbuspub_wq_info, work);
	const struct transitionstate_msg *msg_data = &info->msg;

	LOG_INF("Zbus_pub info: pos_b %d, pos_a %d, off %d", msg_data->pos_b, msg_data->pos_a, msg_data->off);
	zbus_chan_pub(&transitionstate_chan, msg_data, K_MSEC(250));
	LOG_INF("WQ Published to ZBUS");
}

/**
 * @brief initialize and start the work queue
 * 
 */
void init_periph_zbus_wq(void) {
	LOG_INF("Starting WQ");
	k_work_init(&zbuspub_wq_handler.work, zbus_publisher);
	k_work_queue_start(&zbuspub_wq, 
						wq_zbuspub_stack_area, 
						K_THREAD_STACK_SIZEOF(wq_zbuspub_stack_area),
						WORKQ_PRIORITY,
						NULL);
}

/**
 * @brief Callback function for the pos_a pin ISR. Starts debounce and starts pos_a process.
 */
void pos_a_cb(const struct device * dev, struct gpio_callback * cb, uint32_t pins)
{
	LOG_INF("Entered pos a callback");

	zbuspub_wq_handler.msg.pos_a = 1;
	zbuspub_wq_handler.msg.pos_b = 0;
	zbuspub_wq_handler.msg.off = 0;
	k_work_submit_to_queue(&zbuspub_wq, &zbuspub_wq_handler.work);
}

/**
 * @brief Callback function for the pos_b pin ISR. Starts debounce and starts pos_b process.
 */
void pos_b_cb(const struct device * dev, struct gpio_callback * cb, uint32_t pins)
{
	LOG_INF("Entered pos b callback");

	zbuspub_wq_handler.msg.pos_a = 0;
	zbuspub_wq_handler.msg.pos_b = 1;
	zbuspub_wq_handler.msg.off = 0;
	k_work_submit_to_queue(&zbuspub_wq, &zbuspub_wq_handler.work);
}

peripheral.h

#ifndef peripherals
    #define peripherals
    #include <stdint.h>

    int toggle_leds(void);
    int init_gpio(void);
    void pos_a_cb(const struct device * dev, struct gpio_callback * cb, uint32_t pins);
    void pos_b_cb(const struct device * dev, struct gpio_callback * cb, uint32_t pins);
    void init_periph_zbus_wq(void);
    
#endif

RTT Log

SEGGER J-Link V7.86e - Real time terminal output
J-Link OB-SAM3U128-V2-NordicSemi compiled Nov  7 2022 16:21:57 V1.0, SN=683227866
Process: JLinkExe
*** Booting Zephyr OS build v3.2.99-ncs2 ***
[00:00:00.547,790] <inf> main: Starting Main...
[00:00:00.553,253] <inf> btn_periph: Device disconnected
[00:00:00.560,150] <inf> btn_periph: Starting WQ
[00:00:00.566,284] <inf> main: Button Control Thread Init, pre loop
[00:00:27.273,162] <inf> btn_periph: Entered pos a callback
[00:00:27.280,120] <inf> btn_periph: In ZBUS publisher
[00:00:27.286,712] <inf> btn_periph: Zbus_pub info: pos_b 0, pos_a 1, off 0
[00:00:27.295,196] <inf> main: Validator info: pos_b 0, pos_a 1, off 0
[00:00:27.302,703] <inf> main: Zbus Listener transitionstate_data = pos_b 0, pos_a 1, off 0
[00:00:27.312,072] <err> os: ***** USAGE FAULT *****
[00:00:27.318,206] <err> os:   Illegal use of the EPSR
[00:00:27.324,523] <err> os: r0/a1:  0x000112d8  r1/a2:  0x00000000  r2/a3:  0x73030080
[00:00:27.333,953] <err> os: r3/a4:  0x00000000 r12/ip:  0x00000000 r14/lr:  0x00000000
[00:00:27.343,322] <err> os:  xpsr:  0x00000000
[00:00:27.349,060] <err> os: s[ 0]:  0x00000000  s[ 1]:  0x00000000  s[ 2]:  0x00000000  s[ 3]:  0x00000000
[00:00:27.360,382] <err> os: s[ 4]:  0x00000000  s[ 5]:  0x00000000  s[ 6]:  0x00000000  s[ 7]:  0x00000000
[00:00:27.371,734] <err> os: s[ 8]:  0x00000000  s[ 9]:  0x00000000  s[10]:  0x00000000  s[11]:  0x00000000
[00:00:27.383,056] <err> os: s[12]:  0x00000000  s[13]:  0x00000000  s[14]:  0x00000000  s[15]:  0x00000000
[00:00:27.394,348] <err> os: fpscr:  0x00000000
[00:00:27.400,085] <err> os: Faulting instruction address (r15/pc): 0x00011134
[00:00:27.408,599] <err> os: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0
[00:00:27.417,053] <err> os: Current thread: 0x20000540 (thread_Buttoncontrol_id)
[00:00:27.426,208] <err> fatal_error: Resetting system

Related