Saturday, February 22, 2020

[Tech] ESP32 Programming from ARM64 Windows

(Disclosure: I am an employee of Microsoft and work on Windows 10 on ARM, but the content here is from me on my own time. Views expressed are not those of my employer, and there's no guarantee of...well, pretty much anything, but I try.)

I have had some experience using Windows 10 on ARM (ARM64) devices and, given their extreme battery life and sufficiently good performance characteristics, I thought one would be a good foundation for an IoT development machine. (Think about not needing an outlet at a hackathon...)

To test this, I recently decided to finish a project I have most of the parts for: a WiFi-controlled pair of LED strips. A long time ago someone got me a modest ESP32 break-out board for Christmas and I've been itching to use it, and I've had the LED strips since I came up with the idea.

I may yet author a Hackaday.io project describing the build, but for this article I'll be focusing on the development environment. (If I do, I will add the link here and it will be listed here.)


Connecting and Drivers


Connecting the device is straightforward: at the time of this writing, all of the Windows 10 on ARM devices that are out have either USB-A (Asus NovaGo) or USB-C (all others). In my case, that means I need a USB-C-to-A adapter along with the USB-A-to-micro-B cable the board needs.

I did run into one quirk: my ESP32 board kept reenumerating when I first plugged it in. This stopped when I connected it through a powered hub. I then got a driver working with it, unplugged the hub's power, and it kept working, so...YMMV. It's USB-C, after all. ;)

As for getting the driver to load, I recently had this exchange on Twitter, and, while force-using usbser.sys worked, I felt a little silly for not actually trying the part vendor's driver bundle! In the case of Silicon Labs, it turns out they already ship ARM64 drivers as part of their Universal drivers bundle.

There are times when the vendor driver bundle either doesn't exist or doesn't recognize the provided vendor and product IDs. In this case, one path is to use Zadig to associate a specific driver with the device--but Zadig does not yet have ARM64 support. They are looking for contributions to make this happen.

If the driver is already installed (AND YOU KNOW IT'S THE RIGHT ONE, just sayin'), you open Task Manager, find your device, right click and select Update Driver, select "Browse my computer for drivers," select "Let me pick from a list of available drivers on my computer," and navigate to it there. In my case, I got my CP2102 to be associated with usbser.sys by selecting "Ports (COM & LPT)", Microsoft, and USB Serial Device.

I checked a few of the USB driver systems I know to see how ARM64 support is coming:
  • libusb has supported ARM64 Windows since April 2019, but the official downloads still don't include it (2/17/2020).
    • I believe Zadig relies on libusb's binary releases, so this needs to change upstream before Zadig Just Works(TM).
  • Silicon Labs' CP210x USB to UART Bridge VCP Drivers Windows 10 Universal download includes ARM64 support, but the bundled x86 installer may not work on ARM64. (To prevent compat problems, the driver installation APIs don't work under Windows-on-Windows emulation.)
  • FTDI's VCP drivers do not list ARM64 as supported, but if you contact support they may be willing to share a beta version. (2/17/2020)
  • Anything relying on the WinUSB conventions will work fine since the USB stack on ARM64 Windows is identical to the x64 version.
  • usbser.sys is similarly standard on ARM64 Windows as on x64, so anything compatible with it will work.
    • Caveat: As noted in the Zadig Github issue, ARM64 shipped recently enough that the CoInstaller DLLs are not needed (and so aren't provided). Depending on your INF authoring approach, this might be a slight irritation or a major pain. (Thanks to pbatard in the thread mentioned earlier for this discovery.)
I would love to hear about more combinations. If you mention me in a tweet about it, I will do my best to add it here.

Following the Getting Started Guide


Once I settled on the ESP32 with the CP2102 USB-to-Serial adapter and got it working, I started looking into whether I could get the development environment set up for it.

I already knew from articles I had read that I could use either Espressif's own development environment or their environment integrated into the Arduino development environment. When I looked for a decent either-or guide, I found this forum post, and from there I found the official Espressif IoT Development Framework repo and its official docs. I picked the Espressif environment over the Arduino route since I have done a small amount of embedded development before and wanted to see how the sausage is made.

Espressif has an excellent Getting Started Guide with platform-specific bootstrapping guides making up Step 1.

The trick is to catch the note at the top of the Windows instructions that says "Currently only 64-bit versions of Windows are supported. 32-bit Windows can use the Legacy GNU Make Build System." This applies to ARM64 Windows because this relies on the mostly-correct-in-most-contexts assumption that 64-bit Windows is x64 Windows. (Historical footnote: Itanium once made this incorrect too.) Anything compatible with x86 32-bit Windows is most likely (in my experience) to be compatible with ARM64's x86 32-bit emulation, so I proceeded down the Legacy route and ignored the rest of the normal Windows instructions.
(Well, I did try them for fun. The installer they provide reports that it is only compatible with x64 Windows and exits.)


(Note that there is a complete Getting Started Guide for the legacy tools, but I did not use it.)

When I moved on to Step 2, I followed the Linux path. Also, instead of using ~/esp I just use ~.

When I got to Step 3, I also followed the Linux path but got this error:
$ ./install.sh
Installing ESP-IDF tools
ERROR: Platform Windows-ARM64 appears to be unsupported


Looking through install.sh and export.sh, it appears that this is installing dependencies in the MSYS2 environment and setting up the environment. A link had caught my eye earlier, so I went back to look at the guide for setting up the legacy tools from scratch linked from the Legacy GNU Make Build System page. This command looked useful:

$ ./tools/windows/windows_install_prerequisites.sh
This re-does a lot of the work that was supposed to already be done, but it seems to do a little more and includes some instructions in its final output. I futzed around a bunch and eventually reinterpreted those to mean that I should add these lines to ~/.bash_profile:

export IDF_PATH=~/esp-idf
. $IDF_PATH/add_path.sh


...and restart the shell.

This does what Step 4 intends to do, so I skipped it.

Step 5's Linux path worked like a charm.

For Step 6, I used the Windows name for the serial port. In my case it was COM5, as shown in Device Manager under Ports. The really complicated part of this, getting the device to show up as a COM port, was addressed earlier in the article.

Step 7's Linux path produced an error about CMake not being on the PATH. I fixed this by adding this to ~/.bash_profile:

CMAKE_PATH=/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/2019/Community/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/bin
export PATH=$PATH:$CMAKE_PATH

Steps 8, 9, and 10 just worked.

Hello world!
This is esp32 chip with 2 CPU cores, WiFi/BT/BLE, silicon revision 1, 2MB external flash


Conclusion


This actually worked! Now it's just a matter of writing and testing code. I just need to fire up an editor that runs on ARM64 windows like Visual Studio, Visual Studio Code, vim, Notepad++, or...well, I'm certainly no smarter than you are on this point. Use your imagination!

I really appreciate Espressif for having such clear Getting Started materials and especially for the x86 32-bit Windows legacy support. Maybe Ninja will one day support ARM64 Windows and the small tweaks in this article won't be necessary. :)

Thanks go to driver1998 for the tip about the SiLabs ARM64 driver. It really does pay to check a vendor's site before wandering off into hacky paths.

No comments:

Post a Comment