Strange behavior with SPI1_IRQHandler [SOLVED] + Bug report

Hi, I’ve been programming my Photon to act as a Slave, everything works fine when I poll the data in a loop as follows:

if (SPI_I2S_GetITStatus((SPI_TypeDef *) SPI1_BASE, SPI_I2S_IT_RXNE) == SET)
{
    RGB.color(0, 0, 255);
    uint16_t byte = SPI_I2S_ReceiveData((SPI_TypeDef *) SPI1_BASE);
    Serial.println(byte);
    if(byte == (uint16_t) 0x15){
        RGB.color(0, 255, 0);

    }
}

But once I setup the NVIC for the SPI interrupt and receive data on the photon it starts flashing red in an odd patern before it resets itself. Does anyone know what might be the cause?

void HAL_SPI_Begin(HAL_SPI_Interface spi, uint16_t pin)
{
    STM32_Pin_Info* PIN_MAP = HAL_Pin_Map();
    NVIC_InitTypeDef NVIC_InitStructure;
    /* Enable SPI Clock */
    *spiMap[spi]->SPI_RCC_APBRegister |= spiMap[spi]->SPI_RCC_APBClockEnable;

    /* Connect SPI pins to AF */
    GPIO_PinAFConfig(PIN_MAP[spiMap[spi]->SPI_SCK_Pin].gpio_peripheral, PIN_MAP[spiMap[spi]->SPI_SCK_Pin].gpio_pin_source, spiMap[spi]->SPI_AF_Mapping);
    GPIO_PinAFConfig(PIN_MAP[spiMap[spi]->SPI_MISO_Pin].gpio_peripheral, PIN_MAP[spiMap[spi]->SPI_MISO_Pin].gpio_pin_source, spiMap[spi]->SPI_AF_Mapping);
    GPIO_PinAFConfig(PIN_MAP[spiMap[spi]->SPI_MOSI_Pin].gpio_peripheral, PIN_MAP[spiMap[spi]->SPI_MOSI_Pin].gpio_pin_source, spiMap[spi]->SPI_AF_Mapping);


    HAL_Pin_Mode(spiMap[spi]->SPI_SCK_Pin, AF_OUTPUT_PUSHPULL);
    HAL_Pin_Mode(spiMap[spi]->SPI_MISO_Pin, AF_OUTPUT_PUSHPULL);
    HAL_Pin_Mode(spiMap[spi]->SPI_MOSI_Pin, AF_OUTPUT_PUSHPULL);

  //  HAL_Pin_Mode(pin, OUTPUT);
    //HAL_GPIO_Write(pin, Bit_SET);//HIGH

    /* SPI configuration */
    spiMap[spi]->SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    spiMap[spi]->SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
    spiMap[spi]->SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
   // if(spiMap[spi]->SPI_Data_Mode_Set != true)
    //{
        //Default: SPI_MODE3
        spiMap[spi]->SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
        spiMap[spi]->SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    //}
    spiMap[spi]->SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;
    if(spiMap[spi]->SPI_Clock_Divider_Set != true)
    {
        /* Defaults to 15Mbit/s on SPI1, SPI2 and SPI3 */
        if(spi == HAL_SPI_INTERFACE1)
        {
            spiMap[spi]->SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;//60/4=15
        }
        else
        {
            spiMap[spi]->SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;//30/2=15
        }
    }
   // if(spiMap[spi]->SPI_Bit_Order_Set != true)
   // {
        //Default: MSBFIRST
        spiMap[spi]->SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    //}
    spiMap[spi]->SPI_InitStructure.SPI_CRCPolynomial = 7;
   
    /* Configure the SPI interrupt priority */
    NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 14;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    SPI_I2S_DeInit(SPI1);
    spiMap[spi]->SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
    SPI_Init(spiMap[spi]->SPI_Peripheral, &spiMap[spi]->SPI_InitStructure);
    SPI_I2S_ITConfig(spiMap[spi]->SPI_Peripheral, SPI_I2S_IT_RXNE, ENABLE);
    SPI_Cmd(spiMap[spi]->SPI_Peripheral, ENABLE);

    spiMap[spi]->SPI_Enabled = true;
}

