Right after finishing the design for lpc1768_poe, I wanted to actually do a quick simple board. Wanting to do another BGA board, I decided to use up the last two MK66FN2M0VMD18 I had lying around. Since it has a 1mm pitch, it was feasible to route using OSH Park’s 2-layer process. It also has USB HS and SDHC, perfect for a rubber ducky. Thus, the project began.


There’s not much to say about the schematic, it’s among the simplest boards I’ve done. While the USB FS peripheral needs 33Ω series resistors, I couldn’t find any information in the reference manual or datasheet for USB HS and just used a direct connection like the FRDM-K66F. Since I don’t like the KiCad schematic symbol for the TVS diode array, I used individual TVS diodes. Interestingly, the MK66F has an internal 3.3V regulator that’s capable of powering the entire chip, so I used it. In hindsight, it might be undersized for some SD cards.

Layout was quite a fun challenge. Thankfully, the MK66F has all of its VDD and GND pins in the center which made power routing easy. The rest of the connections could be grouped into different sides of the package, making routing those similarly simple. Like the Pi Pico, the 90Ω differential USB trace had to be quite wide since it was 2 layers. I length matched all of the SDHC traces with those squiggles. To keep the board small, I had to cover the Tag-Connect holes with the SD card holder. I ended up soldering wires to the Tag-Connect pads for development.


While the MK66F is supported in Zephyr, like most microcontrollers, it isn’t fully supported. Specifically, there was no USB HS nor SDHC support. Thankfully, getting both working wasn’t too bad.

For USB HS, I started by looking at the register map in the reference manual and existing Zephyr NXP USB drivers. To my pleasant surprise, Zephyr already has a USB HS driver for the i.MX RT chips which has the same register map as the MK66F. They both use EHCI which appears to be a standard specification for the USB register map. After adding the appropriate DTS definition, adapting some soc.c code into my own board.c, and patching Zephyr a bit I had it almost working. At first, enabling USB dropped VDD to ~2.5V, which was strange since I measured the supply current to be ~60mA. Turns out I had to disable the internal regulator’s inrush current limit. Next, all of my setup packets were coming in as all 0s, which disabling the MPU fixed. I’ll properly set up the MPU one day, maybe. After that, it worked! Once Zephyr 3.7.0 comes out, I’ll have to make some minor updates to switch to the new UDC and USBPHY drivers.

For SDHC, I ended up having to write the driver myself. Looking at the existing Zephyr NXP SDHC drivers, they’re mainly glue code to hal_nxp drivers as is the case for many Zephyr drivers. Turns out hal_nxp also has the SDHC driver for MK66F, I simply needed to write the glue code. NXP’s drivers are very well written, the glue code was quite similar to the existing drivers. The driver works well, I’ll list off issues I found with various SD cards I tested with.

  • PNY 32GB - works perfectly every time
  • Patriot 16GB - doesn’t response to CMD0, even when disabling DAT3 detection
  • Generic 128MB - intermittent mount failure
    • 3.3V rail appears very stable, unlikely a regulator issue
    • Lowering clock speed to 25MHz helps
    • Data read request fails, not the initial command requests
    • On reset, OCR never exits busy state

After writing the drivers, I tried my fakeusbdrive app which pretends to be a 64GB USB drive. By hardcoding the right sectors, it appears to have a legitimate FAT32 file system which adds to the illusion. When I initially tried it on a microcontroller with USB FS, it took a long time to mount. With this board, it now mounts on Windows and Linux almost instantly. macOS is strange, it takes roughly the same amount of time to mount. Next I tried the mass storage example, but surprisingly the read and write speeds weren’t much better than SPI, if at all. Since both 25MHz and 50MHz achieved the same transfer speeds, I believe it’s a Zephyr issue. Still, good to see it working. Overall, I’d call this project a success!