We are experiencing a consistent hardfault when trying to access pins in GPIO bank 0 from M4 core 0 with linux booted. The gpio0 device has been deleted from the linux device tree. When we stop the boot process before linux boots, we are able to use LSIO.GPIO0.IO08 to trigger an interrupt and handle it in LSIO_GPIO_INT0_IRQHandler, and then use GPIO_PortGetInterruptFlags to read back the flags and see this which pin caused the interrupt to be triggered.
Once booted into linux, GPIO_PortGetInterruptFlags causes a hard fault (Again, with gpio0 deleted from the device tree – also tested with disabled; same result). Relevant stack on the m4 as far as we can trace it is at the end of this message. Are we missing a step to prevent the linux system from reserving the memory, in addition to removing the node from the device tree?
(gdb) bt
#0 HardFault_Handler () at /home/matt/.platformio/packages/framework-imx8m4-maidbot/framework/devices/MIMX8QM6/gcc/startup_MIMX8QM6_cm4_core0.S:883
#1
#2 0x1ffe10aa in GPIO_PortGetInterruptFlags (base=0x5d080000) at /home/matt/.platformio/packages/framework-imx8m4-maidbot/framework/devices/MIMX8QM6/drivers/fsl_gpio.h:295
#3 LSIO_GPIO_INT0_IRQHandler () at src/test/gpio_test.c:43
#4 0x1ffe23de in IRQSTEER_CommonIRQHandler (base=0x51070000, intMasterIndex=kIRQSTEER_InterruptMaster2)
at /home/matt/.platformio/packages/framework-imx8m4-maidbot/framework/devices/MIMX8QM6/drivers/fsl_irqsteer.c:156
#5 0x1ffe2424 in IRQSTEER_2_DriverIRQHandler () at /home/matt/.platformio/packages/framework-imx8m4-maidbot/framework/devices/MIMX8QM6/drivers/fsl_irqsteer.c:188
#6
#7 0x1ffe118e in TSTMR_ReadTimeStamp (base=0x414100f0) at /home/matt/.platformio/packages/framework-imx8m4-maidbot/framework/devices/MIMX8QM6/drivers/fsl_tstmr.h:75
#8 TSTMR_DelayUs (delayInUs=10000, base=0x414100f0) at /home/matt/.platformio/packages/framework-imx8m4-maidbot/framework/devices/MIMX8QM6/drivers/fsl_tstmr.h:70
#9 main () at src/test/gpio_test.c:110
(gdb) up
#1
(gdb) up
#2 0x1ffe10aa in GPIO_PortGetInterruptFlags (base=0x5d080000) at /home/matt/.platformio/packages/framework-imx8m4-maidbot/framework/devices/MIMX8QM6/drivers/fsl_gpio.h:295
295 return base->ISR;
(gdb) p base
$1 = (GPIO_Type *) 0x5d080000
(gdb) p base->ISR
Cannot access memory at address 0x5d080018
Here’s the relevant test (gpio_test.c).
#include "fsl_device_registers.h"
#include "fsl_debug_console.h"
#include "board.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "fsl_lpuart.h"
#include "fsl_irqsteer.h"
#include "fsl_tstmr.h"
#define BUTTON_GPIO_BANK LSIO__GPIO0
#define BUTTON_GPIO_IRQn LSIO_GPIO_INT0_IRQn
#define BUTTON_1_GPIO_PIN 8U
#define BUTTON_2_GPIO_PIN 9U
#define DELAY_MS(ms) (TSTMR_DelayUs(CM4_0__TSTMR, ms*1000))
#define PIN_TO_FLAG(pin) (1 << pin)
//
// get the NVIC IRQn of given IRQSTEER IRQn
//
// (found in examples/boards/mekmimx8qm/demo_apps/power_mode_switch/cm4_core1/lpm.c)
//
#define GET_IRQSTEER_MASTER_IRQn(IRQn) \
(IRQn_Type)(IRQSTEER_0_IRQn + (IRQn - FSL_FEATURE_IRQSTEER_IRQ_START_INDEX) / 64U)
volatile static bool button_1_pressed = false;
volatile static bool button_2_pressed = false;
/*!
* @brief Interrupt handler
*/
void LSIO_GPIO_INT0_IRQHandler(void)
{
uint32_t flags = GPIO_PortGetInterruptFlags(BUTTON_GPIO_BANK);
if (flags & PIN_TO_FLAG(BUTTON_1_GPIO_PIN))
{
button_1_pressed = true;
GPIO_PortClearInterruptFlags(BUTTON_GPIO_BANK, PIN_TO_FLAG(BUTTON_1_GPIO_PIN));
}
if (flags & PIN_TO_FLAG(BUTTON_2_GPIO_PIN))
{
button_2_pressed = true;
GPIO_PortClearInterruptFlags(BUTTON_GPIO_BANK, PIN_TO_FLAG(BUTTON_2_GPIO_PIN));
}
}
/*!
* @brief Main function
*/
int main(void)
{
sc_ipc_t ipc = BOARD_InitRpc();
BOARD_InitPins(ipc);
BOARD_BootClockRUN();
BOARD_InitMemory();
BOARD_InitDebugConsole();
if (sc_pm_set_resource_power_mode(ipc, SC_R_GPIO_0, SC_PM_PW_MODE_ON) != SC_ERR_NONE)
{
PRINTF("Error: Failed to power on GPIO\r\n");
}
if (sc_pm_set_resource_power_mode(ipc, SC_R_IRQSTR_M4_0, SC_PM_PW_MODE_ON) != SC_ERR_NONE)
{
PRINTF("Error: Failed to power on IRQSTEER!\r\n");
}
IRQSTEER_Init(IRQSTEER);
gpio_pin_config_t button_config = {kGPIO_DigitalInput, 1, kGPIO_IntRisingEdge};
GPIO_PinInit(BUTTON_GPIO_BANK, BUTTON_1_GPIO_PIN, &button_config);
GPIO_PinInit(BUTTON_GPIO_BANK, BUTTON_2_GPIO_PIN, &button_config);
// clear all flags in this GPIO bank
GPIO_PortClearInterruptFlags(BUTTON_GPIO_BANK, 0xFFFFFFFF);
// enable interrupting on both GPIOs
GPIO_PortEnableInterrupts(BUTTON_GPIO_BANK, PIN_TO_FLAG(BUTTON_1_GPIO_PIN));
GPIO_PortEnableInterrupts(BUTTON_GPIO_BANK, PIN_TO_FLAG(BUTTON_2_GPIO_PIN));
// enable the IRQ handler
IRQSTEER_EnableInterrupt(IRQSTEER, BUTTON_GPIO_IRQn);
EnableIRQ(GET_IRQSTEER_MASTER_IRQn(BUTTON_GPIO_IRQn));
// poll button state forever
while (1)
{
if (button_1_pressed)
{
PRINTF("button 1 pressed\r\n");
button_1_pressed = false;
}
if (button_2_pressed)
{
PRINTF("button 2 pressed\r\n");
button_2_pressed = false;
}
DELAY_MS(10);
}
return 0;
}