cancel
Showing results for 
Search instead for 
Did you mean: 

SPI DMA configuration generated by STM32CubeMX does not work

DGast.1
Associate III

I have used STM32CubeMX to generate the configuration required to use SPI1 with DMA for a nucleo H743ZI2 board:

0693W00000YASP6QAP.png 

0693W00000YASaSQAX.png 

Then, I generate the code as a Makefile project and modify the main function to have:

int main(void)
{
  /* USER CODE BEGIN 1 */
 
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USB_OTG_FS_PCD_Init();
  MX_SPI1_Init();
  /* USER CODE BEGIN 2 */
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  uint8_t buff[8] = {0};
  while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
    HAL_StatusTypeDef rc = HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)buff, 8);
    HAL_Delay (1000);   /* Insert delay 100 ms */
  }
  /* USER CODE END 3 */
}

I inspect pin PA5 (as STM32CubeMX indicates is the SPI1 SCK) with my oscilloscope and I see nothing. What is it failing?

Here are the initialization functions:

static void MX_SPI1_Init(void)
{
 
  /* USER CODE BEGIN SPI1_Init 0 */
 
  /* USER CODE END SPI1_Init 0 */
 
  /* USER CODE BEGIN SPI1_Init 1 */
 
  /* USER CODE END SPI1_Init 1 */
  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 0x0;
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
  hspi1.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
  hspi1.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
  hspi1.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi1.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi1.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
  hspi1.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
  hspi1.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
  hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
  hspi1.Init.IOSwap = SPI_IO_SWAP_DISABLE;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */
 
  /* USER CODE END SPI1_Init 2 */
 
}
static void MX_DMA_Init(void)
{
 
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();
 
  /* DMA interrupt init */
  /* DMA1_Stream0_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
  /* DMA1_Stream1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
 
}

1 ACCEPTED SOLUTION

Accepted Solutions
DGast.1
Associate III

I have tried to do this quick hack:

static uint32_t* aligned_buff = (uint32_t*)0x24000000;
[...]
uint8_t* buff = (uint8_t*)aligned_buff;
[...]
HAL_StatusTypeDef rc = HAL_SPI_Transmit_DMA(&hspi1, buff, 8);

And it works.

View solution in original post

7 REPLIES 7
Foued_KH
ST Employee

Hello @DGast.1​ ,

Please try to set : (with High priority)

  • SPI1_TX_DMA_STREAM        DMA2_Stream3
  • SPI1_RX_DMA_STREAM        DMA2_Stream2

and for PA5 :

  • GPIO Mode as GPIO_MODE_AF_PP;
  • GPIO as PULLDOWN
  • Speed ad HIGH

Hope I helped you!

Foued

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

DGast.1
Associate III

I tried and it didn't work.

DGast.1
Associate III

I have found the problem.

At first, I was declaring my transmit buffer in the stack (as explained above):

uint8_t buff[8] = {0};
  while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
    HAL_StatusTypeDef rc = HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)buff, 8);
    HAL_Delay (1000);   /* Insert delay 100 ms */
  }

That doesn't work. However, if I do this:

static const uint32_t aligned_buff[2] = {0};
static const uint8_t* buff = (uint8_t*)aligned_buff;
[...]
while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
    HAL_StatusTypeDef rc = HAL_SPI_Transmit_DMA(&hspi1, buff, 8);
    HAL_Delay (1000);   /* Insert delay 100 ms */
  }
[...]

Then, it works. However, if I remove the `const` from the transmit buffers, it stops working:

static uint32_t aligned_buff[2] = {0};
static uint8_t* buff = (uint8_t*)aligned_buff;
[...]
while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
    HAL_StatusTypeDef rc = HAL_SPI_Transmit_DMA(&hspi1, buff, 8);
    HAL_Delay (1000);   /* Insert delay 100 ms */
  }
[...]

The above doesn't work. How is this poissible?

I have verified the difference between declaring `const` and not doing so, with regards to memory allocation. My `elf` file headers are like:

```

arm-none-eabi-objdump -h nucleo-stm32h743zi2.elf

nucleo-stm32h743zi2.elf:   file format elf32-littlearm

Sections:

Idx Name     Size   VMA    LMA    File off Algn

 0 .isr_vector  00000298 08000000 08000000 00010000 2**0

         CONTENTS, ALLOC, LOAD, READONLY, DATA

 1 .text     00003e98 08000298 08000298 00010298 2**2

         CONTENTS, ALLOC, LOAD, READONLY, CODE

 2 .rodata    00000020 08004130 08004130 00014130 2**2

         CONTENTS, ALLOC, LOAD, READONLY, DATA

 3 .init_array  00000004 08004150 08004150 00014150 2**2

         CONTENTS, ALLOC, LOAD, DATA

 4 .fini_array  00000004 08004154 08004154 00014154 2**2

         CONTENTS, ALLOC, LOAD, DATA

 5 .data     00000010 20000000 08004158 00020000 2**2

         CONTENTS, ALLOC, LOAD, DATA

 6 .bss     00000198 20000010 08004168 00020010 2**2

         ALLOC

 7 ._user_heap_stack 00000600 200001a8 08004168 000201a8 2**0

         ALLOC

 8 .ARM.attributes 0000002e 00000000 00000000 00020010 2**0

         CONTENTS, READONLY

 9 .debug_info  0000fdbb 00000000 00000000 0002003e 2**0

         CONTENTS, READONLY, DEBUGGING, OCTETS

 10 .debug_abbrev 00001d32 00000000 00000000 0002fdf9 2**0

         CONTENTS, READONLY, DEBUGGING, OCTETS

 11 .debug_loc  00007576 00000000 00000000 00031b2b 2**0

         CONTENTS, READONLY, DEBUGGING, OCTETS

 12 .debug_aranges 00000900 00000000 00000000 000390a8 2**3

         CONTENTS, READONLY, DEBUGGING, OCTETS

 13 .debug_ranges 00000980 00000000 00000000 000399a8 2**3

         CONTENTS, READONLY, DEBUGGING, OCTETS

 14 .debug_line  0000aa0f 00000000 00000000 0003a328 2**0

         CONTENTS, READONLY, DEBUGGING, OCTETS

 15 .debug_str  00003f0f 00000000 00000000 00044d37 2**0

         CONTENTS, READONLY, DEBUGGING, OCTETS

 16 .comment   0000004d 00000000 00000000 00048c46 2**0

         CONTENTS, READONLY

 17 .debug_frame 000015c8 00000000 00000000 00048c94 2**2

         CONTENTS, READONLY, DEBUGGING, OCTETS

```

Then, using `nm`, I get this results:

  • When using `const`:
nm nucleo-stm32h743zi2.elf | grep aligned_buff
08004130 r aligned_buff
  • When not using `const`:
nm nucleo-stm32h743zi2.elf | grep buff
2000002c b aligned_buff

As you can see, in case of being const, it goes to `.rodata`, otherwise it goes to `.data`. One is in flash, the other is in RAM, and one is 64 bit aligned and the other isn't.

DGast.1
Associate III

I have tried doing

__attribute__((__aligned__(8))) static uint32_t aligned_buff[2] = {0};
__attribute__((__aligned__(8))) static uint8_t* buff = (uint8_t*)aligned_buff;

so both variables are 64 bits aligned, but still doesn't work.

How is this possible? Does this mean that the buffer used to trigger DMA operations must be in flash? Why?

DGast.1
Associate III

I have read this in the datasheet

0693W00000YAUfKQAX.png 

So it seems DMA buffers can only be located at specific regions.

DGast.1
Associate III

I have tried to do this quick hack:

static uint32_t* aligned_buff = (uint32_t*)0x24000000;
[...]
uint8_t* buff = (uint8_t*)aligned_buff;
[...]
HAL_StatusTypeDef rc = HAL_SPI_Transmit_DMA(&hspi1, buff, 8);

And it works.

Piranha
Chief II