¿Cuál es el propósito de HAL_SPI_TransmitReceive y cómo funciona?

Estoy tratando de entender cómo funciona esta función a pesar de que hay tanta gente quejándose de ello. Mis preguntas son estas:

1) ¿Cuál es la diferencia entre usar esto en mi código:

HAL_SPI_Transmit (SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
HAL_SPI_Receive (SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

y esto:

HAL_SPI_TransmitReceive (SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)

Quiero decir, si uso la función Transmitir primero y luego inmediatamente después, uso la función Recibir , ¿cuál es la diferencia con usar solo TransmitReceive ?

El único problema que se me ocurre es el de recibir mientras se envía. Por ejemplo, digamos que quiero enviar 4 bytes al Esclavo y recibir de él 7 bytes. Entonces hay 2 escenarios:

1er escenario: Si mi dispositivo Esclavo envía datos solo después de que el Maestro haya enviado todos sus datos, lo que significa que el Esclavo esperará que el Maestro envíe 4 bytes y luego ( Esclavo ) comenzará a enviar sus datos y luego el código que debería funcionar es el

HAL_SPI_Transmit(&hspi1,txData,4,TIMEOUTVALUE);
HAL_SPI_Receive(&hspi1,rxData,7,TIMEOUTVALUE);

porque, por lo que puedo pensar, TransmitReceive comenzará a recibir desde el principio, por lo que los primeros 4 bytes recibidos serán basura y los últimos 3 recibidos serán los primeros 3 transmitidos desde el Esclavo .

2do escenario: si mi dispositivo esclavo envía datos después de que el maestro haya enviado solo el primer byte de sus datos, lo que significa que el esclavo va a esperar que el maestro envíe 1 byte y luego ( esclavo ) comenzará a enviar sus datos entonces el código que debería funcionar es el

HAL_SPI_TransmitReceive(&hspi1,txData,rxData,12,TIMEOUTVALUE);

(12 = 4 + 7 + un byte que es el primer byte recibido, que es ficticio porque el esclavo comienza a transmitir después de que el maestro envía el primer byte ).

2) ¿Cómo se usa la variable de tamaño uint16_t en la función TransmitReceive ? Si quiero enviar 4 bytes y simultáneamente recibir 7, ¿voy a usar 11 en la variable de función?

SPI es bidireccional, las funciones unidireccionales desperdician la mitad de la oportunidad. Debería poder decidir cuál usar de eso, por supuesto, siempre puede usar el bidireccional y hacer su propio descarte de datos de recepción o proporcionar datos de envío ficticios.

Respuestas (2)

SPI es una interfaz muy específica y el esclavo solo puede transmitir si el maestro transmite. Tienes que transmitir datos ficticios para recibir algo.

Por lo tanto, no puede enviar 4 bytes y recibir 7. Necesitará enviar tantos datos como sea necesario.

En cada byte enviado por el maestro, el esclavo también envía un byte. Si el esclavo comienza a enviar datos valiosos después de recibir 4 bytes y espera recibir 7 del esclavo, debe enviar 11 bytes.

Entonces, en el escenario 2, ¿cuántos datos debo enviar y recibir?

Una observación interesante de STM32Cube creó archivos HAL para stm32f103: si SPI está configurado como maestro, HAL_SPI_Receiveusa HAL_SPI_TransmitReceive. Envía bytes basura en pData (búfer para recibir bytes del otro extremo) como bytes ficticios.

HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
  uint32_t tickstart;
  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);
  }

 // ....
}