ff-ad9833: Added Für Elise Demo

I added this tune to the demo-melodies.fs file:

Für Elise (first half) played with ff-ad9833 code

My apologies to the Beethoven fans as I had to do some violence to the tune in order to make it monophonic and to fit it inside the 3 octaves provided by my code. I also had to apply some filtering to the recording to try to remove background noise in my apartment.

Here is the tune in source code:

create furelise-p1
d_16th ne  o5 == d_16th nd# o5 == d_16th ne  o5 == d_16th nd# o5 ==
d_16th ne  o5 == d_16th nb  o5 == d_16th nd  o5 == d_16th nc  o5 == 
d_8th  na  o5 == d_16th nr  nr == d_16th nc  o4 == d_16th ne  o4 ==
d_16th na  o5 == d_8th  nb  o5 == d_16th nr  nr == d_16th ne  o4 ==
d_16th ng# o4 == d_16th nb  o5 == d_8th  nc  o5 == d_16th nr  nr ==
d_16th ne  o4 == d_16th ne  o5 == d_16th nd# o5 == d_16th ne  o5 ==
d_16th nd# o5 == d_16th ne  o5 == d_16th nb  o5 == d_16th nd  o5 ==
d_16th nc  o5 == d_8th  na  o5 == d_16th nr  nr == d_16th nc  o4 ==
d_16th ne  o4 == d_16th na  o5 == d_8th  nb  o5 == d_16th nr  nr ==
d_16th ne  o4 == d_16th nc  o5 == d_16th nb  o5 == end-score

create furelise-p2 d_quarter na o5 == end-score

create furelise-p3
d_8th  na o5 == d_16th nr nr == d_16th nb o5 == d_16th nc o5 ==
d_16th nd o5 == end-score

create furelise-p4
d_dt-8th ne  o5 == d_16th ng  o4 == d_16th nf  o5 == d_16th ne  o5 ==
d_dt-8th nd  o5 == d_16th nf  o4 == d_16th ne  o5 == d_16th nd  o5 ==
d_dt-8th nc  o5 == d_16th ne  o4 == d_16th nd  o5 == d_16th nc  o5 ==
d_16th   nb  o5 == d_16th ne  o4 == d_16th ne  o5 == d_16th ne  o4 ==
d_16th   ne  o5 == d_16th ne  o4 == d_16th ne  o5 == d_16th ne  o4 ==
d_16th   ne  o5 == d_16th ne  o5 == d_16th ne  o6 == d_16th nf# o4 ==
d_16th   ng  o4 == d_16th nd# o5 == d_16th ne  o5 == d_16th nf# o4 ==
d_16th   ng  o4 == d_16th nd# o5 == d_16th ne  o5 == d_16th nd# o5 ==
d_16th   ne  o5 == d_16th nd# o5 == d_16th ne  o5 == d_16th nb  o5 ==
d_16th   nd  o5 == d_16th nc  o5 == d_16th na  o5 == d_16th ne  o4 ==
d_16th   na  o4 == d_16th nc  o4 == d_16th ne  o4 == d_16th na  o5 ==
d_16th   nb  o5 == d_16th ne  o4 == d_16th ng# o4 == d_16th ne  o4 ==
d_16th   ng# o4 == d_16th nb  o5 == d_16th nc  o5 == d_16th ne  o4 ==
d_16th   na  o4 == d_16th ne  o4 == d_16th ne  o5 == d_16th nd# o5 ==
d_16th   ne  o5 == d_16th nd# o5 == d_16th ne  o5 == d_16th nb  o5 ==
d_16th   nd  o5 == d_16th nc  o5 == d_16th na  o5 == d_16th ne  o4 ==
d_16th   na  o4 == d_16th nc  o4 == d_16th ne  o4 == d_16th na  o5 ==
d_16th   nb  o5 == d_16th ne  o4 == d_16th ng# o4 == d_16th ne  o4 ==
d_16th   nc  o5 == d_16th nb  o5 == end-score

create furelise-p5 d_dt-quarter na o5 == end-score

That occupied 326 bytes of memory, which was the score bytes along with the bytes needed for the word headers (furelise-p1, etc.) It was divided into five parts to save memory, since some of the parts are repeated.

Free software source code and documentation are available here:

