Should be empty queue always has 1 item no matter how many times receive is called

I am programming in c++ for the pico (2 cores) using the FreeRTOS-SCM. I dont have a debugger but do use printf to output debug info to my pc. The queue is created on one core with a “global” variable handle. It has a capability of holding 10 unsigned char. There is a gpio isr that checks the interrupt is from the correct gpio pin and puts a unsigned char message into the queue. A task on another core polls the queue which always says there is 1 item no matter how many times it is received. Has anyone else seen or experienced this behavior?

Global declaration
QueueHandle_t Button_Queue;

Queue creation in main task.
Button_Queue = xQueueCreate( 10, sizeof( unsigned char) );
if( Button_Queue == NULL )
{
/* Queue was not created and must not be used. */
r_uart(printf(“Button_Queue: failed to create queue!\n”));
}

In ISR routine inside gpio pin and event filter code:
message = BUTTON_MESSAGE_PH_FACTORY_RESET;
if (xQueueSendFromISR (Button_Queue, &message, NULL) == pdTRUE){
printf(“Message Sent %d\n”, message);
}

In the code loop of the Task pinned to the other core:
if (num = uxQueueMessagesWaiting( Button_Queue ) > 0 ) {
if (xQueueReceive(Button_Queue, &message, 0) == pdTRUE){
r_uart(printf(“Messages in Q=%d message=%d\n”, num, message));
}
}

The message is always 0 which is not a valid message number in my program and yes the queue handle was defined as extern in this file. There is only one place to put in a message and I can see that this code only fires when the button is push is released. Interestingly when the button is pressed I never see the correct message number being received from the queue.

BTW, The r_uart() is a wrapper macro that uses the semaphore api to keep the printf thread safe. So it can be ignored. notice i didn’t use it in the ISR to be safe.

Using printf in an ISR is likely a bad idea, and may be corrupting memory somewhere.

Welcome to the forums @ddientis! By “FreeRTOS-SCM” I’m assuming your mean the FreeRTOS-SMP port.

From what I can tell, your button press will add something to the queue. Does QueueReceive ever get called before you’ve clicked the button? Stated differently - I’m wondering if the queue problems start once you’ve added the first item through the queue/entered the ISR or if they start before.

Could you also share your FreeRTOSConfig.h and the task priorities you have used. Thank you. I’m attempting to reproduce on a pico using the SMP kernel and I have replicated your test as best I can. For me I received the proper value in the queue. I’m checking the queue using a task with a higher priority pinned to the second core and it also idles using vTaskDelay for 1sec, between calls to uxQueueMessagesWaiting. I’ve forced the ISR using triggerSoftwareInterrupt(handlerNum);

v795215469.tar (20 KB)

1 Like

Yes, sorry. I am referring to the multi core version of freeRTOS. The receive queue starts receiving immediately even before the button is pushed.

Not allowed to upload attachments yet so sorry for the long post… and strip the links… All my tasks are the same default priority.

/*
 * FreeRTOS V202111.00
 * Copyright (C) 2020 , Inc. or its affiliates.  All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 *
 * 1 tab == 4 spaces!
 */

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

#include "rp2040_config.h"

/*-----------------------------------------------------------
 * Application specific definitions.
 *
 * These definitions should be adjusted for your particular hardware and
 * application requirements.
 *
 * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
 * FreeRTOS API DOCUMENTATION AVAILABLE ON THE WEB SITE.
 *
 * See 
 *----------------------------------------------------------*/

/* Scheduler Related */
#define configUSE_PREEMPTION                    1
#define configUSE_TICKLESS_IDLE                 0
#define configUSE_IDLE_HOOK                     0
#define configUSE_TICK_HOOK                     0
#define configTICK_RATE_HZ                      ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES                    32
#define configMINIMAL_STACK_SIZE                ( configSTACK_DEPTH_TYPE ) 256
#define configUSE_16_BIT_TICKS                  0

