AnsweredAssumed Answered

stm32f103 SPI DMA both master and slave implementation

Question asked by chan.anson.002 on Jul 1, 2014
Latest reply on Jul 3, 2014 by chan.anson.002
hi, all
I'm working on a SPI interface between to stm32f103.
I would like to enable DMA on both sides for high speed transition purpose.
And I want to use EXTI(I wonder if I can use the NSS pin) for synchronization on the master side.( the slave side will have SPI_I2S_IT_RXNE enable and the ISR will be triggered when PTX from master). Please correct me if I am wrong.
The followed is my code, one code base with different macro(WIFI_SPI_MASTER VS WIFI_SPI_SLAVE) defined.
Any input would be grateful. Many thanks.

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_exti.h"
#include "stm32f10x_spi.h"
#include "delay.h"
 
 
/* Private constants -----------------------------------------------------------*/
#define WIFI_SPI_MASTER // or #define WIFI_SPI_SLAVE
#define WIFI_SPI            SPI2
#define TIP_WIFI_SPI_GRP     GPIOB
#define TIP_WIFI_NSS_PIN     GPIO_Pin_10
#define TIP_WIFI_SCK_PIN     GPIO_Pin_13
#define TIP_WIFI_MISO_PIN    GPIO_Pin_14
#define TIP_WIFI_MOSI_PIN    GPIO_Pin_15
 
#define TIP_WIFI_IRQ_PORT_SRC   GPIO_PortSourceGPIOB
#define TIP_WIFI_IRQ_PIN_SRC    GPIO_PinSource10
#define TIP_WIFI_IRQ_EXTI_LINE  EXTI_Line10
#define TIP_WIFI_IRQ_EXTI_CHN   EXTI15_10_IRQn
 
 
#define BufferSize 128
 
#define SPI_DMA              DMA1
#define SPI_DMA_CLK          RCC_AHBPeriph_DMA1 
#define SPI_Rx_DMA_Channel   DMA1_Channel4
#define SPI_Rx_DMA_FLAG      DMA1_FLAG_TC4
#define SPI_Tx_DMA_Channel   DMA1_Channel5
#define SPI_Tx_DMA_FLAG      DMA1_FLAG_TC5 
 
/* Private typedef -------------------------------------------------------------*/
/* Private macro --------------------------------------------------------------*/
 
#ifdef WIFI_SPI_SLAVE
#define SLV2MST_CS  GPIO_SetBits(TIP_WIFI_SPI_GRP,TIP_WIFI_NSS_PIN)
#define SLV2MST_NCS GPIO_ResetBits(TIP_WIFI_SPI_GRP,TIP_WIFI_NSS_PIN)
#endif /* WIFI_SPI_SLAVE */
 
/* Private variable -------------------------------------------------------------*/
uint8_t usb_rx_count = 0;
uint8_t usb_rx_buf[BufferSize] = {0};
uint8_t usb_flag = 0;
uint8_t spi_rx_flag = 0;
uint8_t spi_rx_count = 0;
uint8_t spi_rx_buf[BufferSize] = {0};
uint8_t spi_tx_flag = 0;
uint8_t dma_tx_available = 1;
DMA_InitTypeDef DMA_InitStructure_Tx;
 
 
/* Private functions prototype ----------------------------------------------------*/
/* Private functions ------------------------------------------------------------*/
void RccInit(void)
{
    ErrorStatus HSEStartUpStatus;
    /* RCC system reset(for debug purpose) */
    RCC_DeInit();
 
    /* Enable HSE */
    RCC_HSEConfig(RCC_HSE_ON);
 
    /* Wait till HSE is ready */
    HSEStartUpStatus = RCC_WaitForHSEStartUp();
 
    if(HSEStartUpStatus == SUCCESS)
    {
        /* HCLK = SYSCLK */
        RCC_HCLKConfig(RCC_SYSCLK_Div1);
 
        /* PCLK2 = HCLK */
        RCC_PCLK2Config(RCC_HCLK_Div1);
 
        /* PCLK1 = HCLK/2 */
        RCC_PCLK1Config(RCC_HCLK_Div2);
 
        /* Flash 2 wait state */
        FLASH_SetLatency(FLASH_Latency_2);
        /* Enable Prefetch Buffer */
        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
 
        /* PLLCLK = 8MHz * 9 = 72 MHz */
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
        /* Enable PLL */
        RCC_PLLCmd(ENABLE);
 
        /* Wait till PLL is ready */
        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
        {
        }
 
        /* Select PLL as system clock source */
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
 
        /* Wait till PLL is used as system clock source */
        while(RCC_GetSYSCLKSource() != 0x08)
        {
        }
    }
 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
     
}
 
void GpioInit(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
 
    /* Enable GPIOA, GPIOB, GPIOC and AFIO clocks */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC , ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO  , ENABLE); 
     
    /*  SPI2 : SCK, MISO and MOSI */
