GameCounter/Source/lib/ssd1306xled/ssd1306xled.c

238 lines
6.4 KiB
C

/**
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
*
* @created: 2014-08-12
* @author: Neven Boyanov
*
* This is part of the Tinusaur/SSD1306xLED project.
*
* Copyright (c) 2016 Neven Boyanov, Tinusaur Team. All Rights Reserved.
* Distributed as open source software under MIT License, see LICENSE.txt file.
* Please, as a favor, retain the link http://tinusaur.org to The Tinusaur Project.
*
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
*
*/
// ============================================================================
#include <stdlib.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "ssd1306xled.h"
#include "font6x8.h"
#include "num2str.h"
// ----------------------------------------------------------------------------
// Convenience definitions for PORTB
#define DIGITAL_WRITE_HIGH(PORT) PORTB |= (1 << PORT)
#define DIGITAL_WRITE_LOW(PORT) PORTB &= ~(1 << PORT)
// ----------------------------------------------------------------------------
// Some code based on "IIC_wtihout_ACK" by http://www.14blog.com/archives/1358
const uint8_t ssd1306_init_sequence [] PROGMEM = { // Initialization Sequence
0xAE, // 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, 0x3F, // 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
0xAF // Display ON in normal mode
};
// ----------------------------------------------------------------------------
// These function should become separate library for handling I2C simplified output.
void ssd1306_xfer_start(void)
{
DIGITAL_WRITE_HIGH(SSD1306_SCL); // Set to HIGH
DIGITAL_WRITE_HIGH(SSD1306_SDA); // Set to HIGH
DIGITAL_WRITE_LOW(SSD1306_SDA); // Set to LOW
DIGITAL_WRITE_LOW(SSD1306_SCL); // Set to LOW
}
void ssd1306_xfer_stop(void)
{
DIGITAL_WRITE_LOW(SSD1306_SCL); // Set to LOW
DIGITAL_WRITE_LOW(SSD1306_SDA); // Set to LOW
DIGITAL_WRITE_HIGH(SSD1306_SCL); // Set to HIGH
DIGITAL_WRITE_HIGH(SSD1306_SDA); // Set to HIGH
}
void ssd1306_send_byte(uint8_t byte)
{
uint8_t i;
for (i = 0; i < 8; i++)
{
if ((byte << i) & 0x80)
DIGITAL_WRITE_HIGH(SSD1306_SDA);
else
DIGITAL_WRITE_LOW(SSD1306_SDA);
DIGITAL_WRITE_HIGH(SSD1306_SCL);
DIGITAL_WRITE_LOW(SSD1306_SCL);
}
DIGITAL_WRITE_HIGH(SSD1306_SDA);
DIGITAL_WRITE_HIGH(SSD1306_SCL);
DIGITAL_WRITE_LOW(SSD1306_SCL);
}
void ssd1306_send_command_start(void) {
ssd1306_xfer_start();
ssd1306_send_byte(SSD1306_SA); // Slave address, SA0=0
ssd1306_send_byte(0x00); // write command
}
void ssd1306_send_command_stop(void) {
ssd1306_xfer_stop();
}
void ssd1306_send_command(uint8_t command)
{
ssd1306_send_command_start();
ssd1306_send_byte(command);
ssd1306_send_command_stop();
}
void ssd1306_send_data_start(void)
{
ssd1306_xfer_start();
ssd1306_send_byte(SSD1306_SA);
ssd1306_send_byte(0x40); //write data
}
void ssd1306_send_data_stop(void)
{
ssd1306_xfer_stop();
}
/*
void ssd1306_send_data(uint8_t byte)
{
ssd1306_send_data_start();
ssd1306_send_byte(byte);
ssd1306_send_data_stop();
}
*/
// ----------------------------------------------------------------------------
void ssd1306_init(void)
{
DDRB |= (1 << SSD1306_SDA); // Set port as output
DDRB |= (1 << SSD1306_SCL); // Set port as output
for (uint8_t i = 0; i < sizeof (ssd1306_init_sequence); i++) {
ssd1306_send_command(pgm_read_byte(&ssd1306_init_sequence[i]));
}
}
void ssd1306_setpos(uint8_t x, uint8_t y)
{
ssd1306_send_command_start();
ssd1306_send_byte(0xb0 + y);
ssd1306_send_byte(((x & 0xf0) >> 4) | 0x10); // | 0x10
/* TODO: Verify correctness */ ssd1306_send_byte((x & 0x0f)); // | 0x01
ssd1306_send_command_stop();
}
void ssd1306_fill4(uint8_t p1, uint8_t p2, uint8_t p3, uint8_t p4) {
ssd1306_setpos(0, 0);
ssd1306_send_data_start();
for (uint16_t i = 0; i < 128 * 8 / 4; i++) {
ssd1306_send_byte(p1);
ssd1306_send_byte(p2);
ssd1306_send_byte(p3);
ssd1306_send_byte(p4);
}
ssd1306_send_data_stop();
}
void ssd1306_fill2(uint8_t p1, uint8_t p2) {
ssd1306_fill4(p1, p2, p1, p2);
}
void ssd1306_fill(uint8_t p) {
ssd1306_fill4(p, p, p, p);
}
// ----------------------------------------------------------------------------
void ssd1306_char_font6x8(char ch) {
uint8_t c = ch - 32;
ssd1306_send_data_start();
for (uint8_t i = 0; i < 6; i++)
{
ssd1306_send_byte(pgm_read_byte(&ssd1306xled_font6x8[c * 6 + i]));
}
ssd1306_send_data_stop();
}
void ssd1306_string_font6x8(char *s) {
while (*s) {
ssd1306_char_font6x8(*s++);
}
}
char ssd1306_numdec_buffer[USINT2DECASCII_MAX_DIGITS + 1];
void ssd1306_numdec_font6x8(uint16_t num) {
ssd1306_numdec_buffer[USINT2DECASCII_MAX_DIGITS] = '\0'; // Terminate the string.
uint8_t digits = usint2decascii(num, ssd1306_numdec_buffer);
ssd1306_string_font6x8(ssd1306_numdec_buffer + digits);
}
void ssd1306_numdecp_font6x8(uint16_t num) {
ssd1306_numdec_buffer[USINT2DECASCII_MAX_DIGITS] = '\0'; // Terminate the string.
usint2decascii(num, ssd1306_numdec_buffer);
ssd1306_string_font6x8(ssd1306_numdec_buffer);
}
// ----------------------------------------------------------------------------
void ssd1306_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[])
{
uint16_t j = 0;
uint8_t y;
if (y1 % 8 == 0) y = y1 / 8;
else y = y1 / 8 + 1;
for (y = y0; y < y1; y++)
{
ssd1306_setpos(x0,y);
ssd1306_send_data_start();
for (uint8_t x = x0; x < x1; x++)
{
ssd1306_send_byte(pgm_read_byte(&bitmap[j++]));
}
ssd1306_send_data_stop();
}
}
// ============================================================================