<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Gianluca Pacchiella (Posts about arduino)</title><link>https://ktln2.org/</link><description></description><atom:link href="https://ktln2.org/categories/arduino.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2025 &lt;a href="mailto:gp@ktln2.org"&gt;Gianluca Pacchiella&lt;/a&gt; </copyright><lastBuildDate>Wed, 31 Dec 2025 10:36:33 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Reusing old shit: laptop keyboard</title><link>https://ktln2.org/reusing-old-keyboard/</link><dc:creator>Gianluca Pacchiella</dc:creator><description>&lt;div&gt;&lt;p&gt;Here we are with another experiment in reusing otherwise trash-destined
electronics material; in this episode we are going to refurbish a keyboard,
from the recovering of the internal "matrix" to the design of the PCB destined
as the controller board, to finally reworking of an existing firmware to create
a new USB keyboard.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://ktln2.org/reusing-old-keyboard/"&gt;Read more…&lt;/a&gt; (9 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><category>arduino</category><category>AVR</category><category>keyboard</category><category>WIP</category><guid>https://ktln2.org/reusing-old-keyboard/</guid><pubDate>Fri, 02 Jul 2021 00:00:00 GMT</pubDate></item><item><title>Installing bootloader into ATMega328p</title><link>https://ktln2.org/2017/06/27/installing-bootloader-into-atmega328/</link><dc:creator>Gianluca Pacchiella</dc:creator><description>&lt;p&gt;This is a standard thing to do with an &lt;strong&gt;ATMega328p&lt;/strong&gt;, the core of
the Arduino development board: burn a bootloader into it and then
use a &lt;code&gt;UART&lt;/code&gt; over &lt;code&gt;USB&lt;/code&gt; connection to flash code into it.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://ktln2.org/images/atmega328p.png"&gt;&lt;/p&gt;
&lt;p&gt;There a lot of posts about this procedure, but are scattered
all over the internet, without precise schematics and
the &lt;em&gt;low level&lt;/em&gt; stuffs.&lt;/p&gt;
&lt;p&gt;In particular I want to install a bootloader into a pristine
chip: its default configuration  is different with respect to a
standard Arduino setup, it works without external crystal and with a prescaler of 8 (i.e.
the chip is running at 1MHz). These conditions are problematic
if you want your bootloader to work with the correct baud rate.&lt;/p&gt;
&lt;p&gt;What follow is intended as notes to use as quick reminder to myself with a
little explanation of what's going on.&lt;/p&gt;
&lt;h3&gt;What's an ATMega?&lt;/h3&gt;
&lt;p&gt;First of all the ATMega328p is a microcontroller of the family &lt;strong&gt;ATMega&lt;/strong&gt; (O 'RLY); there are a lot
of chips in this family, with different features but take into account that it's not the only
family (Wikipedia has a &lt;a href="https://en.wikipedia.org/wiki/Atmel_AVR#Basic_families"&gt;list&lt;/a&gt; of these
families).&lt;/p&gt;
&lt;p&gt;All of them are &lt;code&gt;AVR&lt;/code&gt; chips, implementing an &lt;strong&gt;Harvard architecture&lt;/strong&gt;
i.e. the memory addresses for &lt;code&gt;RAM&lt;/code&gt; and executable code are separated: in
particular the flash (where the code you write will live after the uploading),
technically named &lt;strong&gt;program memory&lt;/strong&gt;, it's divided in two sections&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Boot loader section located in the upper part of the program memory&lt;/li&gt;
&lt;li&gt;Application program section located at the start of the program memory&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The important fact is that the start of the bootloader part is not fixed but can be configured.&lt;/p&gt;
&lt;p&gt;The ATMega328p is pretty famous because is the microcontroller used
with the &lt;a href="https://www.arduino.cc/en/Main/ArduinoBoardUno"&gt;Arduino&lt;/a&gt;: it has
28 pins, 23 of which are GPIO and 6 of which are for a 10 bit ADC.&lt;/p&gt;
&lt;p&gt;For more informations read the &lt;a href="http://www.atmel.com/images/doc8161.pdf"&gt;datasheet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I want to replicate with a breadbord the development workflow of an Arduino:
flash a new program into the Application program section after connecting via
a serial connection to the bootloader.&lt;/p&gt;
&lt;p&gt;A thing to note here is that the bootloader is not always running
(there is not an OS into the microcontroller, the system is &lt;em&gt;real time&lt;/em&gt;), so in order
to access the bootloader you have to reset the board and the bootloader must start
after the reset.&lt;/p&gt;
&lt;p&gt;Let see how to configurate the microcontroller and connect the components
on the breadboard.&lt;/p&gt;
&lt;h4&gt;Fuses&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Fuses&lt;/strong&gt; are special one byte registers that contains persistent configuration values
used to tell the microcontroller howto behave; in this case I need the following settings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the dimension for the boot section to be 256 words (in the  &lt;code&gt;AVR&lt;/code&gt; world &lt;code&gt;words&lt;/code&gt; are 16 bit values); moreover the boot address will be &lt;code&gt;0x3F00&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;when reset the microcontroller must start at the boot address (technically speaking we need to configure the &lt;strong&gt;reset vector&lt;/strong&gt; address)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is a configuration regarding the clock that I don't need to change
since is the value that is different from a standard Arduino setup: the table below
show the default fuses for a pristine chip and for an Arduino Uno:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Low&lt;/th&gt;
&lt;th&gt;High&lt;/th&gt;
&lt;th&gt;Extended&lt;/th&gt;
&lt;th&gt;Clock frequency&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ATMega328&lt;/td&gt;
&lt;td&gt;0x62&lt;/td&gt;
&lt;td&gt;0xd9&lt;/td&gt;
&lt;td&gt;0xff&lt;/td&gt;
&lt;td&gt;1MHz&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Arduino Uno&lt;/td&gt;
&lt;td&gt;0xff&lt;/td&gt;
&lt;td&gt;0xde&lt;/td&gt;
&lt;td&gt;0x05&lt;/td&gt;
&lt;td&gt;16MHz&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each fuse comprehends a set of single bit values as showed
in the following table (more informations can be found in
the section &lt;code&gt;Memory Programming&lt;/code&gt; of the datasheet)&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Extended&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;BODLEVEL2&lt;/td&gt;
&lt;td&gt;BODLEVEL1&lt;/td&gt;
&lt;td&gt;BODLEVEL0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;High&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;RSTDISBL&lt;/td&gt;
&lt;td&gt;DWEN&lt;/td&gt;
&lt;td&gt;SPIEN&lt;/td&gt;
&lt;td&gt;WDTON&lt;/td&gt;
&lt;td&gt;EESAVE&lt;/td&gt;
&lt;td&gt;BOOTSZ1&lt;/td&gt;
&lt;td&gt;BOOTSZ0&lt;/td&gt;
&lt;td&gt;BOOTRST&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Low&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CKDIV8&lt;/td&gt;
&lt;td&gt;CKOUT&lt;/td&gt;
&lt;td&gt;SUT1&lt;/td&gt;
&lt;td&gt;SUT0&lt;/td&gt;
&lt;td&gt;CKSEL3&lt;/td&gt;
&lt;td&gt;CKSEL2&lt;/td&gt;
&lt;td&gt;CKSEL1&lt;/td&gt;
&lt;td&gt;CKSEL0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The most significant bits are the left ones.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; fuses are weird, each bit is a boolean but programmed is assigned
to 0 and unprogrammed to 1 and moreover some bits of extended fuses are undefined
so some programmers fail to validate because returns the wrong (but equivalent) value:
for example for the extended fuse: &lt;code&gt;0xFD&lt;/code&gt; is equivalent to &lt;code&gt;0x05&lt;/code&gt; (only bottom 3 bits are significant, and 
Avrdude complains if the top bits are nonzero).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It's important to be sure what values you are modifing since in some cases
it's possible to brick a microcontroller.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In my case I need only to change the bootloader section size and
the boot reset vector so a value of &lt;code&gt;0xDE&lt;/code&gt; for the high fuse will do
the job. And that is the only fuse that is &lt;strong&gt;necessary&lt;/strong&gt; in order to
make the bootloader work.&lt;/p&gt;
&lt;p&gt;Now I can set the high fuse with the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ avrdude  -c buspirate -p atmega328p -P /dev/ttyUSB0 -U hfuse:w:0xDE:m
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By the way for a more direct calculation of the fuses you can use this &lt;a href="http://www.engbedded.com/fusecalc/"&gt;page&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Optiboot&lt;/h3&gt;
&lt;p&gt;This is a common bootloader that can be used with the Arduino IDE
(the page for the standard Arduino bootloader is &lt;a href="https://www.arduino.cc/en/Hacking/Bootloader"&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Normally you can download a precompiled version but in my situation
I need to recompile it to fit my setup. Before to compile we need to download the source code&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git clone https://github.com/optiboot/optiboot &amp;amp;&amp;amp; cd optiboot
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then enter into the directory containing the source code&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ cd optiboot/bootloaders/optiboot/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If your system is configured for autocompletion a &lt;code&gt;make &amp;lt;TAB&amp;gt;&amp;lt;TAB&amp;gt;&lt;/code&gt; should show you all the
available targets&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;atmega1280             atmega168p             atmega32_isp           attiny84               FORCE                  luminet                pro16_isp              virboot328             wildfirev3_isp
atmega1284             atmega168p_isp         atmega644p             baudcheck              isp                    luminet_isp            pro20                  virboot328_isp         xplained168pb
atmega1284_isp         atmega32               atmega8                bobuino                isp-stk500             mega1280               pro20_isp              virboot8               xplained328p
atmega1284p            atmega328              atmega88               bobuino_isp            lilypad                mega1280_isp           pro8                   wildfire               xplained328pb
atmega16               atmega328_isp          atmega88_isp           clean                  lilypad_isp            mighty1284             pro8_isp               wildfirev2             
atmega168              atmega328_pro8         atmega88p_isp          diecimila              lilypad_resonator      mighty1284_isp         sanguino               wildfirev2_isp         
atmega168_isp          atmega328_pro8_isp     atmega8_isp            diecimila_isp          lilypad_resonator_isp  pro16                  sanguino_isp           wildfirev3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before to finally compile it I have to indicate that my setup doesn't include an external
crystal, i.e. the clock frequency is 1MHz; bad enough this cause a problem with the default &lt;code&gt;UART&lt;/code&gt; baud rate: given a frequency not all
the baud rates are possible because of sampling errors, so if we launch the compilation
with the custom frequency but without changing the default baud rate (115200) the process fails&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ make atmega328 AVR_FREQ=1000000L
avr-gcc (GCC) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

BAUD RATE CHECK: Desired: 115200, Real: 125000, UBRRL = 0, Error=8.5%
avr-gcc -g -Wall -Os -fno-split-wide-types -mrelax -mmcu=atmega328p -DF_CPU=1000000L  -DBAUD_RATE=115200 -DLED_START_FLASHES=3        -c -o optiboot.o optiboot.c
optiboot.c:303:6: error: #error BAUD_RATE error greater than 5%
     #error BAUD_RATE error greater than 5%
      ^
optiboot.c:314:2: error: #error Unachievable baud rate (too fast) BAUD_RATE
 #error Unachievable baud rate (too fast) BAUD_RATE 
  ^
&amp;lt;incorporato&amp;gt;: set di istruzioni per l'obiettivo "optiboot.o" non riuscito
make: *** [optiboot.o] Errore 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;AVR_FREQ&lt;/code&gt; value is &lt;strong&gt;super important&lt;/strong&gt;: it tells what frequency the microcontroller
runs at, if this is wrong all the timing-related functionalities are not gonna to work.&lt;/p&gt;
&lt;p&gt;Luckily we can configure the correct value for the baud rate using &lt;code&gt;BAUD_RATE&lt;/code&gt; (in this case I use the minimal value that
I can come up with)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ make atmega328 BAUD_RATE=9600 AVR_FREQ=1000000L
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I should have used the &lt;code&gt;atmega328_isp&lt;/code&gt; target but the weird behaviour for the
extended fuses causes the &lt;code&gt;ISP&lt;/code&gt; to fail when it tries to validate the changed fuse since
some bits are undefined and if the programmer writes this as 1 is possible that reads back
zero when verifies it, making the process fail.&lt;/p&gt;
&lt;p&gt;By the way, if you want to use the &lt;a href="http://dangerousprototypes.com/docs/Bus_Pirate"&gt;bus pirate&lt;/a&gt; as &lt;code&gt;ISP&lt;/code&gt; programmer 
it's possible to call directly the &lt;code&gt;_isp&lt;/code&gt; target like indicated below&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ make atmega328_isp BAUD_RATE=9600 AVR_FREQ=1000000L ISPTOOL=buspirate ISPPORT=/dev/ttyUSB0 ISPSPEED=-b115200
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By the way, I flashed it with &lt;code&gt;avrdude&lt;/code&gt; directly in a separate step&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ avrdude -c buspirate -p m328p -P /dev/ttyUSB0 -U flash:w:optiboot_atmega328.hex
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Breadboard&lt;/h3&gt;
&lt;p&gt;The schematics used to place the components on the breadboard is the following&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://ktln2.org/images/bootloader.png"&gt;&lt;/p&gt;
&lt;p&gt;Two connectors are initialy needed: the &lt;code&gt;ISP&lt;/code&gt; to flash
the bootloader and the &lt;code&gt;UART&lt;/code&gt; to communicate with the bootloader.
The first can be removed once the bootloader is in place and works ok.&lt;/p&gt;
&lt;p&gt;Personally I created a &lt;a href="https://github.com/gipi/AVR-experiments/tree/master/stuffs/ATMegaProgrammer"&gt;breakout&lt;/a&gt; that exposes the 6 &lt;code&gt;ISP&lt;/code&gt; related pins
and then flash using some &lt;a href="https://www.tindie.com/products/FemtoCow/pogo-pin-icsp-spi-programmer-adapter/"&gt;pogo pins&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The thing important to note is the connection between &lt;code&gt;DTR&lt;/code&gt; and &lt;code&gt;RESET&lt;/code&gt; that
allows the board to be reset when uploading the code and
in particular the capacitor between them:
without it the chip won't reset and won't enter the bootloader. I don't
understand why: someone says that "&lt;a href="http://forum.arduino.cc/index.php?topic=26877.0"&gt;the level on this signal line changes when
the serial bridge is connected (enabled in software).
However on the reset you only want a pulse. The capacitor acts as
a differentiator&lt;/a&gt;".&lt;/p&gt;
&lt;p&gt;Also important are the values: experimentally I found that a resistor
of 10K and a capacitor of 0.1uF work well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Also remember to place a big capacitor between power rails in order to
make the system more stable: if you are experiencing random resets or odd
behaviours probably the chip suffers from an unstable power line.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Programming&lt;/h3&gt;
&lt;p&gt;Now it's time to try to flash some application using the bootloader:
&lt;code&gt;Optiboot&lt;/code&gt; declares that uses the &lt;a href="https://github.com/Optiboot/optiboot/wiki/HowOptibootWorks"&gt;stk500v1&lt;/a&gt; protocol
corresponding to the &lt;code&gt;arduino&lt;/code&gt; programmer type (flag &lt;code&gt;-c&lt;/code&gt; of &lt;code&gt;avrdude&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;First of all I'll try to comunicate with the board&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ avrdude -c arduino -p m328p -P /dev/ttyUSB0 -b 9600
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If all is ok we can try to write a minimal snippet of code that toggle the logic level
of pin &lt;code&gt;PB5&lt;/code&gt; (save it in a file named &lt;code&gt;main.c&lt;/code&gt;)&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-c"&gt;#include &amp;lt;avr/io.h&amp;gt;
#include &amp;lt;util/delay.h&amp;gt;

#define BLINK_DELAY_MS 1000

int main() {
 /* set pin 5 of PORTB for output*/
 DDRB |= _BV(DDB5);

 while(1) {
  /* set pin 5 high to turn led on */
  PORTB |= _BV(PORTB5);
  _delay_ms(BLINK_DELAY_MS);

  /* set pin 5 low to turn led off */
  PORTB &amp;amp;= ~_BV(PORTB5);
  _delay_ms(BLINK_DELAY_MS);
 }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is also very good to check that the clock is
set correctly and we haven't screw up the fuses.&lt;/p&gt;
&lt;p&gt;We can use the Arduino build system to save time : create a file named
&lt;code&gt;Makefile&lt;/code&gt; and place in the same directory as &lt;code&gt;main.c&lt;/code&gt; with the
following content:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-Makefile"&gt;BOARD_TAG    = uno
F_CPU        = 1000000L
MONITOR_PORT = /dev/ttyUSB0

AVRDUDE_ARD_BAUDRATE   = 9600

include /usr/share/arduino/Arduino.mk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now it's possible to compile and upload with the simple command&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ make -C source_dir/ upload
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;NB:&lt;/strong&gt; the Arduino build system is installable in a Debian-like system
with the package &lt;code&gt;arduino-mk&lt;/code&gt;.&lt;/p&gt;</description><category>arduino</category><category>atmega</category><category>breadboard</category><category>electronics</category><category>optiboot</category><guid>https://ktln2.org/2017/06/27/installing-bootloader-into-atmega328/</guid><pubDate>Tue, 27 Jun 2017 00:00:00 GMT</pubDate></item></channel></rss>