AVR: eeprom_busy_wait function causes build error

I’m porting old AVR code to a new PlatformIO project. The code was originally created with Atmel Studio a few years ago and targets an ATtiny1614 microcontroller. It’s not using any framework, especially not Arduino. The code used to build and work just fine, but I’m having trouble to get it to build now.

This is my platformio.ini file:

[env:ATtiny1614]
platform = atmelmegaavr
board = ATtiny1614
;framework = arduino

And this is the offending code (only a part shown, it would be too much for this issue):

#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/atomic.h>
#include <util/crc16.h>
#include <util/delay.h>

// EEPROM variables (default value of empty memory is all 1's)
EEMEM uint16_t eeAddress = 0xffff;

uint16_t address = 0;

int main()
{
	setAddress(0);
}

void setAddress(uint16_t newAddress)
{
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
	{
		eeprom_update_word(&eeAddress, newAddress);
		eeprom_busy_wait();
	}
	address = newAddress;
}

The marked code is the call to eeprom_busy_wait(). The message is:

src\main.cpp: In function 'void setAddress(uint16_t)':
src\main.cpp:224:3: error: 'NVM_STATUS' was not declared in this scope
   eeprom_busy_wait();
   ^
src\main.cpp:224:3: note: suggested alternative: 'AC2_STATUS'
src\main.cpp:224:3: error: 'NVM_NVMBUSY_bp' was not declared in this scope
   eeprom_busy_wait();
   ^
src\main.cpp:224:3: note: suggested alternative: 'NVMCTRL_FBUSY_bp'
*** [.pio\build\ATtiny1614\src\main.o] Error 1

That seems to be the only compiler error now. What’s going on? How can I fix this?

I can follow definitions in VSCode and also get to where NVM_STATUS and NVM_NVMBUSY_bp are defined. So VSCode knows where stuff is, but the compiler does not. VSCode finds it in this file: C:\Users.….platformio\packages\toolchain-atmelavr\avr\include\avr\iox32d3.h

The following workaround at least compiles. It’ll take some time before I get to the point where I can test it.

void my_eeprom_busy_wait()
{
	// NOTE: This should do it:
	// eeprom_busy_wait()
	// but it raises compiler errors for undeclared symbols, so here's what VSCode would find:
	do { } while (!bit_is_clear(_SFR_MEM8(0x01CF) /*NVM_STATUS*/, 7 /*NVM_NVMBUSY_bp*/));
}

Versions:

  • VSCode 1.98.0
  • PlatformIO extension 5.217.328
  • Platform Atmel megaAVR 1.9.0
  • OS Windows 11 x64

This is a bug in the avr/eeprom.h header. This was fixed in https://lists.gnu.org/archive/html/avr-libc-commit/2018-06/msg00001.html. This has already been previously discussed in https://github.com/SpenceKonde/megaTinyCore/issues/155#issuecomment-602163934.

PlatformIO does feature an updated toolchain that has this bug fixed, but you have to explicitly tell it to use that. For that, use the platformio.ini (docs, registry)

[env:ATtiny1614]
platform = atmelmegaavr
board = ATtiny1614
platform_packages = 
  toolchain-atmelavr@3.70300.220127

Hence you will also see that your _SFR(0x01CF) definition is wrong. The actual NVMCTRL_STATUS register would have been at NVMCTRL_STATUS _SFR_MEM8(0x1002). Again, no such manual changes are needed when the toolchain is just upgraded.

Correct code (latest version):

Buggy code:

The code

#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/atomic.h>
#include <util/crc16.h>
#include <util/delay.h>
void setAddress(uint16_t newAddress); // function prototype

// EEPROM variables (default value of empty memory is all 1's)
EEMEM uint16_t eeAddress = 0xffff;

uint16_t address = 0;

int main()
{
	setAddress(0);
}

void setAddress(uint16_t newAddress)
{
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
	{
		eeprom_update_word(&eeAddress, newAddress);
		eeprom_busy_wait();
	}
	address = newAddress;
}

then compiles just fine.

1 Like

Thank you, it compiles now.

So as I understand it, I’m fixing the version of some component now. How will I know that this is actually a downgrade instead of an upgrade and I should remove it again because a new build is available? Will I just have to try every once in a while? Or will it break so that I’ll notice?