<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:version="2.0"><channel><title>Naster17</title><description>Personal Blog | Portfolio</description><link>https://naster17.github.io/</link><language>en</language><item><title>Running linux on ESP32 with 4MB Flash</title><link>https://naster17.github.io/blog/linux-on-esp32/</link><guid isPermaLink="true">https://naster17.github.io/blog/linux-on-esp32/</guid><description>Today I&apos;m going to show you how to run Linux on ESP32 with just only 4MB flash memory</description><content:encoded>&lt;blockquote&gt;This rendering was automatically generated by Frosti Feed and may have formatting issues. For the best experience, please visit: &lt;a href=&quot;https://naster17.github.io/blog/linux-on-esp32/&quot;&gt;https://naster17.github.io/blog/linux-on-esp32/&lt;/a&gt;&lt;/blockquote&gt; &lt;h2&gt;Get Started&lt;/h2&gt;
&lt;p&gt;For a long time, no one has been surprised by running Linux on ESP with 8 and 16 MB of memory and RAM. So today we will talk about running Linux on a 4MB platform. And so straight to the point.&lt;br&gt;Download these packages:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;apt install autoconf automake bash bc bison build-essential cmake flex gawk git gperf help2man libncurses-dev libtool libtool-bin libusb-1.0-0 python3 python3-venv rsync texinfo unzip wget cpio
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Get dynconfig&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git clone https://github.com/jcmvbkbc/xtensa-dynconfig -b original
wget https://github.com/jcmvbkbc/xtensa-toolchain-build/raw/e46089b8418f27ecd895881f071aa192dd7f42b5/overlays/original/esp32.tar.gz
mkdir esp32 &amp;amp;&amp;amp; tar -xf esp32.tar.gz -C esp32
sed -i &amp;#39;s/\(XSHAL_ABI\s\+\)XTHAL_ABI_WINDOWED/\1XTHAL_ABI_CALL0/&amp;#39; esp32/{binutils,gcc}/xtensa-config.h
make -C xtensa-dynconfig ORIG=1 CONF_DIR=`pwd` esp32.so
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dont forget to set exports every new shell sessions or add to your shell config file&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;export XTENSA_GNU_CONFIG=`pwd`/xtensa-dynconfig/esp32.so
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Get Toolchain&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git clone https://github.com/jcmvbkbc/crosstool-NG.git -b xtensa-fdpic
cd crosstool-NG
./bootstrap &amp;amp;&amp;amp; ./configure --enable-local &amp;amp;&amp;amp; make
./ct-ng xtensa-esp32-linux-uclibcfdpic
CT_PREFIX=`pwd`/builds nice ./ct-ng build
cd ..
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can check your toolchain set in &lt;strong&gt;crosstool-NG/builds/xtensa-esp32-linux-uclibcfdpic/bin/&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Kernel and Rootfs&lt;/h2&gt;
&lt;p&gt;For pure ESP32 (4MB) we are using &lt;strong&gt;xtensa-2024.05-fdpic&lt;/strong&gt; version&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git clone https://github.com/jcmvbkbc/buildroot -b xtensa-2024.05-fdpic 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Time to create buildroot&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;make -C buildroot O=`pwd`/build-buildroot-esp32 esp32_defconfig
buildroot/utils/config --file build-buildroot-esp32/.config --set-str TOOLCHAIN_EXTERNAL_PATH `pwd`/crosstool-NG/builds/xtensa-esp32-linux-uclibcfdpic
buildroot/utils/config --file build-buildroot-esp32/.config --set-str TOOLCHAIN_EXTERNAL_PREFIX &amp;#39;$(ARCH)-esp32-linux-uclibcfdpic&amp;#39;
buildroot/utils/config --file build-buildroot-esp32/.config --set-str TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX &amp;#39;$(ARCH)-esp32-linux-uclibcfdpic&amp;#39;
nice make -C buildroot O=`pwd`/build-buildroot-esp32
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Bootloader&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git clone https://github.com/jcmvbkbc/esp-idf -b linux-5.1.2
pushd esp-idf
. ./export.sh
cd examples/get-started/linux_boot
idf.py set-target esp32
cp sdkconfig.defaults.esp32 sdkconfig
idf.py build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see the partitions table looks like:&lt;br&gt;&lt;img width=&quot;439&quot; height=&quot;182&quot; alt=&quot;image&quot; src=&quot;https://github.com/user-attachments/assets/7a6a450b-9571-4829-a888-637933f449de&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Flash&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;idf.py flash
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Final Flash&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;parttool.py -b 1000000 write_partition --partition-name linux  --input build-buildroot-esp32/images/xipImage
parttool.py -b 1000000 write_partition --partition-name rootfs --input build-buildroot-esp32/images/rootfs.cramfs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Connect (dont forget to add user in diagout group):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;apt install minicom
minicom -b 115200 -D /dev/ttyUSB0
&lt;/code&gt;&lt;/pre&gt;
&lt;img width=&quot;1216&quot; height=&quot;965&quot; alt=&quot;image&quot; src=&quot;https://github.com/user-attachments/assets/42ab79f7-c061-437a-b409-5a6d1662bd6b&quot; /&gt;

&lt;h2&gt;End&lt;/h2&gt;
&lt;p&gt;Thank you for reading this rather short article. I tried to describe everything to the point.&lt;br&gt;I also wanted to give a thank you to the author who ported Linux to the xtensa platform specialy ESP.&lt;br&gt;His github: &lt;a href=&quot;https://github.com/jcmvbkbc/&quot;&gt;https://github.com/jcmvbkbc/&lt;/a&gt;&lt;br&gt;His scripts to automate build: &lt;a href=&quot;https://github.com/jcmvbkbc/esp32-linux-build&quot;&gt;https://github.com/jcmvbkbc/esp32-linux-build&lt;/a&gt;&lt;/p&gt;
</content:encoded><dc:creator>Naster17</dc:creator><pubDate>Sun, 03 Aug 2025 00:00:00 GMT</pubDate></item><item><title>Deep dive into Arduino programming | From C++ to Assembly</title><link>https://naster17.github.io/blog/deep-dive-arduino/</link><guid isPermaLink="true">https://naster17.github.io/blog/deep-dive-arduino/</guid><description>Today we&apos;re going to dive into low-level programming on the Arduino platform. And make the firmware 10 times smaller!</description><content:encoded>&lt;blockquote&gt;This rendering was automatically generated by Frosti Feed and may have formatting issues. For the best experience, please visit: &lt;a href=&quot;https://naster17.github.io/blog/deep-dive-arduino/&quot;&gt;https://naster17.github.io/blog/deep-dive-arduino/&lt;/a&gt;&lt;/blockquote&gt; &lt;h2&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Write pure Assembly and C code for Arduino&lt;/li&gt;
&lt;li&gt;Make the firmware 10 times smaller!&lt;/li&gt;
&lt;li&gt;Setup avr utils in your linux environment&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Get Started&lt;/h2&gt;
&lt;p&gt;Today we&amp;#39;re going to dive into low-level programming on a platform like Arduino, and especially AVR.&lt;br&gt;Let&amp;#39;s go all the way from vanilla C++ programming to low-level Assembly.&lt;br&gt;And this will lead us to reduce our firmware by as much as 10 times.  &lt;/p&gt;
&lt;p&gt;I will use &lt;strong&gt;Arduno Nano&lt;/strong&gt; and &lt;strong&gt;Arduino Uno&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Installing dependencies&lt;/h2&gt;
&lt;p&gt;It is already assumed that at least you are using Arduino IDE or PlatformIO.&lt;/p&gt;
&lt;p&gt;To work with C and Assembly, we will need a special set of tools and libraries related to AVR.&lt;br&gt;Here&amp;#39;s how to install it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt install gcc-avr binutils-avr avr-libc avrdude
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;C++&lt;/h2&gt;
&lt;p&gt;I think everyone has used the basic Arduino Framework at least once.&lt;br&gt;But in short:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;#include &amp;lt;Ardino.h&amp;gt;
void setup() 
{
    // initialize digital pin LED_BUILTIN as an output.
    pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
    digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
    delay(1000);                      // wait for a second
    digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW
    delay(1000);                      // wait for a second
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Result (flash: 924 bytes)&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/e4d91d5d-9ad1-48fb-b55b-5914f5d6d40d&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;C&lt;/h2&gt;
&lt;p&gt;My favorite and most interesting part is the C language.&lt;br&gt;And so, after installing the dependencies, we have a set of tools and libraries for the AVR platform.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gcc-avr&lt;/code&gt; AVR GNU C Compiler&lt;/li&gt;
&lt;li&gt;&lt;code&gt;binutils-avr&lt;/code&gt; Default binutils for AVR platform such as as, strip, objdump ...&lt;/li&gt;
&lt;li&gt;&lt;code&gt;avr-libc&lt;/code&gt; AVR C Library including avr/io.h util/delay.h ...&lt;/li&gt;
&lt;li&gt;&lt;code&gt;avrdude&lt;/code&gt; The main flasher to flash firmware&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#39;s write the same code that will control the built-in led. He is also as &lt;strong&gt;Blink&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;lt;avr/io.h&amp;gt;
#include &amp;lt;util/delay.h&amp;gt;

#define MS_DELAY 1000

int main (void) {
    /*Set to one the fifth bit of DDRB to one
    **Set digital pin 13 to output mode */
    DDRB |= _BV(DDB5);
    
    while(1) {
        /*Set to one the fifth bit of PORTB to one
        **Set to HIGH the pin 13 */
        PORTB |= _BV(PORTB5);

        /*Wait 1000 ms */
        _delay_ms(MS_DELAY);

        /*Set to zero the fifth bit of PORTB
        **Set to LOW the pin 13 */
        PORTB &amp;amp;= ~_BV(PORTB5);

        /*Wait 1000 ms */
        _delay_ms(MS_DELAY);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Compile&lt;/h4&gt;
&lt;p&gt;Compile object (This process can be used to write makefile)&lt;br&gt;Here we have 2 params. &lt;strong&gt;-DF_CPU=16000000UL&lt;/strong&gt; for CPU clock aka 16MHz and &lt;strong&gt;-mmcu=atmega328p&lt;/strong&gt; which mean MCU type in our case is Atmel Mega328p&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;avr-gcc -s -O2 -DF_CPU=16000000UL -mmcu=atmega328p -o main.o -c main.c
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Linking firmware&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;avr-gcc -s -mmcu=atmega328p main.o -o firmware
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Extract hex representation from binary&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;avr-objcopy -O ihex -R .eeprom firmware firmware.hex
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After all we have HEX file with our firmware&lt;/p&gt;
&lt;h4&gt;Flash&lt;/h4&gt;
&lt;p&gt;Do not forget &lt;code&gt;-D&lt;/code&gt; flag to save your arduino lifespan. &lt;code&gt;-D&lt;/code&gt; used to DO NOT FORMAT all flash every upload.  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Arduino Nano&lt;/strong&gt; Work only with 57600 baud rate for my case.  &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;avrdude -D -F -V -c arduino -p ATMEGA328P -P /dev/ttyUSB0 -b 57600 -U flash:w:firmware.hex -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Arduino Uno&lt;/strong&gt; Work only with 115200 baud rate for my case.  &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;avrdude -D -F -V -c arduino -p ATMEGA328P -P /dev/ttyUSB0 -b 115200 -U flash:w:firmware.hex -v
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Result (flash: 176 bytes)&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/41e986f9-4277-4d4a-8219-f6a89300b6c8&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Assembly&lt;/h2&gt;
&lt;p&gt;And so now is the deepest part of this topic. Assembly. 
And so we have 2 ways to write all the assembly code ourselves or make the compiler do it for us. 
So, perhaps, we will choose the second one, so as not to drag it out for a long time.
You can use the first way and write everything from scratch and &lt;a href=&quot;https://ww1.microchip.com/downloads/en/DeviceDoc/AVR-Instruction-Set-Manual-DS40002198A.pdf&quot;&gt;start here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take our compiled firmware and extract assembly code from it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;avr-objdump -D firmware # we use binary file not hex
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-asm&quot;&gt;jmp	0x68	;  0x68
jmp	0x7c	;  0x7c
eor	r1, r1
out	0x3f, r1	; 63
ldi	r28, 0xFF	; 255
ldi	r29, 0x08	; 8
out	0x3e, r29	; 62
out	0x3d, r28	; 61
call	0x80	;  0x80
jmp	0xac	;  0xac
jmp	0	;  0x0
sbi	0x04, 5	; 4
sbi	0x05, 5	; 5
ldi	r18, 0xFF	; 255
ldi	r24, 0x7B	; 123
ldi	r25, 0x92	; 146
subi	r18, 0x01	; 1
sbci	r24, 0x00	; 0
sbci	r25, 0x00	; 0
brne	.-8      	;  0x8a
rjmp	.+0      	;  0x94
nop
cbi	0x05, 5	; 5
ldi	r18, 0xFF	; 255
ldi	r24, 0x7B	; 123
ldi	r25, 0x92	; 146
subi	r18, 0x01	; 1
sbci	r24, 0x00	; 0
sbci	r25, 0x00	; 0
brne	.-8      	;  0x9e
rjmp	.+0      	;  0xa8
nop
rjmp	.-42     	;  0x82
cli
rjmp	.-2      	;  0xae
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Compile&lt;/h4&gt;
&lt;p&gt;Thx &lt;code&gt;binutils&lt;/code&gt; we can compile our assembly code&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;avr-as -mmcu=atmega328p main.asm -o firmware
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Extract hex representation from binary&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;avr-objcopy -O ihex -R .eeprom firmware firmware.hex
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Flash&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;avrdude -D -F -V -c arduino -p ATMEGA328P -P /dev/ttyUSB0 -b 57600 -U flash:w:firmware.hex -v
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;avrdude -D -F -V -c arduino -p ATMEGA328P -P /dev/ttyUSB0 -b 115200 -U flash:w:firmware.hex -v
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Result (flash: 80 bytes)&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/9155edd4-3019-4b29-90fb-8bb5039b4b3a&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;And so we managed to reduce the size of the firmware even more than 10 times, I would say 10.5 :)&lt;br&gt;But will it be more than a simple experiment, or will it still be more convenient to use the super abstract C++?  &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Who knows...&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><dc:creator>Naster17</dc:creator><pubDate>Mon, 09 Jun 2025 00:00:00 GMT</pubDate></item></channel></rss>