0

I have some driver code that I am testing out for use with an SSD1306 driven OLED screen which is 128x32 (same as the OLED adafruit model). I need this to run in debian (I am using Linario-4.4.9)

I have followed the Debian guides on how to start creating a file handler for the device, this can be seen as follows below. The only thing in oled.h is the device adress (0x3C) and the proto types. I followed the initialization approach taken on the adafruit github (as I tried their code out first on an Ardunio to ensure the screen does in fact work). I believe I may be doing something wrong but I'm not entirely sure what I am doing wrong. I have also listed my init process below.

#include <errno.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include <linux/i2c-dev.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>

#include "oled.h"

int oled;

int  lcd_driver_init(void)
{
        ///< Begin the init proc.
        int dloc = open("/dev/i2c-1", O_RDWR);
        if (dloc < 0 )
        {
                fprintf(stderr, "Error opening i2c device\n");
                return -1;
        }


        if(ioctl(dloc, I2C_SLAVE, SCR_ADDR) < 0)
        {
                fprintf(stderr, "Error in ioctl. Errno :%i\n",errno);
                return -2;
        }

        oled = dloc;
        fprintf(stderr, "init success, device open and local\n");   
        return EXIT_SUCCESS;
}

int oled_command( uint8_t cmd)
{
        char command[2]= {0};
        command[1] = cmd;
        int check = (write(oled, command, 2));

        return check;
}

void oled_cmd_start()
{
        int check = (write(oled, 0x00, sizeof(uint8_t)));
        if(check<0)
                fprintf(stderr, "Errno set:: %i\n", errno);
        return;
}
void oled_data_start()
{
        uint8_t _data_start_[1] ={ 0x40 };
        int check = (write(oled, _data_start_, sizeof(uint8_t)));
        if(check<0)
                fprintf(stderr, "Errno set oled_data_start:: %i\n", errno);
        return;
}

int oled_data (uint8_t xmit)
{

        int check = (write(oled, &xmit, (sizeof(uint8_t))));
        if(check<0)
                fprintf(stderr, "Errno set oled_data:: %i\n", errno);
        return check;
}

INIT PROCESS

void sendcommand(unsigned char payload)
{
    oled_data(0x00);        //Control Byte - Command
    oled_data(payload);     //payload
}
void lcd_init(void)
{

    sendcommand(0xAE);//--Set Display off

    sendcommand(0x00);//--set low column address

    sendcommand(0x10);//--set high column address

    sendcommand(0x81);//--set contrast control register
    sendcommand(0x7f);

    sendcommand(0xa1);//--set segment re-map 95 to 0

    sendcommand(0xA6);//--set normal display

    sendcommand(0xa8);//--set multiplex ratio(1 to 16)
    sendcommand(0x1f);//--duty 1/32

    sendcommand(0xd3);//--set display offset
    sendcommand(0x00);//--not offset

    sendcommand(0xd5);//--set display clock divide ratio/oscillator frequency
    sendcommand(0xf0);//--set divide ratio

    sendcommand(0xd9);//--set pre-charge period
    sendcommand(0x22);

    sendcommand(0xda);//--set com pins hardware configuration
    sendcommand(0x02);//disable left/right remap and set for sequential

    sendcommand(0xdb);//--set vcomh
    sendcommand(0x49);//--0.83*vref

    sendcommand(0x8d);//--set DC-DC enable
    sendcommand(0x14);//

    sendcommand(0xAF);//--turn on oled panel

    sendcommand(0xA4);//--Entire Display ON

}

Following this, I send alternating 0xFF to try and make stripes on the screen. The only thing that shows up is random pixels. Nothing coherent.

I have connected a logic analyzer to sniff the I2C lines, and it appears that when I have the LA connected, the I2C lines no longer function and ERRNO returns an IO fault (#5). There doesn't ever seem to be an issue opening up the device to get the file pointer however.

I do get ERRNO as timeout sometimes, but I have read that this is just an issue with I2C devices using the protocal as write expects a quicker response than I2C might give.

I am also compiling with -std=c99 -O0 to ensure all of the inline functions are there as well as ensuring that loop variables are available.

If anyone can point me in the right direction of can point out some flaw in my approach it would be much appreciated. Thank you.

EDIT

I've checked the device tree and the i2c device is correctly enabled. However none of the i2c_freq speeds seem to be enabled. Could this be causing the timeouts and the garbage data transfer?

Tropical_Peach
  • 1,143
  • 3
  • 16
  • 29
  • By the way, it would be nice if you can provide an I2C version of fbtft driver. It would be benifitial for many people. And kernel driver is much better than user space one (I have sparkfun OLED display like this, though it's SPI connected). – 0andriy Apr 19 '17 at 17:41
  • My debian kernel doesn't have fbtft modules so I am trying to write a loadable kernel module that can take requests and write them to the screen. I've never really done that before though so it might be slow progress. I can link you to a repo of it when I finish it though! – Tropical_Peach Apr 19 '17 at 19:36

2 Answers2

1

I have connected a logic analyzer to sniff the I2C lines, and it appears that when I have the LA connected, the I2C lines no longer function and ERRNO returns an IO fault (#5).

logic analyzer is just a device for measurement. It converts the captured data into timing diagrams, decodes protocol which you have set. So it will not be responsible for any I2C read write error (until your grounding and h/w connections are correct).

For timeout issue either you can try by decreasing the i2c clock-frequency or ioctl I2C_TIMEOUT.

vinod maverick
  • 670
  • 4
  • 14
  • The LA was to ensure that the data was formatted correctly and being transmitted in the correct order, etc. The interesting point here was that when the LA is connected, I don't even get garbage on the OLED, it just stays blank until I disconnect the LA and rerun my program. Timeout, from what I've read, doesn't mean that the write has failed though. It just sets `errno` as the timer has expired. Right? – Tropical_Peach Apr 11 '17 at 05:56
  • I don't know why such weird thing is happening while connecting the LA. It looks only h/w issue to me. Time-out are generated when the I2C bus is considered busy. I think I2C support [two type of timeout](http://docs.lpcware.com/lpc800um/RegisterMaps/i2c/c-Time-out.html). It may be that you are missing some registering setting or sequence while writing (assuming your hardware connections are proper). So one thing can you try: *set these register through I2C tool and verify their updated values as well*. – vinod maverick Apr 11 '17 at 07:04
  • I've tried running the commands through the `i2cset` tool and this yields nothing. The device no longer shows up on `i2cdetect` either. This seems to be a hardware problem since my code isn't wrong and I am using ioctl correctly. – Tropical_Peach Apr 11 '17 at 14:15
  • OK that I was assuming from the beginning itself. BTW if you are not even seeing your device through `i2cdetect` (*make sure you are using the correct the i2c bus number*) then consult your h/w engineer. – vinod maverick Apr 11 '17 at 14:34
  • After resetting completely the device shows back up. (unfortunately I am the h/w engineer! ) – Tropical_Peach Apr 11 '17 at 14:35
  • *what do you means by completely reset ?* is it hardware reset or software reset? – vinod maverick Apr 11 '17 at 14:40
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/141441/discussion-between-tropical-peach-and-vinod-maverick). – Tropical_Peach Apr 11 '17 at 14:43
0

It turns out the SOM has an internal regulator for the I2C lines to be 1V8 where as the SSD1306 chip is running at 3V3 causing information to be mishandled. This behavior wasn't documented on the SOM.

Applying a level shifting chip to the design allowed for proper communication.

If someone has this same problem, check your schematics for voltage mismatch levels.

Tropical_Peach
  • 1,143
  • 3
  • 16
  • 29