Guten Abend miteinander,
Ich habe hier die SSD1306_Minimal Lib , die speziel für die Attiny's geschrieben ist, etwas umgebaut. 1. ich habe anstatt der TinyWire wieder die Wire eingebunden da ich den Attiny-Core von SpenceKonde nutze, und dieser eine auf den Attinys laufende Wire im Core beigelegt hat. Zudem hatte ich , sobald ich den Attiny 167 als Board/Prozessor gewählt habe, mit der TinyWire Probleme , diese zu kompilieren. Da ich auch noch weitere i2C-Sensoren und ne DS3132 am Attiny habe und ich wollte auch nicht 2 verschiedene Wire-libs verwenden.
Als mit der Zeit, während das Projekt fortschritt, der Flash im Attiny etwas voller wurde, habe ich mich entschieden, den Zeichensatz so wie die von mir entworfenen Symbole und Icons/Cliparts aus dem PROGMEM zu werfen und in ein I2C-EEPROM auszulagern. Dies erlaupte mir dann auch gleichzeitig, einen 2. Zeichensatz , den ich in der Titelzeile der Menues nutze, einzubinden. I
Somit habe ich also aus der SSD11306_Minimal Lib die SSD1306_Minimal_EROM lib gesbastelt. Diese liest nun den Zeichensatz (die Zeichensätze) nicht mehr aus dem PROGMEM sondern aus dem I2C EEPROM. Ebenfalls die Bitmap-Grafiken, die original ebenfalls im Flash liegen.
In der vorliegenden version habe ich die EEprom-Grösse von der Adressbreite her auf 64 KByte , also uint16 begrenzt, da ich auch den Ram Verbrauch kleinhalten will/muss.
Hier die SSD1306_minimal_erom.h
/*
SSD1306_minimal.h - SSD1306 OLED Driver Library
2015 Copyright (c) CoPiino Electronics All right reserved.
Original Author: GOF Electronics Co. Ltd.
Modified by: CoPiino Electronics ( http://copiino.cc )
CoPiino Electronics invests time and resources providing this open source code,
please support CoPiino Electronics and open-source hardware by purchasing
products from CoPiino Electronics!
What is it?
This library is derived from GOFi2cOLED library, only for SSD1306 in I2C Mode.
As the original library only supports Frame Buffered mode which requires to have
at least 1024bytes of free RAM for a 128x64px display it is too big for smaller devices.
So this a SSD1306 library that works great with ATTiny85 devices :)
It is a free software; you can redistribute it and/or modify it
under the terms of BSD license, check license.txt for more information.
All text above must be included in any redistribution.
Modified by: SMC
Modifying to opperate with external I2C EPprom/FRAM (naed as ERom) for Fonts and Icons/Cliparts
*/
#ifndef __SSD1306_MINIMAL_EROM_H__
#define __SSD1306_MINIMAL_EROM_H__
#include <Arduino.h>
// config
//#define SlaveAddress 0x3c
//#define RomAddress 0x50
#include <Wire.h>
// defines taken from GOFi2cOLED
#define GOFi2cOLED_Command_Mode 0x80
#define GOFi2cOLED_Data_Mode 0x40
//Fundamental Command (more than one bytes command pleaserefer to SSD1306 datasheet for details)
#define Set_Contrast_Cmd 0x81 //Double byte command to select 1 out of 256 contrast steps.Default(RESET = 0x7F)
#define Entire_Display_On_Resume_Cmd 0xA4 //Resume to RAM content display(RESET), Output follows RAM content
#define Entire_Display_On_Cmd 0xA5 //Entire display ON, Output ignores RAM content
#define GOFi2cOLED_Normal_Display_Cmd 0xA6 //Normal display (RESET)
#define GOFi2cOLED_Inverse_Display_Cmd 0xA7 //Inverse display
#define GOFi2cOLED_Display_Off_Cmd 0xAE //sleep mode(RESET)
#define GOFi2cOLED_Display_On_Cmd 0xAF //normal mode
//Scrolling Command (more than one bytes command pleaserefer to SSD1306 datasheet for details)
#define Right_Horizontal_Scroll_Cmd 0x26
#define Left_Horizontal_Scroll_Cmd 0x27
#define Vertical_Right_Horizontal_Scroll_Cmd 0x29
#define Vertical_Left_Horizontal_Scroll_Cmd 0x2A
#define Activate_Scroll_Cmd 0x2F
#define Deactivate_Scroll_Cmd 0x2E
#define Set_Vertical_Scroll_Area_Cmd 0xA3
//Addressing Setting Command (more than one bytes command pleaserefer to SSD1306 datasheet for details)
#define Set_Memory_Addressing_Mode_Cmd 0x20
#define HORIZONTAL_MODE 0x00
#define VERTICAL_MODE 0x01
#define PAGE_MODE 0x02 //Default(reset)
#define Set_Column_Address_Cmd 0x21 //Setup column start and end address. This command is only for horizontal or vertical addressing mode.
#define Set_Page_Address_Cmd 0x22 //Setup page start and end address. This command is only for horizontal or vertical addressing mode.
//Hardware Configuration (Panel resolution & layout related) Command (more than one bytes command please refer to SSD1306 datasheet for details)
#define Segment_Remap_Cmd 0xA1 //column address 127 is mapped to SEG0
#define Segment_Normal_map_Cmd 0xA0 //Default. column address 0 is mapped to SEG0(RESET)
#define Set_Multiplex_Ratio_Cmd 0xA8 //Set MUX ratio to N+1 MUX
#define COM_Output_Normal_Scan_Cmd 0xC0 //Normal mode (RESET). Scan from COM0 to COM[N �C1]
#define COM_Output_Remap_Scan_Cmd 0xC8 //Remapped mode. Scan from COM[N-1] to COM0
#define Set_Display_Offset_Cmd 0xD3 //Set vertical shift by COM from 0d~63d. The value is reset to 00h after RESET.
#define Set_COM_Pins_Hardware_Config_Cmd 0xDA
//Timing & Driving Scheme Setting Command (more than one bytes command pleaserefer to SSD1some more than one bytes command please 306 datasheet for details)
#define Set_Display_Clock_Divide_Ratio_Cmd 0xD5
#define Set_Precharge_Period_Cmd 0xD9
#define Set_VCOMH_Deselect_Level_Cmd 0xDB
#define No_Operation_Cmd 0xE3
#define Charge_Pump_Setting_Cmd 0x8D
#define Charge_Pump_Enable_Cmd 0x14
#define Charge_Pump_Disable_Cmd 0x10 //default
#define Scroll_Left 0x00
#define Scroll_Right 0x01
#define Scroll_2Frames 0x7
#define Scroll_3Frames 0x4
#define Scroll_4Frames 0x5
#define Scroll_5Frames 0x0
#define Scroll_25Frames 0x6
#define Scroll_64Frames 0x1
#define Scroll_128Frames 0x2
#define Scroll_256Frames 0x3
#define Dummy_Byte_0x00 0x00
#define Dummy_Byte_0xFF 0xFF
//
class SSD1306_Mini {
public:
// call this function once in "void setup()" to initiallize the display
void init(uint8_t dispaddr, uint8_t eromaddr);
// switch the display PixelLeds on
void displayOn();
// switch the display PixelLeds off (low current mode)
void displayOff();
// reset clipArea to maximum and clear the display
void clear();
// move cursor to upper left corner in current clipArea
void startScreen();
// set the clipArea, by default (0,0,128,8)
void clipArea(unsigned char col, unsigned char row, unsigned char w, unsigned char h);
// change the active Font (0 = BasicFont , 1 = BoldFont)
void setFont( bool font );
// move the cursor to a location (similar to clipArea)
void cursorTo( unsigned char row, unsigned char col );
// print a single character
void printChar( char ch );
// print a string to the screen
void printString( const char * pText );
// draw an image with defined x,y position and width,height definition
void drawImage( uint16_t img, unsigned char col, unsigned char row, unsigned char w, unsigned char h );
//
//void displayX(int off);
// private:
void sendCommand(unsigned char command);
void sendData(unsigned char Data);
void getERom (uint16_t romAddr, byte Bytes);
uint32_t getImgAddr (uint16_t img);
byte rombuf[8];
};
#endif
Und hier die SSD1306_minimal_erom.cpp
/*
SSD1306_minimal.h - SSD1306 OLED Driver Library
2015 Copyright (c) CoPiino Electronics All right reserved.
Original Author: GOF Electronics Co. Ltd.
Modified by: CoPiino Electronics ( http://copiino.cc )
CoPiino Electronics invests time and resources providing this open source code,
please support CoPiino Electronics and open-source hardware by purchasing
products from CoPiino Electronics!
What is it?
This library is derived from GOFi2cOLED library, only for SSD1306 in I2C Mode.
As the original library only supports Frame Buffered mode which requires to have
at least 1024bytes of free RAM for a 128x64px display it is too big for smaller devices.
So this a SSD1306 library that works great with ATTiny85 devices :)
It is a free software; you can redistribute it and/or modify it
under the terms of BSD license, check license.txt for more information.
All text above must be included in any redistribution.
*/
#include "SSD1306_minimal_erom.h"
#define BasicFont 0
#define BoldFont1 1019
uint8_t SlaveAddress; // i2c Adresse Display
uint8_t RomAddress; // i2c Adresse Charakter Rom (eeprom/fram)
byte charwidth = 5;
uint16_t FontAddr = BasicFont;
void SSD1306_Mini::getERom(uint16_t romAddr, byte bytes) {
Wire.beginTransmission(RomAddress);
Wire.write(romAddr >> 8);
Wire.write(romAddr);
Wire.endTransmission();
Wire.requestFrom(RomAddress, (byte) bytes);
for (byte i = 0; i < bytes; i++) {
rombuf[i] = (Wire.read());
}
}
uint32_t SSD1306_Mini::getImgAddr (uint16_t img) {
Wire.beginTransmission(RomAddress);
Wire.write(img >> 8);
Wire.write(img);
Wire.endTransmission();
Wire.requestFrom(RomAddress, (byte)2);
return (256 * Wire.read() + Wire.read());
}
void SSD1306_Mini::sendCommand(unsigned char command)
{
Wire.begin(); //initialize I2C
Wire.beginTransmission(SlaveAddress); // begin I2C communication
Wire.write(GOFi2cOLED_Command_Mode); // Set OLED Command mode
Wire.write(command);
Wire.endTransmission(); // End I2C communication
}
void SSD1306_Mini::sendData(unsigned char Data)
{
Wire.begin(); //initialize I2C
Wire.beginTransmission(SlaveAddress); // begin I2C transmission
Wire.write(GOFi2cOLED_Data_Mode); // data mode
Wire.write(Data);
Wire.endTransmission(); // stop I2C transmission
}
void SSD1306_Mini::init(uint8_t dispaddr, uint8_t eromaddr)
{
Wire.begin();
delay(5); //wait for OLED hardware init
// constructor(128, 64);
SlaveAddress = dispaddr;
RomAddress = eromaddr;
sendCommand(GOFi2cOLED_Display_Off_Cmd); /*display off*/
sendCommand(Set_Multiplex_Ratio_Cmd); /*multiplex ratio*/
sendCommand(0x3F); /*duty = 1/64*/
sendCommand(Set_Display_Offset_Cmd); /*set display offset*/
sendCommand(0x00);
sendCommand(Set_Memory_Addressing_Mode_Cmd); //set addressing mode
sendCommand(HORIZONTAL_MODE); //set horizontal addressing mode
sendCommand(0xB0); //set page address
sendCommand(0x00); //set column lower address
sendCommand(0x10); //set column higher address
sendCommand(0x40); /*set display starconstructort line*/
sendCommand(Set_Contrast_Cmd); /*contract control*/
sendCommand(0xcf); /*128*/
sendCommand(Segment_Remap_Cmd); /*set segment remap*/
sendCommand(COM_Output_Remap_Scan_Cmd); /*Com scan direction*/
sendCommand(GOFi2cOLED_Normal_Display_Cmd); /*normal / reverse*/
sendCommand(Set_Display_Clock_Divide_Ratio_Cmd); /*set osc division*/
sendCommand(0x80);
sendCommand(Set_Precharge_Period_Cmd); /*set pre-charge period*/
sendCommand(0xf1);
sendCommand(Set_COM_Pins_Hardware_Config_Cmd); /*set COM pins*/
sendCommand(0x12);
sendCommand(Set_VCOMH_Deselect_Level_Cmd); /*set vcomh*/
sendCommand(0x30);
sendCommand(Deactivate_Scroll_Cmd);
sendCommand(Charge_Pump_Setting_Cmd); /*set charge pump enable*/
sendCommand(Charge_Pump_Enable_Cmd);
sendCommand(GOFi2cOLED_Display_On_Cmd); /*display ON*/
}
void SSD1306_Mini::displayOn() {
sendCommand(GOFi2cOLED_Display_On_Cmd);
}
void SSD1306_Mini::displayOff() {
sendCommand(GOFi2cOLED_Display_Off_Cmd);
}
void SSD1306_Mini::setFont( bool font ) {
charwidth = 5;
FontAddr = BasicFont;
if (font) {
charwidth = 8;
FontAddr = BoldFont1;
}
}
void SSD1306_Mini::clipArea(unsigned char col, unsigned char row, unsigned char w, unsigned char h) {
Wire.begin(); // initialize I2C
Wire.beginTransmission(SlaveAddress); // begin I2C transmission
Wire.write(GOFi2cOLED_Command_Mode); // data mode
Wire.write(Set_Column_Address_Cmd);
Wire.write(0);
Wire.write(col);
Wire.write(col + w - 1);
Wire.endTransmission(); // stop I2C transmission
Wire.begin(); // initialize I2C
Wire.beginTransmission(SlaveAddress); // begin I2C transmission
Wire.write(GOFi2cOLED_Command_Mode); // data mode
Wire.write(Set_Page_Address_Cmd);
Wire.write(0);
Wire.write(row);
Wire.write(row + h - 1);
Wire.endTransmission(); // stop I2C transmission
}
void SSD1306_Mini::cursorTo(unsigned char col, unsigned char row) {
clipArea(col, row, 128 - col, 8 - row);
}
void SSD1306_Mini::startScreen() {
sendCommand(0x00 | 0x0); // low col = 0
sendCommand(0x10 | 0x0); // hi col = 0
sendCommand(0x40 | 0x0); // line #0
}
void SSD1306_Mini::clear() {
sendCommand(0x00 | 0x0); // low col = 0
sendCommand(0x10 | 0x0); // hi col = 0
sendCommand(0x40 | 0x0); // line #0
clipArea(0, 0, 128, 8);
for (uint16_t i = 0; i <= ((128 * 64 / 8) / 16); i++)
{
// send a bunch of data in one xmission
Wire.beginTransmission(SlaveAddress);
Wire.write(GOFi2cOLED_Data_Mode); // data mode
for (uint8_t k = 0; k < 16; k++) {
Wire.write( 0 );
}
Wire.endTransmission();
}
}
void SSD1306_Mini::displayX(int off) {
sendCommand(0x00 | 0x0); // low col = 0
sendCommand(0x10 | 0x0); // hi col = 0
sendCommand(0x40 | 0x0); // line #0
for (uint16_t i = 0; i <= ((128 * 64 / 8) / 16); i++)
{
// send a bunch of data in one xmission
Wire.beginTransmission(SlaveAddress);
Wire.write(GOFi2cOLED_Data_Mode); // data mode
for (uint8_t k = 0; k < 16; k++) {
Wire.write( i * 16 + k + off);
}
Wire.endTransmission();
}
}
void SSD1306_Mini::printChar( char ch ) {
unsigned char i = ch;
getERom(FontAddr + (i * charwidth), charwidth);
Wire.beginTransmission(SlaveAddress);
Wire.write(GOFi2cOLED_Data_Mode); // data mode
Wire.write( 0x00 );
Wire.write( rombuf, charwidth );
if (charwidth == 5) Wire.write( 0x00 );
Wire.endTransmission();
}
void SSD1306_Mini::printString( const char * pText ) {
unsigned char i;
unsigned char len = strlen( pText );
for (i = 0; i < len; i++) {
printChar( pText[i] );
}
}
void SSD1306_Mini::drawImage( uint16_t img, unsigned char col, unsigned char row, unsigned char w, unsigned char h ) {
unsigned char i, imgsize, bufsize, rest;
img = getImgAddr (img);
clipArea( col, row, w, h);
imgsize = w * h;
bufsize = 8; // blockgrösse
rest = (imgsize) % bufsize; // wenn nein, rest merken
for (i = 0; i < (imgsize); i += bufsize) {
if (i == imgsize - rest) bufsize = rest; // buffer auf restliche Bytes setzen
getERom (img + i, bufsize); // symbol blockweise lesen
Wire.beginTransmission(SlaveAddress);
Wire.write(GOFi2cOLED_Data_Mode); // data mode
Wire.write(rombuf, bufsize); // symbol blockweise ins Display
Wire.endTransmission();
}
}
Noch eine kleine Anmerkung: An die Funktion .drawImage wird nicht direkt die Startadresse der jewieligen Bitmap im EEPROM übergeben, sondern die (16bit) Adresse in der Bitmap-Adress-Table, also einer Tabelle in der die Positionen aller Bitmaps , die mit drawImage gezeichnet werden können , vermerkt ist. Die Lib selber weiss also nicht, wo im EEprom die Adresstabelle oder die Symbole selbst gespeichert sind. für die Zeichensätze sind die Startadressen in der Lib eingetragen.
Jetzt die Frage: wie kann ich die Library bei gleichem Funktionsumfang, noch weiter staffen/optimieren in Bezug auf die grösse im Flash?
Und , falls möglich ist es nicht schlimm, wenn auch noch das eine , oder andere Byte im RAM gespart wird. Wobei der RAM im Attiny noch locker ausreichend ist, Da ich im Hauptcode recht sparsam mit dem RAM umgehe.