Skip to main content
Associate III
September 30, 2023
Question

SPI Clock rate limitation?

  • September 30, 2023
  • 8 replies
  • 8030 views

TL;DR. What are the limiting factors for incoming clock speed for an SPI peripheral operating in slave mode?

I'm using the STM32U575 MCU with a few peripherals, and am clocking it down to 16MHz for SYSCLK and all related peripherals.  I'm generating a decent amount of data by running the ADC at 20ksps. (TIM2 triggering ADC4, which drops samples into memory using DMA, and have verified output using a 1Mbaud UART.)  However, what I really need is for this data to come out of the SPI peripheral, and more specifically, synced to an external clock.  I figured the SPI in slave mode would be a good fit.

I've been able to get some test byte arrays out of the SPI peripheral when the SCLK line is receiving 200kHz, however, this starts falling apart at 300kHz.  Falling apart means things like the TX complete callback not firing or the clock and data starting to incur some glitches.  

The setup is the U575 Nucleo board, and the clock source is an external signal generator set to 3.3V square wave.  

As an extra data point, I tried increasing the clock of the U575 to 160MHz (10x), and found that it works at 2MHz and stops working at 3MHz (10x jumps respectively).  

Is there something within the SPI peripheral that limits the speed of the incoming clock?

This topic has been closed for replies.

8 replies

waclawek.jan
Super User
September 30, 2023

DS will contain an exact figure, but for older STM32 the ultimate limit is half the SPI's core clock.

I don't know how can clock glitch in slave mode. If MISO data glitch between bytes (frames) then it's inadequately written software, or internal bus limitation. E.g. you cannot throw some Cube/HAL code on it and expect it to have high performance.

JW

AScha.3
Super User
September 30, 2023

from ds :

AScha3_0-1696060780962.png

so limit for clock/slave is 100 M.

"If you feel a post has answered your question, please click ""Accept as Solution""."
sethkazAuthor
Associate III
September 30, 2023

so limit for clock/slave is 100 M

OK, so clearly it's capable of going faster than I'm finding. So what's actually causing this issue?

I also double checked the conditions listed in the datasheet:

  1. Output speed set to high (I had set this to low previously, as the high drive + oscope probe was causing reflections and double clocking.  I tried all 4 settings, no luck.)
  2. Capacitive load is there, but minimal.  (Not sure how I would reduce this further without ditching the Nucleo for my own board.)
  3. Measurement points (not applicable)
  4. I/O compensation cell: I found that setting and have activated it.  No luck.
  5. HSLV Activated for VDD < 2.7V  (Not applicable, as VDD=3.3V)

Anything else to check?

Seth K
Pavel A.
Super User
October 1, 2023

without ditching the Nucleo for my own board

So on a Nucleo, with flying wires (?) you want > 3 MHz? Hmm.

sethkazAuthor
Associate III
October 1, 2023

If it could be isolated to the fact that it's on a Nucleo board w/ flying wires, then I'd be ok with spending the effort of making my own board.  

However, I can't get it to work at 2MHz with a SYSCLK of 16MHz.  The highest I can get it to work is 200kHz. And I'm able to scale that number from 200kHz to 2MHz by doing a similar jump of 10x in SYSCLK (which then puts me over my power budget). But that makes me think it's a setting issue or a fundamental limitation which I'm not aware of.  

So I'm trying to find that setting and/or fundamental issue. 

Seth K
waclawek.jan
Super User
October 1, 2023

I don't know how can clock glitch in slave mode. If MISO data glitch between bytes (frames) then it's inadequately written software, or internal bus limitation. E.g. you cannot throw some Cube/HAL code on it and expect it to have high performance.

JW

 

sethkazAuthor
Associate III
October 2, 2023

Here's what runs in USER CODE block 2 in main.c

void setup(void)
{
	//Fill this buffer for debug purposes. Otherwise can be commented out
	test_buf.abc.header = 0xAA00FFAA;
	test_buf.abc.footer = 0xFF003355;
	int ii=0;
	for (ii=0; ii<TEST_BUF_DATA_LENGTH; ii++){
		test_buf.abc.data.words[ii]=ii;
	}
	HAL_ADCEx_Calibration_Start(&hadc4, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);
	HAL_ADC_Start_DMA(&hadc4, (uint32_t *)adc_buf.words, ADC_BUF_LEN);
	HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
}

 And here's what runs in the while(1) loop of main.c in USER CODE WHILE.

void loop(void)
{
	//Turns on the green LED to show that it's ready for clock. Debug only.
	LED_GREEN_GPIO_Port->BSRR = (uint32_t)LED_GREEN_Pin; 

	HAL_SPI_Transmit_DMA(&hspi3, test_buf.bytes, TEST_BUF_LENGTH);
	HAL_Delay(10000);
}

I have also enabled the TX complete callback:

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi){
	// Turn off the Green LED, mimicking the enable pin for the clock.
	LED_GREEN_GPIO_Port->BRR = (uint32_t)LED_GREEN_Pin; //Debug purposes only
}

 For completeness, here is the test buffer definition:

#define TEST_BUF_DATA_LENGTH 10
#define TEST_BUF_LENGTH (4 + TEST_BUF_DATA_LENGTH* 2 + 4)

