Skip to content

Commit 46ba35e

Browse files
committed
Add MIMXRT1176 (i.MX RT1170) support with flash boot
Add support for MIMXRT1176 including direct flash boot (XIP) mode. Build system: - Add FLASH_BUILD=1 option for flash-resident builds - Fix UF2_MIMXRT1176_ADDR to 0x30000400 (FCFB at 0x400 offset) - Use MCU-specific memory.ld for MIMXRT1176 Linker scripts: - Add MIMXRT1176_flash.ld for XIP boot configuration - Update MIMXRT1176_memory.ld to support both RAM and flash builds Flash operations: - Fix SCB_InvalidateDCache_by_Addr to use absolute address instead of offset (was causing cache corruption on Cortex-M7) - Add XIP detection to skip FlexSPI re-init when running from flash - Add ROM_API_Init() call required for MIMXRT1176 USB support: - Add optional USB_PWR_PINMUX for boards with USB power control - Fix USB PHY PLL reference clock for RT1176 (24MHz, not 480MHz) Board support: - Add imxrt1170_evk board with clock configuration supporting both RAM (SDP) and flash (XIP) boot modes Other fixes: - Fix CFG_TUSB_MEM_ALIGN to 32 bytes for M7 DCache compatibility - Add MIMXRT1176-specific sources to family.cmake - Update README with RT1170-EVK and FLASH_BUILD documentation
1 parent 94117c4 commit 46ba35e

File tree

15 files changed

+803
-27
lines changed

15 files changed

+803
-27
lines changed

ports/mimxrt10xx/Makefile

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,26 @@ FLASH_BIN_ADDR = $(UF2_$(MCU)_WRITE_ADDR)
77
include ../make.mk
88
include port.mk
99

10+
# Support flash-resident builds with FLASH_BUILD=1
11+
# Default is RAM build for SDP loading
12+
# MIMXRT1176 uses its own memory layout file
13+
ifeq ($(MCU),MIMXRT1176)
14+
MEMORY_LD = $(PORT_DIR)/linker/$(MCU)_memory.ld
15+
else
16+
MEMORY_LD = $(PORT_DIR)/linker/memory.ld
17+
endif
18+
19+
ifeq ($(FLASH_BUILD),1)
20+
LD_FILES ?= \
21+
$(PORT_DIR)/linker/$(MCU)_flash.ld \
22+
$(MEMORY_LD) \
23+
$(PORT_DIR)/linker/common.ld
24+
else
1025
LD_FILES ?= \
1126
$(PORT_DIR)/linker/$(MCU)_ram.ld \
12-
$(PORT_DIR)/linker/memory.ld \
27+
$(MEMORY_LD) \
1328
$(PORT_DIR)/linker/common.ld
29+
endif
1430

1531
SRC_C += \
1632
$(PORT_DIR)/boards.c \
@@ -57,16 +73,24 @@ UF2_MIMXRT1042_ADDR= 0x60000000
5773
UF2_MIMXRT1052_ADDR= 0x60000000
5874
UF2_MIMXRT1062_ADDR= 0x60000000
5975
UF2_MIMXRT1064_ADDR= 0x70000000
60-
UF2_MIMXRT1176_ADDR= 0x30000000
76+
UF2_MIMXRT1176_ADDR= 0x30000400
77+
78+
# WRITE_ADDR used by flash-pyocd-bin target - same as UF2_ADDR for most chips
79+
UF2_MIMXRT1176_WRITE_ADDR= 0x30000400
6180

6281
SDP_PID = $(SDP_$(MCU)_PID)
6382
UF2_ADDR = $(UF2_$(MCU)_ADDR)
6483

6584
DBL_TAP_REG_ADDR = 0x400D410C
6685

