A quick word on ATtiny 1-series interrupts

The Atmel AVR 8-bit microcontrollers have always been a favourite for tinkering; and the massive popularity of the Arduino based on the ATmega 168 and 328 MCUs introduced a lot of hobbyists to this series. The companion ATtiny series from Atmel were the poor stepchildren of the ATmega controllers to an extent - useful for small projects but often quite limited. However, the acquisition of Atmel by Microchip Technology in 2016 ushered in a new series of MCUs bearing the same moniker of ATtiny, but much more capable and innovative. They have been around for a while now, but many hobbyists are just beginning to poke around with these new capable MCUs.

FreeRTOS stack size on ESP32 - words or bytes?

Although FreeRTOS1 is an indispensible tool for working on anything more than the simplest application on ESP32, there are some difficulties to master, such as multitasking. Multitasking using FreeRTOS is accomplished by creating tasks with xTaskCreate() or xTaskCreatePinnedToCore(). In both of these calls, one of the parameters is uxStackDepth which is the allocated stack size for the task. The FreeRTOS documentation on the subject is clear about the units for uxStackDepth:

The number of words (not bytes!) to allocate for use as the task’s stack. For example, if the stack is 16-bits wide and uxStackDepth is 100, then 200 bytes will be allocated for use as the task’s stack. As another example, if the stack is 32-bits wide and uxStackDepth is 400 then 1600 bytes will be allocated for use as the task’s stack.

The FreeRTOS declaration of xTaskCreate() is:

BaseType_t xTaskCreate(    TaskFunction_t pvTaskCode,
                            const char * const pcName,
                            const configSTACK_DEPTH_TYPE uxStackDepth,
                            void *pvParameters,
                            UBaseType_t uxPriority,
                            TaskHandle_t *pxCreatedTask
                          );

where the units of uxStackDepth are words not bytes.

So that’s the story in vanilla FreeRTOS. Then we would expect on ESP32 with 4-byte wide words that if wanted to provide a 4096 byte deep stack, we would use a uxStackDepth value of 1024. But, the plot thickens. In the ESP-IDF implementation of FreeRTOS, the function declaration of xTaskCreate() (and friends) differs:

static inline BaseType_t xTaskCreate(
	TaskFunction_t pxTaskCode, 
	const char *const pcName, 
	const configSTACK_DEPTH_TYPE usStackDepth, 
	void *const pvParameters, 
	UBaseType_t uxPriority, 
	TaskHandle_t *const pxCreatedTask
	);

Notice that the the stack size parameter is now const configSTACK_DEPTH_TYPE usStackDepth and the documentation makes it clear:

IDF FreeRTOS also changes the units of ulStackDepth in the task creation functions. Task stack sizes in Vanilla FreeRTOS are specified in a number of words, whereas in IDF FreeRTOS, the task stack sizes are specified in bytes.2

So on ESP-IDF (and the ESP Arduino core), task creation is in bytes not words.


However, we also sometimes want to see how much of the stack allocation we’re using in order to fine-tune the allocation. In FreeRTOS, we can use the uxTaskGetStackHighWaterMark API to inspect the stack high water mark. For example:

void vTask1( void * pvParameters ) {
    UBaseType_t uxHighWaterMark;
    /* Inspect our own high water mark on entering the task. */
    uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
    for( ;; )
    {
        /* Call any function. */
        vTaskDelay( 1000 );
        /* Calling the function will have used some stack space, we would 
        therefore now expect uxTaskGetStackHighWaterMark() to return a 
        value lower than when it was called on entering the task. */
        uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
    }
}

So does uxTaskGetStackHighWaterMark() returns words or bytes? In the official FreeRTOS documentation for uxTaskGetStackHighWaterMark() we read:

The value returned is the high water mark in words (for example, on a 32 bit machine a return value of 1 would indicate that 4 bytes of stack were unused). If the return value is zero then the task has likely overflowed its stack. If the return value is close to zero then the task has come close to overflowing its stack.3

So, then the answer is words. But does the ESP-IDF implementation differ? Here’s what the documentation says about it:

So the type returned by uxTaskGetStackHighWaterMark() is determined by configSTACK_DEPTH_TYPE. Out-of-the box in the ESP-IDF flavour of FreeRTOS.h, this is defined in FreeRTOS.h as:

#ifndef configSTACK_DEPTH_TYPE

/* Defaults to uint16_t for backward compatibility, but can be overridden
 * in FreeRTOSConfig.h if uint16_t is too restrictive. */
    #define configSTACK_DEPTH_TYPE    uint16_t
#endif

