Author Topic: stm32 SPI - extra clock cycle  (Read 1314 times)

0 Members and 1 Guest are viewing this topic.

Offline gprTopic starter

  • Contributor
  • Posts: 37
  • Country: gb
stm32 SPI - extra clock cycle
« on: April 02, 2023, 09:02:41 pm »
Hi.
I'm writing a piece of code which sends data via SPI from stm32l432kc, spi mode 2 (cpol = 1, phase = 0, 16 bits).
I don't use any library for that, just cmsis (bare metal).

SPI initialization:
Code: [Select]
AD_SPI->CR1 = 0;
constexpr uint32_t cr1 = (0b111 << SPI_CR1_BR_Pos) | SPI_CR1_MSTR_Msk | SPI_CR1_CPOL_Msk;
AD_SPI->CR1 = cr1;
AD_SPI->CR2 |= ~(SPI_CR2_DS_Msk) | (0b1111 << SPI_CR2_DS_Pos);
AD_SPI->CR1 = cr1 | SPI_CR1_SPE;

Writing to SPI:
Code: [Select]
while(! (spi_->SR & SPI_SR_TXE)) {}
spi_->DR = data;
while(! (spi_->SR & SPI_SR_RXNE)) {}
const uint16_t r = spi_->DR;

Attached is a scope screenshot of writing 0xC003 just to test, (two 1's at the beginning and at the end of 16 bits of data). Protocol decoder shows 0xE001, looks like extra 1 is added at the beginning, and the last bit is lost.
Tried to change different SPI settings, and SPI-writing code, it really doesn't change anything. I use the slowest SPI speed, clocks freq is about 15kHz, it doesn't look like signal integrity issue at all. Will try to test on another stm32 in a few days, but for now I'm stuck.

Any ideas what is happening there?


Screenshot attached, channels are SCK, MOSI, NSS.
 

Offline wek

  • Frequent Contributor
  • **
  • Posts: 551
  • Country: sk
Re: stm32 SPI - extra clock cycle
« Reply #1 on: April 02, 2023, 09:56:13 pm »
What's the SCK pin GPIO_OSPEEDR setting? If lowest, try one higher.

JW

 

Offline PCB.Wiz

  • Super Contributor
  • ***
  • Posts: 2241
  • Country: au
Re: stm32 SPI - extra clock cycle
« Reply #2 on: April 02, 2023, 11:25:58 pm »
stm32 SPI - extra clock cycle
If you have an extra pulse problem, it can be helpful to insert a delay between init SPI and sending, as that can show edges from init stage.
Also try varying shift lengths, if supported.
 

Offline AVI-crak

  • Regular Contributor
  • *
  • Posts: 141
  • Country: ru
    • Rtos
Re: stm32 SPI - extra clock cycle
« Reply #3 on: April 03, 2023, 07:59:24 am »
I don't use any library for that, just cmsis (bare metal).
Use the macro from cmsis "_VAL2FLD(field, value)" - this will help to avoid errors.
AD_SPI->CR2 |= ~(SPI_CR2_DS_Msk) | (0b1111 << SPI_CR2_DS_Pos); - a clear error, all bits of the register will be set to 1.
 
The following users thanked this post: gpr

Offline gprTopic starter

  • Contributor
  • Posts: 37
  • Country: gb
Re: stm32 SPI - extra clock cycle
« Reply #4 on: April 03, 2023, 12:39:57 pm »
I don't use any library for that, just cmsis (bare metal).
Use the macro from cmsis "_VAL2FLD(field, value)" - this will help to avoid errors.
AD_SPI->CR2 |= ~(SPI_CR2_DS_Msk) | (0b1111 << SPI_CR2_DS_Pos); - a clear error, all bits of the register will be set to 1.
Oops, it seems you are right, I'll test the fix later.
Initially, I had code like this:
Code: [Select]
AD_SPI->CR2 = (AD_SPI->CR2 & ~(SPI_CR2_DS_Msk | some_other_msk)) | (0b1111 << SPI_CR2_DS_Pos)
But at some point I made a mistake here  :palm:
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3317
  • Country: ca
Re: stm32 SPI - extra clock cycle
« Reply #5 on: April 03, 2023, 01:37:09 pm »
There are different SPI modes. In some modes, the slave samples the data line at the rising edge of the clock. In other modes, the slave samples the data line at the falling edge of the clock.

The SPI signal you produce is meant to be sampled at the falling edge and it is perfectly fine.

The decoder, however, samples the data line at the rising edge.

Hence the difference.
 
The following users thanked this post: SiliconWizard

Offline gprTopic starter

  • Contributor
  • Posts: 37
  • Country: gb
Re: stm32 SPI - extra clock cycle
« Reply #6 on: April 03, 2023, 02:23:33 pm »
Looking at the signal itself, looks like scope's decoding is correct. And its decoder has a knob to sample on raising/falling edge, at least on my scope, and it was set correctly.

I suspect SPI was in TI mode or something like that, because I was writing crap to CR2
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6470
  • Country: es
Re: stm32 SPI - extra clock cycle
« Reply #7 on: April 03, 2023, 08:58:03 pm »
The correct way would be:
Code: [Select]
AD_SPI->CR2 = (AD_SPI->CR2 & ~(SPI_CR2_DS_Msk))  | (0b1111 << SPI_CR2_DS_Pos);

Or using cmsis macro:
Code: [Select]
MODIFY_REG(AD_SPI->CR2, SPI_CR2_DS_Msk, 0b1111 << SPI_CR2_DS_Pos);

But since SPI_CR2_DS_Msk is the same value as 0b1111 << SPI_CR2_DS_Pos:
Code: [Select]
#define SPI_CR2_DS_Msk           (0xFUL << SPI_CR2_DS_Pos)                     /*!< 0x00000F00 */#

You can simply do:
Code: [Select]
AD_SPI->CR2 |= SPI_CR2_DS_Msk;

Try LL, it's pretty good, no handlers wasting memory, it's made of short, specific functions and macros, in the end they do the same as what you're doing.
« Last Edit: April 04, 2023, 08:19:50 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 
The following users thanked this post: gpr


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf