CKOUT: 328P as clock source

Left: Nano serving as fuse bit programmer. Middle: Uno with 328P CKOUT fuse bit programmed. Right, 16Mhz signal coming out of pin 8 (PB0) of Uno.

Wanting to work with an AD9833 signal generator chip, which needs an external master clock source, I was wondering if I could somehow tap into the 16 Mhz clock already feeding the 328P. The answer was yes, it is possible on the 328P to feed this to pin PB0 (a.k.a., digital pin 8).

328P datasheet: Clock Output Buffer

The only tricky part is you have to program a fuse bit on the chip, which can not be done through self-programming, the way you normally upload code through the arduino bootloader. You need to set bit 6 (CKOUT) in the lfuse byte to 0:

So, you have to have a separate programmer, and also you must write the whole byte, meaning you want to be careful to preserve the other bit settings. Fortunately, through the ArduinoISP sketch, you can use another Arduino to program it.

https://www.arduino.cc/en/Tutorial/BuiltInExamples/ArduinoISP/

This is fairly straightforward to wire up. However, somebody on #arduino IRC had to explain to me that it is necessary to put a 60 Ohm resistor across VCC and rst pins on the programmer, if using an Uno or Nano for the programmer. I didn’t catch that reading the tutorial.

Once wired up, you can use avrdude to write the lfuse byte. In my case.

avrdude -c stk500v1 -p m328p -P /dev/ttyUSB0 -b 19200 -U lfuse:w:0xBF:m

The last part of the command instructs avrdude to write byte 0xBF to the lfuse byte. A few things that might not be obvious about that: (1) in 328P fuse bytes, a “0” is considered the “programmed” state, the opposite of what you would intuitively expect; (2) I had to look at the boards.txt file in the arduino ide could to figure out that the “standard” byte value (for an MC used on an Arduino Uno board) is 0xFF. So, if I’m just changing bit 6 to zero, 0xFF needs to become 0xBF.

Screen photo of writing 0xBF to lfuse using avrdude

The fuse change was successful, and I was able to measure 16 Mhz out of PB0 (normally digital pin 8).

Forth SPI on Arduino

One byte (0xa6) transmitted from master out SPI pin using Forth

Arduino-FVM comes with only a few Arduino-function words, basically just a few for working with the digital pins. So the test for Forth was going to be: how difficult is it to access other microchip functionality using memory reads and writes? An encouraging first step was to implement SPI TX, using the information in the 328 datasheet.

C Code Example from 328 datasheet of SPI Master TX

First I needed some constants for the register addresses and bit numbers:

0x24 constant DDR_SPI
0x3 constant DD_MOSI
0x5 constant DD_SCK
0x2 constant DD_SS
0x4c constant SPCR
0x6 constant SPE
0x4 constant MSTR
0x0 constant SPR0
0x4e constant SPDR
0x4d constant SPSR
0x7 constant SPIF

Next I needed to set up the data direction bits for the MOSI, SCK, and SS pins, as well as set some bits in the SPCR register to control mode and communication frequency:

: setup-master-spi ( -- )
1 DD_MOSI lshift
1 DD_SCK lshift
1 DD_SS lshift
or or
DDR_SPI c!
1 SPE lshift
1 MSTR lshift
1 SPR0 lshift
or or
SPCR c!
;

And here is a function for transmitting a single byte, after dropping the byte on the stack:

: tx-master ( ch -- )
SPDR c!
begin
SPSR c@ 1 SPIF lshift and
until
;

And here is a demo procedure for sending byte 0xA6 repeatedly:

: spi-demo
setup-master-spi
begin
0xa6
tx-master
again
;

Now we can see that byte on the oscilloscope, from MOSI pin 11:

SPI signal for byte 0xA6

Byte 0xA6 equals 10100110, which you can understand from the signal image if you know that (1) signal low represents “1” and high represents “0”; (2) the X-scale is 2 microseconds, with one bit per microsecond; and (3) the first bit is the one microsecond of low signal just to the left of the Y axis.

Arduino FORTH: Register Access

Edit after more research: the approach below might not be best possible approach when working with GPIO pins, as it might not be taking advantage of special opcodes for this purpose. Also, due to the two byte FVM cell size, I think there might be some potential for strange effects in nearby registers of a different type (like, the PINC register being after the PORTB register). Heading back to the data sheets…

Edit 2: It looks like FORTH (including Arduino-FVM) has the C@ and C! commands which are single-byte (char) versions of @ and !.

