el microcontrolador no funciona con Nokia 5110 LCD (PCD8544)

Estoy luchando con mi primer microcontrolador AVR, AtTiny85, para que funcione con la conocida pantalla Nokia 5110. Escribí mi propio código para manejar la pantalla LCD, no funcionó. Luego probé un código que encontré en algún lugar de Internet, se suponía que debía manejar la pantalla, pero tampoco lo hizo. Pensé que mi pantalla estaba rota, pero la conecté a Raspberry Pi y ejecuté un script de Adafruit; funcionó sin problemas.

#include <avr/io.h>
#include <util/delay.h>

#define PIN_SCE PB0
#define PIN_RESET PB1
#define PIN_DC PB2
#define PIN_SCLK PB3
#define PIN_MOSI PB4

enum
{
    FUNCTION_SET = 0x20,
    FS_CHIP_POWERDOWN = 0x4,
    FS_VERTICAL_ADDR = 0x2,
    FS_EXTENDED_INSTR = 0x1,

    DISPLAY_NORMAL = 0xc,
    DISPLAY_BLANK = 0x8,
    DISPLAY_ALL_ON = 0x9,
    DISPLAY_INVERSE = 0xd,

    DRAM_SET_X = 0x80,
    DRAM_SET_Y = 0x40,
};

void BitTransfer(uint8_t Bits)
{
    PORTB &= ~(1 << PIN_SCE);
    int8_t i;
    for(i = 7; i>=0; i--)
    {
        if((Bits >> i) & 1)
            PORTB |= (1 << PIN_MOSI);
        else
           PORTB &= ~(1 << PIN_MOSI);

        PORTB |= (1 << PIN_SCLK);
        _delay_us(10);
        PORTB &= ~(1 << PIN_SCLK);
        _delay_us(10);
    }
    PORTB &= ~(1 << PIN_MOSI);
    PORTB |= (1 << PIN_SCE);
}

void SendCommand(uint8_t Command)
{
    PORTB &= ~(1 << PIN_DC);
    BitTransfer(Command);
}

void SendData(uint8_t Data)
{
    PORTB |= (1 << PIN_DC);
    BitTransfer(Data);
}

int main(void)
{
    DDRB |= (1 << PIN_SCE);
    DDRB |= (1 << PIN_RESET);
    DDRB |= (1 << PIN_DC);
    DDRB |= (1 << PIN_SCLK);
    DDRB |= (1 << PIN_MOSI);
    PORTB = 0;
    _delay_us(10);
    PORTB |= (1 << PIN_RESET);
    PORTB |= (1 << PIN_SCE);
    _delay_us(10);

    SendCommand(FUNCTION_SET | FS_EXTENDED_INSTR);
    SendCommand(0xa5); // VOP
    SendCommand(0x06); // temp coefficient
    SendCommand(0x13); // BIAS
    SendCommand(FUNCTION_SET);
    SendCommand(DISPLAY_ALL_ON);
    while(1)
    {
    }

    return 0;
}

Enciendo mi AVR usando pinout de 3.3v de Raspberry Pi, lo mismo con la pantalla LCD. El AVR está trabajando a una frecuencia de 1 MHz. Cuando desconecto el enchufe que lleva a tierra, aparece una línea negra en la pantalla por un momento. No sé, ¿tal vez sea un problema de hardware?

ingrese la descripción de la imagen aquí

