Skip to content

Commit

Permalink
Add Pimoroni Inky Frame 5.7
Browse files Browse the repository at this point in the history
Tweak DTCM and ITCM loading and prevent epd refresh while waiting
for autoreload.
  • Loading branch information
tannewt committed May 11, 2023
1 parent 750615f commit cbfb2d0
Show file tree
Hide file tree
Showing 9 changed files with 224 additions and 14 deletions.
4 changes: 3 additions & 1 deletion main.c
Original file line number Diff line number Diff line change
Expand Up @@ -666,8 +666,10 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool *simulate_reset) {
#endif
{
// Refresh the ePaper display if we have one. That way it'll show an error message.
// Skip if we're about to autoreload. Otherwise we may delay when user code can update
// the display.
#if CIRCUITPY_DISPLAYIO
if (time_to_epaper_refresh > 0) {
if (time_to_epaper_refresh > 0 && !autoreload_pending()) {
time_to_epaper_refresh = maybe_refresh_epaperdisplay();
}

Expand Down
114 changes: 114 additions & 0 deletions ports/raspberrypi/boards/pimoroni_inky_frame_5_7/board.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 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 "mpconfigboard.h"
#include "shared-bindings/busio/SPI.h"
#include "shared-bindings/displayio/FourWire.h"
#include "shared-bindings/microcontroller/Pin.h"
#include "shared-module/displayio/__init__.h"
#include "shared-bindings/board/__init__.h"
#include "supervisor/shared/board.h"

#define DELAY 0x80

// This is an SPD1656 control chip. The display is a 5.7" ACeP EInk.

const uint8_t display_start_sequence[] = {
0x01, 4, 0x37, 0x00, 0x23, 0x23, // power setting
0x00, 2, 0xef, 0x08, // panel setting (PSR)
0x03, 1, 0x00, // PFS
0x06, 3, 0xc7, 0xc7, 0x1d, // booster
0x30, 1, 0x3c, // PLL setting
0x41, 1, 0x00, // TSE
0x50, 1, 0x37, // vcom and data interval setting
0x60, 1, 0x22, // tcon setting
0x61, 4, 0x02, 0x58, 0x01, 0xc0, // tres
0xe3, 1, 0xaa, // PWS
0x04, DELAY | 0, 0xc8, // VCM DC and delay 200ms
};

const uint8_t display_stop_sequence[] = {
0x02, 1, 0x00, // power off
0x07, 1, 0xa5 // deep sleep
};

const uint8_t refresh_sequence[] = {
0x12, 0x00
};

void board_init(void) {
displayio_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = common_hal_board_create_spi(0);

bus->base.type = &displayio_fourwire_type;
common_hal_displayio_fourwire_construct(bus,
spi,
&pin_GPIO28, // EPD_DC Command or data
&pin_GPIO17, // EPD_CS Chip select
&pin_GPIO27, // EPD_RST Reset
1000000, // Baudrate
0, // Polarity
0); // Phase

displayio_epaperdisplay_obj_t *display = &allocate_display()->epaper_display;
display->base.type = &displayio_epaperdisplay_type;
common_hal_displayio_epaperdisplay_construct(
display,
bus,
display_start_sequence, sizeof(display_start_sequence),
1.0, // start up time
display_stop_sequence, sizeof(display_stop_sequence),
600, // width
448, // height
640, // ram_width
480, // ram_height
0, // colstart
0, // rowstart
180, // rotation
NO_COMMAND, // set_column_window_command
NO_COMMAND, // set_row_window_command
NO_COMMAND, // set_current_column_command
NO_COMMAND, // set_current_row_command
0x10, // write_black_ram_command
false, // black_bits_inverted
NO_COMMAND, // write_color_ram_command
false, // color_bits_inverted
0x000000, // highlight_color
refresh_sequence, sizeof(refresh_sequence),
28.0, // refresh_time
NULL, // busy_pin
false, // busy_state
30.0, // seconds_per_frame
false, // always_toggle_chip_select
false, // grayscale
true, // acep
false, // two_byte_sequence_length
false); // address_little_endian
}

// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here.
1 change: 1 addition & 0 deletions ports/raspberrypi/boards/pimoroni_inky_frame_5_7/link.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
firmware_size = 1532k;
17 changes: 17 additions & 0 deletions ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#define MICROPY_HW_BOARD_NAME "Pimoroni Inky Frame 5.7"
#define MICROPY_HW_MCU_NAME "rp2040"

#define CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL (1)
#define CIRCUITPY_DIGITALIO_HAVE_INVALID_DRIVE_MODE (1)

#define MICROPY_HW_LED_STATUS (&pin_GPIO6)

#define DEFAULT_I2C_BUS_SCL (&pin_GPIO4)
#define DEFAULT_I2C_BUS_SDA (&pin_GPIO5)

#define DEFAULT_UART_BUS_TX (&pin_GPIO0)
#define DEFAULT_UART_BUS_RX (&pin_GPIO1)

#define DEFAULT_SPI_BUS_SCK (&pin_GPIO18)
#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO19)
#define DEFAULT_SPI_BUS_MISO (&pin_GPIO16)
26 changes: 26 additions & 0 deletions ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
USB_VID = 0x2E8A
USB_PID = 0x1018
USB_PRODUCT = "Inky Frame 5.7"
USB_MANUFACTURER = "Pimoroni"

CHIP_VARIANT = RP2040
CHIP_FAMILY = rp2

EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ"

CIRCUITPY__EVE = 1

CIRCUITPY_CYW43 = 1
CIRCUITPY_SSL = 1
CIRCUITPY_SSL_MBEDTLS = 1
CIRCUITPY_HASHLIB = 1
CIRCUITPY_WEB_WORKFLOW = 1
CIRCUITPY_MDNS = 1
CIRCUITPY_SOCKETPOOL = 1
CIRCUITPY_WIFI = 1

CFLAGS += -DCYW43_PIN_WL_HOST_WAKE=24 -DCYW43_PIN_WL_REG_ON=23 -DCYW43_WL_GPIO_COUNT=3 -DCYW43_WL_GPIO_LED_PIN=0
# Must be accompanied by a linker script change
CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)'

FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Put board-specific pico-sdk definitions here. This file must exist.
52 changes: 52 additions & 0 deletions ports/raspberrypi/boards/pimoroni_inky_frame_5_7/pins.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#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_TX), MP_ROM_PTR(&pin_GPIO0) },
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO1) },
{ MP_ROM_QSTR(MP_QSTR_HOLD_SYS_EN), MP_ROM_PTR(&pin_GPIO2) },
{ MP_ROM_QSTR(MP_QSTR_I2C_INT), MP_ROM_PTR(&pin_GPIO3) },

