Improving vegetable seed germination with chemical pretreatment

Some vegetable seeds, particularly many exotic chilli pepper varieties and some Asian eggplants are tricky to germinate. After trying the obvious things - cold-induced forced dormancy (cold stratification), abundant moisture, high humidity, and temperatures over 80F, I’ve found that some seeds simply do not germinate with much success at all. But having read a number of articles on this problem, we decided to try an intensive chemical process to see if we could achieve better results. And it looks successful.

Here’s the process:

  1. A 24 hour soak in 2% potassium nitrate (2g potassium nitrate/100 ml water) at 85 degrees F.
  2. A 2-5 minute immersion in 3% hydrogen peroxide.
  3. Remove seeds an place on a paper towel. Fold the paper towel and insert into a plastic baggie.
  4. Mix a 15:1 aqueous solution of hydrogen peroxide (the 3% that is commonly available) and pour just enough into the baggie to saturate the paper towel.
  5. Seal and place on a heating mat at 83-87F.
  6. Check daily for a week.
  7. After a week, replace the hydrogen peroxide soaking solution.

Above, is a photograph of Ping tung (eggplant) seeds germinating after 4 days. In general, using standard germinating practices in ordinary media and without pretreatment, these seeds require 10-14 days. So, the method shows a lot of promise.

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.

Some of the positives of the tinyAVR 1-series are:

  1. The introduction of the UPDI programming interface - moving away from ICSP is a major step forward. Not only does this redue the pin count required for programming from 4 to 1.
  2. Event System: The Event System allows for direct communication between peripherals without involving the CPU. This can lead to more efficient use of resources and faster response times in applications that require real-time processing or precise timing.
  3. Configurable Custom Logic (CCL): The CCL enables the creation of simple logic functions directly in hardware, reducing the need for external components and allowing for more compact and power-efficient designs.

Since, I’m just beginning to look into these MCUs, this post and likely others to follow are just to document some of the features and works in case learning about them is helpful to others.

Prerequisites

Since I’m on macOS and do not own a dedicated Microchip/Atmel branded UPDI programmer, using Microchip Studio with, say an Atmel ICE programmer is not in the cards. For the moment, I’m just working in the Arduino IDE. Not my favourite at all, but with some effort you can get the job done. To program these controllers you do need to set up both the software and hardware environment first.

Hardware setup

You will need a UPDI programmer. There are several options here:

  1. Buy a dedicated UPDI programmer. There are several on the market through Tindie and elsewhere. I have not evaluated them at all; but some seem to be quite capable, including the ability to mass-program devices without a computer.
  2. Convert an Arduino (Uno, Nano, etc.) to a dedicated programmer. This is what I did, using a 5V Nano. It’s a slight overkill but it works. Two modifications are necessary to make it work:
    • Add a 10 uF capacitor from RESET to GND
    • Add a 4K7 Ω resistor from D6 to the UPDI pin.
    • Upload jtag2updi sketch to the Arduino
  3. Convert a USB to serial adapter to a UPDI and use SerialUPDI to program the target.

Software setup

In the Arduino environment, you will need to add the megaTinyCore board library. The installation documentation is straightforward; but it involves a step which requires loading a library.json file from this URL: http://drazzy.com/package_drazzy.com_index.json. Unfortunately at the time of this writing the SSL certificate on this site has expired and Arduino IDE refused to load the library. When you are reading this, it may be fixed; but there is a workaround:

  • Navigate to the URL and when the browser complains about the security risk, just accept it and download the json file.
  • Provide the file URL to the Board Manager in the Arduino preferences. In my case it was: file:////Users/alan/Documents/dev/tinyMegaCore.json
  • Then install the library in Board Manager.

A few caveats:

  • You need to select the programmer in the Tools menu. It is jtag2updi.
  • The Upload button does not work. You need to use Sketch > Upload Using Programmer.
  • You may see the error avrdude: jtagmkII_initialize(): Cannot locate “flash” and “boot” memories in description. Apparently it is inconsequential. It certainly seems so.

Interrupts, finally

