Author Topic: STM32 - using SPI with circular DMA  (Read 2163 times)

0 Members and 1 Guest are viewing this topic.

Offline tru

  • Regular Contributor
  • *
  • Posts: 83
  • Country: gb
Re: STM32 - using SPI with circular DMA
« Reply #25 on: April 22, 2021, 09:30:11 am »
I think you guys have misunderstood my tests, SPI DMA circular mode works in both full-duplex and receive only in master mode.
The restrictions are probably old notes for older MCU - well definitely it doesn't apply to the MCU I'm using STM32F446 (Nucleo64 STM32F446RE).

Ah ha, I think I may have found your problem.  I've noticed in earlier post, you said the DMA is set to half-words (16-bits) and then start this once: HAL_SPI_Receive_DMA (&hspi1, DMA_buf, sizeof(DMA_buf))

The HAL driver mislabelled the size parameter - a better name for it is transfer count.  The sizeof works when the data size is byes but not for other sizes.  An example of correct usage for transferring 48 * 16-bits is:
Code: [Select]
uint16_t DMA_buf[48];
HAL_SPI_Receive_DMA(&hspi1, (uint8_t*)DMA_buf, 48);
sizeof(DMA_buf) will return 96, that will ask DMA to transfer 96 * half-words = 96 * 16-bits.
« Last Edit: April 22, 2021, 09:33:05 am by tru »
 
The following users thanked this post: ebastler

Offline ebastler

  • Super Contributor
  • ***
  • Posts: 3919
  • Country: de
Re: STM32 - using SPI with circular DMA
« Reply #26 on: April 22, 2021, 10:16:40 am »
Ah ha, I think I may have found your problem.  I've noticed in earlier post, you said the DMA is set to half-words (16-bits) and then start this once: HAL_SPI_Receive_DMA (&hspi1, DMA_buf, sizeof(DMA_buf))

The HAL driver mislabelled the size parameter - a better name for it is transfer count.  The sizeof works when the data size is byes but not for other sizes. 

Great minds think alike! ;) 

That same idea occured to me while I was in the shower yesterday morning. I was totally confident that this would be the problem -- I must have been barking up the wrong tree for a few days, SPI and DMA were actually fine, but I was asking the RX DMA to exceed its buffer limits and hence shoot my program down. Headed over to the bench right away (well, I did get dried and dressed, but certainly skipped breakfast) -- but alas, no change.

At which point I began to wonder whether I am committing some totally stupid mistake elsewhere, maybe even less related to SPI and DMA. I will take a step back and revisit my code and CubeMX settings in a few days. Might be best to start over with a minimum solution without the display attached. (Which uses another SPI port and might have caused some crossed mental wires for me...) I need a cooling-off period now!  ;)
 

Offline aandrew

  • Frequent Contributor
  • **
  • Posts: 265
  • Country: ca
Re: STM32 - using SPI with circular DMA
« Reply #27 on: April 22, 2021, 01:40:29 pm »
This post is several days old now and still no Init(), MspInit(), DMA_Start() and Callback() code posted... why not do this so we aren't shooting in the dark?
 

Offline ebastler

  • Super Contributor
  • ***
  • Posts: 3919
  • Country: de
Re: STM32 - using SPI with circular DMA
« Reply #28 on: April 22, 2021, 01:50:17 pm »
This post is several days old now and still no Init(), MspInit(), DMA_Start() and Callback() code posted... why not do this so we aren't shooting in the dark?

Happy to oblige! I am working at the moment but will post it later today. I was reluctant so far, because Siwastaja's initial comment was that the HAL overhead would make this too messy to go through, and since I also have that nagging feeling that my problem lies elsewhere...

Thank you in advance for your willingness to look at the code!
 

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 3839
  • Country: fi
Re: STM32 - using SPI with circular DMA
« Reply #29 on: April 22, 2021, 03:44:58 pm »
Elsewhere?

The point is, if you post all the code, the problem has to be there, in the code.

Very widely accepted forum protocol is to provide minimum example reproducing the problem but this is not possible with the Cube crap. Still, if you don't feel like getting rid of the Cube and writing the minimum case reproducing the problem - this should be about 10 lines and I already posted major part of it earlier -, better to post all the Cube code than nothing at all. Maybe someone can figure something out looking at it, even if long.

Without the code, we can only guess. It's like trying to troubleshoot an analog electronic problem without a schematic.

Quite frankly, you would have written that DMA and SPI initialiazation with the reference manual from scratch many times by now. As a side effect, you would understand how those peripherals work (by reading the manual).
« Last Edit: April 22, 2021, 03:46:55 pm by Siwastaja »
 

