Close

OLED Driver Progress, STM32 I2C woes.

A project log for SBHT - VHF DIGITAL RADIO

SBHT is a data/digital voice radio capable of greater than 4 watts of power initially on the VHF Ham bands.

Shane BurrellShane Burrell 04/04/2015 at 01:373 Comments

I've spent several hours the last few nights trying to figure out why output wasn't working. First I assumed it was an upgrade to Cube 1.5 which is a fairly safe bet, as the HAL drivers are a buggy abstraction layer as to what is actually going on. Then it finally came to me that the proto board had pullups and the Discovery board did not. I enabled the internal pullups and bingo it was working as it should. OLED driver for the SSD1306 is now working along with fonts and mono bitmaps. I've also improved my ADF init strategy which should now support fine cal mode. Hopefully new proto boards will be in late next week. More good news the VHF PA footprint/package can be had in a UHF version which I've ordered samples. Other than a few passives and finding a replacement Tx/Rx switch it should be trivial to have a vhf version and uhf version.

Discussions

Shane Burrell wrote 06/07/2015 at 14:05 point

/*



 * ssd1306.c



 *



 *  Created on: Apr 3, 2015



 *      Author: williamburrell



 */




// OLED is on I2C1




#include



#include "main.h"



#include "fonts.h"




#define I2C_OLED_ADDRESS 0x78



uint8_t I2CMasterBuffer[2];



uint8_t FrameBuffer[(SSD1306_LCDWIDTH/8) * SSD1306_LCDHEIGHT ];



void SSD_1306_SEND_CMD(uint8_t data)



{



uint8_t Buffer[2];



Buffer[0] = 0x00;



Buffer[1] = data;



HAL_I2C_Master_Transmit(&hi2c1, I2C_OLED_ADDRESS,Buffer , 2, 2);



}




void SSD_1306_SEND_CMD_REG(uint8_t cmd, uint8_t value)



{



uint8_t Buffer[2];



Buffer[0] = cmd;



Buffer[1] = value;



HAL_I2C_Master_Transmit(&hi2c1, I2C_OLED_ADDRESS,Buffer , 2, 2);



}



void SSD_1306_SEND_DATA(uint8_t data)



{



uint8_t Buffer[2];



Buffer[0] = SSD1306_SETSTARTLINE;



Buffer[1] = data;



if(HAL_I2C_Master_Transmit(&hi2c1, I2C_OLED_ADDRESS,Buffer , 2, 2) ==  HAL_BUSY)



{



//trace_puts("hi2c1 is BUSY");



}




}



void



SSD_1306_StartScrollLeft( int start, int stop)



{



SSD_1306_SEND_CMD(SSD1306_LEFT_HORIZONTAL_SCROLL);



SSD_1306_SEND_CMD(0X00);



SSD_1306_SEND_CMD((unsigned char)start);



SSD_1306_SEND_CMD(0X00);



SSD_1306_SEND_CMD((unsigned char)stop);



SSD_1306_SEND_CMD(0X01);



SSD_1306_SEND_CMD(0XFF);



SSD_1306_SEND_CMD(SSD1306_ACTIVATE_SCROLL);



}




void



SSD_1306_StartScrollRight(int start, int stop)



{




SSD_1306_SEND_CMD(SSD1306_RIGHT_HORIZONTAL_SCROLL);



SSD_1306_SEND_CMD(0X00);



SSD_1306_SEND_CMD((unsigned char)start);



SSD_1306_SEND_CMD(0X00);



SSD_1306_SEND_CMD((unsigned char)stop);



SSD_1306_SEND_CMD(0X01);



SSD_1306_SEND_CMD(0XFF);



SSD_1306_SEND_CMD(SSD1306_ACTIVATE_SCROLL);



}



void SSD_1306_StopScroll()



{




SSD_1306_SEND_CMD(SSD1306_DEACTIVATE_SCROLL);



}




void SSD1306_DrawPixel(uint8_t x, uint8_t y, uint8_t color) {



  if ((x < 0) || (x >= SSD1306_LCDWIDTH) || (y < 0) || (y >= SSD1306_LCDHEIGHT))



    return;




  // x is which column



    switch (color)



    {



      case SSD_1306_WHITE:   FrameBuffer[x+ (y/8)*SSD1306_LCDWIDTH] |=  (1 << (y&7)); break;



      case SSD_1306_BLACK:   FrameBuffer[x+ (y/8)*SSD1306_LCDWIDTH] &= ~(1 << (y&7)); break;



      case SSD_1306_INVERSE: FrameBuffer[x+ (y/8)*SSD1306_LCDWIDTH] ^=  (1 << (y&7)); break;



    }




}




void SSD1306_SetCursor(uint8_t row, uint8_t col) {



  if (row >= SSD1306_LCDHEIGHT/8) {



    row = SSD1306_LCDHEIGHT/8 - 1;



  }



  if (col >= SSD1306_LCDWIDTH) {



    col = SSD1306_LCDWIDTH - 1;



  }



  //row_ = row; // row is 8 pixels tall; must set to byte sized row



  //col_ = col; // col is 1 pixel wide; can set to any pixel column




  SSD_1306_SEND_CMD(SSD1306_SETLOWCOLUMN | (col & 0XF));



  SSD_1306_SEND_CMD(SSD1306_SETHIGHCOLUMN | (col >> 4));



  SSD_1306_SEND_CMD(SSD1306_SETSTARTPAGE | row);



}




void SSD1306_InvertDisplay(uint8_t i) {



  if (i) {



  SSD_1306_SEND_CMD(SSD1306_INVERTDISPLAY);



  } else {



  SSD_1306_SEND_CMD(SSD1306_NORMALDISPLAY);



  }



}