#define configIDLE_SHOULD_YIELD                 1

/* Synchronization Related */
#define configUSE_MUTEXES                       1
#define configUSE_RECURSIVE_MUTEXES             1
#define configUSE_APPLICATION_TASK_TAG          0
#define configUSE_COUNTING_SEMAPHORES           1
#define configQUEUE_REGISTRY_SIZE               8
#define configUSE_QUEUE_SETS                    1
#define configUSE_TIME_SLICING                  1
#define configUSE_NEWLIB_REENTRANT              0
// todo need this for lwip FreeRTOS sys_arch to compile
#define configENABLE_BACKWARD_COMPATIBILITY     1
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5

/* System */
#define configSTACK_DEPTH_TYPE                  uint32_t
#define configMESSAGE_BUFFER_LENGTH_TYPE        size_t

/* Memory allocation related definitions. */
#define configSUPPORT_STATIC_ALLOCATION         0
#define configSUPPORT_DYNAMIC_ALLOCATION        1
#define configTOTAL_HEAP_SIZE                   (128*1024)
#define configAPPLICATION_ALLOCATED_HEAP        0

/* Hook function related definitions. */
#define configCHECK_FOR_STACK_OVERFLOW          0
#define configUSE_MALLOC_FAILED_HOOK            0
#define configUSE_DAEMON_TASK_STARTUP_HOOK      0

/* Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS           0
#define configUSE_TRACE_FACILITY                1
#define configUSE_STATS_FORMATTING_FUNCTIONS    0

/* Co-routine related definitions. */
#define configUSE_CO_ROUTINES                   0
#define configMAX_CO_ROUTINE_PRIORITIES         1

/* Software timer related definitions. */
#define configUSE_TIMERS                        1
#define configTIMER_TASK_PRIORITY               ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH                10
#define configTIMER_TASK_STACK_DEPTH            1024

/* Interrupt nesting behaviour configuration. */
/*
#define configKERNEL_INTERRUPT_PRIORITY         [dependent of processor]
#define configMAX_SYSCALL_INTERRUPT_PRIORITY    [dependent on processor and application]
#define configMAX_API_CALL_INTERRUPT_PRIORITY   [dependent on processor and application]
*/

#if FREE_RTOS_KERNEL_SMP // set by the RP2040 SMP port of FreeRTOS
/* SMP port only */
#define configNUM_CORES                         2
#define configTICK_CORE                         0
#define configRUN_MULTIPLE_PRIORITIES           1
#define configUSE_CORE_AFFINITY                 1
#endif

/* RP2040 specific */
#define configSUPPORT_PICO_SYNC_INTEROP         1
#define configSUPPORT_PICO_TIME_INTEROP         1

#include <assert.h>
/* Define to trap errors during development. */
#define configASSERT(x)                         assert(x)

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet                1
#define INCLUDE_uxTaskPriorityGet               1
#define INCLUDE_vTaskDelete                     1
#define INCLUDE_vTaskSuspend                    1
#define INCLUDE_vTaskDelayUntil                 1
#define INCLUDE_vTaskDelay                      1
#define INCLUDE_xTaskGetSchedulerState          1
#define INCLUDE_xTaskGetCurrentTaskHandle       1
#define INCLUDE_uxTaskGetStackHighWaterMark     1
#define INCLUDE_xTaskGetIdleTaskHandle          1
#define INCLUDE_eTaskGetState                   1
#define INCLUDE_xTimerPendFunctionCall          1
#define INCLUDE_xTaskAbortDelay                 1
#define INCLUDE_xTaskGetHandle                  1
#define INCLUDE_xTaskResumeFromISR              1
#define INCLUDE_xQueueGetMutexHolder            1

/* A header file that defines trace macro can be included here. */

#endif /* FREERTOS_CONFIG_H */

Thanks, retrying with RUN_MULTIPLE_PRIORITIES as that differed between your and my config.

