Skip to content

Commit 69bc5e1

Browse files
committed
Rudamentary backlight support
1 parent 1a1dbef commit 69bc5e1

9 files changed

Lines changed: 122 additions & 18 deletions

File tree

ports/atmel-samd/boards/pyportal/board.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ void board_init(void) {
8787
MIPI_COMMAND_SET_PAGE_ADDRESS, // Set row command
8888
MIPI_COMMAND_WRITE_MEMORY_START, // Write memory command
8989
display_init_sequence,
90-
sizeof(display_init_sequence));
90+
sizeof(display_init_sequence),
91+
&pin_PB31);
9192
}
9293

9394
bool board_requests_safe_mode(void) {

ports/atmel-samd/common-hal/pulseio/PWMOut.c

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,26 @@ uint8_t tcc_channels[3]; // Set by pwmout_reset() to {0xf0, 0xfc, 0xfc} initia
5858
uint8_t tcc_channels[5]; // Set by pwmout_reset() to {0xc0, 0xf0, 0xf8, 0xfc, 0xfc} initially.
5959
#endif
6060

61+
static uint8_t never_reset_tc_or_tcc[TC_INST_NUM + TCC_INST_NUM];
62+
63+
void common_hal_pulseio_pwmout_never_reset(pulseio_pwmout_obj_t *self) {
64+
if (self->timer->is_tc) {
65+
never_reset_tc_or_tcc[self->timer->index] += 1;
66+
} else {
67+
never_reset_tc_or_tcc[TC_INST_NUM + self->timer->index] += 1;
68+
}
69+
70+
never_reset_pin_number(self->pin->number);
71+
}
72+
73+
void common_hal_pulseio_pwmout_reset_ok(pulseio_pwmout_obj_t *self) {
74+
if (self->timer->is_tc) {
75+
never_reset_tc_or_tcc[self->timer->index] -= 1;
76+
} else {
77+
never_reset_tc_or_tcc[TC_INST_NUM + self->timer->index] -= 1;
78+
}
79+
}
80+
6181
void pwmout_reset(void) {
6282
// Reset all timers
6383
for (int i = 0; i < TCC_INST_NUM; i++) {
@@ -66,6 +86,9 @@ void pwmout_reset(void) {
6686
}
6787
Tcc *tccs[TCC_INST_NUM] = TCC_INSTS;
6888
for (int i = 0; i < TCC_INST_NUM; i++) {
89+
if (never_reset_tc_or_tcc[TC_INST_NUM + i] > 0) {
90+
continue;
91+
}
6992
// Disable the module before resetting it.
7093
if (tccs[i]->CTRLA.bit.ENABLE == 1) {
7194
tccs[i]->CTRLA.bit.ENABLE = 0;
@@ -81,6 +104,9 @@ void pwmout_reset(void) {
81104
}
82105
Tc *tcs[TC_INST_NUM] = TC_INSTS;
83106
for (int i = 0; i < TC_INST_NUM; i++) {
107+
if (never_reset_tc_or_tcc[i] > 0) {
108+
continue;
109+
}
84110
tcs[i]->COUNT16.CTRLA.bit.SWRST = 1;
85111
while (tcs[i]->COUNT16.CTRLA.bit.SWRST == 1) {
86112
}
@@ -99,11 +125,11 @@ bool channel_ok(const pin_timer_t* t) {
99125
t->is_tc;
100126
}
101127

102-
void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
103-
const mcu_pin_obj_t* pin,
104-
uint16_t duty,
105-
uint32_t frequency,
106-
bool variable_frequency) {
128+
pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
129+
const mcu_pin_obj_t* pin,
130+
uint16_t duty,
131+
uint32_t frequency,
132+
bool variable_frequency) {
107133
self->pin = pin;
108134
self->variable_frequency = variable_frequency;
109135

@@ -113,11 +139,11 @@ void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
113139
&& pin->timer[2].index >= TCC_INST_NUM
114140
#endif
115141
) {
116-
mp_raise_ValueError(translate("Invalid pin"));
142+
return PWMOUT_INVALID_PIN;
117143
}
118144

119145
if (frequency == 0 || frequency > 6000000) {
120-
mp_raise_ValueError(translate("Invalid PWM frequency"));
146+
return PWMOUT_INVALID_FREQUENCY;
121147
}
122148

123149
// Figure out which timer we are using.
@@ -184,11 +210,9 @@ void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
184210

185211
if (timer == NULL) {
186212
if (found) {
187-
mp_raise_ValueError(translate("All timers for this pin are in use"));
188-
} else {
189-
mp_raise_RuntimeError(translate("All timers in use"));
213+
return PWMOUT_ALL_TIMERS_ON_PIN_IN_USE;
190214
}
191-
return;
215+
return PWMOUT_ALL_TIMERS_IN_USE;
192216
}
193217

194218
uint8_t resolution = 0;
@@ -259,6 +283,7 @@ void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
259283
gpio_set_pin_function(pin->number, GPIO_PIN_FUNCTION_E + mux_position);
260284

261285
common_hal_pulseio_pwmout_set_duty_cycle(self, duty);
286+
return PWMOUT_OK;
262287
}
263288

264289
bool common_hal_pulseio_pwmout_deinited(pulseio_pwmout_obj_t* self) {

shared-bindings/displayio/Display.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,11 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a
119119
mp_raise_RuntimeError(translate("Too many displays"));
120120
}
121121
self->base.type = &displayio_display_type;
122+
// TODO(tannewt): Support backlight pin.
122123
common_hal_displayio_display_construct(self,
123124
display_bus, args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_colstart].u_int, args[ARG_rowstart].u_int,
124125
args[ARG_color_depth].u_int, args[ARG_set_column_command].u_int, args[ARG_set_row_command].u_int,
125-
args[ARG_write_ram_command].u_int, bufinfo.buf, bufinfo.len);
126+
args[ARG_write_ram_command].u_int, bufinfo.buf, bufinfo.len, NULL);
126127

127128
return self;
128129
}

shared-bindings/displayio/Display.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self,
4040
mp_obj_t bus, uint16_t width, uint16_t height,
4141
int16_t colstart, int16_t rowstart, uint16_t color_depth,
4242
uint8_t set_column_command, uint8_t set_row_command, uint8_t write_ram_command,
43-
uint8_t* init_sequence, uint16_t init_sequence_len);
43+
uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin);
4444

