EEPROM with AVR Libc

Programming Example

Non-volatile storage of configuration parameters is easy with AVR Libc.  Here’s a minimal example, which I tested on the ATMega32u4.  Both my header and program files appear below.



// ------1---------2---------3---------4---------5---------6---------7----------
// config.h        Store and retrieve configuration data using EEPROM
// From Code and Circuits / AVR 8-Bit Microcontroller Examples            
// ------1---------2---------3---------4---------5---------6---------7----------
#ifndef config_h__
#define config_h__
#include <avr/io.h>
#include <stdint.h>
#include <avr/eeprom.h>
#define DEFAULT_PARAM_1 135
#define DEFAULT_PARAM_2 0
#define DEFAULT_PARAM_3 0
#define DEFAULT_PARAM_4 300
//Arbitrary value to ensure EEPROM has been initialized.
typedef struct {
  uint8_t param_1;
  uint8_t param_2;
  uint8_t param_3;
  uint16_t param_4;
  uint16_t check_value;
} config_data;
void get_config(config_data *config_ptr);
uint8_t get_config_param_1(void);
void set_config_param_1(uint8_t new_param_1);
uint16_t get_config_param_4(void);
void set_config_param_4(uint16_t new_param_4);
// ------1---------2---------3---------4---------5---------6---------7----------
// config.c        Store and retrieve configuration data using EEPROM
// From Code and Circuits / AVR 8-Bit Microcontroller Examples            
// ------1---------2---------3---------4---------5---------6---------7----------
#include <avr/io.h>
#include "config.h"
#include "serial_out.h"
static config_data EEMEM configuration;
void get_config(config_data *config_ptr) {
  eeprom_read_block(config_ptr, &configuration, sizeof(config_data));
  if (config_ptr->check_value != CHECK_VALUE) {
    serial_out("Initializing EEPROM.\n");
    config_ptr->param_1 = DEFAULT_PARAM_1;
    config_ptr->param_2 = DEFAULT_PARAM_2;
    config_ptr->param_3 = DEFAULT_PARAM_3;
    config_ptr->param_4 = DEFAULT_PARAM_4;
    config_ptr->check_value = CHECK_VALUE;
    eeprom_write_block(config_ptr, &configuration, sizeof(config_data));
  } else {
    serial_out("EEPROM was initialized.\n");
void set_config_param_1(uint8_t new_param_1){
  eeprom_write_byte(&configuration.param_1, new_param_1);
uint8_t get_config_param_1(void) {
  return eeprom_read_byte(&configuration.param_1);
void set_config_param_4(uint16_t new_param_4){
  eeprom_write_word(&configuration.param_4, new_param_4);
uint16_t get_config_param_4(void) {
  return eeprom_read_word(&configuration.param_4);

AVR Programming — Interrupts

Programming Example

After a decade break, I’m re-learning AVR programming.  Sometimes finding relevant example code is easy, but there appear to be some gaps.  Here’s a minimal implementation using INT0, which I ran on both the SparkFun RedBoard (should work on the Arduino Uno R3 without changes) and the Arduino Micro (changes noted in comments).

For proper triggering, the INT0 line should be debounced when using a switch. The AVR can source sufficient current to drive an LED, but add a current limiting resistor.  A sample pushbutton interface is below.


// ------1---------2---------3---------4---------5---------6---------7----------
// Code Example -- Basic interrupts.
// Enables an interrupt triggered on the falling edge of INT0. The handler
// toggles an IO line (assumed to blink an LED).  For more complex applications,
// consider using nested interrupts and/or the macros in util/atomic.h. 
// From Code and Circuits / AVR 8-Bit Microcontroller Examples
// ------1---------2---------3---------4---------5---------6---------7----------
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
void init_io_pins(void)
  //Configure output controlled by ISR. Use IO12 (Uno/RedBoard: Port B, Pin 4.).
  //For Arduino Micro, change to PortD, Pin 6.
  DDRB |= _BV(DDB4);
  //Configure heartbeat LED on IO13.  RedBoard: PortB, Pin 5.
  //For Arduino Micro, change to PortC, Pin7.
  DDRB |= _BV(DDB5);
void enable_interrupts(void)
  EIMSK &= ~(_BV(INT0)); //Disable INT0 to be safe while accessing EICRA.
  //ISC00 and ISC01 control the "sense" of the interrupt line.  Permitted options
  //are 00 - LOW, 01 - HIGH, 10 - falling edge, 11 - rising edge. Here, interrupt
  //on the falling edge.
  EICRA |= _BV(ISC01);
  EIMSK |= _BV(INT0);    //Enable INT0.
  sei(); //Globally enable interrupts.
int main(void)
  while (1) {
    //Toggle "heartbeat" LED.  Uno/RedBoard: PortB, Pin 5.
    //For Arduino Micro, change to: PortC, Pin7.
    PORTB ^= _BV(DDB5);
  // Toggle IO12 (Uno/RedBoard: PortB, Pin 4).
  // (Arduino Micro: PortD, Pin 6).
  PORTB ^= _BV(DDB4);


INT0 Switch Input
INT0 Switch Input



An AF Phase-Shift Oscillator

Reference circuit

This is a clever design for a phase-shift oscillator. It oscillates reliably at audio frequencies and requires only a few, commonly-available components. A clean sinusoidal output appears after the two pole RC filter network even if there is clipping at the op amp. Please see Horowitz, Paul, and Winfield Hill. The Art of Electronics. 3rd ed. New York: Cambridge University Press, 2015. 438-439.

Phase Shift Oscillator
Phase Shift Oscillator for ~230Hz


A phase-shift oscillator provides positive gain and a \pm 360^{o} phase shift at the oscillation frequency.  I think of this circuit as having two parts: a two pole (passive) RC filter and an op amp integrator.  The integrator provides a fixed -270^{o} phase shift across a broad spectrum, so the circuit oscillates where the RC filter gives a -90^{o} shift.

To find the oscillation frequency, we analyze the filter network:

RC Filter Network
RC Filter Network

Applying KCL at Node V_{1}

\frac{V_{in}-V_{1}}{Z_{R}}+ \frac{V_{out}-V_{1}}{Z_{R}}-\frac{V_{1}}{Z_{C}} = 0 \ (Eq. 1)

And at Node V_{out}:

\frac{V_{1}-V_{out}}{Z_{R}}-\frac{V_{out}}{Z_{C}}=0 \ (Eq. 2)

Combining these equations to eliminate V_{1} yields:


Examining the gain coefficient, we see that when

{Z_{C}}^{2}+{Z_{R}}^{2} = 0 \ (Eq. 3)

the denominator is purely imaginary and the phase shift is -90^{o} as desired.

Because Z_{R} = R and Z_{C} = \frac{1}{j2\pi fC} , the oscillation condition becomes

f=\frac{1}{2\pi RC}

Knowing the oscillation frequency, choose the components of the op amp integrator to minimize loading of the passive filter (here, the resistor is 100 times the magnitude of the impedance of passive filter capacitor it’s in parallel with) and to provide sufficient gain for oscillation.

Simple MF Colpitts Oscillator

Reference Circuit

The following Colpitts Oscillator is built around a 2N3904 transistor.  I verified its operation for various frequencies from 250 kHz to 1.5 MHz.  The inductor is 20 turns of insulated 22 AWG wire on a 1.5 inch diameter cardboard core (the turns are as closely wound as practical, taking about 1.0 inches axially along the core).  I measure the inductance as approximately L \approx 11 \mu H .  The predicted frequency of oscillation for equal tank capacitors is f = \frac{1}{\pi \sqrt{2LC}}.  Capacitor values for the LC tank (lower left of schematic) and the corresponding observed oscillation frequencies are presented in a table.

Practical Colpitts Oscillator
Colpitts Oscillator for 250 kHz – 1.5 MHz



Capacitor Value Observed Frequency
1.5\, nF 1.6\, MHz
10\, nF 670\, kHz
33\, nF 370\, kHz
68\, nF 250\, kHz

The oscillator gave best performance at capacitor values 33 nF and 22 nF.

Measuring Inductance


Measuring inductance is a complex task.  Methods proposed elsewhere require precise measurements with an oscilloscope in its usual (voltage vs. time) display mode.  Methods based on building a filter with the inductor and finding the cutoff or natural frequency assume a sufficiently high-Q that peak/null detection is obvious.  In practice, I find these methods hard to apply.

Is there an easier method to measure inductance using a hobby-grade oscilloscope?

Continue reading Measuring Inductance