Mar 30, 2021 - Putting an ATmega328P into sleep

Comments

Putting an ATmega328P into sleep

For a little project I want to take and send measurements roughly about every 10 minutes. It will run on an ATmega328p microcontroller powered by two AA batteries, so power consumption will be an important issue. The ATmega328p is the heart of every Arduino. But the Arduino with all its extra components draws a lot of power. So it has be run “stand alone” (I’ll create another blog post for that later). But the nice thing is, that you can easily program it on an Arduino and then just pop out the chip from the Arduino and put it onto your final circuit board. But it’s not only the extra components of an Arduino which draws unnecessary power, it’s also the constant “awake” state. Therefore the chip has to be put into sleep mode and only wake up every 10min to perform the measurements. In a typical Arduino sketch you would use the delay method to wait. Here’s a way to replace that with a real sleep method.

The code was mostly taken from Wolles Elektronikkiste - Sleep Modes and Power Management. An excellent resource if you want to know more about different microcontrollers, sleep modes and their power consumptions. check it out!

#include <avr/wdt.h>
#include <avr/sleep.h>

// Taken from:
// https://wolles-elektronikkiste.de/en/sleep-modes-and-power-management 

const unsigned int sleepInSec = 10u * 60u; // 10 min

void setup() {
  sleepSetup();
}

void loop() {
  // do something
  // ...

  sleep(sleepInSec);
}

void sleepSetup() {
  cli();
  wdt_reset();
  WDTCSR |= (1<<WDCE) | (1<<WDE);
  WDTCSR = (1<<WDIE) | (0<<WDE) | (1<<WDP3) | (1<<WDP0);
  // 8s / interrupt, no system reset
  sei();
}

void sleep(unsigned int timeInSec) {
  unsigned int rounds = (unsigned int)(timeInSec / 8u);
  for (unsigned int i=0; i<rounds; i++) {
    wdt_reset();
    set_sleep_mode(SLEEP_MODE_STANDBY);
    sleep_mode();
  }
}

ISR(WDT_vect){
}

Note: This is very approximate. It uses the ATmega328p’s maximum sleep time of 8 seconds, and loops over it, so it will only work for sleep times > 8 sec and be only accurate for multiples of 8. But for stuff like doing something every few minutes, that should be good enough.

It needs some setup steps, wrapped in the sleepSetup method, and then you can call sleep(123) instead of delay(123000).

By the way: Furthermore I tried to reduce the power consumption by running the chip at 8 MHz and 3.3 V instead of 16 MHz. But unfortunately I couldn’t get the nRF24L01 component working in this setup. But surprisingly the ATmega328p seems to work fine with 3.3 V even at 16 MHz, although I read you should reduce the clock frequency when running it on 3.3 V. But it’s a pity, as going down to 8 MHz would half the power usage once more. Very roughly speaking it looks you’ll get a reduction in power consumption to roughly 1/2 for using the ATmega328p stand-alone instead of in the Arduino, another 1/2 by using 3.3 V instead of 5 V, another 1/10 by using sleep (standby) and another 1/2 by using 8 MHz instead of 16 MHz. So in total 1/50 (16 MHz) to 1/100 (8 MHz) compared to the Arduino.

Feb 7, 2021 - Learning Rust (and Maths)

Comments

Lerning Rust (and Maths)

Finally scheduled some time to learn Rust. I bought a book ages ago and also joined a course on Udemy, which was kind of alright, but didn’t really get me going. Then I found the Youtube channel of Ryan Levick, and it’s really great. I can highly recommend to fire up your IDE and code along watching his videos.

At the same time I’m trying to refresh my maths. Also ages ago I bought A Programmer’s Introduction to Mathematics. But as I rather used it for bedtime reading it didn’t really get me anywhere. So I thought I just take the ideas from there and try to implement them in Rust. This way I hopefully pick up both!

So far I’ve implemented the ‘Polynomial interpolation’ mentioned in the first few pages of the book, code on GitLab

Nov 17, 2020 - Python CLI script template

Comments

Python CLI script template

Usually my little Python scripts start with simply using sys.argv[] and print(). But after refactoring they always end up with a structure like this, using the argparse and logging libraries. It’s about time to put this in some kind of copy/pastable template:

import argparse
import logging


DESC = '''
This command line tool does something with a file.
'''

parser = argparse.ArgumentParser(description=DESC)
parser.add_argument("file", help="Some file to process")
parser.add_argument("output", nargs="?", help="Optional output file")
                             #nargs="+" for one or more positional arguments
parser.add_argument("-v", "--verbose", action="count", default=0,
                    help="Verbosity (-v, -vv, etc)")
parser.add_argument("-p", "--param", help="Some additional parameter")
parser.add_argument('--another', default="something", help="Optional parameter "
                                                           "with default value")
parser.add_argument('--flag', action="store_true", default=False,
                    help='Optional flag')

args = parser.parse_args()
loglevel = 30 - (args.verbose * 10)
logging.basicConfig(level=loglevel, format='%(levelname)s: %(message)s')


print(f"Do something with {args.file}")

if args.output:
  print(f"Write to {args.output}")

if args.param:
  print(f"With additional parameter {args.param}")

print(f"The other parameter is {args.another}")

if args.flag:
  print("The flag was set too.")

logging.debug("This is a debug message")
logging.info("This is an info message")
logging.warning("This is a warning message")
logging.error("This is an error message")

Paste this code in a file and have a play with it, especially using the different log levels by using -v, -vv etc. You’ll also notice that you automatically get a nice help (-h) message from argparse for free :-)