ATTINY414 plus small OLED display - Page 1
Forum section: electronics / general

author: bipolunipol
author_rank: Contributor
timestamp: April 03, 2021, 11:00:01 pm
content: Hi,I am designing a device based on the ATTINY414 microcontroller (from the Microchip new series of microcontrollers). I would like the device to measure the current temperature and calculate the rolling average temperature from the last 24 hours (RTC is running in the device).Now I have a problem with the presentation of the results (current temperature plus calculated average). In the device I want to use the I2C OLED 128x32 display, which is based on the SSD1306 driver. Unfortunately, the libraries I found on the Internet (for AVR-GCC) require a large data buffer to be stored in SRAM. 128x32 = 512 bytes. This exceeds the memory size of the microcontroller, which is 256B. Just counting the mean eats up memory. Not counting the memory needed for the OLED buffer...I know I could use a larger microcontroller like the ATTINY1604. However, due to the price and availability of chips (I would like to release a small series of such devices), I would prefer to stay with the ATTINY414. So is there a way to get rid of such a large buffer in SRAM and run the display on such a small microcontroller? I would mainly like to display text and simple graphics such as lines separating the text or thermometer symbol. Maybe you know some good libraries?

author: DavidAlfa
author_rank: Super Contributor
timestamp: April 03, 2021, 11:34:07 pm
content: Try u8g2, you can use page buffer mode, which only needs to allocate ram for one page (128bytes), slower but uses 8x less RAM.I worked a lot with u8g2 lately, didn't use that mode because I had plenty fo ram, so I went to full buffer and DMA to literally let it update itself.This can help a bit:https://www.best-microcontroller-projects.com/ssd1306.htmlIf you post the basic code I'll happily help with that.

author: drvtech
author_rank: Regular Contributor
timestamp: April 03, 2021, 11:40:39 pm
content: I ran into a similar problem recently and used the SSD1306Ascii library which is a lot smaller. IIRC it had fewer built in fonts which made a big difference.

author: MikeK
author_rank: Super Contributor
timestamp: April 04, 2021, 12:50:36 am
content: I have used that display many times with PIC's and have never used that screen buffering method...which you've noted is memory intensive. Screen buffering is only beneficial if you're using graphics or large fonts (but writing large fonts isn't difficult). If you want the typical small font (5x7) then just do a font lookup for the char to be printed and write it to the display. Easy peasy. Writing a larger font isn't much more difficult, just writing to more than one line.

