AnsweredAssumed Answered

STM32F3 SPI slave receive with DMA

Question asked by iorbitearth on Feb 11, 2014
Latest reply on Feb 12, 2014 by iorbitearth
I'm unable to receive data frames from an FPGA on the STM32F3 Discovery board over SPI with DMA. I'm testing on the discovery board with jumpers to the FPGA, but eventually the STM32F303 will be used on a custom board external to the FPGA board, connected via headers.

The FPGA provides clock and data during frame transmission. Each frame is 1119 bytes. 

The SPI peripheral is configured as an Rx only slave with no NSS (because the FPGA doesn't provide chip select). We need to receive the frame data when the clock is active and detect when frame transmission is complete via the DMA transfer complete interrupt.

I'm really struggling to generate any DMA interrupts. I used a logic analyzer connected to the discovery board pins to verify that clock and data signals from the FPGA are fine. I also used a debugger to examine the DMA CCR, CPAR, CMAR, and CNDTR registers after configuration and all bits look to be set correctly.

I'm looking for assistance to identify some obscure configuration I'm missing or whether my approach is incorrect.

001.#define likely(x)   __builtin_expect((x), 1)
002.#define unlikely(x) __builtin_expect((x), 0)
003. 
004.#define FRAME_SIZE 1119
005. 
006.typedef struct {
007.    uint8_t data[FRAME_SIZE];
008.} frame_t;
009. 
010.frame_t    frame_1;
011.frame_t    frame_2;
012.frame_t    *active_frame;
013. 
014. 
015. 
016.void mx_pinout_config(void)
017.{
018.    /* Private typedef ---------------------------------------------------------*/
019.    GPIO_InitTypeDef GPIO_InitStruct;
020. 
021.    /** SPI2 GPIO Configuration
022.        PF9  ------> SPI2_SCK
023.            PB14           ------> SPI2_MISO
024.        PB15     ------> SPI2_MOSI
025.    */
026. 
027.    /*Enable or disable the AHB peripheral clock */
028.    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOF|RCC_AHBPeriph_GPIOB, ENABLE);
029. 
030. 
031.    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
032.    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
033.    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
034.    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
035.    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
036.    GPIO_Init(GPIOF, &GPIO_InitStruct);
037. 
038. 
039.    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14;
040.    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
041.    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
042.    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
043.    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
044.    GPIO_Init(GPIOB, &GPIO_InitStruct);
045. 
046. 
047.    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15;
048.    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
049.    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
050.    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
051.    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
052.    GPIO_Init(GPIOB, &GPIO_InitStruct);
053. 
054.    /*Configure GPIO pin alternate function */
055.    GPIO_PinAFConfig(GPIOF, GPIO_PinSource9, GPIO_AF_5);
056. 
057. 
058.    /*Configure GPIO pin alternate function */
059.    GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_5);
060. 
061.    /*Configure GPIO pin alternate function */
062.    GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_5);
063.}
064. 
065. 
066./**
067. * @brief Initialize SPI/DMA Rx only slave mode.
068. */
069.void spi_init()
070.{
071.    /* Init structure declaration */
072.    SPI_InitTypeDef spi_init_struct;
073.    NVIC_InitTypeDef nvic_init_struct;
074.    DMA_InitTypeDef dma_init_struct;
075. 
076. 
077.    /* Enable peripheral clocks for SPI and DMA */
078.    RCC_APB2PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
079.    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
080. 
081. 
082.    /* Initialize SPI */
083.    SPI_I2S_DeInit(SPI2);
084.    SPI_StructInit(&spi_init_struct);
085.    spi_init_struct.SPI_Direction = SPI_Direction_1Line_Rx;
086.    spi_init_struct.SPI_Mode = SPI_Mode_Slave;
087.    spi_init_struct.SPI_DataSize = SPI_DataSize_8b;
088.    spi_init_struct.SPI_CPOL = SPI_CPOL_Low;
089.    spi_init_struct.SPI_CPHA = SPI_CPHA_2Edge;
090.    spi_init_struct.SPI_NSS = SPI_NSS_Soft;
091.    spi_init_struct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
092.    spi_init_struct.SPI_FirstBit = SPI_FirstBit_MSB;
093.    spi_init_struct.SPI_CRCPolynomial = 7;
094.    SPI_Init(SPI2, &spi_init_struct);
095. 
096. 
097.    /* Initialize DMA */
098.    DMA_DeInit(DMA1_Channel4);
099.    DMA_StructInit(&dma_init_struct);
100.    dma_init_struct.DMA_PeripheralBaseAddr = (uint32_t) &SPI2->DR;
101.    dma_init_struct.DMA_MemoryBaseAddr = (uint32_t) active_frame->data;
102.    dma_init_struct.DMA_DIR = DMA_DIR_PeripheralSRC;
103.    dma_init_struct.DMA_BufferSize = CADU_FRAME_SIZE;
104.    dma_init_struct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
105.    dma_init_struct.DMA_MemoryInc = DMA_MemoryInc_Enable;
106.    dma_init_struct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
107.    dma_init_struct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
108.    dma_init_struct.DMA_Mode = DMA_Mode_Normal;
109.    dma_init_struct.DMA_Priority = DMA_Priority_VeryHigh;
110.    dma_init_struct.DMA_M2M = DMA_M2M_Disable;
111.    DMA_Init(DMA1_Channel4, &dma_init_struct);
112. 
113. 
114.    /* Configure the Priority Group */
115.    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
116. 
117. 
118.    /* Initialize NVIC Struct for DMA */
119.    nvic_init_struct.NVIC_IRQChannel = DMA1_Channel4_IRQn;
120.    nvic_init_struct.NVIC_IRQChannelPreemptionPriority = 1;
121.    nvic_init_struct.NVIC_IRQChannelSubPriority = 0;
122.    nvic_init_struct.NVIC_IRQChannelCmd = ENABLE;
123.    NVIC_Init(&nvic_init_struct);
124. 
125. 
126.    /* Enable SPI */
127.    SPI_Cmd(SPI2, ENABLE);
128. 
129. 
130.    /* Enable DMA Request */
131.    SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);
132. 
133. 
134.    /* Enable DMA */
135.    DMA_Cmd(DMA1_Channel4, ENABLE);
136. 
137. 
138.    /* Enable DMA interrupts */
139.    DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
140.    DMA_ITConfig(DMA1_Channel4, DMA_IT_TE, ENABLE);
141.}
142. 
143. 
144. 
145. 
146. 
147. 
148./**
149. 
150. * @brief Handle DMA interrupt.
151. 
152. */
153. 
154.void DMA1_Channel4_IRQHandler()
155. 
156.{
157. 
158.    /* Transfer Complete */
159. 
160.    if (DMA_GetITStatus(DMA1_FLAG_TC4) == SET)
161. 
162.        dma_tc_isr();
163. 
164. 
165. 
166.    /* Transfer Error */
167. 
168.    if (unlikely(DMA_GetITStatus(DMA1_FLAG_TE4) == SET))
169. 
170.        dma_te_isr();
171. 
172.}
173. 
174. 
175. 
176. 
177./**
178. 
179. * @brief DMA transfer complete interrupt service routine
180. 
181. */
182. 
183.void dma_tc_isr()
184. 
185.{
186.    if (likely(DMA_GetFlagStatus(DMA1_FLAG_TC4) == SET))
187.    {
188.        DMA_ClearITPendingBit(DMA1_FLAG_TC4);
189.    }
190. 
191. 
192. 
193.    /* Disable DMA to set frame pointer */
194. 
195.    DMA_Cmd(DMA1_Channel4, DISABLE);
196. 
197. 
198. 
199.    /* Swap the active frame pointer */
200. 
201.    active_frame = active_frame == &frame_1 ? &frame_2 : &frame_1;
202. 
203. 
204. 
205.    /* Set new CMAR and CNDTR values */
206. 
207.    DMA1_Channel4->CMAR = (uint32_t) active_frame->data;
208. 
209.    DMA1_Channel4->CNDTR = (uint16_t) FRAME_SIZE;
210. 
211. 
212. 
213.    /* Enable DMA */
214. 
215.    DMA_Cmd(DMA1_Channel4, ENABLE);
216. 
217.    DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
218. 
219.    DMA_ITConfig(DMA1_Channel4, DMA_IT_TE, ENABLE);
220.}
221. 
222. 
223. 
224. 
225. 
226./**
227. 
228. * @brief
229. 
230. */
231. 
232.void dma_te_isr(void)
233. 
234.{
235. 
236.    /* Clear the Transfer Error bit by writing 1 to CTEIF3 at IFCR[11] */
237. 
238.    if (likely(DMA_GetFlagStatus(DMA1_FLAG_TE4) != RESET))
239. 
240.    {
241. 
242.        DMA_ClearITPendingBit(DMA1_FLAG_TE4);
243. 
244.    }
245. 
246.}
247. 
248. 
249. 
250. 
251.int main(void)
252.{
253. 
254.    /**
255.     * @remarks
256.     *  At this stage the microcontroller clock setting is already configured,
257.     *  this is done through SystemInit() function which is called from startup
258.    *  file (startup_stm32f30x.s) before to branch to application main.
259.     *  To reconfigure the default setting of SystemInit() function, refer to
260.     *  system_stm32f30x.c file
261.     */
262. 
263. 
264.    mx_pinout_config();
265.     
266.    spi_init();
267. 
268.    while (1) {}
269.     
270.   return 0;
271.}

Outcomes