8000 Merge pull request #1925 from C47D/rgb_status · losingrose/circuitpython@6fad383 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6fad383

Browse files
authored
Merge pull request adafruit#1925 from C47D/rgb_status
Initial support for RGB led as Status indicator, fixes adafruit#1382
2 parents f0cf9a4 + 40fbac1 commit 6fad383

File tree

3 files changed

+150
-36
lines changed

3 files changed

+150
-36
lines changed

ports/nrf/boards/particle_xenon/mpconfigboard.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@
3535

3636
#define MICROPY_HW_LED_STATUS (&pin_P1_12)
3737

38-
#define MICROPY_HW_RGB_LED_RED (&pin_P0_13)
39-
#define MICROPY_HW_RGB_LED_GREEN (&pin_P0_14)
40-
#define MICROPY_HW_RGB_LED_BLUE (&pin_P0_15)
38+
#define CP_RGB_STATUS_R (&pin_P0_13)
39+
#define CP_RGB_STATUS_G (&pin_P0_14)
40+
#define CP_RGB_STATUS_B (&pin_P0_15)
4141

4242
#if QSPI_FLASH_FILESYSTEM
4343
#define MICROPY_QSPI_DATA0 NRF_GPIO_PIN_MAP(0, 20)

ports/nrf/common-hal/pulseio/PWMOut.c

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -77,33 +77,37 @@ void common_hal_pulseio_pwmout_reset_ok(pulseio_pwmout_obj_t *self) {
7777
}
7878
}
7979

80+
void reset_single_pwmout(uint8_t i) {
81+
NRF_PWM_Type* pwm = pwms[i];
82+
83+
pwm->ENABLE = 0;
84+
pwm->MODE = PWM_MODE_UPDOWN_Up;
85+
pwm->DECODER = PWM_DECODER_LOAD_Individual;
86+
pwm->LOOP = 0;
87+
pwm->PRESCALER = PWM_PRESCALER_PRESCALER_DIV_1; // default is 500 hz
88+
pwm->COUNTERTOP = (PWM_MAX_FREQ/500); // default is 500 hz
89+
90+
pwm->SEQ[0].PTR = (uint32_t) pwm_seq[i];
91+
pwm->SEQ[0].CNT = CHANNELS_PER_PWM; // default mode is Individual --> count must be 4
92+
pwm->SEQ[0].REFRESH = 0;
93+
pwm->SEQ[0].ENDDELAY = 0;
94+
95+
pwm->SEQ[1].PTR = 0;
96+
pwm->SEQ[1].CNT = 0;
97+
pwm->SEQ[1].REFRESH = 0;
98+
pwm->SEQ[1].ENDDELAY = 0;
99+
100+
for(int ch =0; ch < CHANNELS_PER_PWM; ch++) {
101+
pwm_seq[i][ch] = (1 << 15); // polarity = 0
102+
}
103+
}
104+
80105
void pwmout_reset(void) {
81106
for(size_t i=0; i < MP_ARRAY_SIZE(pwms); i++) {
82107
if (never_reset_pwm[i] > 0) {
83108
continue;
84109
}
85-
NRF_PWM_Type* pwm = pwms[i];
86-
87-
pwm->ENABLE = 0;
88-
pwm->MODE = PWM_MODE_UPDOWN_Up;
89-
pwm->DECODER = PWM_DECODER_LOAD_Individual;
90-
pwm->LOOP = 0;
91-
pwm->PRESCALER = PWM_PRESCALER_PRESCALER_DIV_1; // default is 500 hz
92-
pwm->COUNTERTOP = (PWM_MAX_FREQ/500); // default is 500 hz
93-
94-
pwm->SEQ[0].PTR = (uint32_t) pwm_seq[i];
95-
pwm->SEQ[0].CNT = CHANNELS_PER_PWM; // default mode is Individual --> count must be 4
96-
pwm->SEQ[0].REFRESH = 0;
97-
pwm->SEQ[0].ENDDELAY = 0;
98-
99-
pwm->SEQ[1].PTR = 0;
100-
pwm->SEQ[1].CNT = 0;
101-
pwm->SEQ[1].REFRESH = 0;
102-
pwm->SEQ[1].ENDDELAY = 0;
103-
104-
for(int ch =0; ch < CHANNELS_PER_PWM; ch++) {
105-
pwm_seq[i][ch] = (1 << 15); // polarity = 0
106-
}
110+
reset_single_pwmout(i);
107111
}
108112
}
109113

