Что такое HAL_SPI_TransmitReceive и как это работает

Я пытаюсь понять, как работает эта функция, хотя на нее так много людей жалуется. Мои вопросы таковы:

1) В чем разница между использованием этого в моем коде:

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)

и это:

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

Я имею в виду, если я сначала использую функцию Transmit , а затем сразу после нее я использую функцию Receive , в чем разница с использованием только TransmitReceive ?

Единственная проблема, о которой я могу думать, это получение при отправке. Например, допустим, что я хочу отправить 4 байта Slave и получить от него 7 байт. Тогда есть 2 сценария:

1-й сценарий: если мое ведомое устройство отправляет данные только после того, как ведущее устройство отправило все свои данные, это означает, что ведомое устройство будет ждать ведущего , чтобы отправить 4 байта, а затем оно ( ведомое ) начнет отправлять свои данные, тогда код, который должно работать это

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

потому что, насколько я могу себе представить, TransmitReceive начнет получать с самого начала, поэтому первые 4 полученных байта будут мусором, а последние 3 полученных будут первыми 3 переданными от ведомого ?

2-й сценарий: если мое ведомое устройство отправляет данные после того, как ведущее устройство отправило только первый байт своих данных, это означает, что ведомое устройство будет ждать ведущего , чтобы отправить 1 байт, а затем оно ( ведомое ) начнет отправлять свои данные, а затем код, который должен работать, это

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

(12 = 4 + 7 + один байт, который является первым полученным байтом, который является фиктивным, потому что Ведомый начинает передачу после того, как 1-й байт отправлен Мастером ) .

2) Как переменная размера uint16_t используется в функции TransmitReceive ? Если я хочу отправить 4 байта и одновременно получить 7, буду ли я использовать 11 в переменной функции?

SPI двунаправленный, однонаправленные функции отбрасывают половину возможностей. Вы должны быть в состоянии разобраться, что использовать из этого, конечно, вы всегда можете использовать двунаправленный и самостоятельно отбрасывать полученные данные или предоставлять фиктивные данные отправки.

Ответы (2)

SPI — это очень специфический интерфейс, и ведомое устройство может передавать только в том случае, если ведущее устройство передает. Вы должны передать фиктивные данные, чтобы что-то получить.

Таким образом, вы не можете отправить 4 байта и получить 7. Вам нужно будет отправить столько данных, сколько необходимо.

На каждый байт, отправленный ведущим ведомым, также отправляется один байт. Если подчиненное устройство начинает отправлять ценные данные после получения 4 байтов, а вы ожидаете получить 7 от подчиненного устройства, вам необходимо отправить 11 байтов.

Итак, в сценарии 2, сколько данных я должен отправить-получить

Интересное наблюдение от STM32Cube создало HAL-файлы для stm32f103: если SPI настроен как Master, HAL_SPI_Receiveсам использует HAL_SPI_TransmitReceive. Он отправляет мусорные байты в pData (буфер для приема байтов с другого конца) как фиктивные байты.

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

 // ....
}