4545
int32_t common_hal_displayio_display_wait_for_frame(displayio_display_obj_t* self);
4646

shared-bindings/pulseio/PWMOut.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,16 @@ STATIC mp_obj_t pulseio_pwmout_make_new(const mp_obj_type_t *type, size_t n_args
108108
// create PWM object from the given pin
109109
pulseio_pwmout_obj_t *self = m_new_obj(pulseio_pwmout_obj_t);
110110
self->base.type = &pulseio_pwmout_type;
111-
common_hal_pulseio_pwmout_construct(self, pin, duty_cycle, frequency, variable_frequency);
111+
pwmout_result_t result = common_hal_pulseio_pwmout_construct(self, pin, duty_cycle, frequency, variable_frequency);
112+
if (result == PWMOUT_INVALID_PIN) {
113+
mp_raise_ValueError(translate("Invalid pin"));
114+
} else if (result == PWMOUT_INVALID_FREQUENCY) {
115+
mp_raise_ValueError(translate("Invalid PWM frequency"));
116+
} else if (result == PWMOUT_ALL_TIMERS_ON_PIN_IN_USE) {
117+
mp_raise_ValueError(translate("All timers for this pin are in use"));
118+
} else if (result == PWMOUT_ALL_TIMERS_IN_USE) {
119+
mp_raise_RuntimeError(translate("All timers in use"));
120+
}
112121

113122
return MP_OBJ_FROM_PTR(self);
114123
}

shared-bindings/pulseio/PWMOut.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,15 @@
3232

3333
extern const mp_obj_type_t pulseio_pwmout_type;
3434

