If you just want to make your board working, you should use the released software, please go back to the main PiLocoBuffer page
You are at the right place if you want to know how to build the firmware running on the ATmega328PB on the PiLocoBuffer board yourself.
In order to build the firmware, download the contents of subversion folder plus the sub folder, start Atmel Studio, load the project file and hit compile. Ready. You will have a hex file that is based on the C sources and on an include file in the sub folder which is an intermediate file in the overall build process, but checked into the subversion for convenience. I started using Atmel Studio for this project, because I needed the integrated debugger together with an AVR-Dragon.
There is also a makefile
in order to build the firmware without Atmel Studio. This is known
to work on Windows using MSYS2 with avr-gcc (8.4.0) and toolchain
installed. It also works on a Raspberry Pi with Raspberry Pi OS installed. See comments
at start of file for targets to use.
The above two methods build the software running on the AVR. But the software also includes
the ID EEPROM image. The rest of the page focuses on building that and how this integrates
with the rest of the firmware. The target ideeprom
of the makefile does the full process
of building the ID EEPROM image but will only run on the Raspberry Pi itself. Just run make ideeprom all
.
The specification of a HAT (“Hardware Attached on Top”) requires an “ID EEPROM” that gives the Rhaspberry Pi OS information about the HAT. Normally this “ID EEPROM” is supposed to be a simple EEPROM of a few kilo bytes that is connected over two I2C wires that only exist on the GPIO header for the purpose of connecting the ID EEPROM.
The information stored contains
I decided that instead of programming two devices (AVR and ID EEPROM) individually, it would be cool to program only the AVR and let the software emulate the EEPROM device. First idea was to store the ID EEPROM data in the EEPROM of the AVR device. That turned out to be not feasible, because the data is about 1600 bytes and that does not fit into the 1kB of the ATmega328PB. I now store the data together with the software in the flash memory of the AVR.
WTF? Okay here is the theory: There is a beast that is called “Device Tree”. This is an abstract representation of the hardware. You loaded your Rhaspberry Pi OS onto your SD card. Now that card comes with a device tree file for every known Rhaspberry Pi variant. The boot loader now chooses the right device tree depending what RasPi variant it detects to be running on today.
This device tree describes the RasPi, not the HAT. In order to also describe the HAT, we need to patch that device tree. This is called “loading a device tree overlay”. The proper device tree overlay contains information about the LCD and the shutdown button. At the beginning of the boot process, RasPi reads the ID EEPROM over IIC. If it finds a device tree overlay it applies it to the previously mentioned device tree loaded for the RasPi variant. This combined device tree is than passed over to the Linux kernel for booting.
The Linux kernel now loads the proper drivers for the hardware described in the device tree - including our beloved LCD and shutdown button. That’s why Linux is capable of displaying the kernel version during boot on our LCD and react on a press on the shutdown button without any modifcation of the SD card.
On the left side you see the input files, intermediate files and tools used. On the right side is mentioned where you get the tools from.
pilocobuffer.dts |
|||
↓ | |||
[Device Tree Compiler] | sudo apt install dts |
||
↓ | |||
pilocobuffer.dtbo |
eeprom_settings.txt |
||
↘ | ↙ | ||
[eepmake tool] | download and install from here | ||
↓ | |||
with_overlays.eep |
|||
↓ | |||
[srec_cat tool] | sudo apt install srecord |
||
↓ | |||
with_overlays.inc |
|||
↓ | |||
TwiEeprom.c |
other *.c | ||
↘ | ↙ | ||
[GCC compiler] | see below | ||
↓ | |||
*.o |
|||
↓ | |||
[GCC linker] | see below | ||
↓ | |||
PiLocoBuffer.elf |
|||
↓ | |||
[avr-objcopy] | see below | ||
↓ | |||
PiLocoBuffer.hex |
AVR-GCC and avr-objcopy could be installed on a Linux system - or in my case up to now come with the installer of Atmel Studio.
Starting from here, I ran the build on Rhaspberry Pi OS “raspios-bullseye”.
The file
pilocobuffer.dts
contains three device tree overlays. They are robbed from two DTS files that are normal part of a linux system:
These links are to a dedicated version of the files. I did not find where the master copy resides…
I copied the contents of the above mentioned standart DTS, but the __overrides__
part is deleted.
For the shutdown button we live with the defaults. For the LCD I put the used GPIOs directly into
the fragments.
This device tree source is read by the device tree compiler.
The DTC writes a “flattened” binary representation of the overlays into intermediate file pilocobuffer.dtbo
.
Another source file is
eeprom_settings.txt
.
It contains some identifying strings like how the HAT is named and who built it. Also the initial
state of the GPIO lines can be set. I could not make this to work…
Next step is that the tool eepmake
reads the intermediate pilocobuffer.dtbo
and the eeprom_settings.txt
and generates the ID EEPROM image with_overlays.eep
. The concept of the HAT specification is to write
this into a dedicated EEPROM device.
Instead we are using the srec_cat
tool
to generate an ANSI C include file with an array declaration that contains the data of the EEPROM image.
The generated include file with_overlays.inc
is an intermediate file in the overall build process, but still is checked into subversion in order to
support building the firmware without the tricky part above.
This is the last step done by the Makefile
in the ID-EEPROM subfolder.
After this, the makefile of the firmware as generated by Atmel Studio 7.0.2594 takes over.
The above mentioned include file is
included by TwiEeprom.c
There is one complication that deserves being mentioned: The IIC interface of the Rhaspberry Pi does not support clock stretching. Clock stretching is a perfectly legal way for an IIC system. If a slave device needs more time, it holds the SCL line low. The master has to detect this and wait. RasPi not implementing it is a known bug.
The TWI subsystem of an AVR uses clock stretching whenever the firmware is not fast enough. You can see garbled pulses on the SCL line when talking to RasPi. In order to make this work, we did two thinks: firstly we run the AVR as fast as possible, which is 12MHz. Secondly the TWI only enters the ISR once. For the first time entering ISR surprisingly there is some interrupt latency forgiven. Than the ISR loops until no more activity is seen on the TWI device.
The firmware consists of three C files:
TwiEeprom.c
emulates the ID EEPROM by giving RasPi read access to the array build abovemain.c
contains handling of the UART that talks to RasPi and copies LocoNet messages between LN and RasPiLed.c
shows the state and flashes LEDs for LN trafficThese are compiled and linked with GCC and than converted to a hex file. The hex file gets distributed as software release. User needs to download this with avrdude into the AVR.