Purpose: Code, flash, and debug embedded projects without spending hours configuring nix (love you nix)
- Global Config & Permissions
- ESP-IDF (ESP32)
- PlatformIO (ESP32S3)
- Arduino Plugin + Boards
- Adafruit Feather RP2040 (USB Host)
My configuration.nix has:
udev.packages = [
pkgs.platformio-core
pkgs.platformio-core.udev
];
I also am in the "dialout" group:
users.users.will.extraGroups = [
"dialout" # home-manager
];
Usage:
idf.py create-project "esp-idf"
Atm I have a permission issue, to fix this I do:
sudo chmod 755 "esp-idf"
cd "esp-idf"
For testing I like to change "esp-idf/main/main.c" to:
#include <stdio.h>
void app_main(void)
{
printf("hello world\n");
}
To set the esp target, run:
idf.py set-target esp32s3
Change to your specific esp-32 though obviously
idf.py build
idf.py flash
Cannot flash whilst monitor is open, use Ctrl+] to close
idf.py monitor
Should get a result like:
I (226) spi_flash: detected chip: gd
I (228) spi_flash: flash io: dio
W (231) spi_flash: Detected size(8192k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (243) sleep_gpio: Configure to isolate all GPIO pins in sleep state
I (249) sleep_gpio: Enable automatic switching of GPIO sleep configuration
I (256) main_task: Started on CPU0
I (266) main_task: Calling app_main()
hello world
I (266) main_task: Returned from app_main()
I personally use this extension:
https://github.com/anurag3301/nvim-platformio.lua
So my steps are a little different, but you will do:
Seach for board via:
pio boards | grep esp32s3
mkdir "pio-esp32s3"
cd "pio-esp32s3"
pio project init -b "seeed_xiao_esp32s3" --ide vim --sample-code --project-dir "pio-esp32s3"
Run via:
pio run --target upload
If you get static binary error, please ensure "platformio-core" is not installed
Fix neovim errors via:
pio run -t compiledb
Though this personally doesn't work for all of them for me...
So we do: add this line to pio-esp32s3/platformio.ini
extra_scripts = pre:extra_script.py
Then add to pio-esp32s3/extra-script.py:
import os
Import("env")
# include toolchain paths
env.Replace(COMPILATIONDB_INCLUDE_TOOLCHAIN=True)
# override compilation DB path
env.Replace(COMPILATIONDB_PATH="compile_commands.json")
If you go into arduino_uno you'll see there's a uno file, but the CLI is a bit of a ballache to use
So I'm using: This plugin You'll see there's a few requirements, the djjson, lsp, etcetc.
~~I won't go into too much detail, but set it up as the repo says, and set arduino_language_server up like this: ( at least for me ) ~~
lua~~ ~~ lspconfig.arduino_language_server.setup({~~ ~~ capabilities = capabilities,~~ ~~ on_attach = on_attach,~~ ~~ })~~ ~~
Originally I used this code:
let
arduino-nvim = pkgs.fetchFromGitHub {
owner = "yuukiflow";
repo = "arduino-nvim";
rev = "main";
sha256 = "sha256-WTFbo5swtyAjLBOk9UciQCiBKOjkbwLStZMO/0uaZYg=";
};
in
.....
".config/nvim/lua/Arduino-Nvim" = {
source = arduino-nvim;
recursive = true;
};
This doesn't work as the plugin has hardcoded this:
cmd = {
"arduino-language-server",
"-cli", "arduino-cli",
"-cli-config", "$HOME/.arduino15/arduino-cli.yaml",
"-clangd", "/usr/bin/clangd",
"-fqbn", board,
},
So I ended up cloning the repo for my home manager config, then decided to delete the .git file ( as lovely jubbly home manager doesn't want to source git repos) Then changed the lsp.lua file where the require....arduino_langage_server.setup.. is to:
cmd = {
"arduino-language-server",
"-cli", "arduino-cli",
"-cli-config", "$HOME/.arduino15/arduino-cli.yaml",
"-clangd",
vim.fn.exepath("clangd"),
"-fqbn", board,
},
This reason being, is this hard-coded clangd path meant the lsp was failing - see my Dotfiles if you wanna
MAKE SURE to delete the .git and if you did a git add to your hmoe manager repo, do a git rm --cached -r PATH TO ARDUINO-NVIM If the repo is a submodule, it will not be moved by home manager
I ran some commands to initialise as I got an error: ( Though the first two are done via the flake now :) )
arduino-cli config init
arduino-cli core update-index
arduino-cli core install arduino:avr
View the bindings for this library on the github repo Here
Now that that's working we'll move onto the adafruit one :)
I had many issues with platform IO as it doesn't technically support RP2040, you have to use some other core for it, so arduino is much easier
I'll be using this cheat sheet: https://www.woolseyworkshop.com/2019/04/14/arduino-command-line-cheatsheet/ And this guide for the usb pasthrough-ness: https://learn.adafruit.com/adafruit-feather-rp2040-with-usb-type-a-host/usb-host-device-info
mkdir adafruit_rp2040 main
cd adafruit_rp2040
arduino-cli lib search "Adafruit TinyUSB" main
Name: "Adafruit TinyUSB Library"
Author: Adafruit
Maintainer: Adafruit <[email protected]>
Sentence: TinyUSB library for Arduino
......... Etc etc
Install via:
arduino-cli lib install "Adafruit TinyUSB Library"@2.1.0 main
Same again, search for pio USB:
arduino-cli lib search "Pio USB" main
Name: "Pico PIO USB"
Author: sekigon-gonnoc
... etcet c
Install:
arduino-cli lib install "Pico PIO USB" main
Then I ran a uh:
arduino-cli lib upgrade
Now gotta select the board, I had to install the board manager for RP2040 etc via: ( https://learn.adafruit.com/adafruit-feather-rp2040-with-usb-type-a-host/arduino-ide-setup )
arduino-cli config add board_manager.additional_urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
Then run:
arduino-cli core update-index main
Downloading index: package_index.tar.bz2 downloaded
Downloading index: package_adafruit_index.json downloaded
Downloading index: package_rp2040_index.json downloaded
Downloading index: package_index.tar.bz2 dow
I also did a cheeky:
arduino-cli core install rp2040:rp2040
Then after we list our boards via:
arduino-cli board listall | grep adafruit
We can find the: Adafruit Feather RP2040 USB Host rp2040:rp2040:adafruit_feather_usb_host
Now, via neovim we press ab and search for our board, once that's done, our board should be selected!
I tried to compile but had some issues, so I added this to the flake.nix:
libudev-zero
export LD_LIBRARY_PATH="${pkgs.libudev-zero}/lib:${pkgs.systemd}/lib:$LD_LIBRARY_PATH"
( It's already in there, no need for you to do it )
I also added picotool to the flake.nix here, but that's alr done
I made the makefile in adafruit_rp2040/Makefile as the built in cmopiler and builder for the neovim plugin doesn't allow for our custom usbstack compile command we have
make upload and make compile work! MUST BE IN BOOTLOADER MODE
embedded_development_nix/adafruit_rp2040 ❯ make upload main
arduino-cli upload --fqbn rp2040:rp2040:adafruit_feather_usb_host:freq=120,usbstack=tinyusb .
Resetting /dev/ttyACM0
Converting to uf2, output size: 119296, start address: 0x2000
Scanning for RP2040 devices
Flashing /run/media/will/RPI-RP2 (RPI-RP2)
Wrote 119296 bytes to /run/media/will/RPI-RP2/NEW.UF2
Flashing /var/run/media/will/RPI-RP2 (RPI-RP2)
Wrote 119296 bytes to /var/run/media/will/RPI-RP2/NEW.UF2
New upload port: /dev/ttyACM0 (serial)
At this point I copied the example code, then went to the git repo to get usbh_helper.h and compiled again ( via make compile
and make upload
)
IT WORKED.
ashing /run/media/will/RPI-RP2 (RPI-RP2)
Wrote 223744 bytes to /run/media/will/RPI-RP2/NEW.UF2
Flashing /var/run/media/will/RPI-RP2 (RPI-RP2)
Wrote 223744 bytes to /var/run/media/will/RPI-RP2/NEW.UF2
New upload port: /dev/ttyACM0 (serial)
After a cheeky monitor command and plugging in my keyboard:
embedded_development_nix/adafruit_rp2040 ❯ arduino-cli monitor main
Using default monitor configuration for board: rp2040:rp2040:adafruit_feather_usb_host
Monitor port settings:
baudrate=9600
bits=8
dtr=on
parity=none
rts=on
stop_bits=1
Connecting to /dev/ttyACM0. Press CTRL-C to exit.
Device removed, address = 1
No device connected (except hub)
Device attached, address = 1
Device 1: ID 0d62:910e
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 0200
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x0d62
idProduct 0x910e
bcdDevice 3302
iManufacturer 0
iProduct 2 HP USB Business Slim Keyboard
iSerialNumber 0
bNumConfigurations 1
Device 1: ID 0d62:910e HP USB Business Slim Keyboard
SHE WORKS !!!!
Now lets move onto the keyboard as that's what I wanted this for:
https://learn.adafruit.com/using-a-keyboard-with-usb-host/arduino
If you followed the previous guide, this is all setup, so we have to do very little:
mkdir adafruit_rp2040_keyboard
cd adafruit_rp2040_keyboard
touch adafruit_rp2040_keyboard.ino
touch usbh_helper.h
cp ../adafruit_rp2040/Makefile .
Copy the files from the URL above ( I changed the baud rate from 115200 to 9600 in the main file )
Then:
make compile
make upload
arduino-cli monitor
Plug a keyboard into your ada feather-fruit then watch as your marvelous typing gets sent via serial:
Keys: O D J
Modifiers: LEFT_SHIFT
Keys: D J
Modifiers: LEFT_SHIFT
Keys: J
Modifiers: LEFT_SHIFT
Keys: J A
Modifiers: LEFT_SHIFT
Keys: A
Modifiers: LEFT_SHIFT
Keys: A S
Modifiers: LEFT_SHIFT
Keys: A S O
Modifiers: LEFT_SHIFT
Modifiers: LEFT_SHIFT
Keys: A S O
Keys: S O D
Keys: O D
Keys: D
No keys pressed
Vvk20k
Man I hate esp idf.
Every single fix for random LSP errors always says the same thing "Hard code your clang command" What if I want to update my system ? What if I want to use clangd for other c++ projects?
I have a fix ! Set your .clangd to:
CompileCommandsDir: build
CompileFlags:
Remove: [-fno-tree-switch-conversion, -fno-shrink-wrap, -mtext-section-literals, -mlongcalls, -fstrict-volatile-bitfields, -march=rv32imac_zicsr_zifencei]
Install esp-idf from the flake.nix ( it's already done )
Then make sure you've got this in your flake.nix ( I have done it already here)
export CLANGD_IDF_PATH=$(which clangd)
Then in your neovim configuration:
local esp_idf_path = os.getenv("IDF_PATH")
local clangd_nix = os.getenv("CLANGD_IDF_PATH")
if esp_idf_path then
-- for esp-idf
require("lspconfig").clangd.setup({
-- handlers = handlers,
capabilities = capabilities,
cmd = { clangd_nix, "--background-index", "--query-driver=**" },
root_dir = function()
-- leave empty to stop nvim from cd'ing into ~/ due to global .clangd file
end,
})
else
-- clangd config
require("lspconfig").clangd.setup({
-- cmd = { 'clangd', "--background-index", "--clang-tidy"},
handlers = {
["textDocument/publishDiagnostics"] = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
disable = { "cpp copyright" },
}),
},
})
end
Basically, use clangd_idf only if idf exists !
And badabing badaboom ! ( idf.py fullclean && idf.py build )
Your lsp works with no "could not find stdio.h" etc errors
-- stm32 side-note:
❯ /opt/stm32cubeide/plugins/com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.13.3.rel1.linux64_1.0.0.202410170706/tools/bin/arm-none-eabi-gcc -print-sysroot /opt/stm32cubeide/plugins/com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.13.3.rel1.linux64_1.0.0.202410170706/tools/bin/../arm-none-eabi
CompileFlags: Add: - --target=arm-none-eabi - --sysroot=/opt/stm32cubeide/plugins/com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.13.3.rel1.linux64_1.0.0.202410170706/tools/bin/../arm-none-eabi
Also uh: https://github.com/alex-schulster/stm_lsp_nvim/tree/main