cancel
Showing results for 
Search instead for 
Did you mean: 

SPI with DMA loopback

nrhinnant
Associate II
Posted on June 18, 2013 at 00:45

The original post was too long to process during our migration. Please click on the attachment to read the original post.
12 REPLIES 12
Posted on June 18, 2013 at 01:23

I think you'd want to declare the buffers as volatile

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
nrhinnant
Associate II
Posted on June 18, 2013 at 04:08

/**
******************************************************************************
* @file SPI/SPI_TwoBoards/SPI_DataExchangeDMA/main.h
* @author MCD Application Team
* @version V1.1.0
* @date 18-January-2013
* @brief Main program body
******************************************************************************
* @attention
*
* <h2><center>© COPYRIGHT 2013 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the ''License'');
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software 
* distributed under the License is distributed on an ''AS IS'' BASIS, 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern
''C''
{
#endif 
/* Includes ------------------------------------------------------------------*/
#include ''stm32f4xx.h''
#include ''stm32f4_discovery.h'' //LEDS 
/* Exported typedef -----------------------------------------------------------*/
#define countof(a) (sizeof(a) / sizeof(*(a)))
typedef 
enum
{FAILED = 0, PASSED = !FAILED} TestStatus;
/* Exported define ------------------------------------------------------------*/
/* Uncomment the line below if you will use the SPI peripheral as a Master */
#define SPI_MASTER */
/* Uncomment the line below if you will use the SPI peripheral as a Slave */
//define SPI_SLAVE 
/* USER_TIMEOUT value for waiting loops. This timeout is just guarantee that the
application will not remain stuck if the USART communication is corrupted. 
You may modify this timeout value depending on CPU frequency and application
conditions (interrupts routines, number of data to transfer, baudrate, CPU
frequency...). */
#define USER_TIMEOUT ((uint32_t)0x64) /* Waiting 1s */
/* SPIx Communication boards Interface */
#define SPIx SPI1
#define SPIx_CLK RCC_APB1Periph_SPI1
#define SPIx_CLK_INIT RCC_APB1PeriphClockCmd
#define SPIx_IRQn SPI1_IRQn
#define SPIx_IRQHANDLER SPI1_IRQHandler
#define SPIx_SCK_PIN GPIO_Pin_5
#define SPIx_SCK_GPIO_PORT GPIOA
#define SPIx_SCK_GPIO_CLK RCC_AHB1Periph_GPIOA
#define SPIx_SCK_SOURCE GPIO_PinSource1
#define SPIx_SCK_AF GPIO_AF_SPI1
#define SPIx_MISO_PIN GPIO_Pin_6
#define SPIx_MISO_GPIO_PORT GPIOA
#define SPIx_MISO_GPIO_CLK RCC_AHB1Periph_GPIOA
#define SPIx_MISO_SOURCE GPIO_PinSource2
#define SPIx_MISO_AF GPIO_AF_SPI1
#define SPIx_MOSI_PIN GPIO_Pin_7
#define SPIx_MOSI_GPIO_PORT GPIOA
#define SPIx_MOSI_GPIO_CLK RCC_AHB1Periph_GPIOA
#define SPIx_MOSI_SOURCE GPIO_PinSource3
#define SPIx_MOSI_AF GPIO_AF_SPI1
#define SPIx_DMA DMA1
#define SPIx_DMA_CLK RCC_AHB1Periph_DMA1
#define SPIx_TX_DMA_CHANNEL DMA_Channel_0
#define SPIx_TX_DMA_STREAM DMA1_Stream4
#define SPIx_TX_DMA_FLAG_TCIF DMA_FLAG_TCIF4
#define SPIx_RX_DMA_CHANNEL DMA_Channel_0
#define SPIx_RX_DMA_STREAM DMA1_Stream3
#define SPIx_RX_DMA_FLAG_TCIF DMA_FLAG_TCIF3
#define BUFFERSIZE 100
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

nrhinnant
Associate II
Posted on June 18, 2013 at 04:09

As evidenced by the ST comments, I'm working with the Standard peripheral library code right now.

nrhinnant
Associate II
Posted on June 18, 2013 at 20:46

Ok, fixed that. Makes sense, though ST doesn't do it in their example code. Doesn't really affect the application, though.

Posted on June 18, 2013 at 21:37

ST uses ''__IO'' which is a volatile type.

The pins would appear to clash with the LIS302DL on the STM32F4-Discovery board. Your DMA controller, channels and stream do not correlate to SPI1, you need to review the tables in RM0090 to understand the associations.

#define SPIx_DMA DMA2
#define SPIx_DMA_CLK RCC_AHB1Periph_DMA2
#define SPIx_TX_DMA_CHANNEL DMA_Channel_3
#define SPIx_TX_DMA_STREAM DMA2_Stream3
#define SPIx_TX_DMA_FLAG_TCIF DMA_FLAG_TCIF3
#define SPIx_RX_DMA_CHANNEL DMA_Channel_3
#define SPIx_RX_DMA_STREAM DMA2_Stream2
#define SPIx_RX_DMA_FLAG_TCIF DMA_FLAG_TCIF2

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
nrhinnant
Associate II
Posted on June 18, 2013 at 23:35

Clive, thanks for your help, you're absolutely right.

I've reworked the code thusly:

#include <stm32f4xx.h>
#include <stm32f4xx_spi.h>
#include ''main.h''
void
init_SPI1(
void
);
void
init_DMA(
void
);
uint8_t SPI1_send(uint8_t data);
uint8_t aTxBuffer[BUFFERSIZE] = {0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,
0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,
0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,
0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,
0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,
0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,
0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,
0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,
0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,
0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA,0xAA, 0xAA};
__IO uint8_t aRxBuffer[BUFFERSIZE]; 
// this function initializes the SPI1 peripheral
void
init_SPI1(
void
){
GPIO_InitTypeDef GPIO_InitStruct;
SPI_InitTypeDef SPI_InitStruct;
// enable clock for used IO pins
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* configure pins used by SPI1
* PA5 = SCK
* PA6 = MISO
* PA7 = MOSI
*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// connect SPI1 pins to SPI alternate function
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
// enable clock for used IO pins
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
/* Configure the chip select pin
in this case we will use PE7 */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOE, &GPIO_InitStruct);
GPIOE->BSRRL |= GPIO_Pin_7; 
// set PE7 high
// enable peripheral clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
/* configure SPI1 in Mode 0 
* CPOL = 0 --> clock is low when idle
* CPHA = 0 --> data is sampled at the first edge
*/
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; 
// set to full duplex mode, seperate MOSI and MISO lines
SPI_InitStruct.SPI_Mode = SPI_Mode_Master; 
// transmit in master mode, NSS pin has to be always high
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; 
// one packet of data is 8 bits wide
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; 
// clock is low when idle
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; 
// data sampled at first edge
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set; 
// set the NSS management to internal and pull internal NSS high
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; 
// SPI frequency is APB2 frequency / 4
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
// data is transmitted MSB first
SPI_Init(SPI1, &SPI_InitStruct); 
SPI_Cmd(SPI1, ENABLE); 
// enable SPI1
}
void
init_DMA(
void
)
{
DMA_InitTypeDef DMA_InitStructure;
/* Enable DMA peripheral clock ------------------------------------------*/
RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_DMA2, ENABLE);
/* DMA configuration -------------------------------------------------------*/
/* Deinitialize DMA Streams */
DMA_DeInit(SPIx_TX_DMA_STREAM);
DMA_DeInit(SPIx_RX_DMA_STREAM);
DMA_StructInit(&DMA_InitStructure);
/* Configure DMA Initialization Structure */
DMA_InitStructure.DMA_BufferSize = BUFFERSIZE ;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable ;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull ;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single ;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t) (&(SPIx->DR)) ;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
/* Configure TX DMA */
DMA_InitStructure.DMA_Channel = SPIx_TX_DMA_CHANNEL ;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral ;
DMA_InitStructure.DMA_Memory0BaseAddr =(uint32_t)aTxBuffer ;
DMA_Init(SPIx_TX_DMA_STREAM, &DMA_InitStructure);
/* Configure RX DMA */
DMA_InitStructure.DMA_Channel = SPIx_RX_DMA_CHANNEL ;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory ;
DMA_InitStructure.DMA_Memory0BaseAddr =(uint32_t)aRxBuffer ; 
DMA_Init(SPIx_RX_DMA_STREAM, &DMA_InitStructure);
}
int
main(
void
){
/* LEDs configuration */
STM_EVAL_LEDInit(LED3);
STM_EVAL_LEDInit(LED4);
STM_EVAL_LEDInit(LED5);
STM_EVAL_LEDInit(LED6);
init_SPI1();
init_DMA();
//enable tx stream, wait until enable is complete
DMA_Cmd(SPIx_TX_DMA_STREAM, ENABLE);
while
( DMA_GetCmdStatus(SPIx_TX_DMA_STREAM) != ENABLE );
//enable rx stream, wait until enable is complete
DMA_Cmd(SPIx_RX_DMA_STREAM, ENABLE);
while
( DMA_GetCmdStatus(SPIx_RX_DMA_STREAM) != ENABLE ); 
//enable SPI DMA tx requests
SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Tx, ENABLE);
//enable SPI DMA rx requests
SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Rx, ENABLE);
STM_EVAL_LEDOn(LED3);
/* Waiting the end of Data transfer */
while
(DMA_GetFlagStatus(SPIx_TX_DMA_STREAM,SPIx_TX_DMA_FLAG_TCIF)==RESET);
STM_EVAL_LEDOn(LED4); 
while
(DMA_GetFlagStatus(SPIx_RX_DMA_STREAM,SPIx_RX_DMA_FLAG_TCIF)==RESET);
/* Clear DMA Transfer Complete Flags */
DMA_ClearFlag(SPIx_TX_DMA_STREAM,SPIx_TX_DMA_FLAG_TCIF);
DMA_ClearFlag(SPIx_RX_DMA_STREAM,SPIx_RX_DMA_FLAG_TCIF); 
/* Disable DMA SPI TX Stream */
DMA_Cmd(SPIx_TX_DMA_STREAM,DISABLE);
/* Disable DMA SPI RX Stream */
DMA_Cmd(SPIx_RX_DMA_STREAM,DISABLE); 
/* Disable SPI DMA TX Requests */
SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Tx, DISABLE);
/* Disable SPI DMA RX Requests */
SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Rx, DISABLE);
/*Wait for the streams to be disabled (necessary for safe operation, see 9.3.17 in RM0090 */
while
( DMA_GetCmdStatus(SPIx_TX_DMA_STREAM) != DISABLE );
while
( DMA_GetCmdStatus(SPIx_RX_DMA_STREAM) != DISABLE );
/* Disable the SPI peripheral */
SPI_Cmd(SPIx, DISABLE); 
//check if a 0xAA byte made it across
if
(aRxBuffer[10] == 0xAA)
{
STM_EVAL_LEDOn(LED5);
STM_EVAL_LEDOn(LED6);
}
//infinite loop
while
(1){}
}

#defines:

#define SPIx SPI1
#define SPIx_DMA DMA2
#define SPIx_DMA_CLK RCC_AHB1Periph_DMA2
#define SPIx_TX_DMA_CHANNEL DMA_Channel_3
#define SPIx_TX_DMA_STREAM DMA1_Stream3
#define SPIx_TX_DMA_FLAG_TCIF DMA_FLAG_TCIF3
#define SPIx_RX_DMA_CHANNEL DMA_Channel_3
#define SPIx_RX_DMA_STREAM DMA1_Stream2
#define SPIx_RX_DMA_FLAG_TCIF DMA_FLAG_TCIF2
#define BUFFERSIZE 100

This code fails on the while loops that check DMA_GetCmdStatus. So what that tells me is that somehow the TX/RX streams are still misconfigured. I'm reading more in an attempt to figure out exactly what that error is.
Posted on June 19, 2013 at 00:08

*** DMA2 ***

Cut-n-paste the #defines I supplied.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
nrhinnant
Associate II
Posted on June 19, 2013 at 00:18

Ah, stupid mistake. I've copied and pasted your #defines.

I still fail on the loop checking whether the TX stream has been enabled, the DMA streams aren't getting enabled.

#define SPIx_DMA DMA2
#define SPIx_DMA_CLK RCC_AHB1Periph_DMA2
#define SPIx_TX_DMA_CHANNEL DMA_Channel_3
#define SPIx_TX_DMA_STREAM DMA2_Stream3
#define SPIx_TX_DMA_FLAG_TCIF DMA_FLAG_TCIF3
#define SPIx_RX_DMA_CHANNEL DMA_Channel_3
#define SPIx_RX_DMA_STREAM DMA2_Stream2
#define SPIx_RX_DMA_FLAG_TCIF DMA_FLAG_TCIF2

nrhinnant
Associate II
Posted on June 19, 2013 at 19:16

There must be someone out there who has done exactly what I'm trying to do. I can't find a working sample of Tx/Rx DMA over SPI (Using polling rather than interrupts) anywhere.