Tengo un problema con el ic FTDI FT232HL.
La aplicación de Windows envía datos al chip a través de USB y el chip envía los datos con un canal SPI.
Verifiqué con un analizador lógico, los bytes se envían correctamente y el reloj SPI coincide con la configuración. Sin embargo, entre cada byte, hay un retraso de 64uS, lo que significa que no importa qué tan alto sea el reloj SPI, la transferencia de datos toma minutos en lugar de segundos.
Me imaginé que tal vez jugar con channelConf.LatencyTimer ayudaría, pero no muestra ninguna diferencia sin importar el valor utilizado (10, 128, 255), el retraso permanece 64uS entre bytes consecutivos.
Debe haber algo que arreglar porque hay numerosos ejemplos de personas que alcanzan altas tasas de transferencia. Además, la demora entre bytes debería ser una configuración en alguna parte.
He usado código de muestra proporcionado con sample-dynamic.c El flujo de bytes se envía con una sola llamada a p_SPI_Write() con una longitud total de 2048 bytes. Probé otra longitud (256, 8192, etc.) sin cambios. Aquí está la configuración utilizada:
channelConf.ClockRate = 5000*1000;
channelConf.LatencyTimer= 10;
channelConf.configOptions = SPI_CONFIG_OPTION_MODE0| SPI_CONFIG_OPTION_CS_DBUS3/*|*/ ;
channelConf.Pin = 0x00000000; /* FinalVal-FinalDir-InitVal-InitDir (for dir: 0=in, 1=out) */
SO: Windows7 X64 Compiler: GCC Library y código de: http://www.ftdichip.com/Support/SoftwareExamples/MPSSE/LibMPSSE-SPI.htm
FYI: Me puse en contacto con el soporte de FTDI, me pidieron que actualizara las bibliotecas a la última (lo cual hice), luego no brindaron más soporte.
Cualquier ayuda apreciada. Gracias.
Por lo general, trabajo con el chip FT2232H, pero saqué un chip FT232HQ solo para poder verificar este problema que estaba teniendo. Es el mismo chip que el chip FT232HL que tiene, solo que en un paquete QFN en lugar de un QFP.
Intenté recrear el problema que describes, pero no pude hacerlo exactamente. Así es como se veía en mi analizador lógico cuando emitía 6 bytes a la vez a una velocidad de reloj de 5 MHz. Hay un pequeño retraso entre bytes, pero no tan grande como 64us.
Aquí hay algunas cosas para comprobar.
p_SPI_Write()
, use SPI_Write()
. Si realiza una sola llamada, agregue el chip apropiado, seleccione las banderas de activación y desactivación (consulte a continuación). Si realiza varias llamadas, asegúrese de agregar las banderas de selección de chip a la primera y última llamada de la serie.SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES
bandera.Aquí hay un código de ejemplo rápido sobre cómo enviar múltiples bytes de datos en caso de que ayude.
uint32 sizeToTransfer = 0;
uint32 sizeTransfered = -1;
uint8 buffer[256]; //Must be large enough for what you are sending.
FT_STATUS status;
//add data
buffer[sizeToTransfer++] = 0x20; //First data byte (can be what you need)
/*
* More bytes added....
*/
buffer[sizeToTransfer++] = 0x00; //Last data byte (can be what you need)
status = SPI_Write(*handle, buffer, sizeToTransfer, &sizeTransfered,
SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES |
SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE |
SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE);
//Don't forget to check status. It should equal FT_OK if everything went well
Descargo de responsabilidad: utilizo el FT2232H y no estoy 100 % seguro de si todas las declaraciones se pueden transferir a este caso.
Que yo sepa, ftdi mpsse spi no está realmente optimizado para un alto rendimiento de datos. Esto se vuelve obvio si uno mira más de cerca la fuente. En la versión actual (revisada el 24.04.2019) hay una llamada INFRA_SLEEP(2) dentro de la función SPI_ToggleCS que provoca un retraso de 2 ms cada vez que cambia el estado de la línea CS. Entonces, si necesita pulsar CS para cada palabra, está condenado. Incluso sin la llamada de suspensión, la latencia USB probablemente ralentizará severamente las cosas. Incluso sin esta llamada, el rendimiento máximo cae por debajo de las expectativas durante mis pruebas. Supongo que la razón de esto es la arquitectura de mpsse en sí. Así que, personalmente, recomendaría seguir con los protocolos admitidos de forma nativa como UART, opto rápido o FIFO para aplicaciones de alto rendimiento si es posible.
Por curiosidad (si este caso aún está abierto): ¿comprobó también si había diferentes controladores? ¿Puedes observar el mismo comportamiento para una PC diferente también?
Detrás de cada llamada a libMPSSE hay una llamada a FT_Write() que en realidad escribe un marco de datos en un USB de alta velocidad. Al usar las funciones de la biblioteca, por lo tanto, está restringido por la capa de comunicación USB (según lo informado por el soporte de FTDI).
La solución para obtener la máxima velocidad es bajar el nivel y almacenar los comandos en un gran FT_Write() para que los datos se empaqueten en un marco de transmisión USB:
{
Add to buffer: GPIO Write for CS lo
Add to buffer: Clock N bytes command
Add to buffer: N bytes of data
Add to buffer: GPIO write for CS hi
Add to buffer: Send immediate command (0x87) – only if you read bytes from the LTC device, not if you only write them
++ Repeat for other commands as much as possible for your use-case …
}
FT_Write of the above buffer
Solo para hacerle saber que creo que los controladores FTDI FT232HL tienen errores porque los errores desaparecen/aparecen según el concentrador/marca USB que se usa y la longitud del cable USB y la forma en que la computadora está "preparada". Al final compré una computadora específica y me quedé con ella para la producción en masa.
Algunos ayudantes:
Tiempo de llamadaBeginPeriod(4); antes de cargar los controladores FTDI ayuda mucho, solo tiene que verificar después de que se configuró el período de tiempo porque a veces Windows no puede actualizar el período (por cualquier motivo). Consulte el siguiente código para verificar si timeBeginPeriod(4) funcionó.
t1d=reloj(); BITBANG_usleep(5*1000);//5ms t2d=reloj(); tgastado=(((float)t2d-(float)t1d) / (CLOCKS_PER_SEC/1000)); if((int)tgastado > 8){ falló, ¡salga o vuelva a intentarlo! }
void BITBANG_usleep(unsigned int usdelay) { clock_t t1,t2; if(usdelay<16*1000)//16ms {t1=reloj(); while(1){t2=reloj(); if(((t2-t1)/ (CLOCKS_PER_SEC/(1000)))>usdelay/1000){break;}}} else {usleep(usdelay);} }
Use un cable corto y eventualmente use un HUB USB en el camino, mejora en gran medida la estabilidad, puede funcionar directamente durante cientos de horas sin problemas.
Espero que ayude, no es la mejor solución, ¡pero funcionó para mí!
chris stratton
ggade29
Ale..chenski
ggade29
Crog
Crog