Naive user question about timer constants and variables

I am fairly new to the Arduino world, but not so much to embedded programming.
I am working with Nano Every boards (atmega4809) and 3.3v compatibles (atmega4808).
My interest is timing and sleep modes.

I have been looking for succinct documentation and examples for using these features for a couple of months now, and have become frustrated. What I need is a clear explanation of the 'Arduino way' to interact with the low level registers that control these features. I also would like to see the constants and their build-time values that are routinely used with these registers. I do not know where to look.

What I want to do is well defined. I want to use the suspend and deep sleep modes for sub 1 second periods (i.e. 600 ms) and then to return to normal execution via an interrupt or an event interrupt.

I have mostly settled on using the MegaCoreX library, though I have also worked with the RocketScream_RTCAVRZero-1.0.0 library as well. The latter is very helpful if you want to use the suspend mode, but only for periods > 1s.

I have found the example in "Getting Started with Real-Time Counter (RTC)" , Microchip's TB3213. It is very helpful and contains an example that comes close to what I need - Appendix : "Example 7-3. RTC PIT Wake from Sleep Code Example". It depends on a call to ccp_write_io(), which, not surprisingly, is not available to the linker used by the Arduino environment.

The only hint f these things that I can find comes by grepping my entire system. I seem only to find them in the MegaCoreX source keywords.txt file, which gives me no information about what the represent.

My best guess at this point is that -as in the RocketScream_RTCAVRZero-1.0.0 library, one combines the desired constants and assigns them to CLKCTRL as in:

temp &= ~CLKCTRL_ENABLE_bm;
temp = CLKCTRL.XOSC32KCTRLA; 
CLKCTRL.XOSC32KCTRLA = temp;

But where is CLKCTRL described, and where are the available constants described, and how to apply them? I see much of the information described in an abstract way in the datasheets and the technical bulletins, but it really doesn't tell me how to do it the 'Arduino way'.

I'm sure that all of this is down to my lack of deep knowledge of how Arduino conventions have evolved over time.

Can anyone help me get a clue?

The manufacturer's page for the ATmega4809: https://www.microchip.com/en-us/product/ATMEGA4809.
With a datasheet.
If you read the datasheet 5 times, then you know the chip.

Arduino does not implement the sleep mode.
There are sleep functions in the gcc-avr library, so you don't have to control the registers yourself. Well, sometimes the ATmega4809 is put in the "MegaAVR" family, but I assume that the sleep functions are for the ATmega4809 as well.
If you are lucky then someone has made a library for the sleep mode that also supports the ATmega4809.
Here is a selection of libraries: https://www.arduino.cc/reference/en/libraries/. Somewhere in a subsection are probably sleep libraries.
You can look on Github for libraries that did not make the selection, or search this forum.

That are many clues, but would this link be enough ? https://forum.arduino.cc/t/help-needed-sleeping-the-atmega4809-arduino-nano-every/914000/

Thank you!

I have read all the pertinent datasheets more than 5 times. Perhaps I'm a bit thick.

No where do I find definitions of things like RTC.PITINTFLAGS.
Where is RTC (a struct or class, I assume) defined? PITINTFLAGS is presumably a struct item or member variable, but where is it defined, and what is the range of possible values? And most important, when those are expressed as constants, how are they spelled?Some of this may be guessed at by reading the datasheets, but I really really do not like this kind of guesswork.
And do the gcc-avr libraries bear any relationship to what Arduino is doing? Nowhere does anything tell me that they do.
And OBTW, where are they hidden?

Dave

The datasheet shows shows that CLKCTRL.XOSC32KCTRLA is a register which uses a few bits, and with explanation what those bits do. The PITINTFLAGS is also a register, but it is only in a register summary.
There is a Application Note "TB3213 Getting Started with RTC" that explains the Real-Time Counter more. That has also a Github with example files: https://github.com/microchip-pic-avr-examples/atmega4809-getting-started-with-rtc-studio

The names used in software are defined by the compiler (not Arduino). They are often exactly the same as the names of the datasheet.

The MegaAVR microcontrollers use the newer register naming style as is used in the processors such as the ATSAMD21G (Arduino Zero). That is not the same as the old ATmega328P programming.

Arduino is on top of the gcc compiler. The gcc compiler has a avr-gcc section to support the microcontrollers. All the hard work at the lowest level is by the avr-gcc. Arduino has a preprocessor that walks through a sketch and makes functions prototypes and so. After that the sketch is given to the gcc compiler and linker.
As a result, you can use all the low level things, such as direct register programming. It is even possible to add a assembly file to your project and that will be compiled as well.

Would that link in my previous post be enough ?

Thanks.

That thread you reference is helpful but not quite what I am hoping for.
It does show clearly that many others are suffering as I am from the lack of documentation. I have read it many times.

I am not familiar with either the old or the new register naming style, though I was aware that the MegaAVR-0 chips were different. I have not found documentation for either one.
I don't use the ATMSAMD21G chips and don't wish to.
The 5v ATmega328P is also unsuitable for my purposes for several reasons.

As I said above, I am all too familiar with the document TB3213. This is where my questions tend to start. There is an example that is very close to what I want in the appendix. But it will not compile because of the alls to ccp_write_io() in the code. It would appear that there is no corresponding call to write to a protected register in the Arudino world.
Other evidence seems to imply that you do this kind of register write using some sort of template or operator overload that uses the '=' sign to insert the value, presumably defined in the Arduino world.

I have not been able to find the gcc-avr header files anywhere, though there may be some hints that they are buried in some form of precompiled file that I cannot recognize.

The gcc-avr header files must exist in some form, the compiler finds them. But there are clearly object files that are meant to accompany them that it is not possible to link to.

Dave

Yeah, that's how it is. Normal people like us have to rely on tutorials that others make.
Both Arduino and the GCC compiler are open source, and everything is in the build environment on your computer, but many things are hidden in gcc libraries.

In the Arduino IDE, in the "Preferences", you can click at the bottom on the settings folder. That brings you to the hidden ".arduino15" folder. The build environment for the MegaAVR is downloaded there. The avr-gcc for the ATmega4809 is there.

I don't know how it is organized, so I did a search for "XOSC32KCTRLA" and it was found in this file:

.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/avr/include/avr/iom4809.h

It turns out that it is not from the gcc compiler, but supplied by Microchip/Atmel for the gcc compiler. It is 5000 lines, so I suppose every register and every bit from the datasheet is defined in that file.

The "sleep.h" is here:

.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/avr/include/avr/sleep.h

Thanks!
I'm not sure why my find and grep searches have not been finding stuff down in those folders. That is one of the main things that I have been looking for.
If I can find what I'm looking for there, I can hopefully sort out my questions.

Maybe if I make this work, I can post something to help others.

Dave

Once you know how Atmel/Microchip has converted their register names to C structure names (ala @Koepel ), it's pretty easy to find the info in the datasheet. RTC peripheral, PITINTFLAGS:

It depends on a call to ccp_write_io(), which, not surprisingly, is not available to the linker used by the Arduino environment.

ccp_write_io() is in <avr/cpufunc.h> from avr-libc - apparently one of the few avr-libc files that isn't included in the Arduino builds by default. Interestingly, it's not used in the App note I found (which uses straight C code to do the "protected register write", which is a bit dangerous given how C compilers these days like to rearrange your code.)

"5V" should not be one of them, because the ATmega series runs on as low as 1.8V. This excellent tutorial covers the timers quite thoroughly.

@WestfW:

Once you know how Atmel/Microchip has converted their register names to C structure names (ala @Koepel ), it's pretty easy to find the info in the datasheet. RTC peripheral, PITINTFLAGS:

Yup, but my suspicious mind wants to see it written somewhere that REXx === OLD_REGx.

@jremington:That is a useful tutorial, but the fact that I know that the timers I'm interested in have been re-architected leaves me in the lurch. This document is quite dated, and though it shows a lot of the thinking behind the use of AVR timers, from the datasheets I can tell that stuff has changed. As a novice, I really do not know what to trust.

Also, I misspoke when I said the 5v ATmega328P isunsuitable for my purposes. I meant that the 5v Arduino Nanos that use ATmega328P are unsuitable for my purposes (the boards, not the chips). Not to mention unavailable.

With @Koepel's kind help I found a lot of what I was looking for (ex. for 4808):

//--------------------------------------------------------------------------
// CLKCTRL - Clock controller registers and enumerated constants.
//
// For nano4808
//--------------------------------------------------------------------------

// Clock controller
//--------------------------------
typedef struct CLKCTRL_struct
{
register8_t MCLKCTRLA; // MCLK Control A
register8_t MCLKCTRLB; // MCLK Control B
register8_t MCLKLOCK; // MCLK Lock
register8_t MCLKSTATUS; // MCLK Status
register8_t reserved_1[12];
register8_t OSC20MCTRLA; // OSC20M Control A
register8_t OSC20MCALIBA; // OSC20M Calibration A
register8_t OSC20MCALIBB; // OSC20M Calibration B
register8_t reserved_2[5];
register8_t OSC32KCTRLA; // OSC32K Control A
register8_t reserved_3[3];
register8_t XOSC32KCTRLA; // XOSC32K Control A
register8_t reserved_4[3];
} CLKCTRL_t;

// clock select select enum
//--------------------------------
typedef enum CLKCTRL_CLKSEL_enum
{
CLKCTRL_CLKSEL_OSC20M_gc = (0x00<<0), // 20MHz oscillator
CLKCTRL_CLKSEL_OSCULP32K_gc = (0x01<<0), // 32KHz oscillator
CLKCTRL_CLKSEL_XOSC32K_gc = (0x02<<0), // 32.768kHz crystal oscillator
CLKCTRL_CLKSEL_EXTCLK_gc = (0x03<<0), // External clock
} CLKCTRL_CLKSEL_t;

// Crystal startup time select enum
//--------------------------------
typedef enum CLKCTRL_CSUT_enum
{
CLKCTRL_CSUT_1K_gc = (0x00<<4), // 1k cycles
CLKCTRL_CSUT_16K_gc = (0x01<<4), // 16k cycles
CLKCTRL_CSUT_32K_gc = (0x02<<4), // 32k cycles
CLKCTRL_CSUT_64K_gc = (0x03<<4), // 64k cycles
} CLKCTRL_CSUT_t;

// Prescaler division select enum
//--------------------------------
typedef enum CLKCTRL_PDIV_enum
{
CLKCTRL_PDIV_2X_gc = (0x00<<1), // 2X
CLKCTRL_PDIV_4X_gc = (0x01<<1), // 4X
CLKCTRL_PDIV_8X_gc = (0x02<<1), // 8X
CLKCTRL_PDIV_16X_gc = (0x03<<1), // 16X
CLKCTRL_PDIV_32X_gc = (0x04<<1), // 32X
CLKCTRL_PDIV_64X_gc = (0x05<<1), // 64X
CLKCTRL_PDIV_6X_gc = (0x08<<1), // 6X
CLKCTRL_PDIV_10X_gc = (0x09<<1), // 10X
CLKCTRL_PDIV_12X_gc = (0x0A<<1), // 12X
CLKCTRL_PDIV_24X_gc = (0x0B<<1), // 24X
CLKCTRL_PDIV_48X_gc = (0x0C<<1), // 48X
} CLKCTRL_PDIV_t;

Other bits are scattered elsewhere.I would like to find the source for ccp_write_io().

Dave

Not at all. The processor data sheet fully describes the functions and programming of the "re-architected" timers.

Keep reading and doing experiments until you understand the material thoroughly.

That you don't understand them leads me to suspect that you have no good reason to reject the "dated" timers of the ATmega series. They probably do what you want.

You might want to look at this note on Spence Konde's github page for a workaround:

Thanks!

That is definitely helpful.
I've been reading the SpenceKonde stuff for clues, but had not seen that.

Dave

Here: [avr-libc] Contents of /trunk/avr-libc/libc/misc/ccp_write.S

There is also a macro in avr/xmega.h (which is already #included) that does essentially the same thing:

#define _PROTECTED_WRITE(reg, value)				\
  __asm__ __volatile__("out %[ccp], %[ccp_ioreg]" "\n\t"	\
		       "sts %[ioreg], %[val]"			\
		       :					\
		       : [ccp] "I" (_SFR_IO_ADDR(CCP)),		\
			 [ccp_ioreg] "d" ((uint8_t)CCP_IOREG_gc),	\
			 [ioreg] "n" (_SFR_MEM_ADDR(reg)),	\
			 [val] "r" ((uint8_t)value))

Thanks! It is good to see what is going on there.

Dave