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
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
/*
* 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
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
Posted what I used to drive the OLED
Are you sure? yes | no