@@ -148,9 +152,9 @@ pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
148152
self->channel = CHANNELS_PER_PWM; // out-of-range value.
149153
bool pwm_already_in_use;
150154
NRF_PWM_Type* pwm;
151-
152-
for (size_t i = 0 ; i < MP_ARRAY_SIZE(pwms); i++) {
153-
pwm = pwms[i];
155+
size_t pwm_index = 0;
156+
for (; pwm_index < MP_ARRAY_SIZE(pwms); pwm_index++) {
157+
pwm = pwms[pwm_index];
154158
pwm_already_in_use = pwm->ENABLE & SPIM_ENABLE_ENABLE_Msk;
155159
if (pwm_already_in_use) {
156160
if (variable_frequency) {
@@ -199,6 +203,7 @@ pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
199203
nrf_pwm_disable(pwm);
200204

201205
if (!pwm_already_in_use) {
206+
reset_single_pwmout(pwm_index);
202207
nrf_pwm_configure(pwm, base_clock, NRF_PWM_MODE_UP, countertop);
203208
}
204209

supervisor/shared/rgb_led_status.c

Lines changed: 117 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,28 @@ busio_spi_obj_t status_apa102;
5050
#endif
5151
#endif
5252

53-
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK))
53+
#if defined(CP_RGB_STATUS_R) || defined(CP_RGB_STATUS_G) || defined(CP_RGB_STATUS_B)
54+
#define CP_RGB_STATUS_LED
55+
56+
#include "shared-bindings/pulseio/PWMOut.h"
57+
#include "shared-bindings/microcontroller/Pin.h"
58+
59+
pulseio_pwmout_obj_t rgb_status_r;
60+
pulseio_pwmout_obj_t rgb_status_g;
61+
pulseio_pwmout_obj_t rgb_status_b;
62+
63+
uint8_t rgb_status_brightness = 0xFF;
64+
65+
uint16_t status_rgb_color[3] = {
66+
0 /* red */, 0 /* green */, 0 /* blue */
67+
};
68+
#endif
69+
70+
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED))
5471
static uint32_t current_status_color = 0;
5572
#endif
5673

74+
5775
void rgb_led_status_init() {
5876
#ifdef MICROPY_HW_NEOPIXEL
5977
common_hal_digitalio_digitalinout_construct(&status_neopixel, MICROPY_HW_NEOPIXEL);
@@ -93,7 +111,34 @@ void rgb_led_status_init() {
93111
#endif
94112
#endif
95113

96-
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK))
114+
115+
#if defined(CP_RGB_STATUS_LED)
116+
if (common_hal_mcu_pin_is_free(CP_RGB_STATUS_R)) {
117+
pwmout_result_t red_result = common_hal_pulseio_pwmout_construct(&rgb_status_r, CP_RGB_STATUS_R, 0, 50000, false);
118+
119+
if (PWMOUT_OK == red_result) {
120+
common_hal_pulseio_pwmout_never_reset(&rgb_status_r);
121+
}
122+
}
123+
124+
if (common_hal_mcu_pin_is_free(CP_RGB_STATUS_G)) {
125+
pwmout_result_t green_result = common_hal_pulseio_pwmout_construct(&rgb_status_g, CP_RGB_STATUS_G, 0, 50000, false);
126+
127+
if (PWMOUT_OK == green_result) {
128+
common_hal_pulseio_pwmout_never_reset(&rgb_status_g);
129+
}
130+
}
131+
132+
if (common_hal_mcu_pin_is_free(CP_RGB_STATUS_B)) {
133+
pwmout_result_t blue_result = common_hal_pulseio_pwmout_construct(&rgb_status_b, CP_RGB_STATUS_B, 0, 50000, false);
134+
135+
if (PWMOUT_OK == blue_result) {
136+
common_hal_pulseio_pwmout_never_reset(&rgb_status_b);
137+
}
138+
}
139+
#endif
140+
141+
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED))
97142
// Force a write of the current status color.
98143
uint32_t rgb = current_status_color;
99144
current_status_color = 0x1000000; // Not a valid color
@@ -109,10 +154,13 @@ void reset_status_led() {
109154
reset_pin_number(MICROPY_HW_APA102_MOSI->number);
110155
reset_pin_number(MICROPY_HW_APA102_SCK->number);
111156
#endif
157+
#if defined(CP_RGB_STATUS_LED)
158+
// TODO: Support sharing status LED with user.
159+
#endif
112160
}
113161

