Merge pull request #319 from adafruit/add-slash-screen

Add slash screen
This commit is contained in:
Limor "Ladyada" Fried 2024-01-05 13:35:38 -05:00 committed by GitHub
commit 64d8e34567
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 757 additions and 55 deletions

View file

@ -1,4 +1,5 @@
cmake_minimum_required(VERSION 3.17)
find_package(Python COMPONENTS Interpreter)
if (NOT DEFINED BOARD)
message(FATAL_ERROR "BOARD is not defined")
@ -30,13 +31,14 @@ set(SDK ${CMAKE_CURRENT_LIST_DIR}/lib/sdk/components)
set(SOFTDEVICE ${CMAKE_CURRENT_LIST_DIR}/lib/softdevice)
set(TUSB ${CMAKE_CURRENT_LIST_DIR}/lib/tinyusb/src)
set(UF2CONV_PY ${CMAKE_CURRENT_LIST_DIR}/lib/uf2/utils/uf2conv.py)
set(UF2_FAMILY_ID_BOOTLOADER 0xd663823c)
#-------------------
# Bootloader
#-------------------
set(CMAKE_EXECUTABLE_SUFFIX .elf)
add_executable(bootloader)
#set_target_properties(bootloader PROPERTIES OUTPUT_NAME "${BOARD}_bootloader.elf")
# SD_VERSION can be overwritten by board.cmake
if(NOT DEFINED SD_VERSION)
@ -51,6 +53,8 @@ target_sources(bootloader PUBLIC
src/dfu_init.c
src/flash_nrf5x.c
src/main.c
src/screen.c
src/images.c
src/boards/boards.c
# nrfx
${NRFX}/drivers/src/nrfx_power.c
@ -112,10 +116,29 @@ target_include_directories(bootloader PUBLIC
${SOFTDEVICE}/mbr/headers
)
# Debug option
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
# TODO not work yet, also need to add segger rtt, DFU_APP_DATA_RESERVED=0, BOOTLOADER_REGION_START=0xED000
set(LD_FILE ${CMAKE_CURRENT_LIST_DIR}/linker/${MCU_VARIANT}_debug.ld)
message(FATAL_ERROR "Debug build not supported yet")
target_sources(bootloader PUBLIC
lib/SEGGER_RTT/RTT/SEGGER_RTT.c
)
target_include_directories(bootloader PUBLIC
lib/SEGGER_RTT/RTT
)
target_compile_definitions(bootloader PUBLIC
CFG_DEBUG
SEGGER_RTT_MODE_DEFAULT=SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL
DFU_APP_DATA_RESERVED=0
)
if (MCU_VARIANT STREQUAL "nrf52840")
target_compile_definitions(bootloader PUBLIC BOOTLOADER_REGION_START=0xEA000)
else ()
target_compile_definitions(bootloader PUBLIC BOOTLOADER_REGION_START=0x6D000)
endif ()
else ()
set(LD_FILE ${CMAKE_CURRENT_LIST_DIR}/linker/${MCU_VARIANT}.ld)
endif ()
@ -123,8 +146,7 @@ endif ()
target_link_options(bootloader PUBLIC
"LINKER:--script=${LD_FILE}"
-L${NRFX}/mdk
--specs=nosys.specs
--specs=nano.specs
--specs=nosys.specs --specs=nano.specs
)
target_compile_options(bootloader PUBLIC
-fno-builtin
@ -149,7 +171,6 @@ target_compile_options(bootloader PUBLIC
)
target_compile_definitions(bootloader PUBLIC
SOFTDEVICE_PRESENT
DFU_APP_DATA_RESERVED=7*4096
)
if (TRACE_ETM STREQUAL "1")
@ -195,6 +216,7 @@ endif ()
if (MCU_VARIANT STREQUAL "nrf52")
set(SD_NAME s132)
set(DFU_DEV_REV 0xADAF)
set(DFU_APP_DATA_RESERVED 7*4096)
target_compile_definitions(bootloader PUBLIC
NRF52
NRF52832_XXAA
@ -207,6 +229,7 @@ if (MCU_VARIANT STREQUAL "nrf52")
elseif (MCU_VARIANT STREQUAL "nrf52833")
set(SD_NAME s140)
set(DFU_DEV_REV 52833)
set(DFU_APP_DATA_RESERVED 7*4096)
target_compile_definitions(bootloader PUBLIC
NRF52833_XXAA
S140
@ -218,6 +241,8 @@ elseif (MCU_VARIANT STREQUAL "nrf52833")
elseif (MCU_VARIANT STREQUAL "nrf52840")
set(SD_NAME s140)
set(DFU_DEV_REV 52840)
# App reserved 40KB (8+32) to match circuitpython for 840
set(DFU_APP_DATA_RESERVED 10*4096)
target_compile_definitions(bootloader PUBLIC
NRF52840_XXAA
S140
@ -233,6 +258,10 @@ endif ()
set(SD_FILENAME ${SD_NAME}_nrf52_${SD_VERSION})
set(SD_HEX ${SOFTDEVICE}/${SD_FILENAME}/${SD_FILENAME}_softdevice.hex)
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_definitions(bootloader PUBLIC DFU_APP_DATA_RESERVED=${DFU_APP_DATA_RESERVED})
endif ()
#----------------------------------
# Get UF2 version from git
#----------------------------------
@ -257,12 +286,12 @@ math(EXPR MK_BOOTLOADER_VERSION "(${RELEASE_VERSION_MAJOR} << 16) + (${RELEASE_V
cmake_print_variables(GIT_VERSION GIT_SUBMODULE_VERSIONS MK_BOOTLOADER_VERSION)
target_compile_definitions(bootloader PUBLIC
UF2_VERSION_BASE="${GIT_VERSION}"
UF2_VERSION="${GIT_VERSION} - ${GIT_SUBMODULE_VERSIONS}"
BLEDIS_FW_VERSION="${GIT_VERSION} ${SD_NAME} ${SD_VERSION}"
MK_BOOTLOADER_VERSION=${MK_BOOTLOADER_VERSION}
)
#----------------------------------
# Post build
#----------------------------------
@ -276,6 +305,8 @@ add_custom_command(TARGET bootloader POST_BUILD
add_custom_command(TARGET bootloader POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:bootloader> $<TARGET_FILE_DIR:bootloader>/bootloader.bin
COMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:bootloader> $<TARGET_FILE_DIR:bootloader>/bootloader.hex
COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/tools/hexmerge.py --overlap=replace -o $<TARGET_FILE_DIR:bootloader>/bootloader_mbr.hex $<TARGET_FILE_DIR:bootloader>/bootloader.hex ${MBR_HEX}
COMMAND ${Python_EXECUTABLE} ${UF2CONV_PY} -f ${UF2_FAMILY_ID_BOOTLOADER} -c -o $<TARGET_FILE_DIR:bootloader>/bootloader_mbr.uf2 $<TARGET_FILE_DIR:bootloader>/bootloader_mbr.hex
VERBATIM)
#----------------------------------
@ -286,11 +317,16 @@ if (NOT DEFINED NRFJPROG)
set(NRFJPROG nrfjprog)
endif()
add_custom_target(flash
add_custom_target(flash-jlink
DEPENDS bootloader
COMMAND ${NRFJPROG} --program $<TARGET_FILE:bootloader> --verify --sectoranduicrerase -f nrf52 --reset
)
add_custom_target(flash-uf2
DEPENDS bootloader
COMMAND ${Python_EXECUTABLE} ${UF2CONV_PY} -f ${UF2_FAMILY_ID_BOOTLOADER} --deploy $<TARGET_FILE_DIR:bootloader>/bootloader_mbr.uf2
)
add_custom_target(flash-sd
COMMAND ${NRFJPROG} --program ${SD_HEX} --verify --sectorerase -f nrf52 --reset
)

View file

@ -123,7 +123,7 @@ else ifeq ($(MCU_SUB_VARIANT),nrf52840)
SD_NAME = s140
DFU_DEV_REV = 52840
CFLAGS += -DNRF52840_XXAA -DS140
# App reserved 40KB to match circuitpython for 840
# App reserved 40KB (8+32) to match circuitpython for 840
DFU_APP_DATA_RESERVED=10*4096
else
$(error Sub Variant $(MCU_SUB_VARIANT) is unknown)
@ -139,6 +139,8 @@ C_SRC += \
src/dfu_init.c \
src/flash_nrf5x.c \
src/main.c \
src/screen.c \
src/images.c \
# all files in boards
C_SRC += src/boards/boards.c
@ -314,6 +316,7 @@ ifneq ($(USE_NFCT),yes)
endif
CFLAGS += -DSOFTDEVICE_PRESENT
CFLAGS += -DUF2_VERSION_BASE='"$(GIT_VERSION)"'
CFLAGS += -DUF2_VERSION='"$(GIT_VERSION) $(GIT_SUBMODULE_VERSIONS)"'
CFLAGS += -DBLEDIS_FW_VERSION='"$(GIT_VERSION) $(SD_NAME) $(SD_VERSION)"'
@ -328,9 +331,9 @@ ifeq ($(DEBUG), 1)
C_SRC += $(RTT_SRC)/RTT/SEGGER_RTT.c
DFU_APP_DATA_RESERVED = 0
# expand bootloader address to 28KB of reserved app
# expand bootloader address to 28KB/40KB of reserved app
ifeq ($(MCU_SUB_VARIANT),nrf52840)
CFLAGS += -DBOOTLOADER_REGION_START=0xED000
CFLAGS += -DBOOTLOADER_REGION_START=0xEA000
else
CFLAGS += -DBOOTLOADER_REGION_START=0x6D000
endif

View file

@ -12,7 +12,7 @@ MEMORY
* APP_ERROR_CHECK_BOOL(*((uint32_t *)NRF_UICR_BOOT_START_ADDRESS) == BOOTLOADER_REGION_START);
*/
/* due to lack of flash for debug, we will use reserved app to extend bootloader size */
FLASH (rx) : ORIGIN = 0xF4000-28K, LENGTH = 0xFE000-0xF4000 - 2K + 28K /* 38 KB */
FLASH (rx) : ORIGIN = 0xF4000 - 40K, LENGTH = 0xFE000-0xF4000 - 2K + 40K /* 38 KB */
BOOTLOADER_CONFIG (r): ORIGIN = 0xFE000 - 2K, LENGTH = 2K

View file

@ -31,9 +31,6 @@
#include "nrf_spim.h"
#endif
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
#define SCHED_MAX_EVENT_DATA_SIZE sizeof(app_timer_event_t) /**< Maximum size of scheduler events. */
#define SCHED_QUEUE_SIZE 30 /**< Maximum number of events in the scheduler queue. */
@ -43,7 +40,16 @@ void neopixel_write(uint8_t* pixels);
void neopixel_teardown(void);
#endif
//------------- IMPLEMENTATION -------------//
//--------------------------------------------------------------------+
// IMPLEMENTATION
//--------------------------------------------------------------------+
static uint32_t _systick_count = 0;
void SysTick_Handler(void) {
_systick_count++;
led_tick();
}
void button_init(uint32_t pin) {
if (BUTTON_PULL == NRF_GPIO_PIN_PULLDOWN) {
nrf_gpio_cfg_sense_input(pin, BUTTON_PULL, NRF_GPIO_PIN_SENSE_HIGH);
@ -96,6 +102,7 @@ void board_init(void) {
#if ENABLE_DCDC_1 == 1
NRF_POWER->DCDCEN = 1;
#endif
// Make sure any custom inits are performed
board_init2();
@ -144,6 +151,10 @@ void board_teardown(void) {
neopixel_teardown();
#endif
#ifdef DISPLAY_PIN_SCK
board_display_teardown();
#endif
// Stop RTC1 used by app_timer
NVIC_DisableIRQ(RTC1_IRQn);
NRF_RTC1->EVTENCLR = RTC_EVTEN_COMPARE0_Msk;
@ -164,13 +175,122 @@ void board_teardown(void) {
board_teardown2();
}
static uint32_t _systick_count = 0;
//--------------------------------------------------------------------+
// Display
//--------------------------------------------------------------------+
#ifdef DISPLAY_PIN_SCK
#include "nrf_spim.h"
void SysTick_Handler(void) {
_systick_count++;
led_tick();
#define TFT_MADCTL_MY 0x80 ///< Page addr order: Bottom to top
#define TFT_MADCTL_MX 0x40 ///< Column addr order: Right to left
#define TFT_MADCTL_MV 0x20 ///< Page/Column order: Reverse Mode ( X <-> Y )
#define TFT_MADCTL_ML 0x10 ///< LCD refresh Bottom to top
#define TFT_MADCTL_MH 0x04 ///< LCD refresh right to left
#define TFT_MADCTL_RGB 0x00 ///< Red-Green-Blue pixel order
#define TFT_MADCTL_BGR 0x08 ///< Blue-Green-Red pixel order
// Note don't use SPIM3 since it has lots of errata
NRF_SPIM_Type* _spim = NRF_SPIM0;
static void spi_write(NRF_SPIM_Type *p_spim, uint8_t const *tx_buf, size_t tx_len) {
nrf_spim_tx_buffer_set(p_spim, tx_buf, tx_len);
nrf_spim_rx_buffer_set(p_spim, NULL, 0);
nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_ENDTX);
nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_START);
// blocking wait until xfer complete
while (!nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END)){}
}
static void tft_controller_init(void);
static inline void tft_cs(bool state) {
nrf_gpio_pin_write(DISPLAY_PIN_CS, state);
}
static inline void tft_dc(bool state) {
nrf_gpio_pin_write(DISPLAY_PIN_DC, state);
}
static void tft_cmd(uint8_t cmd, uint8_t const* data, size_t narg) {
tft_cs(false);
// send command
tft_dc(false);
spi_write(_spim, &cmd, 1);
// send data
if (narg > 0) {
tft_dc(true);
spi_write(_spim, data, narg);
}
tft_cs(true);
}
void board_display_init(void) {
//------------- SPI init -------------//
// highspeed SPIM should set SCK and MOSI to high drive
nrf_gpio_cfg(DISPLAY_PIN_SCK, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_CONNECT,
NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
nrf_gpio_cfg(DISPLAY_PIN_MOSI, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT,
NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
nrf_gpio_cfg_output(DISPLAY_PIN_CS);
nrf_gpio_pin_set(DISPLAY_PIN_CS);
nrf_spim_pins_set(_spim, DISPLAY_PIN_SCK, DISPLAY_PIN_MOSI, NRF_SPIM_PIN_NOT_CONNECTED);
nrf_spim_frequency_set(_spim, NRF_SPIM_FREQ_4M);
nrf_spim_configure(_spim, NRF_SPIM_MODE_0, NRF_SPIM_BIT_ORDER_MSB_FIRST);
nrf_spim_orc_set(_spim, 0xFF);
nrf_spim_enable(_spim);
//------------- Display Init -------------//
nrf_gpio_cfg_output(DISPLAY_PIN_DC);
#if defined(DISPLAY_PIN_RST) && DISPLAY_PIN_RST >= 0
nrf_gpio_cfg_output(DISPLAY_PIN_RST);
nrf_gpio_pin_clear(DISPLAY_PIN_RST);
NRFX_DELAY_MS(10);
nrf_gpio_pin_set(DISPLAY_PIN_RST);
NRFX_DELAY_MS(20);
#endif
#if defined(DISPLAY_PIN_BL) && DISPLAY_PIN_BL >= 0
nrf_gpio_cfg_output(DISPLAY_PIN_BL);
nrf_gpio_pin_write(DISPLAY_PIN_BL, DISPLAY_BL_ON);
#endif
tft_controller_init();
}
void board_display_teardown(void) {
nrf_spim_disable(_spim);
}
void board_display_draw_line(uint16_t y, uint8_t const* buf, size_t nbytes) {
// column and row address set
uint32_t xa32 = DISPLAY_COL_OFFSET << 16 | DISPLAY_WIDTH;
xa32 = __builtin_bswap32(xa32);
y += DISPLAY_ROW_OFFSET;
uint32_t ya32 = (y << 16) | (y + 1);
ya32 = __builtin_bswap32(ya32);
tft_cmd(0x2A, (uint8_t*) &xa32, 4);
tft_cmd(0x2B, (uint8_t*) &ya32, 4);
// command: memory write
tft_cmd(0x2C, buf, nbytes);
}
#endif
//--------------------------------------------------------------------+
// LED Indicator
//--------------------------------------------------------------------+
void pwm_teardown(NRF_PWM_Type* pwm) {
pwm->TASKS_SEQSTART[0] = 0;
pwm->ENABLE = 0;
@ -547,3 +667,108 @@ void neopixel_write (uint8_t *pixels) {
led_pwm_duty_cycle(LED_RGB_BLUE, pixels[0]);
}
#endif
//--------------------------------------------------------------------+
// Display controller
//--------------------------------------------------------------------+
#ifdef DISPLAY_CONTROLLER_ST7789
#define ST_CMD_DELAY 0x80 // special signifier for command lists
#define ST77XX_NOP 0x00
#define ST77XX_SWRESET 0x01
#define ST77XX_RDDID 0x04
#define ST77XX_RDDST 0x09
#define ST77XX_SLPIN 0x10
#define ST77XX_SLPOUT 0x11
#define ST77XX_PTLON 0x12
#define ST77XX_NORON 0x13
#define ST77XX_INVOFF 0x20
#define ST77XX_INVON 0x21
#define ST77XX_DISPOFF 0x28
#define ST77XX_DISPON 0x29
#define ST77XX_CASET 0x2A
#define ST77XX_RASET 0x2B
#define ST77XX_RAMWR 0x2C
#define ST77XX_RAMRD 0x2E
#define ST77XX_PTLAR 0x30
#define ST77XX_TEOFF 0x34
#define ST77XX_TEON 0x35
#define ST77XX_MADCTL 0x36
#define ST77XX_VSCSAD 0x37
#define ST77XX_COLMOD 0x3A
#define ST77XX_MADCTL_MY 0x80
#define ST77XX_MADCTL_MX 0x40
#define ST77XX_MADCTL_MV 0x20
#define ST77XX_MADCTL_ML 0x10
#define ST77XX_MADCTL_RGB 0x00
#define ST77XX_RDID1 0xDA
#define ST77XX_RDID2 0xDB
#define ST77XX_RDID3 0xDC
#define ST77XX_RDID4 0xDD
// Some ready-made 16-bit ('565') color settings:
#define ST77XX_BLACK 0x0000
#define ST77XX_WHITE 0xFFFF
#define ST77XX_RED 0xF800
#define ST77XX_GREEN 0x07E0
#define ST77XX_BLUE 0x001F
#define ST77XX_CYAN 0x07FF
#define ST77XX_MAGENTA 0xF81F
#define ST77XX_YELLOW 0xFFE0
#define ST77XX_ORANGE 0xFC00
static void tft_controller_init(void) {
// Init commands for 7789 screens
uint8_t cmdinit_st7789[] = {
#if !defined(DISPLAY_PIN_RST) || (DISPLAY_PIN_RST < 0)
// Software reset if rst pin not available, no args, w/delay ~150 ms delay
ST77XX_SWRESET, ST_CMD_DELAY, 150,
#endif
// Out of sleep mode, no args, w/delay 10 ms delay
ST77XX_SLPOUT, ST_CMD_DELAY, 10,
// Set color mode, 1 arg + delay: 16-bit color, 10 ms delay
ST77XX_COLMOD, 1 + ST_CMD_DELAY, 0x55, 10,
// Mem access ctrl (directions), 1 arg: Row/col addr, bottom-top refresh
ST77XX_MADCTL, 1, DISPLAY_MADCTL,
// Vertical Scroll Start Address of RAM
// ST77XX_VSCSAD, 2, DISPLAY_VSCSAD >> 8, DISPLAY_VSCSAD & 0xFF,
// Column addr set, 4 args, no delay: XSTART = 0, XEND = 240
ST77XX_CASET, 4, 0x00, 0, 0, 240,
// Row addr set, 4 args, no delay: YSTART = 0 YEND = 320
ST77XX_RASET, 4, 0x00, 0, 320 >> 8, 320 & 0xFF,
// Inversion on
ST77XX_INVON, ST_CMD_DELAY, 10,
// Normal display on, no args, w/delay 10 ms delay
ST77XX_NORON, ST_CMD_DELAY, 10,
// Main screen turn on, no args, delay 10 ms delay
ST77XX_DISPON, ST_CMD_DELAY, 10
};
size_t count = 0;
while (count < sizeof(cmdinit_st7789)) {
uint8_t const cmd = cmdinit_st7789[count++];
uint8_t const cmd_arg = cmdinit_st7789[count++];
uint8_t const has_delay = cmd_arg & ST_CMD_DELAY;
uint8_t const narg = cmd_arg & ~ST_CMD_DELAY;
tft_cmd(cmd, cmdinit_st7789 + count, narg);
count += narg;
if (has_delay) {
uint16_t delay = (uint16_t) cmdinit_st7789[count++];
if (delay == 255) {
delay = 500; // If 255, delay for 500 ms
}
NRFX_DELAY_MS(delay);
}
}
}
#endif

View file

@ -114,6 +114,16 @@ bool button_pressed(uint32_t pin);
bool is_ota(void);
//--------------------------------------------------------------------+
// Display
//--------------------------------------------------------------------+
#ifdef DISPLAY_PIN_SCK
void board_display_init(void);
void board_display_teardown(void);
void board_display_draw_line(uint16_t y, uint8_t const* buf, size_t nbytes);
void screen_draw_drag(void);
#endif
//--------------------------------------------------------------------+
// DEBUG
//--------------------------------------------------------------------+

View file

@ -0,0 +1 @@
set(MCU_VARIANT nrf52840)

View file

@ -0,0 +1 @@
set(MCU_VARIANT nrf52840)

View file

@ -46,6 +46,32 @@
#define BUTTON_2 _PINNUM(1, 10) // right button
#define BUTTON_PULL NRF_GPIO_PIN_PULLUP
//--------------------------------------------------------------------+
// Display
//--------------------------------------------------------------------+
#define DISPLAY_CONTROLLER_ST7789
#define DISPLAY_PIN_SCK _PINNUM(0, 14)
#define DISPLAY_PIN_MOSI _PINNUM(0, 15)
#define DISPLAY_PIN_CS _PINNUM(0, 12)
#define DISPLAY_PIN_DC _PINNUM(0, 13)
#define DISPLAY_PIN_RST _PINNUM(1, 3)
#define DISPLAY_PIN_BL _PINNUM(1, 5)
#define DISPLAY_BL_ON 1 // GPIO state to enable back light
#define DISPLAY_WIDTH 240
#define DISPLAY_HEIGHT 240
#define DISPLAY_COL_OFFSET 0
#define DISPLAY_ROW_OFFSET 80
// Memory Data Access Control & // Vertical Scroll Start Address
#define DISPLAY_MADCTL (TFT_MADCTL_MY)
#define DISPLAY_VSCSAD 0
#define DISPLAY_TITLE "CLUE"
//--------------------------------------------------------------------+
// BLE OTA
//--------------------------------------------------------------------+

View file

@ -47,6 +47,32 @@
#define BUTTON_2 _PINNUM(1, 10) // DFU pin
#define BUTTON_PULL NRF_GPIO_PIN_PULLUP
//--------------------------------------------------------------------+
// Display
//--------------------------------------------------------------------+
#define DISPLAY_CONTROLLER_ST7789
#define DISPLAY_PIN_SCK _PINNUM(0, 26)
#define DISPLAY_PIN_MOSI _PINNUM(0, 5)
#define DISPLAY_PIN_CS _PINNUM(1, 5)
#define DISPLAY_PIN_DC _PINNUM(1, 1)
#define DISPLAY_PIN_RST _PINNUM(1, 3)
#define DISPLAY_PIN_BL _PINNUM(0, 27)
#define DISPLAY_BL_ON 1 // GPIO state to enable back light
#define DISPLAY_WIDTH 240
#define DISPLAY_HEIGHT 135
#define DISPLAY_COL_OFFSET 53
#define DISPLAY_ROW_OFFSET 40
// Memory Data Access Control & // Vertical Scroll Start Address
#define DISPLAY_MADCTL (TFT_MADCTL_MX)
#define DISPLAY_VSCSAD 0
#define DISPLAY_TITLE "Sense TFT"
//--------------------------------------------------------------------+
// BLE OTA
//--------------------------------------------------------------------+
@ -62,7 +88,7 @@
//------------- UF2 -------------//
#define UF2_PRODUCT_NAME "Adafruit Feather nRF52840 Sense TFT"
#define UF2_VOLUME_LABEL "FTHRSNSBOOT"
#define UF2_VOLUME_LABEL "SENSTFTBOOT"
#define UF2_BOARD_ID "nRF52840-FeatherSenseTFT-revA"
#define UF2_INDEX_URL "https://www.adafruit.com/product/"

124
src/images.c Normal file
View file

@ -0,0 +1,124 @@
#include "boards.h"
#if defined(DISPLAY_PIN_SCK)
#include <stdint.h>
// all https://makecode.com/_VrfEKzV4xfvq
// https://makecode.com/_7VxXm3JMPXfM - file
// https://makecode.com/_LuEUCsPEKUbs - download
const uint8_t fileLogo[] = {
32, 32, 71, 140, 201, 151, 1, 2, 146, 1, 2, 146, 63, 2, 151, 9, 153, 9, 153, 9, 146, 1, 9, 146, 3, 9, 146, 7, 9, 137, 205, 72, 140, 206, 36, 139, 207, 18, 138, 206, 36, 139, 205, 72, 149, 7, 9, 146, 3, 9, 146, 1, 9, 153, 9, 153, 9, 153, 9, 148, 63, 2, 146, 1, 2, 146, 1, 2, 146, 201, 191, 191, 191, 174
};
// https://makecode.com/_9b0RcK5yRa12
const uint8_t pendriveLogo[] = {
32, 32, 59, 137, 215, 137, 1, 143, 1, 8, 146, 203, 149, 3, 8, 146, 3, 8, 146, 115, 8, 146, 115, 8, 146, 3, 8, 146, 3, 8, 146, 115, 8, 146, 115, 8, 146, 3, 8, 146, 3, 8, 146, 203, 149, 1, 8, 146, 1, 8, 146, 1, 120, 211, 191, 191, 191, 191, 191, 191, 191, 135
};
// https://makecode.com/_TTqbj705L4mr
const uint8_t arrowLogo[] = {
32, 32, 54, 137, 201, 151, 201, 151, 201, 151, 201, 151, 201, 151, 201, 151, 201, 151, 201, 151, 201, 151, 201, 151, 201, 151, 201, 151, 201, 151, 201, 151, 201, 146, 211, 142, 209, 144, 207, 146, 205, 148, 203, 150, 201, 152, 199, 154, 31, 154, 7, 154, 1, 191, 191, 191, 175
};
const uint8_t font8[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x5e, 0x00, 0x00, 0x00,
0x00, 0x0e, 0x00, 0x0e, 0x00, 0x00,
0x28, 0xfe, 0x28, 0xfe, 0x28, 0x00,
0x4c, 0x92, 0xff, 0x92, 0x64, 0x00,
0x02, 0x65, 0x12, 0x48, 0xa6, 0x40,
0x6c, 0x92, 0x92, 0x6c, 0xa0, 0x00,
0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7c, 0x82, 0x00, 0x00,
0x00, 0x00, 0x82, 0x7c, 0x00, 0x00,
0x54, 0x38, 0x10, 0x38, 0x54, 0x00,
0x10, 0x10, 0x7c, 0x10, 0x10, 0x00,
0x00, 0x00, 0x90, 0x70, 0x00, 0x00,
0x10, 0x10, 0x10, 0x10, 0x10, 0x00,
0x00, 0x00, 0x60, 0x60, 0x00, 0x00,
0x00, 0x60, 0x10, 0x08, 0x06, 0x00,
0x00, 0x3c, 0x42, 0x42, 0x3c, 0x00,
0x00, 0x44, 0x7e, 0x40, 0x00, 0x00,
0x00, 0x44, 0x62, 0x52, 0x4c, 0x00,
0x00, 0x42, 0x4a, 0x4e, 0x32, 0x00,
0x30, 0x28, 0x24, 0x7e, 0x20, 0x00,
0x00, 0x4e, 0x4a, 0x4a, 0x32, 0x00,
0x00, 0x3c, 0x4a, 0x4a, 0x30, 0x00,
0x00, 0x02, 0x62, 0x12, 0x0e, 0x00,
0x00, 0x34, 0x4a, 0x4a, 0x34, 0x00,
0x00, 0x0c, 0x52, 0x52, 0x3c, 0x00,
0x00, 0x00, 0x6c, 0x6c, 0x00, 0x00,
0x00, 0x00, 0x96, 0x76, 0x00, 0x00,
0x10, 0x28, 0x28, 0x44, 0x44, 0x00,
0x28, 0x28, 0x28, 0x28, 0x28, 0x00,
0x44, 0x44, 0x28, 0x28, 0x10, 0x00,
0x00, 0x02, 0x59, 0x09, 0x06, 0x00,
0x3c, 0x42, 0x5a, 0x56, 0x08, 0x00,
0x78, 0x14, 0x12, 0x14, 0x78, 0x00,
0x7e, 0x4a, 0x4a, 0x4a, 0x34, 0x00,
0x00, 0x3c, 0x42, 0x42, 0x24, 0x00,
0x00, 0x7e, 0x42, 0x42, 0x3c, 0x00,
0x00, 0x7e, 0x4a, 0x4a, 0x42, 0x00,
0x00, 0x7e, 0x0a, 0x0a, 0x02, 0x00,
0x00, 0x3c, 0x42, 0x52, 0x34, 0x00,
0x00, 0x7e, 0x08, 0x08, 0x7e, 0x00,
0x00, 0x42, 0x7e, 0x42, 0x00, 0x00,
0x20, 0x40, 0x42, 0x3e, 0x02, 0x00,
0x00, 0x7e, 0x08, 0x14, 0x62, 0x00,
0x00, 0x7e, 0x40, 0x40, 0x40, 0x00,
0x7e, 0x04, 0x18, 0x04, 0x7e, 0x00,
0x00, 0x7e, 0x04, 0x08, 0x7e, 0x00,
0x3c, 0x42, 0x42, 0x42, 0x3c, 0x00,
0x00, 0x7e, 0x12, 0x12, 0x0c, 0x00,
0x00, 0x3c, 0x52, 0x62, 0xbc, 0x00,
0x00, 0x7e, 0x12, 0x12, 0x6c, 0x00,
0x00, 0x24, 0x4a, 0x52, 0x24, 0x00,
0x02, 0x02, 0x7e, 0x02, 0x02, 0x00,
0x00, 0x3e, 0x40, 0x40, 0x3e, 0x00,
0x00, 0x1e, 0x70, 0x70, 0x1e, 0x00,
0x7e, 0x20, 0x18, 0x20, 0x7e, 0x00,
0x42, 0x24, 0x18, 0x24, 0x42, 0x00,
0x06, 0x08, 0x70, 0x08, 0x06, 0x00,
0x00, 0x62, 0x52, 0x4a, 0x46, 0x00,
0x00, 0x7e, 0x42, 0x42, 0x00, 0x00,
0x00, 0x06, 0x08, 0x10, 0x60, 0x00,
0x00, 0x42, 0x42, 0x7e, 0x00, 0x00,
0x08, 0x04, 0x02, 0x04, 0x08, 0x00,
0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
0x00, 0x00, 0x02, 0x04, 0x00, 0x00,
0x00, 0x30, 0x48, 0x48, 0x78, 0x00,
0x00, 0x7e, 0x48, 0x48, 0x30, 0x00,
0x00, 0x30, 0x48, 0x48, 0x48, 0x00,
0x00, 0x30, 0x48, 0x48, 0x7e, 0x00,
0x00, 0x30, 0x68, 0x58, 0x50, 0x00,
0x00, 0x10, 0x7c, 0x12, 0x04, 0x00,
0x00, 0x18, 0xa4, 0xa4, 0x78, 0x00,
0x00, 0x7e, 0x08, 0x08, 0x70, 0x00,
0x00, 0x48, 0x7a, 0x40, 0x00, 0x00,
0x00, 0x40, 0x84, 0x7d, 0x00, 0x00,
0x00, 0x7e, 0x10, 0x28, 0x40, 0x00,
0x00, 0x42, 0x7e, 0x40, 0x00, 0x00,
0x78, 0x08, 0x30, 0x08, 0x70, 0x00,
0x00, 0x78, 0x08, 0x08, 0x70, 0x00,
0x00, 0x30, 0x48, 0x48, 0x30, 0x00,
0x00, 0xfc, 0x24, 0x24, 0x18, 0x00,
0x00, 0x18, 0x24, 0x24, 0xfc, 0x00,
0x00, 0x78, 0x10, 0x08, 0x10, 0x00,
0x00, 0x50, 0x58, 0x68, 0x28, 0x00,
0x00, 0x08, 0x3e, 0x48, 0x20, 0x00,
0x00, 0x38, 0x40, 0x40, 0x78, 0x00,
0x00, 0x18, 0x60, 0x60, 0x18, 0x00,
0x38, 0x40, 0x30, 0x40, 0x38, 0x00,
0x00, 0x48, 0x30, 0x30, 0x48, 0x00,
0x00, 0x5c, 0xa0, 0xa0, 0x7c, 0x00,
0x00, 0x48, 0x68, 0x58, 0x48, 0x00,
0x00, 0x08, 0x36, 0x41, 0x00, 0x00,
0x00, 0x00, 0xfe, 0x00, 0x00, 0x00,
0x00, 0x41, 0x36, 0x08, 0x00, 0x00,
0x00, 0x08, 0x04, 0x08, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
#endif

View file

@ -477,9 +477,4 @@ __attribute__ ((used)) int _write (int fhdl, const void *buf, size_t count) {
return count;
}
__attribute__ ((used)) int _read (int fhdl, char *buf, size_t count) {
(void) fhdl;
return SEGGER_RTT_Read(0, buf, count);
}
#endif

View file

@ -18,10 +18,8 @@
// UART
#ifdef NRF52832_XXAA
#define NRFX_UART_ENABLED 1
#define NRFX_UART0_ENABLED 1
#define NRFX_UART_DEFAULT_CONFIG_IRQ_PRIORITY 7
#define NRFX_UART_DEFAULT_CONFIG_HWFC NRF_UART_HWFC_DISABLED
#define NRFX_UART_DEFAULT_CONFIG_PARITY NRF_UART_PARITY_EXCLUDED

266
src/screen.c Normal file
View file

@ -0,0 +1,266 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Ha Thach (tinyusb.org) 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 "boards.h"
#if defined(DISPLAY_PIN_SCK)
#include <string.h>
#include <stdlib.h>
// Overlap 4x chars by this much.
#define CHAR4_KERNING 3
// Width of a single 4x char, adjusted by kerning
#define CHAR4_KERNED_WIDTH (6 * 4 - CHAR4_KERNING)
#define COL0(r, g, b) ((((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3))
#define COL(c) COL0((c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff)
enum {
COLOR_BLACK = 0,
COLOR_WHITE = 1,
COLOR_RED = 2,
COLOR_PINK = 3,
COLOR_ORANGE = 4,
COLOR_YELLOW = 5,
COLOR_CYAN = 6,
COLOR_GREEN = 7,
COLOR_BLUE = 8,
COLOR_AQUA = 9,
COLOR_PURPLE = 10,
};
// 16-bit 565 color from 24-bit 888 format
const uint16_t palette[] = {
COL(0x000000), // 0
COL(0xffffff), // 1
COL(0xff2121), // 2
COL(0xff93c4), // 3
COL(0xff8135), // 4
COL(0xfff609), // 5
COL(0x249ca3), // 6
COL(0x78dc52), // 7
COL(0x003fad), // 8
COL(0x87f2ff), // 9
COL(0x8e2ec4), // 10
COL(0xa4839f), // 11
COL(0x5c406c), // 12
COL(0xe5cdc4), // 13
COL(0x91463d), // 14
COL(0x000000), // 15
};
// TODO only buffer partial screen to save SRAM
// ESP32s2 can only statically allocated DRAM up to 160KB.
// the remaining 160KB can only be allocated at runtime as heap.
static uint8_t frame_buf[DISPLAY_WIDTH * DISPLAY_HEIGHT];
//static uint8_t* frame_buf;
extern const uint8_t font8[];
extern const uint8_t fileLogo[];
extern const uint8_t pendriveLogo[];
extern const uint8_t arrowLogo[];
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
// print character with font size = 1
static void printch(int x, int y, int color, const uint8_t* fnt) {
for (int i = 0; i < 6; ++i) {
uint8_t* p = frame_buf + (x + i) * DISPLAY_HEIGHT + y;
uint8_t mask = 0x01;
for (int j = 0; j < 8; ++j) {
if (*fnt & mask) {
*p = color;
}
p++;
mask <<= 1;
}
fnt++;
}
}
// print character with font size = 4
static void printch4(int x, int y, int color, const uint8_t* fnt) {
for (int i = 0; i < 6 * 4; ++i) {
uint8_t* p = frame_buf + (x + i) * DISPLAY_HEIGHT + y;
uint8_t mask = 0x01;
for (int j = 0; j < 8; ++j) {
for (int k = 0; k < 4; ++k) {
if (*fnt & mask) {
*p = color;
}
p++;
}
mask <<= 1;
}
if ((i & 3) == 3) {
fnt++;
}
}
}
// print icon
static void printicon(int x, int y, int color, const uint8_t* icon) {
int w = *icon++;
int h = *icon++;
int sz = *icon++;
uint8_t mask = 0x80;
int runlen = 0;
int runbit = 0;
uint8_t lastb = 0x00;
for (int i = 0; i < w; ++i) {
uint8_t* p = frame_buf + (x + i) * DISPLAY_HEIGHT + y;
for (int j = 0; j < h; ++j) {
int c = 0;
if (mask != 0x80) {
if (lastb & mask) {
c = 1;
}
mask <<= 1;
} else if (runlen) {
if (runbit) {
c = 1;
}
runlen--;
} else {
if (sz-- <= 0) {
//TU_LOG1("Screen Panic code = 10");
}
lastb = *icon++;
if (lastb & 0x80) {
runlen = lastb & 63;
runbit = lastb & 0x40;
} else {
mask = 0x01;
}
--j;
continue; // restart
}
if (c) {
*p = color;
}
p++;
}
}
}
// print text with font size = 1
static void print(int x, int y, int col, const char* text) {
int x0 = x;
while (*text) {
char c = *text++;
if (c == '\r') continue;
if (c == '\n') {
x = x0;
y += 10;
continue;
}
/*
if (x + 8 > DISPLAY_WIDTH) {
x = x0;
y += 10;
}
*/
if (c < ' ') c = '?';
if (c >= 0x7f) c = '?';
c -= ' ';
printch(x, y, col, &font8[c * 6]);
x += 6;
}
}
// Print text with font size = 4
static void print4(int x, int y, int color, const char* text) {
while (*text) {
char c = *text++;
c -= ' ';
printch4(x, y, color, &font8[c * 6]);
x += CHAR4_KERNED_WIDTH;
if (x + CHAR4_KERNED_WIDTH > DISPLAY_WIDTH) {
// Next char won't fit.
return;
}
}
}
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
static void draw_screen(uint8_t const* fb) {
uint8_t const* p = fb;
for (int y = 0; y < DISPLAY_WIDTH; ++y) {
uint8_t cc[DISPLAY_HEIGHT * 2];
uint32_t dst = 0;
for (int x = 0; x < DISPLAY_HEIGHT; ++x) {
uint16_t color = palette[*p++ & 0xf];
cc[dst++] = color >> 8;
cc[dst++] = color & 0xff;
}
board_display_draw_line(y, cc, sizeof(cc));
}
}
// draw color bar
static void drawBar(int y, int h, int color) {
for (int x = 0; x < DISPLAY_WIDTH; ++x) {
memset(frame_buf + x * DISPLAY_HEIGHT + y, color, h);
}
}
// draw drag & drop screen
void screen_draw_drag(void) {
drawBar(0, 52, COLOR_GREEN);
drawBar(52, 55, COLOR_BLUE);
drawBar(107, 14, COLOR_ORANGE);
// Center UF2_PRODUCT_NAME and UF2_VERSION_BASE.
int name_x = (DISPLAY_WIDTH - CHAR4_KERNED_WIDTH * (int) strlen(DISPLAY_TITLE)) / 2;
print4(name_x >= 0 ? name_x : 0, 5, COLOR_WHITE, DISPLAY_TITLE);
int version_x = (DISPLAY_WIDTH - 6 * (int) strlen(UF2_VERSION_BASE)) / 2;
print(version_x >= 0 ? version_x : 0, 40, COLOR_PURPLE, UF2_VERSION_BASE);
// TODO the reset should be center as well
print(23, 110, 1, "circuitpython.org");
#define DRAG 70
#define DRAGX 10
printicon(DRAGX + 20, DRAG + 5, COLOR_WHITE, fileLogo);
printicon(DRAGX + 66, DRAG, COLOR_WHITE, arrowLogo);
printicon(DRAGX + 108, DRAG, COLOR_WHITE, pendriveLogo);
print(10, DRAG - 12, COLOR_WHITE, "firmware.uf2");
print(90, DRAG - 12, COLOR_WHITE, UF2_VOLUME_LABEL);
draw_screen(frame_buf);
}
#endif

View file

@ -43,49 +43,41 @@
extern void tusb_hal_nrf_power_event(uint32_t event);
// power callback when SD is not enabled
static void power_event_handler(nrfx_power_usb_evt_t event)
{
static void power_event_handler(nrfx_power_usb_evt_t event) {
tusb_hal_nrf_power_event((uint32_t) event);
}
// Forward USB interrupt events to TinyUSB IRQ Handler
void USBD_IRQHandler(void)
{
void USBD_IRQHandler(void) {
tud_int_handler(0);
}
//------------- IMPLEMENTATION -------------//
void usb_init(bool cdc_only)
{
void usb_init(bool cdc_only) {
// 0, 1 is reserved for SD
NVIC_SetPriority(USBD_IRQn, 2);
// USB power may already be ready at this time -> no event generated
// We need to invoke the handler based on the status initially
uint32_t usb_reg;
uint8_t sd_en = false;
if ( is_sd_existed() )
{
if (is_sd_existed()) {
sd_softdevice_is_enabled(&sd_en);
}
if ( sd_en )
{
if (sd_en) {
sd_power_usbdetected_enable(true);
sd_power_usbpwrrdy_enable(true);
sd_power_usbremoved_enable(true);
sd_power_usbregstatus_get(&usb_reg);
}else
{
} else {
// Power module init
const nrfx_power_config_t pwr_cfg = { 0 };
const nrfx_power_config_t pwr_cfg = {0};
nrfx_power_init(&pwr_cfg);
// Register USB power handler
const nrfx_power_usbevt_config_t config = { .handler = power_event_handler };
const nrfx_power_usbevt_config_t config = {.handler = power_event_handler};
nrfx_power_usbevt_init(&config);
nrfx_power_usbevt_enable();
@ -93,24 +85,25 @@ void usb_init(bool cdc_only)
usb_reg = NRF_POWER->USBREGSTATUS;
}
if ( usb_reg & POWER_USBREGSTATUS_VBUSDETECT_Msk ) {
if (usb_reg & POWER_USBREGSTATUS_VBUSDETECT_Msk) {
tusb_hal_nrf_power_event(NRFX_POWER_USB_EVT_DETECTED);
}
if ( usb_reg & POWER_USBREGSTATUS_OUTPUTRDY_Msk ) {
if (usb_reg & POWER_USBREGSTATUS_OUTPUTRDY_Msk) {
tusb_hal_nrf_power_event(NRFX_POWER_USB_EVT_READY);
}
usb_desc_init(cdc_only);
uf2_init();
// Init TinyUSB stack
tusb_init();
#ifdef DISPLAY_PIN_SCK
board_display_init();
screen_draw_drag();
#endif
}
void usb_teardown(void)
{
void usb_teardown(void) {
// Simulate an disconnect which cause pullup disable, USB perpheral disable and hclk disable
tusb_hal_nrf_power_event(NRFX_POWER_USB_EVT_REMOVED);
}
@ -118,12 +111,10 @@ void usb_teardown(void)
//--------------------------------------------------------------------+
// tinyusb callbacks
//--------------------------------------------------------------------+
void tud_mount_cb(void)
{
void tud_mount_cb(void) {
led_state(STATE_USB_MOUNTED);
}
void tud_umount_cb(void)
{
void tud_umount_cb(void) {
led_state(STATE_USB_UNMOUNTED);
}