Offline aandrew

  • Frequent Contributor
  • **
  • Posts: 265
  • Country: ca
Re: STM32 - using SPI with circular DMA
« Reply #30 on: April 22, 2021, 03:48:46 pm »
His code (not the Cube code) will be small. In fact, since he's using the HAL I would argue that his code would be smaller than yours, from a paste-here perspective. He doesn't have to post the Cube code, but telling us which VERSION of the HAL he's using would be helpful.
 

Online DavidAlfa

  • Frequent Contributor
  • **
  • Posts: 730
  • Country: es
Re: STM32 - using SPI with circular DMA
« Reply #31 on: April 22, 2021, 04:41:50 pm »
Try with slave receive only mode, and disable NSS.
Then send few bytes.... My bet is on the NSS management
Please use the forum, don't PM me!
Stm32 soldering station firmware (I need calibration reports!) here
DSO2x1x GDrive here
 

Offline ebastler

  • Super Contributor
  • ***
  • Posts: 3919
  • Country: de
Re: STM32 - using SPI with circular DMA
« Reply #32 on: April 22, 2021, 06:21:14 pm »
Alright, here goes...

I have removed the other SPI (which drove the display), and instead only toggle a GPIO in the HAL_SPI_RxCpltCallback function to see whether the SPI reception is still alive. The output only gets toggled once, while I would expect it to toggle periodically, after every 32*10 bits.

Hope I didn't introduce any errors during the strip-down. Is this the right way to introduce the callback? My original code did not have any RxCpltCallback at all, but just read data from the DMA_BUF asynchronously. (Edit: That test output toggle only occurs once I turn on the SPI clock from the external signal generator, so I do indeed seem to observe one and only one SPI/DMA cycle.)

Please let me know if anything is missing. Many thanks for your comments!

main.c excerpt (removed the init code for system clock and GPIO)
Code: [Select]
#include "main.h"

SPI_HandleTypeDef hspi1;
DMA_HandleTypeDef hdma_spi1_rx;

// DMA data buffer. 16*2 16-bit values, each used for 10 bits of data, low half-word first
#define DMA_BUF_LEN 32
uint16_t DMA_buf [DMA_BUF_LEN];

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
static void MX_DMA_Init(void);

/* Private user code ---------------------------------------------------------*/

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef* hspi)
{
HAL_GPIO_TogglePin (TESTOUT_GPIO_Port, TESTOUT_Pin);
}

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_SPI1_Init();
  MX_DMA_Init();

  // Initialize SPI1 receive DMA with circular buffer
  HAL_SPI_Receive_DMA (&hspi1, (uint8_t *)DMA_buf, DMA_BUF_LEN);

  while (1)
  {
  }
}

static void MX_SPI1_Init(void)
{
  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_SLAVE;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES_RXONLY;
  hspi1.Init.DataSize = SPI_DATASIZE_10BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_LSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 7;
  hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * Enable DMA controller clock
  */
static void MX_DMA_Init(void)
{
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Channel2_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}

HAL_SPI_MspInit
Code: [Select]
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hspi->Instance==SPI1)
  {
    /* Peripheral clock enable */
    __HAL_RCC_SPI1_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**SPI1 GPIO Configuration
    PB3     ------> SPI1_SCK
    PB4     ------> SPI1_MISO
    PB5     ------> SPI1_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* SPI1 DMA Init */
    /* SPI1_RX Init */
    hdma_spi1_rx.Instance = DMA1_Channel2;
    hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_spi1_rx.Init.Mode = DMA_CIRCULAR;
    hdma_spi1_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
    if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(hspi,hdmarx,hdma_spi1_rx);
  }
}
« Last Edit: April 22, 2021, 06:38:39 pm by ebastler »
 

Online DavidAlfa

  • Frequent Contributor
  • **
  • Posts: 730
  • Country: es
Re: STM32 - using SPI with circular DMA
« Reply #33 on: April 22, 2021, 09:12:15 pm »
Make a test with 8 bit data. Could be a bug or whatever. Did you check the stm32 errata?
I tried myself a moment ago, it worked perfectly in slave only receive mode, and HAL_SPI_Receive_DMA.
Both 8 and 16 bit sizes. None of my stm32 have fine SPI frame size adjustment.
« Last Edit: April 23, 2021, 01:37:20 am by DavidAlfa »
Please use the forum, don't PM me!
Stm32 soldering station firmware (I need calibration reports!) here
DSO2x1x GDrive here
 
The following users thanked this post: ebastler

Offline tru

  • Regular Contributor
  • *
  • Posts: 83
  • Country: gb
