Our board is based on nRF52832 with S132 5.1.0, without RTOS. Now we have a requirement to protect sensitive memory areas with MPU, so I'm trying to run firmware in unprivileged mode (CONTROL=0x01), and I got Bus Fault in sd_app_evt_wait() handler. Should I use __WFE() instead, is it safe with SoftDevice enabled?
What do you mean by "I got a Bus Fault in sd_app_evt_wait()"?
If you use the softdevice, you can use sd_app_evt_wait(). This function calls __WFE() for you, but it doesn't wake up the application layer on softdevice events, so it is better to use sd_app_evt_wait() if you are using the SoftDevice.
To be precise, I added just one line in my app after BLE initialization:
__set_CONTROL(1); // Switch to non-privileged state
With __WFE() everything works fine (at least, I can connect and work with device). With sd_app_evt_wait(), my program is catched in BusFault_Handler once sd_app_evt_wait() is called. Diving deeper into bytecode, I found that SD internally leaves Handler mode in some tricky way, then calls __WFE() from Thread mode. The problem is that SD works with some NVIC or SCB registers that are protected from access in Thread mode.
Do I need some special configuration of M4 core registers? I just can't figure out where I'm wrong.
What happens if you use any other sd_xxx() SoftDevice API? Do they all fail the same way, or is it just the one particular API?
All of the SoftDevice APIs are actually system calls: they execute an svc instruction which triggers a supervisor call trap. I would think that once you enter the SVC trap handler, you would be back in privileged mode again.
Once thing I'm uncertain about here is the stack. There is both an MSP and PSP. When you use unprivileged/thread mode, I think the expectation would be to use the PSP, and then when you take an exception you'd be using the MSP. In your case, I think you're trying to use thread mode but with the MSP. I don't think that's usually how it works.
any other SD calls have no problems because as you said they're pure syscalls. But sd_app_evt_wait has two parts: syscall entry and thread mode continuation (surely, because we couldn't sleep in WFE inside a handler). Return instruction restores unpriviledged context.
About the stack - I didn't cnange SPSEL bit so both modes use MSP, since we have no RTOS this don't cause any stack overhead.
This is a bit outside my expertise, and you probably know more about this than me.
I found an old thread on DevZone discussing this here:
Maybe you can find some relevant information there. The Nordic Engineer who answered on that thread is currently out of office, but he will be back in the middle of next week. You can write your follow up questions here, and I will answer the best I can until he is back, and then I can ask him if we still haven't figured it out.