#ifdef WIFI_SPI_MASTER 
    GPIO_InitStructure.GPIO_Pin = TIP_WIFI_SCK_PIN | TIP_WIFI_MOSI_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
    GPIO_Init(TIP_WIFI_SPI_GRP, &GPIO_InitStructure);
 
    GPIO_InitStructure.GPIO_Pin = TIP_WIFI_MISO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   
    GPIO_Init(TIP_WIFI_SPI_GRP, &GPIO_InitStructure);  
     
    //NSS   SPI_NSS_Soft
    GPIO_InitStructure.GPIO_Pin = TIP_WIFI_NSS_PIN;                             
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;  
    GPIO_Init(TIP_WIFI_SPI_GRP, &GPIO_InitStructure);      
#else
    GPIO_InitStructure.GPIO_Pin = TIP_WIFI_SCK_PIN | TIP_WIFI_MOSI_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 
    GPIO_Init(TIP_WIFI_SPI_GRP, &GPIO_InitStructure);
 
    GPIO_InitStructure.GPIO_Pin = TIP_WIFI_MISO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
    GPIO_Init(TIP_WIFI_SPI_GRP, &GPIO_InitStructure);  
 
    //NSS   SPI_NSS_Soft
    GPIO_InitStructure.GPIO_Pin = TIP_WIFI_NSS_PIN;                             
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(TIP_WIFI_SPI_GRP, &GPIO_InitStructure);  
    GPIO_ResetBits(TIP_WIFI_SPI_GRP,TIP_WIFI_NSS_PIN);
#endif
     
}
 
void DmaInit(void)
{
    DMA_InitTypeDef  DMA_InitStructure;
 
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    /* SPI_MASTER_Rx_DMA_Channel configuration ---------------------------------*/
    DMA_DeInit(SPI_Rx_DMA_Channel);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&WIFI_SPI->DR);
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)spi_rx_buf;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = BufferSize;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(SPI_Rx_DMA_Channel, &DMA_InitStructure);
         
    /* SPI_MASTER_Tx_DMA_Channel configuration ---------------------------------*/
    DMA_DeInit(SPI_Tx_DMA_Channel); 
    DMA_InitStructure_Tx.DMA_PeripheralBaseAddr = (uint32_t)(&WIFI_SPI->DR);
    DMA_InitStructure_Tx.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure_Tx.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure_Tx.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure_Tx.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure_Tx.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure_Tx.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure_Tx.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure_Tx.DMA_M2M = DMA_M2M_Disable;
}
 
void NvicInit(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
     
#ifdef WIFI_SPI_MASTER
    EXTI_InitTypeDef EXTI_InitStructure;
#endif /* WIFI_SPI_MASTER */
     
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
#ifdef WIFI_SPI_MASTER
 
    /* EXTI NVIC configuration*/   
    NVIC_InitStructure.NVIC_IRQChannel = TIP_WIFI_IRQ_EXTI_CHN;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);                                            
 
    GPIO_EXTILineConfig(TIP_WIFI_IRQ_PORT_SRC, TIP_WIFI_IRQ_PIN_SRC);
    EXTI_InitStructure.EXTI_Line = TIP_WIFI_IRQ_EXTI_LINE;                         
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;           //EXTI
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;      //failling edge triger
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;                               //enable exti
    EXTI_Init(&EXTI_InitStructure);
#endif /* WIFI_SPI_MASTER */
 
    /*SPI NVIC configuration*/
    NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
 
    /* DMA NVIC configuration*/
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
     
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
 
}
 
void TIPSpiDmaInit(void)
{
    SPI_InitTypeDef  SPI_InitStructure;
 
    RccInit();
    GpioInit();
    DmaInit();
    NvicInit();
     
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);    //APB1
 
    SPI_Cmd(WIFI_SPI, DISABLE); 
    /* SPI configuration */
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;    //Full-duplex
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                                             //master mode
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                                     //8bit
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                                                    //SCK idle low
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;                                              //SCK sampling begin at first clock edge
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                                                     // software generate NSS
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;   //baudrate control SYSCLK/4
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;                                    //first bit is most segnificant bit
    SPI_InitStructure.SPI_CRCPolynomial = 7;                                              //CRC calculation value 7
    SPI_Init(WIFI_SPI, &SPI_InitStructure); 
 
#ifdef WIFI_SPI_SLAVE
    SPI_I2S_ITConfig(WIFI_SPI, SPI_I2S_IT_RXNE, ENABLE);