author: bipolunipol
author_rank: Contributor
timestamp: April 04, 2021, 05:04:24 pm
content: Thank you for your help.I checked u8g2 and SSD1306Ascii on Arduino and indeed the libraries are much better when it comes to SRAM usage. Now, however, I would like to move it to C in Atmel Studio.I found such code in C as below (there is no buffer in SRAM):lcd.cCode:/** This file is part of lcd library for ssd1306/ssd1309/sh1106 oled-display.** lcd library for ssd1306/ssd1309/sh1106 oled-display is free software: you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation, either version 3 of the License, or any later version.** lcd library for ssd1306/ssd1309/sh1106 oled-display is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with Foobar. If not, see <http://www.gnu.org/licenses/>.** Diese Datei ist Teil von lcd library for ssd1306/ssd1309/sh1106 oled-display.** lcd library for ssd1306/ssd1309/sh1106 oled-display ist Freie Software: Sie können es unter den Bedingungen* der GNU General Public License, wie von der Free Software Foundation,* Version 3 der Lizenz oder jeder späteren* veröffentlichten Version, weiterverbreiten und/oder modifizieren.** lcd library for ssd1306/ssd1309/sh1106 oled-display wird in der Hoffnung, dass es nützlich sein wird, aber* OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite* Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.* Siehe die GNU General Public License für weitere Details.** Sie sollten eine Kopie der GNU General Public License zusammen mit diesem* Programm erhalten haben. Wenn nicht, siehe <http://www.gnu.org/licenses/>.** lcd.h** Created by Michael Köhler on 22.12.16.* Copyright 2016 Skie-Systems. All rights reserved.** lib for OLED-Display with ssd1306/ssd1309/sh1106-Controller* first dev-version only for I2C-Connection* at ATMega328P like Arduino Uno** at GRAPHICMODE lib needs static SRAM for display:* DISPLAY-WIDTH * DISPLAY-HEIGHT + 2 bytes** at TEXTMODE lib need static SRAM for display:* 2 bytes (cursorPosition)*/#include "lcd.h"#include "font.h"#include <string.h>static struct {uint8_t x;uint8_t y;} cursorPosition;static uint8_t charMode = NORMALSIZE;const uint8_t init_sequence [] PROGMEM = { // Initialization SequenceLCD_DISP_OFF, // Display OFF (sleep mode)0x20, 0b00, // Set Memory Addressing Mode// 00=Horizontal Addressing Mode; 01=Vertical Addressing Mode;// 10=Page Addressing Mode (RESET); 11=Invalid0xB0, // Set Page Start Address for Page Addressing Mode, 0-70xC8, // Set COM Output Scan Direction0x00, // --set low column address0x10, // --set high column address0x40, // --set start line address0x81, 0x3F, // Set contrast control register0xA1, // Set Segment Re-map. A0=address mapped; A1=address 127 mapped.0xA6, // Set display mode. A6=Normal; A7=Inverse0xA8, DISPLAY_HEIGHT-1, // Set multiplex ratio(1 to 64)0xA4, // Output RAM to Display// 0xA4=Output follows RAM content; 0xA5,Output ignores RAM content0xD3, 0x00, // Set display offset. 00 = no offset0xD5, // --set display clock divide ratio/oscillator frequency0xF0, // --set divide ratio0xD9, 0x22, // Set pre-charge period0xDA, 0x12, // Set com pins hardware configuration0xDB, // --set vcomh0x20, // 0x20,0.77xVcc0x8D, 0x14, // Set DC-DC enable};void lcd_command(uint8_t cmd[], uint8_t size) {i2c_start((LCD_I2C_ADR << 1) | 0);i2c_byte(0x00); // 0x00 for command, 0x40 for datafor (uint8_t i=0; i<size; i++) {i2c_byte(cmd);}i2c_stop2();}void lcd_data(uint8_t data[], uint16_t size) {i2c_start((LCD_I2C_ADR << 1) | 0);i2c_byte(0x40); // 0x00 for command, 0x40 for datafor (uint16_t i = 0; i<size; i++) {i2c_byte(data);}i2c_stop2();}void lcd_init(uint8_t dispAttr){i2c_init();uint8_t commandSequence[sizeof(init_sequence)+1];for (uint8_t i = 0; i < sizeof (init_sequence); i++) {commandSequence = (pgm_read_byte(&init_sequence));}commandSequence[sizeof(init_sequence)]=(dispAttr);lcd_command(commandSequence, sizeof(commandSequence));lcd_clrscr();}void lcd_gotoxy(uint8_t x, uint8_t y){x = x * sizeof(FONT);lcd_goto_xpix_y(x,y);}void lcd_goto_xpix_y(uint8_t x, uint8_t y){if( x > (DISPLAY_WIDTH) || y > (DISPLAY_HEIGHT/8-1)) return;// out of displaycursorPosition.x=x;cursorPosition.y=y;uint8_t commandSequence[] = {0xb0+y, 0x21, x, 0x7f};lcd_command(commandSequence, sizeof(commandSequence));}void lcd_clrscr(void){uint8_t displayBuffer;memset(displayBuffer, 0x00, sizeof(displayBuffer));for (uint8_t i = 0; i < DISPLAY_HEIGHT/8; i++){lcd_gotoxy(0,i);lcd_data(displayBuffer, sizeof(displayBuffer));}lcd_home();}void lcd_home(void){lcd_gotoxy(0, 0);}void lcd_invert(uint8_t invert){uint8_t commandSequence;if (invert != YES) {commandSequence = 0xA6;} else {commandSequence = 0xA7;}lcd_command(commandSequence, 1);}void lcd_sleep(uint8_t sleep){uint8_t commandSequence;if (sleep != YES) {commandSequence = 0xAF;} else {commandSequence = 0xAE;}lcd_command(commandSequence, 1);}void lcd_set_contrast(uint8_t contrast){uint8_t commandSequence = {0x81, contrast};lcd_command(commandSequence, sizeof(commandSequence));}void lcd_putc(char c){switch (c) {case '\b':// backspacelcd_gotoxy(cursorPosition.x-charMode, cursorPosition.y);lcd_putc(' ');lcd_gotoxy(cursorPosition.x-charMode, cursorPosition.y);break;case '\t':// tabif( (cursorPosition.x+charMode*4) < (DISPLAY_WIDTH/ sizeof(FONT)-charMode*4) ){lcd_gotoxy(cursorPosition.x+charMode*4, cursorPosition.y);}else{lcd_gotoxy(DISPLAY_WIDTH/ sizeof(FONT), cursorPosition.y);}break;case '\n':// linefeedif(cursorPosition.y < (DISPLAY_HEIGHT/8-1)){lcd_gotoxy(cursorPosition.x, cursorPosition.y+charMode);}break;case '\r':// carrige returnlcd_gotoxy(0, cursorPosition.y);break;default:// char doesn't fit in lineif( (cursorPosition.x >= DISPLAY_WIDTH-sizeof(FONT)) || (c < ' ') ) break;// mapping charc -= ' ';if (c >= pgm_read_byte(&special_char) ) {char temp = c;c = 0xff;for (uint8_t i=0; pgm_read_byte(&special_char) != 0xff; i++) {if ( pgm_read_byte(&special_char)-' ' == temp ) {c = pgm_read_byte(&special_char);break;}}if ( c == 0xff ) break;}// print char at displayif (charMode == DOUBLESIZE) {uint16_t doubleChar[sizeof(FONT)];uint8_t dChar;if ((cursorPosition.x+2*sizeof(FONT))>DISPLAY_WIDTH) break;for (uint8_t i=0; i < sizeof(FONT); i++) {doubleChar = 0;dChar = pgm_read_byte(&(FONT[(uint8_t)c]));for (uint8_t j=0; j<8; j++) {if ((dChar & (1 << j))) {doubleChar |= (1 << (j*2));doubleChar |= (1 << ((j*2)+1));}}}uint8_t data[sizeof(FONT)*2];for (uint8_t i = 0; i < sizeof(FONT); i++){// print font to ram, print 6 columnsdata[i<<1]=(doubleChar & 0xff);data[(i<<1)+1]=(doubleChar & 0xff);}lcd_data(data, sizeof(FONT)*2);uint8_t commandSequence[] = {0xb0+cursorPosition.y+1,0x21,cursorPosition.x,0x7f};lcd_command(commandSequence, sizeof(commandSequence));for (uint8_t i = 0; i < sizeof(FONT); i++){// print font to ram, print 6 columnsdata[i<<1]=(doubleChar >> 8);data[(i<<1)+1]=(doubleChar >> 8);}lcd_data(data, sizeof(FONT)*2);commandSequence = 0xb0+cursorPosition.y;commandSequence = cursorPosition.x+(2*sizeof(FONT));lcd_command(commandSequence, sizeof(commandSequence));cursorPosition.x += sizeof(FONT)*2;} else {uint8_t data[sizeof(FONT)];if ((cursorPosition.x+sizeof(FONT))>DISPLAY_WIDTH) break;for (uint8_t i = 0; i < sizeof(FONT); i++){// print font to ram, print 6 columnsdata=(pgm_read_byte(&(FONT[(uint8_t)c])));}lcd_data(data, sizeof(FONT));cursorPosition.x += sizeof(FONT);}break;}}void lcd_charMode(uint8_t mode){charMode = mode;}void lcd_puts(const char* s){while (*s) {lcd_putc(*s++);}}void lcd_puts_p(const char* progmem_s){register uint8_t c;while ((c = pgm_read_byte(progmem_s++))) {lcd_putc(c);}}lcd.hCode:/** This file is part of lcd library for ssd1306/ssd1309/sh1106 oled-display.** lcd library for ssd1306/ssd1309/sh1106 oled-display is free software: you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation, either version 3 of the License, or any later version.** lcd library for ssd1306/ssd1309/sh1106 oled-display is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with Foobar. If not, see <http://www.gnu.org/licenses/>.** Diese Datei ist Teil von lcd library for ssd1306/ssd1309/sh1106 oled-display.** lcd library for ssd1306/ssd1309/sh1106 oled-display ist Freie Software: Sie können es unter den Bedingungen* der GNU General Public License, wie von der Free Software Foundation,* Version 3 der Lizenz oder jeder späteren* veröffentlichten Version, weiterverbreiten und/oder modifizieren.** lcd library for ssd1306/ssd1309/sh1106 oled-display wird in der Hoffnung, dass es nützlich sein wird, aber* OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite* Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.* Siehe die GNU General Public License für weitere Details.** Sie sollten eine Kopie der GNU General Public License zusammen mit diesem* Programm erhalten haben. Wenn nicht, siehe <http://www.gnu.org/licenses/>.** lcd.h** Created by Michael Köhler on 22.12.16.* Copyright 2016 Skie-Systems. All rights reserved.** lib for OLED-Display with ssd1306/ssd1309/sh1106-Controller* first dev-version only for I2C-Connection* at ATMega328P like Arduino Uno** at GRAPHICMODE lib needs SRAM for display* DISPLAY-WIDTH * DISPLAY-HEIGHT + 2 bytes*/#ifndef LCD_H#define LCD_H#ifdef __cplusplusextern "C" {#endif#if (__GNUC__ * 100 + __GNUC_MINOR__) < 303#error "This library requires AVR-GCC 3.3 or later, update to newer AVR-GCC compiler !"#endif#include <inttypes.h>#include <avr/pgmspace.h>/* TODO: define bus */#define I2C// I2C or SPI/* TODO: define displaycontroller *///#define SH1106 // or SSD1306, check datasheet of your display#define SSD1306 // or SSD1306, check datasheet of your display/* TODO: define displaymode */#define TEXTMODE // TEXTMODE for only text to display,//#define GRAPHICMODE //for text and graphic/* TODO: define font */#define FONT ssd1306oled_font// set font here, refer font-name at font.h/font.c/* TODO: define I2C-adress for display */// using 7-bit-adress for lcd-library// if you use your own library for twi check I2C-adress-handle#define LCD_I2C_ADR (0x78 >> 1) // 7 bit slave-adress without r/w-bit// r/w-bit are set/unset by library// e.g. 8 bit slave-adress:// 0x78 = adress 0x3C with cleared r/w-bit (write-mode)#ifdef I2C#include "i2c_simple_master.h"// library for I2C-communication// if you want to use other lib for I2C// edit i2c_xxx commands in this library// i2c_start(), i2c_byte(), i2c_stop()#elif defined SPI// if you want to use your other lib/function for SPI replace SPI-commands#define LCD_PORTPORTB#define LCD_DDRDDRB#define RES_PINPB0#define DC_PINPB1#define CS_PINPB2#endif#ifndef YES#define YES 1#endif#define NORMALSIZE 1#define DOUBLESIZE 2#define LCD_DISP_OFF 0xAE#define LCD_DISP_ON 0xAF#define WHITE 0x01#define BLACK 0x00#define DISPLAY_WIDTH 128#define DISPLAY_HEIGHT 32void lcd_command(uint8_t cmd[], uint8_t size); // transmit command to displayvoid lcd_data(uint8_t data[], uint16_t size); // transmit data to displayvoid lcd_init(uint8_t dispAttr);void lcd_home(void); // set cursor to 0,0void lcd_invert(uint8_t invert); // invert displayvoid lcd_sleep(uint8_t sleep); // display goto sleep (power off)void lcd_set_contrast(uint8_t contrast); // set contrast for displayvoid lcd_puts(const char* s); // print string, \n-terminated, from ram on screen (TEXTMODE)// or buffer (GRAPHICMODE)void lcd_puts_p(const char* progmem_s); // print string from flash on screen (TEXTMODE)// or buffer (GRAPHICMODE)void lcd_clrscr(void); // clear screen (and buffer at GRFAICMODE)void lcd_gotoxy(uint8_t x, uint8_t y); // set curser at pos x, y. x means character,// y means line (page, refer lcd manual)void lcd_goto_xpix_y(uint8_t x, uint8_t y); // set curser at pos x, y. x means pixel,// y means line (page, refer lcd manual)void lcd_putc(char c); // print character on screen at TEXTMODE// at GRAPHICMODE print character to buffervoid lcd_charMode(uint8_t mode); // set size of chars#if defined GRAPHICMODEvoid lcd_drawPixel(uint8_t x, uint8_t y, uint8_t color);void lcd_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t color);void lcd_drawRect(uint8_t px1, uint8_t py1, uint8_t px2, uint8_t py2, uint8_t color);void lcd_fillRect(uint8_t px1, uint8_t py1, uint8_t px2, uint8_t py2, uint8_t color);void lcd_drawCircle(uint8_t center_x, uint8_t center_y, uint8_t radius, uint8_t color);void lcd_fillCircle(uint8_t center_x, uint8_t center_y, uint8_t radius, uint8_t color);void lcd_drawBitmap(uint8_t x, uint8_t y, const uint8_t picture[], uint8_t width, uint8_t height, uint8_t color);void lcd_display(void); // copy buffer to display RAMvoid lcd_clear_buffer(void); // clear display bufferuint8_t lcd_check_buffer(uint8_t x, uint8_t y); // read a pixel value from the display buffervoid lcd_display_block(uint8_t x, uint8_t line, uint8_t width); // display (part of) a display line#endif#ifdef __cplusplus}#endif#endif /* LCD_H */Fonts:Code:/** font.c* i2c** Created by Michael Köhler on 16.09.18.* Copyright 2018 Skie-Systems. All rights reserved.**/#include "font.h"const char ssd1306oled_font[] PROGMEM = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // sp{0x00, 0x00, 0x00, 0x2f, 0x00, 0x00}, // !{0x00, 0x00, 0x07, 0x00, 0x07, 0x00}, // "{0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14}, // #{0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12}, // ${0x00, 0x62, 0x64, 0x08, 0x13, 0x23}, // %{0x00, 0x36, 0x49, 0x55, 0x22, 0x50}, // &{0x00, 0x00, 0x05, 0x03, 0x00, 0x00}, // '{0x00, 0x00, 0x1c, 0x22, 0x41, 0x00}, // ({0x00, 0x00, 0x41, 0x22, 0x1c, 0x00}, // ){0x00, 0x14, 0x08, 0x3E, 0x08, 0x14}, // *{0x00, 0x08, 0x08, 0x3E, 0x08, 0x08}, // +{0x00, 0x00, 0x00, 0xA0, 0x60, 0x00}, // ,{0x00, 0x08, 0x08, 0x08, 0x08, 0x08}, // -{0x00, 0x00, 0x60, 0x60, 0x00, 0x00}, // .{0x00, 0x20, 0x10, 0x08, 0x04, 0x02}, // /{0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E}, // 0{0x00, 0x00, 0x42, 0x7F, 0x40, 0x00}, // 1{0x00, 0x42, 0x61, 0x51, 0x49, 0x46}, // 2{0x00, 0x21, 0x41, 0x45, 0x4B, 0x31}, // 3{0x00, 0x18, 0x14, 0x12, 0x7F, 0x10}, // 4{0x00, 0x27, 0x45, 0x45, 0x45, 0x39}, // 5{0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30}, // 6{0x00, 0x01, 0x71, 0x09, 0x05, 0x03}, // 7{0x00, 0x36, 0x49, 0x49, 0x49, 0x36}, // 8{0x00, 0x06, 0x49, 0x49, 0x29, 0x1E}, // 9{0x00, 0x00, 0x36, 0x36, 0x00, 0x00}, // :{0x00, 0x00, 0x56, 0x36, 0x00, 0x00}, // ;{0x00, 0x08, 0x14, 0x22, 0x41, 0x00}, // <{0x00, 0x14, 0x14, 0x14, 0x14, 0x14}, // ={0x00, 0x00, 0x41, 0x22, 0x14, 0x08}, // >{0x00, 0x02, 0x01, 0x51, 0x09, 0x06}, // ?{0x00, 0x32, 0x49, 0x59, 0x51, 0x3E}, // @{0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C}, // A{0x00, 0x7F, 0x49, 0x49, 0x49, 0x36}, // B{0x00, 0x3E, 0x41, 0x41, 0x41, 0x22}, // C{0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C}, // D{0x00, 0x7F, 0x49, 0x49, 0x49, 0x41}, // E{0x00, 0x7F, 0x09, 0x09, 0x09, 0x01}, // F{0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A}, // G{0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F}, // H{0x00, 0x00, 0x41, 0x7F, 0x41, 0x00}, // I{0x00, 0x20, 0x40, 0x41, 0x3F, 0x01}, // J{0x00, 0x7F, 0x08, 0x14, 0x22, 0x41}, // K{0x00, 0x7F, 0x40, 0x40, 0x40, 0x40}, // L{0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F}, // M{0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F}, // N{0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E}, // O{0x00, 0x7F, 0x09, 0x09, 0x09, 0x06}, // P{0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E}, // Q{0x00, 0x7F, 0x09, 0x19, 0x29, 0x46}, // R{0x00, 0x46, 0x49, 0x49, 0x49, 0x31}, // S{0x00, 0x01, 0x01, 0x7F, 0x01, 0x01}, // T{0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F}, // U{0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F}, // V{0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F}, // W{0x00, 0x63, 0x14, 0x08, 0x14, 0x63}, // X{0x00, 0x07, 0x08, 0x70, 0x08, 0x07}, // Y{0x00, 0x61, 0x51, 0x49, 0x45, 0x43}, // Z{0x00, 0x00, 0x7F, 0x41, 0x41, 0x00}, // [{0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55}, // backslash{0x00, 0x00, 0x41, 0x41, 0x7F, 0x00}, // ]{0x00, 0x04, 0x02, 0x01, 0x02, 0x04}, // ^{0x00, 0x40, 0x40, 0x40, 0x40, 0x40}, // _{0x00, 0x00, 0x01, 0x02, 0x04, 0x00}, // '{0x00, 0x20, 0x54, 0x54, 0x54, 0x78}, // a{0x00, 0x7F, 0x48, 0x44, 0x44, 0x38}, // b{0x00, 0x38, 0x44, 0x44, 0x44, 0x20}, // c{0x00, 0x38, 0x44, 0x44, 0x48, 0x7F}, // d{0x00, 0x38, 0x54, 0x54, 0x54, 0x18}, // e{0x00, 0x08, 0x7E, 0x09, 0x01, 0x02}, // f{0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C}, // g{0x00, 0x7F, 0x08, 0x04, 0x04, 0x78}, // h{0x00, 0x00, 0x44, 0x7D, 0x40, 0x00}, // i{0x00, 0x40, 0x80, 0x84, 0x7D, 0x00}, // j{0x00, 0x7F, 0x10, 0x28, 0x44, 0x00}, // k{0x00, 0x00, 0x41, 0x7F, 0x40, 0x00}, // l{0x00, 0x7C, 0x04, 0x18, 0x04, 0x78}, // m{0x00, 0x7C, 0x08, 0x04, 0x04, 0x78}, // n{0x00, 0x38, 0x44, 0x44, 0x44, 0x38}, // o{0x00, 0xFC, 0x24, 0x24, 0x24, 0x18}, // p{0x00, 0x18, 0x24, 0x24, 0x18, 0xFC}, // q{0x00, 0x7C, 0x08, 0x04, 0x04, 0x08}, // r{0x00, 0x48, 0x54, 0x54, 0x54, 0x20}, // s{0x00, 0x04, 0x3F, 0x44, 0x40, 0x20}, // t{0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C}, // u{0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C}, // v{0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C}, // w{0x00, 0x44, 0x28, 0x10, 0x28, 0x44}, // x{0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C}, // y{0x00, 0x44, 0x64, 0x54, 0x4C, 0x44}, // z{0x00, 0x00, 0x08, 0x77, 0x41, 0x00}, // {{0x00, 0x00, 0x00, 0x63, 0x00, 0x00}, // ¦{0x00, 0x00, 0x41, 0x77, 0x08, 0x00}, // }{0x00, 0x08, 0x04, 0x08, 0x08, 0x04}, // ~/* end of normal char-set *//* put your own signs/chars here, edit special_char too *//* be sure that your first special char stand here */{0x00, 0x3A, 0x40, 0x40, 0x20, 0x7A}, // ü, !!! Important: this must be special_char !!!{0x00, 0x3D, 0x40, 0x40, 0x40, 0x3D}, // Ü{0x00, 0x21, 0x54, 0x54, 0x54, 0x79}, // ä{0x00, 0x7D, 0x12, 0x11, 0x12, 0x7D}, // Ä{0x00, 0x39, 0x44, 0x44, 0x44, 0x39}, // ö{0x00, 0x3D, 0x42, 0x42, 0x42, 0x3D}, // Ö{0x00, 0x02, 0x05, 0x02, 0x00, 0x00}, // °{0x00, 0x7E, 0x01, 0x49, 0x55, 0x73}, // ß{0x00, 0x7C, 0x10, 0x10, 0x08, 0x1C} // µ};const char special_char[] PROGMEM = {// define position of special char in font// {special char, position in font}// be sure that last element of this// array are {0xff, 0xff} and first element// are {first special char, first element after normal char-set in font}{'ü', 95}, // special_char{'Ü', 96},{'ä', 97},{'Ä', 98},{'ö', 99},{'Ö', 100},{'°', 101},{'ß', 102},{'µ', 103},{0xff, 0xff} // end of table special_char};Main:Code://****main.c****//#include "lcd.h"int main(void){lcd_init(LCD_DISP_ON);lcd_clrscr();lcd_set_contrast(0x00);lcd_gotoxy(4,1);lcd_puts("Normal Size");lcd_charMode(DOUBLESIZE);lcd_gotoxy(0,4);lcd_puts(" Double \r\n Size");lcd_charMode(NORMALSIZE);for(;;){//main loop}return 0;}However, I have a problem with starting now because the display is completely unresponsive. In addition, FLASH memory consumption reaches almost 87% from 18%