Re: STM32 - using SPI with circular DMA
« Reply #34 on: April 22, 2021, 11:03:58 pm »
Here's my working code for comparison - maybe you can spot something.  It is working on Nucleo64 F446RE dev board with SPI set to receive master mode, 8 bits, DMA circular mode (I tried to strip out most CubeMX comments etc):
Code: [Select]
#include "main.h"

#define DMA_BUF_LEN 32
uint8_t* m_dma_buf[DMA_BUF_LEN];
uint32_t m_toggle_counter = 0;

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_SPI1_Init(void);

int main(void)
{
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_SPI1_Init();

  HAL_SPI_Receive_DMA(&hspi1, (uint8_t*)m_dma_buf, DMA_BUF_LEN);
 
  while (1)
  {
  }
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 180;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 15;
  RCC_OscInitStruct.PLL.PLLR = 2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Activate the Over-Drive mode
  */
  if (HAL_PWREx_EnableOverDrive() != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

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_RXONLY;
  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_16;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */
}


/**
  * Enable DMA controller clock
  */
static void MX_DMA_Init(void)
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA2_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA2_Stream0_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);

}

static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);

  /*Configure GPIO pin : PC13 */
  GPIO_InitStruct.Pin = GPIO_PIN_13;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pin : PA5 */
  GPIO_InitStruct.Pin = GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef* hspi){
if(hspi->Instance == SPI1){
if((m_toggle_counter / 1000) % 2)
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
else
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);

m_toggle_counter++;
}
}

The call back procedure HAL_SPI_RxCpltCallback() flashes a test LED GPIO PA5, which confirms the DMA request is continuous since it keeps getting called.  I've used a counter with a large division to slow down the flashing.  Sorry, CubeMX or my board doesn't support DMA in half-words and SPI 10-bits so I cannot make it as close to yours, and also I don't have a clocking source to test the SPI receive slave mode, but DavidAlfa confirms he got slave mode working.
« Last Edit: April 22, 2021, 11:06:05 pm by tru »
 
The following users thanked this post: ebastler

Offline tru

  • Regular Contributor
  • *
  • Posts: 83
  • Country: gb
Re: STM32 - using SPI with circular DMA
« Reply #35 on: April 22, 2021, 11:09:26 pm »
Hmm, just noticed your CubeMX code doesn't have a SPI baud rate prescaler setting, or perhaps your chip only has a default?
 

Offline ebastler

  • Super Contributor
  • ***
  • Posts: 3919
  • Country: de
Re: STM32 - using SPI with circular DMA
« Reply #36 on: April 23, 2021, 05:01:13 am »
Hmm, just noticed your CubeMX code doesn't have a SPI baud rate prescaler setting, or perhaps your chip only has a default?

The baud rate prescaler is only active in SPI master mode, I think, as the slave does not generate a clock. If I switch to master mode in CubeMX, it offers the prescaler setting, in slave mode the option is hidden.
 

Offline ebastler

  • Super Contributor
  • ***
  • Posts: 3919
  • Country: de
Re: STM32 - using SPI with circular DMA
« Reply #37 on: April 23, 2021, 05:14:09 am »
Make a test with 8 bit data. Could be a bug or whatever. Did you check the stm32 errata?
I tried myself a moment ago, it worked perfectly in slave only receive mode, and HAL_SPI_Receive_DMA.
Both 8 and 16 bit sizes. None of my stm32 have fine SPI frame size adjustment.

While debugging my full code I also tried to fall back on 8-bit frames, which did not resolve the problem. I will try that again with the minimal code just to make sure.

I had not checked the errata for the 'F303 so far, but just did so. Unfortunately can't find any relevant SPI or DMA issues.
 

Offline tru

  • Regular Contributor
  • *
  • Posts: 83
  • Country: gb
Re: STM32 - using SPI with circular DMA
« Reply #38 on: April 23, 2021, 06:35:39 am »
The baud rate prescaler is only active in SPI master mode, I think, as the slave does not generate a clock. If I switch to master mode in CubeMX, it offers the prescaler setting, in slave mode the option is hidden.
Ah yes, silly me forgot about slave mode!
Also forgot to add the MSP init section from other file:
Code: [Select]
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hspi->Instance==SPI1)
  {
  /* USER CODE BEGIN SPI1_MspInit 0 */

  /* USER CODE END SPI1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_SPI1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**SPI1 GPIO Configuration
    PA6     ------> SPI1_MISO
    PB3     ------> SPI1_SCK
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* SPI1 DMA Init */
    /* SPI1_RX Init */
    hdma_spi1_rx.Instance = DMA2_Stream0;
    hdma_spi1_rx.Init.Channel = DMA_CHANNEL_3;
    hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi1_rx.Init.Mode = DMA_CIRCULAR;
    hdma_spi1_rx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_spi1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(hspi,hdmarx,hdma_spi1_rx);

  /* USER CODE BEGIN SPI1_MspInit 1 */

  /* USER CODE END SPI1_MspInit 1 */
  }

}
 

