cancel
Showing results for 
Search instead for 
Did you mean: 

SPI Half Duplex receive problem : No SCK

stéphane rey
Associate II

Dear all,

I'm trying to perform a simple blocking SPI communication with a slave (TFT driver) on my STM32F769NI-disco board.

I can transmit commands without any problem but I can't receive

Here is my init code called from main():

static void MX_SPI2_Init(void)
{
   /* SPI2 parameter configuration*/
  hspi2.Instance                = SPI2;
  hspi2.Init.Mode               = SPI_MODE_MASTER;                            
  hspi2.Init.Direction          = SPI_DIRECTION_1LINE;                   
  hspi2.Init.DataSize           = SPI_DATASIZE_8BIT;                      
  hspi2.Init.CLKPolarity        = SPI_POLARITY_HIGH;
  hspi2.Init.CLKPhase           = SPI_PHASE_2EDGE;
  hspi2.Init.NSS                = SPI_NSS_SOFT;                                
  hspi2.Init.BaudRatePrescaler  = SPI_BAUDRATEPRESCALER_32;       // PCLK2/8 = 10MHz
  hspi2.Init.FirstBit           = SPI_FIRSTBIT_MSB;                       
  hspi2.Init.TIMode             = SPI_TIMODE_DISABLE;                       
  hspi2.Init.CRCCalculation     = SPI_CRCCALCULATION_DISABLE;       
  hspi2.Init.CRCPolynomial      = 7;                                 
  hspi2.Init.CRCLength          = SPI_CRC_LENGTH_DATASIZE;               
  hspi2.Init.NSSPMode           = SPI_NSS_PULSE_DISABLE;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_NVIC_SetPriority(SPI2_IRQn, 5, 1);
  HAL_NVIC_EnableIRQ(SPI2_IRQn);
}

HAL_SPI_Transmit just works fine. I do not put the code for it here.

Here is the code for my SPI read data :

eST7735S_STATUS ReadData (volatile uint8_t *u8Data, uint8_t u8Size)
{
    volatile uint8_t u8test[4] = { }; // replace u8Data for test purpose for now
    volatile uint8_t u8SPIerror=0;
    volatile uint8_t u8State=0;
 
    while(__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_BSY) != RESET);
 
    vTaskSuspendAll();
 
    HAL_GPIO_WritePin(TFT_GPIO_PORT_DC, TFT_DC, LOW);              /* Set DC pin to data mode */
    
    u8SPIerror = HAL_SPI_Receive(&hspi2, (uint8_t*) u8test, (U16)1, (U32)500);
 
    xTaskResumeAll();
    if (u8SPIerror == HAL_OK)
         return TFT_SUCCESS;         
}

Then I perform a transmit of 1 byte to send a command to the slave and then try to read its answer.

eST7735S_STATUS ReadRDID1 (volatile U8 u8ManufacturerID)
{
    HAL_GPIO_WritePin(TFT_GPIO_PORT_CS, TFT_CS, LOW);               /* Set CS pin low */
      
    if (WriteCommand(ST7735_RDID1) != TFT_SUCCESS) return TFT_ERROR;
    if (ReadData(u8ManufacturerID, 1) != TFT_SUCCESS) return TFT_ERROR;
 
    HAL_GPIO_WritePin(TFT_GPIO_PORT_CS, TFT_CS, HIGH);              /* Set CS pin high */
 
    return TFT_SUCCESS;         
}

I transmit well my ST7735_RDID1 char on the SPI line and then call HAL_SPI_Receive but I've no clock on the SCK line which just goes low and the SPI_Receive routine goes to HAL_TIMEOUT.

By the way, if I set Direction to SPI_DIRECTION_2LINES instead of SPI_DIRECTION_1LINE

Then SCK is well sent (there is a dummy HAL_SPI_TransmitReceive in the HAL_SPI_Receive routine for the 2LINE mode) and my slave tries to answer but obviously this creates a short circuit with MOSI which isn't in three-state in that case.

What I'm doing wrong ??? How to get SCK toggling in half duplex ?

thanks

Stephane

6 REPLIES 6
stéphane rey
Associate II

added this in the init which I guess is useless :

  GPIO_InitTypeDef GPIO_InitStruct_SPI_SCK;
  GPIO_InitStruct_SPI_SCK.Pin = GPIO_PIN_12;
  GPIO_InitStruct_SPI_SCK.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct_SPI_SCK.Pull = GPIO_NOPULL;
  GPIO_InitStruct_SPI_SCK.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct_SPI_SCK); 
 
   GPIO_InitTypeDef GPIO_InitStruct_SPI_MOSI;
  GPIO_InitStruct_SPI_MOSI.Pin = GPIO_PIN_15;
  GPIO_InitStruct_SPI_MOSI.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct_SPI_MOSI.Pull = GPIO_NOPULL;
  GPIO_InitStruct_SPI_MOSI.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct_SPI_MOSI); 

No idea why I can't get SCK in HAL_SPI_Receive ????

Is BIDIMODE set? Is BIDIOE handled when going to receive?

Cube/HAL is open source, debug it as you own code.

JW

stéphane rey
Associate II

Yes I'm debugging HAL_SPI_Receive...

BIDIMODE is set during the configuration per the macro SPI_DIRECTION_1LINE ( = SPI_CR1_BIDIMODE)

However BIDIOE is not... I thought this was only for Tx ONLY or RX ONLY. Do we have to turn BIDIOE in Half Duplex mode between Tx and Rx ?

mmmm.... trying....

thanks

stéphane rey
Associate II

I've added around my HAL_SPI_Receive command the two following lines to turn on and off BIDIOE

SPI_1LINE_RX(&hspi2);
u8SPIerror = HAL_SPI_Receive(&hspi2, (U8*) u8test, 1, 10);
SPI_1LINE_TX(&hspi2);

This has still a strange behavior.

If I send an array of 4 bytes (u8test) to the HAL_SPI_Receive function specifying 1 byte of size :

volatile U8 u8test[4]= {0};
    while(__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_BSY) != RESET);
    volatile U8 u8SPIerror=0;
    volatile U8 u8State=0;
    HAL_GPIO_WritePin(TFT_GPIO_PORT_DC, TFT_DC, LOW);              /* Set DC pin to data mode  */
    SPI_1LINE_RX(&hspi2);
    u8SPIerror = HAL_SPI_Receive(&hspi2, (U8*) u8test, 1, 10);
    SPI_1LINE_TX(&hspi2);

then it sends 16-bits clock even if I specify the size to be 1 byte

0693W000001rh5dQAA.png

and if I send a unsigned char u8test instead of an array,

volatile U8 u8test= 0;

it sends 8-bits clock correctly but with incorrect voltage on the line :

0693W000001rh3IQAQ.png

The SPI starts to clock as soon as you turn it to receive and stops clocking when you turn it to transmit again. It's up to you to ensure the timing, it's not trivial and I don't believe Cube/HAL helps with this in any way.

You may want to bit-bang the protocol, if the extra clocks are an issue.

I don't know why the voltage on data line is incorrect, this may be due to the device on the other end of the line, too. Insert a resistor and measure at both ends to find out which "party" pulls the line to which level.

JW

stéphane rey
Associate II

Thanks for your feedback again.

I'm quite puzzled with what happens on a simple SPI peripheral....

With the following code :

    SPI_1LINE_RX(&hspi2);  // BIDIOE = 0
    u8SPIerror = HAL_SPI_Receive(&hspi2, (U8*) &u8test, 1, 10);
    SPI_1LINE_TX(&hspi2);  // BIDIOE = 1

what I see in step by step is that the clock is sent once I turn BIDIOE to 1 again and not before. It sounds strange to me but ok as I was expecting it would happen when turning BIDIOE to 0.

And then the number of clock bits as well as this strange levels on MOSI depends on the variable type for the buffer. If I set this buffer as an array of unsigned char I do receive my slave data (7C) but with an extra SCK byte whatever is the buffer length for which my slave do not take care, but if I change my buffer variable to a single unsigned char then I have the correct number of SCK bits but MOSI just get weird signals...

amazing to me...