Buenas, esta es la tercera vez que me toca toparme con una "limitacion" en el driver del bus SPI de un micro ARM. Esta situacion que voy a detallar me ha pasado con ST y con NXP, los ARM que uso normalmente. Voy a tratar de explicar el paso a paso para que se entienda lo que veo y como lo he tenido que solucionar.
El ptoyecto que voy a tratar de mejorar es el del cartel de LED RGB (
http://www.todopic.com.ar/foros/index.php?topic=43643.0), el cual voy a actualizar otro día ya que lo tengo funcionando.
En ese cartel, tengo 4 lineas para decodificar 1 de las 16 filas. Luego los drive de los led (TLC5954) necesitan 3 o 4 lineas, una de clock, una de data, una de latch y una de blank.
Mi programa tiene 2 buffer "graficos", uno que coincide con la cantidad de pixeles del cartel, el cual es el buffer donde yo puedo escrivir o cargar imágenes y el segundo es el buffer del SPI, el cual tiene la informacion tal cual la necesitan los TLC, incluyendo el color de cada pixel.
Luego tengo un timer, el cual me interrumpe cada vez que quiero actualizar una fila. Este timer tiene que correr a 16x frecuencia de Frame deseada. Por ejemplo, si quiero trabajar a 120Hz voy a necesitar escribir en cada fila en 1/(16*120)= 520.5 useg o lo que es lo mismo, cada 520.5 useg voy a tener que escribir una nueva fila. En principio, parece un montón de tiempo. Veamos, para manejar 4 módulos de 32 columnas (128 columnas u 8 TLC) necesito enviar 49*8 bits = 392 bits. Por lo que me da una frecuencia teórica de 752,64KHz en el SPI. Hay que tener en cuenta que hay algunos tiempos adicionales como el tiempo que necesario para cambiar de fila, el tiempo para activar la señal de BLANK, preparar la transferencia, etc. Supongamos que pongo el SPI a 1 MHz, debería ser suficiente.
Bien mi rutina del timer es la siguiente:
void TIMER16_0_IRQHandler(void)
{
if (Chip_TIMER_MatchPending(LPC_TIMER16_0, 1))
{
Chip_TIMER_ClearMatch(LPC_TIMER16_0, 1);
// Pongo las salidas de los TLC en 0
Chip_GPIO_SetPinOutHigh(LPC_GPIO, BLK_PORT, BLK_PIN);
// Enmascaro todos los bits del puerto 0 excepto los de direccion (A, B, C, D)
LPC_GPIO->MASK[0] = ~(0xF << A_PIN);
// Aplico el valor binario de la fila directamente al puerto
LPC_GPIO->PIN[0] = (15-ui8FilaActual) << A_PIN;
//Desenmascaro el puerto
LPC_GPIO->MASK[0] = 0;
Chip_SSP_WriteFrames_Blocking(LPC_SSP1, mem_DMA_01[ui8FilaActual], BYTES_X);
//una vez enviados los 49 datos hago un latch
Chip_GPIO_SetPinOutHigh(LPC_GPIO, LAT_PORT, LAT_PIN);
Chip_GPIO_SetPinOutLow(LPC_GPIO, LAT_PORT, LAT_PIN);
// Pongo las salidas de los TLC en ON
Chip_GPIO_SetPinOutLow(LPC_GPIO, BLK_PORT, BLK_PIN);
// Incremento el índice de fila actual
ui8FilaActual++;
// Cuando llego a la fila 16 vuelvo a 0
if(ui8FilaActual == 16){
ui8FilaActual=0;
}
}
}
Cuando pruebo el cartel funciona bien. Entonces voy al Analizador lógico y hago una adquisición para ver cuan sobrado de tiempo estoy:
En esta primer adquisicion se puede ver las señales de CLK, DATA, LATCH, BLANK y finalmente las 4 líneas de decodificacion de Fila. Como se ve, el delta X está en 520.5 useg y la medicion de frecuencia donde apunto con el mouse (CLK) es de 1 MHZ). En principio está todo como lo configuré.
Haciendo un zoom para ver una transmision entera obtengo:
He puesto los cursores para ver que me sobran 42 useg al finalizar la transmision. Por ahora estoy usando una funcion "bloqueante" del SPI.
Bien, el tema es que este cartel posee el doble de módulos, por lo que a 1 MHZ no voy a poder trabajar. Voy a tener que pasar a 2 MHz.
Hago el cambio y vuelvo a adquirir con el analizador lógico:
Aquí empieza a aparecer el problema que quiero compartir. Yo aumenté la velocidad del SPI al doble, pero sigo enviando la misma cantidad de bytes, 49. Uno pensaría que tendría que sobrarme más de 250 useg (cada cambio dura 520useg) sin embargo solo me sobran 180 useg!!!!! si ahí quisiera meter 49 bytes más no podría. En la captura se ve bien que no entrarían el doble de bytes. Por que???? Uno pensaría que en el SPI a 2 MHz puede sacar 49 bytes en 49 * 8 * 0.5 useg = 196 useg, sin embargo acá me esta tomando alrededor de 322 uSeg. Esta situacion se hace más notoria a medida que voy subiendo la velocidad de CLK del SPI. Y esto mismo me ha pasado en varias oportunidades con 2 micros de marcas distintas.
Veamos un poco el detalle del CLK de la transmision del SPI:
He aquí el problema. Cada 8 bits que envía, necesita casi 3 useg para hacer no se qué. O sea, envía 8 bits y le toma 4 useg, luego necesita 3 useg muertos y luego puede continuar con los siguientes 8 bits. Esos 3 useg, con tasas mayores hacen que la cosa no funcione. Por ejemplo, si pongo el SPI a 6 MHz tengo 1.25 useg para enviar 8bits y luego 5.4 useg de tiempo muerto!!!!
En la próxima, la solucion....