6786
# extract _fcfb_origin and _ivt_origin from linker file
87+
ifeq ($(FLASH_BUILD),1)
88+
FCFB_ORIGIN := $(shell sed -n 's/_fcfb_origin.*\(0x.*\);/\1/p' $(TOP)/$(PORT_DIR)/linker/$(MCU)_flash.ld)
89+
IVT_ORIGIN := $(shell sed -n 's/_ivt_origin.*\(0x.*\);/\1/p' $(TOP)/$(PORT_DIR)/linker/$(MCU)_flash.ld)
90+
else
6891
FCFB_ORIGIN := $(shell sed -n 's/_fcfb_origin.*\(0x.*\);/\1/p' $(TOP)/$(PORT_DIR)/linker/$(MCU)_ram.ld)
6992
IVT_ORIGIN := $(shell sed -n 's/_ivt_origin.*\(0x.*\);/\1/p' $(TOP)/$(PORT_DIR)/linker/$(MCU)_ram.ld)
93+
endif
7094

7195
$(BUILD)/$(OUTNAME).hex: $(BUILD)/$(OUTNAME).elf
7296
@echo CREATE $@

ports/mimxrt10xx/README.md

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ To initially flash TinyUF2 on your blank board or board that is shipped with oth
88

99
### External Debugger
1010

11-
jlink or pyocd can be used to program .bin file to appropriate address on external flash which is typically **0x60000000** (RT1062) or **0x60000400** (RT1011). This can be done with `flash-jlink-bin` or `flash-pyocd-bin` make target.
11+
jlink or pyocd can be used to program .bin file to appropriate address on external flash which is typically **0x60000000** (RT1062), **0x60000400** (RT1011), or **0x30000400** (RT1170). This can be done with `flash-jlink-bin` or `flash-pyocd-bin` make target.
1212

