loader: remove unneccesary parenthesis
loader: minor changes
loader: minor changes to usbopen()
This repository holds the sources for a Dactyl-shaped keyboard firmware, running on Teensy 2.0.
Have a look at https://www.pjrc.com/teensy/first_use.html.
On Gentoo, we have crossdev to help us out. To get an AVR cross-compiler toolchain, it's as simple as:
$ crossdev -t avr
It also turns out we need dev-libs/libusb-compat (for <usb.h>
).
$ emerge dev-libs/libusb-compat
There is a graphical utility for flashing the Teensy, but I much prefer a command-line tool, and luckily there is one we can just use: https://github.com/PaulStoffregen/teensy_loader_cli.
Building the tool requires the <usb.h>
header, but that should be
all that's needed to run make
successfully.
To flash the sample slow blinking program on the Teensy 2.0, plug it in, press the push button so the light stops blinking, then run:
$ ./teensy_loader_cli --mcu=TEENSY2 -v -w blink_slow_Teensy2.hex
That should be all there is to it.
The blinky program on the https://www.pjrc.com/teensy/gcc.html page (it's provided as a zip file) provides a larger program that blinks morse code.
With avr-gcc version 13, the blinky sources do not compile out of the
box. In usb_debug_only.c there is a collection of static global
variables that are meant to go in read-only memory (by the
__attribute__((progmem))
attribute). The error looks something like
this:
error: variable ‘xyz’ must be const in order to be put into read-only section by means of ‘__attribute__((progmem))’
Adding const
to these variables lets the program compile. The
default settings in the Makefile target Teensy 2.0 so no further
changes are necessary.
To flash blinky.hex onto our Teensy 2.0 do:
$ teensy_loader_cli --mcu=TEENSY2 -w -v blinky.hex
And off we go!
There's QMK and TMK firmware libraries to make firmware programming super-easy. QMK even has a keyboards/handwired/dactyl folder that can be used as a handy reference.
Why not use it? First of all, QMK seems big. It's a driver for making managing keyboard firmware (including layout) as painless as possible, but I want to experience the pain.
During setup, QMK requests a lot of additional tools that aren't really needed, and suggests downgrading avr-gcc from version 13 to 8.
If I was in the business of making lots of keyboards with many different boards I would probably consider it. But I'm not. And I want to get into the weeds of programming the firmware, including setting up the compilation and flashing pipeline.
The Teensy 2.0 board comes with this diagram:
The thing to understand about programming the board is that each pin is a member of a port. Each port can be viewed as a unsigned 8-bit number. Each port has three registers: PINx, DDRx, and PORTx, where x ∈ {B,C,D,E,F} is the port letter. The PINx register allows reading a specific pin (so it cannot be assigned to), the DDRx register is used to configure the direction (0=Input, 1=Ouput), and PORTx either sets the output low (0) or high (1) (when DDRx = 1) or configures the input (when DDRx = 0, 0=Normal, 1=Pullup Resistor)
Here is the full list of all registers on Teensy 2.0:
Port | PIN | DDR | PORT | Comment |
---|---|---|---|---|
B | 0x3 |
0x4 |
0x5 |
|
C | 0x6 |
0x7 |
0x8 |
Only C6 , C7 |
D | 0x9 |
0xA |
0xB |
|
E | 0xC |
0xD |
0xE |
Only E2 , E6 |
F | 0xF |
0x10 |
0x11 |
The LED is controlled on pin D6. From the blinky sources (and the documentation), we can control the LED by configuring D6 as an output pin, and set it high.
#include <avr/io.h>
DDRD |= (1<<6); // configure as output
PORTD &= (1<<6); // set high
DDRD and PORTD both expand to use the macro _SFR_IO8(). With
-mmcu=atmega32u4
the above expands to:
(*(volatile uint8_t *)((0xA + __SFR_OFFSET)) |= (1<<6);
(*(volatile uint8_t *)((0xB + __SFR_OFFSET)) |= (1<<6);
We can think of the registers as memory locations that can be read or
written to (simply by casting to volatile uint8_t *
and
dereferencing).
The __SFR_OFFSET is either 0x00 or 0x20 - for us it will always be 0x20.
Reference: https://www.pjrc.com/teensy/pins.html