2018-12-11 05:18 PM
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!!!