Environment:
-
Chip: nRF52832
-
NCS Version: v2.8.0 (Zephyr OS v3.7.99)
-
Language: C++ (
main.cpp)
Issue Description: I am trying to implement a custom bare-metal I2C (TWIM0) application by bypassing the default Zephyr I2C driver to directly control the hardware registers. However, as soon as NRF_TWIM0->TASKS_STARTTX = 1; is called and the interrupt triggers, the system immediately crashes with an MPU FAULT (Instruction Access Violation).
The strangest part is that the faulting PC address is always pointing to a RAM address (e.g., 0x200010d0), which is located immediately after my RX/TX static arrays (rxd, txd). It seems the CPU is jumping to RAM to execute the ISR instead of the Flash memory, triggering the eXecute-Never (XN) violation.
What I have tried (Always with Pristine Builds):
-
Disabled
i2c0andspi0inapp.overlay(status = "disabled";) to prevent Zephyr from taking the IRQ 3. -
Set
CONFIG_I2C=ninprj.conf. -
Tried standard
IRQ_CONNECTwithvoid TWIM0_IRQHandler(const void *args). -
Tried
irq_connect_dynamic()withCONFIG_DYNAMIC_INTERRUPTS=y. -
Currently using
ISR_DIRECT_DECLAREandIRQ_DIRECT_CONNECT.
Despite all these attempts to take over the interrupt cleanly, the exact same MPU FAULT occurs pointing to a RAM address.
Error log:
*** Booting nRF Connect SDK v2.8.0-a2386bfc8401 *** *** Using Zephyr OS v3.7.99-0bc3393fb112 *** Rxd addr: 0x200010b4, Txd addr: 0x200010a0 [00:00:00.405,792] <err> os: ***** MPU FAULT ***** [00:00:00.405,822] <err> os: Instruction Access Violation [00:00:00.405,822] <err> os: r0/a1: 0x00007cd8 r1/a2: 0x000000c0 r2/a3: 0xe000e100 [00:00:00.405,853] <err> os: r3/a4: 0x00000001 r12/ip: 0x00000004 r14/lr: 0xfffffffd [00:00:00.405,853] <err> os: xpsr: 0x00000013 [00:00:00.405,853] <err> os: Faulting instruction address (r15/pc): 0x200010d0 [00:00:00.405,914] <err> os: >>> ZEPHYR FATAL ERROR 20: Unknown error on CPU 0 [00:00:00.405,914] <err> os: Fault during interrupt handling [00:00:00.405,944] <err> os: Current thread: 0x20000f20 (main) [00:00:00.700,561] <err> os: Halting system
Source: main.cpp
#include <Configure.h>
#include <setup.h>
#include <zephyr/irq.h>
static uint8_t rxd[20] = {0};
static uint8_t txd[20] = {0};
static void TWIM0_IRQHandler();
int main(void){
NRF_TWIM0->PSEL.SDA = TWIM_PIN_SDA;
NRF_TWIM0->PSEL.SCL = TWIM_PIN_SCL;
NRF_TWIM0->FREQUENCY = 0x06400000;
NRF_TWIM0->RXD.PTR = (uint32_t)rxd;
NRF_TWIM0->RXD.MAXCNT = sizeof(rxd);
NRF_TWIM0->TXD.PTR = (uint32_t)txd;
NRF_TWIM0->TXD.MAXCNT = sizeof(txd);
NRF_TWIM0->INTENSET = (1 << 23) | (1 << 24) | (1 << 20);
printk("Rxd addr: %p, Txd addr: %p\r\n", rxd, txd);
//IRQ_DIRECT_CONNECT(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn, 5, TWIM0_IRQHandler, 0);
IRQ_CONNECT(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn, 5, TWIM0_IRQHandler, NULL, 0);
irq_enable(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn);
NRF_TWIM0->ENABLE = 0x06;
NRF_TWIM0->SHORTS = (1 << 9);
NRF_TWIM0->ADDRESS = ICM42670_ADDR0;
txd[0] = ICM42670_PWR_MGMT0;
txd[1] = 0x9F;
NRF_TWIM0->TXD.MAXCNT = 2;
NRF_TWIM0->TASKS_STARTTX = 1;
while(true){
printk("TEST\r\n");
k_msleep(1000);
}
return 0;
}
void TWIM0_IRQHandler(){
//printk("tESTTEST\r\n");
if(NRF_TWIM0->EVENTS_TXSTARTED == 1){
NRF_TWIM0->EVENTS_TXSTARTED = 0;
//printk("EVENTS_STOPPED\r\n");
}
if(NRF_TWIM0->EVENTS_LASTRX == 1){
NRF_TWIM0->EVENTS_LASTRX = 0;
//printk("EVENTS_LASTRX\r\n");
}
if(NRF_TWIM0->EVENTS_LASTTX == 1){
NRF_TWIM0->EVENTS_LASTTX = 0;
//printk("EVENTS_LASTTX\r\n");
}
}
prj.conf
# General Configuration CONFIG_CPP=y CONFIG_STD_CPP17=y CONFIG_MAIN_STACK_SIZE=2048 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 CONFIG_HEAP_MEM_POOL_SIZE=4096 # Logging Configuration CONFIG_CONSOLE=y CONFIG_LOG=y CONFIG_LOG_PROCESS_THREAD_STACK_SIZE=2048 CONFIG_LOG_BUFFER_SIZE=2048 CONFIG_LOG_DEFAULT_LEVEL=2 CONFIG_RTT_CONSOLE=y CONFIG_USE_SEGGER_RTT=y CONFIG_NO_OPTIMIZATIONS=y CONFIG_I2C=n

