I’m currently working on a project involving the Sparkfun Thing+ and have been struggling with setting up interrupt routines. Despite following the examples provided in the repository, I am unable to get the blue LED to light up, and the button press interrupt isn’t being detected. I’m hoping someone here can help me identify what I’m doing wrong or missing. Any advice would be greatly appreciated!
Problem Overview
Based on the examples, it seems that the process should be straightforward. I need to configure the PAD/GPIO for the desired interrupt in the exceptions
file and then set up the handler to clear the flags and execute the desired function. In my case, I want to detect button presses, so my GPIO configuration looks like this:
GPIOCfgTypeDef gpiocfg_table =
{
{
// Example setting for PAD_11 (sensor interrupt 5)
.usPadNum = PAD_11,
.ucGpioNum = GPIO_2,
.ucFunc = PAD11_FUNC_SEL_SENS_INT_5,
.intr_type = EDGE_TRIGGERED,
.pol_type = FALL_LOW,
.ucPull = PAD_PULLUP,
},
};
Handler Setup
I’ve set up the interrupt handler as follows:
void SensorGpio_Handler(void)
{
NVIC_DisableIRQ(Gpio_IRQn);
uint32_t intrCtrl;
intrCtrl = INTR_CTRL->GPIO_INTR;
if(intrCtrl & (1 << GPIO_2))
{
INTR_CTRL->GPIO_INTR |= (1 << GPIO_2);
buttontoggle();
}
NVIC_ClearPendingIRQ(Gpio_IRQn);
NVIC_EnableIRQ(Gpio_IRQn);
}
Main Code (main.c
)
Here is the relevant section of my main.c
file:
#include “Fw_global_config.h” // This defines application-specific characteristics
#include <stdio.h>
#include “FreeRTOS.h”
#include “task.h”
#include “semphr.h”
#include “timers.h”
#include “RtosTask.h”
/* Include the generic headers required for QORC */
#include “eoss3_hal_gpio.h”
#include “eoss3_hal_rtc.h”
#include “eoss3_hal_fpga_usbserial.h”
#include “s3x_clock_hal.h”
#include “s3x_clock.h”
#include “s3x_pi.h”
#include “dbg_uart.h”
#include “cli.h”
#include “fpga_loader.h” // API for loading FPGA
#include “gateware.h” // FPGA bitstream to load into FPGA
#include “Bootconfig.h”
#include <stdint.h>
#include <stdbool.h>
/*
- Global variable definition
*/
#define USER_BUTTON_GPIO_NUM (0) // PAD 6, GPIO is connected to User Button
#define BLUE_LED_GPIO_NUM (4) // PAD 18, GPIO is connected to Blue LED
#define GREEN_LED_GPIO_NUM (5) // PAD 21, GPIO is connected to Green LED
#define RED_LED_GPIO_NUM (6) // PAD 22, GPIO is connected to Red LED
extern void qf_hardwareSetup();
static void nvic_init(void);
static void leds(void);
void buttontoggle(void);
uint8_t val = 1;
int main(void)
{
qf_hardwareSetup();
nvic_init();
load_fpga(axFPGABitStream_length, axFPGABitStream);
// Use 0x6141 as USB serial product ID (USB PID)
HAL_usbserial_init2(true, false, 0x6141); // Start USB serial not using interrupts
for (int i = 0; i != 4000000; i++) ; // Give it time to enumerate
dbg_str("\n\n");
dbg_str("##########################\n");
dbg_str("Sparkfun Thing+ LED / User Button Test\n");
dbg_str("##########################\n\n");
dbg_str("\n\nHello world!!\n\n"); // <<<<<<<<<<<<<<<<<<<<< Change me!
/* Start the tasks and timer running. */
vTaskStartScheduler();
dbg_str("\n");
HAL_GPIO_Write(BLUE_LED_GPIO_NUM, 1);
while(1);
}
static void nvic_init(void)
{
// To initialize the system, this interrupt should be triggered at main.
// So, we will set its priority just before calling vTaskStartScheduler(), not at the time of enabling each IRQ.
NVIC_SetPriority(Ffe0_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
NVIC_SetPriority(SpiMs_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
NVIC_SetPriority(CfgDma_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
NVIC_SetPriority(Uart_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
NVIC_SetPriority(FbMsg_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
}
// needed for startup_EOSS3b.s asm file
void SystemInit(void)
{
}
void buttontoggle(void)
{
uint8_t ucVal_boton = 0;
HAL_GPIO_Read(2, &ucVal_boton);
if (ucVal_boton != 1) {
for (uint32_t i = 0; i < 1152001; i++) {
dbg_str("");
}
HAL_GPIO_Read(2, &ucVal_boton);
if (ucVal_boton != 1) {
if(val == 1){
val = 0;
}
else{
val = 1;
}
HAL_GPIO_Write(BLUE_LED_GPIO_NUM, val);
}
for (int i = 0; i < 1152001; i++){
dbg_str("");
}
}
}
qf_hardwaresetup.c
#include “Fw_global_config.h”
#include “eoss3_hal_gpio.h”
#include “eoss3_hal_pads.h”
#include “eoss3_hal_pad_config.h”
#include “eoss3_hal_spi.h”
#include “eoss3_hal_uart.h”
#include “s3x_clock.h”
#include “spi_flash.h”
#include “FreeRTOS.h”
#include “task.h”
#include “FreeRTOSConfig.h”
#include “string.h”
extern PadConfig pincfg_table;
extern GPIOCfgTypeDef gpiocfg_table;
extern int sizeof_pincfg_table ;
extern int sizeof_gpiocfg_table;
static void ldo_init(void);
static void system_init(void);
static void uart_setup(void);
static void SPIM_Setup(void);
void qf_hardwareSetup(void) {
SCnSCB->ACTLR |= SCnSCB_ACTLR_DISDEFWBUF_Msk;
S3x_pwrcfg_init();
system_init();
ldo_init();
configure_s3_gpio_interrupts(gpiocfg_table, sizeof_gpiocfg_table);
configure_s3_pads(pincfg_table, sizeof_pincfg_table);
uart_setup();
SPIM_Setup();
}
//Initialize all System Clocks,Gate settings and used Power Resources
static void system_init(void)
{
S3x_Clk_Enable(S3X_M4_S0_S3_CLK);
S3x_Clk_Enable(S3X_M4_S4_S7_CLK);
S3x_Clk_Enable(S3X_M4_S8_S11_CLK);
S3x_Clk_Enable(S3X_M4_S12_S15_CLK);
/* FPU settings ------------------------------------------------------------*/
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
/* Configure Memory to support light sleep and retention mode */
PMU->M4SRAM_SSW_LPMF = 0xFFFF;
PMU->M4SRAM_SSW_LPMH_MASK_N = 0xFFFF;
S3x_Clk_Enable(S3X_FB_16_CLK);
S3x_Clk_Enable(S3X_FB_21_CLK);
S3x_Clk_Enable(S3X_A1_CLK);
S3x_Clk_Enable(S3X_CFG_DMA_A1_CLK);
INTR_CTRL->OTHER_INTR = 0xffffff;
DMA_SPI_MS->DMA_CTRL = DMA_CTRL_STOP_BIT;
}
static void ldo_init(void)
{
/* LDO Settings /
//AIP->LD0_30_CTRL_0 = 0x1ac; // LDO Enable / 0x1ac → Vo =1.01V, imax = 7.2mA, LDO enabled. /
//AIP->LD0_50_CTRL_0 = 0x1ac; // LDO Enable
AIP->LD0_30_CTRL_0 = 0x28c; // LDO Enable / 0x28c → Vo =1.15V, imax = 7.2mA, LDO enabled. /
AIP->LD0_50_CTRL_0 = 0x28c; // LDO Enable
}
/
-
Setup the SPI master for Flash chip
*/
static void SPIM_Setup(void)
{
//SPI master init for SPI flash
spiFlashHandle.Init.ucFreq = SPI_BAUDRATE_5MHZ; //above 5MHz does not work
spiFlashHandle.Init.ucSPIInf = SPI_4_WIRE_MODE;
spiFlashHandle.Init.ucSSn = SPI_SLAVE_1_SELECT;
spiFlashHandle.Init.ulCLKPhase = SPI_PHASE_1EDGE;
spiFlashHandle.Init.ulCLKPolarity = SPI_POLARITY_LOW;
spiFlashHandle.Init.ulDataSize = SPI_DATASIZE_8BIT;
spiFlashHandle.Init.ulFirstBit = SPI_FIRSTBIT_MSB;
spiFlashHandle.ucSPIx = SPI1_MASTER_SEL;
if(HAL_SPI_Init(&spiFlashHandle) != HAL_OK)
{
printf(“HAL_SPI1_Init failed\r\n”);
configASSERT(0); //will hang here with out flash access
return;
}
//make sure there is a Flash chip
if(read_flash_id() == 0)
{
configASSERT(0); //will hang here if cannot read flash
}
return;
}
/*
-
Setup the UART for 115200bps
*/
static void uart_setup(void)
{
int uart_id;
UartBaudRateType brate;
UartHandler uartObj;
memset( (void *)&(uartObj), 0, sizeof(uartObj) );
uart_id = UART_ID_HW;
brate = BAUD_115200;
uartObj.baud = brate;
uartObj.wl = WORDLEN_8B;
uartObj.parity = PARITY_NONE;
uartObj.stop = STOPBITS_1;
uartObj.mode = TX_RX_MODE;
uartObj.hwCtrl = HW_FLOW_CTRL_DISABLE;
uartObj.intrMode = UART_INTR_ENABLE;
uart_init( uart_id, NULL, NULL, &uartObj);
}
HAL_StatusTypeDef HAL_GPIO_IntrCfg(GPIOCfgTypeDef *hGpioCfg)
{
uint32_t *pRegOffset;
PadConfig xPadConf;
//configure the PAD as GPIO
xPadConf.ucPin = hGpioCfg->usPadNum;
xPadConf.ucFunc = hGpioCfg->ucFunc;
xPadConf.ucCtrl = PAD_CTRL_SRC_A0;
xPadConf.ucMode = PAD_MODE_INPUT_EN;
xPadConf.ucPull = hGpioCfg->ucPull;
xPadConf.ucDrv = PAD_DRV_STRENGHT_4MA;
xPadConf.ucSpeed = PAD_SLEW_RATE_SLOW;
xPadConf.ucSmtTrg = PAD_SMT_TRIG_DIS;
HAL_PAD_Config(&xPadConf);
NVIC_DisableIRQ(Gpio_IRQn);
pRegOffset = (uint32_t*)S_INTR_SEL_BASE;
pRegOffset += (((gpio_intr_cfg[hGpioCfg->usPadNum] & 0xF0) >> 4));
*pRegOffset = gpio_intr_cfg[hGpioCfg->usPadNum] & 0xF;
//configure GPIO
INTR_CTRL->GPIO_INTR_TYPE &= (~((uint32_t) (0x1) << hGpioCfg->ucGpioNum)); //zero the bit position
INTR_CTRL->GPIO_INTR_TYPE |= (hGpioCfg->intr_type << hGpioCfg->ucGpioNum); //update the bit with desired value
INTR_CTRL->GPIO_INTR_POL &= (~((uint32_t) (0x1) << hGpioCfg->ucGpioNum)); //zero the bit position
INTR_CTRL->GPIO_INTR_POL |= (hGpioCfg->pol_type << hGpioCfg->ucGpioNum); //update the bit with desired value
// printf(“gpio_intr_type = %x, gpio_intr_pol = %x\r\n”,INTR_CTRL->GPIO_INTR_TYPE,INTR_CTRL->GPIO_INTR_POL);
//Clear the interrupt register
INTR_CTRL->GPIO_INTR |= (1 << hGpioCfg->ucGpioNum);
//configure GPIO interrupt
INTR_CTRL->GPIO_INTR_EN_M4 |= (1 << hGpioCfg->ucGpioNum);
NVIC_ClearPendingIRQ(Gpio_IRQn);
NVIC_SetPriority(Gpio_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
NVIC_EnableIRQ(Gpio_IRQn);
return HAL_OK;
}
void configure_s3_gpio_interrupts(GPIOCfgTypeDef *p_table, int nitems)
{
for (int k = 0; k < nitems; k++)
{
HAL_GPIO_IntrCfg(&p_table[k]);
}
}
Current Situation
Theoretically, this should be a very simple implementation, but for some reason, the blue LED on the board does not light up, and the button press interrupt is not detected. From what I have observed, the declaration and enabling of the interrupt are done in the qf_hardwaresetup.c
file through the call to the function configure_s3_gpio_interrupts(gpiocfg_table, sizeof_gpiocfg_table)
.
I already know that the code is functional in the polling version but I can`t make it work with interruptions.
Request for Help
I am not using any RTOS or similar, and I cannot figure out what is wrong or what I might be missing. If anyone has any insights or suggestions on how to fix this, I would be incredibly grateful!
Thank you very much in advance for your time and help!