union{
	struct {
		uint32_t header;
		union {
			uint16_t words[TEST_BUF_DATA_LENGTH];
			uint8_t bytes[TEST_BUF_DATA_LENGTH*2];
		}data;
		uint32_t footer;
	}abc;
	uint8_t bytes[TEST_BUF_LENGTH];
}test_buf;

SPI Settings:

static void MX_SPI3_Init(void)
{

 /* USER CODE BEGIN SPI3_Init 0 */

 /* USER CODE END SPI3_Init 0 */

 SPI_AutonomousModeConfTypeDef HAL_SPI_AutonomousMode_Cfg_Struct = {0};

 /* USER CODE BEGIN SPI3_Init 1 */

 /* USER CODE END SPI3_Init 1 */
 /* SPI3 parameter configuration*/
 hspi3.Instance = SPI3;
 hspi3.Init.Mode = SPI_MODE_SLAVE;
 hspi3.Init.Direction = SPI_DIRECTION_2LINES_TXONLY;
 hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
 hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
 hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;
 hspi3.Init.NSS = SPI_NSS_SOFT;
 hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
 hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
 hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
 hspi3.Init.CRCPolynomial = 0x7;
 hspi3.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
 hspi3.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
 hspi3.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
 hspi3.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
 hspi3.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
 hspi3.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
 hspi3.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
 hspi3.Init.IOSwap = SPI_IO_SWAP_DISABLE;
 hspi3.Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY;
 hspi3.Init.ReadyPolarity = SPI_RDY_POLARITY_HIGH;
 if (HAL_SPI_Init(&hspi3) != HAL_OK)
 {
 Error_Handler();
 }
 HAL_SPI_AutonomousMode_Cfg_Struct.TriggerState = SPI_AUTO_MODE_DISABLE;
 HAL_SPI_AutonomousMode_Cfg_Struct.TriggerSelection = SPI_GRP2_LPDMA_CH0_TCF_TRG;
 HAL_SPI_AutonomousMode_Cfg_Struct.TriggerPolarity = SPI_TRIG_POLARITY_RISING;
 if (HAL_SPIEx_SetConfigAutonomousMode(&hspi3, &HAL_SPI_AutonomousMode_Cfg_Struct) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN SPI3_Init 2 */

 /* USER CODE END SPI3_Init 2 */

}

Scopeshots:

At 200kHz I get the correct frame out, and the callback triggers, sending channel 3 (PSEUDO_EN aka Green LED) low.

Correct Frame at 200k.png

At 300kHz, I still get the correct frame out, but with 2 noticeable behaviors.  First, channel 3 doesn't go low.  Second, I get an extra high bit(s) after the end of the frame.  

Correct frame, but no CB at 300k.png

 

Seth K
AScha.3
Super User
October 2, 2023

i think, you should stop this useless game. :)

spi is in frames, with some sync (nss) needed, otherwise its just nonsense.

AScha3_0-1696273689667.png

this is the spi - so to test it in any useful way, you have to send data/clk/nss in valid frames.

look at the block diagram of this spi : 

AScha3_1-1696274909080.png

what will it do, giving constant clk as slave ..? nobody knows.

with these setting i have slave receiver from esp8266, which has curious frame packets, but works fine at 16Mbit.

AScha3_2-1696275111572.png

so try with valid spi frame format, maybe just using other spi of this chip as master.

"If you feel a post has answered your question, please click ""Accept as Solution""."
sethkazAuthor
Associate III
October 2, 2023

The glitching I'm seeing is more due to my current setup.  This is definitely something I will fix, but that requires making a custom PCB.  I'm trying to eliminate as many fundamental issues (like that callback not being triggered) as I can before committing to a custom PCB.  

Example: 1MHz clock and the MISO line showing a good deal of overshoot along with some other noise sources coupling onto the measurement.  

Rising Edge at 1MHz.png

Seth K
sethkazAuthor
Associate III
October 2, 2023

So, after manually inspecting the frames, I'm able to get a complete frame out up to 14MHz.  However, the callback is not triggering on any of these, so my problem is still there.  

Seth K
sethkazAuthor
Associate III
October 3, 2023

@AScha.3 Unfortunately, I'm stuck playing this useless game. 

The root cause of the problem is that I need to create a serial data stream out of an MCU which is synced to an ever-present clock.  (This is for a client with a very specific design constraint, and one that I can't share :( )

I thought that either an SPI or USART peripheral would be the way to go, with the SPI being a little more malleable.  I was hoping the SPI would reject the clocks if there wasn't any valid data in the buffer to send.  Similarly, with the ability to SW control the NSS even in slave-mode, that seemed promising.

The SPI does seem to work with getting the data out (See prior post), but I am surprised that the callback falls apart.  I expected some timing variability, but not a situation where it never gets called.

The design I thought of to counteract the clocks was to have a flip-flop on the clock net, so that I could enable/disable, but also perform a divide-by-2 if needed.  

I will try running it in the proper SPI way, and see if some of these issues go away. 

Seth K
AScha.3
Super User
October 3, 2023

ah, more information...so not useless game here, just problematic preconditions . 

so maybe you should give some information, what are the fixed preconditions :

1. fixed cont. clk at  ...xxMHz ?

2. receiver can work with ...spi frame / serial uart input / - or ?

3. amount of data about ..Byte/sec . ?

4. receiver can be slave or master ?

5. distance xx m ? un-/screened cable ?

"If you feel a post has answered your question, please click ""Accept as Solution""."