cancel
Showing results for 
Search instead for 
Did you mean: 

SPI1 Clock speed

Walter Nazarenus
Associate II

Hello,

i am using a Nucleo - F411RE board and i want to create a sine wave with an external DAC (mcp4922). So i initialized a SPI connection to send my sine wave table to the external DAC. The frequency of the ouput sine wave should have 40 KHz. At the beginning i was producing a nice sine wave with a 50 values sine wave table, the freqency was exactly 400 Hz. So i reduced the table and the result was a edgy sine wave with a freq of 4,3 KHz. Better freq but wors signal. So i checked the bus which my SPI1 is attached to, for the STM32F411RE it is the APB2 bus. In my CubeMX program it shows a clock of 16 MHz at this bus. The init function of the systemclock config looks like this:

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 CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /**Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

The clock divider is 1. So the freq will be 16 MHz. My SPI init function looks like this:

static void MX_SPI1_Init(void)
{
  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  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();
  }
}

Here you can see that my SPI_BAUDRATEPRESCALER is 2. So SPI1 clk frq is 8 MHz. If i want to transmit 1 value from my sine table to the DAC it will take me 16 * 125 nS = 2µS. The period Time of 40 KHz is 25µs. That means in perfect conditions i can only just use 25µs/2µs= 12.5 values for my sine table. And there is still the time missing for the chip select. Is it even possible to generate 40Khz?

2 REPLIES 2
berendi
Principal

From the STM32F411RE datasheet:

 SPI1, SPI4 and SPI5 can communicate at up to 50 Mbit/s, SPI2 and SPI3 can communicate at up to 25 Mbit/s.

You have to set up and enable the PLL in RCC to achieve that. The default system clock after reset is 16 MHz, but it can be raised to 100 MHz unsing the PLL.

However the MCP4922 datasheet says that it supports only 20 MHz SPI clock. Allowing some time for the CS pulse, it means a sample rate of 1 MSPS (maybe a bit more), or 25 samples / cycle at 40 kHz.

Maintaining the CS signal is still a bit challenging at this speed. The SPI controller is too dumb to do it alone. Aiming at 20 MHz SPI clock and 1 MSPS, there is a 200 ns gap, i.e. 20 system clock cycles between two consecutive samples. Doing it in code is hopeless, there'd be too much jitter.

Use a PWM signal on TIM1 or TIM8 (the APB2 timers) to generate CS, and use another channel on the same timer in compare mode to trigger a DMA stream which copies the wavetable to SPI. Observe the result with the scope, adjust the timing of the second timer channel if necessary.

I would not even attempt to implement it with HAL, too slow for this kind of work. Get the reference manual, and familiarize yourself with the register interface,

Maybe TI mode or I2S could be used too (latter not with SPI1, and I didn't care to look into the DAC datasheet).

> i can only just use 25µs/2µs= 12.5 values for my sine table.

That's perfectly OK if you have an adequate reconstruction filter

JW