In the tar I posted you can replace sendReport() with printf(). In addition though I am using a newer version of the SMP kernel and one configuration option has been renamed. That is the configNUM_OF_CORES has been renamed to configNUMBER_OF_CORES.

The Kernel I am using is specifically: GitHub - chinglee-iot/FreeRTOS-Kernel: FreeRTOS kernel files only, submoduled into https://github.com/FreeRTOS/FreeRTOS and various other repos. @ 21d9a61c93d8d0d5895ed743464d68d4335b0927

Note that it also worked with RUN_MUTIPLE_PRIORITIES enabled, so it could be a subtle difference in application, or related to the specific version of kernel being used, or something else of course.

I should add I am building a uf2, and the using the pico_enable_stdio_usb() to get printf() output over the usbserial interface. I also use:

stdio_init_all();
while (!stdio_usb_connected) { // LED blin code }

On startup to validate that the usbserial connection is stable before starting the tasks.

I changed the board configuration to default to uart1 Gpio 4,5 for the printf.

I’ve reproduced that change (default uart) locally, however I still used usbserial for debugging output. That combination of things worked here. Have you tried the chinglee SMP kernel variant?

Could you give me better directions to finding the latest stable version of FreeRTOS-SMP for my pico target. Your link has me confused. (not very familiar with git/github)

I need to select the SMP branch not one of the SMP-Dev branches. right?

Correct, please use the smp branch from that repo. I’ve just retested specifically with head of smp, having hash 8128208bdee1f997f83cae631b861f36aeea9b1f and that worked given the setup here which is a little different using usbserial currently, and possibly other details of the application code.

Also the printf() within the ISR context may be causing issues, so please remove that as well.

Eventually I noticed something in my serial output…

Main ping on Core 1
Button_Queue: Number of messages = 0.
Control started on Core 0
Button_Queue Control start1: Number of messages = 0.
Button_Queue Control start2: Number of messages = 0.
Version: 7.95.49 (2271bb6 CY) CRC: b7a28ef3 Date: Mon 2021-11-29 22:50:27 PST Ucode Ver: 1043.2162 FWID 01-c51d9400
cyw43 loaded ok, mac 28:cd:c1:08:1d:d0

Messages in Q=1 message=0
Messages in Q=1 message=0

The text in bold is output directly by the Pico API. Specifically it is the wifi chip initialization which it must use an interrupt for it to communicate with the chip. After which the queue stops working! It just happens to happen at the same time my task transition’s into its endless loop.

Main ping on Core 1
Button_Queue: Number of messages = 0. <–from Main Task on core1
Control started on Core 0 ← Control task starts on core0
Button_Queue Control start1: Number of messages = 0. ← as soon as the control task starts.
Button_Queue Control start2: Number of messages = 0. ← just before the control task endless loop starts at the end of the task setup section.
Version: 7.95.49 (2271bb6 CY) CRC: b7a28ef3 Date: Mon 2021-11-29 22:50:27 PST Ucode Ver: 1043.2162 FWID 01-c51d9400
cyw43 loaded ok, mac 28:cd:c1:08:1d:d0 <—Wifi init message from API
Messages in Q=1 message=0 ← from inside control task loop.
Messages in Q=1 message=0 ← from inside control task loop.

So I looked at the Pico API section for the wifi chip and it looks like I was using the wrong library.
in my CMakeLists.txt I changed the target library from pico_cyw43_arch_none to pico_cyw43_arch_lwip_sys_freertos.

Then it said I needed a lwipopts.h file which I dug up.

Then it said I needed to set NO_SYS to 0 in the file so I did…

It BUILT and … NOTHING. Nothing runs, no serial messages, nothing.

I really hope someone out there knows what I am doing wrong cause I went from the Queue not working to nothing working.

It seems that your problem at hand is fairly elementary and not related to networking, so I would recommend trying to use a bare bone hello world application to build from. Integrating networking (ie lwip in this case) is a quite heavy cookie to chew, so since you apparently just stared with FreeRTOS, you should try to keep it as simple as possible.

As @RAc suggested, keep pico_cyw43_arch_none and first fix the wrong message number issue. Can you share your complete task and ISR code where you see this problem?

If I was allowed to post links or upload I would share the project since it is at an early stage but here is the requested code. Something of note is I am using Jon Durrant’s code example for task classes. He calls them an agentClass. Specifically, from his example RPIPicoFreeRTOSSMPExp on github.

main.cpp
/***

  • Demo program to use FreeRTOS SMP on Both Cores
  • Blink on Core 0 to GPIO 0
  • Blink on Core 1 to GPIO 15
  • Counter showing on GPIO 2 to 5, using Core 1
  • Instructions sent to Counter from Main Task on Core 0
  • Jon Durrant
  • 15-Aug-2022
    */

// — UART — From pico_w.h
// This should move the printf function to use UART1-6,7
//#define PICO_DEFAULT_UART 1
//#define PICO_DEFAULT_UART_TX_PIN 6
//#define PICO_DEFAULT_UART_RX_PIN 7

#include “pico/stdlib.h”
#include “FreeRTOS.h”
#include “task.h”
#include “semphr.h”
#include <stdio.h>
#include <math.h>
#include “hardware/structs/sio.h”
#include “pico/cyw43_arch.h”
#include “macro.h”
#include “BlinkTask.h”
#include “PIO/PIOTask.h”
#include “UI/UITask.h”
#include “Control/ControlTask.h”
#include “hardware/i2c.h”
#include “PowerLedClass.h”
#include “queue.h”
#include “global.h”

RESOURCES resource_mutex; // Global list of Mutex locks for the board resoureces.

//Standard Task priority
#define TASK_PRIORITY ( tskIDLE_PRIORITY + 1UL )

//LED PAD to use
#define VERSION_MAJOR 0
#define VERSION_MINOR 4

#define PH_RESET_BUTTON 20
//#define GPIO_EVENT_HIGH 0x01
//#define GPIO_EVENT_LOW 0x02
//#define GPIO_EVENT_FALLING 0x04
//#define GPIO_EVENT_RISING 0x08
#define DEBOUNCE_TIME 100
#define LONG_PRESS_TIME 10000

QueueHandle_t Button_Queue;

/***

  • reserved_addr - Checks for an i2c reserved address
  • @param params - address (7bit)
  • only used by i2c_scan
    */
    bool reserved_addr(uint8_t addr) {
    // I2C reserves some addresses for special purposes. We exclude these from the scan.
    // These are any addresses of the form 000 0xxx or 111 1xxx
    return (addr & 0x78) == 0 || (addr & 0x78) == 0x78;
    }

/***

  • i2c_scan - Scans the bus to find valid addresses

  • @param params - I2c bus
    /
    void i2c_scan (i2c_inst_t
    I2C_channel,unsigned char ch) {
    printf(“\nI2C%d Bus Scan\n”, ch);
    printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");

    for (int addr = 0; addr < (1 << 7); ++addr) {
    if (addr % 16 == 0) {
    printf("%02x ", addr);
    }

     // Perform a 1-byte dummy read from the probe address. If a slave
     // acknowledges this address, the function returns the number of bytes
     // transferred. If the address byte is ignored, the function returns
     // -1.
    
     // Skip over any reserved addresses.
     int ret;
     uint8_t rxdata;
     if (reserved_addr(addr))
         ret = PICO_ERROR_GENERIC;
     else
         r_display(ret = i2c_read_blocking(I2C_channel, addr, &rxdata, 1, false));
    
     printf(ret < 0 ? "." : "@");
     printf(addr % 16 == 15 ? "\n" : "  ");
    

    }
    printf(“Done.\n”);
    }

void gpio_callback(uint gpio, uint32_t events) {
static TickType_t phTime;
unsigned char message;
//BaseType_t xHigherPriorityTaskWoken = pdFALSE;

switch (gpio){
	case PH_RESET_BUTTON:
		//printf("INT: gpio=%d events=%d ", gpio, events);
		if (events == GPIO_IRQ_EDGE_FALL){
			//printf("fall. ticks=%d\n", phTime);
			if (phTime == 0){
				phTime = xTaskGetTickCount();
				// Queue PH button down message with phTime.
			}
		} else if (events == GPIO_IRQ_EDGE_RISE) {
			//printf("rise. ticks=%d\n", xTaskGetTickCount() - phTime);
			if (phTime != 0) {
				if (xTaskGetTickCount() - phTime > LONG_PRESS_TIME) {
					// Queue button Long push message.
					message = BUTTON_MESSAGE_PH_FACTORY_RESET;
					//xQueueSendFromISR (Button_Queue, &message, NULL);
				}
				if (xTaskGetTickCount() - phTime > DEBOUNCE_TIME) {
					// Queue button push message
					message = BUTTON_MESSAGE_PH_PRESSED;
					//xQueueSendFromISR (Button_Queue, &message, NULL);
				}
			}
			phTime = 0;
		}
		break;
}

}

/***

  • Main task to blink external LED

  • @param params - unused
    */
    void mainTask(void *params){
    r_uart(printf(“Main task started\n”));

    // Configure the chip
    // I2C0 BUS for PORTS, RTC, FLASH
    uint baud;
    gpio_set_function(16, GPIO_FUNC_I2C); // Set pins 12 and 13 for i2c role
    gpio_set_function(17, GPIO_FUNC_I2C);
    baud = i2c_init(i2c0, 100000); // Init i2c0 and set baud rate to 100000hz (1Mhz max supported speed by pico)
    r_uart(printf(“I2C0: i2c_init actual baudrate set to %d.\n”, baud));
    r_uart(i2c_scan(i2c0, 0));

    // I2C1 BUS for DISPLAY
    gpio_set_function(18, GPIO_FUNC_I2C); // Set pins 12 and 13 for i2c role
    gpio_set_function(19, GPIO_FUNC_I2C);
    baud = i2c_init(i2c1, 100000); // Init i2c0 and set baud rate to 1Mhz (max supported speed by pico)
    r_uart(printf(“I2C1: i2c_init actual baudrate set to %d.\n”, baud));
    r_uart(i2c_scan(i2c1, 1));

    // Power LED
    gpio_init(POWERLED_GPIO);
    gpio_set_function(POWERLED_GPIO, GPIO_FUNC_PWM);
    gpio_set_dir(POWERLED_GPIO, true); // Power LED GPIO21 is set to output.

    // PH / Reset Button
    gpio_init(PH_RESET_BUTTON);
    gpio_set_dir(PH_RESET_BUTTON, false); // is set to input.
    gpio_pull_up(PH_RESET_BUTTON);
    gpio_set_irq_enabled_with_callback(PH_RESET_BUTTON, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &gpio_callback);
    Button_Queue = xQueueCreate( 10, sizeof( unsigned char) );
    if( Button_Queue == NULL )
    {
    /* Queue was not created and must not be used. */
    r_uart(printf(“Button_Queue: failed to create queue!\n”));
    }
    int num = uxQueueMessagesWaiting( Button_Queue );
    r_uart(printf(“Button_Queue: Number of messages = %d.\n”, num));

    // CREATE TASKS
    BlinkTask blink(LED_PAD);
    UITask ui;
    //PIOTask pio;
    ControllTask control;

    blink.start(“Blink 0”, TASK_PRIORITY); num = uxQueueMessagesWaiting( Button_Queue );
    ui.start(“UI”, TASK_PRIORITY);
    // pio.start(“PIO”, TASK_PRIORITY);
    control.start(“Control”, TASK_PRIORITY);

    //Bind to CORE 1
    UBaseType_t coreMask = 0x2;
    vTaskCoreAffinitySet( ui.getTask(), coreMask );

    //Bind to CORE 0
    coreMask = 0x1;
    vTaskCoreAffinitySet( blink.getTask(), coreMask );
    vTaskCoreAffinitySet( control.getTask(), coreMask );

    while (true) { // Loop forever
    r_uart(printf(“Main ping on Core %ld\n”,sio_hw->cpuid));
    int num = uxQueueMessagesWaiting( Button_Queue );
    r_uart(printf(“Button_Queue: Number of messages = %d.\n”, num));
    vTaskDelay(60000);
    }
    }

/***

  • Launch the tasks and scheduler
    */
    void vLaunch( void) {

    //Start blink task
    TaskHandle_t task;
    xTaskCreate(mainTask, “MainThread”, 512, NULL, TASK_PRIORITY, &task);

    /* Start the tasks and timer running. */
    vTaskStartScheduler();
    }

/***

  • Main

  • @return
    */
    int main( void )
    {
    //Setup serial over USB and give a few seconds to settle before we start
    //stdio_uart_init_full (uart1, 115200, 6, 7);
    stdio_init_all();
    cyw43_arch_init();
    sleep_ms(2000);
    printf(“\n\n\n\nGO…\n”);
    printf(“Hydrocontroler V%d.%d\n”, VERSION_MAJOR, VERSION_MINOR);
    printf(“Copyright DienstNet LLC 2022\n”);
    printf(“All Rights Reserved.\n\n”);

    //Hardware Mutexes
    resource_mutex.wifi_resource = xSemaphoreCreateMutex();
    resource_mutex.display_resource = xSemaphoreCreateMutex();
    resource_mutex.i2c_resource = xSemaphoreCreateMutex();
    resource_mutex.uart_resource = xSemaphoreCreateMutex();

    //Start tasks and scheduler
    const char *rtos_name;
    #if ( portSUPPORT_SMP == 1 )
    rtos_name = “FreeRTOS SMP”;
    #else
    rtos_name = “FreeRTOS”;
    #endif

#if ( portSUPPORT_SMP == 1 ) && ( configNUM_CORES == 2 )
printf(“%s on both cores:\n”, rtos_name);
#else
printf(“Starting %s on core 0:\n”, rtos_name);
#endif

vLaunch();
return 0;

}

ControlTask.h
/*

  • ControllTask.h
  • Hydroponic system controll application task.
  • Created on: 11/30/22
  •  Author: dddienst
    

*/

#ifndef ControllTask_H_
#define ControllTask_H_

#include “pico/stdlib.h”
#include “FreeRTOS.h”
#include “taskClass.h”
#include “Control/ControlTask.h”

class ControllTask: public Task {
public:
/***
* Constructor
*/
ControllTask();

/***
 * Destructor
 */
virtual ~ControllTask();

protected:

/***
 * Run loop for the Task.
 */
virtual void run();


/***
 * Get the static depth required in words
 * @return - words
 */
virtual configSTACK_DEPTH_TYPE getMaxStackSize();

//Class Variables

};
#endif /* ControllTask_H_ */

ControlTask.cpp
/*

  • ControllTask.cpp
  • Created on: 11/30/22
  •  Author: dddienst
    
  • Runs only on core 0
    */

#include “Control/ControlTask.h”
#include “Control/Relays.h”
#include “stdio.h”
#include “macro.h”
#include “pico/multicore.h”
#include “global.h”
#include “queue.h”

UBaseType_t _uxQueueMessagesWaiting(QueueHandle_t xQueue) {
int num = uxQueueMessagesWaiting(xQueue);
return uxQueueMessagesWaiting(xQueue);
}

BaseType_t _xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait) {
return xQueueReceive(xQueue, pvBuffer, xTicksToWait);
}

/***

  • Constructor
  • @param none
    */
    ControllTask::ControllTask() {

}

/***

  • Destructor
    */
    ControllTask::~ControllTask() {
    stop();
    }

/***

  • Main Run Task for Task
    */
    void ControllTask::run(){
    r_uart(printf(“%s started on Core %d\n”, pName, getCore()));

    unsigned char message = 0;
    unsigned int loop;
    UBaseType_t num;

    num = uxQueueMessagesWaiting( Button_Queue ); r_uart(printf(“Button_Queue Control start1: Number of messages = %d.\n”, num));

    //RELAYS relay(i2c0);
    // relay.test();
    num = uxQueueMessagesWaiting( Button_Queue ); r_uart(printf(“Button_Queue Control start2: Number of messages = %d.\n”, num));

    while (true) { // Loop forever
    if (num = uxQueueMessagesWaiting( Button_Queue ) > 0 ) {

    	if (xQueueReceive(Button_Queue, &message, 0) == pdTRUE){
    		r_uart(printf("Messages in Q=%d message=%d\n", num, message));
    		switch (message) {
    			case BUTTON_MESSAGE_PH_PRESSED:
    				r_uart(printf("Take a PH reading.\n"));
    				break;
    			case BUTTON_MESSAGE_PH_FACTORY_RESET:
    				r_uart(printf("Perform a Factory Reset.\n"));
    				break;
    		}
    	}
    }
    
    vTaskDelay(1000);
    loop++;
    if (loop == 30) {
    	r_uart(printf("%s ping on Core %d\n", pName, getCore()));
    	loop = 0;
    }
    

    }
    }