https://codeberg.org/infrared/ff-ad9833

Running Arduino IDE in Guix

Arduino IDE running on a Guix system

There is no Arduino IDE package for Guix. I asked why once, but I forgot what the reason was — something to do with the way that Arduino build process works I think. Anyway, this is how I get it running on my systems. I suspect this is not the best way, but it works for me. The process is a little convoluted, but I don’t use the IDE very often, so I haven’t been motivated to figure out something better. Typically all I need is avrdude, in order to load Forth firmware onto the chips, and there is an avrdude package available in Guix, as well as a avr-toolchain package and a few other tools.

First you need to make a clone of the git repo:

git clone https://github.com/arduino/Arduino.git

Specifically I am using the some old commit bf24880d7c559751765a43cd1669d893bba267e8, which is the commit for Arduino IDE version 1.8.14, but maybe a newer version would work also.

After changing into the build directory, you must setup the proper build/run environment. I do this by having the following manifest file saved at ~/Manifests/arduino-ide-run.scm:

(use-modules (gnu packages java))

(concatenate-manifests
 (list
  (specifications->manifest
   '("ant"
     "avr-toolchain"
     "bash"
     "coreutils"
     "git"
     "grep"
     "libx11"
     "libxrandr"
     "libxtst"
     "lbzip2"
     "sed"
     "tar"
     "unzip"
     "patchelf"
     "which"))
  (packages->manifest
   `((,icedtea "jdk")))))

Then I set up the environment with the command…

guix environment --pure --preserve='DISPLAY' --preserve='GDM' --preserve='DBUS' --preserve='GIO' --preserve='XDG' --preserve='WINDOW' --preserve='SESSION' --preserve='XCUR' --preserve='DESKTOP' --preserve='XAUTH' -m ~/Manifests/arduino-ide-run.scm

If you want to use the same environment as I am using right now, prefix the command above with guix time-machine --commit=079a7f2c65c51da7b53b0e5ef44c516dc8eaab6e --. (I’m running Gnome DE, but I’m not sure if that makes any difference.)

Then run the command ant run &. In a minute or so you should see the IDE appear.

I problem I have at this point is that, although the IDE runs, you are not able to compile sketches, because the executables in the avr-gcc toolchain are looking for linker & glibc stuff in the wrong place on your system. I fix this by running the following script after the IDE starts, which I have saved in the file ~/Scripts/arduino-patchelf.sh:

GLIBC=/gnu/store/fa6wj5bxkj5ll1d7292a70knmyl7a0cr-glibc-2.31/lib/ld-linux-x86-64.so.2
RPATH=/gnu/store/fa6wj5bxkj5ll1d7292a70knmyl7a0cr-glibc-2.31/lib/
BUILD_DIR=/home/christopher/Repos/Arduino/build

patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/../libexec/gcc/avr/7.3.0/cc1plus
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/avr-g++
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/tools-builder/ctags/5.8-arduino11/ctags
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/../lib/gcc/avr/7.3.0/../../../../avr/bin/as
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/avr-gcc
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/../libexec/gcc/avr/7.3.0/cc1
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/avr-gcc-ar
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/../lib/gcc/avr/7.3.0/../../../../avr/bin/ar
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/../libexec/gcc/avr/7.3.0/collect2
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/../lib/gcc/avr/7.3.0/../../../../avr/bin/ld
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/../libexec/gcc/avr/7.3.0/lto-wrapper
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/../lib/gcc/../../libexec/gcc/avr/7.3.0/lto1
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/avr-objcopy
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/avrdude
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/avr-size

You will need to adjust the variables on top according to the location of things on your system. Unfortunately, it is necessary to run this script every time you call ant run, or at least I haven’t figured out a way to get around that. I’ve been told it is possible instead to just set a symbolic link from the “standard” location glibc location to the actual location, but I didn’t want to do this for fear that there might be some effect on the purity of my other build environments.

Hopefully somebody will put together a Guix package soon, but this is a workaround in the meantime.

AVR ISP Shield

I’m not getting paid to say this, but I bought this ISP Shield for Arduino and found it to be convenient:

DIYMORE AVR ISP Shield attached to an UNO, with chip loaded.

This setup is the same as programming using two Arduino boards and the Arduino ISP sketch, but a more compact and convenient, since you don’t have to figure out where the wires go, and you can clip the chip into the ZIF socket.

I like this better than the other programmers I have used, at least for burning 328P chips. To use it, you must (one time) load the Arduino as an ISP sketch onto the 328P chip, and then afterwards attach the shield. When burning chips with avrdude, use the stk500v1 programmer type.

Shield disconnected from UNO

ff-ad9833 Repo

codeberg repository for ad9833-related FlashForth code

For my on-going exploration of ad9833 audio generation using FlashForth 5, a code repository is now available at codeberg:

https://codeberg.org/infrared/ff-ad9833

So far, I have a demo-pitches word that plays c4, e4, g4, and c5 frequencies, but I can set other frequencies ranging from a4 to g#6, using the words I have so far. There is no system yet for setting duration, so I can’t play notes proper. But it was fun setting up a system for setting the equal temperament pitches.

In microcontroller programming, it is much easier to justify efforts to save memory. I needed to store the precalculated frequency register data values for each pitch. Originally I had a table like so:

$5274 , $4000 ,
$538d , $4000 , 
$54b7 , $4000 ,
$55f2 , $4000 ,
...
$4b5a , $4002 ,

With each line (two 16 bits words) representing one pitch. However, the first two bits in each 16-bit word are actually not frequency data, but register addressing bits, which can easily be added in later. Also, the second 16-bit word in each pair has (in my application) only two bits of actual frequency data, which are the two right most bits. So, I cut the table memory usage in half by packing those two bits into the left-most two bits of the first word in each pair:

\ packaged freq register data for equal temp
\ pitches from A4, A#4, B4 , ... , G#6
\ format numbered from lsb to msb:
\ 0-13: the 14 LSBs of the lsb register load
\ 14-15: the 2 LSBs of the msb register load

create packed-pitches
$1274 , $138d ,
$14b7 , $15f2 ,
$1740 , $18a2 ,
$1a19 , $1ba7 ,
...

Now each line in the table is actually two separate pitches. Then I just need a few words to separate the bits back out into separate words, and recombine them with the frequency register addressing bits:

0  constant na
1  constant na#
2  constant nb
3  constant nc
4  constant nc#
5  constant nd
6  constant nd#
7  constant ne
8  constant nf
9  constant nf#
10 constant ng
11 constant ng#

0 constant o4
1 constant o5
2 constant o6

: pull-pitch ( note octave -- u ) 12 * + cells packed-pitches + @ ;

: pull-14lsb %0011111111111111 and ;

: pull-2msb %1100000000000000 and 14 rshift ;

%0100000000000000 constant FREG0

: tx-pitch ( note octave -- )
    pull-pitch cp>r pull-14lsb FREG0 or 2tx-spi
    r> pull-2msb FREG0 or 2tx-spi ;

In testing, I have some trouble with some pitches getting distorted when I set the volume to higher levels. I suspect the problem is that I am still using the USB power supply and need to feed in my +5V from an external PS. I plan to try that next week, God willing.

Audio Circuit: Single Frequency Output Selection

Audio Circuit Driven by Op Amp, GY-9833 frequency synthesizer, and Arduino

Above is the circuit I mentioned earlier had been intending to design with a small 3W speaker driven by an LM386 op amp driven by an AD9833 frequency synthesizer chip, driven by SPI (sourced in the schematic from an Arduino Uno).

I thought designing and testing this simple circuit would only take an hour or two. But I got hung up for a lot of hours because, in the breadboard, I was getting weird spurious signals in the output when I had the the circuit set to certain volume levels, and I couldn’t figure out what the problem was. In the end, the problem was fixed by putting a large capacitor across +5V and AGND. After that, this output sounded pure and pleasant, testing with 1000Hz, 1500Hz, and 2000Hz signals. I do not know if it is really necessary to use a capacitor quite that big, but I didn’t feel like doing additional testing.

I had thoughts to turn the circuit into a PCB, though it would be through-hole (easier to assemble) and not a miniature surface-mount design like would be seen in a commercial application. This would be around 6cm x 5cm, with the speaker plugging in on the right pins and the Arduino plugging in on the left header. The GY-9833 module would slide onto the center pins and could be soldered on to them.

I can provide design files later after I finish laying out the traces. I can also post some FlashForth code later.