Further, several comments on the official Espressif ESP32 forums posted by Espressif developers point to this function returning bytes not words. For example,

Stack is in bytes…4

and

Vanilla freertos is using dword for creating task and stack watermark. esp-idf is using bytes as base size in both functions.5

Conclusion

In the end, the short version of this story is that on ESP32, working in ESP-IDF and friends, that stack size is assigned and reported in bytes.

References

Our vermiculture process: A sustainable contribution

Several people have asked me how we manage a very productive vegetable garden; so I’ve written this post as a brief description of one aspect our our approach - vermiculture.

One of our overarching family goals is sustainable living. It’s basically about leaving a small footprint. A practical component of this philosophical stance is dealing with food waste. We deal with kitchen waste with a combination of bokashi composting and vermicomposting (also known as vermiculture) It’s not for the faint-of-heart and some are horrified to learn that I keep thousands - possibly hundreds of thousands - of worms in our basement. But some have asked me to describe our process; so this article is meant just to document it. There is a lot of art and science to vermiculture and this is not meant to be a definitive guide to vermiculture.

An approach to interleaved and variable musical practice: Tools and techniques

“How do you get to Carnegie Hall” goes the old joke. “Practice, practice, practice.” But of course there’s no other way. If the science of talent development has taught us anything over the last fifty years, it’s that there is no substitute for strategic practice. Some even argue that innate musical abilities don’t exist. Whether it’s nature, nurture, or both, show me a top-notch musician and I’ll show you a person who has learned to practice well. Here we’ll take a dive into a set of practice techniques that I’ve developed, along with tools to realize them in the practice room.

Telling Hazel not to match locked files

Hazel is a centrepiece of my automation suite on macOS. I rely on it to watch directories and take complex actions on files contained within them. Recently I discovered an issue with files that are locked in the Finder. If files that otherwise match all the rules are locked, then Hazel will attempt to execute the rules. But the locked status may preclude execution. For example, I began seeing frequent Hazel notifications popups such as:

Quickly change playlist view options on macOS

While Apple is slowly coming around to recognizing that some of its users listen to classical music, there is one quirk in the Music app on macOS that betrays its deep bias toward pop music. It’s this: when you create a new playlist, the application defaults to displaying the tracks in its “Playlist” view, which as far as I can tell serves no other function than to consume real-estate in the UI by displaying a thumbnail of the album art.

Obsidian file creation date debacle and a solution

Obsidian is pretty reckless with file creation dates. If you modify a note in Obsidian, it updates the file creation date. This renders Dataview queries that rely on it useless. For an introduction to this issue, see this lengthy thread on the Obsidian forums.

Workarounds

There are a several solutions to this problem.

1. YAML-based dates

One can include a cdate (or similar) field in the note’s front matter and just direct the Dataview query against that, e.g. LIST FROM "" WHERE startswith(cdate,"2023-05-29") SORT file.ctime asc. This works, but of course it requires you to always place that field ahead of your note content. Some people like that; others not so much.

Changing the file creation date on macOS

If you modify a file in-place using sed with the -i option, you will get a file that has a new file creation date. On macOS 13.3.1, this is absolutely 100% true, although you will read claims otherwise. I ran into this problem while implementing a Hazel rule that updates YAML automatically in my Obsidian notes.

Background

I have use YAML frontmatter in my Obsidian notes. It looks like:

---
uid:     20221120152124
aliases: [20221120152124, AllAboutShell]
cdate:   2022-11-20 15:21
mdate:   2023-05-18 05:14
type:    zettel
---

My goal is to update the mdate field whenever the file changes. Hazel is the perfect tool for this, so I set about writing a rule that covers this case. The heart of the rule is a shell script action that writes the modification date:

Flatten airports in X-Plane

Some airports in X-Plane have terrain issues that can be quite entertaining.

This Delta 737-800 got lost in the maze of cargo ramps at PANC and was trying to taxi back to the terminal when it encountered a steep icy taxiway. It required 65% N1 just to get up the slope.

Clearly a fix is required. It turns out to be quite simple. In the global airports file apt.dat, find the offending airport. In this case, it’s PANC where its entry looks like:

Hazel deletes custom file icons, and a workaround

I use Hazel extensively for automating file management tasks on my macOS systems. Recently I found that Hazel aggressively matches an invisible system file that appears whenever you use a custom file or folder icon. I’ll describe the problem and present a workaround.

In a handful of directories, I have a rule that prevents users (me) from adding certain file types. So the rule just matches any file that is not an image, for example, and deletes it. This is all well and good until to try to add a custom icon to this directory. Since the file Icon? that gets created as a result is not an image, the Hazel rule dutifully deletes it.