/***

  • Get the static depth required in words
  • @return - words
    */
    configSTACK_DEPTH_TYPE ControllTask::getMaxStackSize(){
    return 1024;
    }

I just bumped your forum privilege level - hopefully high enough.

Link to my project files

Note: I am developing on a PC and using vscode. The uf2 file builds to build/src.
One thought is to wait some period of time for the chip to initialize but the amount of time it takes is indeterminant. I wonder if there is a api call I can make to determine if it is complete? then create and use the queue.

UPDATE: I can confirm that if I wait until after the wifi chip init message the queue can be created and used as expected. I am just not sure if the init timing will always happen within a certain time period. I suppose I could create a queue and use it to wait till it goes bad to know when it is safe to create the real queue. LOL

You problem from your description is unclear and I think you are mixing too many things at once. I’d recommend to address problems one by one - start by commenting out all tasks and enable them one by one every time ensuring that things are working as expected.

I looked at your code and here are some of my suggestions -

  1. You can update the control task definition to the following -
 void ControllTask::run(){
	r_uart(printf("%s started on Core %d\n", pName, getCore()));
	
	unsigned char message = 0;
	unsigned int loop;

	r_uart(printf("Button_Queue Control start1: Number of messages = %d.\n", uxQueueMessagesWaiting( Button_Queue )));


	while (true) { // Loop forever
		if (xQueueReceive(Button_Queue, &message, 1000) == pdTRUE){
			r_uart(printf("Messages in Q=%d message=%d\n", uxQueueMessagesWaiting( Button_Queue ), message));
			switch (message) {
				case BUTTON_MESSAGE_PH_PRESSED:
					r_uart(printf("Take a PH reading.\n"));
					break;
				case BUTTON_MESSAGE_PH_FACTORY_RESET:
					r_uart(printf("Perform a Factory Reset.\n"));
					break;
			}
		}
	}
		
		loop++;
		if (loop == 30) {
			r_uart(printf("%s ping on Core %d\n", pName, getCore()));
			loop = 0;
		}
	}
}
  1. Increase stack sizes of tasks as you are using printfs in tasks which is usually stack hungry.

  2. Check the return values of xQueueSendFromISR calls.

Please make sure that this button press functionality works before enabling other functionalities. Also note that these C++ wrappers are not supplied by us and therefore, if there is any bug in these wrappers, you may need to contact the author of theses wrappers.

1 Like