-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
mimxrt/bootloader: Enable support for the UF2 bootloader. #15983
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
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 ☔ View full report in Codecov by Sentry. |
Code size report:
|
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). |
ports/mimxrt/Makefile
Outdated
@@ -467,7 +474,13 @@ $(BUILD)/lib/tinyusb/src/device/usbd.o: CFLAGS += -Wno-missing-braces | |||
# Build targets | |||
# ============================================================================= | |||
|
|||
# Do not build the .uf2 target for MIMXRT1050_EVK, MIMXRT1170_EVK, Teensy40 and Teensy41 | |||
# These boards do not support the bootloader properly. | |||
ifneq ($(BOARD), $(filter $(BOARD), MIMXRT1050_EVK TEENSY40 TEENSY41 MIMXRT1170_EVK)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest adding a make variable to those boards that use the bootloader, instead of testing for specific boards. Eg USE_BOOTLOADER = 1
, and then here ifeq ($(USE_BOOTLOADER),1)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. I'll do. The default would be to use the bootloader.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This switch only controls the creation of the .uf2 file. The memory layout is the same for boards which do not use the uf2 bootloader. That reminds me of adding the rule to add the .uf2 file to the download page. I assume that a .uf2 file is silently skipped if missing.
ports/mimxrt/Makefile
Outdated
$(BUILD)/firmware.uf2: $(BUILD)/firmware.elf | ||
$(Q)$(OBJCOPY) -O binary -R .stack -R .ivt -R .flash_config $^ $@-binpart | ||
$(Q)$(PYTHON) $(TOP)/tools/uf2conv.py -b $(BOOTLOADER_SIZE) -f MIMXRT10XX -c -o $@ $@-binpart | ||
$(Q)rm $@-binpart |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file lives in the build directory so there's no need to remove it here.
You could also create a new rule for $(BUILD)/firmware.uf2_bin
that has the objcopy line from this rule, and then make this rule depend on that one. Similar to how samd does it.
Also I suggest making a UF2CONV
variable for uf2conv.py
, same as in samd.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK for the non-remove. I'll look into using the variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
ports/mimxrt/boards/common.ld
Outdated
@@ -90,10 +92,9 @@ SECTIONS | |||
. = ALIGN(4); | |||
} > m_interrupts | |||
|
|||
__VECTOR_RAM = __Vectors; | |||
__RAM_VECTOR_TABLE_SIZE_BYTES = 0x0; | |||
__Vectors_RAM = itcm_start; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be __Vectors_RAM = ORIGIN(m_isr)
instead? I know it's the same thing, but m_isr
seems more logical, and the source of truth here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That should work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
1. Load the MicroPython firmware directly to the device. The MicroPython | ||
firmware files for that method have the extension .bin or .hex and are available | ||
at the MicroPython download site. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will the .bin/.hex files work without having a bootloader installed? I don't think they will, because interrupts_start
and text_start
have been changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. They work. I tested that by erasing the flash of a device and then installing the .bin and .hex files. At Teensy this is the default. But to be sure, I'll repeat the test.
Loading a .bin, .hex or .elf file overwrites the bootloader. Being able to use the .elf file is convenient for debugging.
91d58d9
to
f8b12c1
Compare
@dpgeorge The changes you suggested are now implemented. I tested the PR again using:
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. |
f8b12c1
to
c2a86e0
Compare
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. |
ports/mimxrt/Makefile
Outdated
@@ -162,6 +163,13 @@ SRC_HAL_IMX_C += \ | |||
$(MCU_DIR)/drivers/fsl_romapi.c | |||
endif | |||
|
|||
# If not empty, then it is 10xx. | |||
ifneq ($(findstring MIMXRT10, $(MCU_SERIES)),) | |||
BOOTLOADER_SIZE := 0x6000C000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this variable would be better called APPLICATION_ADDR
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure I can change that, because that's what it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
c2a86e0
to
69079d7
Compare
@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. 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 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. |
574e47e
to
ab0d051
Compare
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 |
I'm not sure I understand the question, I never worked on this flash driver. However, note that 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. |
Thanks. I looked into the code of
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. |
ab0d051
to
7084737
Compare
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. |
@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. |
7084737
to
580d9e8
Compare
580d9e8
to
feddf6e
Compare
@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:
@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. |
feddf6e
to
f854433
Compare
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) |
b40abbc
to
95751b1
Compare
I'm going to test this on the weekend, haven't forgotten about it. |
95751b1
to
e7d8cc2
Compare
@iabdalkader OK. Don't worry. |
@robert-hh I programmed the bootloader:
Now when I copy |
The question is: a) does MicroPyhton run 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. |
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 |
Can you run at least twice the cycle:
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. |
I've already did, and it worked fine. I only tested |
Thank you for testing and confirming. One last question: Is it possible to write to the file system with MicroPython? For instance using mpremote. |
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. |
Allowing to use e.g. the Adafruit bootloaders 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. 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 Double reset is hard to achieve on MIMXRT boards, since there is no clean reset pin. Some MIMXRT boards provide it by switching the power. Some boards are excluded from the .uf2 build: - MIMXRT1050_EVK: The uf2 bootloader is built for the QSPI version of the board. MicroPython supports the Hyperflash version. - MIMXRT1176_EVK: No support for this board yet, but it should be possible. Signed-off-by: robert-hh <robert@hammelrath.com>
Changes: - Change the LUT table ordering to be similar to the order of the UF2-Bootloader and fsl_romapi.h. - Rewrite the LUT entry for PAGEPROGRAM_QUAD and update the LUT. That enabled QUAD program again. Signed-off-by: robert-hh <robert@hammelrath.com>
This change stopped problems with USB IRQ happening during flash writes. Signed-off-by: robert-hh <robert@hammelrath.com>
Signed-off-by: robert-hh <robert@hammelrath.com>
And use these to initialize the LUT table properly for the various flash types. The different flash types differ by 3 parameters. Thus it is easier to just keep one copy of the qspiflash_config structure with the LUT table and update it during flash initialisation as needed. Signed-off-by: robert-hh <robert@hammelrath.com>
The flash clock frequency may have been set to a different value by a bootloader. Set the frequency according to the configured value. Use a table of pre-calculated dividers to get the closest value for the flash frequency, achieving for MIMXRT10xx: 30 -> 30.85 MHz 50 -> 49.65 MHz 60 -> 60 MHz 75 -> 75.13 MHz 80 -> 80 MHz 100 -> 99.31 Mhz 133 -> 132.92 MHz 166 -> 166.15 MHz for MIMXRT1176: 30 -> 31 MHz 50 -> 52.8 MJz 60 -> 58.7 MHz 75 -> 75.4 MHz 80 -> 75.4 MHz 100 -> 105.6 MHz 133 -> 132 MHz 166 -> 176 MHz Signed-off-by: robert-hh <robert@hammelrath.com>
e7d8cc2
to
0a433a0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tested this on TEENSY40:
- build and flash the non-uf2 firmware using Teensy Loader
- flash tinyuf2 (using Teensy Loader)
- deploy MicroPython uf2 via MSC
- use
machine.bootloader()
to enter the bootloader - reflash non-uf2 version of MicroPython using Teensy Loader
All the above works! Very good.
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:
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:
Tested with:
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 8000 flash use acceptable.
Some boards are excluded from the .uf2 build: