Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

flash_safe_execute fails with FreeRTOS timer #2213

Closed
sykacek opened this issue Jan 26, 2025 · 5 comments
Closed

flash_safe_execute fails with FreeRTOS timer #2213

sykacek opened this issue Jan 26, 2025 · 5 comments
Assignees
Milestone

Comments

@sykacek
Copy link

sykacek commented Jan 26, 2025

When I run the code below on my RP2040, LED blinks for less than a second and then the whole system fails (I can't access it over the serial, it is frozen). It compiles without any warnings and CMake is also ok.

#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"

#include "pico/flash.h"

#include "hardware/flash.h"
#include "hardware/sync.h"

#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"

#define NVS_SIZE		(4096)
#define NVS_SECTORS		(446)
#define PAGE_SIZE		(256)
#define PAGE_SECTORS		(NVS_SECTORS * NVS_SIZE / PAGE_SIZE)

#define FLASH_WRITE_START	(0x42000)
#define FLASH_READ_START	(FLASH_WRITE_START + XIP_BASE)

#define FLASH_SECTORS		(256)

#define BUFFER_SIZE		((256 - 4) / (sizeof(int16_t)))
#define BUFFER_COUNT		(BUFFER_SIZE / (2 * 3))

/* 256 byte structure */
typedef struct callback {
	char fmt[4];
	int16_t data[BUFFER_SIZE];
	int16_t counter;
	int8_t flash;
	uint32_t offset;
	int8_t led;
} callback_t;

volatile callback_t callback = {
	.fmt = "DATA",
	.counter = 0,
	.flash = 1,
	.offset = FLASH_WRITE_START,
	.led = 0,
};

volatile TimerHandle_t tim;
static TaskHandle_t init_handler;
static int state;

volatile int x = 0;

void print_buf(void *buf, uint32_t len){
	char *c = (char *)buf;

	puts("debug:\n");

	for(int i = 0; i < len; ++i){
		printf("%x ", *c);
		c++;

		if(i%16 == 15)
			puts("");
	}
}

static void write_flash(void *arg){
	flash_range_program(callback.offset, (const uint8_t *)&callback, PAGE_SIZE);
	callback.offset += PAGE_SIZE;
}

static void timer_callback(TimerHandle_t timer){
	printf("hello %d\n", callback.counter);
	if(callback.flash){
		callback.flash = 0;
		flash_safe_execute(write_flash, NULL, UINT32_MAX);
	}

	uint32_t i = callback.counter;
	int16_t *pnt = (int16_t *)callback.data;

	pnt[i++] = x++;
	pnt[i++] = x++;
	pnt[i++] = x++;

	gpio_put(25, callback.led);
	callback.led = !callback.led;

	callback.counter += i;
	if(i % 252 == 0){
		callback.counter = 0;
		callback.flash = 1;
	}
}

static void pico_init_task(void *arg){
	tim = xTimerCreate("TIMER",
			pdMS_TO_TICKS(100),
			pdTRUE,
			(void *)0x00,
			timer_callback
	);

	assert(tim != NULL);
	xTimerStart(tim, 0);

	while(1){
		;;
	}	
}

int main(void){
	stdio_init_all();
	flash_safe_execute_core_init();

	gpio_init(25);
	gpio_set_dir(25, GPIO_OUT);
	gpio_put(25, 1);

	xTaskCreate(pico_init_task, "task", 128, NULL, 1, &init_handler);
	vTaskStartScheduler();

}

I encountered the same behavior when I was accessing flash without flash_safe_execute, I though that using it would prevent the issues, what am I doing wrong? In the critical flash section I have also tried using save_and_disable_interrupts() without flash_safe_execute and flash_safe_execute_core_init but LED just went on and the system froze again.

static void write_flash(void *arg){
	uint32_t irqs = save_and_disable_interrupts();
	flash_range_program(callback.offset, (const uint8_t *)&callback, PAGE_SIZE);
	callback.offset += PAGE_SIZE;
	restore_interrupts_from_disabled(irqs);
}

this didn't help. I attach FreeRTOSConfig.h below.

/* Scheduler Related */
#define configUSE_PREEMPTION                    1
#define configUSE_TICKLESS_IDLE                 0
#define configUSE_IDLE_HOOK                     0
#define configUSE_PASSIVE_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]
*/

/* SMP port only */
#define configNUMBER_OF_CORES                   2
#define configTICK_CORE                         0
#define configRUN_MULTIPLE_PRIORITIES           1
#define configUSE_CORE_AFFINITY                 1

/* 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

I am using latest git pull of PICO SDK and FreeRTOS 202406-LTS, with FreeRTOS-Kernel 11.1.0., arm-none-eabi-gcc (15:10.3-2021.07-4) 10.3.1 20210621 (release). I attach CMakeLists.txt just in case

cmake_minimum_required(VERSION 3.13)

include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)
include($ENV{FREERTOS_KERNEL_PATH}/portable/ThirdParty/GCC/RP2040/FreeRTOS_Kernel_import.cmake)

project(app)

pico_sdk_init()

add_executable(app
	main.c
)

add_compile_options(-Wall -Wextra)

target_include_directories(app PRIVATE
	${CMAKE_CURRENT_LIST_DIR}
)

target_link_libraries(app
	pico_stdlib
	hardware_flash
	FreeRTOS-Kernel-Heap4
)

pico_enable_stdio_usb(app 1)
pico_enable_stdio_uart(app 1)

pico_add_extra_outputs(app)

add_custom_target(flash cp ${PROJECT_NAME}.uf2 /media/mike/RPI-RP2)

Thanks for help!

@lurch
Copy link
Contributor

lurch commented Jan 27, 2025

I've got no idea if it's related to your problem or not (I've not yet used FreeRTOS myself), but I see that you're using flash_safe_execute_core_init, but at https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_flash/include/pico/flash.h#L57 it says "This is not necessary for FreeRTOS SMP" ?

@rvt
Copy link

rvt commented Jan 27, 2025

Can you try to wrap your write_flash function with __not_in_flash_func?

eg void __not_in_flash_func(write_flash)(void *param)
also, I am pretty sure you need to erase before you write, but check this... it's been a while since I used it.

I never used save_and_disable_interrupts and I write from FreeRTOS via a web interface just fine.

On a side note, are you really needing to write your flash that often? This can wear out your flash quite fast...

@kilograham kilograham added this to the 2.1.1 milestone Jan 31, 2025
@kilograham kilograham self-assigned this Jan 31, 2025
@sykacek
Copy link
Author

sykacek commented Feb 2, 2025

void __not_in_flash_func(write_flash)(void *param) didn't help, program crashes again after writing to flash, save_and_disable_interrupts works fine only in main loop before starting the timer, so you are right about not using it inside the callback routines. Can you please provide me a snippet of that FreeRTOS web interface? Thanks in advance.

@rvt
Copy link

rvt commented Feb 4, 2025

@sykacek this is the code I am currently working on : https://github.com/rvt/OpenAce/blob/initial/src/lib/webserver/ace/webserver.cpp

This is what I use to generate the openace_fsdata.c file : https://github.com/rvt/OpenAce/blob/initial/src/lib/webserver/external/makefs.py

The website itself can be found here : https://github.com/rvt/OpenAce/tree/initial/src/SystemGUI

@kilograham
Copy link
Contributor

Your code is buggy, and you are writing off the end of your buffer corrupting stuff.

    callback.counter += i; // <<< did you mean 1 not i?
    if (i % 252 == 0) {    // <<< with i not 1, this does not catch the end of the loop; also the data buffer is only 126 `int16_t`s big not 252!
        callback.counter = 0;
        callback.flash = 1;
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants