Display: first text on OLED.

Note by Traumflug: this code was written by Ruslan Popov a lot
earlier already. I picked it to i2c_test.c to get "something"
visible running. This is the commit finally adjusted to the new
display infrastructure.
This commit is contained in:
Ruslan Popov 2015-11-03 19:12:55 +03:00 committed by Markus Hitter
parent 5f95784c0b
commit e3fd9eaea7
4 changed files with 180 additions and 96 deletions

114
display_ssd1306.c Normal file
View File

@ -0,0 +1,114 @@
/** \file
\brief Code specific to the SSD1306 display.
*/
#include "display_ssd1306.h"
#ifdef DISPLAY_TYPE_SSD1306
#include "displaybus.h"
#include "font.h"
static const uint8_t PROGMEM init_sequence[] = {
0x00, // Command marker.
0xAE, // Display off.
0xD5, 0x80, // Display clock divider (reset).
0xA8, 0x1F, // 1/32 duty.
0x40 | 0x00, // Start line (reset).
0x20, 0x02, // Page addressing mode (reset).
0x22, 0x00, 0x03, // Start and end page in horiz./vert. addressing mode[1].
0x21, 0x00, 0x7F, // Start and end column in horiz./vert. addressing mode.
0xA0 | 0x00, // No segment remap (reset).
0xC0 | 0x00, // Normal com pins mapping (reset).
0xDA, 0x02, // Sequental without remap com pins.
0x81, 0x7F, // Contrast (reset).
0xDB, 0x20, // Vcomh (reset).
0xD9, 0xF1, // Precharge period.
0x8D, 0x14, // Charge pump.
0xA6, // Positive display.
0xA4, // Resume display.
0xAF // Display on.
};
// [1] Do not set this to 0x00..0x07 on a 32 pixel high display, or vertical
// addressing mode will mess up. 32 pixel high displays have only 4 pages
// (0..3), still addressing logic accepts, but can't deal with the 0..7
// meant for 64 pixel high displays.
/**
* Initializes the display's controller configuring the way of
* displaying data.
*/
void display_init(void) {
uint8_t i;
displaybus_init(DISPLAY_I2C_ADDRESS);
for (i = 0; i < sizeof(init_sequence); i++) {
// Send last byte with 'last_byte' set.
displaybus_write(init_sequence[i], (i == sizeof(init_sequence) - 1));
}
}
/**
Clear the screen. As this display supports many sophisticated commands,
but not a simple 'clear', we have to overwrite the entire memory with
zeros, byte by byte.
*/
void display_clear(void) {
uint16_t i;
// Set horizontal adressing mode.
displaybus_write(0x00, 0);
displaybus_write(0x20, 0);
displaybus_write(0x00, 1);
// Write 512 zeros.
displaybus_write(0x40, 0);
for (i = 0; i < 512; i++) {
displaybus_write(0x00, (i == 511));
}
// Return to page adressing mode.
displaybus_write(0x00, 0);
displaybus_write(0x20, 0);
displaybus_write(0x02, 1);
}
/**
Prints the text at a given position.
*/
void display_text_P(uint8_t line, uint8_t column, PGM_P message) {
uint8_t i;
// Enter command mode.
displaybus_write(0x00, 0);
// Set line.
displaybus_write(0xB0 | (line & 0x03), 0);
// Set column.
displaybus_write(0x00 | (column & 0x0F), 0);
displaybus_write(0x10 | ((column >> 4) & 0x0F), 1);
// Render text to bitmap to display.
displaybus_write(0x40, 0);
while (pgm_read_byte(message)) {
uint8_t index = pgm_read_byte(message) - 0x20;
// Send the character bitmap.
for (i = 0; i < pgm_read_byte(&font[index].columns); i++) {
displaybus_write(pgm_read_byte(&font[index].data[i]), 0);
}
// Send space between characters.
for (i = 0; i < FONT_SYMBOL_SPACE; i++) {
displaybus_write(0x00, 0);
}
message++;
}
// Send another space for transmission end.
displaybus_write(0x00, 1);
}
#endif /* DISPLAY_TYPE_SSD1306 */

