AnsweredAssumed Answered

stm32f4 discovery board spi dma example

Question asked by de_carvalho.felipe on Jun 2, 2014
Latest reply on Jun 2, 2014 by waclawek.jan
Hi, I have been trying to get the spi dma example to work with no success. I have checked and tried everything I could think of.
I have 2 stm32f4 discovery boards connected as per instructions in readme file inside example folder and I'm using coocox IDE to compile and download code to flash. I have changed the code to work with SPI1 instead of SPI2. The spi pins on both boards are connected via ~2cm (1") wires (shortest I could make without making connection difficult).
I haven't tried the interrupt example yet as it does not suit for the application I need but I will be trying after I finish this post.
I have made sure that all initialization is done correctly and using a scope I can see that the clock is there and that data is being shifted out, so for transmission it seems to be working but reception is not working. When I'm in debug mode on the slave side I can check the RX buffer and I see that it receives data but it is all garbage. One good sign is that the length of the garbage data is 1byte smaller than the length of the transmitted signal. This shows that it is detecting data from the transmitter but why it is only garbage I can't figure out.
Here is the code I'm using:
/**
  ******************************************************************************
  * @file    SPI/SPI_TwoBoards/SPI_DataExchangeDMA/main.c
  * @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:
  *
  *
  * 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.
  *
  ******************************************************************************
  */
 
/* Includes ------------------------------------------------------------------*/
#include "main.h"
 
/** @addtogroup STM32F4xx_StdPeriph_Examples
  * @{
  */
 
/** @addtogroup SPI_DataExchangeDMA
  * @{
  */
 
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
    uint8_t aTxBuffer[BUFFERSIZE] = "SPI Master/Slave : Communication between two SPI using DMA";
__IO uint8_t aRxBuffer [BUFFERSIZE];
__IO uint8_t ubRxIndex = 0;
__IO uint8_t ubTxIndex = 0;
__IO uint32_t TimeOut = 0;
 
SPI_InitTypeDef  SPI_InitStructure;
 
/* Private function prototypes -----------------------------------------------*/
static void SPI_Config(void);
static void SysTickConfig(void);
static TestStatus Buffercmp(uint8_t* pBuffer1, __IO uint8_t* pBuffer2, uint16_t BufferLength);
 
/* Private functions ---------------------------------------------------------*/
 
/**
  * @brief  Main program
  * @param  None
  * @retval None
  */
int main(void)
{
  /*!< At this stage the microcontroller clock setting is already configured,
       this is done through SystemInit() function which is called from startup
       files (startup_stm32f40xx.s/startup_stm32f427x.s) before to branch to
       application main.
       To reconfigure the default setting of SystemInit() function, refer to
       system_stm32f4xx.c file
     */
  uint16_t i;
  /* SPI configuration */
  SPI_Config();
   
  /* SysTick configuration */
  SysTickConfig();
   
  /* LEDs configuration */     
  STM_EVAL_LEDInit(LED1);
  STM_EVAL_LEDInit(LED2);
  STM_EVAL_LEDInit(LED3);
  STM_EVAL_LEDInit(LED4);
   
 /* GPIO_InitTypeDef GPIO_InitStructure;
 
 
 
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
 
 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_Init(GPIOA, &GPIO_InitStructure);*/
 
  for(i=0;i<BUFFERSIZE;i++)
  {
      aRxBuffer[i]=0x00;
  }
#ifdef SPI_MASTER
  /* Master board configuration */   
  /* Initializes the SPI communication */
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  SPI_Init(SPIx, &SPI_InitStructure);
   
  /* The Data transfer is performed in the SPI using Direct Memory Access */
 
  /* Enable DMA SPI TX Stream */
  DMA_Cmd(SPIx_TX_DMA_STREAM,ENABLE);
 
  /* Enable DMA SPI RX Stream */
  DMA_Cmd(SPIx_RX_DMA_STREAM,ENABLE);
 
  /* Enable SPI DMA TX Requsts */
  SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Tx, ENABLE);
 
  /* Enable SPI DMA RX Requsts */
  SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Rx, ENABLE);
   
  /* Configure the Tamper Button */
  STM_EVAL_PBInit(BUTTON_WAKEUP,BUTTON_MODE_GPIO);
   
  /* Wait until Tamper Button is pressed */
  while (!GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0));
   
  /* Enable the SPI peripheral */
  SPI_Cmd(SPIx, ENABLE);
   
#endif /* SPI_MASTER */
   
#ifdef SPI_SLAVE
  /* Slave board configuration */
  /* Initializes the SPI communication */
  SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
  SPI_Init(SPIx, &SPI_InitStructure);
 
  /* Enable DMA SPI TX Stream */
  DMA_Cmd(SPIx_TX_DMA_STREAM,ENABLE);
 
  /* Enable DMA SPI RX Stream */
  DMA_Cmd(SPIx_RX_DMA_STREAM,ENABLE); 
   
  /* Enable SPI DMA TX Requsts */
  SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Tx, ENABLE);
 
  /* Enable SPI DMA RX Requsts */
  SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Rx, ENABLE);
 
  /* Enable the SPI peripheral */
  SPI_Cmd(SPIx, ENABLE);
  
#endif /* SPI_SLAVE */
 
  /* Waiting the end of Data transfer */
  while (DMA_GetFlagStatus(SPIx_TX_DMA_STREAM,SPIx_TX_DMA_FLAG_TCIF)==RESET);
  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 Requsts */
  SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Tx, DISABLE);
 
  /* Disable SPI DMA RX Requsts */
  SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Rx, DISABLE);
 
  /* Disable the SPI peripheral */
  SPI_Cmd(SPIx, DISABLE);
 
  if (Buffercmp(aTxBuffer, aRxBuffer, BUFFERSIZE) != FAILED)
  {
    /* Turn ON LED1 and LED3 */
    STM_EVAL_LEDOn(LED1);
    STM_EVAL_LEDOn(LED3);
    /* Turn OFF LED2 and LED4 */
    STM_EVAL_LEDOff(LED2);
    STM_EVAL_LEDOff(LED4);
  }
  else
  {
    /* Turn OFF LED1 and LED3 */
    STM_EVAL_LEDOff(LED1);
    STM_EVAL_LEDOff(LED3);
    /* Turn ON LED2 and LED4 */
    STM_EVAL_LEDOn(LED2);
    STM_EVAL_LEDOn(LED4);
  }
 
  /* Infinite Loop */
  while (1)
  {
  
}
 
/**
  * @brief  Configures the SPI Peripheral.
  * @param  None
  * @retval None
  */
static void SPI_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  DMA_InitTypeDef DMA_InitStructure;
 
  /* Peripheral Clock Enable -------------------------------------------------*/
  /* Enable the SPI clock */
  SPIx_CLK_INIT(SPIx_CLK, ENABLE);
   
  /* Enable GPIO clocks */
  RCC_AHB1PeriphClockCmd(SPIx_SCK_GPIO_CLK | SPIx_MISO_GPIO_CLK | SPIx_MOSI_GPIO_CLK, ENABLE);
   
  /* Enable DMA clock */
  RCC_AHB1PeriphClockCmd(SPIx_DMA_CLK, ENABLE);
 
  /* SPI GPIO Configuration --------------------------------------------------*/
  /* GPIO Deinitialisation */
  GPIO_DeInit(SPIx_SCK_GPIO_PORT);
  GPIO_DeInit(SPIx_MISO_GPIO_PORT);
  GPIO_DeInit(SPIx_MOSI_GPIO_PORT);
   
  /* Connect SPI pins to AF5 */ 
  GPIO_PinAFConfig(SPIx_SCK_GPIO_PORT, SPIx_SCK_SOURCE, SPIx_SCK_AF);
  GPIO_PinAFConfig(SPIx_MISO_GPIO_PORT, SPIx_MISO_SOURCE, SPIx_MISO_AF);   
  GPIO_PinAFConfig(SPIx_MOSI_GPIO_PORT, SPIx_MOSI_SOURCE, SPIx_MOSI_AF);
 
  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;
 
  /* SPI SCK pin configuration */
  GPIO_InitStructure.GPIO_Pin = SPIx_SCK_PIN;
  GPIO_Init(SPIx_SCK_GPIO_PORT, &GPIO_InitStructure);
   
  /* SPI  MISO pin configuration */
  GPIO_InitStructure.GPIO_Pin SPIx_MISO_PIN;
  GPIO_Init(SPIx_MISO_GPIO_PORT, &GPIO_InitStructure); 
 
  /* SPI  MOSI pin configuration */
  GPIO_InitStructure.GPIO_Pin SPIx_MOSI_PIN;
  GPIO_Init(SPIx_MOSI_GPIO_PORT, &GPIO_InitStructure);
  
  /* SPI configuration -------------------------------------------------------*/
  SPI_I2S_DeInit(SPIx);
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; // | SPI_NSSInternalSoft_Set;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
//  SPI_InitStructure.SPI_CRCPolynomial = 7;
   
  /* DMA configuration -------------------------------------------------------*/
  /* Deinitialize DMA Streams */
  DMA_DeInit(SPIx_TX_DMA_STREAM);
  DMA_DeInit(SPIx_RX_DMA_STREAM);
   
  /* 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);
   
}
 
/**
  * @brief  Configure a SysTick Base time to 10 ms.
  * @param  None
  * @retval None
  */