{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) },
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) },

{ MP_ROM_QSTR(MP_QSTR_LED_ACT), MP_ROM_PTR(&pin_GPIO6) },
{ MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO6) },
{ MP_ROM_QSTR(MP_QSTR_LED_CONN), MP_ROM_PTR(&pin_GPIO7) },
{ MP_ROM_QSTR(MP_QSTR_SWITCH_CLK), MP_ROM_PTR(&pin_GPIO8) },
{ MP_ROM_QSTR(MP_QSTR_SWITCH_LATCH), MP_ROM_PTR(&pin_GPIO9) },
{ MP_ROM_QSTR(MP_QSTR_SWITCH_OUT), MP_ROM_PTR(&pin_GPIO10) },
{ MP_ROM_QSTR(MP_QSTR_LED_A), MP_ROM_PTR(&pin_GPIO11) },
{ MP_ROM_QSTR(MP_QSTR_LED_B), MP_ROM_PTR(&pin_GPIO12) },
{ MP_ROM_QSTR(MP_QSTR_LED_C), MP_ROM_PTR(&pin_GPIO13) },
{ MP_ROM_QSTR(MP_QSTR_LED_D), MP_ROM_PTR(&pin_GPIO14) },
{ MP_ROM_QSTR(MP_QSTR_LED_E), MP_ROM_PTR(&pin_GPIO15) },