56
display_ssd1306.h Normal file
View File

@ -0,0 +1,56 @@
#ifndef _DISPLAY_SSD1306_H
#define _DISPLAY_SSD1306_H
#include "config_wrapper.h"
#ifdef DISPLAY_TYPE_SSD1306
#define DISPLAY
#define DISPLAY_I2C_ADDRESS (0x3C << 1)
#define DISPLAY_LINES 4
#define DISPLAY_SYMBOLS_PER_LINE 16
#define HOTENDS_COUNT 1
#define HOTBED_ZONES 1
#define DISPLAY_PLACE_HOTEND 0, 0, 8
#define DISPLAY_PLACE_HOTBED 0, 8, 8
#define DISPLAY_PLACE_X 1, 0, 5
#define DISPLAY_PLACE_Y 1, 5, 5
#define DISPLAY_PLACE_Z 1, 10, 5
#define DISPLAY_PLACE_FEEDRATE 2, 0, 5
#define DISPLAY_PLACE_PROGRESS 2, 5, 5
#define DISPLAY_PLACE_TIMER 2, 10, 6
#define DISPLAY_PLACE_STATUS 3, 0, 16
typedef struct {
uint16_t hotend_temp[HOTENDS_COUNT];
uint16_t hotbed_temp[HOTBED_ZONES];
uint16_t x;
uint16_t y;
uint16_t z;
uint16_t feedrate;
uint8_t progress; // in percents
uint32_t timer; // in seconds
} DISPLAY_T;
void display_init(void);
void display_on(void);
void display_hotend(uint8_t index);
void display_hotbed(uint8_t index);
void display_point(uint16_t x, uint16_t y, uint16_t z);
void display_feedrate(uint16_t value);
void display_progress(uint8_t value);
void display_timer(uint32_t value);
void display_off(void);
void display_clear(void);
void display_text_P(uint8_t line, uint8_t column, PGM_P message_P);
#endif /* DISPLAY_TYPE_SSD1306 */
#endif /* _DISPLAY_SSD1306_H */

View File

