Settings menu works Movement working & TMP calibrated Tip reading sensibily Accuracy seems ok Trimmed down overshoot by biasing integral Saving to flash working, detailed idle Sleep mode Description scrolls Building for DFU working Motion detection update Use manual alg instead, using highpass filter, then sum current change vs rolling average Re-shuffle the pwm code organisation
244 lines
6.0 KiB
C++
244 lines
6.0 KiB
C++
/*
|
|
* OLED.cpp
|
|
*
|
|
* Created on: 29Aug.,2017
|
|
* Author: Ben V. Brown
|
|
*/
|
|
|
|
#include <OLED.hpp>
|
|
#include <string.h>
|
|
/*Setup params for the OLED screen*/
|
|
/*http://www.displayfuture.com/Display/datasheet/controller/SSD1307.pdf*/
|
|
/*All commands are prefixed with 0x80*/
|
|
/*Data packets are prefixed with 0x40*/
|
|
const uint8_t configLength = 50;
|
|
uint8_t OLED_Setup_Array[] = { /**/
|
|
0x80, 0xAE,/*Display off*/
|
|
0x80, 0xD5,/*Set display clock divide ratio / osc freq*/
|
|
0x80, 0x52,/*Divide ratios*/
|
|
0x80, 0xA8,/*Set Multiplex Ratio*/
|
|
0x80, 0x0E, /*16 == max brightness,39==dimmest*/
|
|
0x80, 0xC0,/*Set COM Scan direction*/
|
|
0x80, 0xD3,/*Set vertical Display offset*/
|
|
0x80, 0x00,/*0 Offset*/
|
|
0x80, 0x40,/*Set Display start line to 0*/
|
|
0x80, 0xA0,/*Set Segment remap to normal*/
|
|
0x80, 0x8D,/*Charge Pump*/
|
|
0x80, 0x14,/*Charge Pump settings*/
|
|
0x80, 0xDA,/*Set VCOM Pins hardware config*/
|
|
0x80, 0x02,/*Combination 2*/
|
|
0x80, 0x81,/*Contrast*/
|
|
0x80, 0x33,/*^51*/
|
|
0x80, 0xD9,/*Set pre-charge period*/
|
|
0x80, 0xF1,/*Pre charge period*/
|
|
0x80, 0xDB,/*Adjust VCOMH regulator ouput*/
|
|
0x80, 0x30,/*VCOM level*/
|
|
0x80, 0xA4,/*Enable the display GDDR*/
|
|
0x80, 0XA6,/*Normal display*/
|
|
0x80, 0x20,/*Memory Mode*/
|
|
0x80, 0x00,/*Wrap memory*/
|
|
0x80, 0xAF /*Display on*/
|
|
};
|
|
//Setup based on the SSD1307 and modified for the SSD1306
|
|
|
|
OLED::OLED(I2C_HandleTypeDef* i2cHandle) {
|
|
i2c = i2cHandle;
|
|
cursor_x = cursor_y = 0;
|
|
currentFont = FONT_12;
|
|
fontWidth = 12;
|
|
inLeftHandedMode = false;
|
|
firstStripPtr = &screenBuffer[13];
|
|
secondStripPtr = &screenBuffer[13 + 96];
|
|
fontHeight = 16;
|
|
fontWidth = 12;
|
|
displayOffset = 0;
|
|
displayOnOffState = true;
|
|
|
|
}
|
|
|
|
void OLED::initialize() {
|
|
HAL_Delay(5);
|
|
HAL_GPIO_WritePin(OLED_RESET_GPIO_Port, OLED_RESET_Pin, GPIO_PIN_SET);
|
|
HAL_Delay(5);
|
|
//Send the setup settings
|
|
HAL_I2C_Master_Transmit(i2c, DEVICEADDR_OLED, (uint8_t*) OLED_Setup_Array, configLength, 0xFFFF);
|
|
//displayOnOff(true);
|
|
|
|
screenBuffer[0] = 0x80;
|
|
screenBuffer[1] = 0x21;
|
|
screenBuffer[2] = 0x80;
|
|
screenBuffer[3] = inLeftHandedMode ? 0 : 32;
|
|
screenBuffer[4] = 0x80;
|
|
screenBuffer[5] = inLeftHandedMode ? 95 : 0x7F;
|
|
|
|
screenBuffer[6] = 0x80;//Set pages to rollover after 2
|
|
screenBuffer[7] = 0x22;
|
|
screenBuffer[8] = 0x80;
|
|
screenBuffer[9] = 0x00;
|
|
screenBuffer[10] = 0x80;
|
|
screenBuffer[11] = 0x01;
|
|
|
|
screenBuffer[12] = 0x40;
|
|
|
|
}
|
|
|
|
//Write out the buffer to the OLEd & call any rendering objects
|
|
void OLED::refresh() {
|
|
screenBuffer[12] = 0x40; // Ensure it never gets overwritten
|
|
screenBuffer[3] = inLeftHandedMode ? 0 : 32;
|
|
screenBuffer[5] = inLeftHandedMode ? 95 : 0x7F; // It rolls over when it exceeds this number (this is last writable column)
|
|
HAL_I2C_Master_Transmit(i2c, DEVICEADDR_OLED, screenBuffer, 12 + 96 * 2 + 1, 0xFFFF);
|
|
|
|
}
|
|
|
|
void OLED::drawChar(char c) {
|
|
//prints a char to the screen
|
|
if (c == '\n')
|
|
cursor_y += fontHeight;
|
|
if (c < ' ')
|
|
return;
|
|
uint8_t* charPointer;
|
|
c -= ' ';
|
|
//Fonts are offset to start at the space char.
|
|
charPointer = ((uint8_t*) currentFont) + ((fontWidth * (fontHeight / 8)) * c);
|
|
if (cursor_x >= 0)
|
|
drawArea(cursor_x, cursor_y, fontWidth, fontHeight, charPointer);
|
|
cursor_x += fontWidth;
|
|
}
|
|
|
|
void OLED::displayOnOff(bool on) {
|
|
|
|
if (on != displayOnOffState) {
|
|
uint8_t data[6] = { 0x80, 0X8D, 0x80, 0X14, 0x80, 0XAF }; //on
|
|
if (!on) {
|
|
data[3] = 0x10;
|
|
data[5] = 0xAE;
|
|
}
|
|
HAL_I2C_Master_Transmit(i2c, DEVICEADDR_OLED, data, 6, 0xFFFF);
|
|
displayOnOffState = on;
|
|
}
|
|
}
|
|
|
|
void OLED::setRotation(bool leftHanded) {
|
|
if (inLeftHandedMode != leftHanded) {
|
|
//send command struct again with changes
|
|
if (leftHanded == 1) {
|
|
OLED_Setup_Array[11] = 0xC8; //c1?
|
|
OLED_Setup_Array[19] = 0xA1;
|
|
} else if (leftHanded == 0) {
|
|
OLED_Setup_Array[11] = 0xC0;
|
|
OLED_Setup_Array[19] = 0xA0;
|
|
}
|
|
HAL_I2C_Master_Transmit(i2c, DEVICEADDR_OLED, (uint8_t*) OLED_Setup_Array, 50, 0xFFFF);
|
|
inLeftHandedMode = leftHanded;
|
|
}
|
|
}
|
|
|
|
//print a string to the current cursor location
|
|
void OLED::print(const char* str) {
|
|
while (str[0]) {
|
|
drawChar(str[0]);
|
|
str++;
|
|
}
|
|
}
|
|
|
|
void OLED::setCursor(int16_t x, int16_t y) {
|
|
cursor_x = x;
|
|
cursor_y = y;
|
|
}
|
|
|
|
void OLED::setFont(uint8_t fontNumber) {
|
|
if (fontNumber == 1) {
|
|
//small font
|
|
currentFont = ASCII6x8;
|
|
fontHeight = 8;
|
|
fontWidth = 6;
|
|
} else if (fontNumber == 2) {
|
|
currentFont = ExtraFontChars;
|
|
fontHeight = 16;
|
|
fontWidth = 12;
|
|
} else {
|
|
currentFont = FONT_12;
|
|
fontHeight = 16;
|
|
fontWidth = 12;
|
|
}
|
|
}
|
|
|
|
void OLED::drawImage(const uint8_t* buffer, uint8_t x, uint8_t width) {
|
|
drawArea(x, 0, width, 16, buffer);
|
|
}
|
|
|
|
//maximum places is 5
|
|
void OLED::printNumber(uint16_t number, uint8_t places) {
|
|
char buffer[6];
|
|
buffer[5] = 0; //null
|
|
if (places == 5) {
|
|
buffer[4] = '0' + number % 10;
|
|
number /= 10;
|
|
} else
|
|
buffer[4] = 0;
|
|
|
|
if (places > 3) {
|
|
buffer[3] = '0' + number % 10;
|
|
number /= 10;
|
|
} else
|
|
buffer[3] = 0;
|
|
|
|
if (places > 2) {
|
|
buffer[2] = '0' + number % 10;
|
|
number /= 10;
|
|
} else
|
|
buffer[2] = 0;
|
|
|
|
if (places > 1) {
|
|
buffer[1] = '0' + number % 10;
|
|
number /= 10;
|
|
} else
|
|
buffer[1] = 0;
|
|
buffer[0] = '0' + number % 10;
|
|
number /= 10;
|
|
print(buffer);
|
|
}
|
|
|
|
void OLED::clearScreen() {
|
|
memset(firstStripPtr, 0, 96);
|
|
memset(secondStripPtr, 0, 96);
|
|
}
|
|
|
|
bool OLED::getRotation() {
|
|
return inLeftHandedMode;
|
|
}
|
|
void OLED::drawBattery(uint8_t state) {
|
|
if (state > 10)
|
|
state = 10;
|
|
drawSymbol(3 + state);
|
|
}
|
|
void OLED::drawSymbol(uint8_t symbolID) {
|
|
//draw a symbol to the current cursor location
|
|
setFont(2);
|
|
drawChar(' ' + symbolID); // space offset is in all fonts, so we pad it here and remove it later
|
|
setFont(0);
|
|
}
|
|
|
|
//Draw an area, but y must be aligned on 0/8 offset
|
|
void OLED::drawArea(int16_t x, int8_t y, uint8_t wide, uint8_t height, const uint8_t* ptr) {
|
|
// Splat this from x->x+wide in two strides
|
|
if (x < 0)
|
|
return; //cutoffleft
|
|
if ((x + wide) > 96)
|
|
return; //cutoff right
|
|
if (y == 0) {
|
|
//Splat first line of data
|
|
for (uint8_t xx = 0; xx < (wide); xx++) {
|
|
firstStripPtr[xx + x] = ptr[xx];
|
|
}
|
|
}
|
|
if (y == 8 || height == 16) {
|
|
// Splat the second line
|
|
for (uint8_t xx = 0; xx < wide; xx++) {
|
|
secondStripPtr[x + xx] = ptr[xx + (height == 16 ? wide : 0)];
|
|
|
|
}
|
|
}
|
|
}
|