Si pudiera ser un problema de hardware, ¿cómo espera que lo identifiquemos ya que no proporcionó ningún esquema?
(a) "Escribí mi propio código para manejar la pantalla LCD, no funcionó".-> (b) "Probé un código que encontré en algún lugar de Internet [...] pero tampoco funcionó".- > (c) "Lo adjunté a Raspberry Pi [...] funcionó sin ningún problema". - Poniendo esos 3 puntos juntos, entonces un problema de ah/w con su h/w relacionado con AVR parece algo que debería investigar. Dado que es nuevo en AVR, no empiece con pantallas LCD. Comience con el simple "LED parpadeante" y avance hacia cosas más complicadas. Si desea ayuda con su h/w, proporcione el esquema y las fotos de su h/w real. Para tu información, ¡la potencia de 3,3 V del RPi es limitada!
Gracias por el diagrama, no es un esquema normal, pero nos brinda información. La falta de un capacitor de desacoplamiento para la MCU es obvia, pero podría no afectar la operación. Agrega uno de todos modos. Compruebe que la corriente de 3,3 V esté dentro del límite de RPi. La falta de fotos significa que no podemos saber si el cableado real coincide con el diagrama de cableado. Como dije, si fuera yo, comenzaría con un programa de "parpadeo de LED" para comenzar, lo que le permite probar que su MCU está funcionando, a la velocidad de reloj esperada, y puede programarse con éxito. Después de eso, usaría un 'alcance para ver las señales SPI cuando se ejecuta un código LCD "bien conocido". HH.
Condensador de 4,7 uF agregado, sin efecto, pero lo dejo clavado. Se comprobó la prueba de parpadeo del LED: funcionó como lo programé. Cuando sugirió asegurarse de que RPi puede proporcionar suficiente corriente, se me ocurrió usar baterías en lugar de molestarme con Raspberry. En mi humilde opinión, RPi debería poder alimentar el AVR y la pantalla LCD, pero ¿por qué no intentarlo?
Bien, expliqué cómo abordaría la depuración de su problema, pero otros pueden tener enfoques diferentes. Desafortunadamente, las preguntas normales de EE.SE no son el mejor lugar para depurar problemas, un comentario a la vez. Cuando obtenga más "reputación" (puntos), puede usar las salas de chat y las personas que tienen suficiente tiempo pueden tomar una sesión de depuración para chatear (lo he hecho un par de veces). Tenga en cuenta que la capacidad de corriente máxima RPi 3.3V está documentada, por lo que puede usar su multímetro para medir la corriente que consume su MCU y LCD para confirmar la compatibilidad, sin adivinar. ¡De todos modos, buena suerte!
Parece que no es causado por una corriente insuficiente. Encendí el AVR y la pantalla LCD con dos pilas alcalinas AA, y seguía igual. Podría agregar algunas fotos del cableado, pero está muy desordenado.

Respuestas (1)

¿son esos los mismos comandos que usaron los otros ejemplos de trabajo? Mis ejemplos de trabajo (este, el raspberry pi está manejando la pantalla) tienen algunos comandos/configuraciones más.

    spi_command(0x21); //extended commands
//    spi_command(0xB0); //vop
    spi_command(0xBF); //vop
    spi_command(0x04); //temp coef
    spi_command(0x14); //bias mode 1:48
    spi_command(0x20); //extended off
    spi_command(0x0C); //display on

//experiment 1
if(1)
{
    spi_command(0x80); //column
    spi_command(0x40); //row
    for(ra=0;ra<504;ra++) spi_data(ra);
}

Probablemente esté corriendo lo suficientemente lento como para no necesitar demoras, pero podría agregar un poco más, entre todo, básicamente, el cambio de D/C a la selección de spi al primer cambio de datos y así sucesivamente.

¿Tiene un alcance para examinar el autobús? Puede alimentar las señales a la frambuesa pi y muestrear muy rápido y guardar los datos para usarlos como un analizador lógico (el metal desnudo es más fácil/mejor, pero posiblemente también pueda hacerlo en Linux). O use cualquier otro microcontrolador siempre que sea más rápido de lo que cree que está golpeando un poco.

También puede poner luces LED en las líneas y hacer que los retrasos sean masivos, lo suficientemente lentos para que pueda ver visualmente qué está sucediendo y en qué orden.

Si la pantalla funciona cuando se usa el código comercial, pero no con el suyo, entonces claramente no es la pantalla. Es algo que su código está o no está haciendo. Es un objetivo spi bastante fácil de manipular, no se requiere volver a leer, solo disparar cosas.

Probablemente no tenga el almacenamiento en el microcontrolador, pero sí en el pi, también puede adoptar otro enfoque, tomar su código bit bang, simular el gpio y crear un archivo de registro de cada cambio de estado. Luego haga que el programa real simplemente los elimine. Al menos puedes ver visualmente

#include <stdio.h>

unsigned char port;

static void spi_delay ( void )
{
}

static void spi_dc ( unsigned int x )
{
    if(x) port|=(1<<0);
    else  port&=~(1<<0);
    printf("0x%02X,\n",port);
}
static void spi_cs ( unsigned int x )
{
    if(x) port|=(1<<1);
    else  port&=~(1<<1);
    printf("0x%02X,\n",port);
}
static void spi_clk ( unsigned int x )
{
    if(x) port|=(1<<2);
    else  port&=~(1<<2);
    printf("0x%02X,\n",port);
}
static void spi_mosi ( unsigned int x )
{
    if(x) port|=(1<<3);
    else  port&=~(1<<3);
    printf("0x%02X,\n",port);
}

