cancel
Showing results for 
Search instead for 
Did you mean: 

SPI bugs in F446/429?

Mikas Longbardi
Associate II
Posted on August 21, 2017 at 03:58

Surely this issue has been beaten to death already?

SPI3:

Are there any known 'end of byte/word transmit' function (soft/hardware)

working on SPI3 in master mode? Actually in 'any' mode,  im just doing

simple plain periodic (plenty of dead time in between transmits, not

constant that would hold BSY low) transmit with no interference (i hope)

of  NSS/SSI crap, only GPIO pin as strobe for external shift register.

I cant detect any SPI BSY being set during transmission as it should be!

Is there any specific setup flow and init of SPI logic needed?

SPI3->DR = ledbuff;                                  //Write SPI transmit reg 

while((SPI3->SR & SPI_SR_TXE) == 0)  //Test until TXE flag is 1

{}

while((SPI3->SR & SPI_SR_BSY) == 1)  //Test until Busy flag is 0

{}

According to errata for rev A of F446 and rev11 for F429 there are complex

bugs in SPI module and equal complex suggestions for workarounds that

apparently dont work ,BSY mentioned.

Is there a workaround that one could use RXNE (MISO-MOSI loopback)

or something else as a detector?

Contemplating use USART instead since it works out of the box by detecting

TC flag unfortunately USART's in synchronous mode is much slower then SPI.
14 REPLIES 14
Posted on August 21, 2017 at 08:13

Don't people use the RXNE flag to indicate the last bit out finished?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
William Warnots
Associate III
Posted on August 21, 2017 at 09:45

uint8_t dSPIN_Write_Byte(uint8_t byte)

{

/* Buffer used for transmission */

uint8_t aTxBuffer[] = {0x00};

/* Buffer used for reception */

uint8_t aRxBuffer[] = {0xF};

aTxBuffer[0] = byte;

HAL_GPIO_WritePin(dSPIN_nSS_Port, dSPIN_nSS_Pin, 0);

HAL_Delay(0.000003); //3000ns

if(HAL_SPI_TransmitReceive(&dSPIN_SPI, (uint8_t *)aTxBuffer, (uint8_t *)aRxBuffer, 1, 250) != HAL_OK)

{ }

while (__HAL_SPI_GET_FLAG(&dSPIN_SPI, SPI_FLAG_BSY) != 0);

HAL_GPIO_WritePin(dSPIN_nSS_Port, dSPIN_nSS_Pin, 1);

HAL_Delay(0.0008);

return aRxBuffer[0];

}
Mikas Longbardi
Associate II
Posted on August 21, 2017 at 20:25

>>>Don't people use the RXNE flag to indicate the last bit out finished?

That's what i thought could work in a 

MOSI-MISO loopback l

ast bit of transmit detect

in some modes other then master MOSI only but apparently it's not needed since this

works in

master MOSI only 

:

SPI3->DR = count;                                          //Write SPI transmit reg with counter value

while((SPI3->SR & SPI_SR_RXNE) == 0) {}  //Test RXNE flag is 1

GPIOC->BSRR |= GPIO_BSRR_BS_11;       //Set PC11 high, strobe signal start

GPIOC->BSRR |= GPIO_BSRR_BR_11;       //Set PC11 low, strobe signal end

dummy = SPI3->DR;                                       //Dummy read SPI RD to clear RXNE flag

Note:

CPOL=0 and CPHA=0 , data captured on rising CLK edge.

CLK rate lowest, then PC11 strobe are 2us late after last rising CLK edge

.

CLK rate highest, then PC11 strobe are ca 2uS late after 

last falling CLK edge.

Why? Havent investigated and frankly i dont care, wasted 

way 

to much time

on this crappy/buggy ST SPI design.

But it seams to be enough time for various HC shift registers other CMOS

shifters needs longer/delayed strobe times which can be fixed by adding

software as usual.

>>>

aRxBuffer, 1, 250) != HAL_OK)

Sorry dont use HAL only direct register but

 parts of your code is blocking by nature. 

Noticed ST seams to have 'redesigned' the SPI module in the upcoming H7, about time!

