Author Topic: ATTINY414 plus small OLED display  (Read 2113 times)

0 Members and 1 Guest are viewing this topic.

Offline bipolunipolTopic starter

  • Contributor
  • Posts: 32
  • Country: us
ATTINY414 plus small OLED display
« on: April 03, 2021, 11:00:01 pm »
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?
« Last Edit: April 03, 2021, 11:01:56 pm by bipolunipol »
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5907
  • Country: es
Re: ATTINY414 plus small OLED display
« Reply #1 on: April 03, 2021, 11:34:07 pm »
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.html

If you post the basic code I'll happily help with that. :-+
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 
The following users thanked this post: bipolunipol

Offline drvtech

  • Regular Contributor
  • *
  • Posts: 111
  • Country: gb
Re: ATTINY414 plus small OLED display
« Reply #2 on: April 03, 2021, 11:40:39 pm »
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.
 
The following users thanked this post: bipolunipol

Offline MikeK

  • Super Contributor
  • ***
  • Posts: 1314
  • Country: us
Re: ATTINY414 plus small OLED display
« Reply #3 on: April 04, 2021, 12:50:36 am »
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.
 
The following users thanked this post: bipolunipol

Offline bipolunipolTopic starter

  • Contributor
  • Posts: 32
  • Country: us
Re: ATTINY414 plus small OLED display
« Reply #4 on: April 04, 2021, 05:04:24 pm »
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.c
Code: [Select]
/*
 * 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 Sequence
    LCD_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=Invalid
    0xB0,            // Set Page Start Address for Page Addressing Mode, 0-7
    0xC8,            // Set COM Output Scan Direction
    0x00,            // --set low column address
    0x10,            // --set high column address
    0x40,            // --set start line address
    0x81, 0x3F,      // Set contrast control register
    0xA1,            // Set Segment Re-map. A0=address mapped; A1=address 127 mapped.
    0xA6,            // Set display mode. A6=Normal; A7=Inverse
    0xA8, DISPLAY_HEIGHT-1, // Set multiplex ratio(1 to 64)
    0xA4,            // Output RAM to Display
// 0xA4=Output follows RAM content; 0xA5,Output ignores RAM content
    0xD3, 0x00,      // Set display offset. 00 = no offset
    0xD5,            // --set display clock divide ratio/oscillator frequency
    0xF0,            // --set divide ratio
    0xD9, 0x22,      // Set pre-charge period
    0xDA, 0x12,      // Set com pins hardware configuration
    0xDB,            // --set vcomh
    0x20,            // 0x20,0.77xVcc
    0x8D, 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 data
    for (uint8_t i=0; i<size; i++) {
        i2c_byte(cmd[i]);
    }
    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 data
    for (uint16_t i = 0; i<size; i++) {
        i2c_byte(data[i]);
    }
    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[i] = (pgm_read_byte(&init_sequence[i]));
    }
    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[0]);
    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 display
    cursorPosition.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[DISPLAY_WIDTH];
    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[1];
    if (invert != YES) {
        commandSequence[0] = 0xA6;
    } else {
        commandSequence[0] = 0xA7;
    }
    lcd_command(commandSequence, 1);
}
void lcd_sleep(uint8_t sleep){
    uint8_t commandSequence[1];
    if (sleep != YES) {
        commandSequence[0] = 0xAF;
    } else {
        commandSequence[0] = 0xAE;
    }
    lcd_command(commandSequence, 1);
}
void lcd_set_contrast(uint8_t contrast){
    uint8_t commandSequence[2] = {0x81, contrast};
    lcd_command(commandSequence, sizeof(commandSequence));
}
void lcd_putc(char c){
    switch (c) {
        case '\b':
            // backspace
            lcd_gotoxy(cursorPosition.x-charMode, cursorPosition.y);
            lcd_putc(' ');
            lcd_gotoxy(cursorPosition.x-charMode, cursorPosition.y);
            break;
        case '\t':
            // tab
            if( (cursorPosition.x+charMode*4) < (DISPLAY_WIDTH/ sizeof(FONT[0])-charMode*4) ){
                lcd_gotoxy(cursorPosition.x+charMode*4, cursorPosition.y);
            }else{
                lcd_gotoxy(DISPLAY_WIDTH/ sizeof(FONT[0]), cursorPosition.y);
            }
            break;
        case '\n':
            // linefeed
            if(cursorPosition.y < (DISPLAY_HEIGHT/8-1)){
                lcd_gotoxy(cursorPosition.x, cursorPosition.y+charMode);
            }
            break;
        case '\r':
            // carrige return
            lcd_gotoxy(0, cursorPosition.y);
            break;
        default:
            // char doesn't fit in line
            if( (cursorPosition.x >= DISPLAY_WIDTH-sizeof(FONT[0])) || (c < ' ') ) break;
            // mapping char
            c -= ' ';
            if (c >= pgm_read_byte(&special_char[0][1]) ) {
                char temp = c;
                c = 0xff;
                for (uint8_t i=0; pgm_read_byte(&special_char[i][1]) != 0xff; i++) {
                    if ( pgm_read_byte(&special_char[i][0])-' ' == temp ) {
                        c = pgm_read_byte(&special_char[i][1]);
                        break;
                    }
                }
                if ( c == 0xff ) break;
            }
            // print char at display

            if (charMode == DOUBLESIZE) {
                uint16_t doubleChar[sizeof(FONT[0])];
                uint8_t dChar;
                if ((cursorPosition.x+2*sizeof(FONT[0]))>DISPLAY_WIDTH) break;
               
                for (uint8_t i=0; i < sizeof(FONT[0]); i++) {
                    doubleChar[i] = 0;
                    dChar = pgm_read_byte(&(FONT[(uint8_t)c][i]));
                    for (uint8_t j=0; j<8; j++) {
                        if ((dChar & (1 << j))) {
                            doubleChar[i] |= (1 << (j*2));
                            doubleChar[i] |= (1 << ((j*2)+1));
                        }
                    }
                }
                uint8_t data[sizeof(FONT[0])*2];
                for (uint8_t i = 0; i < sizeof(FONT[0]); i++)
                {
                    // print font to ram, print 6 columns
                    data[i<<1]=(doubleChar[i] & 0xff);
                    data[(i<<1)+1]=(doubleChar[i] & 0xff);
                }
                lcd_data(data, sizeof(FONT[0])*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[0]); i++)
                {
                    // print font to ram, print 6 columns
                    data[i<<1]=(doubleChar[i] >> 8);
                    data[(i<<1)+1]=(doubleChar[i] >> 8);
                }
                lcd_data(data, sizeof(FONT[0])*2);
               
                commandSequence[0] = 0xb0+cursorPosition.y;

                commandSequence[2] = cursorPosition.x+(2*sizeof(FONT[0]));

                lcd_command(commandSequence, sizeof(commandSequence));
                cursorPosition.x += sizeof(FONT[0])*2;
            } else {
                uint8_t data[sizeof(FONT[0])];
                if ((cursorPosition.x+sizeof(FONT[0]))>DISPLAY_WIDTH) break;
               
            for (uint8_t i = 0; i < sizeof(FONT[0]); i++)
                {
                    // print font to ram, print 6 columns
                    data[i]=(pgm_read_byte(&(FONT[(uint8_t)c][i])));
                }
                lcd_data(data, sizeof(FONT[0]));
                cursorPosition.x += sizeof(FONT[0]);
            }

            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.h

Code: [Select]
/*
 * 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 __cplusplus
extern "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_PORT PORTB
#define LCD_DDR DDRB
#define RES_PIN PB0
#define DC_PIN PB1
#define CS_PIN PB2

#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        32
   
   
   
    void lcd_command(uint8_t cmd[], uint8_t size);    // transmit command to display
    void lcd_data(uint8_t data[], uint16_t size);    // transmit data to display
    void lcd_init(uint8_t dispAttr);
    void lcd_home(void);                            // set cursor to 0,0
    void lcd_invert(uint8_t invert);        // invert display
    void lcd_sleep(uint8_t sleep);            // display goto sleep (power off)
    void lcd_set_contrast(uint8_t contrast);    // set contrast for display
    void 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 buffer
    void lcd_charMode(uint8_t mode);            // set size of chars
#if defined GRAPHICMODE
    void 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 RAM
    void lcd_clear_buffer(void); // clear display buffer
    uint8_t lcd_check_buffer(uint8_t x, uint8_t y); // read a pixel value from the display buffer
    void 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: [Select]
/*
 *  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[][6] 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[0] !!!
{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[][2] 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[0]
    {'Ü', 96},
    {'ä', 97},
    {'Ä', 98},
    {'ö', 99},
    {'Ö', 100},
    {'°', 101},
    {'ß', 102},
    {'µ', 103},
    {0xff, 0xff} // end of table special_char
};


Main:

Code: [Select]
//****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% :(
« Last Edit: April 04, 2021, 05:06:56 pm by bipolunipol »
 

Online ajb

  • Super Contributor
  • ***
  • Posts: 2604
  • Country: us
Re: ATTINY414 plus small OLED display
« Reply #5 on: April 08, 2021, 04:57:42 pm »
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.

Screen 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.

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):

However, I have a problem with starting now because the display is completely unresponsive. In addition, FLASH memory consumption reaches almost 87% from 18% :(

How 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.
 

Offline camila

  • Contributor
  • !
  • Posts: 11
  • Country: us
Re: ATTINY414 plus small OLED display
« Reply #6 on: April 08, 2021, 06:34:00 pm »
I recently wanted a flexible way of displaying information from a project, and found this small monochrome 64x48 OLED display on Aliexpress [1]. A similar one is available from Sparkfun [2]. 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.
 

Offline phil from seattle

  • Super Contributor
  • ***
  • Posts: 1029
  • Country: us
Re: ATTINY414 plus small OLED display
« Reply #7 on: April 08, 2021, 06:43:45 pm »
The ATTiny 1614 is 100% compatible (same periphs just more RAM), has 2K bytes of RAM and is about $0.20 more expensive.
« Last Edit: April 08, 2021, 07:21:14 pm by phil from seattle »
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5907
  • Country: es
Re: ATTINY414 plus small OLED display
« Reply #8 on: April 08, 2021, 08:05:56 pm »
I recently wanted a flexible way of displaying information from a project, and found this small monochrome 64x48 OLED display on Aliexpress [1]. A similar one is available from Sparkfun [2]. 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.

And 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).
« Last Edit: April 08, 2021, 08:08:29 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf