Skip to main content
N ORhan
Associate III
November 9, 2018
Question

SPI clock is not clocking!

  • November 9, 2018
  • 7 replies
  • 1333 views

Hi everyone, i'm trying to read some data from an accelerator and for this purpose using SPI. I'm using NUCLEO-F401RE board. So after enabling SPI, clock pin goes HIGH as i want (CPOL=1) but when i send data CLK stays as HIGH until i disable SPI, meaning that it does not clock! What is the possible causes of this problem? What am i doing wrong?

Thanks.

This topic has been closed for replies.

7 replies

Tesla DeLorean
Guru
November 9, 2018

>>What am i doing wrong?

Let's not play guessing games, attach a minimal project that illustrates the condition. ZIP to a single file.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
N ORhan
N ORhanAuthor
Associate III
November 9, 2018

OK Clive, first is my spi.c file and the second is main. I'm using SPI2 (PB10, PB14, PB15) and PB9 as slave select as GPIO output.

.............................................................111111111111111.................................................................

#include "spi.h"

void SPI2_Config(void)

{

RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;

RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;

GPIOB->MODER |= GPIO_MODER_MODER10_1 | GPIO_MODER_MODER14_1 | GPIO_MODER_MODER15_1;

GPIOB->MODER &= ~(GPIO_MODER_MODER10_0 | GPIO_MODER_MODER14_0 | GPIO_MODER_MODER15_0);

GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR10 | GPIO_OSPEEDER_OSPEEDR14 | GPIO_OSPEEDER_OSPEEDR15;

GPIOB->AFR[1] |= 5UL<<8 | 5UL<<24 | 5UL<<28; //Alternating function 5 for SPI2

//Configure PB9 as output GPIO as NSS//

GPIOB->MODER |= GPIO_MODER_MODER9_0;

GPIOB->MODER &= ~GPIO_MODER_MODER9_1;

GPIOB->OTYPER &= ~GPIO_OTYPER_OT_9;

GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9;

GPIOB->ODR |= GPIO_ODR_ODR_9;

SPI2->CR1 = 0x0000;

SPI2->CR1 |= SPI_Direction_2Lines_FullDuplex | SPI_CR1_SSM | SPI_BaudRatePrescaler_32 | SPI_CR1_MSTR | SPI_CPOL_High | SPI_CPHA_2Edge;

SPI2->CR2 |= SPI_CR2_SSOE;

for(uint32_t i=0; i<1000000; i++);

}

void SPI2_Enable(void)

{

SPI2->CR1 |= SPI_CR1_SPE;

}

void SPI2_Disable(void)

{

SPI2->CR1 &= ~SPI_CR1_SPE;

}

void SPI2_SendData(uint8_t data)

{

SPI2->DR = data;

}

uint16_t SPI2_ReceiveData(void)

{

return SPI2->DR;

}

..........................................................2222222222222222......................................................................

int main(void)

{

Clock_Config();

SPI2_Config();

GPIOB->ODR &= ~GPIO_ODR_ODR_9;

for(uint32_t i=0; i<1000000; i++);

SPI2_Enable();

for(uint32_t i=0; i<1000000; i++);

SPI2_SendData(0x8F);

while(!((SPI2->SR)&(SPI_SR_TXE)));

while(!((SPI2->SR)&(SPI_SR_RXNE)));

while((SPI2->SR)&(SPI_SR_BSY));

received_data = SPI2_ReceiveData();

SPI2_Disable();

for(uint32_t i=0; i<1000000; i++);

GPIOB->ODR |= GPIO_ODR_ODR_9;

 /* Infinite loop */

 while (1)

 {

 }

}

waclawek.jan
Super User
November 9, 2018

Read back the GPIO registers and check if they are set as you think they are. And, if they are not, swap these two statements:

RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;

RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;

to avoid the "some time is needed between enabling (GPIO) clock in RCC until the enabled peripheral gets really available" problem (look into the errata).

JW

N ORhan
N ORhanAuthor
Associate III
November 10, 2018

Thank you for your answer JW. I checked all registers of the corresponding GPIO's and all of them are as i want them to be. When i checked on oscilloscope after enabling SPI2 clock goes HIGH as i want and when i send data it does not alternate. Also MOSI signal goes HIGH just after sending the data and it stays HIGH too.

T J
Senior III
November 10, 2018

I would suggest that you enable the SPI at startup and never disable it..

are you sure about this?

SPI2_SendData(0x8F);
while(!((SPI2->SR)&(SPI_SR_TXE)));
while(!((SPI2->SR)&(SPI_SR_RXNE)));
while((SPI2->SR)&(SPI_SR_BSY));
received_data = SPI2_ReceiveData();

how do you know the SPI is not busy before you send the data ?

how do you know the RxData you receive is fresh and not double buffered and old.?

N ORhan
N ORhanAuthor
Associate III
November 10, 2018

Thanks TJ, i got your warnings. I add BUSY flag control before SPI2_SendData() function but how can i control double buffering? For 16 clock cycle RX buffer can be full once isn't it?

T J
Senior III
November 10, 2018

I think you are on the right track but we could be here forever...

Here you can see, we drop the nSS, transfer the address and read a byte, then lift the nSS.

I run the InitSPI once at startup, just to satisfy HAL... ( I dont drop the nSS during initialisation)

void initSPI(void) {
 int8_t TxSPIBuffer[1];
 int8_t RxSPIBuffer[1];
 TxSPIBuffer[0] = 0xFF;
 HAL_SPI_TransmitReceive(&hspi1, (uint8_t*)TxSPIBuffer, (uint8_t *)RxSPIBuffer, 1, 10);
}
 
int8_t readLis3DEByte(char address) {
 address &= 0x3F; // 6bit address
 address += 0x80; // Read
 address += 0x40; // Auto Increment
 HAL_GPIO_WritePin(LIS3DE_nSS_GPIO_Port, LIS3DE_nSS_Pin, GPIO_PIN_RESET);
 
 transfer(address);
 char dummyByte = 0;
 char RxSPI = transfer_receive(dummyByte);
 
 HAL_GPIO_WritePin(LIS3DE_nSS_GPIO_Port, LIS3DE_nSS_Pin, GPIO_PIN_SET);
 return RxSPI;
}
void transfer(unsigned short data) { // send only
 char RxSPI;
 
 while (!(hspi1.Instance->SR & SPI_FLAG_TXE)) ; //wait until finished sending the last byte
 *((__IO uint8_t *)&hspi1.Instance->DR) = data;
 RxSPI = hspi1.Instance->DR; // read Rx byte and discard, only clearing the buffer
}
char transfer_receive(unsigned short data) { // send and receive byte
 char RxSPI; 
 while(!(hspi1.Instance->SR & SPI_FLAG_TXE)) // make sure the last byte is gone.
 ;
 while ((hspi1.Instance->SR & SPI_FLAG_RXNE)) // unload any fifo
 RxSPI = hspi1.Instance->DR; //empty and dump all fifo bytes
 
 *((__IO uint8_t *)&hspi1.Instance->DR) = data; // force the SPI to transceive 8 bit
 while(!(hspi1.Instance->SR & SPI_FLAG_TXE)) // wait to transmitter double buffer to shift into transmitter
 ; 
 while ((hspi1.Instance->SR & SPI_FLAG_BSY)) ; // wait for data to shift out of the processor pins
 while((hspi1.Instance->SR & SPI_FLAG_RXNE)) // read all the bytes received, only keep the last one
 RxSPI = hspi1.Instance->DR; // we only want the last byte
 
 return RxSPI;
}