Posted on August 21, 2017 at 21:20

The peripheral is synchronous and symmetrical, same clock moving data in/out, with selectable phase

Don't do this (ie RMW)

GPIOC->BSRR |= GPIO_BSRR_BS_11;       //Set PC11 high, strobe signal start

GPIOC->BSRR |= GPIO_BSRR_BR_11;       //Set PC11 low, strobe signal end

Just write the register, it uses combinational logic to set or clear the specific bits you write into the BSRR

ie equivalent to GPIOC->ODR = (GPIOC->ODR | BSRRL) & ~BSRRH in a single atomic action

GPIOC->BSRR = (1 << 11); // Set bit 11

GPIOC->BSRR = (1 << (11 + 16)); // Clear bit 11

The USART and SPI have design complexity that an undergrad IC design major should be able to implement using 1990's schematic capture tools, and they didn't really understand practical uses cases for chip select. Definitely needed someone on the design team who had a better grip of logic, writing software drivers and actually using an assortment of SPI parts. They went to town on the I2C peripheral, but I'm not sure it helped the software implementation

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Mikas Longbardi
Associate II
Posted on August 21, 2017 at 23:31

>>The peripheral is synchronous and symmetrical, same clock moving data in/out, with selectable phase

The problem with BSY according to errata is that it loses synchronicity with bus clock, BSY can become

sporadic therefore ST recommends TXE, RXNE as detectors. Seams ST uninterested to fix it. 

>>Don't do this (ie RMW)

>>GPIOC->BSRR = (1 << (11+16));  //Set bit 11

But...

GPIOC->BSRR = (1 << 27);  //Clear bit 11..  is clearer.

Instead, can i do?:

GPIOC->BSRR = GPIO_BSRR_BS_11;  

 //Set PC11 high

GPIOC->BSRR = GPIO_BSRR_BR_11;  //Set PC11 low

It gives the same disassembly and timing as your suggestion.

And for those who wonder about the difference in timing.

This makes PC11 c:a 1.5uS late and 0.7uS wide. 10 instructions

GPIOC->BSRR |= GPIO_BSRR_BS_11; //Set PC11 high

GPIOC->BSRR |= GPIO_BSRR_BR_11; //Set PC11 low

This makes PC11 c:a 1.2uS late and 0.45uS wide. 6 instructions

GPIOC->BSRR = (1 << 11); // Set bit 11

GPIOC->BSRR = (1 << (11 + 16)); // Clear bit 11

Disclaimer:! I have an old uncalibrated shabby scope and no compiler optimization!

Back in c:a 1986-90+'ish we had 68HC11F1  who had splendid auto address,  auto CS toggle SPI

well working bug free and superb documentation, ST designers should read that manual

to get inspiration.

Posted on August 22, 2017 at 01:51

>>

Seams ST uninterested to fix it. 

I think it is a stance of not creating dozens of stepping to have to special case, and not having people with legacy golden firmware images suddenly not behaving in a constant/predictable way from one order of chips to another.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Mikas Longbardi
Associate II
Posted on August 22, 2017 at 20:19

>>>I think it is a stance of not creating dozens of stepping to have to special case, and not having

>>>people with legacy golden firmware images suddenly not behaving in a constant/predictable

>>>way from one order of chips to another.

It might be so, but perhaps a bit of a contradiction since customers are  recommended to use RXNE

instead of BSY so if they fix BSY it would still be compatible and transparent with ST suggested

RXNE etc workarounds.

I bet it's about economics and not firmware, ST screwed it up so they thought it's cheaper to use

RXNE then to fix BSY logic and that makes perfect sense out of an economic situation.

If i would be the ST top head boss of MCU design i would indeed make the same decision.

So did ST ever fix I2C logic  or should i just go soft pin toggling instead? Pherhaps they fixed in H7?

mckenney
Senior
Posted on August 25, 2017 at 18:35

while((SPI3->SR & SPI_SR_BSY) == 1)  //Test until Busy flag is 0

Um, SPI_SR_BSY is 0x80, not 0x01.

Mikas Longbardi
Associate II
Posted on August 26, 2017 at 12:15

Good Loordy yes!