void SSD_1306_RENDER()



{



SSD_1306_SEND_CMD_REG(SSD1306_SETLOWCOLUMN,0x0);  // low col = 0



SSD_1306_SEND_CMD_REG(SSD1306_SETHIGHCOLUMN,0x0);  // hi col = 0



SSD_1306_SEND_CMD_REG(SSD1306_SETSTARTLINE,0x0); // line #0




    uint16_t i;



    for (i=0; i<((SSD1306_LCDWIDTH/8) * SSD1306_LCDHEIGHT); i++)



    {



    SSD_1306_SEND_DATA(FrameBuffer[i]);



    }



}



void SSD_1306_ALL_ON()



{



memset(FrameBuffer,0xFF,(SSD1306_LCDWIDTH/8) * SSD1306_LCDHEIGHT);



SSD_1306_RENDER();



}



void SSD_1306_CLEAR_SCREEN()



{



memset(FrameBuffer,0x00,(SSD1306_LCDWIDTH/8) * SSD1306_LCDHEIGHT);



SSD_1306_RENDER();



}



void SSD_1306_INIT()



{



int vccstate = 1;



// Init sequence taken from datasheet for UG-2864HSWEG01 (128x64 OLED module)




SSD_1306_SEND_CMD(0xAE);   //display off



SSD_1306_SEND_CMD(0x20); //Set Memory Addressing Mode



SSD_1306_SEND_CMD(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid



SSD_1306_SEND_CMD(0xb0); //Set Page Start Address for Page Addressing Mode,0-7



SSD_1306_SEND_CMD(0xc8); //Set COM Output Scan Direction



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



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



SSD_1306_SEND_CMD(0x40);//--set start line address



SSD_1306_SEND_CMD(0x81);//--set contrast control register



SSD_1306_SEND_CMD(0x7f);



SSD_1306_SEND_CMD(0xa1);//--set segment re-map 0 to 127



SSD_1306_SEND_CMD(0xa6);//--set normal display



SSD_1306_SEND_CMD(0xa8);//--set multiplex ratio(1 to 64)



SSD_1306_SEND_CMD(0x3F);//



SSD_1306_SEND_CMD(0xa4);//0xa4,Output follows RAM content;0xa5,Output ignores RAM content



SSD_1306_SEND_CMD(0xd3);//-set display offset



SSD_1306_SEND_CMD(0x00);//-not offset



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



SSD_1306_SEND_CMD(0xf0);//--set divide ratio



SSD_1306_SEND_CMD(0xd9);//--set pre-charge period



SSD_1306_SEND_CMD(0x22); //



SSD_1306_SEND_CMD(0xda);//--set com pins hardware configuration



SSD_1306_SEND_CMD(0x12);



SSD_1306_SEND_CMD(0xdb);//--set vcomh



SSD_1306_SEND_CMD(0x20);//0x20,0.77xVcc



SSD_1306_SEND_CMD(0x8d);//--set DC-DC enable



SSD_1306_SEND_CMD(0x14);//



SSD_1306_SEND_CMD(0xaf);//--turn on oled panel




}



int put_char_xy( char ch, unsigned int x, unsigned int y, const FONT_INFO *p_font, uint16_t color)



{



  int i, h, w;



  if (p_font!=NULL)



  {



    i = ch - p_font->start_char;



    int width = p_font->p_character_descriptor[i].width;



    int height = p_font->p_character_descriptor[i].height;



    int offset = p_font->p_character_descriptor[i].offset;



    int origin = p_font->p_character_descriptor[i].origin;



    const uint8_t *p_char = (p_font->p_character_bitmaps) + offset;



    int bitcnt = 0;



    uint8_t mask;




    for (h=0; h
    {



// Plot pixels for first byte.



w = 0;



while (w < width)



{



mask = 0x80;



for(bitcnt=0;bitcnt<8;bitcnt++)


{



if ((*p_char&mask)!=0)



{



SSD1306_DrawPixel(x+w, y+h+origin, SSD_1306_WHITE);



//LCD_SetPixel(x+w, y+h+origin, color);



}



//fprintf(stderr, "H=%d : W=%d : B=%d\n", h, w, bitcnt);



mask >>= 1;



w += 1;



}



++p_char;



}



     }



    return p_font->p_character_descriptor[i].width;



  }



  return 0;



}




void put_string_xy( char *p_str, unsigned int x, unsigned int y, const FONT_INFO *p_font, uint16_t color)



{



  int _x = 0;



  while (*p_str!=0)



  {



_x += put_char_xy(*p_str,x+_x,y,p_font,color);



_x += 1;



p_str += 1;



  }



}




// Return the length of a string in pixels when printed using the provided font.



int measure_string(char *p_str, const FONT_INFO *p_font)



{



  int i;



  int strlen_pixels = 0;



  if (p_font!=NULL)



  {



    while (*p_str!=0)



    {



      i = *p_str - p_font->start_char;



      strlen_pixels += p_font->p_character_descriptor[i].width;



      strlen_pixels += 1;



      p_str += 1;



    }



  }



  return strlen_pixels;



}

  Are you sure? yes | no

Joe wrote 06/06/2015 at 05:45 point

Sounds awesome!  Any chance at getting a peek at the STM32 code to drive the OLED display?  I don't need much, just how to initialize the OLED and display anything on the screen.  

  Are you sure? yes | no

Shane Burrell wrote 06/07/2015 at 14:08 point

Posted what I used to drive the OLED

  Are you sure? yes | no