author: ajb
author_rank: Super Contributor
timestamp: April 08, 2021, 04:57:42 pm
content: Quote from: MikeK on April 04, 2021, 12:50:36 amScreen buffering is necessary any time you need to do an update that does not align to a page boundary without having to redraw extra parts of the screen. If you're okay with only using fonts or graphics that are a multiple of the page size and are always aligned to the page boundaries, or always redrawing extra bits, then sure, there's less benefit to the buffer, but there can also be performance and program structure benefits if you can just write to the buffer (fast) and then let a background task update the display (slow). But if you don't have the memory then you don't have the memory.Quote from: bipolunipol on April 04, 2021, 05:04:24 pmHow does the initialization compare to what you were using before? There could be an issue there, or in the way that the I2C is being initialized/handled between the two libraries/environments. The code size could be (at least partially) a result of different optimization levels, you'll need to check this in the compiler settings in Atmel Studio. I think it defaults to no optimization, but you can increase the optimization level or select size optimization depending on what works better for your application.

author: camila
author_rank: Contributor
timestamp: April 08, 2021, 06:34:00 pm
content: I recently wanted a flexible way of displaying information from a project, and found this small monochrome 64x48 OLED display on Aliexpress . A similar one is available from Sparkfun . Although both SPI and I2C versions are available, I chose the SPI version because the display update is faster.The display needs 4 pins to drive it, just within the capabilities of the ATtiny85 and leaving one pin available for another application. You can't read the display memory, so to do graphics you need to write into a buffer in RAM, and then copy this to the display. Because the display is 64x48 pixels it requires 64x48/8 or 384 bytes of memory for the graphics buffer, again just within the capabilities of the ATtiny85.

author: phil from seattle
author_rank: Super Contributor
timestamp: April 08, 2021, 06:43:45 pm
content: The ATTiny 1614 is 100% compatible (same periphs just more RAM), has 2K bytes of RAM and is about $0.20 more expensive.

author: DavidAlfa
author_rank: Super Contributor
timestamp: April 08, 2021, 08:05:56 pm
content: Quote from: camila on April 08, 2021, 06:34:00 pmAnd if you target is most get most I/Os possible, and it's ok for the display to be slower, go for a i2C one (only 2 I/Os).