Creo una clase de pantalla OLED para el SSD1306 y su funcionamiento es bastante sencillo. La pantalla se almacena en búfer (método fuera de pantalla) y, al realizar una actualización, "descarga" el búfer a la pantalla a través de I2C, en este caso un total de 512 bytes (128x32 píxeles), pero también puede ser de 1024 bytes (128x64 píxeles).
El método fuera de pantalla es evitar el parpadeo y el rendimiento más rápido porque solo se actualiza cuando quiero que se actualice. Muy útil con animaciones por ejemplo.
Sin embargo, no es nada lujoso en muchas actualizaciones, es una operación costosa y en su mayoría no es necesario debido a pequeños cambios en la pantalla. También siento curiosidad por la velocidad de fotogramas, con menos actualizaciones necesarias, ¿funciona mejor?
Por eso quiero ser una clase lo suficientemente inteligente como para enviar solo los cambios, por lo que no necesito cuidar los problemas de velocidad / rendimiento. Esto ya está funcionando parcialmente (con un búfer doble), para detectar los cambios y enviar solo aquellos, sin embargo, aparecen en una posición incorrecta. Esto se debe a un método anterior, con un simple volcado, no es necesario especificar cada ubicación de pares de píxeles, simplemente bombea una matriz de valores.
¿Qué tipo de comando / instrucción del SSD1306 necesito para establecer la posición de destino o puedo omitir valores? No puedo resolverlo utilizando la hoja de datos .
Aquí está mi código (AVR-C):
// Send start address
if (useRegisters) // Send TWI Start
{
// Send start address
TWCR = _BV(TWEN) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
while(TOD_CHK_WAIT((TWCR & _BV(TWINT))) == 0) {};
TWDR = twiAddress<<1;
TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA);
while (TOD_CHK_WAIT((TWCR & _BV(TWINT)) == 0)) {};
TWDR = TOD_DATA_CONTINUE;
TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA);
while(TOD_CHK_WAIT((TWCR & _BV(TWINT)) == 0)) {};
}
else
{
pinSendStart( twiAddress<<1 );
pinWaitForAck();
pinWriteByte(TOD_DATA_CONTINUE);
pinWaitForAck();
}
// Dump buffer
for (uint16_t i=0; i < cacheSize; i++) // Send data
{
bool bUpdate = ((!doubleBuffer) || ( doubleBuffer && (displayCache[cacheSize-1+i] != displayCache[i])));
if( doubleBufferFirstTime || bUpdate )
{
if( doubleBuffer )
{ displayCache[cacheSize-1+i]=displayCache[i]; }
if( useRegisters )
{
if( !doubleBufferFirstTime && doubleBuffer )
{
// Set location must be here
// /* X */ set( TOD_SET_COLUMN_ADDR, x ); //width-1 );
// /* Y */ set( TOD_SET_PAGE_ADDR , y ); //height-1 );
}
TWDR = displayCache[i];
TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA); // Clear TWINT to proceed
while(TOD_CHK_WAIT((TWCR & _BV(TWINT)) == 0)) {}; // Wait for TWI to be ready
}
else {
pinWriteByte(displayCache[i]);
pinWaitForAck();
}
}
}
doubleBufferFirstTime=false;
if( useRegisters ) // Send TWI Stop
{ TWCR = _BV(TWEN)| _BV(TWINT) | _BV(TWSTO); } // Send STOP
else { pinSendStop(); }
Intenté usar COLUMN_ADDR (21h) y PAGE_ADDR (22h) para establecer el desplazamiento, el dispositivo no parece gustarle (se bloquea). ¿Qué puedo usar para cambiar la compensación u omitir una compensación específica?
Esta es la configuración de la pantalla:
set( TOD_SET_DISPLAY_CLOCK_DIV_RATIO , 0x80 );
set( TOD_SET_MULTIPLEX_RATIO , height-1 );
set( TOD_SET_DISPLAY_OFFSET , 0x0 );
set( TOD_SET_START_LINE | 0x0 );
set( TOD_CHARGE_PUMP , 0x14 );
set( TOD_MEMORY_ADDR_MODE , 0x00 );
set( TOD_SET_SEGMENT_REMAP | 0x1 );
set( TOD_COM_SCAN_DIR_DEC );
set( TOD_SET_COM_PINS , ( height > 32 )?0x12:0x02 );
set( TOD_SET_CONTRAST_CONTROL , 0xCF );
set( TOD_SET_PRECHARGE_PERIOD , 0xF1 );
set( TOD_SET_VCOM_DETECT , 0x40 );
set( TOD_DISPLAY_ALL_ON_RESUME );
set( TOD_NORMAL_DISPLAY );
set( TOD_DEACTIVATE_SCROLL );
show();
Editar 21 Okt 2017
Ver mi respuesta publicada.