Setting up an esp32 development environment in nixos using vscode and ESP-IDF
With the basic hardware assembled the remaining tasks include:
- Sending code to the esp32 (blinking LED aka hello world)
- Wiring the stepper
- Spinning the stepper
- Powering from a battery
- Controlling from an app
We will be tackling step 1 in this post.
Platform setup
My desktop is dual booted with Windows 10 and NixOS (a rather neat linux distro based around a more deterministic package manager). With extensive experience writing code using Windows Subsystem for Linux I can confidently say please no more, let's use linux. Unfortunately this means I will have to reboot to switch between CAD and Code. Not the end of the world!
ESP32: via vscode
Since other development is going through VSCode I started with the Espressif IDF plugin for vscode and ended with an absolutely heinous slog through my lack of understanding about nix.
After combing through extensive attempts and documentation this post along with 10 hours of new understanding I managed to get an LED blinking.
The nix deps are composed of three files,
- esp-idf.nix - The development sdk for esp32
- esp32-toolchain.nix - The compiler etc to target the esp32
- shell.nix - Setting up the development environment with the above
esp-idf.nix
{ stdenv, fetchFromGitHub, pkgs, makeWrapper }:
let
version = "v4.1-dev";
pypkgs = python-packages: with python-packages; [
pyserial
click
cryptography
future
pyparsing
pyelftools
setuptools
];
python = pkgs.python2.withPackages pypkgs;
in stdenv.mkDerivation rec {
name = "esp-idf";
src = fetchFromGitHub {
owner = "espressif";
repo = "esp-idf";
rev = "${version}";
fetchSubmodules = true;
sha256 = "0d1iqxz1jqz3rrk2c5dq33wp1v71d9190wv3bnigxlp5kcsj0j1w";
};
buildInputs = [
python
];
propagatedBuildInputs = [
pkgs.cmake
pkgs.ninja
pkgs.gcc
pkgs.git
pkgs.ncurses
pkgs.flex
pkgs.bison
pkgs.gperf
pkgs.ccache
python
];
phases = [ "unpackPhase" "installPhase" "fixupPhase" ];
installPhase = ''
cp -r . $out
'';
meta = with stdenv.lib; {
description = "ESP IDF";
homepage = https://docs.espressif.com/projects/esp-idf/en/stable/get-started/linux-setup.html;
license = licenses.gpl3;
};
}
esp-toolchain.nix
{ stdenv, fetchurl, makeWrapper, buildFHSUserEnv }:
let
fhsEnv = buildFHSUserEnv {
name = "esp32-toolchain-env";
targetPkgs = pkgs: with pkgs; [ zlib ];
runScript = "";
};
in
stdenv.mkDerivation rec {
name = "esp32-toolchain";
version = "2019r2";
src = fetchurl {
# https://github.com/espressif/esp-idf/blob/release/v4.1/tools/tools.json#L27
url = "https://dl.espressif.com/dl/xtensa-esp32-elf-gcc8_2_0-esp-2019r2-linux-amd64.tar.gz";
sha256 = "1pzv1r9kzizh5gi3gsbs6jg8rs1yqnmf5rbifbivz34cplfprm76";
};
buildInputs = [ makeWrapper ];
phases = [ "unpackPhase" "installPhase" ];
installPhase = ''
cp -r . $out
for FILE in $(ls $out/bin); do
FILE_PATH="$out/bin/$FILE"
if [[ -x $FILE_PATH ]]; then
mv $FILE_PATH $FILE_PATH-unwrapped
makeWrapper ${fhsEnv}/bin/esp32-toolchain-env $FILE_PATH --add-flags "$FILE_PATH-unwrapped"
fi
done
'';
meta = with stdenv.lib; {
description = "ESP32 toolchain";
homepage = https://docs.espressif.com/projects/esp-idf/en/stable/get-started/linux-setup.html;
license = licenses.gpl3;
};
}
shell.nix
{ pkgs ? import <nixpkgs> {} }:
let
esp-idf = (pkgs.callPackage ./esp-idf.nix {});
esp32-toolchain = (pkgs.callPackage ./esp32-toolchain.nix {});
in
pkgs.mkShell {
buildInputs = [
esp-idf
esp32-toolchain
];
shellHook = ''
set -e
export IDF_PATH=${esp-idf}
export NIX_CFLAGS_LINK=-lncurses
export PATH=$PATH:$IDF_PATH/tools
'';
}
After plugging in the device via USB a quick ls shows a tempting device:
ls -d /dev/tty*
...
/dev/ttyUSB0
Testing the toolchain:
cp -r $IDF_PATH/examples/getting-started/blink .
# chmod omitted
cd blink
idf.py build
sudo idf.py -p /dev/ttyUSB0 flash
And with that the esp32 is blinking. Excellent! Next step is wiring up and controlling the stepper.