stm32 SPI - extra clock cycle - Page 1
Forum section: electronics / general

author: gpr
author_rank: Contributor
timestamp: April 02, 2023, 09:02:41 pm
content: 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: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: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.

author: wek
author_rank: Frequent Contributor
timestamp: April 02, 2023, 09:56:13 pm
content: What's the SCK pin GPIO_OSPEEDR setting? If lowest, try one higher.JW

author: PCB.Wiz
author_rank: Super Contributor
timestamp: April 02, 2023, 11:25:58 pm
content: Quote from: gpr on April 02, 2023, 09:02:41 pmIf 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.

author: AVI-crak
author_rank: Regular Contributor
timestamp: April 03, 2023, 07:59:24 am
content: Quote from: gpr on April 02, 2023, 09:02:41 pmUse 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.

author: gpr
author_rank: Contributor
timestamp: April 03, 2023, 12:39:57 pm
content: Quote from: AVI-crak on April 03, 2023, 07:59:24 amOops, it seems you are right, I'll test the fix later.Initially, I had code like this:Code: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

author: NorthGuy
author_rank: Super Contributor
timestamp: April 03, 2023, 01:37:09 pm
content: 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.

author: gpr
author_rank: Contributor
timestamp: April 03, 2023, 02:23:33 pm
content: 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

author: DavidAlfa
author_rank: Super Contributor
timestamp: April 03, 2023, 08:58:03 pm
content: The correct way would be:Code:AD_SPI->CR2 = (AD_SPI->CR2 & ~(SPI_CR2_DS_Msk)) | (0b1111 << SPI_CR2_DS_Pos);Or using cmsis macro:Code: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:#define SPI_CR2_DS_Msk (0xFUL << SPI_CR2_DS_Pos) /*!< 0x00000F00 */#You can simply do:Code: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.