External fourwire works and blinka splash after

This commit is contained in:
Scott Shawcroft 2019-01-17 00:20:16 -08:00
parent 05d8885a1a
commit 84292ad890
No known key found for this signature in database
GPG Key ID: FD0EDC4B6C53CA59
18 changed files with 253 additions and 80 deletions

2
main.c
View File

@ -201,7 +201,7 @@ bool run_code_py(safe_mode_t safe_mode) {
}
}
// Turn off the display before the heap disappears.
reset_primary_display();
reset_displays();
stop_mp();
free_memory(heap);

View File

@ -44,7 +44,7 @@ void run_background_tasks(void) {
audio_dma_background();
#endif
#ifdef CIRCUITPY_DISPLAYIO
displayio_refresh_display();
displayio_refresh_displays();
#endif
#if MICROPY_PY_NETWORK

View File

@ -46,3 +46,5 @@
#define IGNORE_PIN_PA25 1
#define CIRCUITPY_I2CSLAVE
#define CIRCUITPY_DISPLAYIO (1)
#define CIRCUITPY_DISPLAY_LIMIT (3)

View File

@ -1,6 +1,6 @@
#include "shared-bindings/board/__init__.h"
#include "board_busses.h"
#include "supervisor/shared/board_busses.h"
// This mapping only includes functional names because pins broken
// out on connectors are labeled with their MCU name available from

View File

@ -13,7 +13,7 @@
// QSPI Data pins
#define MICROPY_PORT_A ( PORT_PA08 | PORT_PA09 | PORT_PA10 | PORT_PA11 )
// QSPI CS, and QSPI SCK
#define MICROPY_PORT_B ( PORT_PB10 | PORT_PB11 )
#define MICROPY_PORT_B ( PORT_PB10 | PORT_PB11 | PORT_PB22 )
#define MICROPY_PORT_C ( 0 )
#define MICROPY_PORT_D (0)

View File

@ -1,7 +1,7 @@
#include "shared-bindings/board/__init__.h"
#include "boards/board.h"
#include "board_busses.h"
#include "supervisor/shared/board_busses.h"
// This mapping only includes functional names because pins broken
// out on connectors are labeled with their MCU name available from
@ -72,7 +72,5 @@ STATIC const mp_map_elem_t board_global_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&board_display_obj)}
};
MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);

View File

