Skip to content

Commit

Permalink
Update power management logic of the WS0010 driver
Browse files Browse the repository at this point in the history
  • Loading branch information
akasaka committed Oct 24, 2024
1 parent f60fce9 commit fdc28c2
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 24 deletions.
8 changes: 7 additions & 1 deletion include/devices/mid_clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
#define HAS_OUTPUT_WS0010
#define HAS_TEMP_SENSOR
#define HAS_KEYPAD
#define HAS_SERIAL_MIDI
#define HAS_VARYING_BRIGHTNESS
#define HAS_LIGHT_SENSOR
#define HAS_MOTION_SENSOR

// Plasma Information System OS (not DOS, there's no disk in it!)
#define PRODUCT_NAME "uPIS-OS"
Expand Down Expand Up @@ -38,6 +40,10 @@ const gpio_num_t HWCONF_WS0010_DATABUS_GPIOS[] = {
const gpio_num_t HWCONF_WS0010_RS_GPIO = GPIO_NUM_19;
const gpio_num_t HWCONF_WS0010_EN_GPIO = GPIO_NUM_18;

// ---- Connection to light sensors ----
const gpio_num_t HWCONF_MOTION_GPIO = GPIO_NUM_39;
const gpio_num_t HWCONF_LIGHTSENSE_GPIO = GPIO_NUM_36;

#define HWCONF_DISPLAY_WIDTH_PX 100
#define HWCONF_DISPLAY_HEIGHT_PX 16

Expand Down
7 changes: 5 additions & 2 deletions include/display/ws0010.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,17 @@ class Ws0010OledDriver: public DisplayDriver {
gpio_num_t rs_gpio;
gpio_num_t en_gpio;
bool is_writing_ddram;
bool show_state;
bool is_dim = false;
uint8_t ddram_ptr;

inline void set_databus(uint8_t data);
inline void set_is_command(bool);
inline void pulse_clock();
void write_string(const char *);
void write_stride(uint8_t stride);

bool show_state;
bool bright_state;
bool power_state;
void _set_pmu_internal();
};
#endif
61 changes: 40 additions & 21 deletions src/display/ws0010.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <esp32-hal-gpio.h>
#include <esp_err.h>

#define WS0010_NO_BFI

#ifndef WS0010_BFI_DIMMER_DURATION_US
#define WS0010_BFI_DIMMER_DURATION_US 6600 //<- experimentally found value for roughly 50% brightness @ 5v supply
#endif
Expand All @@ -24,7 +26,9 @@ Ws0010OledDriver::Ws0010OledDriver(
rs_gpio = rs;
en_gpio = en;
is_writing_ddram = false;
is_dim = false;
show_state = false;
bright_state = false;
power_state = false;
ddram_ptr = 0;
}

Expand Down Expand Up @@ -117,29 +121,20 @@ void Ws0010OledDriver::reset() {
delayMicroseconds(400);
delay(200);

write_string("uPIS-OS init");
write_string("uPIS-OS WS0010 init");
delay(500);

taskEXIT_CRITICAL(&_spinlock);
}

void Ws0010OledDriver::set_show(bool show) {
taskENTER_CRITICAL(&_spinlock);
show_state = show;
set_is_command(true);
set_databus(0b00001000 | (show ? 0b111 : 0)); // cursor and blink always off
pulse_clock();
delayMicroseconds(5);
taskEXIT_CRITICAL(&_spinlock);
_set_pmu_internal();
}

void Ws0010OledDriver::set_power(bool power) {
taskENTER_CRITICAL(&_spinlock);
set_is_command(true);
set_databus(0b00011000 | (power ? 0b111 : 0b011)); // G/C always set to GRAPHIC
pulse_clock();
delayMicroseconds(400);
taskEXIT_CRITICAL(&_spinlock);
power_state = power;
_set_pmu_internal();
}

void Ws0010OledDriver::clear() {
Expand Down Expand Up @@ -168,8 +163,11 @@ void Ws0010OledDriver::write_stride(uint8_t stride) {
void Ws0010OledDriver::write_fanta(const uint8_t * strides, size_t count) {
taskENTER_CRITICAL(&_spinlock);
#ifndef WS0010_NO_BFI
bool show_backup = show_state;
set_show(false);
if(power_state && show_state) {
set_is_command(true);
set_databus(0b00001000 | 0b000); // cursor and blink always off
pulse_clock();
}
#endif
// First write even (top row), then odd (bottom row)
for(int i = 0; i < count - 1; i += 2) {
Expand All @@ -181,17 +179,38 @@ void Ws0010OledDriver::write_fanta(const uint8_t * strides, size_t count) {
write_stride(strides[i]);
}
#ifndef WS0010_NO_BFI
if(is_dim) {
delayMicroseconds(WS0010_BFI_DIMMER_DURATION_US);
if(power_state && show_state) {
set_is_command(true);
set_databus(0b00001000 | 0b111); // cursor and blink always off
pulse_clock();
}
set_show(show_backup);
#endif
taskEXIT_CRITICAL(&_spinlock);
}

void Ws0010OledDriver::set_bright(bool bright) {
ESP_LOGI(LOG_TAG, "BFI dimming is now %s", bright ? "OFF":"ON");
is_dim = !bright;
bright_state = bright;
_set_pmu_internal();
}

// The power management of the WS0010 running at 5V is somewhat wacky, so the set_bright and set_show and set_power commands don't really match up with
// the real stuff that the controller does
void Ws0010OledDriver::_set_pmu_internal() {
taskENTER_CRITICAL(&_spinlock);
bool actual_bright = bright_state;
bool actual_show = (show_state && power_state);

set_is_command(true);
set_databus(0b00011000 | (actual_bright ? 0b111 : 0b011)); // G/C always set to GRAPHIC
pulse_clock();
delayMicroseconds(10);

set_is_command(true);
set_databus(0b00001000 | (actual_show ? 0b111 : 0b000)); // cursor and blink always off
pulse_clock();
delayMicroseconds(5);

taskEXIT_CRITICAL(&_spinlock);
}

#endif

0 comments on commit fdc28c2

Please sign in to comment.