Interrupt watchdog restart when writing to NVS

User avatar
dg9ngf
Posts: 65
Joined: Mon Sep 16, 2019 6:49 pm
Location: Germany
Contact:

Interrupt watchdog restart when writing to NVS

Postby dg9ngf » Mon Dec 15, 2025 7:25 pm

Hello,

I'm a first-time NVS user and have read the documentation about it and looked at the example code. I was able to write a few entries to NVS and the data can be read and it persists a power cycle. So I guess it works.

But at one point in the program, the device restarts when I want to write a new value to an existing entry. I can overwrite that entry from the start of the main function, but not when requested later at runtime.

The flow is this:

- A message is received on UART, it is put to a queue
- Another task reads from the queue and processes the message
- When the message requests setting that value, that's done

It has worked once to set the value the very first time, but when I try it now, the ESP32 restarts with the message "TG1WDT_SYS_RESET" or "Guru Meditation Error: Core 0 panic'ed (Cache disabled but cached memory region accessed)."

What's going on there? Why can't I write to NVS after more than a few seconds into runtime? Do I need something else that's not documented? I'm not setting any timeouts here or for the task that runs the queue. I've doubled that stack size to 8192 already but that wasn't the cause.

The actual set code is exactly from the example:

Code: Select all

static nvs_handle_t nvsHandle;

// Called once at startup
void initNvs()
{
	// Initialize NVS
	esp_err_t err = nvs_flash_init();
	if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
	{
		// NVS partition was truncated and needs to be erased
		// Retry nvs_flash_init
		ESP_ERROR_CHECK(nvs_flash_erase());
		err = nvs_flash_init();
	}
	ESP_ERROR_CHECK(err);

	// Open NVS handle
	err = nvs_open("storage", NVS_READWRITE, &nvsHandle);
	if (err != ESP_OK)
	{
		ESP_LOGE(TAG, "Error opening NVS handle: %s", esp_err_to_name(err));
		return;
	}
}

// Called when processing the message to save the data
bool nvsSetUInt32(const char* key, uint32_t value)
{
	esp_err_t err = nvs_set_u32(nvsHandle, key, value);
	if (err != ESP_OK)
	{
		ESP_LOGE(TAG, "Error writing uint32 value for key \"%s\" to NVS: %s", key, esp_err_to_name(err));
		return false;
	}
	err = nvs_commit(nvsHandle);
	if (err != ESP_OK)
	{
		ESP_LOGE(TAG, "Error committing NVS changes: %s", esp_err_to_name(err));
		return false;
	}
	return true;
}

User avatar
dg9ngf
Posts: 65
Joined: Mon Sep 16, 2019 6:49 pm
Location: Germany
Contact:

Re: Interrupt watchdog restart when writing to NVS

Postby dg9ngf » Mon Dec 15, 2025 8:31 pm

During debugging, I found that I can set every single key exactly once, no matter from which context. Every second set for the same key crashes the device. Deleting the key first seems to help, I can now write data multiple times from everywhere. Is this normal?

Code: Select all

bool nvsSetUInt32(const char* key, uint32_t value)
{
	esp_err_t err = nvs_erase_key(nvsHandle, key);
	if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND)
	{
		ESP_LOGE(TAG, "Error erasing key \"%s\" from NVS before writing: %s", key, esp_err_to_name(err));
	}
	err = nvs_set_u32(nvsHandle, key, value);
	if (err != ESP_OK)
	{
		ESP_LOGE(TAG, "Error writing uint32 value for key \"%s\" to NVS: %s", key, esp_err_to_name(err));
		return false;
	}
	if (!inTransaction)
	{
		err = nvs_commit(nvsHandle);
		if (err != ESP_OK)
		{
			ESP_LOGE(TAG, "Error committing NVS changes: %s", esp_err_to_name(err));
			return false;
		}
	}
	return true;
}

MicroController
Posts: 2669
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: Interrupt watchdog restart when writing to NVS

Postby MicroController » Mon Dec 15, 2025 9:10 pm

But at one point in the program, the device restarts when I want to write a new value to an existing entry. I can overwrite that entry from the start of the main function, but not when requested later at runtime.
...
What's going on there?
...
The actual set code is exactly from the example:
There's a bug somewhere in the rest of your code. Could be anything, and may or may not be actually related to the NVS operation.

Code: Select all

bool nvsSetUInt32(const char* key, uint32_t value)
{
	esp_err_t err = nvs_set_u32(nvsHandle, key, value);
First thing to check would be that "nvsHandle" and "key" are actually still valid when this gets executed.

User avatar
dg9ngf
Posts: 65
Joined: Mon Sep 16, 2019 6:49 pm
Location: Germany
Contact:

Re: Interrupt watchdog restart when writing to NVS

Postby dg9ngf » Mon Dec 15, 2025 9:28 pm

First thing to check would be that "nvsHandle" and "key" are actually still valid when this gets executed.
Can I keep the handle for longer (i.e. the entire runtime) or am I supposed to open and close the NVS for each access?

key is a constant literal string passed as a parameter, it cannot be invalid.

MicroController
Posts: 2669
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: Interrupt watchdog restart when writing to NVS

Postby MicroController » Tue Dec 16, 2025 12:44 am

Can I keep the handle for longer (i.e. the entire runtime) ... ?
Yes, you definitely can.

ESP_rrtandler
Posts: 53
Joined: Wed May 31, 2023 6:54 pm

Re: Interrupt watchdog restart when writing to NVS

Postby ESP_rrtandler » Thu Dec 18, 2025 9:31 am

First thing to check would be that "nvsHandle" and "key" are actually still valid when this gets executed.
Can I keep the handle for longer (i.e. the entire runtime) or am I supposed to open and close the NVS for each access?

key is a constant literal string passed as a parameter, it cannot be invalid.
You can reuse the handle, there is no need to reopen it.

What you see might be caused by the access violation. Like unintended variable overwrite or masked scope (global vs local declarations). Make sure you are accessing the same variable holding the NVS handle from the initialisation code as well as from the functions serving as the queue consumer. What you have posted so far suggests the globally declared NVS handle. Make sure it is not re-declared under the same name elsewhere in the code, i.e. in the function(s) writing the data on behalf of queue reading.

Who is online

Users browsing this forum: Qwantbot and 4 guests