static void SysTickConfig(void)
{
  /* Setup SysTick Timer for 10ms interrupts  */
  if (SysTick_Config(SystemCoreClock / 100))
  {
    /* Capture error */
    while (1);
  }
 
  /* Configure the SysTick handler priority */
  NVIC_SetPriority(SysTick_IRQn, 0x0);
}
 
 
/**
  * @brief  Compares two buffers.
  * @param  pBuffer1, pBuffer2: buffers to be compared.
  * @param  BufferLength: buffer's length
  * @retval PASSED: pBuffer1 identical to pBuffer2
  *         FAILED: pBuffer1 differs from pBuffer2
  */
static TestStatus Buffercmp(uint8_t* pBuffer1, __IO uint8_t* pBuffer2, uint16_t BufferLength)
{
  while (BufferLength--)
  {
    if (*pBuffer1 != *pBuffer2)
    {
      return FAILED;
    }
    pBuffer1++;
    pBuffer2++;
  }
 
  return PASSED;
}
 
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
 
  /* Infinite loop */
  while (1)
  {}
}
#endif
 
/**
  * @}
  */
 
/**
  * @}
  */
 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
 
main.h
 
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
#include "STM324x7i_eval.h"
#include "stm32_eval_legacy.h"
 
/* 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_APB2Periph_SPI1
  #define SPIx_CLK_INIT                  RCC_APB2PeriphClockCmd
  #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_PinSource5
  #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_PinSource6
  #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_PinSource7
  #define SPIx_MOSI_AF                   GPIO_AF_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             DMA2_Stream5
  #define SPIx_TX_DMA_FLAG_TCIF          DMA_FLAG_TCIF5
  #define SPIx_RX_DMA_CHANNEL            DMA_Channel_3
  #define SPIx_RX_DMA_STREAM             DMA2_Stream0
  #define SPIx_RX_DMA_FLAG_TCIF          DMA_FLAG_TCIF0
 
 
 
 
#define BUFFERSIZE                       100
 
stm32fxx_it.c
 
void SPIx_IRQHANDLER(void)
{
  /* SPI in Receiver mode */
 
  if (SPI_I2S_GetITStatus(SPIx, SPI_I2S_IT_RXNE) == SET)
  {
    if (ubRxIndex < BUFFERSIZE)
    {
 
      /* Receive Transaction data */
      aRxBuffer[ubRxIndex++] = SPI_I2S_ReceiveData(SPIx);
    }
    else
    {
        ubRxIndex=0;
      /* Disable the Rx buffer not empty interrupt */
      SPI_I2S_ITConfig(SPIx, SPI_I2S_IT_RXNE, DISABLE);
    }
  }
  /* SPI in Tramitter mode */
  if (SPI_I2S_GetITStatus(SPIx, SPI_I2S_IT_TXE) == SET)
  {
    if (ubTxIndex < BUFFERSIZE)
    {
      /* Send Transaction data */
      SPI_I2S_SendData(SPIx, aTxBuffer[ubTxIndex++]);
 
    }
    else
    {
        ubTxIndex=0;
      /* Disable the Tx buffer empty interrupt */
      SPI_I2S_ITConfig(SPIx, SPI_I2S_IT_TXE, DISABLE);
    }
  }
}

I really can't see what I'm doing wrong here. I have already read other posts related but couldn't find an answer.
The strange thing is that if I program 1 board as master and place a jumper from pin PA6-PA7 then it "works", that is, clearing the RX buffer before data is sent or received and checking the buffer after transmission I can see the buffer filled with the correct data. This made me think that maybe the wires for connecting both boards are too long, but even at ~300KHz clock?
Any help will be most appreciated.
thanks

Outcomes