Works fine without this part of the code:

/* Configure the SPI interrupt priority */
NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 14;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);


the SPI1_IRQHandler(void) function is empty.

EDIT: The same exact thing happens when I try to use SPI3 with interrupts
EDIT2: After some debugging I have found that the Photon ends up in a Hardfault handler. Any thoughts?

Regards

Thanks for posting this issue! Could you provide a code snippet that illustrates the problem? That will help us reproduce the issue so we can investigate a fix.

Thanks!
mat.

@mdma, I’m trying to add SPI Slave capabilities to the photon, in order to do so I need to create an interrupt for receiving SPI data.

I have modified the spi_hal.c file as follows:

void HAL_SPI_Begin(HAL_SPI_Interface spi, uint16_t pin)
{
    STM32_Pin_Info* PIN_MAP = HAL_Pin_Map();

    /* Enable SPI Clock */
    *spiMap[spi]->SPI_RCC_APBRegister |= spiMap[spi]->SPI_RCC_APBClockEnable;

    /* Connect SPI pins to AF */
    GPIO_PinAFConfig(PIN_MAP[spiMap[spi]->SPI_SCK_Pin].gpio_peripheral, PIN_MAP[spiMap[spi]->SPI_SCK_Pin].gpio_pin_source, spiMap[spi]->SPI_AF_Mapping);
    GPIO_PinAFConfig(PIN_MAP[spiMap[spi]->SPI_MISO_Pin].gpio_peripheral, PIN_MAP[spiMap[spi]->SPI_MISO_Pin].gpio_pin_source, spiMap[spi]->SPI_AF_Mapping);
    GPIO_PinAFConfig(PIN_MAP[spiMap[spi]->SPI_MOSI_Pin].gpio_peripheral, PIN_MAP[spiMap[spi]->SPI_MOSI_Pin].gpio_pin_source, spiMap[spi]->SPI_AF_Mapping);


    HAL_Pin_Mode(spiMap[spi]->SPI_SCK_Pin, AF_OUTPUT_PUSHPULL);
    HAL_Pin_Mode(spiMap[spi]->SPI_MISO_Pin, AF_OUTPUT_PUSHPULL);
    HAL_Pin_Mode(spiMap[spi]->SPI_MOSI_Pin, AF_OUTPUT_PUSHPULL);

  //  HAL_Pin_Mode(pin, OUTPUT);
    //HAL_GPIO_Write(pin, Bit_SET);//HIGH

    /* SPI configuration */
    spiMap[spi]->SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    spiMap[spi]->SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
    spiMap[spi]->SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
   // if(spiMap[spi]->SPI_Data_Mode_Set != true)
    //{
        //Default: SPI_MODE3
        spiMap[spi]->SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
        spiMap[spi]->SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    //}
    spiMap[spi]->SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;
    if(spiMap[spi]->SPI_Clock_Divider_Set != true)
    {
        /* Defaults to 15Mbit/s on SPI1, SPI2 and SPI3 */
        if(spi == HAL_SPI_INTERFACE1)
        {
            spiMap[spi]->SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;//60/4=15
        }
        else
        {
            spiMap[spi]->SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;//30/2=15
        }
    }
   // if(spiMap[spi]->SPI_Bit_Order_Set != true)
   // {
        //Default: MSBFIRST
        spiMap[spi]->SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    //}
    spiMap[spi]->SPI_InitStructure.SPI_CRCPolynomial = 7;

    /* Configure the Priority Group to 1 bit */
    NVIC_InitTypeDef NVIC_InitStructure;
    /* Configure the SPI interrupt priority */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

    /* Configure the SPI interrupt priority */
    NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    SPI_I2S_DeInit(spiMap[spi]->SPI_Peripheral);
    spiMap[spi]->SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
    SPI_Init(spiMap[spi]->SPI_Peripheral, &spiMap[spi]->SPI_InitStructure);
    SPI_I2S_ITConfig(spiMap[spi]->SPI_Peripheral, SPI_I2S_IT_RXNE, ENABLE);
    SPI_Cmd(spiMap[spi]->SPI_Peripheral, ENABLE);
     //SPI_I2S_ITConfig((SPI_TypeDef *) SPI1_BASE, SPI_I2S_IT_RXNE, ENABLE);

    //SPI_Init(spiMap[spi]->SPI_Peripheral, &spiMap[spi]->SPI_InitStructure);

    //SPI_Cmd(spiMap[spi]->SPI_Peripheral, ENABLE);
    spiMap[spi]->SPI_Enabled = true;
}