114162
void new_status_color(uint32_t rgb) {
115-
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK))
163+
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED))
116164
if (current_status_color == rgb) {
117165
return;
118166
}
@@ -143,10 +191,30 @@ void new_status_color(uint32_t rgb) {
143191
common_hal_busio_spi_write(&status_apa102, status_apa102_color, 8);
144192
#endif
145193
#endif
194+
195+
#if defined(CP_RGB_STATUS_LED)
196+
uint8_t red_u8 = (rgb_adjusted >> 16) & 0xFF;
197+
uint8_t green_u8 = (rgb_adjusted >> 8) & 0xFF;
198+
uint8_t blue_u8 = rgb_adjusted & 0xFF;
199+
200+
#if defined(CP_RGB_STATUS_INVERTED_PWM)
201+
status_rgb_color[0] = (1 << 16) - 1 - ((uint16_t) (red_u8 << 8) + red_u8);
202+
status_rgb_color[1] = (1 << 16) - 1 - ((uint16_t) (green_u8 << 8) + green_u8);
203+
status_rgb_color[2] = (1 << 16) - 1 - ((uint16_t) (blue_u8 << 8) + blue_u8);
204+
#else
205+
status_rgb_color[0] = (uint16_t) (red_u8 << 8) + red_u8;
206+
status_rgb_color[1] = (uint16_t) (green_u8 << 8) + green_u8;
207+
status_rgb_color[2] = (uint16_t) (blue_u8 << 8) + blue_u8;
208+
#endif
209+
210+
common_hal_pulseio_pwmout_set_duty_cycle(&rgb_status_r, status_rgb_color[0]);
211+
common_hal_pulseio_pwmout_set_duty_cycle(&rgb_status_g, status_rgb_color[1]);
212+
common_hal_pulseio_pwmout_set_duty_cycle(&rgb_status_b, status_rgb_color[2]);
213+
#endif
146214
}
147215