@ -54,6 +54,17 @@ void never_reset_sercom(Sercom* sercom) {
}
}
void allow_reset_sercom(Sercom* sercom) {
// Reset all SERCOMs except the ones being used by on-board devices.
Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS;
for (int i = 0; i < SERCOM_INST_NUM; i++) {
if (sercom_instances[i] == sercom) {
never_reset_sercoms[i] = false;
break;
}
}
}
void reset_sercoms(void) {
// Reset all SERCOMs except the ones being used by on-board devices.
Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS;
@ -235,6 +246,8 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) {
if (common_hal_busio_spi_deinited(self)) {
return;
}
allow_reset_sercom(self->spi_desc.dev.prvt);
spi_m_sync_disable(&self->spi_desc);
spi_m_sync_deinit(&self->spi_desc);
reset_pin_number(self->clock_pin);

View File

@ -53,6 +53,16 @@ void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t* self,
never_reset_pin_number(reset->number);
}
void common_hal_displayio_fourwire_deinit(displayio_fourwire_obj_t* self) {
if (self->bus == &self->inline_bus) {
common_hal_busio_spi_deinit(self->bus);
}
reset_pin_number(self->command.pin->number);
reset_pin_number(self->chip_select.pin->number);
reset_pin_number(self->reset.pin->number);
}
bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t obj) {
displayio_fourwire_obj_t* self = MP_OBJ_TO_PTR(obj);
if (!common_hal_busio_spi_try_lock(self->bus)) {

View File

@ -34,6 +34,7 @@
typedef struct {
mp_obj_base_t base;
busio_spi_obj_t* bus;
busio_spi_obj_t inline_bus;
digitalio_digitalinout_obj_t command;
digitalio_digitalinout_obj_t chip_select;
digitalio_digitalinout_obj_t reset;

View File

@ -100,6 +100,8 @@ void never_reset_pin_number(uint8_t pin_number) {
}
void reset_pin_number(uint8_t pin_number) {
never_reset_pins[GPIO_PORT(pin_number)] &= ~(1 << GPIO_PIN(pin_number));
if (pin_number >= PORT_BITS) {
return;
}

View File

@ -40,18 +40,19 @@
//| .. currentmodule:: displayio
//|
//| :class:`FourWire` -- Manage updating a display over SPI four wire protocol
//| :class:`Display` -- Manage updating a display over a display bus
//| ==========================================================================
//|
//| Manage updating a display over SPI four wire protocol in the background while Python code runs.
//| It doesn't handle display initialization.
//| 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.
//|
//| .. warning:: This will be changed before 4.0.0. Consider it very experimental.
//|
//| .. class:: Display(display_bus, *, width, height, colstart=0, rowstart=0, color_depth=16,
//| set_column_command=0x2a set_row_command=0x2b, write_ram_command=0x2c)
//|
//| Create a FourWire object associated with the given pins.
//| Create a Display object.
//|
STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_color_depth, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command };
@ -80,11 +81,15 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[ARG_init_sequence].u_obj, &bufinfo, MP_BUFFER_READ);
displayio_display_obj_t *self;
if (display_bus == &primary_display.fourwire_bus) {
self = &primary_display.display;
} else {
self = m_new_obj(displayio_display_obj_t);
displayio_display_obj_t *self = NULL;
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
if (displays[i].display.base.type == NULL) {
self = &displays[i].display;
break;
}
}
if (self == NULL) {
mp_raise_RuntimeError(translate("Display limit reached"));
}
self->base.type = &displayio_display_type;
common_hal_displayio_display_construct(self,

View File

@ -69,18 +69,21 @@ STATIC mp_obj_t displayio_fourwire_make_new(const mp_obj_type_t *type, size_t n_
if (command == mp_const_none || chip_select == mp_const_none) {
mp_raise_ValueError(translate("Command and chip_select required"));
}
assert_pin_free(command);
assert_pin_free(chip_select);
assert_pin_free(reset);
displayio_fourwire_obj_t* self;
displayio_fourwire_obj_t* self = NULL;
mp_obj_t spi = args[ARG_spi_bus].u_obj;
if (board_spi() == spi && primary_display.bus_type == NULL) {
self = &primary_display.fourwire_bus;
primary_display.bus_type = &displayio_fourwire_type;
} else {
// TODO(tannewt): Always check pin free. For now we ignore the primary display.
assert_pin_free(command);
assert_pin_free(chip_select);
assert_pin_free(reset);
self = m_new_obj(displayio_fourwire_obj_t);
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
if (displays[i].fourwire_bus.base.type== NULL) {
self = &displays[i].fourwire_bus;
self->base.type = &displayio_fourwire_type;
break;
}
}
if (self == NULL) {
mp_raise_RuntimeError(translate("Display bus limit reached"));
}
common_hal_displayio_fourwire_construct(self,

View File

@ -39,6 +39,8 @@ void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t* self,
busio_spi_obj_t* spi, const mcu_pin_obj_t* command,
const mcu_pin_obj_t* chip_select, const mcu_pin_obj_t* reset);
void common_hal_displayio_fourwire_deinit(displayio_fourwire_obj_t* self);
bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t self);
void common_hal_displayio_fourwire_send(mp_obj_t self, bool command, uint8_t *data, uint32_t data_length);

View File

@ -38,6 +38,8 @@ void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t* sel
const mcu_pin_obj_t* data0, const mcu_pin_obj_t* command,
const mcu_pin_obj_t* chip_select, const mcu_pin_obj_t* reset, const mcu_pin_obj_t* write);
void common_hal_displayio_parallelbus_deinit(displayio_parallelbus_obj_t* self);
bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t self);
void common_hal_displayio_parallelbus_send(mp_obj_t self, bool command, uint8_t *data, uint32_t data_length);

View File

@ -32,6 +32,7 @@
#include "shared-bindings/displayio/__init__.h"
#include "shared-bindings/displayio/Bitmap.h"
#include "shared-bindings/displayio/ColorConverter.h"
#include "shared-bindings/displayio/Display.h"
#include "shared-bindings/displayio/FourWire.h"
#include "shared-bindings/displayio/Group.h"
#include "shared-bindings/displayio/OnDiskBitmap.h"
@ -61,6 +62,7 @@
//|
//| Bitmap
//| ColorConverter
//| Display
//| FourWire
//| Group
//| OnDiskBitmap
@ -71,10 +73,22 @@
//| All libraries change hardware state but are never deinit
//|
//| .. method:: release_displays()
//|
//| Releases any actively used displays so theis pins can be used again.
//|
STATIC mp_obj_t displayio_release_displays(void) {
common_hal_displayio_release_displays();
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(displayio_release_displays_obj, displayio_release_displays);
STATIC const mp_rom_map_elem_t displayio_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_displayio) },
{ MP_ROM_QSTR(MP_QSTR_Bitmap), MP_ROM_PTR(&displayio_bitmap_type) },
{ MP_ROM_QSTR(MP_QSTR_ColorConverter), MP_ROM_PTR(&displayio_colorconverter_type) },
{ MP_ROM_QSTR(MP_QSTR_Display), MP_ROM_PTR(&displayio_display_type) },
{ MP_ROM_QSTR(MP_QSTR_Group), MP_ROM_PTR(&displayio_group_type) },
{ MP_ROM_QSTR(MP_QSTR_OnDiskBitmap), MP_ROM_PTR(&displayio_ondiskbitmap_type) },
{ MP_ROM_QSTR(MP_QSTR_Palette), MP_ROM_PTR(&displayio_palette_type) },
@ -82,6 +96,8 @@ STATIC const mp_rom_map_elem_t displayio_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_Sprite), MP_ROM_PTR(&displayio_sprite_type) },
{ MP_ROM_QSTR(MP_QSTR_FourWire), MP_ROM_PTR(&displayio_fourwire_type) },
{ MP_ROM_QSTR(MP_QSTR_release_displays), MP_ROM_PTR(&displayio_release_displays_obj) },
};
STATIC MP_DEFINE_CONST_DICT(displayio_module_globals, displayio_module_globals_table);

