Menu

Dump digits of Pi on AVR microcontrollers

Vince C.

This project serves absolutely no purpose at all. It stems from an idea discussed on the Arduino Discord channel.

Warning

This project has been tested on a Linux machine only. Significant changes may be required to adapt the software to run on Windows.

Description

This project builds a firmware for AVR microcontrollers (typically ATmega328) that prints, through the serial interface, as many digits of Pi as possible.

The digits are fetched from http://www.geom.uiuc.edu/~huberty/math5337/groupe/digits.html, which lists one hundred thousand (100,000) of them. Of course, that much is way beyond the storage capacity of an Arduino (aka ATmega328). As a matter of fact, the latter microcontroller only has 32kB flash memory, of which 512 bytes (typically) are reserved for the bootloader. In order to store the largest number of digits, some sacrifice must be done: the main program, though running on an Arduino, is built from scratch, i.e. not relying on the Arduino library at all.

Storing one digit per byte would of course be a total waste of space. This is why digits are packed into one byte as nibbles. A nibble is 4 bits, ranging from 0 to 0x0A. The program running on the microcontroller prints nibbles in pairs, reading the string, byte after byte. The higher nibble is printed first.

Without any data, the program size is 232 bytes, which leaves 32768-512-232 = 32024 bytes. That is enough to hold more than 64000 digits. That is the limit that was chosen.

The project contains two parts:
* a console tool, take-pi, written in C++, to extract a given amount of digits of Pi, which are piped to the standard input; the result is written to the standard output as a C-style array;
* the actual AVR program.

The project ships with a Makefile to automate everything:

  • query the web site URL and extract the digits of Pi into a cache file (data/pi.txt)
  • building the extract tool
  • execute the extract tool and build the array in a C file in the project directory
  • compile the main program and data file

Execution time

The serial speed is set to 9600 baud. It takes approximately one minute to print the entire list of 60,000 digits.

Building the firmware

Building the project relies upon GNU make. Running make on the command line will recurse into directory tools and build the extract tool, which is a dependency of the main AVR application. Consequently, a directory data appears, which stores a cached version of the entire list of digits. The extract tool, take-pi, only extracts as many as desired to fit the remaining program memory space.

Dependencies

The following packages must be installed on a Linux distribution — the Windows equivalent shall also be installed on a Windows machine:

  • avr-gcc
  • avr-libc
  • avr-binutils
  • avrdude
  • binutils (sed, grep)
  • curl
  • GNU make

With the exception of binutils, curl and GNU make, these packages are installed when the Arduino IDE is installed. The former utilities generally are installed by default.

The project has been successfully compiled on Manjaro with avr-gcc-10.1.0 and avr-libc-2.1.0.

File structure

After building the project, the following executables are available, form the project directory:

Fetching digits of Pi

Although the data file is created automatically, it is still possible to run the formatting tool on the command line. The only argument it requires is the number of digits to include in the array.

Reminder: As already mentioned, the number of digits is even as one digit forms a nibble (4 bits) and every byte in program memory stores exactly two nibbles.

For instance, running tool/take-pi 64 < data/pi.txt reads 64 digits (each being a single character) from data/pi.txt (if it was previously cached by running make) and writes to the standard output the contents of a C source file to store the data in program memory. The standard output is expected to be redirected to a file. Example:

#include <avr/pgmspace.h>

const char PI[] PROGMEM = {
    0x14, 0x15, 0x92, 0x65, 0x35, 0x89, 0x79, 0x32, 0x38, 0x46, 0x26, 0x43, 0x38, 0x32, 0x79, 0x50, 
    0x28, 0x84, 0x19, 0x71, 0x69, 0x39, 0x93, 0x75, 0x10, 0x58, 0x20, 0x97, 0x49, 0x44, 0x59, 0x23, 
    0x07, 0x81, 0x64, 0x06, 0x28, 0x62, 0x08, 0x99, 0x86, 0x28, 0x03, 0x48, 0x25, 0x34, 0x21, 0x17, 
    0x06, 0x79, 0xFF
};

The output should be redirected to pi-data.c in order to update the application. Running make again will update the microcontroller application (firmware).

Important note: Altough the sequence may look like a string, it is not. Therefore it ends with 0xFF instead of the C-style terminating NUL as there happens to be two consecutive nibbles, both set to zero.

Uploading the firmware

Running make alone only builds the microcontroller firmware, along with the extract tool. To upload the firmware to an Arduino Uno, simply run:

make upload

Compiling for the Arduino Mega

The makefile by default produces a firmware to run on the Arduino Uno. It can of course be edited for a different board¹. Edit the line that says CPU=atmega328, change it to CPU=atmega2560 and save the file. The arguments to avrdude will be updated automatically upon running make or make upload.

¹ Currently only the Uno and Mega are supported.


Project Members:


Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.