#endif
    SPI_Cmd(WIFI_SPI, ENABLE); 
     
}
 
 bool TIPSpiDmaSend(uint8_t* buf, uint8_t len)
{
    /* DMA1 Channel (triggered by USART_Tx event) Config */
 
    DMA_Cmd(SPI_Tx_DMA_Channel, DISABLE);
    SPI_I2S_DMACmd(WIFI_SPI, SPI_I2S_DMAReq_Tx, DISABLE);
    SPI_Cmd(WIFI_SPI, DISABLE);
     
    DMA_DeInit(SPI_Tx_DMA_Channel);  /*needs deInit before Init*/
    DMA_InitStructure_Tx.DMA_MemoryBaseAddr = (uint32_t)buf;
    DMA_InitStructure_Tx.DMA_BufferSize = len;
    DMA_Init(SPI_Tx_DMA_Channel, &DMA_InitStructure_Tx);
 
#ifdef WIFI_SPI_SLAVE
    SLV2MST_CS;
#endif /* WIFI_SPI_SLAVE */
 
    /* Enable DMA1 Channel_Tx */
    DMA_Cmd(SPI_Tx_DMA_Channel, ENABLE);
    SPI_I2S_DMACmd(WIFI_SPI,  SPI_I2S_DMAReq_Tx, ENABLE);
    DMA_ITConfig(SPI_Tx_DMA_Channel, DMA_IT_TC, ENABLE);
 
    /* Enable the WIFI_SPI */
    SPI_Cmd(WIFI_SPI, ENABLE); 
    dma_tx_available = 0;
    return TRUE;
}
   
 int main(void)
 {
    uint8_t count = 0;
    TIPUSBInit();
    TIPSpiDmaInit();
     
    for(;;)
    {
        if(usb_flag)
        {
            usb_flag = 0;
            TIPSpiDmaSend(usb_rx_buf,usb_rx_count);
        }
        if(spi_rx_flag)
        {
            delay_ms(100);
            USBSend(spi_rx_buf,BufferSize-DMA_GetCurrDataCounter(SPI_Rx_DMA_Channel));
        spi_rx_flag = 0;
        }
    }
 
 
  
 /*******************************************************************************
 * Function Name  : SPI2_IRQHandler
 * Description    : This function handles SPI2 global interrupt request.
 * Input          : None
 * Output         : None
 * Return         : None
 *******************************************************************************/
 void SPI2_IRQHandler(void)
 {
 
    if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_RXNE) != RESET)
    {
        if(!spi_rx_flag)
        {
            spi_rx_flag = 1;
            SPI_I2S_DMACmd(WIFI_SPI,  SPI_I2S_DMAReq_Rx, ENABLE);
        }  
    }
 }
  
 void EXTI15_10_IRQHandler(void)
 {
     if(EXTI_GetITStatus(TIP_WIFI_IRQ_EXTI_LINE) != RESET)
     {
        if(GPIO_ReadInputDataBit(TIP_WIFI_SPI_GRP,TIP_WIFI_NSS_PIN)==Bit_SET) /*it is a raising edge, begin of transition*/
        {
            SPI_I2S_DMACmd(WIFI_SPI,  SPI_I2S_DMAReq_Rx, ENABLE);
            spi_rx_flag = 1;
        }
        else /*it is a falling edge, end of transition*/
        {
            SPI_I2S_DMACmd(WIFI_SPI,  SPI_I2S_DMAReq_Rx, DISABLE);
            spi_rx_flag = 0;
        }
        EXTI_ClearITPendingBit(TIP_WIFI_IRQ_EXTI_LINE);
     }
 }
 
void EXTI1_IRQHandler(void)
{
     if(EXTI_GetITStatus(TIP_WIFI_IRQ_EXTI_LINE) != RESET)
     {
        if(GPIO_ReadInputDataBit(TIP_WIFI_SPI_GRP,TIP_WIFI_NSS_PIN)==Bit_SET) /*it is a raising edge, begin of transition*/
        {
            spi_rx_flag = 1;
 
        }
        else /*it is a falling edge, end of transition*/
        {
            spi_rx_flag = 0;
        }
        EXTI_ClearITPendingBit(TIP_WIFI_IRQ_EXTI_LINE);
     }
 
}
 
  /*******************************************************************************
 * Function Name  : DMA1_Channel4_IRQHandler
 * Description    : This function handles DMA1 Channel 4 interrupt request.
 * Input          : None
 * Output         : None
 * Return         : None
 *******************************************************************************/
 void DMA1_Channel4_IRQHandler(void)
 {
     if(DMA_GetITStatus(DMA1_IT_TC4))
         DMA_ClearFlag(DMA1_FLAG_TC4);
 }
  
 /*******************************************************************************
 * Function Name  : DMA1_Channel5_IRQHandler
 * Description    : This function handles DMA1 Channel 5 interrupt request.
 * Input          : None
 * Output         : None
 * Return         : None
 *******************************************************************************/
 void DMA1_Channel5_IRQHandler(void)
 {
     if(DMA_GetITStatus(DMA1_IT_TC5))
         DMA_ClearFlag(DMA1_FLAG_TC5);
     dma_tx_available = 1;
#ifdef WIFI_SPI_SLAVE
    SLV2MST_NCS;
#endif /* WIFI_SPI_SLAVE */ 
 }

Outcomes