Jugar con I2C no produce los resultados esperados para SSD1306-OLED

0

Estoy tratando de usar una pantalla OLED con I2C, pero no pasa nada (literalmente), así que vengo aquí para ver si alguien puede arrojar algo de luz sobre lo que he hecho mal.

Mi primer enfoque fue escribir un software I2C-driver, después de leer sobre el protocolo en una aplicación de Texas Instruments, pero de alguna manera mis señales de SDA y SCL ocurrieron completamente separadas (el pulso del reloj vino después de datos). 4h de búsqueda de errores Descubrí que había 2 de 5 pines GPIO en mi PIC12F683 que estaban dañados.

En ese momento estaba harto, así que agarré un PIC16F886 con hardware-I2C, porque mi principal objetivo era usar la pantalla OLED en lugar de escribir un controlador de protocolo.

Sin embargo, ni siquiera eso funciona. En el bucle principal, enciendo / paro un LED solo para ver si el bucle se está ejecutando, y está en efecto. Esto significa, creo, que el propio I2C está funcionando (ya que tengo un bucle mientras espera el ACK, y ya está), pero la pantalla de alguna manera permanece apagada.

La pantalla es completamente nueva y no se usa, por lo que debería funcionar, pero, por supuesto, existe la posibilidad de que esté rota. El principal sospechoso aquí es mi código, sin embargo, es muy probable que yo haya olvidado algo.

Entonces, aquí está, escrito para el PIC16F886 usando el compilador XC8:

#include <xc.h>

// CONFIG1
#pragma config FOSC = INTRC_NOCLKOUT// Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON       // RE3/MCLR pin function select bit (RE3/MCLR pin function is MCLR)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = OFF      // Brown Out Reset Selection bits (BOR disabled)
#pragma config IESO = OFF       // Internal External Switchover bit (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled)
#pragma config LVP = OFF        // Low Voltage Programming Enable bit (RB3 pin has digital I/O, HV on MCLR must be used for programming)

// CONFIG2
#pragma config BOR4V = BOR40V   // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V)
#pragma config WRT = OFF        // Flash Program Memory Self Write Enable bits (Write protection off)

#define OLED_CONTRAST 0x81
#define OLED_DISPLAY_ALL_ON_RESUME 0xa5
#define OLED_NORMAL_DISPLAY 0xa6
#define OLED_DISPLAY_ON 0xaf
#define OLED_DISPLAY_OFF 0xAE
#define OLED_ADDRESS 0b01111000
#define OLED_WRITE   0b01111000
#define OLED_READ    0b01111001

#define LED RC7

void delay() {
    volatile unsigned long korv;

    for (korv = 0; korv < 2*65535; korv++) {
        NOP();
    }
}

void init_mcu() {
    OSCCON = 0b01110001;        // 8MHz intosc

    ANSEL  = 0;                 // Digital I/O
    ANSELH = 0;

    CM1CON0 = 0;                // Disable comparators
    CM2CON0 = 0;

    TRISA = 0;
    TRISB = 0;
    TRISC = 0b00011000;         // SDA/SCL - inputs

    SSPCONbits.SSPEN = 1;       // Enable serial module
    SSPCONbits.SSPM = 0b1000;   // I2C-master

    SSPCON2bits.RCEN = 0;       // Disable receive mode
    SSPADD = 4;                 // 8MHz Fosc -> 400kbps I2C
    SSPSTATbits.SMP = 0;        // Enable slew rate control for 400kHz
}

void i2c_wait() {
    while (!SSPIF) {}
    SSPIF = 0;
}

void i2c_start() {
    SSPCON2bits.SEN = 1;
    i2c_wait();
}

void i2c_stop() {
    SSPCON2bits.PEN = 1;
    i2c_wait();
}

void i2c_write_byte(unsigned char b) {
    SSPBUF = b;
    i2c_wait();
}

void oled_command(unsigned char c) {
    i2c_start();
    i2c_write_byte(OLED_WRITE);
    i2c_write_byte(0x00);                   // D/C
    i2c_write_byte(c);
    i2c_stop();
}

void main() {
    init_mcu();

    while (1) {
        oled_command(OLED_DISPLAY_ON);

        LED = 1;
        delay();

        oled_command(OLED_DISPLAY_OFF);
        LED = 0;
        delay();
    }
}

¿Hay algún error obvio con respecto al uso de I2C, lo he hecho?

ACTUALIZAR

Esquemas, foto de osciloscopio y tablero de prueba de la siguiente manera.

El alcance SDA / SCL produce 5V más o menos constante, sin pulsos en absoluto. Suponiendo que se rompió el chip, lo reemplacé con uno nuevo, uno nuevo de fábrica. Mismo error.

Estoy completamente perdido aquí.

    
pregunta bos

1 respuesta

4

Parece que estás usando un SSD1306 oled. (vale la pena mencionar!)

Para dar vida a esta pantalla, debe inicializarla. La secuencia que utilizo es

  static constexpr const uint8_t init_sequence[] = {
     CMD_MODE,  DISPLAYOFF,                   
     CMD_MODE,  SETDISPLAYCLOCKDIV,   0x80,   
     CMD_MODE,  SETMULTIPLEX,         0x3F,   
     CMD_MODE,  SETDISPLAYOFFSET,     0x00,   
     CMD_MODE,  SETSTARTLINE        | 0x00,  
     CMD_MODE,  CHARGEPUMP,           0x14,   
     CMD_MODE,  MEMORYMODE,           0x00,   
     CMD_MODE,  SEGREMAP            | 0x01,
     CMD_MODE,  COMSCANDEC,
     CMD_MODE,  SETCOMPINS,           0x12,   
     CMD_MODE,  SETCONTRAST,          0xCF,   
     CMD_MODE,  SETPRECHARGE,         0xF1,  
     CMD_MODE,  SETVCOMDETECT,        0x40,   
     CMD_MODE,  DISPLAYALLON_RESUME,          
     CMD_MODE,  NORMALDISPLAY,                
     CMD_MODE,  DISPLAYON                     
  };

Después de eso, puedes comenzar a escribir en la RAM de píxeles.

No estoy seguro de que el interruptor de encendido / apagado que usas muestre algo (incluso con la inicialización correcta) cuando la RAM del píxel sea todo ceros.

Pero como el siguiente truco insinuó en su comentario, podría haber muchos problemas. Comience con un simple chip I2C, como un PCF8574A. Una vez que consiga que funcione, copie el código de un controlador conocido para su pantalla y haga que funcione en su contexto. Mi controlador se puede encontrar en enlace Está en C ++, pero Debería poder adaptarlo a C.

(O mejor aún: cambie a un chip moderno que admita los módulos C ++! Cortex o Arduino Due de Aliexpress. O tome un LPC1114 si desea un chip DIP).

    
respondido por el Wouter van Ooijen

Lea otras preguntas en las etiquetas