1
0
forked from me/IronOS

Larger OLED Support (#1713)

* Update header to declare full buffer size

* Strip refactoring

* Refactor the OLED scrolldown part 1

* High res capable scroll down

* Allow button press to skip scroll

* Bunch of Misc Fixups
This commit is contained in:
Ben V. Brown
2023-06-18 22:50:31 +10:00
committed by GitHub
parent d3d8e3d2d5
commit c6918093fb
8 changed files with 160 additions and 127 deletions

View File

@@ -379,20 +379,32 @@ uint8_t preStartChecksDone() {
} }
uint8_t getTipResistanceX10() { uint8_t getTipResistanceX10() {
#ifdef TIP_RESISTANCE_SENSE_Pin
// Return tip resistance in x10 ohms // Return tip resistance in x10 ohms
// We can measure this using the op-amp // We can measure this using the op-amp
return lastTipResistance; return lastTipResistance;
#else
return TIP_RESISTANCE;
#endif
} }
uint8_t getTipThermalMass() { uint8_t getTipThermalMass() {
#ifdef TIP_RESISTANCE_SENSE_Pin
if (lastTipResistance >= 80) { if (lastTipResistance >= 80) {
return TIP_THERMAL_MASS; return TIP_THERMAL_MASS;
} }
return 45; return 45;
#else
return TIP_THERMAL_MASS;
#endif
} }
uint8_t getTipInertia() { uint8_t getTipInertia() {
#ifdef TIP_RESISTANCE_SENSE_Pin
if (lastTipResistance >= 80) { if (lastTipResistance >= 80) {
return TIP_THERMAL_MASS; return TIP_THERMAL_MASS;
} }
return 10; return 10;
#else
return TIP_THERMAL_MASS;
#endif
} }

View File

