cancel
Showing results for 
Search instead for 
Did you mean: 

Read mode for SPI configured as half duplex master for stm32f405 - How do I read just 1 byte?

SClok
Associate

Hi STM community!

I am attempting to configure an ada2200 demodulator using an SPI communication line with an stm32f405 microcontroller acting as the bus master. To set up this peripheral, I need to set registers on the device via the SPI communication line, then read those registers back to ensure successful configuration. I need to set up the SPI as a half duplex communication line because the ada2200 only has one data pin for both reads from and writes to its registers.

I will attach samples of my code below, but here is a summary of what I have implemented so far. I am able to transmit instructions and register values over the mosi line of the SPI to the ada2200. I can see the correct bits being shifted into the ada2200 using a scope. However, when I try to perform a read using the SPI in half duplex mode using the HAL_SPI_Receive(spihandle, buffer, timeout) function, the clock signal cycles way too many times. I have pinpointed where this problem with the clock is arising. In the HAL_SPI_Receive function, if the SPI is set up as a half duplex line, SPI_1LINE_RX(hspi) will be called to set the bits in SPI's ctr1 register that indicate read only mode. After this call, I can see on the scope that the clock cycles continuously. I don't know why this is happening. Here is the code I use to set up the comms line. Any ideas?

void DemodulatorInit(SPI_HandleTypeDef *handle)
{
	DemodulatorHandle = handle;
 
	DemodulatorSetSpecifiedRegister(DEMODULATOR_INSTRUCTION_SERIAL_INTERFACE_REGISTER, DEMODULATOR_SERIAL_INTERFACE_REGISTER_SET);
	DemodulatorSetSpecifiedRegister(DEMODULATOR_INSTRUCTION_ANALOG_PIN_CONFIG_REGISTER, DEMODULATOR_ANALOG_PIN_CONFIG_REGISTER_SET);
	DemodulatorSetSpecifiedRegister(DEMODULATOR_INSTRUCTION_SYNC_CONTROL_REGISTER, DEMODULATOR_SYNC_CONTROL_REGISTER_SET);
	DemodulatorSetSpecifiedRegister(DEMODULATOR_INSTRUCTION_DEMOD_CONTROL_REGISTER, DEMODULATOR_DEMOD_CONTROL_REGISTER_SET);
	DemodulatorSetSpecifiedRegister(DEMODULATOR_INSTRUCTION_CLOCK_CONFIG_REGISTER, DEMODULATOR_CLOCK_CONFIG_REGISTER_SET);
 
	DemodulatorReadFromSpecifiedRegister(DEMODULATOR_INSTRUCTION_SERIAL_INTERFACE_REGISTER);
	DemodulatorReadFromSpecifiedRegister(DEMODULATOR_INSTRUCTION_ANALOG_PIN_CONFIG_REGISTER);
	DemodulatorReadFromSpecifiedRegister(DEMODULATOR_INSTRUCTION_SYNC_CONTROL_REGISTER);
	DemodulatorReadFromSpecifiedRegister(DEMODULATOR_INSTRUCTION_DEMOD_CONTROL_REGISTER);
	DemodulatorReadFromSpecifiedRegister(DEMODULATOR_INSTRUCTION_CLOCK_CONFIG_REGISTER);
}
 
void DemodulatorSetSpecifiedRegister(uint32_t reg, uint8_t value)
{
	HAL_GPIO_WritePin(ADA_CS_GPIO_Port, ADA_CS_Pin, GPIO_PIN_RESET);
	FillBuffWithInt32(&transmitToDemodulatorBuffer[0], 4, reg);
	HAL_SPI_Transmit(DemodulatorHandle, &transmitToDemodulatorBuffer[2], 2, 10);
	transmitToDemodulatorBuffer[0] = value;
	HAL_SPI_Transmit(DemodulatorHandle, &transmitToDemodulatorBuffer[0], 1, 10);
	HAL_GPIO_WritePin(ADA_CS_GPIO_Port, ADA_CS_Pin, GPIO_PIN_SET);
}
 
void DemodulatorReadFromSpecifiedRegister(uint32_t reg)
{
	HAL_GPIO_WritePin(ADA_CS_GPIO_Port, ADA_CS_Pin, GPIO_PIN_RESET);
	FillBuffWithInt32(&transmitToDemodulatorBuffer[0], 4, reg | DEMODULATOR_READ_ENABLE_MASK);
	HAL_SPI_Transmit(DemodulatorHandle, &transmitToDemodulatorBuffer[2], 2, 10);
	ClearBuffer(&receiveFromDemodulatorBuffer[0], 4);
	transmitToDemodulatorBuffer[0] = 0;
	HAL_SPI_Receive(DemodulatorHandle, &receiveFromDemodulatorBuffer[0], 1, 10);
	HAL_GPIO_WritePin(ADA_CS_GPIO_Port, ADA_CS_Pin, GPIO_PIN_SET);
}

Here is the HAL_SPI_Receive function for reference.

/**
  * @brief  Receive an amount of data in blocking mode.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @param  pData pointer to data buffer
  * @param  Size amount of data to be received
  * @param  Timeout Timeout duration
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
#if (USE_SPI_CRC != 0U)
  __IO uint16_t tmpreg = 0U;
#endif /* USE_SPI_CRC */
  uint32_t tickstart = 0U;
  HAL_StatusTypeDef errorcode = HAL_OK;
 
  if((hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES))
  {
     hspi->State = HAL_SPI_STATE_BUSY_RX;
     /* Call transmit-receive function to send Dummy data on Tx line and generate clock on CLK line */
    return HAL_SPI_TransmitReceive(hspi,pData,pData,Size,Timeout);
  }
 
  /* Process Locked */
  __HAL_LOCK(hspi);
 
  /* Init tickstart for timeout management*/
  tickstart = HAL_GetTick();
 
  if(hspi->State != HAL_SPI_STATE_READY)
  {
    errorcode = HAL_BUSY;
    goto error;
  }
 
  if((pData == NULL ) || (Size == 0))
  {
    errorcode = HAL_ERROR;
    goto error;
  }
 
  /* Set the transaction information */
  hspi->State       = HAL_SPI_STATE_BUSY_RX;
  hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
  hspi->pRxBuffPtr  = (uint8_t *)pData;
  hspi->RxXferSize  = Size;
  hspi->RxXferCount = Size;
 
  /*Init field not used in handle to zero */
  hspi->pTxBuffPtr  = (uint8_t *)NULL;
  hspi->TxXferSize  = 0U;
  hspi->TxXferCount = 0U;
  hspi->RxISR       = NULL;
  hspi->TxISR       = NULL;
 
#if (USE_SPI_CRC != 0U)
  /* Reset CRC Calculation */
  if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
  {
    SPI_RESET_CRC(hspi);
    /* this is done to handle the CRCNEXT before the latest data */
    hspi->RxXferCount--;
  }
#endif /* USE_SPI_CRC */
 
  /* Configure communication direction: 1Line */
  if(hspi->Init.Direction == SPI_DIRECTION_1LINE)
  {
    SPI_1LINE_RX(hspi);
  }
 
  /* Check if the SPI is already enabled */
  if((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE)
  {
    /* Enable SPI peripheral */
    __HAL_SPI_ENABLE(hspi);
  }
 
    /* Receive data in 8 Bit mode */
  if(hspi->Init.DataSize == SPI_DATASIZE_8BIT)
  {
    /* Transfer loop */
    while(hspi->RxXferCount > 0U)
    {
      /* Check the RXNE flag */
      if(__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE))
      {
        /* read the received data */
        (* (uint8_t *)pData)= *(__IO uint8_t *)&hspi->Instance->DR;
        pData += sizeof(uint8_t);
        hspi->RxXferCount--;
      }
      else
      {
        /* Timeout management */
        if((Timeout == 0U) || ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick()-tickstart) >=  Timeout)))
        {
          errorcode = HAL_TIMEOUT;
          goto error;
        }
      }
    }
  }
  else
  {
    /* Transfer loop */
    while(hspi->RxXferCount > 0U)
    {
      /* Check the RXNE flag */
      if(__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE))
      {
        *((uint16_t*)pData) = hspi->Instance->DR;
        pData += sizeof(uint16_t);
        hspi->RxXferCount--;
      }
      else
      {
        /* Timeout management */
        if((Timeout == 0U) || ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick()-tickstart) >=  Timeout)))
        {
          errorcode = HAL_TIMEOUT;
          goto error;
        }
      }
    }
  }
 
#if (USE_SPI_CRC != 0U)
  /* Handle the CRC Transmission */
  if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
  {
    /* freeze the CRC before the latest data */
    SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT);
 
    /* Read the latest data */
    if(SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_RXNE, SET, Timeout, tickstart) != HAL_OK)
    {
      /* the latest data has not been received */
      errorcode = HAL_TIMEOUT;
      goto error;
    }
 
    /* Receive last data in 16 Bit mode */
    if(hspi->Init.DataSize == SPI_DATASIZE_16BIT)
    {
      *((uint16_t*)pData) = hspi->Instance->DR;
    }
    /* Receive last data in 8 Bit mode */
    else
    {
      (*(uint8_t *)pData) = *(__IO uint8_t *)&hspi->Instance->DR;
    }
 
    /* Wait the CRC data */
    if(SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_RXNE, SET, Timeout, tickstart) != HAL_OK)
    {
      SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC);
      errorcode = HAL_TIMEOUT;
      goto error;
    }
 
    /* Read CRC to Flush DR and RXNE flag */
    tmpreg = hspi->Instance->DR;
    /* To avoid GCC warning */
    UNUSED(tmpreg);
  }
#endif /* USE_SPI_CRC */
 
  /* Check the end of the transaction */
  if((hspi->Init.Mode == SPI_MODE_MASTER)&&((hspi->Init.Direction == SPI_DIRECTION_1LINE)||(hspi->Init.Direction == SPI_DIRECTION_2LINES_RXONLY)))
  {
    /* Disable SPI peripheral */
    __HAL_SPI_DISABLE(hspi);
  }
 
#if (USE_SPI_CRC != 0U)
  /* Check if CRC error occurred */
  if(__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_CRCERR))
  {
    SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC);
    __HAL_SPI_CLEAR_CRCERRFLAG(hspi);
  }
#endif /* USE_SPI_CRC */
 
  if(hspi->ErrorCode != HAL_SPI_ERROR_NONE)
  {
    errorcode = HAL_ERROR;
  }
 
error :
  hspi->State = HAL_SPI_STATE_READY;
  __HAL_UNLOCK(hspi);
  return errorcode;
}

Here is my initialization of the SPI generated by cubeMX.

/* SPI1 init function */
static void MX_SPI1_Init(void)
{
 
  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_1LINE;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
}

Thanks so much!!!

0 REPLIES 0