Add Bangle.js 2, JDI memory displays and ACeP epd

This 2-in-1 PR started with the goal of support the Bangle.js 2
smartwatch with *no USB*.
* Adds "secure" DFU build support with a committed private key.
* Adds 3-bit color support with one dummy bit for the JDI memory display
* Allows nrf boards to have a board_background_task() run in RUN_BACKGROUND_TASK.
  This is needed because the Bangle.js 2 uses the watchdog to reset.
* Renamed port_background_task() to port_background_tick() to indicate it
  runs on tick, not RUN_BACKGROUND_TASK.
* Marks serial connected when the display terminal is inited. This means
  that safe mode messages show up on the display.

ACep, 7-color epaper displays also pack 3 bits in 4. So, I added that
support as well.
* Adds 3-bit ACeP color support for 7-color e-paper displays. (Not
  watch related but similar due to color depth.)
* Allows a refresh sequence instead of a single int command. The 7" ACeP
  display requires a data byte for refresh.
* Adds optional delay after resetting the display. The ACeP displays
  need this. (Probably to load LUTs from flash.)
* Adds a cleaning phase for ACeP displays before the real refresh.

For both:
* Add dither support to Palette.
* Palette no longer converts colors when set. Instead, it caches
  converted colors at each index.
* ColorConverter now caches the last converted color. It should make
  conversions faster for repeated colors (not dithering.)
This commit is contained in:
Scott Shawcroft 2022-07-29 22:09:49 -07:00
parent ca24cff0d3
commit 931c7c1c51
No known key found for this signature in database
GPG Key ID: 0DFD512649C052DA
53 changed files with 752 additions and 194 deletions

View File

@ -37,7 +37,7 @@ runs:
# arm
- name: Get arm toolchain
if: inputs.platform == 'aarch' || inputs.platform == 'arm'
if: inputs.platform == 'aarch' || inputs.platform == 'arm' || inputs.platform == 'nrf'
uses: carlosperate/arm-none-eabi-gcc-action@v1
with:
release: '10-2020-q4'
@ -65,6 +65,22 @@ runs:
echo >> $GITHUB_PATH "$PATH"
shell: bash
# nrf
- name: Get nrfutil 7+
if: inputs.platform == 'nrf'
run: |
wget https://developer.nordicsemi.com/.pc-tools/nrfutil/x64-linux/nrfutil
chmod +x nrfutil
./nrfutil install nrf5sdk-tools
mkdir -p $HOME/.local/bin
mv nrfutil $HOME/.local/bin
echo "$HOME/.local/bin" >> $GITHUB_PATH
shell: bash
- name: Print nrfutil version
if: inputs.platform == 'nrf'
run: nrfutil -V
shell: bash
# riscv
- name: Get riscv toolchain
if: inputs.platform == 'riscv'

View File

@ -25,6 +25,7 @@ jobs:
boards-aarch: ${{ steps.set-matrix.outputs.boards-aarch }}
boards-arm: ${{ steps.set-matrix.outputs.boards-arm }}
boards-esp: ${{ steps.set-matrix.outputs.boards-esp }}
boards-nrf: ${{ steps.set-matrix.outputs.boards-nrf }}
boards-riscv: ${{ steps.set-matrix.outputs.boards-riscv }}
boards-rpi: ${{ steps.set-matrix.outputs.boards-rpi }}
cp-version: ${{ steps.set-up-submodules.outputs.version }}
@ -252,6 +253,16 @@ jobs:
boards: ${{ needs.scheduler.outputs.boards-esp }}
cp-version: ${{ needs.scheduler.outputs.cp-version }}
nrf:
needs: [scheduler, mpy-cross, tests]
if: ${{ needs.scheduler.outputs.boards-nrf != '[]' }}
uses: ./.github/workflows/build-boards.yml
secrets: inherit
with:
platform: nrf
boards: ${{ needs.scheduler.outputs.boards-nrf }}
cp-version: ${{ needs.scheduler.outputs.cp-version }}
riscv:
needs: [scheduler, mpy-cross, tests]
if: ${{ needs.scheduler.outputs.boards-riscv != '[]' }}

@ -1 +1 @@
Subproject commit 2d292ad4e67890d4b85b027431ba9fef7bf561fd
Subproject commit 73fafcbe4c66b23df63be31e9227353b695abb08

View File

@ -202,10 +202,6 @@ msgstr ""
msgid "%q out of range"
msgstr ""
#: ports/atmel-samd/common-hal/microcontroller/Pin.c
msgid "%q pin invalid"
msgstr ""
#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c
msgid "%q step cannot be zero"
msgstr ""
@ -1210,9 +1206,11 @@ msgid "Internal watchdog timer expired."
msgstr ""
#: py/argcheck.c shared-bindings/digitalio/DigitalInOut.c
#: shared-bindings/displayio/EPaperDisplay.c
msgid "Invalid %q"
msgstr ""
#: ports/atmel-samd/common-hal/microcontroller/Pin.c
#: shared-bindings/microcontroller/Pin.c
msgid "Invalid %q pin"
msgstr ""

View File

@ -57,5 +57,8 @@ void port_finish_background_task(void) {
}
#endif
void port_background_tick(void) {
}
void port_background_task(void) {
}

View File

@ -52,6 +52,10 @@ uint8_t stop_sequence[] = {
0x02, 0x80, 0xf0 // Power off
};
uint8_t refresh_sequence[] = {
0x12, 0x00
};
void board_init(void) {
busio_spi_obj_t *spi = &displays[0].fourwire_bus.inline_bus;
common_hal_busio_spi_construct(spi, &pin_PB13, &pin_PB15, NULL, false);
@ -74,6 +78,7 @@ void board_init(void) {
bus,
start_sequence,
sizeof(start_sequence),
0, // start up time
stop_sequence,
sizeof(stop_sequence),
300, // width
@ -92,13 +97,15 @@ void board_init(void) {
NO_COMMAND, // write_color_ram_command (can add this for grayscale eventually)
false, // color_bits_inverted
0x000000, // highlight_color
0x12, // refresh_display_command
refresh_sequence, // refresh_display_sequence
sizeof(refresh_sequence),
40, // refresh_time
&pin_PA01, // busy_pin
false, // busy_state
5, // seconds_per_frame
false, // chip_select (don't always toggle chip select)
false, // grayscale
false, // acep
false); // two_byte_sequence_length
}

View File

@ -53,3 +53,10 @@ CIRCUITPY_DISPLAY_FONT = $(TOP)/ports/atmel-samd/boards/ugame10/brutalist-6.bdf
# Override optimization to keep binary small
OPTIMIZATION_FLAGS = -Os
# We don't have room for the fonts for terminalio for certain languages,
# so turn off terminalio and force a clean build.
ifneq (,$(filter $(TRANSLATION),ja ko ru))
CIRCUITPY_TERMINALIO = 0
RELEASE_NEEDS_CLEAN_BUILD = 1
endif

View File

@ -211,5 +211,5 @@ mcu_pin_function_t *mcu_find_pin_function(mcu_pin_function_t *table, const mcu_p
return table;
}
}
mp_raise_ValueError_varg(translate("%q pin invalid"), name);
mp_raise_ValueError_varg(translate("Invalid %q pin"), name);
}

View File

@ -33,5 +33,8 @@ void port_start_background_task(void) {
void port_finish_background_task(void) {
}
void port_background_tick(void) {
}
void port_background_task(void) {
}

View File

@ -30,6 +30,8 @@
#include "supervisor/filesystem.h"
#include "supervisor/shared/stack.h"
void port_background_tick(void) {
}
void port_background_task(void) {
}
void port_start_background_task(void) {

View File

@ -40,7 +40,7 @@
#include "common-hal/pulseio/PulseIn.h"
#endif
void port_background_task(void) {
void port_background_tick(void) {
// Zero delay in case FreeRTOS wants to switch to something else.
vTaskDelay(0);
#if CIRCUITPY_PULSEIO
@ -48,6 +48,9 @@ void port_background_task(void) {
#endif
}
void port_background_task(void) {
}
void port_start_background_task(void) {
}

View File

@ -109,6 +109,10 @@ const uint8_t display_stop_sequence[] = {
0x02, 0x00 // Power off
};
const uint8_t refresh_sequence[] = {
0x12, 0x00
};
void board_init(void) {
// Debug UART
#ifdef DEBUG
@ -137,6 +141,7 @@ void board_init(void) {
display,
bus,
display_start_sequence, sizeof(display_start_sequence),
0, // start up time
display_stop_sequence, sizeof(display_stop_sequence),
296, // width
128, // height
@ -154,13 +159,14 @@ void board_init(void) {
0x13, // write_color_ram_command
false, // color_bits_inverted
0x000000, // highlight_color
0x12, // refresh_display_command
refresh_sequence, sizeof(refresh_sequence),
1.0, // refresh_time
&pin_GPIO5, // busy_pin
false, // busy_state
5.0, // seconds_per_frame
false, // always_toggle_chip_select
true, // grayscale
false, // acep
false); // two_byte_sequence_length
}

View File

@ -32,6 +32,8 @@
void port_background_task(void) {
}
void port_background_tick(void) {
}
void port_start_background_task(void) {
}
void port_finish_background_task(void) {

View File

@ -28,10 +28,14 @@
#include "supervisor/port.h"
void port_background_task(void) {
}
void port_background_tick(void) {
#if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO
audio_dma_background();
#endif
}
void port_start_background_task(void) {
}
void port_finish_background_task(void) {

View File

@ -275,7 +275,8 @@ endif
#####################
.phony: dfu-gen dfu-flash
NRFUTIL = adafruit-nrfutil
NRFUTIL = nrfutil
ADAFRUIT_NRFUTIL = adafruit-nrfutil
ifeq ($(MCU_SUB_VARIANT),nrf52840)
DFU_TOUCH = --touch 1200
@ -293,14 +294,19 @@ __check_defined = \
## Flash with DFU serial
dfu-flash: $(BUILD)/dfu-package.zip
@:$(call check_defined, SERIAL, example: SERIAL=/dev/ttyUSB0)
$(NRFUTIL) --verbose dfu serial --package $^ -p $(SERIAL) -b 115200 --singlebank $(DFU_TOUCH)
$(ADAFRUIT_NRFUTIL) --verbose dfu serial --package $^ -p $(SERIAL) -b 115200 --singlebank $(DFU_TOUCH)
## Create DFU package file
dfu-gen: $(BUILD)/dfu-package.zip
$(BUILD)/dfu-package.zip: $(BUILD)/firmware.hex
$(NRFUTIL) dfu genpkg --sd-req 0xFFFE --dev-type 0x0052 --application $^ $(BUILD)/dfu-package.zip
$(ADAFRUIT_NRFUTIL) dfu genpkg --sd-req 0xFFFE --dev-type 0x0052 --application $^ $(BUILD)/dfu-package.zip
# Espruino DFU
$(BUILD)/firmware.espruino.zip: $(BUILD)/firmware.hex
$(Q)$(NRFUTIL) pkg generate $(BUILD)/firmware.espruino.zip --application $^ --application-version 0xff --hw-version 52 --sd-req 0xa9,0xae,0xb6 --key-file espruino_dfu_private_key.pem
espruino-dfu-gen: $(BUILD)/firmware.espruino.zip
include $(TOP)/py/mkrules.mk

View File

@ -24,6 +24,8 @@
* THE SOFTWARE.
*/
#include "background.h"
#include "py/runtime.h"
#include "supervisor/filesystem.h"
#include "supervisor/port.h"
@ -44,10 +46,11 @@
void port_start_background_task(void) {
}
void port_finish_background_task(void) {
}
void port_background_task(void) {
void port_background_tick(void) {
#if CIRCUITPY_AUDIOPWMIO
audiopwmout_background();
#endif
@ -55,3 +58,11 @@ void port_background_task(void) {
i2s_background();
#endif
}
// Allow boards to override this.
MP_WEAK void board_background_task(void) {
}
void port_background_task(void) {
board_background_task();
}

View File

@ -27,4 +27,6 @@
#ifndef MICROPY_INCLUDED_NRF_BACKGROUND_H
#define MICROPY_INCLUDED_NRF_BACKGROUND_H
void board_background_task(void);
#endif // MICROPY_INCLUDED_NRF_BACKGROUND_H

View File

@ -0,0 +1,97 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "supervisor/board.h"
#include "background.h"
#include "mpconfigboard.h"
#include "shared-bindings/busio/SPI.h"
#include "shared-bindings/displayio/FourWire.h"
#include "shared-bindings/framebufferio/FramebufferDisplay.h"
#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h"
#include "shared-module/displayio/__init__.h"
digitalio_digitalinout_obj_t extcomin;
digitalio_digitalinout_obj_t display_on;
uint32_t last_down_ticks_ms;
void board_init(void) {
common_hal_digitalio_digitalinout_construct(&extcomin, &pin_P0_06);
common_hal_digitalio_digitalinout_switch_to_output(&extcomin, true, DRIVE_MODE_PUSH_PULL);
common_hal_digitalio_digitalinout_never_reset(&extcomin);
common_hal_digitalio_digitalinout_construct(&display_on, &pin_P0_07);
common_hal_digitalio_digitalinout_switch_to_output(&display_on, true, DRIVE_MODE_PUSH_PULL);
common_hal_digitalio_digitalinout_never_reset(&display_on);
sharpdisplay_framebuffer_obj_t *fb = &allocate_display_bus()->sharpdisplay;
fb->base.type = &sharpdisplay_framebuffer_type;
busio_spi_obj_t *spi = &fb->inline_bus;
common_hal_busio_spi_construct(spi, &pin_P0_26, &pin_P0_27, NULL, false);
common_hal_busio_spi_never_reset(spi);
common_hal_sharpdisplay_framebuffer_construct(fb, spi, &pin_P0_05, 500000, 176, 176, true);
primary_display_t *display = allocate_display();
framebufferio_framebufferdisplay_obj_t *self = &display->framebuffer_display;
self->base.type = &framebufferio_framebufferdisplay_type;
common_hal_framebufferio_framebufferdisplay_construct(self, fb, 0, true);
}
bool board_requests_safe_mode(void) {
return false;
}
void reset_board(void) {
nrf_gpio_cfg_input(17, NRF_GPIO_PIN_PULLUP);
}
void board_deinit(void) {
// common_hal_displayio_release_displays();
}
void board_background_task(void) {
if (!nrf_gpio_pin_read(17)) {
if (last_down_ticks_ms == 0) {
last_down_ticks_ms = supervisor_ticks_ms32();
}
} else {
last_down_ticks_ms = 0;
}
// If the button isn't pressed, then feed the watchdog.
if (last_down_ticks_ms == 0) {
NRF_WDT->RR[0] = 0x6E524635;
return;
}
// if the button has been pressed less than 5 seconds, then feed the watchdog.
uint32_t now = supervisor_ticks_ms32();
if (now - last_down_ticks_ms < 5000) {
NRF_WDT->RR[0] = 0x6E524635;
}
// Don't feed the watchdog so that it'll expire and kick us to the bootloader.
}

View File

@ -0,0 +1,44 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2016 Glenn Ruben Bakke
* Copyright (c) 2018 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "nrfx/hal/nrf_gpio.h"
#define MICROPY_HW_BOARD_NAME "Espruino Bangle.js 2"
#define MICROPY_HW_MCU_NAME "nRF52840"
#define MICROPY_HW_LED_STATUS (&pin_P0_19)
#if SPI_FLASH_FILESYSTEM
#define SPI_FLASH_MOSI_PIN &pin_P0_15
#define SPI_FLASH_MISO_PIN &pin_P0_13
#define SPI_FLASH_SCK_PIN &pin_P0_16
#define SPI_FLASH_CS_PIN &pin_P0_14
#endif
#define CIRCUITPY_BOOT_BUTTON (&pin_P0_17)
#define BOARD_HAS_32KHZ_XTAL (1)

View File

@ -0,0 +1,27 @@
CIRCUITPY_CREATOR_ID = 0xBA000000
CIRCUITPY_CREATION_ID = 0x0BA20001
MCU_CHIP = nrf52840
SPI_FLASH_FILESYSTEM = 1
EXTERNAL_FLASH_DEVICES = "XT25F64B,GD25Q64C"
CIRCUITPY_USB = 0
CIRCUITPY_FULL_BUILD = 1
CIRCUITPY_AUDIOBUSIO = 0
CIRCUITPY_AUDIOPWMIO = 0
CIRCUITPY_COUNTIO = 0
CIRCUITPY_NEOPIXEL_WRITE = 0
CIRCUITPY_ROTARYIO = 0
CIRCUITPY_SYNTHIO = 0
CIRCUITPY_AESIO = 0
CIRCUITPY_ANALOGIO = 1
CIRCUITPY_AUDIOCORE = 0
CIRCUITPY_AUDIOMIXER = 0
CIRCUITPY_RAINBOWIO = 0
CIRCUITPY_RGBMATRIX = 0
CIRCUITPY_ONEWIREIO = 0
CIRCUITPY_BUILD_EXTENSIONS = espruino.zip
CIRCUITPY_DISPLAYIO = 1

View File

@ -0,0 +1,41 @@
#include "shared-bindings/board/__init__.h"
#include "supervisor/board.h"
#include "shared-module/displayio/__init__.h"
STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
{ MP_ROM_QSTR(MP_QSTR_PRESSURE_SCL), MP_ROM_PTR(&pin_P0_02) },
{ MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_P0_03) },
{ MP_ROM_QSTR(MP_QSTR_MEMLCD_CS), MP_ROM_PTR(&pin_P0_05) },
{ MP_ROM_QSTR(MP_QSTR_MEMLCD_EXTCOMIN), MP_ROM_PTR(&pin_P0_06) },
{ MP_ROM_QSTR(MP_QSTR_MEMLCD_DISP), MP_ROM_PTR(&pin_P0_07) },
{ MP_ROM_QSTR(MP_QSTR_BACKLIGHT), MP_ROM_PTR(&pin_P0_08) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_P0_17) },
{ MP_ROM_QSTR(MP_QSTR_VIBRATE), MP_ROM_PTR(&pin_P0_19) },
{ MP_ROM_QSTR(MP_QSTR_HRM_POWER), MP_ROM_PTR(&pin_P0_21) },
{ MP_ROM_QSTR(MP_QSTR_HRM_INT), MP_ROM_PTR(&pin_P0_22) },
{ MP_ROM_QSTR(MP_QSTR_CHARGE_PORT), MP_ROM_PTR(&pin_P0_23) },
{ MP_ROM_QSTR(MP_QSTR_HRM_SDA), MP_ROM_PTR(&pin_P0_24) },
{ MP_ROM_QSTR(MP_QSTR_CHARGE_COMPLETE), MP_ROM_PTR(&pin_P0_25) },
{ MP_ROM_QSTR(MP_QSTR_MEMLCD_SCK), MP_ROM_PTR(&pin_P0_26) },
{ MP_ROM_QSTR(MP_QSTR_MEMLCD_MOSI), MP_ROM_PTR(&pin_P0_27) },
{ MP_ROM_QSTR(MP_QSTR_GPS_POWER), MP_ROM_PTR(&pin_P0_29) },
{ MP_ROM_QSTR(MP_QSTR_GPS_TX), MP_ROM_PTR(&pin_P0_30) },
{ MP_ROM_QSTR(MP_QSTR_GPS_RX), MP_ROM_PTR(&pin_P0_31) },
{ MP_ROM_QSTR(MP_QSTR_HRM_SCL), MP_ROM_PTR(&pin_P1_00) },
{ MP_ROM_QSTR(MP_QSTR_TOUCH_SDA), MP_ROM_PTR(&pin_P1_01) },
{ MP_ROM_QSTR(MP_QSTR_TOUCH_SCL), MP_ROM_PTR(&pin_P1_02) },
{ MP_ROM_QSTR(MP_QSTR_TOUCH_INT), MP_ROM_PTR(&pin_P1_03) },
{ MP_ROM_QSTR(MP_QSTR_ACCEL_SDA), MP_ROM_PTR(&pin_P1_04) },
{ MP_ROM_QSTR(MP_QSTR_ACCEL_SCL), MP_ROM_PTR(&pin_P1_05) },
{ MP_ROM_QSTR(MP_QSTR_COMPASS_SDA), MP_ROM_PTR(&pin_P1_10) },
{ MP_ROM_QSTR(MP_QSTR_COMPASS_SCL), MP_ROM_PTR(&pin_P1_11) },
{ MP_ROM_QSTR(MP_QSTR_PRESSURE_SDA), MP_ROM_PTR(&pin_P1_13) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)}
};
MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

View File

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIK5uG3MovsdlHdw0xKzHsiv7hCRlFFQbwF30wW2KT4YJoAoGCCqGSM49
AwEHoUQDQgAElQMkm+myar6SNwygD8seLeccsydVakcn3kHvxVK5AUnTCcYEFKPY
B9RfTIE/mwpHoaXs8e4swKX9nPBeC2mTZQ==
-----END EC PRIVATE KEY-----

View File

@ -30,8 +30,12 @@
void port_start_background_task(void) {
}
void port_finish_background_task(void) {
}
void port_background_tick(void) {
}
void port_background_task(void) {
}

View File

@ -260,6 +260,10 @@ const uint8_t display_stop_sequence[] = {
POF, 0x00 // Power off
};
const uint8_t refresh_sequence[] = {
DRF, 0x00
};
void board_init(void) {
// Drive the EN_3V3 pin high so the board stays awake on battery power
enable_pin_obj.base.type = &digitalio_digitalinout_type;
@ -293,6 +297,7 @@ void board_init(void) {
display,
bus,
display_start_sequence, sizeof(display_start_sequence),
0, // start up time
display_stop_sequence, sizeof(display_stop_sequence),
296, // width
128, // height
@ -310,13 +315,14 @@ void board_init(void) {
DTM1, // write_color_ram_command
false, // color_bits_inverted
0x000000, // highlight_color
DRF, // refresh_display_command
refresh_sequence, sizeof(refresh_sequence), // refresh_display_command
1.0, // refresh_time
&pin_GPIO26, // busy_pin
false, // busy_state
2.0, // seconds_per_frame
false, // always_toggle_chip_select
false, // grayscale
false, // acep
false); // two_byte_sequence_length
}

View File

@ -35,6 +35,8 @@
void port_background_task(void) {
}
void port_background_tick(void) {
}
void port_start_background_task(void) {
}
void port_finish_background_task(void) {

View File

@ -159,7 +159,12 @@ STATIC mp_uint_t bleio_characteristic_buffer_ioctl(mp_obj_t self_in, mp_uint_t r
STATIC mp_obj_t bleio_characteristic_buffer_obj_get_in_waiting(mp_obj_t self_in) {
bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_characteristic_buffer_rx_characters_available(self));
uint32_t available = common_hal_bleio_characteristic_buffer_rx_characters_available(self);
if (available == 0) {
// Only check if connected when none available, otherwise, allow code to continue.
raise_error_if_not_connected(self);
}
return MP_OBJ_NEW_SMALL_INT(available);
}
MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_buffer_get_in_waiting_obj, bleio_characteristic_buffer_obj_get_in_waiting);

View File

@ -71,14 +71,16 @@
//| write_color_ram_command: Optional[int] = None,
//| color_bits_inverted: bool = False,
//| highlight_color: int = 0x000000,
//| refresh_display_command: int,
//| refresh_display_command: Union[int, circuitpython_typing.ReadableBuffer],
//| refresh_time: float = 40,
//| busy_pin: Optional[microcontroller.Pin] = None,
//| busy_state: bool = True,
//| seconds_per_frame: float = 180,
//| always_toggle_chip_select: bool = False,
//| grayscale: bool = False,
//| two_byte_sequence_length: bool = False
//| advanced_color_epaper: bool = False,
//| two_byte_sequence_length: bool = False,
//| start_up_time: float = 0
//| ) -> None:
//| """Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or `paralleldisplay.ParallelBus`).
//|
@ -92,8 +94,8 @@
//|
//| :param display_bus: The bus that the display is connected to
//| :type _DisplayBus: displayio.FourWire or paralleldisplay.ParallelBus
//| :param ~circuitpython_typing.ReadableBuffer start_sequence: Byte-packed initialization sequence.
//| :param ~circuitpython_typing.ReadableBuffer stop_sequence: Byte-packed initialization sequence.
//| :param ~circuitpython_typing.ReadableBuffer start_sequence: Byte-packed command sequence.
//| :param ~circuitpython_typing.ReadableBuffer stop_sequence: Byte-packed command sequence.
//| :param int width: Width in pixels
//| :param int height: Height in pixels
//| :param int ram_width: RAM width in pixels
@ -110,14 +112,16 @@
//| :param int write_color_ram_command: Command used to write pixels values into the update region
//| :param bool color_bits_inverted: True if 0 bits are used to show the color. Otherwise, 1 means to show color.
//| :param int highlight_color: RGB888 of source color to highlight with third ePaper color.
//| :param int refresh_display_command: Command used to start a display refresh
//| :param int refresh_display_command: Command used to start a display refresh. Single int or byte-packed command sequence
//| :param float refresh_time: Time it takes to refresh the display before the stop_sequence should be sent. Ignored when busy_pin is provided.
//| :param microcontroller.Pin busy_pin: Pin used to signify the display is busy
//| :param bool busy_state: State of the busy pin when the display is busy
//| :param float seconds_per_frame: Minimum number of seconds between screen refreshes
//| :param bool always_toggle_chip_select: When True, chip select is toggled every byte
//| :param bool grayscale: When true, the color ram is the low bit of 2-bit grayscale
//| :param bool advanced_color_epaper: When true, the display is a 7-color advanced color epaper (ACeP)
//| :param bool two_byte_sequence_length: When true, use two bytes to define sequence length
//| :param float start_up_time: Time to wait after reset before sending commands
//| """
//| ...
STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
@ -127,7 +131,8 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size
ARG_set_current_row_command, ARG_write_black_ram_command, ARG_black_bits_inverted,
ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_highlight_color,
ARG_refresh_display_command, ARG_refresh_time, ARG_busy_pin, ARG_busy_state,
ARG_seconds_per_frame, ARG_always_toggle_chip_select, ARG_grayscale, ARG_two_byte_sequence_length };
ARG_seconds_per_frame, ARG_always_toggle_chip_select, ARG_grayscale, ARG_advanced_color_epaper,
ARG_two_byte_sequence_length, ARG_start_up_time };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_start_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ },
@ -148,14 +153,16 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size
{ MP_QSTR_write_color_ram_command, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
{ MP_QSTR_color_bits_inverted, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
{ MP_QSTR_highlight_color, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x000000} },
{ MP_QSTR_refresh_display_command, MP_ARG_INT | MP_ARG_REQUIRED },
{ MP_QSTR_refresh_display_command, MP_ARG_OBJ | MP_ARG_REQUIRED },
{ MP_QSTR_refresh_time, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(40)} },
{ MP_QSTR_busy_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
{ MP_QSTR_busy_state, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} },
{ MP_QSTR_seconds_per_frame, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(180)} },
{ MP_QSTR_always_toggle_chip_select, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
{ MP_QSTR_grayscale, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
{ MP_QSTR_advanced_color_epaper, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
{ MP_QSTR_two_byte_sequence_length, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
{ MP_QSTR_start_up_time, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(0)} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@ -177,10 +184,10 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size
primary_display_t *disp = allocate_display_or_raise();
displayio_epaperdisplay_obj_t *self = &disp->epaper_display;
;
mp_float_t refresh_time = mp_obj_get_float(args[ARG_refresh_time].u_obj);
mp_float_t seconds_per_frame = mp_obj_get_float(args[ARG_seconds_per_frame].u_obj);
mp_float_t start_up_time = mp_obj_get_float(args[ARG_start_up_time].u_obj);
mp_int_t write_color_ram_command = NO_COMMAND;
mp_int_t highlight_color = args[ARG_highlight_color].u_int;
@ -188,19 +195,40 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size
write_color_ram_command = mp_obj_get_int(args[ARG_write_color_ram_command].u_obj);
}
bool two_byte_sequence_length = args[ARG_two_byte_sequence_length].u_bool;
mp_obj_t refresh_obj = args[ARG_refresh_display_command].u_obj;
const uint8_t *refresh_buf;
mp_buffer_info_t refresh_bufinfo;
size_t refresh_buf_len = 0;
mp_int_t refresh_command;
if (mp_obj_get_int_maybe(refresh_obj, &refresh_command)) {
uint8_t *command_buf = m_malloc(3, true);
command_buf[0] = refresh_command;
command_buf[1] = 0;
command_buf[2] = 0;
refresh_buf = command_buf;
refresh_buf_len = two_byte_sequence_length? 3: 2;
} else if (mp_get_buffer(refresh_obj, &refresh_bufinfo, MP_BUFFER_READ)) {
refresh_buf = refresh_bufinfo.buf;
refresh_buf_len = refresh_bufinfo.len;
} else {
mp_raise_ValueError_varg(translate("Invalid %q"), MP_QSTR_refresh_display_command);
}
self->base.type = &displayio_epaperdisplay_type;
common_hal_displayio_epaperdisplay_construct(
self,
display_bus,
start_bufinfo.buf, start_bufinfo.len, stop_bufinfo.buf, stop_bufinfo.len,
start_bufinfo.buf, start_bufinfo.len, start_up_time, stop_bufinfo.buf, stop_bufinfo.len,
args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_ram_width].u_int, args[ARG_ram_height].u_int,
args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation,
args[ARG_set_column_window_command].u_int, args[ARG_set_row_window_command].u_int,
args[ARG_set_current_column_command].u_int, args[ARG_set_current_row_command].u_int,
args[ARG_write_black_ram_command].u_int, args[ARG_black_bits_inverted].u_bool, write_color_ram_command,
args[ARG_color_bits_inverted].u_bool, highlight_color, args[ARG_refresh_display_command].u_int, refresh_time,
args[ARG_color_bits_inverted].u_bool, highlight_color, refresh_buf, refresh_buf_len, refresh_time,
busy_pin, args[ARG_busy_state].u_bool, seconds_per_frame,
args[ARG_always_toggle_chip_select].u_bool, args[ARG_grayscale].u_bool, args[ARG_two_byte_sequence_length].u_bool
args[ARG_always_toggle_chip_select].u_bool, args[ARG_grayscale].u_bool, args[ARG_advanced_color_epaper].u_bool, two_byte_sequence_length
);
return self;

View File

@ -37,12 +37,12 @@ extern const mp_obj_type_t displayio_epaperdisplay_type;
#define NO_COMMAND 0x100
void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t *self,
mp_obj_t bus, const uint8_t *start_sequence, uint16_t start_sequence_len, const uint8_t *stop_sequence, uint16_t stop_sequence_len,
mp_obj_t bus, const uint8_t *start_sequence, uint16_t start_sequence_len, mp_float_t start_up_time, const uint8_t *stop_sequence, uint16_t stop_sequence_len,
uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation,
uint16_t set_column_window_command, uint16_t set_row_window_command,
uint16_t set_current_column_command, uint16_t set_current_row_command,
uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, mp_float_t refresh_time,
const mcu_pin_obj_t *busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select, bool grayscale, bool two_byte_sequence_length);
uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, const uint8_t *refresh_sequence, uint16_t refresh_sequence_len, mp_float_t refresh_time,
const mcu_pin_obj_t *busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select, bool grayscale, bool acep, bool two_byte_sequence_length);
bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t *self);

View File

@ -40,29 +40,54 @@
//| """Map a pixel palette_index to a full color. Colors are transformed to the display's format internally to
//| save memory."""
//|
//| def __init__(self, color_count: int) -> None:
//| def __init__(self, color_count: int, *, dither: bool = False) -> None:
//| """Create a Palette object to store a set number of colors.
//|
//| :param int color_count: The number of colors in the Palette"""
//| :param int color_count: The number of colors in the Palette
//| :param bool dither: When true, dither the RGB color before converting to the display's color space
//| """
//| ...
// TODO(tannewt): Add support for other color formats.
// TODO(tannewt): Add support for 8-bit alpha blending.
//|
STATIC mp_obj_t displayio_palette_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
enum { ARG_color_count };
enum { ARG_color_count, ARG_dither };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_color_count, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_dither, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
displayio_palette_t *self = m_new_obj(displayio_palette_t);
self->base.type = &displayio_palette_type;
common_hal_displayio_palette_construct(self, args[ARG_color_count].u_int);
common_hal_displayio_palette_construct(self, args[ARG_color_count].u_int, args[ARG_dither].u_bool);
return MP_OBJ_FROM_PTR(self);
}
//| dither: bool
//| """When `True` the Palette dithers the output color by adding random
//| noise when truncating to display bitdepth"""
STATIC mp_obj_t displayio_palette_obj_get_dither(mp_obj_t self_in) {
displayio_palette_t *self = MP_OBJ_TO_PTR(self_in);
return mp_obj_new_bool(common_hal_displayio_palette_get_dither(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(displayio_palette_get_dither_obj, displayio_palette_obj_get_dither);
STATIC mp_obj_t displayio_palette_obj_set_dither(mp_obj_t self_in, mp_obj_t dither) {
displayio_palette_t *self = MP_OBJ_TO_PTR(self_in);
common_hal_displayio_palette_set_dither(self, mp_obj_is_true(dither));
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(displayio_palette_set_dither_obj, displayio_palette_obj_set_dither);
MP_PROPERTY_GETSET(displayio_palette_dither_obj,
(mp_obj_t)&displayio_palette_get_dither_obj,
(mp_obj_t)&displayio_palette_set_dither_obj);
//| def __bool__(self) -> bool: ...
//| def __len__(self) -> int:
//| """Returns the number of colors in a Palette"""
@ -185,6 +210,7 @@ STATIC mp_obj_t displayio_palette_obj_is_transparent(mp_obj_t self_in, mp_obj_t
MP_DEFINE_CONST_FUN_OBJ_2(displayio_palette_is_transparent_obj, displayio_palette_obj_is_transparent);
STATIC const mp_rom_map_elem_t displayio_palette_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_dither), MP_ROM_PTR(&displayio_palette_dither_obj) },
{ MP_ROM_QSTR(MP_QSTR_make_transparent), MP_ROM_PTR(&displayio_palette_make_transparent_obj) },
{ MP_ROM_QSTR(MP_QSTR_make_opaque), MP_ROM_PTR(&displayio_palette_make_opaque_obj) },
{ MP_ROM_QSTR(MP_QSTR_is_transparent), MP_ROM_PTR(&displayio_palette_is_transparent_obj) },

View File

@ -31,11 +31,14 @@
extern const mp_obj_type_t displayio_palette_type;
void common_hal_displayio_palette_construct(displayio_palette_t *self, uint16_t color_count);
void common_hal_displayio_palette_construct(displayio_palette_t *self, uint16_t color_count, bool dither);
void common_hal_displayio_palette_set_color(displayio_palette_t *self, uint32_t palette_index, uint32_t color);
uint32_t common_hal_displayio_palette_get_color(displayio_palette_t *self, uint32_t palette_index);
uint32_t common_hal_displayio_palette_get_len(displayio_palette_t *self);
void common_hal_displayio_palette_set_dither(displayio_palette_t *self, bool dither);
bool common_hal_displayio_palette_get_dither(displayio_palette_t *self);
void common_hal_displayio_palette_make_opaque(displayio_palette_t *self, uint32_t palette_index);
void common_hal_displayio_palette_make_transparent(displayio_palette_t *self, uint32_t palette_index);
bool common_hal_displayio_palette_is_transparent(displayio_palette_t *self, uint32_t palette_index);

View File

@ -33,14 +33,42 @@
#include "shared-module/displayio/__init__.h"
#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"
//| class SharpMemoryFramebuffer:
//| """A framebuffer for a memory-in-pixel display. Sharp makes monochrome displays and JDI used
//| to make 8-color displays.
//|
//| This initializes a display and connects it into CircuitPython. Unlike other
//| objects in CircuitPython, Display objects live until `displayio.release_displays()`
//| is called. This is done so that CircuitPython can use the display itself."""
//|
//| def __init__(
//| self,
//| spi_bus: busio.SPI,
//| chip_select: microcontroller.Pin,
//| width: int,
//| height: int,
//| baudrate: int = 2000000,
//| jdi_display: bool = False,
//| ) -> None:
//| """Create a framebuffer for the memory-in-pixel display.
//|
//| :param busio.SPI spi_bus: The SPI bus that the display is connected to
//| :param microcontroller.Pin chip_select: The pin connect to the display's chip select line
//| :param int width: The width of the display in pixels
//| :param int height: The height of the display in pixels
//| :param int baudrate: The baudrate to communicate with the screen at
//| :param bool jdi_display: When True, work with an 8-color JDI display. Otherwise, a monochrome Sharp display.
//| """
//| ...
STATIC mp_obj_t sharpdisplay_framebuffer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
enum { ARG_spi_bus, ARG_chip_select, ARG_width, ARG_height, ARG_baudrate, NUM_ARGS };
enum { ARG_spi_bus, ARG_chip_select, ARG_width, ARG_height, ARG_baudrate, ARG_jdi_display, NUM_ARGS };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_spi_bus, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_chip_select, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} },
{ MP_QSTR_height, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} },
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 2000000} },
{ MP_QSTR_jdi_display, MP_ARG_BOOL, {.u_bool = false} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
MP_STATIC_ASSERT(MP_ARRAY_SIZE(allowed_args) == NUM_ARGS);
@ -53,7 +81,7 @@ STATIC mp_obj_t sharpdisplay_framebuffer_make_new(const mp_obj_type_t *type, siz
sharpdisplay_framebuffer_obj_t *self = &allocate_display_bus_or_raise()->sharpdisplay;
self->base.type = &sharpdisplay_framebuffer_type;
common_hal_sharpdisplay_framebuffer_construct(self, spi, chip_select, args[ARG_baudrate].u_int, args[ARG_width].u_int, args[ARG_height].u_int);
common_hal_sharpdisplay_framebuffer_construct(self, spi, chip_select, args[ARG_baudrate].u_int, args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_jdi_display].u_bool);
return MP_OBJ_FROM_PTR(self);
}
@ -69,6 +97,12 @@ STATIC mp_int_t sharpdisplay_framebuffer_get_buffer(mp_obj_t self_in, mp_buffer_
return 0;
}
//| def deinit(self) -> None:
//| """Free the resources (pins, timers, etc.) associated with this
//| SharpMemoryFramebuffer instance. After deinitialization, no further operations
//| may be performed."""
//| ...
//|
STATIC mp_obj_t sharpdisplay_framebuffer_deinit(mp_obj_t self_in) {
sharpdisplay_framebuffer_obj_t *self = (sharpdisplay_framebuffer_obj_t *)self_in;
common_hal_sharpdisplay_framebuffer_deinit(self);

View File

@ -26,9 +26,18 @@
#pragma once
// #include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"
// #include "shared-module/framebufferio/FramebufferDisplay.h"
#include "py/objtype.h"
#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"
extern const mp_obj_type_t sharpdisplay_framebuffer_type;
void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_t *self, busio_spi_obj_t *spi, const mcu_pin_obj_t *chip_select, int baudrate, int width, int height, bool jdi_display);
void common_hal_sharpdisplay_framebuffer_swap_buffers(sharpdisplay_framebuffer_obj_t *self, uint8_t *dirty_row_bitmask);
void common_hal_sharpdisplay_framebuffer_deinit(sharpdisplay_framebuffer_obj_t *self);
void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_obj_t *self, mp_buffer_info_t *bufinfo);
int common_hal_sharpdisplay_framebuffer_get_height(sharpdisplay_framebuffer_obj_t *self);
int common_hal_sharpdisplay_framebuffer_get_width(sharpdisplay_framebuffer_obj_t *self);
void common_hal_sharpdisplay_framebuffer_swap_buffers(sharpdisplay_framebuffer_obj_t *self, uint8_t *dirty_row_bitmask);
void common_hal_sharpdisplay_framebuffer_reset(sharpdisplay_framebuffer_obj_t *self);
void common_hal_sharpdisplay_framebuffer_reconstruct(sharpdisplay_framebuffer_obj_t *self);

View File

@ -54,6 +54,13 @@ uint16_t displayio_colorconverter_compute_rgb565(uint32_t color_rgb888) {
return r5 << 11 | g6 << 5 | b5;
}
uint8_t displayio_colorconverter_compute_rgbd(uint32_t color_rgb888) {
uint32_t r1 = (color_rgb888 >> 23) & 0x1;
uint32_t g1 = (color_rgb888 >> 15) & 0x1;
uint32_t b1 = (color_rgb888 >> 7) & 0x1;
return r1 << 3 | g1 << 2 | b1 << 1 /* | dummy */;
}
uint8_t displayio_colorconverter_compute_luma(uint32_t color_rgb888) {
uint32_t r8 = (color_rgb888 >> 16);
uint32_t g8 = (color_rgb888 >> 8) & 0xff;
@ -96,6 +103,44 @@ uint8_t displayio_colorconverter_compute_hue(uint32_t color_rgb888) {
return hue;
}
uint8_t displayio_colorconverter_compute_sevencolor(uint32_t color_rgb888) {
// This is DDX=1, the default for the displays.
uint8_t chroma = displayio_colorconverter_compute_chroma(color_rgb888);
if (chroma >= 64) {
uint8_t hue = displayio_colorconverter_compute_hue(color_rgb888);
// Red 0
if (hue < 10) {
return 0x4;
}
// Orange 21
if (hue < 21 + 10) {
return 0x6;
}
// Yellow 42
if (hue < 42 + 21) {
return 0x5;
}
// Green 85
if (hue < 85 + 42) {
return 0x2;
}
// Blue 170
if (hue < 170 + 42) {
return 0x3;
}
// The rest is red to 255
return 0x4;
} else {
uint8_t luma = displayio_colorconverter_compute_luma(color_rgb888);
if (luma >= 128) {
return 0x1; // White
} else {
return 0x0; // Black
}
}
}
void displayio_colorconverter_compute_tricolor(const _displayio_colorspace_t *colorspace, uint8_t pixel_hue, uint32_t *color) {
int16_t hue_diff = colorspace->tricolor_hue - pixel_hue;
@ -207,18 +252,9 @@ uint32_t displayio_colorconverter_convert_pixel(displayio_colorspace_t colorspac
return pixel;
}
void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t *colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color) {
void displayio_convert_color(const _displayio_colorspace_t *colorspace, bool dither, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color) {
uint32_t pixel = input_pixel->pixel;
if (self->transparent_color == pixel) {
output_color->opaque = false;
return;
}
pixel = displayio_colorconverter_convert_pixel(self->input_colorspace, pixel);
if (self->dither) {
if (dither) {
uint8_t randr = (displayio_colorconverter_dither_noise_2(input_pixel->tile_x,input_pixel->tile_y));
uint8_t randg = (displayio_colorconverter_dither_noise_2(input_pixel->tile_x + 33,input_pixel->tile_y));
uint8_t randb = (displayio_colorconverter_dither_noise_2(input_pixel->tile_x,input_pixel->tile_y + 33));
@ -272,10 +308,44 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d
output_color->pixel = pixel;
output_color->opaque = true;
return;
} else if (colorspace->depth == 4) {
uint8_t packed;
if (colorspace->sevencolor) {
packed = displayio_colorconverter_compute_sevencolor(pixel);
} else {
packed = displayio_colorconverter_compute_rgbd(pixel);
}
output_color->pixel = packed;
output_color->opaque = true;
return;
}
output_color->opaque = false;
}
void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t *colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color) {
uint32_t pixel = input_pixel->pixel;
if (self->transparent_color == pixel) {
output_color->opaque = false;
return;
}
if (!self->dither && self->cached_colorspace == colorspace && self->cached_input_pixel == input_pixel->pixel) {
output_color->pixel = self->cached_output_color;
return;
}
displayio_input_pixel_t rgb888_pixel = *input_pixel;
rgb888_pixel.pixel = displayio_colorconverter_convert_pixel(self->input_colorspace, input_pixel->pixel);
displayio_convert_color(colorspace, self->dither, &rgb888_pixel, output_color);
if (!self->dither) {
self->cached_colorspace = colorspace;
self->cached_input_pixel = input_pixel->pixel;
self->cached_output_color = output_color->pixel;
}
}
// Currently no refresh logic is needed for a ColorConverter.

View File

@ -38,6 +38,11 @@ typedef struct displayio_colorconverter {
bool dither;
uint8_t input_colorspace;
uint32_t transparent_color;
// Cache the last computed color in case the are the same.
const _displayio_colorspace_t *cached_colorspace;
uint32_t cached_input_pixel;
uint32_t cached_output_color;
} displayio_colorconverter_t;
bool displayio_colorconverter_needs_refresh(displayio_colorconverter_t *self);
@ -47,10 +52,15 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d
uint32_t displayio_colorconverter_dither_noise_1(uint32_t n);
uint32_t displayio_colorconverter_dither_noise_2(uint32_t x, uint32_t y);
// Convert version that doesn't require a colorconverter object.
void displayio_convert_color(const _displayio_colorspace_t *colorspace, bool dither, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color);
uint16_t displayio_colorconverter_compute_rgb565(uint32_t color_rgb888);
uint8_t displayio_colorconverter_compute_rgbd(uint32_t color_rgb888);
uint8_t displayio_colorconverter_compute_luma(uint32_t color_rgb888);
uint8_t displayio_colorconverter_compute_chroma(uint32_t color_rgb888);
uint8_t displayio_colorconverter_compute_hue(uint32_t color_rgb888);
uint8_t displayio_colorconverter_compute_sevencolor(uint32_t color_rgb888);
void displayio_colorconverter_compute_tricolor(const _displayio_colorspace_t *colorspace, uint8_t pixel_hue, uint32_t *color);
#endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_COLORCONVERTER_H

View File

@ -28,6 +28,7 @@
#include "py/gc.h"
#include "py/runtime.h"
#include "shared/runtime/interrupt_char.h"
#include "shared-bindings/displayio/ColorConverter.h"
#include "shared-bindings/displayio/FourWire.h"
#include "shared-bindings/displayio/I2CDisplay.h"
@ -47,21 +48,31 @@
#define DELAY 0x80
void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t *self,
mp_obj_t bus, const uint8_t *start_sequence, uint16_t start_sequence_len,
mp_obj_t bus, const uint8_t *start_sequence, uint16_t start_sequence_len, mp_float_t start_up_time,
const uint8_t *stop_sequence, uint16_t stop_sequence_len,
uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height,
int16_t colstart, int16_t rowstart, uint16_t rotation,
uint16_t set_column_window_command, uint16_t set_row_window_command,
uint16_t set_current_column_command, uint16_t set_current_row_command,
uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, mp_float_t refresh_time,
const mcu_pin_obj_t *busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool chip_select, bool grayscale, bool two_byte_sequence_length) {
uint16_t write_black_ram_command, bool black_bits_inverted,
uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color,
const uint8_t *refresh_sequence, uint16_t refresh_sequence_len, mp_float_t refresh_time,
const mcu_pin_obj_t *busy_pin, bool busy_state, mp_float_t seconds_per_frame,
bool chip_select, bool grayscale, bool acep, bool two_byte_sequence_length) {
uint16_t color_depth = 1;
if (highlight_color != 0x000000) {
self->core.colorspace.tricolor = true;
self->core.colorspace.tricolor_hue = displayio_colorconverter_compute_hue(highlight_color);
self->core.colorspace.tricolor_luma = displayio_colorconverter_compute_luma(highlight_color);
}
if (acep) {
self->core.colorspace.sevencolor = true;
color_depth = 4; // bits. 7 colors + clean
self->acep = acep;
grayscale = false;
}
displayio_display_core_construct(&self->core, bus, width, height, ram_width, ram_height, colstart, rowstart, rotation, 1, true, true, 1, true, true);
displayio_display_core_construct(&self->core, bus, width, height, ram_width, ram_height, colstart, rowstart, rotation, color_depth, grayscale, true, 1, true, true);
self->set_column_window_command = set_column_window_command;
self->set_row_window_command = set_row_window_command;
@ -71,7 +82,6 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t
self->black_bits_inverted = black_bits_inverted;
self->write_color_ram_command = write_color_ram_command;
self->color_bits_inverted = color_bits_inverted;
self->refresh_display_command = refresh_display_command;
self->refresh_time = refresh_time * 1000;
self->busy_state = busy_state;
self->refreshing = false;
@ -81,8 +91,11 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t
self->start_sequence = start_sequence;
self->start_sequence_len = start_sequence_len;
self->start_up_time_ms = start_up_time * 1000;
self->stop_sequence = stop_sequence;
self->stop_sequence_len = stop_sequence_len;
self->refresh_sequence = refresh_sequence;
self->refresh_sequence_len = refresh_sequence_len;
self->busy.base.type = &mp_type_NoneType;
self->two_byte_sequence_length = two_byte_sequence_length;
@ -193,6 +206,8 @@ STATIC void displayio_epaperdisplay_start_refresh(displayio_epaperdisplay_obj_t
// run start sequence
self->core.bus_reset(self->core.bus);
common_hal_time_delay_ms(self->start_up_time_ms);
send_command_sequence(self, true, self->start_sequence, self->start_sequence_len);
displayio_display_core_start_refresh(&self->core);
}
@ -211,9 +226,8 @@ uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaper
STATIC void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t *self) {
// Actually refresh the display now that all pixel RAM has been updated.
displayio_display_core_begin_transaction(&self->core);
self->core.send(self->core.bus, DISPLAY_COMMAND, self->chip_select, &self->refresh_display_command, 1);
displayio_display_core_end_transaction(&self->core);
send_command_sequence(self, false, self->refresh_sequence, self->refresh_sequence_len);
supervisor_enable_tick();
self->refreshing = true;
@ -326,8 +340,10 @@ STATIC bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t *
memset(mask, 0, mask_length * sizeof(mask[0]));
memset(buffer, 0, buffer_size * sizeof(buffer[0]));
self->core.colorspace.grayscale = true;
self->core.colorspace.grayscale_bit = 7;
if (self->grayscale) {
self->core.colorspace.grayscale = true;
self->core.colorspace.grayscale_bit = 7;
}
if (pass == 1) {
if (self->grayscale) { // 4-color grayscale
self->core.colorspace.grayscale_bit = 6;
@ -335,6 +351,8 @@ STATIC bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t *
} else if (self->core.colorspace.tricolor) {
self->core.colorspace.grayscale = false;
displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer);
} else if (self->core.colorspace.sevencolor) {
displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer);
}
} else {
displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer);
@ -366,6 +384,38 @@ STATIC bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t *
return true;
}
STATIC bool _clean_area(displayio_epaperdisplay_obj_t *self) {
uint16_t width = displayio_display_core_get_width(&self->core);
uint16_t height = displayio_display_core_get_height(&self->core);
// Allocated and shared as a uint32_t array so the compiler knows the
// alignment everywhere.
uint8_t buffer[width / 2];
memset(buffer, 0x77, width / 2);
uint8_t write_command = self->write_black_ram_command;
displayio_display_core_begin_transaction(&self->core);
self->core.send(self->core.bus, DISPLAY_COMMAND, self->chip_select, &write_command, 1);
displayio_display_core_end_transaction(&self->core);
for (uint16_t j = 0; j < height; j++) {
if (!displayio_display_core_begin_transaction(&self->core)) {
// Can't acquire display bus; skip the rest of the data. Try next display.
return false;
}
self->core.send(self->core.bus, DISPLAY_DATA, self->chip_select, (uint8_t *)buffer, width / 2);
displayio_display_core_end_transaction(&self->core);
// TODO(tannewt): Make refresh displays faster so we don't starve other
// background tasks.
#if CIRCUITPY_USB
usb_background();
#endif
}
return true;
}
bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t *self) {
if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) {
@ -393,6 +443,18 @@ bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t *s
if (current_area == NULL) {
return true;
}
if (self->acep) {
displayio_epaperdisplay_start_refresh(self);
_clean_area(self);
displayio_epaperdisplay_finish_refresh(self);
while (self->refreshing && !mp_hal_is_interrupted()) {
RUN_BACKGROUND_TASKS;
}
}
if (mp_hal_is_interrupted()) {
return false;
}
displayio_epaperdisplay_start_refresh(self);
while (current_area != NULL) {
displayio_epaperdisplay_refresh_area(self, current_area);

View File

@ -39,9 +39,12 @@ typedef struct {
digitalio_digitalinout_obj_t busy;
uint32_t milliseconds_per_frame;
const uint8_t *start_sequence;
uint32_t start_sequence_len;
const uint8_t *stop_sequence;
uint32_t stop_sequence_len;
const uint8_t *refresh_sequence;
uint16_t start_sequence_len;
uint16_t stop_sequence_len;
uint16_t refresh_sequence_len;
uint16_t start_up_time_ms;
uint16_t refresh_time;
uint16_t set_column_window_command;
uint16_t set_row_window_command;
@ -49,15 +52,15 @@ typedef struct {
uint16_t set_current_row_command;
uint16_t write_black_ram_command;
uint16_t write_color_ram_command;
uint8_t refresh_display_command;
uint8_t hue;
bool busy_state;
bool black_bits_inverted;
bool color_bits_inverted;
bool refreshing;
bool grayscale;
display_chip_select_behavior_t chip_select;
bool acep;
bool two_byte_sequence_length;
display_chip_select_behavior_t chip_select;
} displayio_epaperdisplay_obj_t;
void displayio_epaperdisplay_change_refresh_mode_parameters(displayio_epaperdisplay_obj_t *self,

View File

@ -90,7 +90,7 @@ void common_hal_displayio_ondiskbitmap_construct(displayio_ondiskbitmap_t *self,
displayio_palette_t *palette = m_new_obj(displayio_palette_t);
palette->base.type = &displayio_palette_type;
common_hal_displayio_palette_construct(palette, number_of_colors);
common_hal_displayio_palette_construct(palette, number_of_colors, false);
if (number_of_colors > 1) {
uint16_t palette_size = number_of_colors * sizeof(uint32_t);

View File

@ -28,9 +28,18 @@
#include "shared-module/displayio/ColorConverter.h"
void common_hal_displayio_palette_construct(displayio_palette_t *self, uint16_t color_count) {
void common_hal_displayio_palette_construct(displayio_palette_t *self, uint16_t color_count, bool dither) {
self->color_count = color_count;
self->colors = (_displayio_color_t *)m_malloc(color_count * sizeof(_displayio_color_t), false);
self->dither = dither;
}
void common_hal_displayio_palette_set_dither(displayio_palette_t *self, bool dither) {
self->dither = dither;
}
bool common_hal_displayio_palette_get_dither(displayio_palette_t *self) {
return self->dither;
}
void common_hal_displayio_palette_make_opaque(displayio_palette_t *self, uint32_t palette_index) {
@ -56,12 +65,7 @@ void common_hal_displayio_palette_set_color(displayio_palette_t *self, uint32_t
return;
}
self->colors[palette_index].rgb888 = color;
self->colors[palette_index].luma = displayio_colorconverter_compute_luma(color);
self->colors[palette_index].rgb565 = displayio_colorconverter_compute_rgb565(color);
uint8_t chroma = displayio_colorconverter_compute_chroma(color);
self->colors[palette_index].chroma = chroma;
self->colors[palette_index].hue = displayio_colorconverter_compute_hue(color);
self->colors[palette_index].cached_colorspace = NULL;
self->needs_refresh = true;
}
@ -69,40 +73,26 @@ uint32_t common_hal_displayio_palette_get_color(displayio_palette_t *self, uint3
return self->colors[palette_index].rgb888;
}
bool displayio_palette_get_color(displayio_palette_t *self, const _displayio_colorspace_t *colorspace, uint32_t palette_index, uint32_t *color) {
void displayio_palette_get_color(displayio_palette_t *self, const _displayio_colorspace_t *colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color) {
uint32_t palette_index = input_pixel->pixel;
if (palette_index > self->color_count || self->colors[palette_index].transparent) {
return false; // returns transparent
output_color->opaque = false;
return;
}
if (colorspace->tricolor) {
uint8_t luma = self->colors[palette_index].luma;
*color = luma >> (8 - colorspace->depth);
// Chroma 0 means the color is a gray and has no hue so never color based on it.
if (self->colors[palette_index].chroma <= 16) {
if (!colorspace->grayscale) {
*color = 0;
}
return true;
}
uint8_t pixel_hue = self->colors[palette_index].hue;
displayio_colorconverter_compute_tricolor(colorspace, pixel_hue, color);
} else if (colorspace->grayscale) {
size_t bitmask = (1 << colorspace->depth) - 1;
*color = (self->colors[palette_index].luma >> colorspace->grayscale_bit) & bitmask;
} else if (colorspace->depth == 16) {
uint16_t packed = self->colors[palette_index].rgb565;
if (colorspace->reverse_bytes_in_word) {
// swap bytes
packed = __builtin_bswap16(packed);
}
*color = packed;
} else if (colorspace->depth == 32) {
*color = self->colors[palette_index].rgb888;
} else {
return false;
// Cache results when not dithering.
if (!self->dither && self->colors[palette_index].cached_colorspace == colorspace) {
output_color->pixel = self->colors[palette_index].cached_color;
return;
}
return true;
displayio_input_pixel_t rgb888_pixel = *input_pixel;
rgb888_pixel.pixel = self->colors[palette_index].rgb888;
displayio_convert_color(colorspace, self->dither, &rgb888_pixel, output_color);
if (!self->dither) {
self->colors[palette_index].cached_colorspace = colorspace;
self->colors[palette_index].cached_color = output_color->pixel;
}
}
bool displayio_palette_needs_refresh(displayio_palette_t *self) {

View File

@ -40,6 +40,7 @@ typedef struct {
uint8_t grayscale_bit; // The lowest grayscale bit. Normally 8 - depth.
bool grayscale;
bool tricolor;
bool sevencolor; // Acep e-ink screens.
bool pixels_in_byte_share_row;
bool reverse_pixels_in_byte;
bool reverse_bytes_in_word;
@ -48,10 +49,8 @@ typedef struct {
typedef struct {
uint32_t rgb888;
uint16_t rgb565;
uint8_t luma;
uint8_t hue;
uint8_t chroma;
const _displayio_colorspace_t *cached_colorspace;
uint32_t cached_color;
bool transparent; // This may have additional bits added later for blending.
} _displayio_color_t;
@ -74,11 +73,12 @@ typedef struct displayio_palette {
_displayio_color_t *colors;
uint32_t color_count;
bool needs_refresh;
bool dither;
} displayio_palette_t;
// Returns false if color fetch did not succeed (out of range or transparent).
// Returns true if color is opaque, and sets color.
bool displayio_palette_get_color(displayio_palette_t *palette, const _displayio_colorspace_t *colorspace, uint32_t palette_index, uint32_t *color);
void displayio_palette_get_color(displayio_palette_t *palette, const _displayio_colorspace_t *colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color);
;
bool displayio_palette_needs_refresh(displayio_palette_t *self);
void displayio_palette_finish_refresh(displayio_palette_t *self);

View File

@ -507,7 +507,7 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self,
if (self->pixel_shader == mp_const_none) {
output_pixel.pixel = input_pixel.pixel;
} else if (mp_obj_is_type(self->pixel_shader, &displayio_palette_type)) {
output_pixel.opaque = displayio_palette_get_color(self->pixel_shader, colorspace, input_pixel.pixel, &output_pixel.pixel);
displayio_palette_get_color(self->pixel_shader, colorspace, &input_pixel, &output_pixel);
} else if (mp_obj_is_type(self->pixel_shader, &displayio_colorconverter_type)) {
displayio_colorconverter_convert(self->pixel_shader, colorspace, &input_pixel, &output_pixel);
}

View File

@ -66,7 +66,7 @@ typedef bool (*framebuffer_set_brightness_fun)(mp_obj_t, mp_float_t);
typedef int (*framebuffer_get_bytes_per_cell_fun)(mp_obj_t);
typedef int (*framebuffer_get_color_depth_fun)(mp_obj_t);
typedef int (*framebuffer_get_first_pixel_offset_fun)(mp_obj_t);
typedef int (*framebuffer_get_grayscale_fun)(mp_obj_t);
typedef bool (*framebuffer_get_grayscale_fun)(mp_obj_t);
typedef int (*framebuffer_get_height_fun)(mp_obj_t);
typedef int (*framebuffer_get_native_frames_per_second_fun)(mp_obj_t);
typedef bool (*framebuffer_get_pixels_in_byte_share_row_fun)(mp_obj_t);

View File

@ -36,6 +36,7 @@
#include "supervisor/memory.h"
#define SHARPMEM_BIT_WRITECMD_LSB (0x80)
#define JDI_BIT_WRITECMD_LSB (0x90)
#define SHARPMEM_BIT_VCOM_LSB (0x40)
STATIC uint8_t bitrev(uint8_t n) {
@ -54,7 +55,11 @@ int common_hal_sharpdisplay_framebuffer_get_height(sharpdisplay_framebuffer_obj_
}
STATIC int common_hal_sharpdisplay_framebuffer_get_row_stride(sharpdisplay_framebuffer_obj_t *self) {
return (self->width + 7) / 8 + 2;
if (self->jdi_display) {
return (self->width + 1) / 2 + 2;
} else {
return (self->width + 7) / 8 + 2;
}
}
STATIC int common_hal_sharpdisplay_framebuffer_get_first_pixel_offset(sharpdisplay_framebuffer_obj_t *self) {
@ -99,10 +104,18 @@ void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_ob
memset(alloc->ptr, 0, self->bufinfo.len);
uint8_t *data = self->bufinfo.buf;
*data++ = SHARPMEM_BIT_WRITECMD_LSB;
if (self->jdi_display) {
*data++ = JDI_BIT_WRITECMD_LSB;
} else {
*data++ = SHARPMEM_BIT_WRITECMD_LSB;
}
for (int y = 0; y < height; y++) {
*data = bitrev(y + 1);
if (self->jdi_display) {
*data = y + 1;
} else {
*data = bitrev(y + 1);
}
data += row_stride;
}
self->full_refresh = true;
@ -128,7 +141,14 @@ void common_hal_sharpdisplay_framebuffer_deinit(sharpdisplay_framebuffer_obj_t *
memset(self, 0, sizeof(*self));
}
void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_t *self, busio_spi_obj_t *spi, const mcu_pin_obj_t *chip_select, int baudrate, int width, int height) {
void common_hal_sharpdisplay_framebuffer_construct(
sharpdisplay_framebuffer_obj_t *self,
busio_spi_obj_t *spi,
const mcu_pin_obj_t *chip_select,
int baudrate,
int width,
int height,
bool jdi_display) {
common_hal_digitalio_digitalinout_construct(&self->chip_select, chip_select);
common_hal_digitalio_digitalinout_switch_to_output(&self->chip_select, true, DRIVE_MODE_PUSH_PULL);
common_hal_never_reset_pin(chip_select);
@ -139,6 +159,7 @@ void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_
self->width = width;
self->height = height;
self->baudrate = baudrate;
self->jdi_display = jdi_display;
common_hal_sharpdisplay_framebuffer_get_bufinfo(self, NULL);
}
@ -169,7 +190,8 @@ STATIC void common_hal_sharpdisplay_framebuffer_swapbuffers(sharpdisplay_framebu
}
// output a trailing zero
common_hal_busio_spi_write(self->bus, data, 1);
uint8_t zero[2] = {0, 0};
common_hal_busio_spi_write(self->bus, zero, self->jdi_display ? 2 : 1);
// set chip select low
common_hal_digitalio_digitalinout_set_value(&self->chip_select, false);
@ -191,7 +213,13 @@ STATIC void sharpdisplay_framebuffer_get_bufinfo(mp_obj_t self_in, mp_buffer_inf
}
STATIC int sharpdisplay_framebuffer_get_color_depth(mp_obj_t self_in) {
return 1;
sharpdisplay_framebuffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
return self->jdi_display ? 4 : 1;
}
STATIC bool sharpdisplay_framebuffer_get_grayscale(mp_obj_t self_in) {
sharpdisplay_framebuffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
return !self->jdi_display;
}
STATIC int sharpdisplay_framebuffer_get_height(mp_obj_t self_in) {
@ -234,6 +262,7 @@ const framebuffer_p_t sharpdisplay_framebuffer_proto = {
.deinit = sharpdisplay_framebuffer_deinit,
.get_bufinfo = sharpdisplay_framebuffer_get_bufinfo,
.get_color_depth = sharpdisplay_framebuffer_get_color_depth,
.get_grayscale = sharpdisplay_framebuffer_get_grayscale,
.get_height = sharpdisplay_framebuffer_get_height,
.get_width = sharpdisplay_framebuffer_get_width,
.swapbuffers = sharpdisplay_framebuffer_swapbuffers,

View File

@ -41,19 +41,10 @@ typedef struct {
uint16_t width, height;
uint32_t baudrate;
bool full_refresh : 1;
bool full_refresh;
bool jdi_display;
} sharpdisplay_framebuffer_obj_t;
void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_t *self, busio_spi_obj_t *spi, const mcu_pin_obj_t *chip_select, int baudrate, int width, int height);
void common_hal_sharpdisplay_framebuffer_swap_buffers(sharpdisplay_framebuffer_obj_t *self, uint8_t *dirty_row_bitmask);
void common_hal_sharpdisplay_framebuffer_deinit(sharpdisplay_framebuffer_obj_t *self);
void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_obj_t *self, mp_buffer_info_t *bufinfo);
int common_hal_sharpdisplay_framebuffer_get_height(sharpdisplay_framebuffer_obj_t *self);
int common_hal_sharpdisplay_framebuffer_get_width(sharpdisplay_framebuffer_obj_t *self);
void common_hal_sharpdisplay_framebuffer_swap_buffers(sharpdisplay_framebuffer_obj_t *self, uint8_t *dirty_row_bitmask);
void common_hal_sharpdisplay_framebuffer_reset(sharpdisplay_framebuffer_obj_t *self);
void common_hal_sharpdisplay_framebuffer_reconstruct(sharpdisplay_framebuffer_obj_t *self);
extern const framebuffer_p_t sharpdisplay_framebuffer_proto;
void common_hal_sharpdisplay_framebuffer_collect_ptrs(sharpdisplay_framebuffer_obj_t *);

View File

@ -406,7 +406,7 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ
if (self->pixel_shader == mp_const_none) {
output_pixel.pixel = input_pixel.pixel;
} else if (mp_obj_is_type(self->pixel_shader, &displayio_palette_type)) {
output_pixel.opaque = displayio_palette_get_color(self->pixel_shader, colorspace, input_pixel.pixel, &output_pixel.pixel);
displayio_palette_get_color(self->pixel_shader, colorspace, &input_pixel, &output_pixel);
} else if (mp_obj_is_type(self->pixel_shader, &displayio_colorconverter_type)) {
displayio_colorconverter_convert(self->pixel_shader, colorspace, &input_pixel, &output_pixel);
}

View File

@ -90,7 +90,11 @@ void port_interrupt_after_ticks(uint32_t ticks);
// may not be a system level sleep.
void port_idle_until_interrupt(void);
// Execute port specific actions during background tasks.
// Execute port specific actions during background tick. Only if ticks are enabled.
void port_background_tick(void);
// Execute port specific actions during background tasks. This is before the
// background callback system.
void port_background_task(void);
// Take port specific actions at the beginning and end of background tasks.

View File

@ -74,6 +74,7 @@ bool PLACE_IN_ITCM(background_callback_pending)(void) {
static bool in_background_callback;
void PLACE_IN_ITCM(background_callback_run_all)() {
port_background_task();
if (!background_callback_pending()) {
return;
}

View File

@ -158,7 +158,7 @@ STATIC void supervisor_bluetooth_start_advertising(void) {
_private_advertising = true;
// Advertise with less power when doing so publicly to reduce who can hear us. This will make it
// harder for someone with bad intentions to pair from a distance.
if (!bonded) {
if (!bonded || boot_in_discovery_mode) {
tx_power = -20;
adv = public_advertising_data;
adv_len = sizeof(public_advertising_data);
@ -179,7 +179,7 @@ STATIC void supervisor_bluetooth_start_advertising(void) {
}
uint32_t status = _common_hal_bleio_adapter_start_advertising(&common_hal_bleio_adapter_obj,
true,
bonded, // Advertise anonymously if we are bonded
_private_advertising, // Advertise anonymously if we are privately advertising
timeout,
interval,
adv,

View File

@ -159,6 +159,14 @@ void supervisor_stop_terminal(void) {
#endif
}
bool supervisor_terminal_started(void) {
#if CIRCUITPY_TERMINALIO
return tilegrid_tiles != NULL;
#else
return false;
#endif
}
void supervisor_display_move_memory(void) {
#if CIRCUITPY_TERMINALIO
displayio_tilegrid_t *scroll_area = &supervisor_terminal_scroll_area_text_grid;

View File

@ -54,6 +54,7 @@ extern displayio_tilegrid_t supervisor_blinka_sprite;
void supervisor_start_terminal(uint16_t width_px, uint16_t height_px);
void supervisor_stop_terminal(void);
bool supervisor_terminal_started(void);
void supervisor_display_move_memory(void);

View File

@ -192,6 +192,12 @@ bool serial_connected(void) {
}
#endif
#if CIRCUITPY_TERMINALIO
if (supervisor_terminal_started()) {
return true;
}
#endif
if (port_serial_connected()) {
return true;

View File

@ -66,13 +66,20 @@ for board in build_boards:
if clean_build:
build_dir += "-{language}".format(language=language)
extensions = [
extension.strip()
for extension in board_settings["CIRCUITPY_BUILD_EXTENSIONS"].split(",")
]
artifacts = [os.path.join(build_dir, "firmware." + extension) for extension in extensions]
make_result = subprocess.run(
"make -C ../ports/{port} TRANSLATION={language} BOARD={board} BUILD={build} -j {cores}".format(
"make -C ../ports/{port} TRANSLATION={language} BOARD={board} BUILD={build} -j {cores} {artifacts}".format(
port=board_info["port"],
language=language,
board=board,
build=build_dir,
cores=cores,
artifacts=" ".join(artifacts),
),
shell=True,
stdout=subprocess.PIPE,
@ -86,10 +93,6 @@ for board in build_boards:
success = "\033[31mfailed\033[0m"
other_output = ""
extensions = [
extension.strip()
for extension in board_settings["CIRCUITPY_BUILD_EXTENSIONS"].split(",")
]
for extension in extensions:
temp_filename = "../ports/{port}/{build}/firmware.{extension}".format(

View File

@ -42,14 +42,14 @@ from shared_bindings_matrix import (
all_ports_all_boards,
)
PORT_TO_ARCH = {
PORT_TO_BUILD_JOB = {
"atmel-samd": "arm",
"broadcom": "aarch",
"cxd56": "arm",
"espressif": "esp",
"litex": "riscv",
"mimxrt10xx": "arm",
"nrf": "arm",
"nrf": "nrf",
"raspberrypi": "rpi",
"stm": "arm",
}
@ -203,14 +203,14 @@ def set_boards_to_build(build_all: bool):
boards_to_build = all_board_ids
break
# Split boards by architecture.
arch_to_boards = {"aarch": [], "arm": [], "esp": [], "riscv": [], "rpi": []}
# Split boards by build job.
build_job_to_boards = {"aarch": [], "arm": [], "esp": [], "nrf": [], "riscv": [], "rpi": []}
# Append previously failed boards
for arch in arch_to_boards:
arch_to_job = f"build-{arch}"
if arch_to_job in last_failed_jobs:
for board in last_failed_jobs[arch_to_job]:
for build_job in build_job_to_boards:
job_name = f"build-{build_job}"
if job_name in last_failed_jobs:
for board in last_failed_jobs[job_name]:
if not board in boards_to_build:
boards_to_build.append(board)
@ -225,12 +225,12 @@ def set_boards_to_build(build_all: bool):
# if this happens it's not in `board_to_port`.
if not port:
continue
arch_to_boards[PORT_TO_ARCH[port]].append(board)
build_job_to_boards[PORT_TO_BUILD_JOB[port]].append(board)
print(" ", board)
# Set the step outputs for each architecture
for arch in arch_to_boards:
set_output(f"boards-{arch}", json.dumps(arch_to_boards[arch]))
for build_job in build_job_to_boards:
set_output(f"boards-{build_job}", json.dumps(build_job_to_boards[build_job]))
def set_docs_to_build(build_doc: bool):

View File

@ -180,51 +180,25 @@ displayio_bitmap_t blinka_bitmap = {{
_displayio_color_t blinka_colors[7] = {{
{{
.rgb888 = 0x000000,
.rgb565 = 0x0000,
.luma = 0x00,
.chroma = 0,
.transparent = true
}},
{{
.rgb888 = 0x8428bc,
.rgb565 = 0x8978,
.luma = 0xff, // We cheat the luma here. It is actually 0x60
.hue = 184,
.chroma = 148
{{ // Purple
.rgb888 = 0x8428bc
}},
{{
.rgb888 = 0xff89bc,
.rgb565 = 0xFCB8,
.luma = 0xb5,
.hue = 222,
.chroma = 118
{{ // Pink
.rgb888 = 0xff89bc
}},
{{
.rgb888 = 0x7beffe,
.rgb565 = 0x869F,
.luma = 0xe0,
.hue = 124,
.chroma = 131
{{ // Light blue
.rgb888 = 0x7beffe
}},
{{
.rgb888 = 0x51395f,
.rgb565 = 0x5A0D,
.luma = 0x47,
.hue = 185,
.chroma = 38
{{ // Dark purple
.rgb888 = 0x51395f
}},
{{
.rgb888 = 0xffffff,
.rgb565 = 0xffff,
.luma = 0xff,
.chroma = 0
{{ // White
.rgb888 = 0xffffff
}},
{{
.rgb888 = 0x0736a0,
.rgb565 = 0x01f5,
.luma = 0x44,
.hue = 147,
.chroma = 153
{{ // Dark Blue
.rgb888 = 0x0736a0
}},
}};
@ -270,16 +244,10 @@ c_file.write(
#if CIRCUITPY_TERMINALIO
_displayio_color_t terminal_colors[2] = {
{
.rgb888 = 0x000000,
.rgb565 = 0x0000,
.luma = 0x00,
.chroma = 0
.rgb888 = 0x000000
},
{
.rgb888 = 0xffffff,
.rgb565 = 0xffff,
.luma = 0xff,
.chroma = 0
.rgb888 = 0xffffff
},
};