static void spi_command ( unsigned int cmd )
{
    unsigned int ra;
    unsigned int rb;

    spi_dc(0);
    spi_cs(0);
    spi_delay();
    for(rb=cmd,ra=0;ra<8;ra++,rb<<=1)
    {
        spi_mosi((rb>>7)&1);
        spi_delay();
        spi_clk(1);
        spi_delay();
        spi_clk(0);
        spi_delay();
    }
    spi_cs(1);
}

static void spi_data ( unsigned int data )
{
    unsigned int ra;
    unsigned int rb;

    spi_dc(1);
    spi_cs(0);
    spi_delay();
    for(rb=data,ra=0;ra<8;ra++,rb<<=1)
    {
        spi_mosi((rb>>7)&1);
        spi_delay();
        spi_clk(1);
        spi_delay();
        spi_clk(0);
        spi_delay();
    }
    spi_cs(1);
}

int main ( void )
{
    port=0;

    spi_clk(0);
    spi_data(0);
    spi_cs(0);
    spi_cs(1);

    spi_command(0x21); //extended commands
...

para ese inicio y comando dando esta salida:

0x00,
0x01,
0x01,
0x01,
0x05,
0x01,
0x01,
0x05,
0x01,
0x01,
0x05,
0x01,
0x01,
0x05,
0x01,
0x01,
0x05,
0x01,
0x01,
0x05,
0x01,
0x01,
0x05,
0x01,
0x01,
0x05,
0x01,
0x03,
0x01,
0x03,
0x02,
0x00,
0x00,
0x04,
0x00,
0x00,
0x04,
0x00,
0x08,
0x0C,
0x08,
0x00,
0x04,
0x00,
0x00,
0x04,
0x00,
0x00,
0x04,
0x00,
0x00,
0x04,
0x00,
0x08,
0x0C,
0x08,
0x0A,

Tenga en cuenta que en el código tengo el bit 0 como D/C, el bit 1 es cs, el 2 es clk y el 3 mosi. no se restableció en este código, creo que este solo se restableció a la alimentación, puede ajustarlos fácilmente.

Puede tomar esa salida y luego introducirla en algún código que ejecute en el pi o el microcontrolador (si tiene espacio).

for(x=0;x<datalen;x++)
{
  PORT = data[x];
  delay();
}

Puede crear algunas herramientas para ver visualmente las formas de onda (recomiendo mirar el formato vcd muy simple y usar gtkwave). o incluso mejor, simplemente imprímalos como binarios y gire la cabeza hacia un lado.

Al menos puede tener la sensación de que tiene las cosas conectadas correctamente y que está golpeando bien, una vez que eso funciona, reemplaza las funciones de configuración/borrado para cada bit con acceso directo al gpio y mueve el código al microcontrolador. incluso puede escribirlo de manera que se compile en ambos sentidos con una capa de abstracción.

Si tiene un osciloscopio multicanal, puede ahorrarse mucho trabajo. Bit banging spi o i2c o mdio, etc., realmente necesita un alcance o necesita construir un analizador lógico a partir de un microcontrolador o algo así. Se prefiere el alcance, especialmente para cosas como i2c y mdio, donde puede ver cuándo los autobuses cambian de dirección y qué tan rápido/lento son los pull ups.

ahora que lo pienso, tenía un botón de reinicio en ese microcontrolador del que tomé prestado ese código y ese reinicio también fue a la pantalla, así que cuando reinicié el mcu para volver a ejecutar el código o volver a un gestor de arranque para descargar el siguiente experimento, la pantalla también se reinició. puede hacer fácilmente lo que estaba haciendo, asegúrese de que el reinicio sea lo suficientemente largo, el error sea demasiado largo para todo esto, luego acorte los retrasos más tarde una vez que funcione (o una vez que realmente los mida).
"Depuré" la salida de AVR usando mi Raspberry y pude recibir los bytes correctos. Probaré tus comandos.
simplemente arrojando ideas, al final del día, cuando se golpea un poco, necesita "ver" qué formas de onda está generando. Y, a veces, mirar su código y pensar que sabe lo que está produciendo no es lo suficientemente bueno, especialmente cuando no funciona. No todos tienen acceso a un osciloscopio multicanal, pero tal vez tenga algo más que pueda usar.