I’ve basically added this snippet:

NVIC_InitTypeDef NVIC_InitStructure;
/* Configure the SPI interrupt priority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

/* Configure the SPI interrupt priority */
NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

My application contains the following code:

#include "application.h"
#include "stdarg.h"
#include <stm32f2xx.h>
#include <stm32f2xx_spi.h>
#include <stm32f2xx_gpio.h>

SYSTEM_MODE(MANUAL);
void test(){
    RGB.color(0, 255, 0);

}
/* This function is called once at start up ----------------------------------*/
void setup()
{
    Serial1.begin(115200 );
    SPI.begin();
    RGB.control(true);
    RGB.color(255, 0, 0);
}


void  SPI1_IRQHandler(void){
    if (SPI_I2S_GetITStatus((SPI_TypeDef *) SPI1_BASE, SPI_I2S_IT_RXNE) == SET)
    {
        uint16_t byte = SPI_ReceiveData((SPI_TypeDef *) SPI1_BASE);
        if(byte == '0x15'){
            RGB.color(0, 255, 0);
        }
    }
}

/* This function loops forever --------------------------------------------*/
void loop(){
  //  RGB.color(0, 255, 0);
}

Unfortunately no matter what I do, as soon as I send any SPI data to the photon it ends up in a hard_fault, it never even reaches the SPI1_IRQHandler

As soon as I remove the NVIC configuration from the spi_hal.c file the SPI starts working again but I have to check if new data has arrived in a loop instead of having an interrupt

Regards

Please be sure you are also overriding the interrupt set by WICED - you’ll see this in core_hal.c. Otherwise the WICED interrupt handler will be used, which has a different name.

1 Like

Alright, giving this a try right now

Hi, after a bit of trial and error trying to find the Index value (USART2Index, SysTickIndex ,…) for SPI1, I was not able to find it.
Would you mind telling me what the correct value would be? It seems that they are not related to the vector table inside the MCU

Regards

Yes, they are related to the vector table in the MCU. The WICED interrupt name is SPI1_irq, so if you call your ISR that, it should just work. Alternatively you can patch the ISR table at index 45.

2 Likes

Perfect! It works now! I really appreciate your help, I might be proficient in “C”, but hardware layers are a whole new world to me.

