Cortex-M7 + MPU

karsa wrote on Monday, May 21, 2018:

FreeRTOS has a documented MPU port for CM3 and CM4F. Has anyone attempted to adapt/port MPU functions to a CM7?

The only post I can find thus far is this one which seems to be more about using the MPU in the application generally, but not for RTOS task protection.

CM7 seems to be a superset of MPU-related functions compared to CM4 (namely, it has more registers), so I’m wondering if the CM4 port functions for the MPU would “just work” with the existing CM7 port.

My specific processor is an ST Cortex-M7 STM32F746ZG.

Could use either FreeRTOS 9 or 10. Considering down-sizing to CM4 just so we can more easily leverage the MPU.

Any ideas?

rtel wrote on Monday, May 21, 2018:

I’m not aware of any reasons that would prevent the Cortex-M4F MPU port
running on an M7. If you find any, then let us know!

karsa wrote on Tuesday, May 22, 2018:

When diff-ing the CM4 port to the CM7 port, I see there’s almost no difference except for some special CM7 instructions to enable/disable privileged mode. The line of code indicates an errata workaround using cpsid/cpsie instructions, but it’s not yet clear what the errata are.

void xPortPendSVHandler( void )
	"	cpsid i								\n" /* Errata workaround. */
	"	msr basepri, r0						\n"
	"	dsb									\n"
	"	isb									\n"
	"	cpsie i								\n" /* Errata workaround. */

Presumably, we’ll need to merge these instructions to the CM4 MPU port version of this function to get it running properly on the CM7, but that should be it.

Thanks for the feedback!

rtel wrote on Tuesday, May 22, 2018:

That is only necessary if you are using a very early version of the M7
core, r0p1 I seem to recall but the core version is detailed in the name
of the directory the posted code comes from.

pairadox wrote on Wednesday, May 30, 2018:

I’ve been working on getting the FreeRTOS(version 10) CM4 MPU port to run on the CM7. I was finally able to get the port working after a little bit. But I did run into one problem and would like some feedback on how I resolved it.

In port.c I was having trouble with the function “static void prvRestoreContextOfFirstTask( void )”
The following lines:

	"	ldmia r1!, {r4-r11}				\n" /* Read 4 sets of MPU registers. */
	"	stmia r2!, {r4-r11}				\n" /* Write 4 sets of MPU registers. */
	"	ldmia r0!, {r3-r11, r14}		\n" /* Pop the registers that are not automatically saved on exception entry. */

The first two instructions load the MPU configuration from the TCB. However the last instruction which should be loading the stack frame from the task stack would load r3-r11 and r14 with zero.

I eventually found that this appears to be caused by having the Data cache enabled. When I turned off data caching the issue went away.

I do want data caching enabled so before the assembly block a make a call to invalidate and clean the data cache before resorting the first task context (SCB_CleanInvalidateDCache()). This appears to work and have no lasting side-effects.

I just wanted to see if this is the right approach to solve the cache coherence issue and if this is a known issue.


rtel wrote on Wednesday, May 30, 2018:

Sounds reasonable, but I wonder if all you need are memory barriers
here. When you push the registers they are in fact being written to the
MPU, so perhaps as the hardware is being updated you need some ISB and
DSB instructions after the write to wait for the the writes to complete.
That is something that could show up on the M7 but not the M4. The M4
port was updated when the M7 was launched to ensure it could be used on
both - the only real difference being the additional data and
instruction barrier instructions and it might be they are also needed in
the MPU port which was not running on M7s before (perhaps contrary to my
previous remark that there should be no reasons why it could not be used
on the M7 too!).