@ -15,99 +15,16 @@
#include <string.h> #include <string.h>
#include "config_wrapper.h" #include "config_wrapper.h"
#include "displaybus.h" #include "display_ssd1306.h"
#include "font.h" #include "font.h"
#define DISPLAY_I2C_ADDRESS (0x3C << 1)
const uint8_t PROGMEM display_init[] = {
0x00, // Command marker.
0xAE, // Display off.
0xD5, 0x80, // Display clock divider (reset).
0xA8, 0x1F, // 1/32 duty.
0x40 | 0x00, // Start line (reset).
0x20, 0x02, // Page addressing mode (reset).
0x22, 0x00, 0x03, // Start and end page in horiz./vert. addressing mode[1].
0x21, 0x00, 0x7F, // Start and end column in horiz./vert. addressing mode.
0xA0 | 0x00, // No segment remap (reset).
0xC0 | 0x00, // Normal com pins mapping (reset).
0xDA, 0x02, // Sequental without remap com pins.
0x81, 0x7F, // Contrast (reset).
0xDB, 0x20, // Vcomh (reset).
0xD9, 0xF1, // Precharge period.
0x8D, 0x14, // Charge pump.
0xA6, // Positive display.
0xA4, // Resume display.
0xAF // Display on.
};
// [1] Do not set this to 0x00..0x07 on a 32 pixel high display, or vertical
// addressing mode will mess up. 32 pixel high displays have only 4 pages
// (0..3), still addressing logic accepts, but can't deal with the 0..7
// meant for 64 pixel high displays.
static void i2c_test(void) { static void i2c_test(void) {
uint16_t i;
const char* message = "Welcome to Teacup";
for (i = 0; i < sizeof(display_init); i++) {
// Send last byte with 'last_byte' set.
displaybus_write(pgm_read_byte(&display_init[i]),
(i == sizeof(display_init) - 1));
}
/** /**
Clear the screen. As this display supports many sophisticated commands,
but not a simple 'clear', we have to overwrite the entire memory with
zeros, byte by byte.
*/
// Set horizontal adressing mode.
displaybus_write(0x00, 0);
displaybus_write(0x20, 0);
displaybus_write(0x00, 1);
// Write 512 zeros.
displaybus_write(0x40, 0);
for (i = 0; i < 512; i++) {
displaybus_write(0x00, (i == 511));
}
// Return to page adressing mode.
displaybus_write(0x00, 0);
displaybus_write(0x20, 0);
displaybus_write(0x02, 1);
/**
Setup cursor on display.
"Welcome to Teacup" is 64 pixel columns wide, entire display is "Welcome to Teacup" is 64 pixel columns wide, entire display is
128 columns, so we offset by 32 columns to get it to the center. 128 columns, so we offset by 32 columns to get it to the center.
*/ */
displaybus_write(0x00, 0); display_text_P(1, 32, PSTR("Welcome to Teacup"));
// Line 1.
displaybus_write(0xB0 | 1, 0);
// Column 32.
displaybus_write(0x00 | (32 & 0x0F), 0);
displaybus_write(0x10 | ((32 >> 4) & 0x0F), 1);
// Render text to bitmap to display.
displaybus_write(0x40, 0);
while (*message) {
uint8_t index = (uint8_t)*message - 0x20;
// Send the character bitmap.
for (i = 0; i < pgm_read_byte(&font[index].columns); i++) {
displaybus_write(pgm_read_byte(&font[index].data[i]), 0);
}
// Send space between characters.
for (i = 0; i < FONT_SYMBOL_SPACE; i++) {
displaybus_write(0x00, 0);
}
message++;
}
// Send another space for transmission end.
displaybus_write(0x00, 1);
} }
#endif /* I2C_TEST */ #endif /* I2C_TEST */

View File

@ -32,7 +32,7 @@
#include "config_wrapper.h" #include "config_wrapper.h"
#ifdef I2C #ifdef I2C
// This is temporary, until display code is completed. // This is temporary, until display code is completed.
// It includes static i2c_test(), which is called in main(): // It includes static i2c_test(), which is called in init():
#define I2C_TEST #define I2C_TEST
#include "i2c_test.c" #include "i2c_test.c"
#undef I2C_TEST #undef I2C_TEST
@ -51,8 +51,8 @@
#include "clock.h" #include "clock.h"
#include "intercom.h" #include "intercom.h"
#include "spi.h" #include "spi.h"
#include "displaybus.h"
#include "sd.h" #include "sd.h"
#include "display_ssd1306.h"
#include "simulator.h" #include "simulator.h"
#ifdef SIMINFO #ifdef SIMINFO
@ -95,10 +95,6 @@ void init(void) {
spi_init(); spi_init();
#endif #endif
#ifdef DISPLAY_BUS
displaybus_init(DISPLAY_I2C_ADDRESS);
#endif
// set up timers // set up timers
timer_init(); timer_init();
@ -127,6 +123,12 @@ void init(void) {
// prepare the power supply // prepare the power supply
power_init(); power_init();
#ifdef DISPLAY
display_init();
display_clear();
i2c_test();
#endif
// say hi to host // say hi to host
serial_writestr_P(PSTR("start\nok\n")); serial_writestr_P(PSTR("start\nok\n"));
@ -147,11 +149,6 @@ int main (void)
init(); init();
#ifdef DISPLAY_BUS
// This is temporary, until display code is completed.
i2c_test();
#endif
// main loop // main loop
for (;;) for (;;)
{ {