The Atmel specific keywords that come with Arduino-FVM are rather limited – basically just PINMODE, DIGITALREAD, and DIGITALWRITE. So, to do much of interest you would want to start playing around with the atmel microprocessor registers. This is mostly straightforward, however, as the registers are accessible simply as locations in ram, meaning you just write or read bits to ram to get what you want. Doing this in FORTH, you need a few tools

  • @ word: read from a memory location
  • ! word: write to a memory location
  • HEX word: switch to hexidecimal interpretation of the stack input/output (DECIMAL to switch back).
  • Pinout for your arduino board (available on the internet)
  • Data sheet for your specific microcontroller (available on the internet)

Here is a quick example of lighting up the LED through a register write. First, we need to know our pin number and also which register we are dealing with, available from the pinout.

Arduino Nano Pinout

There we have pin number 13 (decimal) for the LED, and register PB5. First, to keep this post a bit shorter, we we simply use the PINMODE keyword to set pin 13 to output mode:

true 13 pinmode

Now we look at the datasheet to get the memory location for register PB5.

A page from 328P Datasheet

So, PORTB register is at 0x25 (hex) and bit five is what we want. Now, let’s see what is already in that memory location. On my chip, I got:

hex
0x25 @ . 0

Just keep in mind however, as you can see using the CELL command, that you have actually read in two bytes. So, if you get something like 0x2000, you are only interested in the first byte (the right-most 00).

As a general practice, I only want to write to the bit of interest, preserving other bit states. So, I drop a 1 for that bit on the stack, and use an OR to light up just that bit. A 1 in bit 5 is hex 0x20.

0x25 @ 0x20 or 0x25 ! 

And the LED lights up. We can see now what we have in register memory:

0x25 @ . 20

That is a trivial example, but I think you would need to go into this memory “peeking” and “poking” in order to do more advanced things like control the interrupt system or special purpose pins. At least, I find the idea more appealing than having to write C interface functions on the backend. Of course, you would want to hide the details inside nice forth functions.

Learning FORTH on Arduino

Some output from Nano running FORTH (no command echo)

FORTH is interesting as a language not as ugly and boring as C, yet more lightweight than lisp. For the uno (328PU) ulisp requires 97% of the program store space, and 74% of your dynamic memory, while Arduino-FVM needs 36% of program storage space and 69% of dynamic memory. There is more for me to explore as far as space efficiency goes, but anyway I’m giving FORTH a try.

There are a few different FORTH implementations for Arduino – I was looking for the easiest path to get set-up. I landed on Arduino-FVM simply because it was the first one I found that was an Arduino sketch/library which I load quickly without having to learn anything new about how to upload to the 328. I just had to install the FVM library, and then compile a sketch which gives me the actual interpreter to load on the microcontroller.

https://github.com/mikaelpatel/Arduino-FVM

You can’t really learn the fundamentals of FORTH programming from just looking at Arduino-FVM documentation; so I installed gforth on my Guix desktop computer and used the gforth info page that has nice reference material and an extensive tutorial. Then I looked at the Arduino-FVM source code, which documents the parameters for the arduino-specific words.

This one liner will blink the LED on and off:

: blink true 13 pinmode begin 500 delay 13 digitaltoggle again ; blink

For those total unfamiliar with FORTH, it is sort of like doing programming on a reverse polish notation calculator, but with a larger stack available.

Minimalist Arduino Board

Atmel 328PU microcontroller with minimal circuitry for 16Mhz operation

I wanted to get a feel for using the 328P without the arduino board, and practice soldering. I used this tutorial:

https://www.arduino.cc/en/Tutorial/BuiltInExamples/ArduinoToBreadboard/

16Mhz operation requires two capacitors, a quartz crystal, and a 10k resistor, as represented above. It is possible to cut down on the circuitry by using the internal 8Mhz oscillator, but I didn’t do that.

Up close view of top of minimalistic 328P board.

In my prototype, to supply power I simply clip 5V and GND leads onto the pads on the sides. The two wires coming out are the UART read and write lines (serial communication).

I plugged it into power and a USB-serial device (the TPE-USBSERIAL from ThinkPenguin) and to my surprise it worked the first time. I had already loaded ulisp on the microcontroller, and was able to run some lisp commands through the serial connection.

I was surprised it simply worked, mainly because of my frightening magnet-wire solder work.

Scary looking magnet wire mess on back of prototype board.

Methinks I might have to use a bigger board next time, or figure out a different approach.