148216
void temp_status_color(uint32_t rgb) {
149-
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK))
217+
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED))
150218
uint32_t rgb_adjusted = rgb;
151219
rgb_adjusted = color_brightness(rgb, rgb_status_brightness);
152220
#endif
@@ -168,6 +236,27 @@ void temp_status_color(uint32_t rgb) {
168236
common_hal_busio_spi_write(&status_apa102, colors, 12);
169237
#endif
170238
#endif
239+
#if defined(CP_RGB_STATUS_LED)
240+
uint8_t red_u8 = (rgb_adjusted >> 16) & 0xFF;
241+
uint8_t green_u8 = (rgb_adjusted >> 8) & 0xFF;
242+
uint8_t blue_u8 = rgb_adjusted & 0xFF;
243+
244+
uint16_t temp_status_color_rgb[3] = {0};
245+
246+
#if defined(CP_RGB_STATUS_INVERTED_PWM)
247+
temp_status_color_rgb[0] = (1 << 16) - 1 - ((uint16_t) (red_u8 << 8) + red_u8);
248+
temp_status_color_rgb[1] = (1 << 16) - 1 - ((uint16_t) (green_u8 << 8) + green_u8);
249+
temp_status_color_rgb[2] = (1 << 16) - 1 - ((uint16_t) (blue_u8 << 8) + blue_u8);
250+
#else
251+
temp_status_color_rgb[0] = (uint16_t) (red_u8 << 8) + red_u8;
252+
temp_status_color_rgb[1] = (uint16_t) (green_u8 << 8) + green_u8;
253+
temp_status_color_rgb[2] = (uint16_t) (blue_u8 << 8) + blue_u8;
254+
#endif
255+
256+
common_hal_pulseio_pwmout_set_duty_cycle(&rgb_status_r, temp_status_color_rgb[0]);
257+
common_hal_pulseio_pwmout_set_duty_cycle(&rgb_status_g, temp_status_color_rgb[1]);
258+
common_hal_pulseio_pwmout_set_duty_cycle(&rgb_status_b, temp_status_color_rgb[2]);
259+
#endif
171260
}
172261

173262
void clear_temp_status() {
@@ -181,10 +270,30 @@ void clear_temp_status() {
181270
common_hal_busio_spi_write(&status_apa102, status_apa102_color, 8);
182271
#endif
183272
#endif
273+
#if defined(CP_RGB_STATUS_LED)
274+
275+
uint16_t red = 0;
276+
uint16_t green = 0;
277+
uint16_t blue = 0;
278+
279+
#if defined(CP_RGB_STATUS_INVERTED_PWM)
280+
red = (1 << 16) - 1 - status_rgb_color[0];
281+
green = (1 << 16) - 1 - status_rgb_color[1];
282+
blue = (1 << 16) - 1 - status_rgb_color[2];
283+
#else
284+
red = status_rgb_color[0];
285+
green = status_rgb_color[1];
286+
blue = status_rgb_color[2];
287+
#endif
288+
289+
common_hal_pulseio_pwmout_set_duty_cycle(&rgb_status_r, red);
290+
common_hal_pulseio_pwmout_set_duty_cycle(&rgb_status_g, green);
291+
common_hal_pulseio_pwmout_set_duty_cycle(&rgb_status_b, blue);
292+
#endif
184293
}
185294

186295
uint32_t color_brightness(uint32_t color, uint8_t brightness) {
187-
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK))
296+
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED))
188297
uint32_t result = ((color & 0xff0000) * brightness / 255) & 0xff0000;
189298
result += ((color & 0xff00) * brightness / 255) & 0xff00;
190299
result += ((color & 0xff) * brightness / 255) & 0xff;
@@ -195,7 +304,7 @@ uint32_t color_brightness(uint32_t color, uint8_t brightness) {
195304
}
196305

197306
void set_rgb_status_brightness(uint8_t level){
198-
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK))
307+
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED))
199308
rgb_status_brightness = level;
200309
uint32_t current_color = current_status_color;
201310
// Temporarily change the current color global to force the new_status_color call to update the
@@ -210,7 +319,7 @@ void prep_rgb_status_animation(const pyexec_result_t* result,
210319
bool found_main,
211320
safe_mode_t safe_mode,
212321
rgb_status_animation_t* status) {
213-
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK))
322+
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED))
214323
new_status_color(ALL_DONE);
215324
status->pattern_start = ticks_ms;
216325
status->safe_mode = safe_mode;
@@ -256,7 +365,7 @@ void prep_rgb_status_animation(const pyexec_result_t* result,
256365
}
257366

258367
void tick_rgb_status_animation(rgb_status_animation_t* status) {
259-
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK))
368+
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED))
260369
uint32_t tick_diff = ticks_ms - status->pattern_start;
261370
if (status->ok) {
262371
// All is good. Ramp ALL_DONE up and down.

0 commit comments

Comments
 (0)
0