cancel
Showing results for 
Search instead for 
Did you mean: 

SPI clock is not clocking!

N ORhan
Associate III

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.

7 REPLIES 7

>>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
Up vote any posts that you find helpful, it shows what's working..
N ORhan
Associate III

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)

 {

 }

}

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

T J
Lead

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.?

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.

N ORhan
Associate III

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
Lead

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;
}