Tengo ATMEGA328P y pantalla I2C (SSD1306). Estoy intentando simplemente colocar un solo píxel en una pantalla con el menor código posible para poder aprender desde allí.
Pude hacer esto con frambuesa usando el siguiente código:
// gcc ssd1306.c -lwiringPi -o ssd1306
#include <stdio.h>
#include <string.h>
#include <wiringPiI2C.h>
#define WIDTH 128
#define HEIGHT 64
int buffer[ WIDTH * HEIGHT / 8 ];
int i2cd;
void ssd1306_command(unsigned int c)
{
unsigned int control = 0x00;
wiringPiI2CWriteReg8( i2cd, control, c );
}
void ssd1306_byte(unsigned int c)
{
unsigned int control = 0x40;
wiringPiI2CWriteReg8( i2cd, control, c );
}
void drawPixel( int x, int y, unsigned int color )
{
switch (color)
{
case 1: // white
buffer[x + ( y / 8 ) * WIDTH ] = 1;
break;
case 0: // black
buffer[x + ( y / 8 ) * WIDTH ] = 0;
break;
}
}
void init()
{
i2cd = wiringPiI2CSetup( 0x3C ); // address
ssd1306_command(0xAE); // 0xAE // display off
ssd1306_command(0xD5); // 0xD5 // set display clock division
ssd1306_command(0x80); // the suggested ratio 0x80
ssd1306_command(0xA8); // 0xA8 set multiplex
ssd1306_command(63); // set height
ssd1306_command(0xD3); // set display offset
ssd1306_command(0x0); // no offset
ssd1306_command(64); // line #0 setstartline
ssd1306_command(0x8D); // 0x8D // chargepump
ssd1306_command(0x14);
ssd1306_command(0x20); // memory mode
ssd1306_command(0x00); // 0x0 act like ks0108
ssd1306_command(161); // segremap
ssd1306_command(0xC8); // comscandec
ssd1306_command(0xDA); // 0xDA set com pins
ssd1306_command(0x12);
ssd1306_command(0x81); // 0x81 // set contract
ssd1306_command(0xCF);
ssd1306_command(0xD9); // 0xd9 set pre-charge
ssd1306_command(0xF1);
ssd1306_command(0xDB); // SSD1306_SETVCOMDETECT
ssd1306_command(0x40);
ssd1306_command(0xA4); // 0xA4 // display all on resume
ssd1306_command(0xA6); // 0xA6 // normal display
ssd1306_command(0x2E); // deactivate scroll
ssd1306_command(0xAF); // --turn on oled panel
}
void renderBuffer(void)
{
ssd1306_command(0x21); // column address
ssd1306_command(0); // Column start address (0 = reset)
ssd1306_command(127); // Column end address (127
ssd1306_command(0x22); // page address
ssd1306_command(0x00); // Page start address (0 = reset)
ssd1306_command(7); // Page end address
int i;
for (i = 0; i < ( 128 * 64 / 8 ); i++)
{
ssd1306_byte( buffer[i] );
}
}
void clearBuffer(void)
{
memset( buffer, 0, ( 128 * 64 / 8 ) * sizeof( int ) );
}
void main()
{
init();
clearBuffer();
drawPixel( 10, 10, 1 );
renderBuffer();
}
Todo funciona perfectamente hasta ahora cuando trato de hacer lo mismo con i2c_master.c para mi ATMEGA: enlace
#ifndef F_CPU
#define F_CPU 8000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include "i2c_master.c"
#include "i2c_master.h"
#define SSD1306_ADDRESS 0x3C
void initDisplay()
{
i2c_start(SSD1306_ADDRESS);
i2c_write(0xAE); // 0xAE // display off
i2c_write(0xD5); // 0xD5 // set display clock division
i2c_write(0x80); // the suggested ratio 0x80
i2c_write(0xA8); // 0xA8 set multiplex
i2c_write(63); // set height
i2c_write(0xD3); // set display offset
i2c_write(0x0); // no offset
i2c_write(64); // line #0 setstartline
i2c_write(0x8D); // 0x8D // chargepump
i2c_write(0x14);
i2c_write(0x20); // memory mode
i2c_write(0x00); // 0x0 act like ks0108
i2c_write(161); // segremap
i2c_write(0xC8); // comscandec
i2c_write(0xDA); // 0xDA set com pins
i2c_write(0x12);
i2c_write(0x81); // 0x81 // set contract
i2c_write(0xCF);
i2c_write(0xD9); // 0xd9 set pre-charge
i2c_write(0xF1);
i2c_write(0xDB); // SSD1306_SETVCOMDETECT
i2c_write(0x40);
i2c_write(0xA4); // 0xA4 // display all on resume
i2c_write(0xA6); // 0xA6 // normal display
i2c_write(0x2E); // deactivate scroll
i2c_write(0xAF); // --turn on oled panel
i2c_stop();
}
void drawPixel()
{
i2c_start( SSD1306_ADDRESS );
i2c_write(0x21); // column address
i2c_write(0); // Column start address (0 = reset)
i2c_write(127); // Column end address (127
i2c_write(0x22); // page address
i2c_write(0x00); // Page start address (0 = reset)
i2c_write(7); // Page end address
int i;
int z=0;
for ( i = 0; i < ( 128 * 64 / 8 ); i++ )
{
if ( z == 0 )
{
i2c_write( 0xff );
z = 1;
}
else
{
i2c_write( 0x00 );
z = 0;
}
}
i2c_stop();
}
int main(void){
i2c_init();
initDisplay();
drawPixel();
return 0;
}
pero el píxel no está dibujado ..
Uso los siguientes ajustes de fusibles (uso 8Mhz interno) lfuse: w: 0xe2: m -U hfuse: w: 0xd9: m
Tengo la siguiente configuración de hardware:
-ATMEGA328P connected to a 4.0v power source
-ADC5 (SCL) connected to OLED's SCL (with additional line to VCC with 15k resistor in between)
-ADC4 (SDA) connected to OLED's SDA (with additional line to VCC with 15k resistor in between)
También intenté eliminar las resistencias y 'la conexión vcc extra', y lo conecté de la misma forma que lo hice con la frambuesa, pero no hice ninguna diferencia. ¿Alguna pista sobre qué estoy haciendo mal? He estado atrapado en esto por días ... ¡Gracias!
Información adicional:
(a) Por favor, proporcione una foto del h / w.
(b)SuministrelahojadedatosparaelmóduloOLED.
(c) ¿Ha medido si el módulo OLED tiene pull-ups I2C? incorporados y habilitados, o son sus 15k pull-ups los únicos en el autobús?
Creo que no hay pull-ups incorporados. Aquí hay una cita de la hoja de datos:
Both the data line (SDA) and the clock line (SCL) should be pulled up by external resistors
(d) ¿Tiene acceso a un osciloscopio y tiene experiencia en su uso?
Lamentablemente no tengo un osciloscopio ...
(e) Si es así, ¿puede proporcionar rastros que muestren el aumento & caída de un pequeño ¿Muestra de ambas señales I2C?
-
(f) Aunque es menos útil que un alcance en esta etapa, ¿tiene acceso a un analizador lógico, incluso a uno barato?
Desafortunadamente, tampoco tengo un analizador lógico ...