1313
```
1414
make BOARD=metro_m7_1011 flash-jlink-bin
@@ -43,12 +43,80 @@ Note: Since SDP with BootROM doesn't requires external debugger and always exist
4343

4444
Double tap to enter bootloader mode, then simply drag & drop `update-tinyuf2_BOARD.uf2` into BOOT drive to update. The update file can be generated by running make with `self-update` target or simply download it from [release page](https://github.com/adafruit/tinyuf2/releases).
4545

46+
## RT1170/RT1176 Support
47+
48+
The RT1170/RT1176 requires a different flashing approach than other RT10xx chips. The SDP (Serial Download Protocol) method used by other chips does not work reliably for RT1170 because:
49+
- The RT1170 ROM bootloader uses `blhost` protocol instead of `sdphost`
50+
- Self-programming to flash is disabled for RT1176 builds
51+
52+
**For RT1170, you must use `FLASH_BUILD=1` and flash via a debugger.**
53+
54+
### Building for RT1170
55+
56+
```
57+
make BOARD=imxrt1170_evk FLASH_BUILD=1 all
58+
```
59+
60+
This creates a flash-resident (XIP) build that executes directly from flash. Key differences:
61+
- Uses `MIMXRT1176_flash.ld` linker script (code linked at 0x3000xxxx)
62+
- Data/BSS placed in DTCM (0x20000000)
63+
- Clock configuration preserves ROM bootloader settings when running from flash
64+
65+
The flash layout for RT1170 is:
66+
- **0x30000400**: FCFB (FlexSPI Configuration Block)
67+
- **0x30001000**: IVT (Image Vector Table)
68+
- **0x30002000**: Application code (vector table + text)
69+
70+
### RT1170-EVK Boot Switch Settings
71+
72+
The RT1170-EVK/EVKB uses SW1 (4-position DIP switch) to select boot mode:
73+
74+
| Mode | SW1[1] | SW1[2] | SW1[3] | SW1[4] | Description |
75+
|-------|--------|--------|--------|--------|-------------|
76+
| SDP | OFF | OFF | OFF | ON | Serial Download Mode (for debugger access) |
77+
| Flash | OFF | OFF | ON | OFF | Internal Boot from flash (normal operation) |
78+
79+
Note: OFF = switch down/open, ON = switch up/closed.
80+
81+
### Flashing TinyUF2 to RT1170-EVK
82+
83+
**Requirements:** A debug probe (MCU-Link on the EVK, or external J-Link/CMSIS-DAP) and LinkServer or equivalent flash tool.
84+
85+
**Procedure:**
86+
87+
1. Build the flash-resident version:
88+
```
89+
make BOARD=imxrt1170_evk FLASH_BUILD=1 clean all
90+
```
91+
92+
2. Connect the debug probe (MCU-Link is built into the EVK)
93+
94+
3. Set SW1 to Flash boot mode: **0-0-1-0** (only switch 3 ON)
95+
96+
4. Flash the ELF file using LinkServer:
97+
```
98+
LinkServer flash MIMXRT1176xxxxx:MIMXRT1170-EVK-CM7-ONLY erase
99+
LinkServer flash MIMXRT1176xxxxx:MIMXRT1170-EVK-CM7-ONLY load _build/imxrt1170_evk/tinyuf2-imxrt1170_evk.elf
100+
```
101+
102+
5. Reset the board - TinyUF2 should enumerate as USB mass storage device "RT1170BOOT"
103+
104+
**Alternative using pyocd** (if LinkServer is not available):
105+
```
106+
pyocd erase -t mimxrt1170_cm7 --chip
107+
pyocd load -t mimxrt1170_cm7 _build/imxrt1170_evk/tinyuf2-imxrt1170_evk.elf
108+
pyocd reset -t mimxrt1170_cm7
109+
```
110+
111+
Note: pyocd flash programming may not work reliably on all RT1170 boards. LinkServer is recommended.
112+
46113
## Supported Boards
47114

48115
- [Adafruit Metro M7 1011](https://www.adafruit.com/product/4950)
49116
- [MIMX RT1010 Evaluation Kit](https://www.nxp.com/design/development-boards/i.mx-evaluation-and-development-boards/i.mx-rt1010-evaluation-kit:MIMXRT1010-EVK)
50117
- [MIMX RT1020 Evaluation Kit](https://www.nxp.com/design/development-boards/i.mx-evaluation-and-development-boards/i.mx-rt1020-evaluation-kit:MIMXRT1020-EVK)
51118
- [MIMX RT1060 Evaluation Kit](https://www.nxp.com/design/development-boards/i.mx-evaluation-and-development-boards/mimxrt1060-evk-i.mx-rt1060-evaluation-kit:MIMXRT1060-EVK)
119+
- [MIMX RT1170 Evaluation Kit](https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/i-mx-rt1170-evaluation-kit:MIMXRT1170-EVK)
52120
- [Teensy 4.0](https://www.pjrc.com/store/teensy40.html)
53121
- [Teensy 4.1](https://www.pjrc.com/store/teensy41.html)
54122

ports/mimxrt10xx/board_flash.c

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ static uint8_t _flash_cache[SECTOR_SIZE] __attribute__((aligned(4)));
6363
// compare and write tinyuf2 to flash every time it is running
6464
#define COMPARE_AND_WRITE_TINYUF2 0
6565

66+
#if !defined(MIMXRT1176_cm7_SERIES)
6667
// Check if TinyUF2 running in SRAM matches the on flash contents
6768
static bool compare_tinyuf2_ram_vs_flash(void)
6869
{
@@ -98,25 +99,50 @@ static void write_tinyuf2_to_flash(void)
9899
board_flash_flush();
99100
TUF2_LOG1("TinyUF2 copied to flash.\r\n");
100101
}
102+
#endif // !defined(MIMXRT1176_cm7_SERIES)
103+
104+
// Check if we're executing from flash (XIP mode)
105+
// If PC is in the FlexSPI address range, skip FlexSPI re-initialization
106+
static inline bool is_running_from_flash(void) {
107+
extern char __isr_vector[];
108+
uint32_t vec_addr = (uint32_t)__isr_vector;
109+
return (vec_addr >= FLEXSPI_FLASH_BASE) && (vec_addr < (FLEXSPI_FLASH_BASE + 0x10000000));
110+
}
101111

102112
void board_flash_init(void)
103113
{
104-
ROM_FLEXSPI_NorFlash_Init(FLEXSPI_INSTANCE, flash_cfg);
114+
#if defined(MIMXRT1176_cm7_SERIES)
115+
// MIMXRT1176 requires ROM_API_Init to be called before using ROM API functions
116+
ROM_API_Init();
117+
#endif
118+
119+
// Skip FlexSPI initialization if already running from flash (XIP mode)
120+
// Re-initializing FlexSPI while executing from it would crash the system
121+
if (!is_running_from_flash()) {
122+
ROM_FLEXSPI_NorFlash_Init(FLEXSPI_INSTANCE, flash_cfg);
123+
}
105124

106125
// TinyUF2 will copy its image to flash if one of conditions meets:
107126
// - Boot Mode is '01' i.e Serial Download Mode (BootRom)
108127
// - Flash FCFB is invalid e.g blank flash
109128
// - Flash contents does not match running tinyuf2 in SRAM (depending on COMPARE_AND_WRITE_TINYUF2)
129+
//
130+
// NOTE: Self-flash is disabled for MIMXRT1176 because the code is linked for
131+
// RAM addresses and won't run correctly from flash. Use debugger to flash
132+
// firmware directly after using UF2 drag-drop.
133+
#if !defined(MIMXRT1176_cm7_SERIES)
110134
uint32_t const boot_mode = (SRC->SBMR2 & SRC_SBMR2_BMOD_MASK) >> SRC_SBMR2_BMOD_SHIFT;
111135
bool const fcfb_valid = (*(uint32_t*) FCFB_START_ADDRESS == FLEXSPI_CFG_BLK_TAG);
112136
bool const matched_flash = compare_tinyuf2_ram_vs_flash();
113137

138+
(void) boot_mode; // Used in TUF2_LOG1 which may be disabled
114139
TUF2_LOG1("Boot Mode = %lu, fcfb_valid = %u, matched_flash = %u\r\n", boot_mode, fcfb_valid, matched_flash);
115140

116-
if (boot_mode == 1 || !fcfb_valid || !matched_flash)
141+
if (!fcfb_valid || !matched_flash)
117142
{
118143
write_tinyuf2_to_flash();
119144
}
145+
#endif
120146
}
121147

122148
uint32_t board_flash_size(void)
@@ -151,7 +177,8 @@ void board_flash_flush(void)
151177
status = ROM_FLEXSPI_NorFlash_Erase(FLEXSPI_INSTANCE, flash_cfg, sector_addr, SECTOR_SIZE);
152178
__enable_irq();
153179

154-
SCB_InvalidateDCache_by_Addr((uint32_t *)sector_addr, SECTOR_SIZE);
180+
// Use absolute address for cache invalidation, not the offset
181+
SCB_InvalidateDCache_by_Addr((uint32_t *)_flash_page_addr, SECTOR_SIZE);
155182

156183
if ( status != kStatus_Success )
157184
{
@@ -175,7 +202,8 @@ void board_flash_flush(void)
175202
}
176203
}
177204

178-
SCB_InvalidateDCache_by_Addr((uint32_t *)sector_addr, SECTOR_SIZE);
205+
// Use absolute address for cache invalidation, not the offset
206+
SCB_InvalidateDCache_by_Addr((uint32_t *)_flash_page_addr, SECTOR_SIZE);
179207
}
180208

181209
_flash_page_addr = NO_CACHE;
@@ -210,9 +238,11 @@ void board_flash_erase_app(void)
210238
ROM_FLEXSPI_NorFlash_Init(FLEXSPI_INSTANCE, flash_cfg);
211239
ROM_FLEXSPI_NorFlash_EraseAll(FLEXSPI_INSTANCE, flash_cfg);
212240

241+
#if !defined(MIMXRT1176_cm7_SERIES)
213242
// write bootloader to flash
214243
TUF2_LOG1("Erase app firmware: ");
215244
write_tinyuf2_to_flash();
245+
#endif
216246
}
217247

218248
bool board_flash_protect_bootloader(bool protect)

ports/mimxrt10xx/boards.c

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,23 @@ void board_usb_init(void)
9797
{
9898
USBPHY_Type* usb_phy;
9999

100+
#ifdef USB_PWR_PINMUX
101+
// Enable USB power pin if defined by board (active high)
102+
IOMUXC_SetPinMux(USB_PWR_PINMUX, 0);
103+
IOMUXC_SetPinConfig(USB_PWR_PINMUX, 0x10B0U);
104+
gpio_pin_config_t usb_pwr_config = { kGPIO_DigitalOutput, 1, kGPIO_NoIntmode };
105+
GPIO_PinInit(USB_PWR_PORT, USB_PWR_PIN, &usb_pwr_config);
106+
#endif
107+
100108
#if BOARD_TUD_RHPORT == 0
101109
// Clock
110+
#if defined(MIMXRT1176_cm7_SERIES)
111+
// RT1176 USB PHY PLL expects reference clock frequency (24MHz from OSC24M)
112+
// PLL multiplies by 20 to get 480MHz: 24MHz * 20 = 480MHz
113+
CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 24000000U);
114+
#else
102115
CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
116+
#endif
103117
CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U);
104118

105119
#ifdef USBPHY1
@@ -110,7 +124,11 @@ void board_usb_init(void)
110124

111125
#elif BOARD_TUD_RHPORT == 1
112126
// USB1
127+
#if defined(MIMXRT1176_cm7_SERIES)
128+
CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usbphy480M, 24000000U);
129+
#else
113130
CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
131+
#endif
114132
CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, 480000000U);
115133
usb_phy = USBPHY2;
116134
#endif
@@ -121,10 +139,19 @@ void board_usb_init(void)
121139
// Enable all power for normal operation
122140
usb_phy->PWD = 0;
123141

124-
// TX Timing
142+
// TX Timing - use board-specific values if defined, otherwise defaults
143+
#ifndef BOARD_USB_PHY_D_CAL
144+
#define BOARD_USB_PHY_D_CAL (0x0CU)
145+
#endif
146+
#ifndef BOARD_USB_PHY_TXCAL45DP
147+
#define BOARD_USB_PHY_TXCAL45DP (0x06U)
148+
#endif
149+
#ifndef BOARD_USB_PHY_TXCAL45DM
150+
#define BOARD_USB_PHY_TXCAL45DM (0x06U)
151+
#endif
125152
uint32_t phytx = usb_phy->TX;
126153
phytx &= ~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK);
127-
phytx |= USBPHY_TX_D_CAL(0x0C) | USBPHY_TX_TXCAL45DP(0x06) | USBPHY_TX_TXCAL45DM(0x06);
154+
phytx |= USBPHY_TX_D_CAL(BOARD_USB_PHY_D_CAL) | USBPHY_TX_TXCAL45DP(BOARD_USB_PHY_TXCAL45DP) | USBPHY_TX_TXCAL45DM(BOARD_USB_PHY_TXCAL45DM);
128155
usb_phy->TX = phytx;
129156
}
130157

@@ -376,6 +403,10 @@ void board_uart_init(uint32_t baud_rate)
376403
uart_config.enableRx = true;
377404

378405
uint32_t freq;
406+
#if defined(MIMXRT117x_SERIES)
407+
// MIMXRT1176 uses different clock API - get clock from root configuration
408+
freq = CLOCK_GetRootClockFreq(kCLOCK_Root_Lpuart1);
409+
#else
379410
if (CLOCK_GetMux(kCLOCK_UartMux) == 0) /* PLL3 div6 80M */
380411
{
381412
freq = (CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 6U) / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
@@ -384,6 +415,7 @@ void board_uart_init(uint32_t baud_rate)
384415
{
385416
freq = CLOCK_GetOscFreq() / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
386417
}
418+
#endif
387419

388420
LPUART_Init(UART_DEV, &uart_config, freq);
389421
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
set(MCU_VARIANT MIMXRT1176)
2+
3+
set(JLINK_DEVICE MIMXRT1176xxxA_M7)
4+
set(PYOCD_TARGET mimxrt1170_cm7)
5+
set(NXPLINK_DEVICE MIMXRT1176xxxxx:MIMXRT1170-EVK)
6+
7+
function(update_board TARGET)
8+
target_sources(${TARGET} PRIVATE
9+
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/clock_config.c
10+
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/flash_config.c
11+
)
12+
target_compile_definitions(${TARGET} PUBLIC
13+
CPU_MIMXRT1176DVMAA_cm7
14+
MIMXRT117x_SERIES
15+
)
16+
endfunction()

0 commit comments

Comments
 (0)