AnsweredAssumed Answered

NVIC with STM32F4

Question asked by spencer.warren on Jun 19, 2014
Latest reply on Jun 19, 2014 by spencer.warren
Hello all,

I am encountering some strange behaviour with my STM32F4 Discovery board; I am attempting to set up an transfer with another micro-controller via SPI and DMA, and have initialized the peripherals / handlers as follows.  Before writing the code to do the actual transfer, I attempted to get my interrupt handler working, however here I find myself hung up.  When I debug the NVIC register and step through my program (I'm using iar workbench), I find that the ISPR is not being set on the call to:
NVIC_EnableIRQ(SPI_PORT_DMA_RX_IRQn);

despite the NVIC_EnableIRQ call successfully setting the NVIC->ISER[14] (DMA1_Stream3) register to 1.  Additionally, (and frankly with NVIC_EnableIRQ not work I wouldn't expect this to), if I do begin transmitting SPI to the micro, even after the buffer fills up, it does not generate an interrupt (though it does encounter a bus fault..).

I don't have very much experience with STM32; would anyone be able to set me on the right track for getting these interrupts firing?

Cheers,

Warren

#include "stm32f4xx.h"
#include "stm32f4_discovery.h"
#include <string.h>
#include <stdio.h>
  
  
#define SPI_PORT                  SPI2
#define SPI_PORT_CLOCK            RCC_APB1Periph_SPI2
  
#define SPI_SCK_PIN              GPIO_Pin_13
#define SPI_SCK_GPIO_PORT        GPIOB
#define SPI_SCK_SOURCE           GPIO_PinSource13
#define SPI_SCK_AF               GPIO_AF_SPI2
  
#define SPI_MOSI_PIN             GPIO_Pin_15
#define SPI_MOSI_GPIO_PORT       GPIOB
#define SPI_MOSI_GPIO_CLK        RCC_AHB1Periph_GPIOB
#define SPI_MOSI_SOURCE          GPIO_PinSource15
#define SPI_MOSI_AF              GPIO_AF_SPI2
#define SPI_PORT_DR_ADDRESS      SPI_PORT->DR
  
#define SPI_PORT_DMA                       DMA1
#define SPI_PORT_DMAx_CLK                  RCC_AHB1Periph_DMA1
#define SPI_PORT_RX_DMA_CHANNEL            DMA_Channel_0
#define SPI_PORT_RX_DMA_STREAM             DMA1_Stream3
#define SPI_PORT_RX_DMA_FLAG_TCIF          DMA_FLAG_TCIF3
#define SPI_PORT_DMA_RX_IRQn               DMA1_Stream3_IRQn
#define SPI_PORT_DMA_RX_IRQHandler         DMA1_Stream3_IRQHandler
  
#define BUFFER_SIZE 600
 
// Globals
static uint8_t BUFFER[BUFFER_SIZE];
 
 
// FUNCTION DEFINITIONS
void SPI_PORT_DMA_RX_IRQHandler(void);
static void init(void);
  
void SPI_PORT_DMA_RX_IRQHandler(){
    if(DMA_GetITStatus(SPI_PORT_RX_DMA_STREAM, DMA_IT_TCIF3) == SET) {
        DMA_Cmd(SPI_PORT_RX_DMA_STREAM, DISABLE);
        DMA_ClearITPendingBit(SPI_PORT_RX_DMA_STREAM, DMA_IT_TCIF3);
    }
    
}
  
static void init(){
    // Configure the clocks for the various peripherals
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    RCC_APB1PeriphClockCmd(SPI_PORT_CLOCK, ENABLE);
    RCC_AHB1PeriphClockCmd(SPI_PORT_DMAx_CLK, ENABLE);
    RCC_AHB1PeriphClockCmd(SPI_MOSI_GPIO_CLK, ENABLE);
         
     
     
    DMA_InitTypeDef DMA_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef SPI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
         
    // Set up GPIO's
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
         
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
     
    // Connect SPI pins to AF5
    GPIO_PinAFConfig(SPI_SCK_GPIO_PORT, SPI_SCK_SOURCE, SPI_SCK_AF);
    GPIO_PinAFConfig(SPI_MOSI_GPIO_PORT, SPI_MOSI_SOURCE, SPI_MOSI_AF);
     
    // Now configure the pins themselves, but the SPI pins use the alternate function
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
    GPIO_InitStructure.GPIO_Pin = SPI_SCK_PIN;
    GPIO_Init(SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = SPI_MOSI_PIN;
    GPIO_Init(SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
     
    // Now we can set up the SPI peripheral
    // Assume the target is write only and we look after the chip select ourselves
    SPI_I2S_DeInit(SPI_PORT);
    SPI_StructInit(&SPI_InitStructure);
    SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_RxOnly;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
    SPI_Init(SPI_PORT, &SPI_InitStructure);
         
         
    // Set up the DMA
    // Start with a blank DMA configuration
    DMA_DeInit(SPI_PORT_RX_DMA_STREAM);
     
    DMA_StructInit(&DMA_InitStructure);
    DMA_InitStructure.DMA_Channel = SPI_PORT_RX_DMA_CHANNEL;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
    DMA_InitStructure.DMA_BufferSize = sizeof(message);
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
     
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & SPI_PORT_DR_ADDRESS;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) BUFFER;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
     
    DMA_Init(SPI_PORT_RX_DMA_STREAM, &DMA_InitStructure);
    DMA_ITConfig(SPI_PORT_RX_DMA_STREAM, DMA_IT_TC, ENABLE);
         
    // Enable dma rx request.
    SPI_I2S_DMACmd(SPI_PORT, SPI_I2S_DMAReq_Rx, ENABLE);
    // Enable the SPI port
    SPI_Cmd(SPI_PORT, ENABLE);
    DMA_Cmd (SPI_PORT_RX_DMA_STREAM, ENABLE);
         
    // Ensure DMA is enabled before initiate the interrupt
    while(DMA_GetCmdStatus(SPI_PORT_RX_DMA_STREAM) != ENABLE)
        __NOP(); // Will eventually put a timeout here
             
         
    // Enable the interrupt in the NVIC
    NVIC_InitStructure.NVIC_IRQChannel = SPI_PORT_DMA_RX_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}
   
uint32_t main(void){
    SystemInit();
    __enable_irq();
    init();
  
    NVIC_EnableIRQ(SPI_PORT_DMA_RX_IRQn);
    NVIC_SetPendingIRQ(SPI_PORT_DMA_RX_IRQn);
    printf("%d\n", NVIC_GetPendingIRQ (SPI_PORT_DMA_RX_IRQn));
   
    return 1;
}

Outcomes