{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO16) },
{ MP_ROM_QSTR(MP_QSTR_INKY_CS), MP_ROM_PTR(&pin_GPIO17) },
{ MP_ROM_QSTR(MP_QSTR_SCLK), MP_ROM_PTR(&pin_GPIO18) },
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO19) },
{ MP_ROM_QSTR(MP_QSTR_SD_DAT1), MP_ROM_PTR(&pin_GPIO20) },
{ MP_ROM_QSTR(MP_QSTR_SD_DAT2), MP_ROM_PTR(&pin_GPIO21) },
{ MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO22) },

{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) },

{ MP_ROM_QSTR(MP_QSTR_INKY_RES), MP_ROM_PTR(&pin_GPIO27) },
{ MP_ROM_QSTR(MP_QSTR_INKY_DC), MP_ROM_PTR(&pin_GPIO28) },

{ MP_ROM_QSTR(MP_QSTR_SMPS_MODE), MP_ROM_PTR(&pin_CYW1) },
{ MP_ROM_QSTR(MP_QSTR_VBUS_SENSE), MP_ROM_PTR(&pin_CYW2) },

{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
{ MP_ROM_QSTR(MP_QSTR_STEMMA_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(&displays[0].epaper_display)},
};
MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);
17 changes: 9 additions & 8 deletions ports/raspberrypi/supervisor/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,22 +104,23 @@ safe_mode_t port_init(void) {
_binary_info();
// Set brown out.

// Load from the XIP memory space that doesn't cache. That way we don't
// evict anything else. The code we're loading is linked to the RAM address
// anyway.
size_t nocache = 0x03000000;

// Copy all of the "tightly coupled memory" code and data to run from RAM.
// This lets us use the 16k cache for dynamically used data and code.
// We must do this before we try and call any of its code or load the data.
uint32_t *itcm_flash_copy = (uint32_t *)(((size_t)&_ld_itcm_flash_copy) | nocache);
for (uint32_t i = 0; i < ((size_t)&_ld_itcm_size) / 4; i++) {
(&_ld_itcm_destination)[i] = (&_ld_itcm_flash_copy)[i];
// Now zero it out to evict the line from the XIP cache. Without this,
// it'll stay in the XIP cache anyway.
(&_ld_itcm_flash_copy)[i] = 0x0;
(&_ld_itcm_destination)[i] = itcm_flash_copy[i];
}

// Copy all of the data to run from DTCM.
uint32_t *dtcm_flash_copy = (uint32_t *)(((size_t)&_ld_dtcm_data_flash_copy) | nocache);
for (uint32_t i = 0; i < ((size_t)&_ld_dtcm_data_size) / 4; i++) {
(&_ld_dtcm_data_destination)[i] = (&_ld_dtcm_data_flash_copy)[i];
// Now zero it out to evict the line from the XIP cache. Without this,
// it'll stay in the XIP cache anyway.
(&_ld_dtcm_data_flash_copy)[i] = 0x0;
(&_ld_dtcm_data_destination)[i] = dtcm_flash_copy[i];
}

// Clear DTCM bss.
Expand Down
6 changes: 1 addition & 5 deletions tools/cortex-m-fault-gdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,8 @@ def _armv6m_fault(self):
print("vtor", hex(vtor))

icsr = self._read(ICSR)
if (icsr & (1 << 23)) != 0:
print("No preempted exceptions")
else:
print("Another exception was preempted")
vectactive = icsr & 0x1FF
print(hex(icsr), vectactive)
print("icsr", hex(icsr), vectactive)
if vectactive != 0:
if vectactive in EXCEPTIONS:
vectactive = EXCEPTIONS[vectactive]
Expand Down

2 comments on commit cbfb2d0

@dearmash
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick question, I've been tinkering with trying to get CPY to run on the inky 7_3, and just saw this come around. I'm more or less abandoning what I've done and I can start building on this instead.

I'm curious if the display is working for you on the 5_7? I've updated the init seq for 7.3 but still trying to iron things out.

@tannewt
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup! I'd suggest opening a draft PR and we can follow up there.

Please sign in to comment.