@@ -5,7 +5,7 @@
#include "Settings.h" #include "Settings.h"
#include "USBPD.h" #include "USBPD.h"
#include "configuration.h" #include "configuration.h"
#include "stm32f1xx_hal.h"
void power_check() { void power_check() {
#ifdef POW_PD #ifdef POW_PD
// Cant start QC until either PD works or fails // Cant start QC until either PD works or fails
@@ -27,7 +27,7 @@ bool getIsPoweredByDCIN() {
#endif #endif
#ifdef MODEL_TS101 #ifdef MODEL_TS101
// TODO have to check what we are using // TODO have to check what we are using
return false; return HAL_GPIO_ReadPin(DC_SELECT_GPIO_Port, DC_SELECT_Pin) == GPIO_PIN_SET;
#endif #endif
#ifdef MODEL_TS100 #ifdef MODEL_TS100
return true; return true;

View File

@@ -113,7 +113,7 @@ uint16_t getADCVin(uint8_t sample) {
latestADC += hadc2.Instance->JDR2; latestADC += hadc2.Instance->JDR2;
latestADC += hadc2.Instance->JDR3; latestADC += hadc2.Instance->JDR3;
latestADC += hadc2.Instance->JDR4; latestADC += hadc2.Instance->JDR4;
latestADC <<= 3; latestADC <<= 1;
filter.update(latestADC); filter.update(latestADC);
} }
return filter.average(); return filter.average();

View File

@@ -224,10 +224,10 @@
#ifdef MODEL_TS80 #ifdef MODEL_TS80
#define VOLTAGE_DIV 780 // Default divider from schematic #define VOLTAGE_DIV 780 // Default divider from schematic
#define CALIBRATION_OFFSET 900 // the adc offset in uV #define CALIBRATION_OFFSET 900 // the adc offset in uV
#define PID_POWER_LIMIT 24 // Sets the max pwm power limit #define PID_POWER_LIMIT 35 // Sets the max pwm power limit
#define POWER_LIMIT 24 // 24 watts default power limit #define POWER_LIMIT 32 // 24 watts default power limit
#define HARDWARE_MAX_WATTAGE_X10 180 #define HARDWARE_MAX_WATTAGE_X10 320
#define POW_QC #define POW_QC
@@ -238,9 +238,9 @@
#define VOLTAGE_DIV 650 // Default for TS80P with slightly different resistors #define VOLTAGE_DIV 650 // Default for TS80P with slightly different resistors
#define CALIBRATION_OFFSET 1500 // the adc offset in uV #define CALIBRATION_OFFSET 1500 // the adc offset in uV
#define PID_POWER_LIMIT 35 // Sets the max pwm power limit #define PID_POWER_LIMIT 35 // Sets the max pwm power limit
#define POWER_LIMIT 30 // 30 watts default power limit #define POWER_LIMIT 32 // 30 watts default power limit
#define HARDWARE_MAX_WATTAGE_X10 300 #define HARDWARE_MAX_WATTAGE_X10 320
#define POW_PD 1 #define POW_PD 1
#define POW_QC 1 #define POW_QC 1

View File

@@ -160,7 +160,7 @@
#define HAS_POWER_DEBUG_MENU #define HAS_POWER_DEBUG_MENU
#define TEMP_NTC #define TEMP_NTC
#define I2C_SOFT_BUS_2 // For now we are doing software I2C to get around hardware chip issues #define I2C_SOFT_BUS_2 // For now we are doing software I2C to get around hardware chip issues
#define OLED_I2CBB #define OLED_I2CBB2
#define MODEL_HAS_DCDC // We dont have DC/DC but have reallly fast PWM that gets us roughly the same place #define MODEL_HAS_DCDC // We dont have DC/DC but have reallly fast PWM that gets us roughly the same place
#endif #endif

View File

@@ -14,9 +14,8 @@
#include <string.h> #include <string.h>
// rendering to the buffer // rendering to the buffer
uint8_t *OLED::firstStripPtr; // Pointers to the strips to allow for buffer uint8_t *OLED::stripPointers[4]; // Pointers to the strips to allow for buffer having extra content
// having extra content
uint8_t *OLED::secondStripPtr; // Pointers to the strips
bool OLED::inLeftHandedMode; // Whether the screen is in left or not (used for bool OLED::inLeftHandedMode; // Whether the screen is in left or not (used for
// offsets in GRAM) // offsets in GRAM)
OLED::DisplayState OLED::displayState; OLED::DisplayState OLED::displayState;
@@ -24,7 +23,7 @@ int16_t OLED::cursor_x, OLED::cursor_y;
bool OLED::initDone = false; bool OLED::initDone = false;
uint8_t OLED::displayOffset; uint8_t OLED::displayOffset;
uint8_t OLED::screenBuffer[16 + (OLED_WIDTH * (OLED_HEIGHT / 8)) + 10]; // The data buffer uint8_t OLED::screenBuffer[16 + (OLED_WIDTH * (OLED_HEIGHT / 8)) + 10]; // The data buffer
uint8_t OLED::secondFrameBuffer[OLED_WIDTH * 2]; uint8_t OLED::secondFrameBuffer[16 + (OLED_WIDTH * (OLED_HEIGHT / 8)) + 10];
uint32_t OLED::displayChecksum; uint32_t OLED::displayChecksum;
/*Setup params for the OLED screen*/ /*Setup params for the OLED screen*/
/*http://www.displayfuture.com/Display/datasheet/controller/SSD1307.pdf*/ /*http://www.displayfuture.com/Display/datasheet/controller/SSD1307.pdf*/
@@ -33,7 +32,7 @@ uint32_t OLED::displayChecksum;
I2C_CLASS::I2C_REG OLED_Setup_Array[] = { I2C_CLASS::I2C_REG OLED_Setup_Array[] = {
/**/ /**/
{0x80, 0xAE, 0}, /*Display off*/ {0x80, 0xAE, 0}, /*Display off*/
{0x80, 0xD5, 0}, /*Set display clock divide ratio / osc freq*/ {0x80, 0xD3, 0}, /*Set display clock divide ratio / osc freq*/
{0x80, 0x52, 0}, /*Divide ratios*/ {0x80, 0x52, 0}, /*Divide ratios*/
{0x80, 0xA8, 0}, /*Set Multiplex Ratio*/ {0x80, 0xA8, 0}, /*Set Multiplex Ratio*/
{0x80, OLED_HEIGHT - 1, 0}, /*Multiplex ratio adjusts how far down the matrix it scans*/ {0x80, OLED_HEIGHT - 1, 0}, /*Multiplex ratio adjusts how far down the matrix it scans*/
@@ -41,11 +40,11 @@ I2C_CLASS::I2C_REG OLED_Setup_Array[] = {
{0x80, 0xD3, 0}, /*Set vertical Display offset*/ {0x80, 0xD3, 0}, /*Set vertical Display offset*/
{0x80, 0x00, 0}, /*0 Offset*/ {0x80, 0x00, 0}, /*0 Offset*/
{0x80, 0x40, 0}, /*Set Display start line to 0*/ {0x80, 0x40, 0}, /*Set Display start line to 0*/
#ifdef OLED_SEGMENT_MAP_REVERSED #ifdef OLED_SEGMENT_MAP_REVERSED
{0x80, 0xA1, 0}, /*Set Segment remap to normal*/ {0x80, 0xA1, 0}, /*Set Segment remap to normal*/
#else #else
{0x80, 0xA0, 0}, /*Set Segment remap to normal*/ {0x80, 0xA0, 0}, /*Set Segment remap to normal*/
#endif #endif
{0x80, 0x8D, 0}, /*Charge Pump*/ {0x80, 0x8D, 0}, /*Charge Pump*/
{0x80, 0x14, 0}, /*Charge Pump settings*/ {0x80, 0x14, 0}, /*Charge Pump settings*/
{0x80, 0xDA, 0}, /*Set VCOM Pins hardware config*/ {0x80, 0xDA, 0}, /*Set VCOM Pins hardware config*/
@@ -111,13 +110,21 @@ static uint8_t easeInOutTiming(uint8_t t) { return t * t * (300 - 2 * t) / 10000
* @param b The value associated with 100% * @param b The value associated with 100%
* @param t The percentage [0..<100] * @param t The percentage [0..<100]
*/ */
static uint8_t lerp(uint8_t a, uint8_t b, uint8_t t) { return a + t * (b - a) / 100; } static uint16_t lerp(uint16_t a, uint16_t b, uint16_t t) { return a + t * (b - a) / 100; }
void OLED::initialize() { void OLED::initialize() {
cursor_x = cursor_y = 0; cursor_x = cursor_y = 0;
inLeftHandedMode = false; inLeftHandedMode = false;
firstStripPtr = &screenBuffer[FRAMEBUFFER_START]; #ifdef OLED_128x32
secondStripPtr = &screenBuffer[FRAMEBUFFER_START + OLED_WIDTH]; stripPointers[0] = &screenBuffer[FRAMEBUFFER_START];
stripPointers[1] = &screenBuffer[FRAMEBUFFER_START + OLED_WIDTH];
stripPointers[2] = &screenBuffer[FRAMEBUFFER_START + 2 * OLED_WIDTH];
stripPointers[3] = &screenBuffer[FRAMEBUFFER_START + 3 * OLED_WIDTH];
#else
stripPointers[0] = &screenBuffer[FRAMEBUFFER_START];
stripPointers[1] = &screenBuffer[FRAMEBUFFER_START + OLED_WIDTH];
#endif
displayOffset = 0; displayOffset = 0;
memcpy(&screenBuffer[0], &REFRESH_COMMANDS[0], sizeof(REFRESH_COMMANDS)); memcpy(&screenBuffer[0], &REFRESH_COMMANDS[0], sizeof(REFRESH_COMMANDS));
@@ -133,14 +140,13 @@ void OLED::initialize() {
initDone = true; initDone = true;
} }
void OLED::setFramebuffer(uint8_t *buffer) { void OLED::setFramebuffer(uint8_t *buffer) {
if (buffer == NULL) { stripPointers[0] = &buffer[FRAMEBUFFER_START];
firstStripPtr = &screenBuffer[FRAMEBUFFER_START]; stripPointers[1] = &buffer[FRAMEBUFFER_START + OLED_WIDTH];
secondStripPtr = &screenBuffer[FRAMEBUFFER_START + OLED_WIDTH];
return;
}
firstStripPtr = &buffer[0]; #ifdef OLED_128x32
secondStripPtr = &buffer[OLED_WIDTH]; stripPointers[2] = &buffer[FRAMEBUFFER_START + (2 * OLED_WIDTH)];
stripPointers[3] = &buffer[FRAMEBUFFER_START + (3 * OLED_WIDTH)];
#endif
} }
/* /*
@@ -233,7 +239,10 @@ void OLED::maskScrollIndicatorOnOLED() {
// Start of data // Start of data
0x40, 0x40,
#ifdef OLED_128x32
0x00,
0x00,
#endif
// Clears two 8px strips // Clears two 8px strips
0x00, 0x00,
0x00, 0x00,
@@ -249,8 +258,14 @@ void OLED::maskScrollIndicatorOnOLED() {
* Otherwise a rewinding navigation animation is shown to the second framebuffer contents. * Otherwise a rewinding navigation animation is shown to the second framebuffer contents.
*/ */
void OLED::transitionSecondaryFramebuffer(bool forwardNavigation) { void OLED::transitionSecondaryFramebuffer(bool forwardNavigation) {
uint8_t *firstBackStripPtr = &secondFrameBuffer[0]; uint8_t *stripBackPointers[4];
uint8_t *secondBackStripPtr = &secondFrameBuffer[OLED_WIDTH]; stripBackPointers[0] = &secondFrameBuffer[0];
stripBackPointers[1] = &secondFrameBuffer[OLED_WIDTH];
#ifdef OLED_128x32
stripBackPointers[2] = &secondFrameBuffer[OLED_WIDTH * 2];
stripBackPointers[3] = &secondFrameBuffer[OLED_WIDTH * 3];
#endif
TickType_t totalDuration = TICKS_100MS * 5; // 500ms TickType_t totalDuration = TICKS_100MS * 5; // 500ms
TickType_t duration = 0; TickType_t duration = 0;
@@ -262,6 +277,7 @@ void OLED::transitionSecondaryFramebuffer(bool forwardNavigation) {
uint8_t progress = ((duration * 100) / totalDuration); // Percentage of the period we are through for animation uint8_t progress = ((duration * 100) / totalDuration); // Percentage of the period we are through for animation
progress = easeInOutTiming(progress); progress = easeInOutTiming(progress);
progress = lerp(0, OLED_WIDTH, progress); progress = lerp(0, OLED_WIDTH, progress);
// Constrain
if (progress > OLED_WIDTH) { if (progress > OLED_WIDTH) {
progress = OLED_WIDTH; progress = OLED_WIDTH;
} }
@@ -278,11 +294,19 @@ void OLED::transitionSecondaryFramebuffer(bool forwardNavigation) {
offset = progress; offset = progress;
memmove(&firstStripPtr[oldStart], &firstStripPtr[oldPrevious], OLED_WIDTH - progress); memmove(&stripPointers[0][oldStart], &stripPointers[0][oldPrevious], OLED_WIDTH - progress);
memmove(&secondStripPtr[oldStart], &secondStripPtr[oldPrevious], OLED_WIDTH - progress); memmove(&stripPointers[1][oldStart], &stripPointers[1][oldPrevious], OLED_WIDTH - progress);
#ifdef OLED_128x32
memmove(&stripPointers[2][oldStart], &stripPointers[2][oldPrevious], OLED_WIDTH - progress);
memmove(&stripPointers[3][oldStart], &stripPointers[3][oldPrevious], OLED_WIDTH - progress);
#endif
memmove(&firstStripPtr[newStart], &firstBackStripPtr[newEnd], progress); memmove(&stripPointers[0][newStart], &stripBackPointers[0][newEnd], progress);
memmove(&secondStripPtr[newStart], &secondBackStripPtr[newEnd], progress); memmove(&stripPointers[1][newStart], &stripBackPointers[1][newEnd], progress);
#ifdef OLED_128x32
memmove(&stripPointers[2][newStart], &stripBackPointers[2][newEnd], progress);
memmove(&stripPointers[3][newStart], &stripBackPointers[3][newEnd], progress);
#endif
refresh(); refresh();
osDelay(TICKS_100MS / 7); osDelay(TICKS_100MS / 7);
@@ -296,60 +320,62 @@ void OLED::useSecondaryFramebuffer(bool useSecondary) {
if (useSecondary) { if (useSecondary) {
setFramebuffer(secondFrameBuffer); setFramebuffer(secondFrameBuffer);
} else { } else {
setFramebuffer(NULL); setFramebuffer(screenBuffer);
} }
} }
/** /**
* Plays a transition animation of scrolling downward. Note this does *not* * This assumes that the current display output buffer has the current on screen contents
* use the secondary framebuffer. * Then the secondary buffer has the "new" contents to be slid up onto the screen
* * Sadly we cant use the hardware scroll as some devices with the 128x32 screens dont have the GRAM for holding both screens at once
* This transition relies on the previous screen data already in the OLED
* RAM. The caller shall not call `OLED::refresh()` before calling this
* method, as doing so will overwrite the previous screen data. The caller
* does not need to call `OLED::refresh()` after this function returns.
* *
* **This function blocks until the transition has completed or user presses button** * **This function blocks until the transition has completed or user presses button**
*/ */
void OLED::transitionScrollDown() { void OLED::transitionScrollDown() {
// We want to draw the updated framebuffer to the next page downward.
uint8_t const pageStart = screenBuffer[13];
uint8_t const nextPage = (pageStart + (OLED_HEIGHT / 8)) % 8;
// Change page start address:
screenBuffer[13] = nextPage;
// Change page end address:
screenBuffer[15] = (nextPage + 1) % 8;
refresh(); // Now refresh to write out the contents to the new page for (uint8_t heightPos = 0; heightPos < OLED_HEIGHT; heightPos++) {
osDelay(TICKS_100MS / 5); // For each line, we shuffle all bits up a row
for (uint8_t xPos = 0; xPos < OLED_WIDTH; xPos++) {
const uint16_t firstStripPos = FRAMEBUFFER_START + xPos;
const uint16_t secondStripPos = firstStripPos + OLED_WIDTH;
#ifdef OLED_128x32
// For 32 pixel high OLED's we have four strips to tailchain
const uint16_t thirdStripPos = secondStripPos + OLED_WIDTH;
const uint16_t fourthStripPos = thirdStripPos + OLED_WIDTH;
// Move the MSB off the first strip, and pop MSB from second strip onto the first strip
screenBuffer[firstStripPos] = (screenBuffer[firstStripPos] >> 1) | ((screenBuffer[secondStripPos] & 0x01) << 7);
// Now shuffle off the second strip
screenBuffer[secondStripPos] = (screenBuffer[secondStripPos] >> 1) | ((screenBuffer[thirdStripPos] & 0x01) << 7);
// Now shuffle off the third strip
screenBuffer[thirdStripPos] = (screenBuffer[thirdStripPos] >> 1) | ((screenBuffer[fourthStripPos] & 0x01) << 7);
// Now forth strip gets the start of the new buffer
screenBuffer[fourthStripPos] = (screenBuffer[fourthStripPos] >> 1) | ((secondFrameBuffer[firstStripPos] & 0x01) << 7);
// Now cycle all the secondary buffers
uint8_t startLine = (pageStart * 8) + 1; secondFrameBuffer[firstStripPos] = (secondFrameBuffer[firstStripPos] >> 1) | ((secondFrameBuffer[secondStripPos] & 0x01) << 7);
secondFrameBuffer[secondStripPos] = (secondFrameBuffer[secondStripPos] >> 1) | ((secondFrameBuffer[thirdStripPos] & 0x01) << 7);
uint8_t scrollTo = (pageStart + (OLED_HEIGHT / 8)) * 8; secondFrameBuffer[thirdStripPos] = (secondFrameBuffer[thirdStripPos] >> 1) | ((secondFrameBuffer[fourthStripPos] & 0x01) << 7);
// Finally on the bottom row; we shuffle it up ready
// Scroll the screen by changing display start line. secondFrameBuffer[fourthStripPos] >>= 1;
// This effectively scrolls off the bottom of the current page and into the next one #else
for (uint8_t current = startLine; current <= scrollTo; current++) { // Move the MSB off the first strip, and pop MSB from second strip onto the first strip
if (getButtonState() != BUTTON_NONE) { screenBuffer[firstStripPos] = (screenBuffer[firstStripPos] >> 1) | ((screenBuffer[secondStripPos] & 0x01) << 7);
current = scrollTo; // Now shuffle off the second strip MSB, and replace it with the MSB of the secondary buffer
screenBuffer[secondStripPos] = (screenBuffer[secondStripPos] >> 1) | ((secondFrameBuffer[firstStripPos] & 0x01) << 7);
// Finally, do the shuffle on the second frame buffer
secondFrameBuffer[firstStripPos] = (secondFrameBuffer[firstStripPos] >> 1) | ((secondFrameBuffer[secondStripPos] & 0x01) << 7);
// Finally on the bottom row; we shuffle it up ready
secondFrameBuffer[secondStripPos] >>= 1;
#endif
} }
if (getButtonState() != BUTTON_NONE) {
// Set display start line (0x40~0x7F): // Exit early, but have to transition whole buffer
// X[5:0] - display start line value memcpy(screenBuffer + FRAMEBUFFER_START, secondFrameBuffer + FRAMEBUFFER_START, sizeof(screenBuffer) - FRAMEBUFFER_START);
uint8_t scrollCommandByte = 0b01000000 | (current & 0b00111111); refresh(); // Now refresh to write out the contents to the new page
return;
// Also update setup command for "set display start line": }
OLED_Setup_Array[8].val = scrollCommandByte; refresh(); // Now refresh to write out the contents to the new page
I2C_CLASS::I2C_RegisterWrite(DEVICEADDR_OLED, 0x80, scrollCommandByte);
osDelay(TICKS_100MS / 7); osDelay(TICKS_100MS / 7);
} }
// Now that scroll is done, revert to default page to avoid wrap issues
screenBuffer[13] = pageStart;
screenBuffer[15] = (pageStart + 1) % 8;
uint8_t scrollCommandByte = 0b01000000;
OLED_Setup_Array[8].val = scrollCommandByte;
refresh();
I2C_CLASS::I2C_RegisterWrite(DEVICEADDR_OLED, 0x80, scrollCommandByte);
} }
void OLED::setRotation(bool leftHanded) { void OLED::setRotation(bool leftHanded) {
@@ -387,7 +413,7 @@ void OLED::setRotation(bool leftHanded) {
screenBuffer[7] = inLeftHandedMode ? OLED_GRAM_END_FLIP : OLED_GRAM_END; // End address of the ram segment we are writing to (96 wide) screenBuffer[7] = inLeftHandedMode ? OLED_GRAM_END_FLIP : OLED_GRAM_END; // End address of the ram segment we are writing to (96 wide)
screenBuffer[9] = inLeftHandedMode ? 0xC8 : 0xC0; screenBuffer[9] = inLeftHandedMode ? 0xC8 : 0xC0;
// Force a screen refresh // Force a screen refresh
const int len = FRAMEBUFFER_START + (OLED_WIDTH * 2); const int len = FRAMEBUFFER_START + (OLED_WIDTH * (OLED_HEIGHT / 8));
I2C_CLASS::Transmit(DEVICEADDR_OLED, screenBuffer, len); I2C_CLASS::Transmit(DEVICEADDR_OLED, screenBuffer, len);
osDelay(TICKS_10MS); osDelay(TICKS_10MS);
checkDisplayBufferChecksum(); checkDisplayBufferChecksum();
@@ -540,15 +566,16 @@ void OLED::drawArea(int16_t x, int8_t y, uint8_t wide, uint8_t height, const uin
if (y == 0) { if (y == 0) {
// Splat first line of data // Splat first line of data
for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) { for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) {
firstStripPtr[xx + x] = ptr[xx]; stripPointers[0][xx + x] = ptr[xx];
} }
} }
if (y == 8 || height == 16) { if (y == 8 || height >= 16) {
// Splat the second line // Splat the second line
for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) { for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) {
secondStripPtr[x + xx] = ptr[xx + (height == 16 ? wide : 0)]; stripPointers[1][x + xx] = ptr[xx + (height == 16 ? wide : 0)];
} }
} }
// TODO NEEDS HEIGHT HANDLERS for 24/32
} }
// Draw an area, but y must be aligned on 0/8 offset // Draw an area, but y must be aligned on 0/8 offset
@@ -574,15 +601,15 @@ void OLED::drawAreaSwapped(int16_t x, int8_t y, uint8_t wide, uint8_t height, co
if (y == 0) { if (y == 0) {
// Splat first line of data // Splat first line of data
for (uint8_t xx = visibleStart; xx < visibleEnd; xx += 2) { for (uint8_t xx = visibleStart; xx < visibleEnd; xx += 2) {
firstStripPtr[xx + x] = ptr[xx + 1]; stripPointers[0][xx + x] = ptr[xx + 1];
firstStripPtr[xx + x + 1] = ptr[xx]; stripPointers[0][xx + x + 1] = ptr[xx];
} }
} }
if (y == 8 || height == 16) { if (y == 8 || height == 16) {
// Splat the second line // Splat the second line
for (uint8_t xx = visibleStart; xx < visibleEnd; xx += 2) { for (uint8_t xx = visibleStart; xx < visibleEnd; xx += 2) {
secondStripPtr[x + xx] = ptr[xx + 1 + (height == 16 ? wide : 0)]; stripPointers[1][x + xx] = ptr[xx + 1 + (height == 16 ? wide : 0)];
secondStripPtr[x + xx + 1] = ptr[xx + (height == 16 ? wide : 0)]; stripPointers[1][x + xx + 1] = ptr[xx + (height == 16 ? wide : 0)];
} }
} }
} }
@@ -608,13 +635,13 @@ void OLED::fillArea(int16_t x, int8_t y, uint8_t wide, uint8_t height, const uin
if (y == 0) { if (y == 0) {
// Splat first line of data // Splat first line of data
for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) { for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) {
firstStripPtr[xx + x] = value; stripPointers[0][xx + x] = value;
} }
} }
if (y == 8 || height == 16) { if (y == 8 || height == 16) {
// Splat the second line // Splat the second line
for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) { for (uint8_t xx = visibleStart; xx < visibleEnd; xx++) {
secondStripPtr[x + xx] = value; stripPointers[1][x + xx] = value;
} }
} }
} }
@@ -630,9 +657,9 @@ void OLED::drawFilledRect(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, bool c
mask = mask << (y0 % 8); mask = mask << (y0 % 8);
for (uint8_t col = x0; col < x1; col++) for (uint8_t col = x0; col < x1; col++)
if (clear) if (clear)
firstStripPtr[(y0 / 8) * 96 + col] &= ~mask; stripPointers[0][(y0 / 8) * 96 + col] &= ~mask;
else else
firstStripPtr[(y0 / 8) * 96 + col] |= mask; stripPointers[0][(y0 / 8) * 96 + col] |= mask;
} }
// Next loop down the line the total number of solids // Next loop down the line the total number of solids
if (y0 / 8 != y1 / 8) if (y0 / 8 != y1 / 8)
@@ -640,18 +667,18 @@ void OLED::drawFilledRect(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, bool c
for (uint8_t r = (y0 / 8); r < (y1 / 8); r++) { for (uint8_t r = (y0 / 8); r < (y1 / 8); r++) {
// This gives us the row index r // This gives us the row index r
if (clear) if (clear)
firstStripPtr[(r * 96) + col] = 0; stripPointers[0][(r * 96) + col] = 0;
else else
firstStripPtr[(r * 96) + col] = 0xFF; stripPointers[0][(r * 96) + col] = 0xFF;
} }
// Finally draw the tail // Finally draw the tail
mask = ~(mask << (y1 % 8)); mask = ~(mask << (y1 % 8));
for (uint8_t col = x0; col < x1; col++) for (uint8_t col = x0; col < x1; col++)
if (clear) if (clear)
firstStripPtr[(y1 / 8) * 96 + col] &= ~mask; stripPointers[0][(y1 / 8) * 96 + col] &= ~mask;
else else
firstStripPtr[(y1 / 8) * 96 + col] |= mask; stripPointers[0][(y1 / 8) * 96 + col] |= mask;
} }
void OLED::drawHeatSymbol(uint8_t state) { void OLED::drawHeatSymbol(uint8_t state) {

View File

@@ -37,18 +37,15 @@ extern "C" {
#define DEVICEADDR_OLED (0x3c << 1) #define DEVICEADDR_OLED (0x3c << 1)
#ifdef OLED_128x32 #ifdef OLED_128x32
// TODO; for now just cropping in on the screen from 128x32 to 96x16 #define OLED_WIDTH 128
#define OLED_WIDTH 96 #define OLED_HEIGHT 32
#define OLED_HEIGHT 16 #define OLED_GRAM_START 0x00 // Should be 0x00 when we have full width
#define OLED_GRAM_START 0x10 // Should be 0x00 when we have full width #define OLED_GRAM_END 0x7F // Should be 0x7F when we have full width
#define OLED_GRAM_END 0x6F // Should be 0x7F when we have full width
#define OLED_GRAM_START_FLIP 0 #define OLED_GRAM_START_FLIP 0
#define OLED_GRAM_END_FLIP 95 #define OLED_GRAM_END_FLIP 0x7F
#define OLED_VCOM_LAYOUT 0x12 #define OLED_VCOM_LAYOUT 0x12
#define OLED_SEGMENT_MAP_REVERSED #define OLED_SEGMENT_MAP_REVERSED
#warning "128x32 OLED's Not fully supported"
#else #else
#define OLED_WIDTH 96 #define OLED_WIDTH 96
#define OLED_HEIGHT 16 #define OLED_HEIGHT 16
@@ -80,7 +77,7 @@ public:
static void refresh() { static void refresh() {
if (checkDisplayBufferChecksum()) { if (checkDisplayBufferChecksum()) {
const int len = FRAMEBUFFER_START + (OLED_WIDTH * 2); const int len = FRAMEBUFFER_START + (OLED_WIDTH * (OLED_HEIGHT / 8));
I2C_CLASS::Transmit(DEVICEADDR_OLED, screenBuffer, len); I2C_CLASS::Transmit(DEVICEADDR_OLED, screenBuffer, len);
// DMA tx time is ~ 20mS Ensure after calling this you delay for at least 25ms // DMA tx time is ~ 20mS Ensure after calling this you delay for at least 25ms
// or we need to goto double buffering // or we need to goto double buffering
@@ -121,7 +118,7 @@ public:
// Draws a number at the current cursor location // Draws a number at the current cursor location
static void printNumber(uint16_t number, uint8_t places, FontStyle fontStyle, bool noLeaderZeros = true); static void printNumber(uint16_t number, uint8_t places, FontStyle fontStyle, bool noLeaderZeros = true);
// Clears the buffer // Clears the buffer
static void clearScreen() { memset(firstStripPtr, 0, OLED_WIDTH * 2); } static void clearScreen() { memset(stripPointers[0], 0, OLED_WIDTH * (OLED_HEIGHT / 8)); }
// Draws the battery level symbol // Draws the battery level symbol
static void drawBattery(uint8_t state) { drawSymbol(3 + (state > 10 ? 10 : state)); } static void drawBattery(uint8_t state) { drawSymbol(3 + (state > 10 ? 10 : state)); }
// Draws a checkbox // Draws a checkbox
@@ -143,7 +140,7 @@ public:
private: private:
static bool checkDisplayBufferChecksum() { static bool checkDisplayBufferChecksum() {
uint32_t hash = 0; uint32_t hash = 0;
const int len = FRAMEBUFFER_START + (OLED_WIDTH * 2); const int len = sizeof(screenBuffer);
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
hash += (i * screenBuffer[i]); hash += (i * screenBuffer[i]);
} }
@@ -154,16 +151,15 @@ private:
} }
static void drawChar(uint16_t charCode, FontStyle fontStyle); // Draw a character to the current cursor location static void drawChar(uint16_t charCode, FontStyle fontStyle); // Draw a character to the current cursor location
static void setFramebuffer(uint8_t *buffer); static void setFramebuffer(uint8_t *buffer);
static uint8_t *firstStripPtr; // Pointers to the strips to allow for buffer having extra content static uint8_t *stripPointers[4]; // Pointers to the strips to allow for buffer having extra content
static uint8_t *secondStripPtr; // Pointers to the strips
static bool inLeftHandedMode; // Whether the screen is in left or not (used for offsets in GRAM) static bool inLeftHandedMode; // Whether the screen is in left or not (used for offsets in GRAM)
static bool initDone; static bool initDone;
static DisplayState displayState; static DisplayState displayState;
static int16_t cursor_x, cursor_y; static int16_t cursor_x, cursor_y;
static uint8_t displayOffset; static uint8_t displayOffset;
static uint32_t displayChecksum; static uint32_t displayChecksum;
static uint8_t screenBuffer[16 + (OLED_WIDTH * 2) + 10]; // The data buffer static uint8_t screenBuffer[16 + (OLED_WIDTH * (OLED_HEIGHT / 8)) + 10]; // The data buffer
static uint8_t secondFrameBuffer[OLED_WIDTH * 2]; static uint8_t secondFrameBuffer[16 + OLED_WIDTH * (OLED_HEIGHT / 8) + 10];
}; };
#endif /* OLED_HPP_ */ #endif /* OLED_HPP_ */

View File

@@ -1006,9 +1006,6 @@ void gui_Menu(const menuitem *menu) {
animOpenState = true; animOpenState = true;
// The menu entering/exiting transition uses the secondary framebuffer, // The menu entering/exiting transition uses the secondary framebuffer,
// but the scroll down transition does not. // but the scroll down transition does not.
if (navState == NavState::ScrollingDown) {
OLED::useSecondaryFramebuffer(false);
}
OLED::setCursor(0, 0); OLED::setCursor(0, 0);
OLED::clearScreen(); OLED::clearScreen();
if (menu[currentScreen].shortDescriptionSize > 0) { if (menu[currentScreen].shortDescriptionSize > 0) {
@@ -1019,6 +1016,7 @@ void gui_Menu(const menuitem *menu) {
// Play the scroll down animation. // Play the scroll down animation.
OLED::maskScrollIndicatorOnOLED(); OLED::maskScrollIndicatorOnOLED();
OLED::transitionScrollDown(); OLED::transitionScrollDown();
OLED::useSecondaryFramebuffer(false);
} else { } else {
// The menu was drawn in a secondary framebuffer. // The menu was drawn in a secondary framebuffer.
// Now we play a transition from the pre-drawn primary // Now we play a transition from the pre-drawn primary