View File

@ -27,8 +27,6 @@
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO___INIT___H
#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO___INIT___H
#include "py/obj.h"
// Nothing now.
void common_hal_displayio_release_displays(void);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO___INIT___H

View File

@ -1,68 +1,190 @@
#include <string.h>
#include "shared-module/displayio/__init__.h"
#include "shared-bindings/displayio/Bitmap.h"
#include "shared-bindings/displayio/Display.h"
#include "shared-bindings/displayio/Group.h"
#include "shared-bindings/displayio/Palette.h"
#include "shared-bindings/displayio/Sprite.h"
primary_display_t primary_display;
primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT];
void displayio_refresh_display(void) {
displayio_display_obj_t* display = &primary_display.display;
void displayio_refresh_displays(void) {
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
if (displays[i].display.base.type == NULL) {
continue;
}
displayio_display_obj_t* display = &displays[i].display;
if (!displayio_display_frame_queued(display)) {
return;
if (!displayio_display_frame_queued(display)) {
return;
}
if (displayio_display_refresh_queued(display)) {
PORT->Group[1].DIRSET.reg = 1 << 22;
// We compute the pixels
uint16_t x0 = 0;
uint16_t y0 = 0;
uint16_t x1 = display->width;
uint16_t y1 = display->height;
size_t index = 0;
//size_t row_size = (x1 - x0);
uint16_t buffer_size = 256;
uint32_t buffer[buffer_size / 2];
displayio_display_start_region_update(display, x0, y0, x1, y1);
for (uint16_t y = y0; y < y1; ++y) {
for (uint16_t x = x0; x < x1; ++x) {
uint16_t* pixel = &(((uint16_t*)buffer)[index]);
*pixel = 0;
PORT->Group[1].OUTTGL.reg = 1 << 22;
//if (index == 0) {
if (display->current_group != NULL) {
displayio_group_get_pixel(display->current_group, x, y, pixel);
}
// } else {
// *pixel = (((uint16_t*)buffer)[0]);
// }
PORT->Group[1].OUTTGL.reg = 1 << 22;
index += 1;
// The buffer is full, send it.
if (index >= buffer_size) {
if (!displayio_display_send_pixels(display, buffer, buffer_size / 2)) {
displayio_display_finish_region_update(display);
return;
}
index = 0;
}
}
}
// Send the remaining data.
if (index && !displayio_display_send_pixels(display, buffer, index * 2)) {
displayio_display_finish_region_update(display);
return;
}
displayio_display_finish_region_update(display);
}
displayio_display_finish_refresh(display);
}
if (displayio_display_refresh_queued(display)) {
PORT->Group[1].DIRSET.reg = 1 << 22;
}
// We compute the pixels
uint16_t x0 = 0;
uint16_t y0 = 0;
uint16_t x1 = display->width;
uint16_t y1 = display->height;
size_t index = 0;
//size_t row_size = (x1 - x0);
uint16_t buffer_size = 256;
uint32_t buffer[buffer_size / 2];
displayio_display_start_region_update(display, x0, y0, x1, y1);
for (uint16_t y = y0; y < y1; ++y) {
for (uint16_t x = x0; x < x1; ++x) {
uint16_t* pixel = &(((uint16_t*)buffer)[index]);
*pixel = 0;
uint32_t blinka_bitmap_data[32] = {
0x00000011, 0x11000000,
0x00000111, 0x53100000,
0x00000111, 0x56110000,
0x00000111, 0x11140000,
0x00000111, 0x20002000,
0x00000011, 0x13000000,
0x00000001, 0x11200000,
0x00000000, 0x11330000,
0x00000000, 0x01122000,
0x00001111, 0x44133000,
0x00032323, 0x24112200,
0x00111114, 0x44113300,
0x00323232, 0x34112200,
0x11111144, 0x44443300,
0x11111111, 0x11144401,
0x23232323, 0x21111110
};
PORT->Group[1].OUTTGL.reg = 1 << 22;
displayio_bitmap_t blinka_bitmap = {
.base = {.type = &displayio_bitmap_type },
.width = 16,
.height = 16,
.data = blinka_bitmap_data,
.stride = 2,
.bits_per_value = 4,
.x_shift = 3,
.x_mask = 0x7,
.bitmask = 0xf
};
//if (index == 0) {
if (display->current_group != NULL) {
displayio_group_get_pixel(display->current_group, x, y, pixel);
}
// } else {
// *pixel = (((uint16_t*)buffer)[0]);
// }
uint32_t blinka_transparency[1] = {0x80000000};
uint32_t blinka_colors[8] = {0x1e910000, 0x72dc722b, 0xffffb05a, 0x00000000,
0x80000000, 0x00000000, 0x00000000, 0x00000000};
displayio_palette_t blinka_palette = {
.base = {.type = &displayio_palette_type },
.opaque = blinka_transparency,
.colors = blinka_colors,
.color_count = 16,
.needs_refresh = false
};
PORT->Group[1].OUTTGL.reg = 1 << 22;
displayio_sprite_t blinka_sprite = {
.base = {.type = &displayio_sprite_type },
.bitmap = &blinka_bitmap,
.pixel_shader = &blinka_palette,
.x = 0,
.y = 0,
.width = 16,
.height = 16,
.needs_refresh = false
};
index += 1;
// The buffer is full, send it.
if (index >= buffer_size) {
if (!displayio_display_send_pixels(display, buffer, buffer_size / 2)) {
displayio_display_finish_region_update(display);
return;
}
index = 0;
mp_obj_t splash_children[1] = {
&blinka_sprite,
};
displayio_group_t splash = {
.base = {.type = &displayio_group_type },
.x = 0,
.y = 0,
.size = 1,
.max_size = 1,
.children = splash_children,
.needs_refresh = true
};
void reset_displays(void) {
// The SPI buses used by FourWires may be allocated on the heap so we need to move them inline.
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
if (displays[i].fourwire_bus.base.type != &displayio_fourwire_type) {
continue;
}
displayio_fourwire_obj_t* fourwire = &displays[i].fourwire_bus;
if (((uint32_t) fourwire->bus) < ((uint32_t) &displays) ||
((uint32_t) fourwire->bus) > ((uint32_t) &displays + CIRCUITPY_DISPLAY_LIMIT)) {
busio_spi_obj_t* original_spi = fourwire->bus;
memcpy(&fourwire->inline_bus, original_spi, sizeof(busio_spi_obj_t));
fourwire->bus = &fourwire->inline_bus;
// Check for other displays that use the same spi bus and swap them too.
for (uint8_t j = i + 1; j < CIRCUITPY_DISPLAY_LIMIT; j++) {
if (displays[i].fourwire_bus.bus == original_spi) {
displays[i].fourwire_bus.bus = &fourwire->inline_bus;
}
}
}
// Send the remaining data.
if (index && !displayio_display_send_pixels(display, buffer, index * 2)) {
displayio_display_finish_region_update(display);
return;
}
displayio_display_finish_region_update(display);
}
displayio_display_finish_refresh(display);
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
if (displays[i].display.base.type == NULL) {
continue;
}
displayio_display_obj_t* display = &displays[i].display;
common_hal_displayio_display_show(display, &splash);
}
}
void reset_primary_display(void) {
common_hal_displayio_display_show(&primary_display.display, NULL);
void common_hal_displayio_release_displays(void) {
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
mp_const_obj_t bus_type = displays[i].fourwire_bus.base.type;
if (bus_type == NULL) {
continue;
} else if (bus_type == &displayio_fourwire_type) {
common_hal_displayio_fourwire_deinit(&displays[i].fourwire_bus);
} else if (bus_type == &displayio_parallelbus_type) {
//common_hal_displayio_parallelbus_deinit(&displays[i].parallel_bus);
}
displays[i].fourwire_bus.base.type = NULL;
}
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
displays[i].display.base.type = NULL;
}
// TODO(tannewt): Clear the display datastructures and release everything used.
}

View File

@ -36,13 +36,12 @@ typedef struct {
displayio_fourwire_obj_t fourwire_bus;
displayio_parallelbus_obj_t parallel_bus;
};
mp_const_obj_t bus_type;
displayio_display_obj_t display;
} primary_display_t;
extern primary_display_t primary_display;
extern primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT];
void displayio_refresh_display(void);
void reset_primary_display(void);
void displayio_refresh_displays(void);
void reset_displays(void);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO___INIT___H