micropython icon indicating copy to clipboard operation
micropython copied to clipboard

mimxrt/bootloader: Enable support for the UF2 bootloader.

Open robert-hh opened this issue 1 year ago • 3 comments

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.

robert-hh avatar Oct 09 '24 09:10 robert-hh

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.

codecov[bot] avatar Oct 09 '24 09:10 codecov[bot]

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

github-actions[bot] avatar Oct 09 '24 09:10 github-actions[bot]

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).

mattytrentini avatar Oct 10 '24 04:10 mattytrentini

@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.

robert-hh avatar Jan 24 '25 16:01 robert-hh

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.

dpgeorge avatar Jan 26 '25 12:01 dpgeorge

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.

robert-hh avatar Jan 26 '25 12:01 robert-hh

@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. Call Stack on Fault

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.

robert-hh avatar Jan 26 '25 16:01 robert-hh

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?

robert-hh avatar Jan 26 '25 20:01 robert-hh

@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.

iabdalkader avatar Jan 26 '25 21:01 iabdalkader

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.

robert-hh avatar Jan 27 '25 08:01 robert-hh

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.

robert-hh avatar Jan 27 '25 09:01 robert-hh

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.

robert-hh avatar Jan 28 '25 08:01 robert-hh

@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.

robert-hh avatar Feb 02 '25 15:02 robert-hh

@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?

robert-hh avatar Feb 04 '25 14:02 robert-hh

@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.

iabdalkader avatar Feb 04 '25 17:02 iabdalkader

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)

robert-hh avatar Feb 04 '25 19:02 robert-hh

I'm going to test this on the weekend, haven't forgotten about it.

iabdalkader avatar Feb 06 '25 18:02 iabdalkader

@iabdalkader OK. Don't worry.

robert-hh avatar Feb 06 '25 18:02 robert-hh

@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?

iabdalkader avatar Feb 08 '25 14:02 iabdalkader

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.

robert-hh avatar Feb 08 '25 15:02 robert-hh

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.

iabdalkader avatar Feb 08 '25 15:02 iabdalkader

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.

robert-hh avatar Feb 08 '25 15:02 robert-hh

Can you run at least twice the cycle:

I've already did, and it worked fine. I only tested machine.bootloader() nothing else.

iabdalkader avatar Feb 08 '25 15:02 iabdalkader

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.

robert-hh avatar Feb 08 '25 16:02 robert-hh

Yes, the filesystem is writable.

iabdalkader avatar Feb 08 '25 16:02 iabdalkader

Thanks again.

robert-hh avatar Feb 08 '25 17:02 robert-hh

Thanks @robert-hh for improving this PR, and @iabdalkader for testing.

Is this now ready to be merged?

dpgeorge avatar Feb 09 '25 11:02 dpgeorge

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.

robert-hh avatar Feb 09 '25 11:02 robert-hh