¿Por qué la operación de lectura SPI de 4 cables necesita que lea la línea MISO en cada operación de transmisión?

Deseo leer un dispositivo esclavo SPI. Así es como pensé que sería el procedimiento:

CS_BAJO

  1. SPI_Write(dirección_esclavo)
  2. SPI_Write(registro)
  3. SPI_Write(0x00) //byte ficticio
  4. datos = SPI_Read()

CS_ALTO

Sin embargo, esto no funciona. Para que funcione, esto es lo que tengo que seguir:

CS_BAJO

  1. SPI_Write(dirección_esclavo)
  2. temperatura = SPI_Read()
  3. SPI_Write(registro)
  4. temperatura = SPI_Read()
  5. SPI_Write(0x00) //byte ficticio
  6. datos = SPI_Read()

CS_ALTO

¿Por qué tengo que leer los datos en la línea MISO incluso cuando sé que no habrá nada deseable?

PD: Las funciones SPI Read() y Write() son solo mis propias implementaciones, nada en particular para una sola MCU.

Editar: según lo solicitado, proporciono algunos detalles sobre las MCU.

Estoy usando dos MCU: STM32F303VCT y TI TIVA123GH6PM . Ambas MCU requieren que siga dicho procedimiento.

Aquí está mi implementación de la función de transmisión y recepción SPI en STM32

uint8_t SPI_rdwr(uint8_t data)
{
    
    *(__IO uint8_t *)&SPI1->DR = data;              //send data
    
    while(!(SPI1->SR & SPI_SR_TXE));                // wait till TX buffer is empty
    
    while(SPI1->SR & SPI_SR_BSY);                  // wait if SPI line is busy
    
    while(!(SPI1->SR & SPI_SR_RXNE));               //wait till RX buffe is NOT empty                   

    return *(__IO uint8_t *)&SPI1->DR;          //return data if data received on MISO line
    
}
Es solo la naturaleza de la transmisión de datos full-duplex.
Si funciona o no, depende de la MCU y la implementación de SPI que tenga y el código que escribió para usarlo. ¿Divulgarías qué MCU estás usando para responder esto?
Puede ser que SPI_Read sea lo que registra los datos de LECTURA en la CPU ... y por lo tanto también registra los datos de ESCRITURA en el periférico. Si es así, omitirlo no funcionará.
O el hardware SPI tiene un búfer de lectura que puede recibir, por ejemplo, un byte y no se actualizará desde el registro de desplazamiento a menos que se lea. No lo sabemos a menos que @Luffy nos proporcione la marca/modelo exacto de MCU y proporcione un código para ver qué está mal.
Dado que es su propia implementación, díganos qué hace la función SPI_Read()
@Justme He agregado algunos detalles como edición.
@ user253751 He agregado algunos detalles ahora. Por favor, míralo. En mi subrutina he combinado los procedimientos de transmisión y recepción en uno. Tengo una función de transmisión separada donde solo 1. escribo en el registro de datos y 2. espero hasta que el búfer TX esté vacío. Uso la función de transmisión cuando solo deseo escribir en un registro particular en un dispositivo esclavo.
Entonces mi conjetura es: si el búfer de recepción está lleno, obtienes una condición de falla que detiene SPI.
@Luffy Pero tu spi_rdwr no coincide con lo que preguntaste primero. Depende del esclavo cómo funciona, pero su rdwr debería funcionar bien para la operación full-duplex y, de hecho, STM32 SPI requiere que lea el búfer de recepción o no se actualizará con los datos recibidos. El rdwr ahora transmite y recibe un byte. Y no mencionas con qué esclavo te comunicas, así que no puedo decirte si el protocolo es correcto o no.
@Justme es un expansor IO MCP23S17. La mayoría de los dispositivos esclavos requieren el envío de 3 bytes en un ciclo de selección de chip, es lo que me imagino. El rdwr en el código simplemente integra las funciones SPI_Write y SPI_Receive que mencioné como un algoritmo, ya que la escritura es seguida por una lectura de todos modos.
@Luffy No, te imaginas mal, cualquier dispositivo es libre de elegir el protocolo que eligieron los diseñadores. MCP23S17 es un poco extraño. Requiere escritura de código de operación, registro y luego escritura o lectura de datos. No hay bytes ficticios, por lo que ninguna de las secuencias que presentó es correcta.
@Luffy Justme tiene razón. SPI es solo una forma de mover bytes. Lo que significan esos bytes y, lógicamente, quién es el que escribe y quién es el lector es completamente arbitrario, y la operación de dúplex completo también es posible y algunos dispositivos pueden admitirlo bien, mientras que otros hacen un trabajo mediocre.

Respuestas (1)

¿Por qué la operación de lectura SPI de 4 cables necesita que lea la línea MISO en cada operación de transmisión?

Porque:

  1. Por razones de rendimiento, los implementadores de HAL escribieron SPI_Write sin el bucle "esperar a que el registro de transmisión esté vacío" incorporado, pero SPI_Readtiene dicho bucle. En ese caso, emitir escrituras sin lecturas sobrecargaría el búfer. Su implementación también desperdicia tiempo en ese ciclo: una vez que puede leer, también puede escribir; o

  2. La biblioteca de abstracción de hardware (HAL) que está utilizando configura el silicio para que funcione de esa manera, cuando el silicio no requiere que sea así,

  3. y tal vez no estés configurando el HAL para que lo haga de la forma que quieres, en caso de que el HAL lo admitiera (y necesariamente también el silicio); o

  4. tal vez no esté configurando el silicio para que haga lo "correcto" cuando el silicio lo permite; o

  5. el silicio está diseñado para funcionar de esa manera y no de otra manera.

No recuerdo los detalles de la implementación de SPI en los chips que está utilizando, pero:

  1. Algunas implementaciones de SPI pueden tener el receptor apagado y, por lo tanto, las lecturas no serán necesarias ya que esa función estará deshabilitada.

  2. SPI probablemente se puede usar con DMA, por lo que no le importará demasiado la sobrecarga de hacer las lecturas.

  3. Incluso si lo hace en software, las lecturas pueden ser baratas. No usar HAL probablemente también ayudaría con eso, aunque asegúrese de compilar el código en una configuración de versión optimizada y auditar el ensamblado para confirmar que no hace nada innecesario. Incluso su código escrito a mano hace cosas innecesarias.