35-
extern void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
35+
typedef enum {
36+
PWMOUT_OK,
37+
PWMOUT_INVALID_PIN,
38+
PWMOUT_INVALID_FREQUENCY,
39+
PWMOUT_ALL_TIMERS_ON_PIN_IN_USE,
40+
PWMOUT_ALL_TIMERS_IN_USE
41+
} pwmout_result_t;
42+
43+
extern pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
3644
const mcu_pin_obj_t* pin, uint16_t duty, uint32_t frequency,
3745
bool variable_frequency);
3846
extern void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self);
@@ -43,4 +51,8 @@ extern void common_hal_pulseio_pwmout_set_frequency(pulseio_pwmout_obj_t* self,
4351
extern uint32_t common_hal_pulseio_pwmout_get_frequency(pulseio_pwmout_obj_t* self);
4452
extern bool common_hal_pulseio_pwmout_get_variable_frequency(pulseio_pwmout_obj_t* self);
4553

54+
// This is used by the supervisor to claim PWMOut devices indefinitely.
55+
extern void common_hal_pulseio_pwmout_never_reset(pulseio_pwmout_obj_t *self);
56+
extern void common_hal_pulseio_pwmout_reset_ok(pulseio_pwmout_obj_t *self);
57+
4658
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_PULSEIO_PWMOUT_H

shared-module/displayio/Display.c

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "py/runtime.h"
3030
#include "shared-bindings/displayio/FourWire.h"
3131
#include "shared-bindings/displayio/ParallelBus.h"
32+
#include "shared-bindings/microcontroller/Pin.h"
3233
#include "shared-bindings/time/__init__.h"
3334
#include "shared-module/displayio/__init__.h"
3435
#include "supervisor/shared/display.h"
@@ -42,7 +43,8 @@
4243
void common_hal_displayio_display_construct(displayio_display_obj_t* self,
4344
mp_obj_t bus, uint16_t width, uint16_t height, int16_t colstart, int16_t rowstart,
4445
uint16_t color_depth, uint8_t set_column_command, uint8_t set_row_command,
45-
uint8_t write_ram_command, uint8_t* init_sequence, uint16_t init_sequence_len) {
46+
uint8_t write_ram_command, uint8_t* init_sequence, uint16_t init_sequence_len,
47+
const mcu_pin_obj_t* backlight_pin) {
4648
self->width = width;
4749
self->height = height;
4850
self->color_depth = color_depth;
@@ -96,6 +98,19 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self,
9698
// initialization.
9799
self->refresh = true;
98100
self->current_group = &circuitpython_splash;
101+
102+
if (backlight_pin != NULL && common_hal_mcu_pin_is_free(backlight_pin)) {
103+
pwmout_result_t result = common_hal_pulseio_pwmout_construct(&self->backlight_pwm, backlight_pin, 0, 5000, false);
104+
if (result != PWMOUT_OK) {
105+
self->backlight_inout.base.type = &digitalio_digitalinout_type;
106+
common_hal_digitalio_digitalinout_construct(&self->backlight_inout, backlight_pin);
107+
never_reset_pin_number(backlight_pin->number);
108+
} else {
109+
self->backlight_pwm.base.type = &pulseio_pwmout_type;
110+
common_hal_pulseio_pwmout_never_reset(&self->backlight_pwm);
111+
}
112+
}
113+
self->auto_brightness = true;
99114
}
100115

101116
void common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group) {
@@ -158,3 +173,29 @@ bool displayio_display_send_pixels(displayio_display_obj_t* self, uint32_t* pixe
158173
self->send(self->bus, false, (uint8_t*) pixels, length * 4);
159174
return true;
160175
}
176+
177+
void displayio_display_update_backlight(displayio_display_obj_t* self) {
178+
if (!self->auto_brightness || self->updating_backlight) {
179+
return;
180+
}
181+
if (ticks_ms - self->last_backlight_refresh < 100) {
182+
return;
183+
}
184+
self->updating_backlight = true;
185+
if (self->backlight_pwm.base.type == &pulseio_pwmout_type) {
186+
common_hal_pulseio_pwmout_set_duty_cycle(&self->backlight_pwm, 0xffff);
187+
} else if (self->backlight_inout.base.type == &digitalio_digitalinout_type) {
188+
common_hal_digitalio_digitalinout_set_value(&self->backlight_inout, true);
189+
}
190+
self->updating_backlight = false;
191+
self->last_backlight_refresh = ticks_ms;
192+
}
193+
194+
void release_display(displayio_display_obj_t* self) {
195+
if (self->backlight_pwm.base.type == &pulseio_pwmout_type) {
196+
common_hal_pulseio_pwmout_reset_ok(&self->backlight_pwm);
197+
common_hal_pulseio_pwmout_deinit(&self->backlight_pwm);
198+
} else if (self->backlight_inout.base.type == &digitalio_digitalinout_type) {
199+
common_hal_digitalio_digitalinout_deinit(&self->backlight_inout);
200+
}
201+
}

shared-module/displayio/Display.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
#ifndef MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_DISPLAY_H
2828
#define MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_DISPLAY_H
2929

30-
#include "shared-module/displayio/Group.h"
30+
#include "shared-bindings/digitalio/DigitalInOut.h"
31+
#include "shared-bindings/displayio/Group.h"
32+
#include "shared-bindings/pulseio/PWMOut.h"
3133

3234
typedef bool (*display_bus_begin_transaction)(mp_obj_t bus);
3335
typedef void (*display_bus_send)(mp_obj_t bus, bool command, uint8_t *data, uint32_t data_length);
@@ -50,6 +52,16 @@ typedef struct {
5052
display_bus_begin_transaction begin_transaction;
5153
display_bus_send send;
5254
display_bus_end_transaction end_transaction;
55+
union {
56+
digitalio_digitalinout_obj_t backlight_inout;
57+
pulseio_pwmout_obj_t backlight_pwm;
58+
};
59+
uint64_t last_backlight_refresh;
60+
bool auto_brightness:1;
61+
bool updating_backlight:1;
5362
} displayio_display_obj_t;
5463

64+
void displayio_display_update_backlight(displayio_display_obj_t* self);
65+
void release_display(displayio_display_obj_t* self);
66+
5567
#endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_DISPLAY_H

shared-module/displayio/__init__.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ void displayio_refresh_displays(void) {
2020
continue;
2121
}
2222
displayio_display_obj_t* display = &displays[i].display;
23+
displayio_display_update_backlight(display);
2324

2425
if (!displayio_display_frame_queued(display)) {
2526
return;
@@ -82,6 +83,7 @@ void common_hal_displayio_release_displays(void) {
8283
displays[i].fourwire_bus.base.type = &mp_type_NoneType;
8384
}
8485
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
86+
release_display(&displays[i].display);
8587
displays[i].display.base.type = &mp_type_NoneType;
8688
}
8789

@@ -117,6 +119,7 @@ void reset_displays(void) {
117119
continue;
118120
}
119121
displayio_display_obj_t* display = &displays[i].display;
122+
display->auto_brightness = true;
120123
common_hal_displayio_display_show(display, &circuitpython_splash);
121124
}
122125
}

0 commit comments

Comments
 (0)