AnsweredAssumed Answered

Configure STM32F407 as dual SPI slave device

Question asked by Pavlos Stavrou on Oct 18, 2017
Latest reply on Jan 12, 2018 by waclawek.jan



I am having some trouble setting up my STM32F407 mcu to be a dual spi slave with dma.


What I am trying to accomplish is this :

 - STM will have two SPI ports configured and will be a slave to both ports (currently I am using SPI1 and SPI2)

 - SPI1 will use DMA for Tx , SPI2 will use DMA for both Tx and Rx

 - SPI1 is setup with a S/W NSS signal. Whenever a falling edge is detected I setup the DMA transfer (16 bit length)

 - SPI2 is setup with HW NSS signal. It also uses circular mode and double buffering (24 byte length for each transaction)


On SPI1 I transmit a 16bit value that corresponds to an incremental encoder measurement. (SPI_ENCODER_COM)

On SPI2 I transmit and receive a 24 byte message that contains various information. (SPI_COM)


Each slave instance works fine on its own, meaning when only one of them has been set-up.

The issue occurs when both SPI slave instances are active.


What happens is that as soon I setup the DMA transfer for the encoder value, both SPI instances transmit that exact value. So if for example 0x1213 is the encoder value, then for the 24 transmitted bytes, all I see is 0x1213 repeated 12 times. I use different DMA peripheral, channel and stream for each SPI instance, as output by the CubeMX application.


Below is my SPI setup.

#define SPI_COM_MODULE                      SPI2
#define SPI_COM_CLK_PIN                     GPIO_PIN_13
#define SPI_COM_CLK_PORT                    GPIOB
#define SPI_COM_CLK_AF                      GPIO_AF5_SPI2
#define SPI_COM_MISO_PIN                    GPIO_PIN_14
#define SPI_COM_MISO_PORT                   GPIOB
#define SPI_COM_MISO_AF                     GPIO_AF5_SPI2
#define SPI_COM_MOSI_PIN                    GPIO_PIN_15
#define SPI_COM_MOSI_PORT                   GPIOB
#define SPI_COM_MOSI_AF                     GPIO_AF5_SPI2
#define SPI_COM_CS_PIN                      GPIO_PIN_12
#define SPI_COM_CS_PORT                     GPIOB
#define SPI_COM_CS_AF                       GPIO_AF5_SPI2
#define SPI2_TX_DMA_STREAM                  DMA1_Stream4
#define SPI2_TX_DMA_CHANNEL                 DMA_CHANNEL_0
#define SPI2_RX_DMA_STREAM                  DMA1_Stream3
#define SPI2_RX_DMA_CHANNEL                 DMA_CHANNEL_0
#define SPI2_TX_DMA_IRQn                    DMA1_Stream4_IRQn
#define SPI2_RX_DMA_IRQn                    DMA1_Stream3_IRQn
#define SPI_COM_DMA_TX_IRQHandler           DMA1_Stream4_IRQHandler
#define SPI_COM_DMA_RX_IRQHandler           DMA1_Stream3_IRQHandler

#define SPI_ENCODER_COM_MODULE              SPI1
#define SPI_ENCODER_COM_CLK_PIN             GPIO_PIN_5
#define SPI_ENCODER_COM_CLK_AF              GPIO_AF5_SPI1
#define SPI_ENCODER_COM_MISO_PIN            GPIO_PIN_6
#define SPI_ENCODER_COM_MISO_AF             GPIO_AF5_SPI1
#define SPI_ENCODER_COM_MOSI_PIN            GPIO_PIN_7
#define SPI_ENCODER_COM_MOSI_AF             GPIO_AF5_SPI1
#define SPI_ENCODER_COM_CS_PIN              GPIO_PIN_15
#define SPI_ENCODER_COM_CS_PORT             GPIOA
#define SPI_ENCODER_COM_CS_AF               GPIO_AF5_SPI1
#define SPI_ENCODER_INT_LINE                EXTI15_10_IRQn
#define SPI_ENCODER_INT_HANDLER             EXTI15_10_IRQHandler
#define SPI_ENCODER_COM_DMA_TX              DMA2
#define SPI_ENCODER_COM_DMA_TX_IRQn         DMA2_Stream5_IRQn
#define SPI_ENCODER_COM_DMA_TX_IRQHandler   DMA2_Stream5_IRQHandler

Here is the initialization for SPI_ENCODER_COM

 spiEncoder.spiHandle.Instance = SPI_ENCODER_COM_MODULE;
spiEncoder.spiHandle.Init.Direction = SPI_DIRECTION_2LINES;
spiEncoder.spiHandle.Init.CLKPhase = SPI_PHASE_2EDGE;
spiEncoder.spiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
spiEncoder.spiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
spiEncoder.spiHandle.Init.CRCPolynomial = 10;
spiEncoder.spiHandle.Init.DataSize = SPI_DATASIZE_16BIT;
spiEncoder.spiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
spiEncoder.spiHandle.Init.NSS = SPI_NSS_SOFT;
spiEncoder.spiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
spiEncoder.spiHandle.Init.Mode = SPI_MODE_SLAVE;
spiEncoder.config.module = SPI_ENCODER_COM_MODULE;
spiEncoder.config.clk_af = SPI_ENCODER_COM_CLK_AF;
spiEncoder.config.clk_pin = SPI_ENCODER_COM_CLK_PIN;
spiEncoder.config.clk_port = SPI_ENCODER_COM_CLK_PORT;
spiEncoder.config.miso_af = SPI_ENCODER_COM_MISO_AF;
spiEncoder.config.miso_pin = SPI_ENCODER_COM_MISO_PIN;
spiEncoder.config.miso_port = SPI_ENCODER_COM_MISO_PORT;
spiEncoder.config.mosi_af = SPI_ENCODER_COM_MOSI_AF;
spiEncoder.config.mosi_pin = SPI_ENCODER_COM_MOSI_PIN;
spiEncoder.config.mosi_port = SPI_ENCODER_COM_MOSI_PORT;
spiEncoder.config.cs_af = SPI_ENCODER_COM_CS_AF;
spiEncoder.config.cs_pin = SPI_ENCODER_COM_CS_PIN;
spiEncoder.config.cs_port = SPI_ENCODER_COM_CS_PORT;
spiEncoder.config.hw_cs = 0;
spiEncoder.enable_dma_tx = 1;
spiEncoder.enable_dma_rx = 0;
spiEncoder.dma_tx = SPI_ENCODER_COM_DMA_TX;
spiEncoder.hdma_tx.Instance = SPI_ENCODER_COM_DMA_INSTANCE_TX;
spiEncoder.hdma_tx.Init.Channel = SPI_ENCODER_COM_DMA_CHANNEL_TX;
spiEncoder.hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
spiEncoder.hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
spiEncoder.hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
spiEncoder.hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
spiEncoder.hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
spiEncoder.hdma_tx.Init.Mode = DMA_NORMAL;
spiEncoder.hdma_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
spiEncoder.hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
spiEncoder.hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
spiEncoder.hdma_tx.Init.MemBurst = DMA_MBURST_SINGLE;
spiEncoder.hdma_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
spiEncoder.dma_tx_irqn = SPI_ENCODER_COM_DMA_TX_IRQn;
__HAL_LINKDMA(&spiEncoder->spiHandle, hdmatx, spiEncoder->hdma_tx);
This is how I setup the DMA transfer in teh interrupt handler for the CS (NSS) line.
HAL_SPI_Transmit_DMA(&spiEncoder.spiHandle, (uint8_t*)(&enc_ticks), 1);

Here is the initialization for SPI_COM

 spiCom->hdma_tx.Instance = SPI2_TX_DMA_STREAM;
spiCom->hdma_tx.Init.Channel = SPI2_TX_DMA_CHANNEL;
spiCom->hdma_rx.Instance = SPI2_RX_DMA_STREAM;
spiCom->hdma_rx.Init.Channel = SPI2_RX_DMA_CHANNEL;
spiCom->hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
spiCom->hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
spiCom->hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
spiCom->hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
spiCom->hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
spiCom->hdma_tx.Init.Mode = DMA_CIRCULAR;
spiCom->hdma_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
spiCom->hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
spiCom->hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
spiCom->hdma_tx.Init.MemBurst = DMA_MBURST_SINGLE;
spiCom->hdma_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
__HAL_LINKDMA(&spiCom->spiHandler, hdmatx, spiCom->hdma_tx);
spiCom->hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
spiCom->hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE;
spiCom->hdma_rx.Init.MemInc = DMA_MINC_ENABLE;
spiCom->hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
spiCom->hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
spiCom->hdma_rx.Init.Mode = DMA_CIRCULAR;
spiCom->hdma_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
spiCom->hdma_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
spiCom->hdma_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
spiCom->hdma_rx.Init.MemBurst = DMA_MBURST_SINGLE;
spiCom->hdma_rx.Init.PeriphBurst = DMA_PBURST_SINGLE;
__HAL_LINKDMA(&spiCom->spiHandler, hdmarx, spiCom->hdma_rx);
This is how I setup the DMA transfer. This is a function I wrote.

(uint8_t *)&_tx_buff0,
(uint8_t *)&_tx_buff1,
(uint8_t *)&_rx_buff0,
(uint8_t *)&_rx_buff1,


First of all I would like to ask if what I am trying to achieve is possible. I wasn;t able to find something searching forums and application notes.

Is something wrong with my SPI/DMA setup ?


Any help is relaly appreciated as I am stuck on this for quite a few days now. 

I am also able to share more code if something is not clear in the code above.