Offline ebastler

  • Super Contributor
  • ***
  • Posts: 3919
  • Country: de
Re: STM32 - using SPI with circular DMA
« Reply #39 on: April 23, 2021, 07:48:38 am »
Elsewhere?
The point is, if you post all the code, the problem has to be there, in the code.

I can think of many things that could go wrong outside of the source code: A missing or bad connection on the breadboard, incorrect jumper settings for the boot selection, some untoward debug setting in the IDE, a counterfeit and buggy CPU... I checked and double-checked the aspects which I thought of, but obviously can't rule out that something else might be wrong.

Quote
Quite frankly, you would have written that DMA and SPI initialiazation with the reference manual from scratch many times by now. As a side effect, you would understand how those peripherals work (by reading the manual).

Maybe coding from scratch would have been quicker, or maybe I would still be trying to figure out how to set up the system clocks... ::) Most likely, I would be exactly where I am now, since setting the registers correctly does not seem to be the problem.

No need to reprimand me for using HAL and CubeMX, I think. I did make that choice consciously (and not without doubts -- a HAL manual which is actually longer than the processor's reference manual seems to defeat the purpose of a HAL to some extent...) I have programmed various microcontrollers on the bare metal level over the years, starting with the 8051, so I am not coming at this straight from Arduinos. But did find the STM32 family a bit overwhelming and thought I'd give the "modern" approach a try; and it certainly has helped me to get my bearings quicker in several cases. Still undecided what approach I will take on my next project.
« Last Edit: April 23, 2021, 09:28:27 am by ebastler »
 

Offline ebastler

  • Super Contributor
  • ***
  • Posts: 3919
  • Country: de
Re: STM32 - using SPI with circular DMA
« Reply #40 on: May 06, 2021, 05:57:49 pm »
Quick update: I have revisited this project now, using a different STM32 processor instead of the STM32F303 I had tried without success.

Using an STM32F401 (on a small "black pill" protoboard made by WeAct in China) everything works like a charm, with the exact same source code and the same peripheral settings! So the simple concept -- just a circular DMA continuously updating a buffer which gets read asynchronously, without using any interrupts -- works nicely in this application.

I still have no idea what is wrong with my implementation on the 'F303: Is it an undocumented CPU erratum, or one that I could not spot and relate to my situation, or do I have a conterfeit CPU after all? But I have limited interest in finding that out; the 'F303 boards are unobtainable anyway at the moment, while the 'F401 are easily available.

In any case, thanks again to those of you who have provided ideas for this wild goose chase!
 

Online voltsandjolts

  • Supporter
  • ****
  • Posts: 1154
  • Country: gb
Re: STM32 - using SPI with circular DMA
« Reply #41 on: May 07, 2021, 11:10:20 am »
Could you post a copy of the complete buildable and working project?
 

Offline ebastler

  • Super Contributor
  • ***
  • Posts: 3919
  • Country: de
Re: STM32 - using SPI with circular DMA
« Reply #42 on: May 07, 2021, 06:52:28 pm »
Could you post a copy of the complete buildable and working project?

Sure, if it is useful -- attached here. This should be the complete project for use with STMCubeIDE. To help you get your bearings:

This is meant as an X/Y "oscilloscope" display for a functional model of a vintage computer -- the Pilot ACE, based on a 1945 design by Alan Turing and realized in 1950. The ACE operates bit-serially, and the oscilloscope displays the contents of one (selectable) ultrasonic delay line, i.e. the main memory. Each delay line comprises 16 words @ 20 bits in my scaled-down functional model. This gets displayed as a simple array of bright and dim spots, one spot per bit. The original Pilot ACE did this on a CRT, of course; I am using a small TFT display driven by an ST7735.

TIM1 receives a word sync signal from the ACE (high pulse at the beginning of each word) and provides a PWM output which is high for 16 words, then low for 16 words. Used as the NSS signal for SPI1.

SPI1 operates in receive-only slave mode with hardware NSS, driven by the clock and data stream from the ACE. Its circular DMA continuously dumps the received data into a 40-byte buffer. The buffer is read (asynchronously) in the main loop of main.c and displayed on the "oscilloscope" screen.

SPI2 operates in master mode to drive the ST7735 mini TFT display.
 
The following users thanked this post: voltsandjolts


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf