Most versions of the i.MXRT microcontroller family do not include any flash for your program code. While this automatically forces you to buy an additional memory chip, at least you can choose what suits you best (QSPI-/Hyper-flash, µSD, etc).
When the µC is powering up, an internal bootloader is started to load the program code from the external memory device. It needs to know what kind of device it is going to talk to (basic initial configuration) and where it is connected.
NXP provides two ways of setting this initial configuration options:
- eFUSE → one time programmable memory for a non-volatile configuration
- GPIO override → pin state is sampled by the bootloader and overrides the eFUSE setting
Of course, there are also different boot modes to choose from (the bootloader needs know whether to read GPIOs) and this is done by pulling two GPIO pin states up/down:
- Boot from eFUSE (ignore any GPIOs)
- Serial downloader (load firmware over USB or UART)
- Internal boot mode (use eFUSE settings and override them by the GPIOs, if BT_FUSE_SEL=0)
This might sound a bit unusual, but the LPC4300 series (and probably other flashless ones) are quite similar to this. I planed to use the GPIO override mode, because my preferred QSPI-flash should work with default eFUSE settings and I wanted to keep flexibility. What could go possibly go wrong? - A lot! The FPGA is directly connected to the µC and should also be configured by the µC. When the board powers up, both chips will be initially unconfigured and only after the µC is up, the FPGA will come to life (if there is any bitstream). All µC I worked with before configure their GPIOs as inputs without any pull-up/down by default. Not so the iCE40! It sets the GPIOs to inputs with a pullup! Of course, I connected some GPIO override pins of the µC to the FPGA with its great pullup-by-default magic and created some fantastic boot configurations.
After realizing this issue, I wanted to boot directly from the default eFUSE settings because this should solve all problems right? As the defaults are exactly what I need for my flash anyway I don't even need to deal with the FUSEs and risk bricking my chip. Loading a program into RAM and executing it from there worked just fine. Loading a program into the flash seemed to work as well, but running it didn't work. My debugger always showed me a HardFault and stopped the execution at an unexpected memory address (for a simple "Hello world" example). It turned out, that this address belongs to the internal ROM where the bootloader stuff is stored. I was confused and disappointed.
In several locations in the reference manual and on page 72 in the datasheet you find the hint: "Boot Options, Pin value overrides fuse settings for BT_FUSE_SEL = ‘0’.". Nice, but totally unimportant for my setup so I did not care. If you read chapter 8.3.3 (page 189/190) in the reference manual about the "Boot From Fuses mode" you find another hint: "If BT_FUSE_SEL = 0, indicating that the boot device was not programmed yet, the boot flow jumps directly to the Serial Downloader.". This is very important and the exact reason why I spend nearly one week troubleshooting my board and software setup! If I chose the GPIO override mode, my FPGA created a wired boot configuration and all went wrong. If I chose the eFUSE mode, the µC decided to jump straight into the serial downloader because the fuse was not blown! There is an appnote about using the serial bootloader and NXP's computer software where they explain why this behaviour is great. Of course, I did not read this appnote and had no clue. Burning this one little fuse makes you loose the GPIO override forever, but it can save your day!
To configure the fuse settings I started the "MfgTool2.exe" to boot the chip into some special mode and then the "blhost.exe" tool for changing and verifying the eFUSE setting. Both tools and a documentation about the available commands can be found in the "Tools & Software" section of the µC on NXP's website, within the "Flash loader" package. I used the commands below to blow the fuse, but you should verify them yourself. It is a ONE time programmable memory.
blhost.exe -u 0x15a2,0x0073 efuse-program-once 0x06 00000010 blhost.exe -u 0x15a2,0x0073 efuse-read-once 0x06
To flash and debug the i.MXRT1021 microcontroller you can use a cheap LPC-Link2 (but only with NXP firmware, the SEGGER firmware is too old) or some NXP evalboard that includes a Link2-like programmer. A LPCXpresso43S67 (OM13084) worked for me. Any OOCD-like solution was missing a working target configuration file, as well as the Black Magic Probe. It would be great if this would change someday :)
- The iCE40 sets all IOs to inputs with a pull-up, when it is not configured otherwise!
- The "Boot From eFUSE"-mode on the i.MXRT1021 (and others) is jumping straight into "Serial downloader"-mode as long as the BT_FUSE_SEL is not blown (it indicates that the chip is "configured")! → Read p.189/190 (8.3.3) in the reference manual.
- It might be useful to add power sequencing, such that the µC has to boot successfully before any other chip can startup and mess with it.