This post was last edited by cruelfox on 2020-4-30 00:46
I have been playing with the Cortex-A7 core of the STM32MP157A because it is new to me. In addition to the two A7 cores, this chip is also equipped with a Cortex-m4 core. However, the M4 core is "lower" in status, and the A7 core is the leader in terms of access rights to on-chip devices. There is no Flash inside the STM32MP157A, and the Boot ROM is only for the A7 core to run, so the program running on the M4 core needs to be provided to it by the A7 core. This also has greater flexibility, and software can be dynamically loaded for the M4 core when Linux is running.
STM32MP157 has an "Engineering Mode" for debugging. On the DK1 development board, you can set the BOOT switch below to BOOT0=0, BOOT2=1 to enter "Engineering Mode" (described on the wiki, but not in the datasheet, which is only described as "Reserved(Noboot)"). In this mode, the ROM Bootloader will start the M4 core, and you can use OpenOCD to debug the M4 core program. When I debugged before, the status of cpu2 (corresponding to the M4 core) listed by OpenOCD was always "examine deferred", so it could not be accessed.
But after I changed the BOOT status and restarted the machine, I found that cpu2 was still "examine deferred". It seems to be a problem with the debugger itself. Later I found the answer on the Internet-you also need to use the set ENG_MODE 1 command in OpenOCD. In this way, you can switch to debugging the M4 core.
This is a bit like the debugging of the old STM32, except that there is no Flash, and you can't reset init and stop at the first instruction. The two A7 cores remain running, and after the switch, the halt command is only valid for cpu2. (Before the switch, it was valid for cpu0 and cpu1 together, and you can't stop cpu0 or cpu1 alone. I don't understand this problem)
To test the M4 core, I took an old program and modified it:
int main(void)
{
gpio_config();
xTaskCreate( blink1, "Blink One", STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL );
xTaskCreate( blink2, "Blink Two", STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL );
xTaskCreate( blink3, "Blink Three", STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL );
xTaskCreate( blink4, "Blink Four", STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL );
vTaskStartScheduler();
}
I built a FreeRTOS framework and used four tasks to operate the GPIO flip at different time intervals to make different LEDs turn on and off. The GPIO register operation is the same as that of STM32F4, but the operation of enabling GPIO in RCC is different from that of STM32F4. I found this when I was writing the A7 program. Since it does not involve competing for resources with the A7 core, I will not consider other issues.
In addition to the necessary register definition header file stm32mp157axx_cm4.h, you can also find the startup_stm32mp15xx.s startup file (including interrupt vector table, ResetHandler code) and stm32mp15x_m4.ld link script in the development software package. This is enough to compile the program with GCC. Note the description of memory allocation in the provided LD script:
MEMORY
{
m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000298
m_text (RX) : ORIGIN = 0x10000000, LENGTH = 0x00020000
m_data (RW) : ORIGIN = 0x10020000, LENGTH = 0x00020000
m_ipc_shm (RW) : ORIGIN = 0x10040000, LENGTH = 0x00008000
}
The programs executed by the M4 core are stored in several SRAMs, which do not interfere with the SYSRAM of the A7 core. The HEX file is compiled and can be loaded and run with OpenOCD. The operation commands are as follows:
> load_image f:/test.hex
664 bytes written at address 0x00000000
3076 bytes written at address 0x10000000
downloaded 3740 bytes in 0.031250s (116.875 KiB/s)
> mdw 0 2
0x00000000: 10040000 10000b71
> reg sp 0x10040000
sp (/32): 0x10040000
> reg pc 0x10000b71
pc (/32): 0x10000B71
> resumeAlthough
the interrupt vector table is written at 0x0, it can only be loaded at reset. Now we can only modify the SP and PC registers to initialize manually. Finally, use the resume command to make the M4 core run.
So only Engineer mode can debug the M4 core? Of course not, it is just that the ROM bootloader enables the core in this mode. By default, the M4 core is stopped and needs software to enable it:
The manual says that the BOOT_MCU bit (in the MP_GCR register of RCC) is set to 1, and the MCU will not leave the Stop state until it is reset. So I will test it: put the board into normal boot mode, power it on, boot to U-Boot and press a key in the terminal when prompted to let u-boot wait. Then start OpenOCD and connect the board using set ENG_MODE 1. At this time, check the status of the M4 core and you will see a difference:
> targets
TargetName Type Endian TapName State
-- ------------------ ---------- ------ ------- ----------- ------------
0* stm32mp15x.cpu0 cortex_a little stm32mp15x.tap running
1 stm32mp15x.cpu1 cortex_a little stm32mp15x.tap running
2 stm32mp15x.axi mem_ap little stm32mp15x.tap running
3 stm32mp15x.ap1 mem_ap little stm32mp15x.tap running
4 stm32mp15x.cpu2 cortex_m little stm32mp15x.tap unknown
5 stm32mp15x.ap2 mem_ap little stm32mp15x.tap unknown
Because it is still in CStop state, I will try to set BOOT_MCU to 1 (register address 0x5000010C):
> mdw 0x5000010c
0x5000010c: 00000000
> mww 0x5000010c 1
> mdw 0x5000010c
0x5000010c: 00000001
Then reset the MCU. Of course, pressing the reset switch does not work, and it cannot reset other parts. From the manual, I found this register:
Bit 2 is MCURST, writing 1 can reset the MCU. So execute:
> mww 0x50000404 2
> targets
TargetName Type Endian TapName State
-- ------------------ ---------- ------ --- --------------- ------------
0* stm32mp15x.cpu0 cortex_a little stm32mp15x.tap halted
1 stm32mp15x.cpu1 cortex_a little stm32mp15x.tap halted
2 stm32mp15x .axi mem_ap little stm32mp15x.tap running
3 stm32mp15x.ap1 mem_ap little stm32mp15x.tap running
4 stm32mp15x.cpu2 cortex_m little stm32mp15x.tap unknown
5 stm32mp15x.ap2 mem_ap little stm32mp15x.tap unknown
But OpenOCD still doesn't recognize the status of this core? It may be a problem with OpenOCD, so I quit OpenOCD, reconnected, and checked the status - OK, cpu2 is halted.
Then I can load the program into SRAM, using the same load_image command. Then, I reset the MCU to let it get the entry address from the interrupt vector table.
> targets stm32mp15x.cpu2
> load_image f:/test.hex
664 bytes written at address 0x00000000
3076 bytes written at address 0x10000000
downloaded 3740 bytes in 0.031250s (116.875 KiB/s)
> targets stm32mp15x.cpu0
> mww 0x50000404 2
The operation of resetting the MCU must be performed by the MCU, so you need to switch targets in OpenOCD.
From the LED flashing status I can determine that the M4 core program has run normally.
The A7 core is still in the halted state, so I resume it and let U-Boot do the rest: boot Linux. The LED continues to flash, and then during the Linux system boot, the flashing stops - I think Linux has taken over the GPIO, so the M4 program cannot operate them. In OpenOCD, I can no longer debug the M4 core, so it seems that Linux has interfered with the operation of the M4. I will only know this if I dig deeper...
Getting the A7 and M4 cores to work together is a more advanced topic. The STM32MP157 has some hardware designed to allow communication between the MPU and MCU subsystems, and there are corresponding supporting frameworks in software. If Linux is put into Suspend to RAM mode, the M4 core is kept running at low power to handle simple tasks, and the A7 core is woken up to resume Linux execution only when needed, which will save more power than a pure Linux system.
This content is originally created by cruelfox , a user on the EEWORLD forum. If you want to reprint or use it for commercial purposes, you must obtain the author's consent and indicate the source