Now, finally the actual subject of the post - interrupts on the tinyAVR 1-series. I’m only concerned with pin interrupts here. They are easy to use and configure but there are a few things to be aware of:

  • Any pin can have an external interrupt
  • All interrupts on a port have a single vector. It is up to the developer to distinguish between the pins that could have generated the interrupt. For example PORTA_PORT_vect covers all of the interrupts on the PORTA pins.
  • The developer is responsible for clearing the interrupt flag in the interrupt service routine.
  • The Arduino function attachInterrupt() can be used, but it is not recommended. There are several reasons for this; but chiefly it imposes significant overhead.

The simple project I’m describing here uses one of those microwave presence detectors that you can find everywhere on AliExpress:

I’ve wired this up with an ATtiny 1614 on an SMD to DIP adapter board, with the microwave module connected to PA5 and an indicator LED to PA6. When presence is detected, the code should toggle the LED. Simple.

Set up interrupt

To set up the interrupt, we will just designate PA5 as an input pin and enable a rising signal interrupt on it:

void setup() {
    // Interrupt on PA5
    PORTA.DIRCLR = PIN5_bm;
    PORTA.PIN5CTRL = PORT_ISC_RISING_gc;
    
    // enable global interrupts
    sei();
}

Don’t forget to enable global interrupts with sei().

Interrupt service routine

As mentioned, all of the pins in a port are capable of using external interrupts, but they share a single vector. Our ISR needs to distinguish which pin generated the interrupt, do its work as quickly as possible and reset the interrupt flag, not necessarily in that order.

volatile bool didReceiveRadarPulse = false;

ISR(PORTA_PORT_vect) {
    // reset the PORTA.INTFLAGS - necessary on this series
    uint8_t portAFlags = PORTA.INTFLAGS;
    PORTA.INTFLAGS = portAFlags;
    if (portAFlags & PIN5_bm) {
        // Handle the interrupt for PA5
        didReceiveRadarPulse = true;
    }
}

The trick of reading the flags and writing the same value back to them works because of a hardware feature of this register:

So, we just read the value so we can use it to test whether our PA5 interrupt was triggered and then immediately write the value back to reset it. We could also just do the pin toggle in the ISR, but since we’re leaving the door open to doing more sophisticated things with this skeletal code, we will set a boolean didReceiveRadarPulse to true and then act on that in the loop().

Toggle a pin

In other MCUs toggling a pin often meant keeping track of the state yourself. Interestingly, the tinyAVR 1-series has a register just for toggling an output pin. So we can just PORTA.OUTTGL = PIN6_bm and it’s done!

Complete code

Here’s the full working code for ATtiny 1614.

/*

Test interrupts on ATtiny 1614

*/
#include <Arduino.h>
#include <avr/io.h>
#include <avr/interrupt.h>

volatile bool didReceiveRadarPulse = false;

ISR(PORTA_PORT_vect) {
    // reset the PORTA.INTFLAGS - necessary on this series
    uint8_t portAFlags = PORTA.INTFLAGS;
    PORTA.INTFLAGS = portAFlags;
    if (portAFlags & PIN5_bm) {
        // Handle the interrupt for PA5
        didReceiveRadarPulse = true;
    }
}

void setup() {
    PORTA.DIRSET = PIN6_bm;  // simple toggle
    PORTA.OUTCLR = PIN6_bm;  // turn off
    // Interrupt on PA5
    PORTA.DIRCLR = PIN5_bm;
    PORTA.PIN5CTRL = PORT_ISC_RISING_gc;
    // enable global interrupts
    sei();
}

// the loop routine runs over and over again forever:
void loop() {
    if (didReceiveRadarPulse) {
        PORTA.OUTTGL = PIN6_bm;
        didReceiveRadarPulse = false;  // reset our radar pulse flag
    }
}

If you have any difficulties, I can try to help. See my contact page.

References

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:

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.

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.

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.

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:20221120152124aliases:[20221120152124,AllAboutShell]cdate:2022-11-2015:21mdate:2023-05-1805:14type:zettel— My goal is to update the mdate field whenever the file changes.

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.