parent
285f9acfb5
commit
52ed0f0ee7
@ -0,0 +1,7 @@
|
||||
{
|
||||
"microbit-dal": {
|
||||
"bluetooth": {
|
||||
"enabled": 0
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,184 @@
|
||||
/************************************************************************
|
||||
* font.h
|
||||
*
|
||||
* Copyright (C) Lisa Milne 2014 <lisa@ltmnet.com>
|
||||
*
|
||||
* This program 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
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
/*
|
||||
* The font has been found on opengameart.org:
|
||||
* http://opengameart.org/content/8x8-ascii-bitmap-font-with-c-source
|
||||
*/
|
||||
|
||||
#ifndef FONT_H
|
||||
#define FONT_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define NB_FONT_TILES 95
|
||||
#define FIRST_FONT_CHAR 0x20
|
||||
|
||||
|
||||
#define NORMAL(x) (x)
|
||||
|
||||
/*
|
||||
* Actual font data is written in "human drawing order", but must be sent in revers bit order
|
||||
* for some drivers (Epaper for example).
|
||||
* This macro takes care of bit reversal for each font byte once and for all.
|
||||
* This is a little bit ugly, but made at compile time, which allows storage of modified font
|
||||
* in FLASH memory.
|
||||
*/
|
||||
#define REV1(x) ( (((x) >> 1) & 0x5555555555555555) | (((x) & 0x5555555555555555) << 1) )
|
||||
#define REV2(x) ( ((REV1(x) >> 2) & 0x3333333333333333) | ((REV1(x) & 0x3333333333333333) << 2) )
|
||||
#define REVERSE(x) ( ((REV2(x) >> 4) & 0x0F0F0F0F0F0F0F0F) | ((REV2(x) & 0x0F0F0F0F0F0F0F0F) << 4) )
|
||||
|
||||
|
||||
/*
|
||||
* Actual font data is written in "human drawing order", but must be sent in a "vertical" way
|
||||
* for some drivers (Oled for example).
|
||||
* This macro takes care of bit reversal for each font byte once and for all.
|
||||
* This is a little bit ugly, but made at compile time, which allows storage of modified font
|
||||
* in FLASH memory.
|
||||
*/
|
||||
#define SBV(x, n) ( ((x) & (0x01ULL << (n * 8))) >> (n * 7) )
|
||||
#define VER1(x) ( SBV(x, 7) | SBV(x, 6) | SBV(x, 5) | SBV(x, 4) | SBV(x, 3) | SBV(x, 2) | SBV(x, 1) | SBV(x, 0) )
|
||||
#define VER2(x, n) ( (VER1((x) >> n)) << (n * 8) )
|
||||
#define VERTICAL(x) ( VER2(x, 0) | VER2(x, 1) | VER2(x, 2)| VER2(x, 3)| VER2(x, 4)| VER2(x, 5)| VER2(x, 6)| VER2(x, 7) )
|
||||
|
||||
|
||||
/*
|
||||
* Actual font data is written in "human drawing order", but must be sent in a "vertical" way
|
||||
* for some drivers (Oled for example).
|
||||
* This macro takes care of bit reversal for each font byte once and for all.
|
||||
* This is a little bit ugly, but made at compile time, which allows storage of modified font
|
||||
* in FLASH memory.
|
||||
*/
|
||||
#define SBR(x, n) REVERSE( SBV(x, n) )
|
||||
#define VR1(x) ( SBR(x, 7) | SBR(x, 6) | SBR(x, 5) | SBR(x, 4) | SBR(x, 3) | SBR(x, 2) | SBR(x, 1) | SBR(x, 0) )
|
||||
#define VR2(x, n) ( (VR1((x) >> (7 - n))) << (n * 8) )
|
||||
#define VERTICAL_REV(x) ( VR2(x, 0) | VR2(x, 1) | VR2(x, 2)| VR2(x, 3)| VR2(x, 4)| VR2(x, 5)| VR2(x, 6)| VR2(x, 7) )
|
||||
|
||||
|
||||
/*
|
||||
* The values in this array are a 8x8 bitmap font for ascii characters
|
||||
* As memory is a very precious ressource on a micro-controller all chars
|
||||
* before "space" (0x20) have been removed.
|
||||
*/
|
||||
#define FONT_TABLE \
|
||||
ROW(0x0000000000000000), /* (space) */ /* 0x20 */ \
|
||||
ROW(0x0808080800080000), /* ! */ \
|
||||
ROW(0x2828000000000000), /* " */ \
|
||||
ROW(0x00287C287C280000), /* # */ \
|
||||
ROW(0x081E281C0A3C0800), /* $ */ \
|
||||
ROW(0x6094681629060000), /* % */ \
|
||||
ROW(0x1C20201926190000), /* & */ \
|
||||
ROW(0x0808000000000000), /* ' */ \
|
||||
ROW(0x0810202010080000), /* ( */ \
|
||||
ROW(0x1008040408100000), /* ) */ \
|
||||
ROW(0x2A1C3E1C2A000000), /* * */ \
|
||||
ROW(0x0008083E08080000), /* + */ \
|
||||
ROW(0x0000000000081000), /* , */ \
|
||||
ROW(0x0000003C00000000), /* - */ \
|
||||
ROW(0x0000000000080000), /* . */ \
|
||||
ROW(0x0204081020400000), /* / */ \
|
||||
ROW(0x1824424224180000), /* 0 */ /*x30 */ \
|
||||
ROW(0x08180808081C0000), /* 1 */ \
|
||||
ROW(0x3C420418207E0000), /* 2 */ \
|
||||
ROW(0x3C420418423C0000), /* 3 */ \
|
||||
ROW(0x081828487C080000), /* 4 */ \
|
||||
ROW(0x7E407C02423C0000), /* 5 */ \
|
||||
ROW(0x3C407C42423C0000), /* 6 */ \
|
||||
ROW(0x7E04081020400000), /* 7 */ \
|
||||
ROW(0x3C423C42423C0000), /* 8 */ \
|
||||
ROW(0x3C42423E023C0000), /* 9 */ \
|
||||
ROW(0x0000080000080000), /* : */ \
|
||||
ROW(0x0000080000081000), /* ; */ \
|
||||
ROW(0x0006186018060000), /* < */ \
|
||||
ROW(0x00007E007E000000), /* = */ \
|
||||
ROW(0x0060180618600000), /* > */ \
|
||||
ROW(0x3844041800100000), /* ? */ \
|
||||
ROW(0x003C449C945C201C), /* @ */ /* 0x40 */ \
|
||||
ROW(0x1818243C42420000), /* A */ \
|
||||
ROW(0x7844784444780000), /* B */ \
|
||||
ROW(0x3844808044380000), /* C */ \
|
||||
ROW(0x7844444444780000), /* D */ \
|
||||
ROW(0x7C407840407C0000), /* E */ \
|
||||
ROW(0x7C40784040400000), /* F */ \
|
||||
ROW(0x3844809C44380000), /* G */ \
|
||||
ROW(0x42427E4242420000), /* H */ \
|
||||
ROW(0x3E080808083E0000), /* I */ \
|
||||
ROW(0x1C04040444380000), /* J */ \
|
||||
ROW(0x4448507048440000), /* K */ \
|
||||
ROW(0x40404040407E0000), /* L */ \
|
||||
ROW(0x4163554941410000), /* M */ \
|
||||
ROW(0x4262524A46420000), /* N */ \
|
||||
ROW(0x1C222222221C0000), /* O */ \
|
||||
ROW(0x7844784040400000), /* P */ /* 0x50 */ \
|
||||
ROW(0x1C222222221C0200), /* Q */ \
|
||||
ROW(0x7844785048440000), /* R */ \
|
||||
ROW(0x1C22100C221C0000), /* S */ \
|
||||
ROW(0x7F08080808080000), /* T */ \
|
||||
ROW(0x42424242423C0000), /* U */ \
|
||||
ROW(0x8142422424180000), /* V */ \
|
||||
ROW(0x4141495563410000), /* W */ \
|
||||
ROW(0x4224181824420000), /* X */ \
|
||||
ROW(0x4122140808080000), /* Y */ \
|
||||
ROW(0x7E040810207E0000), /* Z */ \
|
||||
ROW(0x3820202020380000), /* [ */ \
|
||||
ROW(0x4020100804020000), /* \ */ \
|
||||
ROW(0x3808080808380000), /* ] */ \
|
||||
ROW(0x1028000000000000), /* ^ */ \
|
||||
ROW(0x00000000007E0000), /* _ */ \
|
||||
ROW(0x1008000000000000), /* ` */ /* 0x60 */ \
|
||||
ROW(0x003C023E463A0000), /* a */ \
|
||||
ROW(0x40407C42625C0000), /* b */ \
|
||||
ROW(0x00001C20201C0000), /* c */ \
|
||||
ROW(0x02023E42463A0000), /* d */ \
|
||||
ROW(0x003C427E403C0000), /* e */ \
|
||||
ROW(0x0018103810100000), /* f */ \
|
||||
ROW(0x0000344C44340438), /* g */ \
|
||||
ROW(0x2020382424240000), /* h */ \
|
||||
ROW(0x0800080808080000), /* i */ \
|
||||
ROW(0x0800180808080870), /* j */ \
|
||||
ROW(0x20202428302C0000), /* k */ \
|
||||
ROW(0x1010101010180000), /* l */ \
|
||||
ROW(0x0000665A42420000), /* m */ \
|
||||
ROW(0x00002E3222220000), /* n */ \
|
||||
ROW(0x00003C42423C0000), /* o */ \
|
||||
ROW(0x00005C62427C4040), /* p */ /* 0x70 */ \
|
||||
ROW(0x00003A46423E0202), /* q */ \
|
||||
ROW(0x00002C3220200000), /* r */ \
|
||||
ROW(0x001C201804380000), /* s */ \
|
||||
ROW(0x00103C1010180000), /* t */ \
|
||||
ROW(0x00002222261A0000), /* u */ \
|
||||
ROW(0x0000424224180000), /* v */ \
|
||||
ROW(0x000081815A660000), /* w */ \
|
||||
ROW(0x0000422418660000), /* x */ \
|
||||
ROW(0x0000422214081060), /* y */ \
|
||||
ROW(0x00003C08103C0000), /* z */ \
|
||||
ROW(0x1C103030101C0000), /* { */ \
|
||||
ROW(0x0808080808080800), /* | */ \
|
||||
ROW(0x38080C0C08380000), /* } */ \
|
||||
ROW(0x000000324C000000), /* ~ */
|
||||
/* End of Table */
|
||||
|
||||
|
||||
#define DECLARE_FONT(font_name) \
|
||||
const uint64_t font_name[NB_FONT_TILES] = { \
|
||||
FONT_TABLE \
|
||||
};
|
||||
|
||||
#endif /* FONT_H */
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 British Broadcasting Corporation.
|
||||
This software is provided by Lancaster University by arrangement with the BBC.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "MicroBit.h"
|
||||
#include "ssd1306.h"
|
||||
|
||||
MicroBit uBit;
|
||||
MicroBitI2C i2c(I2C_SDA0,I2C_SCL0);
|
||||
MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_DIGITAL_OUT);
|
||||
|
||||
int main()
|
||||
{
|
||||
// Initialise the micro:bit runtime.
|
||||
uBit.init();
|
||||
|
||||
ssd1306 screen(&uBit, &i2c, &P0);
|
||||
while(true)
|
||||
{
|
||||
screen.display_line(0,0,"ABCDEFGHIJKLMNOP");
|
||||
screen.display_line(1,0,"BCDEFGHIJKLMNOP");
|
||||
screen.display_line(2,0,"CDEFGHIJKLMNOP");
|
||||
screen.display_line(3,0,"DEFGHIJKLMNOP");
|
||||
screen.display_line(4,0,"EFGHIJKLMNOP");
|
||||
screen.display_line(5,0,"FGHIJKLMNOP");
|
||||
screen.display_line(6,0,"GHIJKLMNOP");
|
||||
screen.display_line(7,0,"HIJKLMNOP");
|
||||
screen.update_screen();
|
||||
uBit.sleep(1000);
|
||||
}
|
||||
|
||||
release_fiber();
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,335 @@
|
||||
#include "MicroBit.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include "ssd1306.h"
|
||||
#include "font.h"
|
||||
|
||||
#define ROW(x) VERTICAL_REV(x)
|
||||
DECLARE_FONT(font);
|
||||
|
||||
ssd1306::ssd1306(MicroBit* uB, MicroBitI2C* uBi2c, MicroBitPin* pin_reset, uint8_t addr):uBit(uB),i2c(uBi2c),reset(pin_reset), address(addr)
|
||||
{
|
||||
buffer_set(gddram, 0x00);
|
||||
video_mode = SSD130x_DISP_NORMAL;
|
||||
contrast = 128;
|
||||
scan_dir = SSD130x_SCAN_BOTTOM_TOP;
|
||||
read_dir = SSD130x_RIGHT_TO_LEFT;
|
||||
offset_dir = SSD130x_MOVE_TOP;
|
||||
offset = 4;
|
||||
fullscreen = true;
|
||||
charge_pump = SSD130x_INTERNAL_PUMP;
|
||||
initialize();
|
||||
}
|
||||
|
||||
int ssd1306::initialize()
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t val = 0;
|
||||
fullscreen = 1;
|
||||
|
||||
reset->setDigitalValue(1);
|
||||
uBit->sleep(1);
|
||||
reset->setDigitalValue(0);
|
||||
uBit->sleep(10);
|
||||
reset->setDigitalValue(1);
|
||||
|
||||
ret = display_power(SSD130x_DISP_OFF);//AE
|
||||
if (ret != 0)
|
||||
{
|
||||
uBit->display.scroll("Power Error");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = set_display_on(SSD130x_DISP_RAM);//A4
|
||||
if (ret != 0)
|
||||
{
|
||||
uBit->display.scroll("DISP RAM Error");
|
||||
return ret;
|
||||
}
|
||||
//0xD5 0xF0
|
||||
set_display_clock(0x00,0x0F);
|
||||
|
||||
//0xA8 0x3F
|
||||
set_mux_ratio(0x3F);
|
||||
//0xD3 0x00
|
||||
set_display_offset(offset_dir, offset);
|
||||
//0|0x00
|
||||
send_command(SSD130x_CMD_COL_LOW_NIBLE(0x00),NULL,0);
|
||||
//0x8D 0x14
|
||||
if (charge_pump == SSD130x_INTERNAL_PUMP)
|
||||
{
|
||||
val = SSD130x_CMD_CHARGE_INTERN;
|
||||
send_command(SSD130x_CMD_CHARGE_PUMP,&val,1);
|
||||
}
|
||||
|
||||
//0x20 0x00
|
||||
ret = set_mem_addressing_mode(SSD130x_ADDR_TYPE_HORIZONTAL);
|
||||
if (ret != 0) {
|
||||
uBit->display.scroll("Mem Mode");
|
||||
return ret;
|
||||
}
|
||||
|
||||
//0x21,0,127
|
||||
set_column_address(0,127);
|
||||
//return 0;
|
||||
//0x22,0,63
|
||||
set_page_address(0,7);
|
||||
//0xa0|0x1
|
||||
ret = set_read_direction();
|
||||
if (ret != 0) {
|
||||
uBit->display.scroll("Read Dir");
|
||||
return ret;
|
||||
}
|
||||
//0xC8
|
||||
ret = set_scan_direction();
|
||||
if (ret != 0) {
|
||||
uBit->display.scroll("Scan Dir");
|
||||
return ret;
|
||||
}
|
||||
|
||||
//0xDA,0x12
|
||||
val = 0x12;
|
||||
send_command(SSD130x_CMD_COM_PIN_CONF,&val,1);
|
||||
set_contrast(0xFF);
|
||||
//0xd9 0xF1
|
||||
//0DB 0x40
|
||||
if (charge_pump == SSD130x_INTERNAL_PUMP)
|
||||
{
|
||||
val = 0xF1;
|
||||
send_command(SSD130x_CMD_SET_PRECHARGE, &val,1);
|
||||
val = SSD130x_VCOM_083;
|
||||
send_command(SSD130x_CMD_VCOM_LEVEL, &val,1);
|
||||
}
|
||||
send_command(SSD130x_CMD_PAGE_START_ADDR(0),NULL,0);
|
||||
|
||||
ret = set_display_on(SSD130x_DISP_NORMAL);//A6
|
||||
return display_power(SSD130x_DISP_ON);
|
||||
}
|
||||
|
||||
int ssd1306::power_off()
|
||||
{
|
||||
return display_power(SSD130x_DISP_OFF);
|
||||
}
|
||||
|
||||
int ssd1306::power_on()
|
||||
{
|
||||
return display_power(SSD130x_DISP_ON);
|
||||
}
|
||||
|
||||
int ssd1306::set_contrast(uint8_t ctrst)
|
||||
{
|
||||
contrast = ctrst;
|
||||
return send_command(SSD130x_CMD_CONTRAST, &contrast,1);
|
||||
}
|
||||
|
||||
int ssd1306::display_video_reverse()//FIXME params
|
||||
{
|
||||
if (video_mode == SSD130x_DISP_REVERSE)
|
||||
return send_command(SSD130x_CMD_DISP_REVERSE, NULL, 0);
|
||||
else
|
||||
return send_command(SSD130x_CMD_DISP_NORMAL, NULL, 0);
|
||||
}
|
||||
|
||||
#define CMD_BUF_SIZE 24
|
||||
int ssd1306::send_command(uint8_t cmd, uint8_t* data, uint8_t len)
|
||||
{
|
||||
char cmd_buf[CMD_BUF_SIZE] = {SSD130x_NEXT_BYTE_CMD,cmd};
|
||||
|
||||
if (2*len > CMD_BUF_SIZE-2)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int ret;
|
||||
if (len != 0)
|
||||
{
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
cmd_buf[2+(2*i)] = SSD130x_NEXT_BYTE_CMD;
|
||||
cmd_buf[3+(2*i)] = data[i];
|
||||
}
|
||||
}
|
||||
|
||||
ret = i2c->write(SSD130x_ADDR, cmd_buf, 2+(len*2));
|
||||
if( ret != MICROBIT_OK)
|
||||
{
|
||||
uBit->display.scroll("Command Error");
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ssd1306::set_mem_addressing_mode(uint8_t mode)
|
||||
{
|
||||
return send_command(SSD130x_CMD_ADDR_MODE,&mode,1);
|
||||
}
|
||||
|
||||
int ssd1306::set_column_address(uint8_t col_start, uint8_t col_end)
|
||||
{
|
||||
uint8_t buf[2] = {col_start,col_end};
|
||||
return send_command(SSD130x_CMD_COL_ADDR, buf, 2);
|
||||
}
|
||||
|
||||
int ssd1306::set_page_address(uint8_t page_start, uint8_t page_end)
|
||||
{
|
||||
uint8_t buf[2] = {page_start,page_end};
|
||||
return send_command(SSD130x_CMD_PAGE_ADDR, buf, 2);
|
||||
}
|
||||
|
||||
int ssd1306::set_display_on(uint8_t use_ram)
|
||||
{
|
||||
if (use_ram == SSD130x_DISP_BLANK)
|
||||
{
|
||||
return send_command(SSD130x_CMD_DISP_NORMAL, NULL,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return send_command(SSD130x_CMD_DISP_RAM, NULL,0);
|
||||
}
|
||||
}
|
||||
|
||||
int ssd1306::display_power(uint8_t status)
|
||||
{
|
||||
if (status == SSD130x_DISP_OFF)
|
||||
{
|
||||
return send_command(SSD130x_CMD_DISP_OFF, NULL,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return send_command(SSD130x_CMD_DISP_ON, NULL,0);
|
||||
}
|
||||
}
|
||||
|
||||
int ssd1306::set_scan_direction() //FIXME
|
||||
{
|
||||
if (scan_dir == SSD130x_SCAN_TOP_BOTTOM)
|
||||
{
|
||||
return send_command(SSD130x_CMD_COM_SCAN_NORMAL, NULL,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return send_command(SSD130x_CMD_COM_SCAN_REVERSE, NULL,0);
|
||||
}
|
||||
}
|
||||
|
||||
int ssd1306::set_read_direction()
|
||||
{
|
||||
if(read_dir == SSD130x_RIGHT_TO_LEFT)
|
||||
return send_command(SSD130x_CMD_SEG0_MAP_RIGHT, NULL,0);
|
||||
else
|
||||
return send_command(SSD130x_CMD_SEG0_MAP_LEFT, NULL,0);
|
||||
}
|
||||
|
||||
int ssd1306::set_mux_ratio(uint8_t ratio)
|
||||
{
|
||||
uint8_t data = SSD130x_MUX_DATA(ratio);
|
||||
return send_command(SSD130x_CMD_PAGE_ADDR, &data, 1);
|
||||
}
|
||||
|
||||
int ssd1306::set_display_clock(uint8_t divide, uint8_t frequency)
|
||||
{
|
||||
uint8_t data = SSD130x_CLK_DIV(divide) | SSD130x_CLK_FREQ(frequency);
|
||||
if (data != 0xF0)
|
||||
uBit->display.scroll("Error Clock");
|
||||
return send_command(SSD130x_CMD_DISP_CLK_DIV, &data, 1);
|
||||
}
|
||||
|
||||
int ssd1306::set_display_offset(uint8_t dir, uint8_t nb_lines)
|
||||
{
|
||||
uint8_t offset = 0;
|
||||
if (nb_lines >= SSD130x_NB_LINES)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
if (dir == SSD130x_MOVE_TOP)
|
||||
offset = SSD130x_OFFSET_DATA(nb_lines);
|
||||
else
|
||||
offset = SSD130x_OFFSET_DATA(SSD130x_NB_LINES - nb_lines);
|
||||
return send_command(SSD130x_CMD_DISPLAY_OFFSET, &offset, 1);
|
||||
}
|
||||
|
||||
int ssd1306::update_screen()
|
||||
{
|
||||
int ret;
|
||||
if (!fullscreen) {
|
||||
ret = set_column_address(0, 127);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ret = set_page_address(0, 7);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
fullscreen = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Setup I2C transfer */
|
||||
gddram[0] = SSD130x_DATA_ONLY;
|
||||
|
||||
/* Send data on I2C bus */
|
||||
ret = i2c->write(SSD130x_ADDR, (char*) gddram,GDDRAM_SIZE+1);
|
||||
if (ret != MICROBIT_OK)
|
||||
{
|
||||
uBit->display.scroll("Full Screen Error");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ssd1306::display_char(uint8_t line, uint8_t col, uint8_t c)
|
||||
{
|
||||
uint8_t tile = (c > FIRST_FONT_CHAR) ? (c - FIRST_FONT_CHAR) : 0;
|
||||
uint8_t* tile_data = (uint8_t*)(&font[tile]);
|
||||
buffer_set_tile(gddram, col, line, tile_data);
|
||||
}
|
||||
|
||||
int ssd1306::display_line(uint8_t line, uint8_t col, const char* text)
|
||||
{
|
||||
int len = strlen((char*)text);
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
uint8_t tile = (text[i] > FIRST_FONT_CHAR) ? (text[i] - FIRST_FONT_CHAR) : 0;
|
||||
uint8_t* tile_data = (uint8_t*)(&font[tile]);
|
||||
buffer_set_tile(gddram, col++, line, tile_data);
|
||||
if (col >= (OLED_LINE_CHAR_LENGTH)) {
|
||||
col = 0;
|
||||
line++;
|
||||
if (line >= SSD130x_NB_PAGES) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Set whole display to given value */
|
||||
int ssd1306::buffer_set(uint8_t *gddram, uint8_t val)
|
||||
{
|
||||
memset(gddram + 1, val, GDDRAM_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Change our internal buffer, without actually displaying the changes */
|
||||
int ssd1306::buffer_set_pixel(uint8_t* gddram, uint8_t x0, uint8_t y0, uint8_t state)
|
||||
{
|
||||
uint8_t* addr = gddram + 1 + ((y0 / 8) * 128) + x0;
|
||||
if (state != 0) {
|
||||
*addr |= (0x01 << (y0 % 8));
|
||||
} else {
|
||||
*addr &= ~(0x01 << (y0 % 8));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Change a "tile" in the bitmap memory.
|
||||
* A tile is a 8x8 pixels region, aligned on a 8x8 grid representation of the display.
|
||||
* x0 and y0 are in number of tiles.
|
||||
*/
|
||||
int ssd1306::buffer_set_tile(uint8_t* gddram, uint8_t x0, uint8_t y0, uint8_t* tile)
|
||||
{
|
||||
uint8_t* addr = gddram + 1 + (y0 * 128) + (x0 * 8);
|
||||
memcpy(addr, tile, 8);
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,248 @@
|
||||
/****************************************************************************
|
||||
* ssd1306.h
|
||||
*
|
||||
* I2C Driver for 128x64 oled display drivers
|
||||
*
|
||||
* Copyright 2016 Nathael Pajani <nathael.pajani@ed3l.fr>
|
||||
* Copyright 2022 Chomienne Anthony <anthony@mob-dev.fr>
|
||||
*
|
||||
*
|
||||
* This program 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
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*************************************************************************** */
|
||||
|
||||
/**
|
||||
* This code is mainly an adaptation of code provided by Techno-Innov (Nathael Pajani <nathael.pajani@ed3l.fr>)
|
||||
* www.techno-innov.fr
|
||||
* http://git.techno-innov.fr
|
||||
*/
|
||||
|
||||
#ifndef SSD1306
|
||||
#define SSD1306
|
||||
|
||||
#define SSD130x_ADDR 0x7A
|
||||
|
||||
#define SSD130x_NB_LINES 64
|
||||
#define SSD130x_NB_PAGES 8
|
||||
#define SSD130x_NB_COL 128
|
||||
|
||||
|
||||
enum ssd130x_defs {
|
||||
SSD130x_DISP_OFF = 0,
|
||||
SSD130x_DISP_ON,
|
||||
SSD130x_DISP_RAM,
|
||||
SSD130x_DISP_BLANK,
|
||||
/* For reverse video */
|
||||
SSD130x_DISP_NORMAL,
|
||||
SSD130x_DISP_REVERSE,
|
||||
/* For scan dirrection */
|
||||
SSD130x_SCAN_TOP_BOTTOM,
|
||||
SSD130x_SCAN_BOTTOM_TOP,
|
||||
SSD130x_RIGHT_TO_LEFT,
|
||||
SSD130x_LEFT_TO_RIGHT,
|
||||
/* For display offset */
|
||||
SSD130x_MOVE_TOP,
|
||||
SSD130x_MOVE_BOTTOM,
|
||||
};
|
||||
|
||||
|
||||
#define SSD130x_DATA_ONLY 0x40
|
||||
#define SSD130x_NEXT_BYTE_DATA 0xC0
|
||||
#define SSD130x_NEXT_BYTE_CMD 0x80
|
||||
|
||||
/* Display controll */
|
||||
#define SSD130x_CMD_CONTRAST 0x81
|
||||
#define SSD130x_CMD_DISP_RAM 0xA4
|
||||
#define SSD130x_CMD_DISP_NORAM 0xA5
|
||||
#define SSD130x_CMD_DISP_NORMAL 0xA6
|
||||
#define SSD130x_CMD_DISP_REVERSE 0xA7
|
||||
#define SSD130x_CMD_DISP_OFF 0xAE
|
||||
#define SSD130x_CMD_DISP_ON 0xAF
|
||||
|
||||
/* Scrolling controll */
|
||||
#define SSD130x_CMD_SCROLL_RIGHT 0x26
|
||||
#define SSD130x_CMD_SCROLL_LEFT 0x27
|
||||
#define SSD130x_CMD_VSCROLL_RIGHT 0x29
|
||||
#define SSD130x_CMD_VSCROLL_LEFT 0x2A
|
||||
#define SSD130x_CMD_STOP_SCROLL 0x2E
|
||||
#define SSD130x_CMD_START_SCROLL 0x2F
|
||||
#define SSD130x_CMD_VSCROLL_REGION 0xA3
|
||||
/* Data bytes for scrolling controll */
|
||||
#define SSD130x_SCROLL_DATA_DUMMY 0x00
|
||||
#define SSD130x_SCROLL_DATA_END 0xFF
|
||||
#define SSD130x_SCROLL_DATA_START_PAGE(x) ((x) & 0x07)
|
||||
#define SSD130x_SCROLL_DATA_END_PAGE(x) ((x) & 0x07)
|
||||
#define SSD130x_SCROLL_DATA_ROWS(x) ((x) & 0x3F)
|
||||
#define SSD130x_SCROLL_DATA_STEP(x) ((x) & 0x07)
|
||||
/* Scroll steps definitions */
|
||||
#define SSD130x_SCROLL_2_FRAMES 0x07
|
||||
#define SSD130x_SCROLL_3_FRAMES 0x04
|
||||
#define SSD130x_SCROLL_4_FRAMES 0x05
|
||||
#define SSD130x_SCROLL_5_FRAMES 0x00
|
||||
#define SSD130x_SCROLL_25_FRAMES 0x06
|
||||
#define SSD130x_SCROLL_64_FRAMES 0x01
|
||||
#define SSD130x_SCROLL_128_FRAMES 0x02
|
||||
#define SSD130x_SCROLL_256_FRAMES 0x03
|
||||
|
||||
/* GDDRAM Adressing */
|
||||
#define SSD130x_CMD_ADDR_MODE 0x20
|
||||
/* Data bytes for adressing mode election */
|
||||
#define SSD130x_ADDR_TYPE_HORIZONTAL 0x00
|
||||
#define SSD130x_ADDR_TYPE_VERTICAL 0x01
|
||||
#define SSD130x_ADDR_TYPE_PAGE 0x02
|
||||
|
||||
/* GDDRAM Page adressing mode */
|
||||
#define SSD130x_CMD_COL_LOW_NIBLE(x) (0x00 + ((x) & 0x0F))
|
||||
#define SSD130x_CMD_COL_HIGH_NIBLE(x) (0x10 + ((x) & 0x0F))
|
||||
#define SSD130x_CMD_PAGE_START_ADDR(x) (0xB0 + ((x) & 0x07))
|
||||
|
||||
/* GDDRAM horizontal or vertical addressing mode */
|
||||
#define SSD130x_CMD_COL_ADDR 0x21
|
||||
#define SSD130x_CMD_PAGE_ADDR 0x22
|
||||
/* Data bytes for horizontal or vertical adressing mode */
|
||||
#define SSD130x_ADDR_COL(x) ((x) & 0x7F)
|
||||
#define SSD130x_ADDR_PAGE(x) ((x) & 0x07)
|
||||
|
||||
/* Charge pump */
|
||||
#define SSD130x_EXT_VCC 0x01
|
||||
#define SSD130x_INTERNAL_PUMP 0x00
|
||||
#define SSD130x_CMD_CHARGE_PUMP 0x8D
|
||||
#define SSD130x_CMD_CHARGE_EXT 0x10
|
||||
#define SSD130x_CMD_CHARGE_INTERN 0x14
|
||||
|
||||
/* Hardware configuration */
|
||||
#define SSD130x_CMD_START_LINE(x) (0x40 + ((x) & 0x3F))
|
||||
#define SSD130x_CMD_SEG0_MAP_RIGHT 0xA1
|
||||
#define SSD130x_CMD_SEG0_MAP_LEFT 0xA0
|
||||
|
||||
/* Hardware configuration : Mux ratio */
|
||||
#define SSD130x_CMD_SET_MUX 0xA8
|
||||
/* Set mux ratio Data to N+1 (Values for N from 0 to 14 are invalid) */
|
||||
#define SSD130x_MUX_DATA(x) ((x) & 0x3F) /* Reset is N=63 (64 mux) */
|
||||
|
||||
/* Hardware configuration : COM Scan */
|
||||
#define SSD130x_CMD_COM_SCAN_NORMAL 0xC0 /* Reset mode : top to bottom */
|
||||
#define SSD130x_CMD_COM_SCAN_REVERSE 0xC8 /* Bottom to top */
|
||||
#define SSD130x_CMD_DISPLAY_OFFSET 0xD3
|
||||
/* Data for display offset (COM shift) */
|
||||
#define SSD130x_OFFSET_DATA(x) ((x) & 0x3F)
|
||||
#define SSD130x_CMD_COM_PIN_CONF 0xDA
|
||||
/* Data for COM pins hardware configuration */
|
||||
#define SSD130x_COM_SEQUENTIAL (0x00 << 4)
|
||||
#define SSD130x_COM_ALTERNATIVE (0x01 << 4) /* Reset mode */
|
||||
#define SSD130x_COM_NO_REMAP (0x00 << 5) /* Reset mode */
|
||||
#define SSD130x_COM_REMAP (0x01 << 5)
|
||||
|
||||
/* Timing and driving scheme : Clock */
|
||||
#define SSD130x_CMD_DISP_CLK_DIV 0xD5
|
||||
#define SSD130x_CLK_DIV(x) ((x) & 0x0F) /* Set to N+1 (Default is 0+1) */
|
||||
#define SSD130x_CLK_FREQ(x) (((x) & 0x0F) << 4) /* Reset is 0x80 */
|
||||
|
||||
/* Timing and driving scheme : Precharge */
|
||||
#define SSD130x_CMD_SET_PRECHARGE 0xD9
|
||||
#define SSD130x_PRECHARGE_PHASE1(x) ((x) & 0x0F) /* Default to 2, 0 is invalid */
|
||||
#define SSD130x_PRECHARGE_PHASE2(x) (((x) & 0x0F) << 4) /* Default to 2, 0 is invalid */
|
||||
|
||||
/* Timing and driving scheme : Voltage */
|
||||
#define SSD130x_CMD_VCOM_LEVEL 0xDB
|
||||
#define SSD130x_VCOM_065 0x00
|
||||
#define SSD130x_VCOM_077 0x20
|
||||
#define SSD130x_VCOM_083 0x30
|
||||
|
||||
/* NO-OP */
|
||||
#define SSD130x_CMD_NOP 0xE3
|
||||
|
||||
/* Status register read */
|
||||
#define SSD130x_STATUS_ON (0x01 << 6)
|
||||
|
||||
#define GDDRAM_SIZE (128 * 8)
|
||||
|
||||
#define OLED_LINE_CHAR_LENGTH (SSD130x_NB_COL / 8)
|
||||
#define DISPLAY_LINE_LENGTH (OLED_LINE_CHAR_LENGTH + 1)
|
||||
|
||||
#include <cstdint>
|
||||
#include <MicroBit.h>
|
||||
|
||||
class ssd1306 {
|
||||
public:
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
ssd1306(MicroBit* uB, MicroBitI2C* uBi2c, MicroBitPin* pin_reset,uint8_t addr = SSD130x_ADDR);
|
||||
|
||||
/**
|
||||
* Power Off the screen
|
||||
*/
|
||||
int power_off();
|
||||
|
||||
/**
|
||||
* Power On the screen
|
||||
*/
|
||||
int power_on();
|
||||
|
||||
/**
|
||||
* Display a single char a position (line, col)
|
||||
*/
|
||||
void display_char(uint8_t line, uint8_t col, uint8_t c);
|
||||
|
||||
/**
|
||||
* Display a text at position (line, col)
|
||||
*/
|
||||
int display_line(uint8_t line, uint8_t col, const char* text);
|
||||
|
||||
/**
|
||||
* update screen display
|
||||
* should be called after a series of display change
|
||||
*/
|
||||
int update_screen();
|
||||
|
||||
private:
|
||||
int initialize();
|
||||
int send_command(uint8_t cmd, uint8_t* data, uint8_t len);
|
||||
int set_mem_addressing_mode(uint8_t mode);
|
||||
int set_column_address(uint8_t col_start, uint8_t col_end);
|
||||
int set_page_address(uint8_t page_start, uint8_t page_end);
|
||||
int set_display_on(uint8_t use_ram);
|
||||
int display_power(uint8_t status);
|
||||
int set_scan_direction();
|
||||
int set_read_direction();
|
||||
int set_display_offset(uint8_t dir, uint8_t nb_lines);
|
||||
int set_mux_ratio(uint8_t ratio);
|
||||
int set_display_clock(uint8_t divide, uint8_t frequency);
|
||||
int set_contrast(uint8_t contrast);
|
||||
int display_video_reverse();
|
||||
|
||||
int buffer_set(uint8_t *gddram, uint8_t val);
|
||||
int buffer_set_pixel(uint8_t* gddram, uint8_t x0, uint8_t y0, uint8_t state);
|
||||
int buffer_set_tile(uint8_t* gddram, uint8_t x0, uint8_t y0, uint8_t* tile);
|
||||
|
||||
|
||||
MicroBit* uBit;
|
||||
MicroBitI2C* i2c;
|
||||
MicroBitPin* reset;
|
||||
uint8_t gddram[ 1 + GDDRAM_SIZE ];
|
||||
uint8_t address;
|
||||
uint8_t video_mode;
|
||||
uint8_t contrast;
|
||||
uint8_t scan_dir;
|
||||
uint8_t read_dir;
|
||||
uint8_t offset_dir;
|
||||
uint8_t offset;
|
||||
uint8_t charge_pump;
|
||||
bool fullscreen;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in new issue