In return I’d like to report a bug (least I can do) that can be found in interrupts_irq.h (https://github.com/spark/firmware/blob/develop/hal/inc/interrupts_irq.h)

typedef enum hal_irq_t {
#if defined(STM32F10X_MD) || defined(STM32F10X_HD)
    __All_irq = 0,
    SysInterrupt_SysTick = 1,
    SysInterrupt_TIM1_CC = 2,
    SysInterrupt_TIM2,
    SysInterrupt_TIM3,
    SysInterrupt_TIM4,
    __Last_irq = 6




#elif defined(STM32F2XX)
    __All_irq = 0,
    SysInterrupt_SysTick,
    SysInterrupt_TIM1_CC_IRQ,
    SysInterrupt_TIM1_Compare1,
    SysInterrupt_TIM1_Compare2,
    SysInterrupt_TIM1_Compare3,
    SysInterrupt_TIM1_Compare4,
    SysInterrupt_TIM2_IRQ,
    SysInterrupt_TIM2_Compare1,
    SysInterrupt_TIM2_Compare2,
    SysInterrupt_TIM2_Compare3,
    SysInterrupt_TIM2_Compare4,
    SysInterrupt_TIM2_Update,
    SysInterrupt_TIM2_Trigger,
    SysInterrupt_TIM3_IRQ,
    SysInterrupt_TIM3_Compare1,
    SysInterrupt_TIM3_Compare2,
    SysInterrupt_TIM3_Compare3,
    SysInterrupt_TIM3_Compare4,
    SysInterrupt_TIM3_Update,
    SysInterrupt_TIM3_Trigger,
    SysInterrupt_TIM4_IRQ,
    SysInterrupt_TIM4_Compare1,
    SysInterrupt_TIM4_Compare2,
    SysInterrupt_TIM4_Compare3,
    SysInterrupt_TIM4_Compare4,
    SysInterrupt_TIM4_Update,
    SysInterrupt_TIM4_Trigger,
    SysInterrupt_TIM5_IRQ,
    SysInterrupt_TIM5_Compare1,
    SysInterrupt_TIM5_Compare2,
    SysInterrupt_TIM5_Compare3,
    SysInterrupt_TIM5_Compare4,
    SysInterrupt_TIM5_Update,
    SysInterrupt_TIM5_Trigger,
    SysInterrupt_TIM6_DAC_IRQ,
    SysInterrupt_TIM6_Update,
    SysInterrupt_TIM7_IRQ,
    SysInterrupt_TIM7_Update,
    SysInterrupt_TIM1_BRK_TIM9_IRQ,
    SysInterrupt_TIM1_Break,
    SysInterrupt_TIM9_Compare1,
    SysInterrupt_TIM9_Compare2,
    SysInterrupt_TIM9_Update,
    SysInterrupt_TIM9_Trigger,
    SysInterrupt_TIM1_UP_TIM10_IRQ,
    SysInterrupt_TIM1_Update,
    SysInterrupt_TIM10_Compare,
    SysInterrupt_TIM10_Update,
    SysInterrupt_TIM8_BRK_TIM12_IRQ,
    SysInterrupt_TIM8_Break,
    SysInterrupt_TIM12_Compare1,
    SysInterrupt_TIM12_Compare2,
    SysInterrupt_TIM12_Update,
    SysInterrupt_TIM12_Trigger,
    SysInterrupt_TIM8_UP_TIM13_IRQ,
    SysInterrupt_TIM8_Update,
    SysInterrupt_TIM13_Compare,
    SysInterrupt_TIM13_Update,
    SysInterrupt_TIM8_TRG_COM_TIM14_IRQ,
    SysInterrupt_TIM8_Trigger,
    SysInterrupt_TIM14_COM,
    SysInterrupt_TIM14_Compare,
    SysInterrupt_TIM14_Update,
    SysInterrupt_TIM8_IRQ,
    SysInterrupt_TIM8_Compare1,
    SysInterrupt_TIM8_Compare2,
    SysInterrupt_TIM8_Compare3,
    SysInterrupt_TIM8_Compare4,
    SysInterrupt_TIM1_TRG_COM_TIM11_IRQ,
    SysInterrupt_TIM1_Trigger,
    SysInterrupt_TIM1_COM,
    SysInterrupt_TIM11_Compare,
    SysInterrupt_TIM11_Update,
    SysInterrupt_ADC_IRQ,
    SysInterrupt_SPI1_IRQ,
    SysInterrupt_CAN2_TX_IRQ,
    SysInterrupt_CAN2_RX0_IRQ,
    SysInterrupt_CAN2_RX1_IRQ,
    SysInterrupt_CAN2_SCE_IRQ,
    __Last_irq = 46
#else
    __Last_irq = 0
#endif
} hal_irq_t;

The __Last_irq = 46 value is incorrect; there are 80 entries in the enum. This causes the is_valid_irq() function to return false when validating interrupts > 46

Regards

1 Like

Thanks for the work! I’m sure others would appreciate it if you could provide a short digest of how to enable similar functionality in their projects. Any chance? The holy grail would be a PR to the main firmware branch but that’s asking a lot.

It sounds like you got yours to work. I would really appreciate some direction on using the photon as a slave SPI device. I don’t need interrupts.

I have not modified registers much for programming on the particle platform but I have experience modifying registers on PIC products.

Senior EE Undergrad at SDState.edu
-Nate