mimxrt/bootloader: Enable support for the UF2 bootloader.
Based on tinyuf2, which can be installed and used with MicroPython. The .uf2 file is created in addition to the .bin and .hex files allowing to use the latter ones without the bootloader for debugging and testing.
Changes:
- Set the location of the ISR Vector and .text segment to 0x6000C000 and 0x6000C400.
- Reserve an area at the start of ITCM for a copy of the interrupt vector table and copy the table on reset to this place.
- Extend machine.bootloader() by setting the magic number to enable the bootloader on reset.
- Create a .uf2 file which skips the segments below 0x6000C000.
- Update the deploy instructions.
- Change the autobuild script to include the .uf2 file.
The bootloader has to be installed as a preparation step using the board specific methods, but then the firmware's .uf2 file version can be installed using the bootloader. The bootloader can be invoked with:
- double reset
- calling machine.bootloader()
- Using the touch1200 method
Tested with:
- Adafruit Metro M7
- MIMXRt1011-EVK
- MIMXRT1015-EVK
- MIMXRT1021-EVK
- Olimex RT1011
- Seeed ARCH MIX
- Makediary RT1011 Nano Kit
The change is especially useful for boards which are delivered with a UF2 bootloader like the Adafruit Metro M7 or with no bootloader like the Olimex and Seeed boards. There, the more complicated initial install has to be done only once. The bootloader needs 48kByte of flash memory. But the MIMXRT boards have plenty of flash space, making this additional flash use acceptable.
Some boards are excluded from the .uf2 build:
- MIMXRT1050_EVK: The uf2 bootloader is built for the QSPI version of the board. MicroPyton supports the Hyperflash version.
- TEENSY40, TEENSY41: There is trouble with the uf2 bootloader even when working with Circuitpython. The Bootloader can be installed and works once after installation. But it cannot be invoked by any of the above means.
- MIMXRT1176_EVK: No support for this board yet, but it should be possible.
Codecov Report
All modified and coverable lines are covered by tests :white_check_mark:
Project coverage is 98.59%. Comparing base (
b2ce9b6) to head (0a433a0). Report is 6 commits behind head on master.
Additional details and impacted files
@@ Coverage Diff @@
## master #15983 +/- ##
=======================================
Coverage 98.59% 98.59%
=======================================
Files 167 167
Lines 21599 21599
=======================================
Hits 21295 21295
Misses 304 304
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
Code size report:
bare-arm: +0 +0.000%
minimal x86: +0 +0.000%
unix x64: +0 +0.000% standard
stm32: +0 +0.000% PYBV10
mimxrt: +420 +0.115% TEENSY40[incl +32(data)]
rp2: +0 +0.000% RPI_PICO_W
samd: +0 +0.000% ADAFRUIT_ITSYBITSY_M4_EXPRESS
qemu rv32: +0 +0.000% VIRT_RV32
Thanks for making this change @robert-hh, and I've also tested with the Makerdiary Nano Kit; appears to work fine (and with the default bootloader - based on TnyUF2 - shipped with the product).
@dpgeorge The changes you suggested are now implemented. I tested the PR again using:
- MIMXRT1011 with the boards Adafruit Metro M7 and Makediary Nano Kit
- MIMXRT1015 with the boards MIMXRT1015-EVK
- MIMXRT1021 with the board MIMXRT1020-EVK
- MIMXRT1052 with the board Seeed Arch Mix.
- MIMXRT1062 with Teensy 4.1 (no uf2 bootloader)
I tested both using the UF2 bootloader for uploading the .uf2 file when supported and uploading the generated .hex resp. .elf file using a Segger adapter or the Teensy bootloader. The "standalone" versions of the firmware can still be uploaded and work, turning off the uf2 bootloader.
I tested both using the UF2 bootloader for uploading the .uf2 file when supported and uploading the generated .hex resp. .elf file using a Segger adapter or the Teensy bootloader. The "standalone" versions of the firmware can still be uploaded and work, turning off the uf2 bootloader.
Excellent. Thanks for retesting.
I made a few little changes, enabling the bootloader on Teensy boards as a test for other MIMXRT106x boards. There was a problem that wit calling machine.bootloader() the ROM bootloader was called instead of the UF2 bootloader. That should have affected the other boards as well, and is changed now. With Teensy both the teensy loader or the UF2 bootloader can be used. But using the teensy loader would disable the UF2 bootloader. The methods for starting the UF2 boatloader on Teensy are calling machine.reset() or the touch1200 method. Lacking a reset button, double reset does not work.
@dpgeorge With further testing of this PR it appears, that there is a problem with flash write access at some boards. The TinyUF2 bootloader re-configures the flash - IMHO without any need . I thought I had compensated for that, but it seems that not for each board or flash type. So please wait with merging.
Edit: The problem occurs only with MIMXRT1010 boards, and happens when using mpremote to copy a file to the board, when the file does not yet exist. The directory entry is created, but on file copy the is an internal hard fault. If the file exists, even with 0 length, copy runs fine. Local file operation at the board succeed well. The same firmware loaded to the board directly without the UF2 bootloader works well. Stack trace on hard fault below. It looks as if file write and USB communication get in conflict.
The SCBDisableCache/EnableCache .... was already a point of discussion. If I remove it, I get a Python Exception with OSError: 36
There is another phenomenon: With the UF2 Bootloader active the execution speed on some boards is heavily reduced. No impact for Teensy 4.x, but for instance with the MIMXRT1020-EVK the speed is cut to halve. The bootloader configures flash write to single speed instead of quad speed, but on during the test there are no flash writes. Anyhow, the whole flash sections needs a rework. I started it, but at low drive since flash access works.
I changed the low level functions for flash to reverse the order of disabling flash and disabling IRQ (and the oppostite), after which I could not provoke the flash write problem again. The commit is attached.
@iabdalkader is that some info for your recent reasoning, whether this SCB_CleanInvalidateDCache(); SCB_DisableDCache(); is needed or not?
@iabdalkader is that some info for your recent reasoning, whether this
SCB_CleanInvalidateDCache(); SCB_DisableDCache();is needed or not?
I'm not sure I understand the question, I never worked on this flash driver. However, note that SCB_DisableDCache already cleans and invalidates the cache, so you probably don't need SCB_CleanInvalidateDCache at all.
I'm actually more concerned about the flash changes: they seem to downgrade the flash from QUAD to single line, among other unknown changes. I'd at least make sure all changes are conditional on the bootloader being enabled, and document the changes in the commit.
EDIT: If you were asking if we needed the clean/invalidate, yes. The flash contents is going to change, so any cached reads need to be invalidated. I don't think there's any dirty lines (writes) to flush though.
However, note that SCB_DisableDCache already cleans and invalidates the cache
Thanks. I looked into the code of SCB_DisableDCache and you're right. So I can remove the clearing.
I'm actually more concerned about the flash changes: they seem to downgrade the flash from QUAD to single line.
I'm not overall happy about it, even if write time is not increased a lot. The flash clock frequency for a iMXRT1011 board is 60MHz. So the data transfer time is 4.3µs (quad) or 17µs (single) compared to page program times of 600 to 2400 µs. In addition, if you program the device with a .bin or .hex file, the uf2-bootloader is bypassed. Looking at the timing at the flash chip with an oscilloscope, the flash read is still done in quad mode.
Comparing the flash frequencies, it seems that the UF2 bootloader reconfigures the flash clock from ~100Mhz to ~60MHz for iMXRT1011 and 30MHz for i.MXRT1021. That explains the speed difference. Have to switch that back or ask Hatach not to change the flash clock.
I looked to change back the flash config at runtime, but this is hardly feasible. Even at runtime of MicroPython, the flash configuration of the UF2 bootloader is used, and when trying to change that, the bootloader does not start the app. So I'll make a PR for the bootloader. The genuine flash config of MicroPython will be used when the bootloader is overwritten. That set-up has to be reworked in a separate PR. Edit: The PR in the UF2-bootloader repository is made. No further change needed so far here.
@dpgeorge Meanwhile Adafruit has updated it's repository with the higher clock frequencies. Only that this is not yet in a release of binary images, which could be referenced. Scott Shawcroft was so kind to direct me to the place in the CircuitPython code where the flash clock is changed at runtime. I adapted that for the MIMXRT port and it works, at least for the mimxr10xx series. I can add that change to this PR, so we do not have to wait for the next release of the UF2-bootloader.
@dpgeorge Quad mode page program is now enabled again as well. I added per-board settings to cover the different commands and arguments for each board. The flash chips differ by three parameters, frequency, command to enable Quad mode and Argument for that command. Adding these to the board .mk file seemed easier than adding a flash_config.c file to each board definition. I had prepared that option as well, but it required adding many files which were mostly identical. Tested for all board I have with both using the UF2 bootloader and loading the firmware directly. Test overview:
Board Flash Chip Timing Freq QE_CMD QE_ARG Build UF2 Direct load
Adafruit MM7 W25Q64JV 3ns 133 MHz 0x31 0x02 OK OK OK
Makediary NK W25Q128JV 3ns 133 MHz 0x31 0x02 OK OK OK
MIMXRT1010 AT25SF128A 5ns 100 MHz 0x31 0x02 OK OK OK
MIMXRT1015 AT25SF128A 5ns 100 MHz 0x31 0x02 OK OK OK
MIMXRT1020 IS25LP064 3ns 133 MHz 0x01 0x40 OK OK OK
MIMXRT1050 NOR IS25WP064 5ns 133 MHz 0x01 0x40 Same setup as Arch mix
MIMXRT1050 HPR S26KS512SDPBHI02 5ns 133 MHz OK - OK
MIMXRT1060 IS25WP064 5ns 133 MHz 0x01 0x40 No board for test
MIMXRT1064 W25Q32JV 3ns 100 MHz 0x31 0x02 No board for test
MIMXRT1176 IS25WP128-JBLE 3ns 133 MHz 0x31 0x02 OK - OK
Olimex RT1010 EN25Q16-104 3ns 100 MHz 0x01 0x40 OK OK OK
SEEED ARCH MIX IS25WP064 5ns 133 MHz 0x01 0x40 OK OK OK
Teensy 4.0 W25Q16JVUXIM 5ns 133 MHz 0x31 0x02 OK OK OK
Teensy 4.1 W25Q64JVXGIM 3ns 133 MHz 0x31 0x02 OK OK OK
@iabdalkader Could you test that PR with a MIMXRT1064 board, if you still have access to it?
@iabdalkader Could you test that PR with a MIMXRT1064 board, if you still have access to it?
I'll see if I can find it.
The commit that sets the flash clock frequency according to the configured value is added now. It may not be needed any more with the next release of the UF2 bootloader. But for all users with an older version of the bootloader this is useful. It applied only to i.mxrt10xx boards with QSPI flash. Tested with:
i.mxrt 1011 (MIMXRT1011-EVK) i.mxrt 1015 (MIMXRT1015-EVK) i.mxrt 1021 (MIMXRT1020-EVK) i.mxrt 1052 (Seeed Arch Mix 1052) i.mxrt 1062 (Teensy 4.1)
I'm going to test this on the weekend, haven't forgotten about it.
@iabdalkader OK. Don't worry.
@robert-hh I programmed the bootloader:
[10245.500663] scsi 0:0:0:0: Direct-Access Adafruit UF2 Bootloader 1.0 PQ: 0 ANSI: 2
[10245.502161] sd 0:0:0:0: [sda] 65801 512-byte logical blocks: (33.7 MB/32.1 MiB)
Now when I copy firmware.uf2 to the MSC disk it seems to overwrite itself. Shouldn't the flash address, in the linker script, change when the bootloader is enabled?
The question is:
a) does MicroPyhton run b) can you restart the bootloader with machine.bootloader().
The code for text should start at flash_start + 32k. the firmware.bin and firmware-hex images still containc the ISR, such the these files can be loaded directly, overwriting the bootloader. But these parts of the firmware are stripped from the .uf2 file, avoiding to overwrite the bootloader.
The question is:
a) does MicroPyhton run b) can you restart the bootloader with machine.bootloader().
Not sure what happened the first time, but when I copy the firmware now it works. And yes, I can enter the bootloader again via machine.bootloader(), so all is good.
Can you run at least twice the cycle:
- start bootloader
- upload firmware
touch1200 should work as well to start the bootlader, and reset twice. Although the timing for latter is a little bit tricky on the -EVK board. You have to push reset the second time JUST when the led close to the MCU goes off.
Can you run at least twice the cycle:
I've already did, and it worked fine. I only tested machine.bootloader() nothing else.
Thank you for testing and confirming. One last question: Is it possible to write to the file system with MicroPython? For instance using mpremote. That confirms the quad mode is properly enabled for writing.
Yes, the filesystem is writable.
Thanks again.
Thanks @robert-hh for improving this PR, and @iabdalkader for testing.
Is this now ready to be merged?
I would say yes. The last commit will not be needed any more, when the UF2 bootloader site is updated. Anyhow, it does not hurt.