diff --git a/Code/pico_multi_booter/CMakeLists.txt b/Code/pico_multi_booter/CMakeLists.txt index b6bc14c..fc047a0 100644 --- a/Code/pico_multi_booter/CMakeLists.txt +++ b/Code/pico_multi_booter/CMakeLists.txt @@ -76,15 +76,15 @@ add_dependencies(PREPARE_sd_boot BUILT_boot) add_dependencies(sd_boot PREPARE_sd_boot) add_dependencies(BUILT_sd_boot sd_boot) -add_dependencies(PREPARE_picomite BUILT_sd_boot) -add_dependencies(picomite PREPARE_picomite) -add_dependencies(BUILT_picomite picomite) +add_dependencies(PREPARE_PicoMite BUILT_sd_boot) +add_dependencies(PicoMite PREPARE_PicoMite) +add_dependencies(BUILT_PicoMite PicoMite) # *************************************************************************** # * Join the BOOT and all APP '.uf2' files together * # *************************************************************************** -set(UF2S boot.uf2 sd_boot.uf2 picomite.uf2) +set(UF2S boot.uf2 sd_boot.uf2 PicoMite.uf2) add_custom_target(JOIN COMMENT "Combine the '.uf2' files" @@ -95,7 +95,7 @@ add_custom_target(JOIN ${UF2S} ) -add_dependencies(JOIN BUILT_picomite) +add_dependencies(JOIN BUILT_PicoMite) add_custom_target(${PROJECT} ALL DEPENDS JOIN) diff --git a/Code/pico_multi_booter/README.md b/Code/pico_multi_booter/README.md index 94acfbd..9389d41 100644 --- a/Code/pico_multi_booter/README.md +++ b/Code/pico_multi_booter/README.md @@ -4,7 +4,7 @@ Here is a bootloader for PicoCalc combined slightly modified [PicoMite](https:// - Pico1 - No sdcard inserted,load default app to run from flash. -- Sdcard inserted, SD boot menu will show up, load third pico app bin to run at FLASH TARGET OFFSET 2048k-200k +- Sdcard inserted, SD boot menu will show up, load third pico app bin to run at FLASH TARGET OFFSET 2048k-188k ## How to compile ``` @@ -37,7 +37,7 @@ config.h ### SD Card Application Build and Deployment **Important Note:** ``` -Applications intended for SD card boot "MUST REBUILD" using a custom linker script to accommodate the program's offset(200k) address. +Applications intended for SD card boot "MUST REBUILD" using a custom linker script to accommodate the program's offset(188k) address. Applications intended for SD card boot is in **bin** format, not uf2. @@ -48,7 +48,7 @@ This section explains how to build and deploy applications on an SD card. Below #### Step 1 Copy Custom Link Script -Copy `memmap_sdcard_app.ld` to your project repository. +Copy `memmap_default_rp2040.ld` and `memmap_default_rp2350.ld` to your project repository. #### Step 2 Add Custom Link Script to CMakeList.txt @@ -61,7 +61,6 @@ pico_add_extra_outputs(${CMAKE_PROJECT_NAME}) ... function(enable_sdcard_app target) - #pico_set_linker_script(${target} ${CMAKE_SOURCE_DIR}/memmap_sdcard_app.ld) if(${PICO_PLATFORM} STREQUAL "rp2040") pico_set_linker_script(${CMAKE_PROJECT_NAME} ${CMAKE_SOURCE_DIR}/memmap_default_rp2040.ld) elseif(${PICO_PLATFORM} MATCHES "rp2350") diff --git a/Code/pico_multi_booter/applink.py b/Code/pico_multi_booter/applink.py index 7973604..7c3dc08 100644 --- a/Code/pico_multi_booter/applink.py +++ b/Code/pico_multi_booter/applink.py @@ -468,8 +468,8 @@ def Built(dir, app): print("original last: ", last," ",'{:02X}'.format(last)) print("orignal size: ","{:>3}k".format(Size(last-strt, 1024))) print("orignal used: ","{:>3}k".format(Size(last, 4*1024))) - if last < 0x10032000: - last = 0x10032000 + if last < 0x1002F000: + last = 0x1002F000 size = "{:>3}k".format(Size(last-strt, 1024)) used = "{:>3}k".format(Size(last, 4*1024)) diff --git a/Code/pico_multi_booter/linker_scripts/memmap_default.ld.mp.rp2040 b/Code/pico_multi_booter/linker_scripts/memmap_default.ld.mp.rp2040 index f0251d5..6dcb8c7 100644 --- a/Code/pico_multi_booter/linker_scripts/memmap_default.ld.mp.rp2040 +++ b/Code/pico_multi_booter/linker_scripts/memmap_default.ld.mp.rp2040 @@ -1,7 +1,7 @@ /*arduino-pico*/ MEMORY { - FLASH(rx) : ORIGIN = 0x10000000 + 200k, LENGTH = __FLASH_LENGTH__ - 200k + FLASH(rx) : ORIGIN = 0x10000000 + 188k, LENGTH = __FLASH_LENGTH__ - 188k RAM(rwx) : ORIGIN = 0x20000000, LENGTH = __RAM_LENGTH__ SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k diff --git a/Code/pico_multi_booter/linker_scripts/memmap_mp_rp2040.ld b/Code/pico_multi_booter/linker_scripts/memmap_mp_rp2040.ld index 1905bf3..188c343 100644 --- a/Code/pico_multi_booter/linker_scripts/memmap_mp_rp2040.ld +++ b/Code/pico_multi_booter/linker_scripts/memmap_mp_rp2040.ld @@ -24,7 +24,7 @@ MEMORY { - FLASH(rx) : ORIGIN = 0x10000000 + 200k, LENGTH = 2048k - 200k + FLASH(rx) : ORIGIN = 0x10000000 + 188k, LENGTH = 2048k - 188k RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k diff --git a/Code/pico_multi_booter/linker_scripts/rpi-pico.ld b/Code/pico_multi_booter/linker_scripts/rpi-pico.ld index 2a2b595..b9d4e9d 100644 --- a/Code/pico_multi_booter/linker_scripts/rpi-pico.ld +++ b/Code/pico_multi_booter/linker_scripts/rpi-pico.ld @@ -4,7 +4,7 @@ MEMORY { - FLASH(rx) : ORIGIN = 0x10000000 + 200k, LENGTH = 2048k - 200k + FLASH(rx) : ORIGIN = 0x10000000 + 188k, LENGTH = 2048k - 188k RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k diff --git a/Code/pico_multi_booter/memmap_default_rp2040.ld b/Code/pico_multi_booter/memmap_default_rp2040.ld index 31efe94..53614ad 100644 --- a/Code/pico_multi_booter/memmap_default_rp2040.ld +++ b/Code/pico_multi_booter/memmap_default_rp2040.ld @@ -1,6 +1,6 @@ MEMORY { - FLASH(rx) : ORIGIN = 0x10000000 + 200k, LENGTH = 2048k - 200k + FLASH(rx) : ORIGIN = 0x10000000 + 188k, LENGTH = 2048k - 188k RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k diff --git a/Code/pico_multi_booter/memmap_default_rp2350.ld b/Code/pico_multi_booter/memmap_default_rp2350.ld index 949a391..ac9a8ce 100644 --- a/Code/pico_multi_booter/memmap_default_rp2350.ld +++ b/Code/pico_multi_booter/memmap_default_rp2350.ld @@ -23,7 +23,7 @@ MEMORY { - FLASH(rx) : ORIGIN = 0x10000000 + 200k, LENGTH = 4096k - 200k + FLASH(rx) : ORIGIN = 0x10000000 + 256k, LENGTH = 4096k - 256k RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 512k SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k @@ -299,4 +299,4 @@ SECTIONS ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded block must be in first 4096 bytes of the binary") /* todo assert on extra code */ -} +} \ No newline at end of file diff --git a/Code/pico_multi_booter/picomite/AllCommands.h b/Code/pico_multi_booter/picomite/AllCommands.h index 5c55319..29ef867 100644 --- a/Code/pico_multi_booter/picomite/AllCommands.h +++ b/Code/pico_multi_booter/picomite/AllCommands.h @@ -418,7 +418,7 @@ void fun_map(void); { (unsigned char *)"Drive", T_CMD, 0, cmd_disk }, { (unsigned char *)"Play", T_CMD, 0, cmd_play }, { (unsigned char *)"PIO", T_CMD, 0, cmd_pio }, - { (unsigned char *)"Text", T_CMD, 0, cmd_text }, + { (unsigned char *)"New", T_CMD, 0, cmd_new }, { (unsigned char *)"Pixel", T_CMD, 0, cmd_pixel }, { (unsigned char *)"Circle", T_CMD, 0, cmd_circle }, { (unsigned char *)"Line", T_CMD, 0, cmd_line }, @@ -480,7 +480,7 @@ void fun_map(void); { (unsigned char *)"Cat", T_CMD, 0, cmd_inc }, { (unsigned char *)"Color", T_CMD, 0, cmd_colour }, { (unsigned char *)"Files", T_CMD, 0, cmd_files }, - { (unsigned char *)"New", T_CMD, 0, cmd_new }, + { (unsigned char *)"Text", T_CMD, 0, cmd_text }, { (unsigned char *)"Autosave", T_CMD, 0, cmd_autosave }, { (unsigned char *)"WS2812", T_CMD, 0, cmd_WS2812 }, { (unsigned char *)"Keypad", T_CMD, 0, cmd_keypad }, diff --git a/Code/pico_multi_booter/picomite/CMakeLists.txt b/Code/pico_multi_booter/picomite/CMakeLists.txt index 59c5e41..99a9bfe 100644 --- a/Code/pico_multi_booter/picomite/CMakeLists.txt +++ b/Code/pico_multi_booter/picomite/CMakeLists.txt @@ -1,17 +1,43 @@ +cmake_minimum_required(VERSION 3.13) +# Valid builds are PICO, PICOUSB, VGA, VGAUSB, HDMI(rp2350 only), HDMIUSB(rp2350 only), WEB - -set(APP_NAME picomite) set(PICOCALC true) -#set(SDBOOT true) +# For dynamic loading from SD card: +# SDBOOT requires the bootloader to be in the first 256KB of flash +# PicoMite will need to be shifted by this amount, and all references to +# positions in flash updated to accomodate. THIS OPTION IS NOT READY YET. +# details: https://github.com/adwuard/Picocalc_SD_Boot +set(SDBOOT true) # Compile for PICO 1 Board set(COMPILE PICO) -set(PICO_PLATFORM rp2040) -set(PICO_BOARD pico) +# Compile for PICO 2 Board +#set(COMPILE PICORP2350) +#set(COMPILE WEBRP2350) - -add_executable(${APP_NAME} +if (COMPILE STREQUAL "HDMI" OR COMPILE STREQUAL "WEBRP2350" OR COMPILE STREQUAL "HDMIUSB" OR COMPILE STREQUAL "VGARP2350" OR COMPILE STREQUAL "VGAUSBRP2350" OR COMPILE STREQUAL "PICORP2350" OR COMPILE STREQUAL "PICOUSBRP2350" ) + set(PICO_PLATFORM rp2350) + if (COMPILE STREQUAL "WEBRP2350") + set(PICO_BOARD pico2_w) + else() + set(PICO_BOARD pimoroni_pga2350) + endif() +else() + set(PICO_PLATFORM rp2040) + if (COMPILE STREQUAL "WEB") + set(PICO_BOARD pico_w) + else() + set(PICO_BOARD pico) + endif() +endif() +include(pico_sdk_import.cmake) +project(PicoMite C CXX ASM) +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +#set(PICO_NO_COPRO_DIS 1) +pico_sdk_init() +add_executable(PicoMite PicoMite.c Memory.c regex.c @@ -47,21 +73,56 @@ add_executable(${APP_NAME} VS1053.c aes.c ) +if (COMPILE STREQUAL "WEB" OR COMPILE STREQUAL "WEBRP2350" ) + target_sources(PicoMite PRIVATE + SSD1963.c + Touch.c + GUI.c + cJSON.c + mqtt.c + MMMqtt.c + MMTCPclient.c + MMtelnet.c + MMntp.c + MMtcpserver.c + tftp.c + MMtftp.c + MMudp.c + ) + set_source_files_properties(cJSON.c PROPERTIES COMPILE_FLAGS -Os) + target_include_directories(PicoMite PRIVATE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts + ) + Pico_enable_stdio_usb(PicoMite 1) +endif() -target_sources(${APP_NAME} PRIVATE +if ((COMPILE STREQUAL "PICO") OR (COMPILE STREQUAL "PICOUSB") OR (COMPILE STREQUAL "PICORP2350") OR (COMPILE STREQUAL "PICOUSBRP2350") OR (COMPILE STREQUAL "WEBRP2350")) + target_sources(PicoMite PRIVATE SSD1963.c Touch.c GUI.c) +endif() -target_sources(${APP_NAME} PRIVATE +if (COMPILE STREQUAL "VGAUSB" OR COMPILE STREQUAL "PICOUSBRP2350" OR COMPILE STREQUAL "VGAUSBRP2350" OR COMPILE STREQUAL "PICOUSB" OR COMPILE STREQUAL "HDMIUSB") + target_sources(PicoMite PRIVATE + USBKeyboard.c + ) +else() + target_sources(PicoMite PRIVATE Keyboard.c mouse.c ) +endif() - +if(COMPILE STREQUAL "VGARP2350" OR COMPILE STREQUAL "WEBRP2350" OR COMPILE STREQUAL "PICORP2350" OR COMPILE STREQUAL "HDMI" OR COMPILE STREQUAL "HDMIUSB" OR COMPILE STREQUAL "VGAUSBRP2350" OR COMPILE STREQUAL "PICOUSBRP2350") + target_sources(PicoMite PRIVATE + upng.c + ) +endif() if(PICOCALC STREQUAL "true") - target_sources(${APP_NAME} PRIVATE + target_sources(PicoMite PRIVATE picocalc/i2ckbd.c ) endif() @@ -79,27 +140,33 @@ set_source_files_properties(hxcmod.c PROPERTIES COMPILE_FLAGS -Os) set_source_files_properties(MATHS.c PROPERTIES COMPILE_FLAGS -Os) set_source_files_properties(Editor.c PROPERTIES COMPILE_FLAGS -Os) set_source_files_properties(aes.c PROPERTIES COMPILE_FLAGS -Os) -pico_generate_pio_header(${APP_NAME} ${CMAKE_CURRENT_LIST_DIR}/PicoMiteI2S.pio) - -pico_define_boot_stage2(slower_boot2 ${PICO_DEFAULT_BOOT_STAGE2_FILE}) -target_compile_definitions(slower_boot2 PRIVATE PICO_FLASH_SPI_CLKDIV=4) -pico_set_boot_stage2(${APP_NAME} slower_boot2) - -pico_enable_stdio_usb(${APP_NAME} 1) -pico_enable_stdio_uart(${APP_NAME} 0) - -pico_add_extra_outputs(${APP_NAME}) -pico_add_uf2_output(${APP_NAME}) - -target_link_options(${APP_NAME} PRIVATE -Wl,--print-memory-usage) -target_link_options(${APP_NAME} PRIVATE -Wl,-z,max-page-size=4096) - -pico_set_linker_script(${APP_NAME} ${CMAKE_BINARY_DIR}/${APP_NAME}.ld) +pico_generate_pio_header(PicoMite ${CMAKE_CURRENT_LIST_DIR}/PicoMiteI2S.pio) +if (COMPILE STREQUAL "VGAUSB" OR COMPILE STREQUAL "VGA" OR COMPILE STREQUAL "PICO" OR COMPILE STREQUAL "PICOUSB" OR COMPILE STREQUAL "WEB") + pico_define_boot_stage2(slower_boot2 ${PICO_DEFAULT_BOOT_STAGE2_FILE}) + target_compile_definitions(slower_boot2 PRIVATE PICO_FLASH_SPI_CLKDIV=4) + pico_set_boot_stage2(PicoMite slower_boot2) +endif() +if (COMPILE STREQUAL "VGAUSB" OR COMPILE STREQUAL "VGA" OR COMPILE STREQUAL "VGAUSBRP2350" OR COMPILE STREQUAL "VGARP2350") + pico_generate_pio_header(PicoMite ${CMAKE_CURRENT_LIST_DIR}/PicoMiteVGA.pio) +endif() -pico_set_printf_implementation(${APP_NAME} compiler) +if (COMPILE STREQUAL "VGAUSB" OR COMPILE STREQUAL "PICOUSB" OR COMPILE STREQUAL "HDMIUSB" OR COMPILE STREQUAL "PICOUSBRP2350" OR COMPILE STREQUAL "VGAUSBRP2350") + Pico_enable_stdio_usb(PicoMite 0) + target_include_directories(PicoMite PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/usb_host_files + ) +else() + Pico_enable_stdio_usb(PicoMite 1) +endif() -target_compile_options(${APP_NAME} PRIVATE -DNDEBUG +pico_enable_stdio_uart(PicoMite 0) +pico_add_extra_outputs(PicoMite) +pico_set_printf_implementation(PicoMite compiler) +if(COMPILE STREQUAL "VGARP2350" OR COMPILE STREQUAL "WEBRP2350" OR COMPILE STREQUAL "PICORP2350" OR COMPILE STREQUAL "HDMI" OR COMPILE STREQUAL "HDMIUSB" OR COMPILE STREQUAL "VGAUSBRP2350" OR COMPILE STREQUAL "PICOUSBRP2350") + pico_set_float_implementation(PicoMite pico_dcp) +endif() +target_compile_options(PicoMite PRIVATE -DNDEBUG -DPICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE=0 -DPICO_ADC_CLKDIV_ROUND_NEAREST -DPICO_XOSC_STARTUP_DELAY_MULTIPLIER=64 @@ -110,22 +177,64 @@ target_compile_options(${APP_NAME} PRIVATE -DNDEBUG -DPICO_MALLOC_PANIC -O2 -Wall) - - -target_compile_options(${APP_NAME} PRIVATE -DPICOMITE - -DPICO_HEAP_SIZE=0x1000 - -DGUICONTROLS - -DPICO_CORE0_STACK_SIZE=0x1000 +# all RP2350 variants +if (COMPILE STREQUAL "HDMI" OR COMPILE STREQUAL "WEBRP2350" OR COMPILE STREQUAL "HDMIUSB" OR COMPILE STREQUAL "PICORP2350" OR COMPILE STREQUAL "PICOUSBRP2350" OR COMPILE STREQUAL "VGARP2350" OR COMPILE STREQUAL "VGAUSBRP2350") + target_compile_options(PicoMite PRIVATE -Drp2350 + -DPICO_FLASH_SPI_CLKDIV=4 + -DPICO_PIO_USE_GPIO_BASE + ) +endif() +# all PicoMite variants - enable the gui +if (COMPILE STREQUAL "PICO" OR COMPILE STREQUAL "PICOUSB" OR COMPILE STREQUAL "PICORP2350" OR COMPILE STREQUAL "PICOUSBRP2350") + target_compile_options(PicoMite PRIVATE -DPICOMITE + -DPICO_HEAP_SIZE=0x1000 + -DGUICONTROLS + -DPICO_CORE0_STACK_SIZE=0x1000 + ) +endif() +# all VGA variants +if (COMPILE STREQUAL "VGA" OR COMPILE STREQUAL "VGAUSB" OR COMPILE STREQUAL "VGARP2350" OR COMPILE STREQUAL "VGAUSBRP2350") + target_compile_options(PicoMite PRIVATE -DPICOMITEVGA + -DPICO_HEAP_SIZE=0x2000 + -DPICO_CORE0_STACK_SIZE=0x2000 + ) +endif() +# HDMI variants +if (COMPILE STREQUAL "HDMI" OR COMPILE STREQUAL "HDMIUSB") + target_compile_options(PicoMite PRIVATE -DPICOMITEVGA + -DHDMI + -DPICO_HEAP_SIZE=0x2000 + -DPICO_CORE0_STACK_SIZE=0x2000 + ) +endif() +#Web variants need more heap +if(COMPILE STREQUAL "WEB" OR COMPILE STREQUAL "WEBRP2350") + target_compile_options(PicoMite PRIVATE -DPICOMITEWEB + -DPICO_HEAP_SIZE=0x4000 + -DGUICONTROLS + -DCYW43_HOST_NAME="WebMite" + -DPICO_CYW43_ARCH_POLL + -DPICO_CORE0_STACK_SIZE=0x4000 + ) +endif() +#USB variants +if (COMPILE STREQUAL "PICOUSB" OR COMPILE STREQUAL "PICOUSBRP2350" OR COMPILE STREQUAL "VGAUSB" OR COMPILE STREQUAL "VGAUSBRP2350" OR COMPILE STREQUAL "HDMIUSB") +target_compile_options(PicoMite PRIVATE -DUSBKEYBOARD ) - +endif() +#special case WEB RP2350 gets the GUI controls +if(COMPILE STREQUAL "WEBRP2350") + target_compile_options(PicoMite PRIVATE -DGUICONTROLS + ) +endif() #set the PICOCALC flag if(PICOCALC STREQUAL "true") - target_compile_options(${APP_NAME} PRIVATE -DPICOCALC + target_compile_options(PicoMite PRIVATE -DPICOCALC ) endif() -target_link_libraries(${APP_NAME} +target_link_libraries(PicoMite pico_stdlib hardware_flash hardware_irq @@ -136,39 +245,65 @@ target_link_libraries(${APP_NAME} hardware_dma hardware_exception hardware_pio - pico_multicore - pico_unique_id ) +if(COMPILE STREQUAL "VGAUSB" OR COMPILE STREQUAL "PICOUSB" OR COMPILE STREQUAL "HDMIUSB" OR COMPILE STREQUAL "PICOUSBRP2350" OR COMPILE STREQUAL "VGAUSBRP2350") + target_link_libraries(PicoMite + tinyusb_host + tinyusb_board + pico_multicore + ) +endif() -set(UF2_SOURCE ${CMAKE_CURRENT_BINARY_DIR}/${APP_NAME}.uf2) -set(UF2_DEST ${CMAKE_BINARY_DIR}/${APP_NAME}.uf2) +if(COMPILE STREQUAL "VGA" OR COMPILE STREQUAL "PICO" OR COMPILE STREQUAL "HDMI" OR COMPILE STREQUAL "VGARP2350" OR COMPILE STREQUAL "PICORP2350") + target_link_libraries(PicoMite + pico_multicore + ) +endif() + +if(COMPILE STREQUAL "VGARP2350" OR COMPILE STREQUAL "WEBRP2350" OR COMPILE STREQUAL "PICORP2350" OR COMPILE STREQUAL "HDMI" OR COMPILE STREQUAL "HDMIUSB" OR COMPILE STREQUAL "VGAUSBRP2350" OR COMPILE STREQUAL "PICOUSBRP2350") + target_link_libraries(PicoMite + pico_rand + ) +endif() + +if(COMPILE STREQUAL "WEB" OR COMPILE STREQUAL "WEBRP2350" ) + target_link_libraries(PicoMite + pico_cyw43_arch_lwip_poll + ) +endif() + +if(SDBOOT STREQUAL "true" AND (COMPILE STREQUAL "PICORP2350" OR COMPILE STREQUAL "WEBRP2350")) + pico_set_linker_script(PicoMite ${CMAKE_SOURCE_DIR}/memmap_default_rp2350.ld) +endif() + +if(SDBOOT STREQUAL "true" AND (COMPILE STREQUAL "PICO")) + pico_set_linker_script(PicoMite ${CMAKE_SOURCE_DIR}/memmap_default_rp2040.ld) +endif() + +set(UF2_SOURCE ${CMAKE_CURRENT_BINARY_DIR}/PicoMite.uf2) +set(UF2_DEST ${CMAKE_BINARY_DIR}/PicoMite.uf2) add_custom_command( OUTPUT ${UF2_DEST} DEPENDS ${UF2_SOURCE} COMMAND ${CMAKE_COMMAND} -E copy ${UF2_SOURCE} ${UF2_DEST} - COMMENT "Copying ${APP_NAME}.uf2 to top-level build dir" + COMMENT "Copying PicoMite.uf2 to top-level build dir" ) -add_custom_target(PREPARE_${APP_NAME} - COMMENT "Create Linker Script for '${APP_NAME}'" +add_custom_target(PREPARE_PicoMite + COMMENT "Create Linker Script for 'PicoMite'" COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/applink.py PREPARE ${CMAKE_BINARY_DIR} - ${APP_NAME}) + PicoMite) -add_custom_target(BUILT_${APP_NAME} - COMMENT "Record Build Details for '${APP_NAME}'" +add_custom_target(BUILT_PicoMite + COMMENT "Record Build Details for 'PicoMite'" DEPENDS ${UF2_DEST} COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/applink.py BUILT ${CMAKE_BINARY_DIR} - ${APP_NAME}) + PicoMite) - - -if(SDBOOT STREQUAL "true") - pico_set_linker_script(${APP_NAME} ${CMAKE_SOURCE_DIR}/memmap_sdcard_app.ld) -endif() diff --git a/Code/pico_multi_booter/picomite/Commands.c b/Code/pico_multi_booter/picomite/Commands.c index 0a8365d..57bf10c 100644 --- a/Code/pico_multi_booter/picomite/Commands.c +++ b/Code/pico_multi_booter/picomite/Commands.c @@ -955,13 +955,13 @@ int printWrappedText(const char *text, int screenWidth, int listcnt, int all) { void cmd_help(void){ getargs(&cmdline,1,(unsigned char *)","); - if(!ExistsFile("A:/help.txt"))error("A:/help.txt not found"); + if(!ExistsFile("B:/help.txt"))error("B:/help.txt not found"); if(!argc){ MMPrintString("Enter help and the name of the command or function\r\nUse * for multicharacter wildcard or ? for single character wildcard\r\n"); } else { int fnbr = FindFreeFileNbr(); char *buff=GetTempMemory(STRINGSIZE); - BasicFileOpen("A:/help.txt",fnbr, FA_READ); + BasicFileOpen("B:/help.txt",fnbr, FA_READ); int ListCnt = CurrentY/(FontTable[gui_font >> 4][1] * (gui_font & 0b1111)) + 2; char *p=(char *)getCstring(argv[0]); bool end=false; @@ -1251,9 +1251,20 @@ retest_an_if: // and it is just a number, so get it and find the line nextstmt = findline(getinteger(argv[4]), true); else { - // there is a statement after the ELSE clause so just point to it (the byte after the ELSE token) +/* // there is a statement after the ELSE clause so just point to it (the byte after the ELSE token) for(p = cmdline; *p && *p != ss[1]; p++); // search for the token nextstmt = p + 1; // and point to the byte after +*/ + // IF THEN ELSE + // Find and read the THEN function token. + for(p = cmdline; *p && *p != ss[0]; p++){} + // Skip the command that must start with. + p++; + skipspace(p); + p += sizeof(CommandToken); + // Find and read the ELSE function token. + for(; *p && *p != ss[1]; p++); + nextstmt = p+1; // The statement after the ELSE token. } } else { // no ELSE on a single line IF statement, so just continue with the next statement @@ -1608,7 +1619,7 @@ void MIPS16 do_chain(unsigned char *cmdline){ SaveContext(); ClearVars(0,false); InitHeap(false); - if (*filename && !FileLoadProgram(buf, true)) return; + if (*buf && !FileLoadProgram(buf, true)) return; ClearRuntime(false); PrepareProgram(true); RestoreContext(false); @@ -2108,7 +2119,8 @@ void MIPS16 __not_in_flash_func(cmd_do)(void) { unsigned char *p, *tp, *evalp; if(cmdtoken==cmdWHILE)error("Unknown command"); // if it is a DO loop find the WHILE token and (if found) get a pointer to its expression - while(*cmdline && *cmdline != tokenWHILE) cmdline++; + while(*cmdline && *cmdline != tokenWHILE && *cmdline != tokenUNTIL) cmdline++; + if(*cmdline == tokenUNTIL)error("Syntax"); if(*cmdline == tokenWHILE) { evalp = ++cmdline; } @@ -3638,7 +3650,7 @@ void execute(char* mycmd) { } else { unsigned char* p = inpbuf; - char* q; +// char* q; // char fn[STRINGSIZE] = { 0 }; unsigned short tkn=GetCommandValue((unsigned char *)"RUN"); tknbuf[0] = (tkn & 0x7f ) + C_BASETOKEN; @@ -3646,10 +3658,10 @@ void execute(char* mycmd) { p[0] = (tkn & 0x7f ) + C_BASETOKEN; p[1] = (tkn >> 7) + C_BASETOKEN; //tokens can be 14-bit memmove(&p[2], &p[4], strlen((char *)p) - 4); - if ((q = strchr((char *)p, ':'))) { +/* if ((q = strchr((char *)p, ':'))) { q--; *q = '0'; - } + }*/ p[strlen((char*)p) - 2] = 0; // MMPrintString(fn); PRet(); // CloseAudio(1); diff --git a/Code/pico_multi_booter/picomite/Draw.c b/Code/pico_multi_booter/picomite/Draw.c index ca254ee..a9e1a20 100644 --- a/Code/pico_multi_booter/picomite/Draw.c +++ b/Code/pico_multi_booter/picomite/Draw.c @@ -46,7 +46,6 @@ extern mutex_t frameBufferMutex; #define LONG long #define max(x, y) (((x) > (y)) ? (x) : (y)) #define min(x, y) (((x) < (y)) ? (x) : (y)) -#define RoundUptoInt(a) (((a) + (32 - 1)) & (~(32 - 1)))// round up to the nearest whole integer void DrawFilledCircle(int x, int y, int radius, int r, int fill, int ints_per_line, uint32_t *br, MMFLOAT aspect, MMFLOAT aspect2); void hline(int x0, int x1, int y, int f, int ints_per_line, uint32_t *br); void SaveTriangle(int bnbr, char *buff); @@ -118,7 +117,7 @@ typedef struct _BMPDECODER short gui_font; int gui_fcolour; int gui_bcolour; -short low_y=LCDMaxV, high_y=0, low_x=LCDMaxH, high_x=0; +short low_y=2000, high_y=-1, low_x=2000, high_x=-1; int PrintPixelMode=0; short CurrentX=0, CurrentY=0; // the current default position for the next char to be written @@ -4982,7 +4981,7 @@ void restorepanel(void){ DrawPixel = DrawPixelNormal; DrawBLITBuffer = DrawBufferSPISCR; ScrollLCD = ScrollLCDSPISCR; - if(Option.DISPLAY_TYPE == ILI9341 || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE == ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE == ST7789B){ + if(Option.DISPLAY_TYPE == ILI9341 || Option.DISPLAY_TYPE == ST7796SP || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE == ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE == ST7789B){ ReadBuffer = ReadBufferSPISCR; ReadBLITBuffer = ReadBufferSPISCR; } @@ -4992,7 +4991,7 @@ void restorepanel(void){ DrawBuffer = DrawBufferSPI; DrawPixel = DrawPixelNormal; DrawBLITBuffer = DrawBufferSPI; - if(Option.DISPLAY_TYPE == ILI9341 || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE == ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE == ST7789B){ + if(Option.DISPLAY_TYPE == ILI9341 || Option.DISPLAY_TYPE == ST7796SP || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE == ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE == ST7789B){ ReadBLITBuffer = ReadBufferSPI; ReadBuffer = ReadBufferSPI; ScrollLCD = ScrollLCDSPI; @@ -5024,7 +5023,7 @@ void restorepanel(void){ WriteBuf=NULL; } void setframebuffer(void){ - if(!((Option.DISPLAY_TYPE>I2C_PANEL && Option.DISPLAY_TYPE < BufferedPanel) || (Option.DISPLAY_TYPE>=SSDPANEL && Option.DISPLAY_TYPEI2C_PANEL && Option.DISPLAY_TYPE < BufferedPanel) || (Option.DISPLAY_TYPE>=SSDPANEL && Option.DISPLAY_TYPE=NEXTGEN))return; DrawRectangle=DrawRectangle16; DrawBitmap= DrawBitmap16; ScrollLCD=ScrollLCD16; @@ -5294,7 +5293,7 @@ void blitmerge (int x0, int y0, int w, int h, uint8_t colour){ #ifdef PICOMITE mutex_enter_blocking(&frameBufferMutex); // lock the frame buffer #endif - if(Option.DISPLAY_TYPE==ILI9341 || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE==ST7789B || Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P ){ + if(Option.DISPLAY_TYPE==ILI9341 || Option.DISPLAY_TYPE == ST7796SP || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE==ST7789B || Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P ){ while(GetLineILI9341()!=0){} } for(int y=y0;y=HRes || y>=VRes)return; - if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); + if((Option.DISPLAY_TYPE>=VIRTUAL && Option.DISPLAY_TYPE>1))+(x>>1)); if(x & 1){ @@ -7039,7 +7038,7 @@ void DrawRectangle16(int x1, int y1, int x2, int y2, int c){ // unsigned char mask; unsigned char colour = RGB121(c);; unsigned char bcolour=(colour<<4) | colour; - if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); + if((Option.DISPLAY_TYPE>=VIRTUAL && Option.DISPLAY_TYPE= HRes) x1 = HRes - 1; if(x2 < 0) x2 = 0; @@ -7077,7 +7076,7 @@ void DrawBitmap16(int x1, int y1, int width, int height, int scale, int fc, int if(x1>=HRes || y1>=VRes || x1+width*scale<0 || y1+height*scale<0)return; unsigned char fcolour = RGB121(fc); unsigned char bcolour = RGB121(bc); - if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); + if((Option.DISPLAY_TYPE>=VIRTUAL && Option.DISPLAY_TYPE=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); + if((Option.DISPLAY_TYPE>=VIRTUAL && Option.DISPLAY_TYPE=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); + if((Option.DISPLAY_TYPE>=VIRTUAL && Option.DISPLAY_TYPE=0 && x=0 && y=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); + if((Option.DISPLAY_TYPE>=VIRTUAL && Option.DISPLAY_TYPE=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); + if((Option.DISPLAY_TYPE>=VIRTUAL && Option.DISPLAY_TYPE=0 && x=0 && y=HRes || y>=VRes)return; - if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); + if((Option.DISPLAY_TYPE>=VIRTUAL && Option.DISPLAY_TYPE>3))+(x>>3)); uint8_t bit = 1<<(x % 8); if(c)*p |=bit; @@ -7293,7 +7292,7 @@ void DrawRectangle2(int x1, int y1, int x2, int y2, int c){ int x,y,x1p, x2p, t; unsigned char mask; volatile unsigned char *p; - if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); + if((Option.DISPLAY_TYPE>=VIRTUAL && Option.DISPLAY_TYPE= HRes) x1 = HRes - 1; if(x2 < 0) x2 = 0; @@ -7361,7 +7360,7 @@ void DrawBitmap2(int x1, int y1, int width, int height, int scale, int fc, int b unsigned char mask; if(x1>=HRes || y1>=VRes || x1+width*scale<0 || y1+height*scale<0)return; int tilematch=0; - if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); + if((Option.DISPLAY_TYPE>=VIRTUAL && Option.DISPLAY_TYPE=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); + if((Option.DISPLAY_TYPE>=VIRTUAL && Option.DISPLAY_TYPE=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); + if((Option.DISPLAY_TYPE>=VIRTUAL && Option.DISPLAY_TYPE=0 && x=0 && y=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); + if((Option.DISPLAY_TYPE>=VIRTUAL && Option.DISPLAY_TYPE=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); + if((Option.DISPLAY_TYPE>=VIRTUAL && Option.DISPLAY_TYPE= NEXTGEN) return; DisplayHRes = HRes = display_details[Option.DISPLAY_TYPE].horizontal; DisplayVRes = VRes = display_details[Option.DISPLAY_TYPE].vertical; if(Option.DISPLAY_TYPE==VIRTUAL_M){ diff --git a/Code/pico_multi_booter/picomite/Draw.h b/Code/pico_multi_booter/picomite/Draw.h index 3360b43..ceafd15 100644 --- a/Code/pico_multi_booter/picomite/Draw.h +++ b/Code/pico_multi_booter/picomite/Draw.h @@ -105,8 +105,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF #define PIN_RESTART 9997 // reset caused by entering 0 at the PIN prompt #define RESTART_NOAUTORUN 9996 // reset required after changing the LCD or touch config #define PinRead(a) gpio_get(PinDef[a].GPno) -#define LCDMaxV 480 -#define LCDMaxH 800 #define VMaxV 480 #define VMaxH 640 extern int GetJustification(char *p, int *jh, int *jv, int *jo); diff --git a/Code/pico_multi_booter/picomite/Editor.c b/Code/pico_multi_booter/picomite/Editor.c index 79f0b88..006bbac 100644 --- a/Code/pico_multi_booter/picomite/Editor.c +++ b/Code/pico_multi_booter/picomite/Editor.c @@ -374,8 +374,8 @@ void edit(unsigned char *cmdline, bool cmdfile) { gui_fcolour = WHITE; gui_bcolour = BLACK; } - if(Option.DISPLAY_CONSOLE == true && gui_font_width > 16*HRes/640) error("Font is too large"); - if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf)FreeMemorySafe((void **)&WriteBuf); + if(Option.DISPLAY_CONSOLE == true && HRes/gui_font_width <32) error("Font is too large"); + if(Option.DISPLAY_TYPE>=VIRTUAL && Option.DISPLAY_TYPE>= 1; @@ -1589,23 +1588,9 @@ void cmd_port(void) { pincode++; } } - readmask=gpio_get_all64(); + readmask=gpio_get_out_level_all64(); readmask &=mask; - gpio_xor_mask64(setmask ^ readmask); -#ifdef rp2350 - #ifdef PICOMITEWEB - int n=NBRPINS; - #else - int n=rp2350a ? 44: NBRPINS; - #endif -#else - int n=NBRPINS; -#endif - - for(int i=0;i>=1; - } + gpio_xor_mask(setmask ^ readmask); } @@ -1660,6 +1645,7 @@ void fun_port(void) { getargs(&ep, NBRPINS * 4, (unsigned char *)","); if((argc & 0b11) != 0b11) error("Invalid syntax"); uint64_t pinstate=gpio_get_all64(); + uint64_t outpinstate=gpio_get_out_level_all64(); for(i = argc - 3; i >= 0; i -= 4) { code=0; if(!(code=codecheck(argv[i])))argv[i]+=2; @@ -1673,7 +1659,8 @@ void fun_port(void) { else pin=pincode; if(IsInvalidPin(pin) || !(ExtCurrentConfig[pin] == EXT_DIG_IN || ExtCurrentConfig[pin] == EXT_DIG_OUT || ExtCurrentConfig[pin] == EXT_INT_HI || ExtCurrentConfig[pin] == EXT_INT_LO || ExtCurrentConfig[pin] == EXT_INT_BOTH)) error("Invalid input pin"); value <<= 1; - value |= (pinstate & (1<MAX_PROG_SIZE)error("File size % cannot exceed %",fsize,MAX_PROG_SIZE); - uint8_t *q=(uint8_t *)c; - memset(q,0,MAX_PROG_SIZE); - for(int k = 0; k < fsize; k++){ // write to the flash byte by byte - *q++=FileGetChar(fnbr); - } - FileClose(fnbr); - } else if ((p = checkstring(cmdline, (unsigned char *)"FILE LOAD"))) { int overwrite=0; @@ -533,6 +509,7 @@ void MIPS16 cmd_psram(void) } uint8_t *c = (uint8_t *)(PSRAMblock + ((i - 1) * MAX_PROG_SIZE)); if (*c != 0x0 && overwrite==0) error("Already programmed"); + memset(c,0xFF,MAX_PROG_SIZE); ClearTempMemory(); SaveContext(); MemLoadProgram(argv[2],c); @@ -717,8 +694,10 @@ void MIPS16 cmd_flash(void) pp--; if ((unsigned char)*pp == T_NEWLINE) { + char *p=(char *)pp; MMPrintString(": \""); - llist((unsigned char *)buff, (unsigned char *)pp); + buff[0]='\'';buff[1]='#'; + while(buff[0]=='\'' && buff[1]=='#')p=(char *)llist((unsigned char *)buff, (unsigned char *)p); MMPrintString(buff); MMPrintString("\"\r\n"); } @@ -5017,7 +4996,7 @@ void LoadOptions(void) RGB121map[15] = WHITE; #ifdef PICOCALC - Option.DISPLAY_TYPE = ILI9488P; + Option.DISPLAY_TYPE = ST7796SP; Option.SYSTEM_CLK = 14; Option.SYSTEM_MOSI = 15; Option.SYSTEM_MISO = 16; @@ -5083,6 +5062,7 @@ void ResetOptions(bool startup) Option.DefaultBrightness = 100; Option.Baudrate = CONSOLE_BAUDRATE; Option.PROG_FLASH_SIZE=MAX_PROG_SIZE; + Option.ColourCode=0x01; #ifdef PICOMITEVGA Option.DISPLAY_CONSOLE = 1; Option.DISPLAY_TYPE = SCREENMODE1; @@ -5259,7 +5239,6 @@ void FlashWriteAlign(void) } FlashWriteWord(0xFFFFFFFF); } - void FlashWriteClose(void) { while (mi8p != 0) diff --git a/Code/pico_multi_booter/picomite/Functions.c b/Code/pico_multi_booter/picomite/Functions.c index a9ad4ec..4960650 100644 --- a/Code/pico_multi_booter/picomite/Functions.c +++ b/Code/pico_multi_booter/picomite/Functions.c @@ -508,8 +508,8 @@ typedef enum { MMCMDLINE, #ifdef PICOMITEWEB MMMESSAGE, - MMTOPIC, MMADDRESS, + MMTOPIC, #endif MMFLAG, MMDISPLAY, @@ -575,16 +575,16 @@ typedef enum { Mstrcpy(sret,messagebuff); targ=T_STR; break; - case MMTOPIC: - sret = GetTempMemory(STRINGSIZE); // this will last for the life of the command - Mstrcpy(sret,topicbuff); - targ=T_STR; - break; case MMADDRESS: sret = GetTempMemory(STRINGSIZE); // this will last for the life of the command Mstrcpy(sret,addressbuff); targ=T_STR; break; + case MMTOPIC: + sret = GetTempMemory(STRINGSIZE); // this will last for the life of the command + Mstrcpy(sret,topicbuff); + targ=T_STR; + break; #endif case MMFLAG: iret=g_flag; diff --git a/Code/pico_multi_booter/picomite/Hardware_Includes.h b/Code/pico_multi_booter/picomite/Hardware_Includes.h index 099cb11..632028a 100644 --- a/Code/pico_multi_booter/picomite/Hardware_Includes.h +++ b/Code/pico_multi_booter/picomite/Hardware_Includes.h @@ -62,6 +62,7 @@ extern volatile unsigned int PauseTimer; extern volatile unsigned int IntPauseTimer; extern volatile unsigned int Timer1, Timer2, Timer3, Timer4, Timer5; //1000Hz decrement timer extern volatile unsigned int diskchecktimer; +extern volatile unsigned int clocktimer; extern volatile int ds18b20Timer; extern volatile int CursorTimer; extern volatile unsigned int I2CTimer; @@ -297,8 +298,10 @@ extern struct tagMTRand *g_myrand; #define putch _putch #endif #endif +#define nunaddr 0xA4 / 2 #define CURSOR_OFF 350 // cursor off time in mS #define CURSOR_ON 650 // cursor on time in mS +#define RoundUptoInt(a) (((a) + (32 - 1)) & (~(32 - 1)))// round up to the nearest whole integer #define dp(...) {unsigned char s[140];sprintf((char *)s, __VA_ARGS__); MMPrintString((char *)s); MMPrintString((char *)"\r\n");} diff --git a/Code/pico_multi_booter/picomite/I2C.c b/Code/pico_multi_booter/picomite/I2C.c index 4fb7128..3dac84c 100644 --- a/Code/pico_multi_booter/picomite/I2C.c +++ b/Code/pico_multi_booter/picomite/I2C.c @@ -40,7 +40,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF #include "hardware/irq.h" -#define nunaddr 0xA4 / 2; #define PinRead(a) gpio_get(PinDef[a].GPno) extern void DrawBufferMEM(int x1, int y1, int x2, int y2, unsigned char * p); extern void ReadBufferMEM(int x1, int y1, int x2, int y2, unsigned char * buff); @@ -304,11 +303,17 @@ void cmd_i2c(void) { "CLOSE")) != NULL) i2cDisable(p); else if ((p = checkstring(cmdline, (unsigned char * ) - "WRITE")) != NULL) - i2cSend(p); + "WRITE")) != NULL){ + if(I2C0SDApin==Option.SYSTEM_I2C_SDA) I2C_Timeout=1000; + i2cSend(p); + if(I2C0SDApin==Option.SYSTEM_I2C_SDA) I2C_Timeout=SystemI2CTimeout; + } else if ((p = checkstring(cmdline, (unsigned char * ) - "READ")) != NULL) - i2cReceive(p); + "READ")) != NULL){ + if(I2C0SDApin==Option.SYSTEM_I2C_SDA) I2C_Timeout=1000; + i2cReceive(p); + if(I2C0SDApin==Option.SYSTEM_I2C_SDA) I2C_Timeout=SystemI2CTimeout; + } else if ((p = checkstring(cmdline, (unsigned char * ) "CHECK")) != NULL) i2cCheck(p); @@ -338,11 +343,17 @@ void cmd_i2c2(void) { "CLOSE")) != NULL) i2c2Disable(p); else if ((p = checkstring(cmdline, (unsigned char * ) - "WRITE")) != NULL) - i2c2Send(p); + "WRITE")) != NULL){ + if(I2C1SDApin==Option.SYSTEM_I2C_SDA) I2C2_Timeout=1000; + i2c2Send(p); + if(I2C1SDApin==Option.SYSTEM_I2C_SDA) I2C2_Timeout=SystemI2CTimeout; + } else if ((p = checkstring(cmdline, (unsigned char * ) - "READ")) != NULL) - i2c2Receive(p); + "READ")) != NULL){ + if(I2C1SDApin==Option.SYSTEM_I2C_SDA) I2C2_Timeout=1000; + i2c2Receive(p); + if(I2C1SDApin==Option.SYSTEM_I2C_SDA) I2C2_Timeout=SystemI2CTimeout; + } else if ((p = checkstring(cmdline, (unsigned char * ) "CHECK")) != NULL) i2c2Check(p); @@ -614,6 +625,7 @@ void CheckI2CKeyboard(int noerror, int read) { void RtcGetTime(int noerror) { char * buff = GetTempMemory(STRINGSIZE); // Received data is stored here int DS1307; + clocktimer=(1000*60*60); if (I2C0locked) { I2C_Sendlen = 1; // send one byte I2C_Rcvlen = 0; @@ -691,9 +703,24 @@ void MIPS16 cmd_rtc(void) { unsigned char * p; void * ptr = NULL; if (!(I2C0locked || I2C1locked)) error("SYSTEM I2C not configured"); - if (checkstring(cmdline, (unsigned char * ) - "GETTIME")) { - RtcGetTime(0); + if (checkstring(cmdline, (unsigned char * )"GETTIME")) { + int repeat=5; + noRTC=0; + while(1){ + while(!(classicread==0 && nunchuckread==0)){routinechecks();} + RtcGetTime(1); + if(noRTC==0)break; + repeat--; + if(!repeat)break; + } + if(noRTC){ + if (CurrentLinePtr) error("RTC not responding"); + if (Option.RTC) { + MMPrintString("RTC not responding"); + MMPrintString("\r\n"); + } + } + return; } if ((p = checkstring(cmdline, (unsigned char * ) @@ -1072,8 +1099,10 @@ void i2cCheck(unsigned char * p) { addr = getinteger(argv[0]); if (addr < 0 || addr > 0x7F) error("Invalid I2C address"); // int ret=i2c_read_blocking(i2c0, addr, &rxdata, 1, false); - int ret = i2c_read_timeout_us(i2c0, addr, & rxdata, 1, false, 100); - mmI2Cvalue = ret < 0 ? 1 : 0; + int i2cret = i2c_read_timeout_us(i2c0, addr, & rxdata, 1, false, 1000); + mmI2Cvalue = 0; + if (i2cret == PICO_ERROR_GENERIC) mmI2Cvalue = 1; + if (i2cret == PICO_ERROR_TIMEOUT) mmI2Cvalue = 2; } void i2c2Check(unsigned char * p) { int addr; @@ -1084,8 +1113,10 @@ void i2c2Check(unsigned char * p) { addr = getinteger(argv[0]); if (addr < 0 || addr > 0x7F) error("Invalid I2C address"); // int ret=i2c_read_blocking(i2c1, addr, &rxdata, 1, false); - int ret = i2c_read_timeout_us(i2c1, addr, & rxdata, 1, false, 100); - mmI2Cvalue = ret < 0 ? 1 : 0; + int i2cret = i2c_read_timeout_us(i2c1, addr, & rxdata, 1, false, 1000); + mmI2Cvalue = 0; + if (i2cret == PICO_ERROR_GENERIC) mmI2Cvalue = 1; + if (i2cret == PICO_ERROR_TIMEOUT) mmI2Cvalue = 2; } // receive data from an I2C slave - master mode void i2cReceive(unsigned char * p) { @@ -1446,6 +1477,7 @@ void GeneralReceive(unsigned int addr, int nbr, char * p) { if (I2C0locked) { I2C_Rcvbuf_Float = NULL; I2C_Rcvbuf_Int = NULL; + I2C_Rcvbuf_String = NULL; I2C_Sendlen = 0; // send one byte I2C_Rcvlen = nbr; I2C_Addr = addr; // address of the device @@ -1453,6 +1485,7 @@ void GeneralReceive(unsigned int addr, int nbr, char * p) { } else { I2C2_Rcvbuf_Float = NULL; I2C2_Rcvbuf_Int = NULL; + I2C2_Rcvbuf_String = NULL; I2C2_Sendlen = 0; // send one byte I2C2_Rcvlen = nbr; I2C2_Addr = addr; // address of the device diff --git a/Code/pico_multi_booter/picomite/I2C.h b/Code/pico_multi_booter/picomite/I2C.h index a854302..d622e14 100644 --- a/Code/pico_multi_booter/picomite/I2C.h +++ b/Code/pico_multi_booter/picomite/I2C.h @@ -65,7 +65,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF #define I2C_Status_Slave_Receive_Rdy 0x00100000 #define I2C_Status_Slave_Receive_Full 0x00200000 #define SSD1306_I2C_Addr 0x3c - +#ifdef PICOCALC +#define SystemI2CTimeout 500 +#else +#define SystemI2CTimeout 5 +#endif // Global variables provided by I2C.c extern unsigned int I2C_Timer; // master timeout counter extern char *I2C_IntLine; // pointer to the master interrupt line number diff --git a/Code/pico_multi_booter/picomite/MMBasic.c b/Code/pico_multi_booter/picomite/MMBasic.c index bb8862b..ab5d1f1 100644 --- a/Code/pico_multi_booter/picomite/MMBasic.c +++ b/Code/pico_multi_booter/picomite/MMBasic.c @@ -557,33 +557,34 @@ void MIPS16 DefinedSubFun(int isfun, unsigned char *cmd, int index, MMFLOAT *fa, #else void MIPS16 __not_in_flash_func(DefinedSubFun)(int isfun, unsigned char *cmd, int index, MMFLOAT *fa, long long int *i64a, unsigned char **sa, int *typ) { #endif - unsigned char *p, *s, *tp, *ttp, tcmdtoken; - unsigned char *CallersLinePtr, *SubLinePtr = NULL; + + unsigned char *p, *s, *tp, *ttp, tcmdtoken; + unsigned char *CallersLinePtr, *SubLinePtr = NULL; unsigned char *argbuf1; unsigned char **argv1; int argc1; unsigned char *argbuf2; unsigned char **argv2; int argc2; unsigned char fun_name[MAXVARLEN + 1]; unsigned char *argbyref; - int i; + int i; int ArgType, FunType; int *argtype; union u_argval { - MMFLOAT f; // the value if it is a float - long long int i; // the value if it is an integer - MMFLOAT *fa; // pointer to the allocated memory if it is an array of floats - long long int *ia; // pointer to the allocated memory if it is an array of integers - unsigned char *s; // pointer to the allocated memory if it is a string + MMFLOAT f; // the value if it is a float + long long int i; // the value if it is an integer + MMFLOAT *fa; // pointer to the allocated memory if it is an array of floats + long long int *ia; // pointer to the allocated memory if it is an array of integers + unsigned char *s; // pointer to the allocated memory if it is a string } *argval; int *argVarIndex; CallersLinePtr = CurrentLinePtr; - SubLinePtr = subfun[index]; // used for error reporting - p = SubLinePtr + sizeof(CommandToken); // point to the sub or function definition + SubLinePtr = subfun[index]; // used for error reporting + p = SubLinePtr + sizeof(CommandToken); // point to the sub or function definition skipspace(p); ttp = p; - + // copy the sub/fun name from the definition into temp storage and terminate // p is left pointing to the end of the name (ie, start of the argument list in the definition) - CurrentLinePtr = SubLinePtr; // report errors at the definition + CurrentLinePtr = SubLinePtr; // report errors at the definition tp = fun_name; *tp++ = *p++; while(isnamechar(*p)) *tp++ = *p++; if(*p == '$' || *p == '%' || *p == '!') { @@ -593,7 +594,7 @@ void MIPS16 __not_in_flash_func(DefinedSubFun)(int isfun, unsigned char *cmd, in *tp++ = *p++; } *tp = 0; - + if(isfun && *p != '(' /*&& (*SubLinePtr != cmdCFUN)*/) error("Function definition"); // find the end of the caller's identifier, tp is left pointing to the start of the caller's argument list @@ -620,7 +621,6 @@ void MIPS16 __not_in_flash_func(DefinedSubFun)(int isfun, unsigned char *cmd, in FunType |= (V_FIND | V_DIM_VAR | V_LOCAL | V_EMPTY_OK); } - // from now on // tp = the caller's argument list // p = the argument list for the definition @@ -634,11 +634,11 @@ void MIPS16 __not_in_flash_func(DefinedSubFun)(int isfun, unsigned char *cmd, in return; } // from now on we have a user defined sub or function (not a C routine) - + if(gosubindex >= MAXGOSUB) error("Too many nested SUB/FUN"); errorstack[gosubindex] = CallersLinePtr; - gosubstack[gosubindex++] = isfun ? NULL : nextstmt; // NULL signifies that this is returned to by ending ExecuteProgram() - #define buffneeded MAX_ARG_COUNT*(sizeof(union u_argval)+ 2*sizeof(int)+3*sizeof(unsigned char *)+sizeof(unsigned char))+ 2*STRINGSIZE + gosubstack[gosubindex++] = isfun ? NULL : nextstmt; // NULL signifies that this is returned to by ending ExecuteProgram() + #define buffneeded MAX_ARG_COUNT*(sizeof(union u_argval)+ 2*sizeof(int)+3*sizeof(unsigned char *)+sizeof(unsigned char))+ 2*STRINGSIZE // allocate memory for processing the arguments argval=GetSystemMemory(buffneeded); argtype=(void *)argval+MAX_ARG_COUNT * sizeof(union u_argval); @@ -664,12 +664,12 @@ void MIPS16 __not_in_flash_func(DefinedSubFun)(int isfun, unsigned char *cmd, in CurrentLinePtr = CallersLinePtr; // report errors at the caller if(argc1 > argc2 || (argc1 && (argc1 & 1) == 0)) error("Argument list"); - // step through the arguments supplied by the caller and get the value supplied + // step through the arguments supplied by the caller and get the value supplied // these can be: // - missing (ie, caller did not supply that parameter) // - a variable, in which case we need to get a pointer to that variable's data and save its index so later we can get its type // - an expression, in which case we evaluate the expression and get its value and type - for(i = 0; i < argc2; i += 2) { // count through the arguments in the definition of the sub/fun + for(i = 0; i < argc2; i += 2) { // count through the arguments in the definition of the sub/fun if(i < argc1 && *argv1[i]) { // check if the argument is a valid variable if(i < argc1 && isnamestart(*argv1[i]) && *skipvar(argv1[i], false) == 0) { @@ -690,19 +690,26 @@ void MIPS16 __not_in_flash_func(DefinedSubFun)(int isfun, unsigned char *cmd, in // check for BYVAL or BYREF in sub/fun definition argbyref[i]=0; skipspace(argv2[i]); - if(toupper(*argv2[i]) == 'B' && toupper(*(argv2[i]+1)) == 'Y') { - if((checkstring(argv2[i] + 2, (unsigned char *)"VAL")) != NULL) { // if BYVAL - argtype[i] = 0; // remove any pointer flag in the caller - argv2[i] += 5; // skip to the variable start - } else { - if((checkstring(argv2[i] + 2, (unsigned char *)"REF")) != NULL) { // if BYREF - if((argtype[i] & T_PTR) == 0) error("Variable required for BYREF"); - argv2[i] += 5; // skip to the variable start - } - argbyref[i]=1; - } - skipspace(argv2[i]); - } + if(toupper(*argv2[i]) == 'B' && toupper(*(argv2[i]+1)) == 'Y') { + if((checkstring(argv2[i] + 2, (unsigned char *)"VAL")) != NULL) { // if BYVAL + //Only if not an array remove any pointer flag in the caller + if(g_vartbl[argVarIndex[i]].dims[0] == 0){ + argtype[i] = 0; + }else{ + error("Array as BYVAL not allowed $",argv1[i]); + } + argv2[i] += 5; // skip to the variable start + argbyref[i]=2; + } else { + if((checkstring(argv2[i] + 2, (unsigned char *)"REF")) != NULL) { // if BYREF + //if((argtype[i] & T_PTR) == 0) error("Variable required for BYREF $", argv1[i]); + argv2[i] += 5; // skip to the variable start + argbyref[i]=1; + if((argtype[i] & T_PTR) == 0)error("Variable required for BYREF $", argv1[i]); + } + } + skipspace(argv2[i]); + } // if argument is present and is not a pointer to a variable then evaluate it as an expression if(argtype[i] == 0) { @@ -724,6 +731,16 @@ void MIPS16 __not_in_flash_func(DefinedSubFun)(int isfun, unsigned char *cmd, in g_LocalIndex++; for(i = 0; i < argc2; i += 2) { // count through the arguments in the definition of the sub/fun ArgType = T_NOTYPE; + //skip BYVAL/BYREF keywords + if(toupper(*argv2[i]) == 'B' && toupper(*(argv2[i]+1)) == 'Y') { + if((checkstring(argv2[i] + 2,(unsigned char *) "VAL")) != NULL) { + argv2[i] += 5; + }else if((checkstring(argv2[i] + 2, (unsigned char *)"REF")) != NULL) { // if BYREF + argv2[i] += 5; // skip to the variable start + } + } + + // if (argbyref[i] )argv2[i] += 5; tp = skipvar(argv2[i], false); // point to after the variable skipspace(tp); if(*tp == tokenAS) { // are we using Microsoft syntax (eg, AS INTEGER)? @@ -734,11 +751,12 @@ void MIPS16 __not_in_flash_func(DefinedSubFun)(int isfun, unsigned char *cmd, in ArgType |= (V_FIND | V_DIM_VAR | V_LOCAL | V_EMPTY_OK); tp = findvar(argv2[i], ArgType); // declare the local variable if(g_vartbl[g_VarIndex].dims[0] > 0) error("Argument list"); // if it is an array it must be an empty array - + CurrentLinePtr = CallersLinePtr; // report errors at the caller // if the definition called for an array, special processing and checking will be required if(g_vartbl[g_VarIndex].dims[0] == -1) { + //if( (argbyref[i]==2)) error("Array must be passed as BYREF $",argv1[i]); int j; if(g_vartbl[argVarIndex[i]].dims[0] == 0) error("Expected an array"); if(TypeMask(g_vartbl[g_VarIndex].type) != TypeMask(argtype[i])) error("Incompatible type: $", argv1[i]); @@ -749,8 +767,8 @@ void MIPS16 __not_in_flash_func(DefinedSubFun)(int isfun, unsigned char *cmd, in // if this is a pointer check and the type is NOT the same as that requested in the sub/fun definition if((argtype[i] & T_PTR) && TypeMask(g_vartbl[g_VarIndex].type) != TypeMask(argtype[i])) { - if(argbyref[i]){ error("BYREF requires same types: $", argv1[i]);} - if((TypeMask(g_vartbl[g_VarIndex].type) & T_STR) || (TypeMask(argtype[i]) & T_STR)) + if(argbyref[i]==1){ error("BYREF requires same types: $", argv1[i]);} + if((TypeMask(g_vartbl[g_VarIndex].type) & T_STR) || (TypeMask(argtype[i]) & T_STR)) error("Incompatible type: $", argv1[i]); // make this into an ordinary argument if(g_vartbl[argVarIndex[i]].type & T_PTR) { @@ -760,7 +778,7 @@ void MIPS16 __not_in_flash_func(DefinedSubFun)(int isfun, unsigned char *cmd, in } argtype[i] &= ~T_PTR; // and remove the pointer flag } - + // if this is a pointer (note: at this point the caller type and the required type must be the same) if(argtype[i] & T_PTR) { // the argument supplied was a variable so we must setup the local variable as a pointer @@ -842,9 +860,9 @@ void MIPS16 __not_in_flash_func(DefinedSubFun)(int isfun, unsigned char *cmd, in else *sa = tp; // for a string we just need to return the local memory *typ = FunType; // save the function type for the caller - ClearVars(g_LocalIndex--, true); // delete any local variables + ClearVars(g_LocalIndex--, true); // delete any local variables g_TempMemoryIsChanged = true; // signal that temporary memory should be checked - gosubindex--; + gosubindex--; } char MIPS16 *strcasechr(const char *p, int ch) @@ -2785,11 +2803,11 @@ void MIPS16 error(char *msg, ...) { } if(OptionErrorSkip) longjmp(ErrNext, 1); // if OPTION ERROR SKIP/IGNORE is in force #ifdef PICOMITE - multicore_fifo_push_blocking(0xFF); - busy_wait_ms(mergetimer+200); - if(mergerunning){ - _excep_code = RESET_COMMAND; - SoftReset(); + multicore_fifo_push_blocking(0xFF); + busy_wait_ms(mergetimer+200); + if(mergerunning){ + _excep_code = RESET_COMMAND; + SoftReset(); } #endif diff --git a/Code/pico_multi_booter/picomite/MM_Misc.c b/Code/pico_multi_booter/picomite/MM_Misc.c index 9199de4..3739ff5 100644 --- a/Code/pico_multi_booter/picomite/MM_Misc.c +++ b/Code/pico_multi_booter/picomite/MM_Misc.c @@ -2050,7 +2050,7 @@ void MIPS16 printoptions(void){ } PRet(); } - if(Option.DISPLAY_TYPE >= VIRTUAL){ + if(Option.DISPLAY_TYPE >= VIRTUAL && Option.DISPLAY_TYPE=VGADISPLAY))Option.NoScroll=1; + if(!(Option.DISPLAY_TYPE==ST7789B || Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ST7796SP || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ILI9341 || Option.DISPLAY_TYPE>=VGADISPLAY))Option.NoScroll=1; if(!(Option.DISPLAY_ORIENTATION == DISPLAY_LANDSCAPE) && Option.DISPLAY_TYPE==SSDTYPE) error("Landscape only"); skipspace(tp); Option.DefaultFC = WHITE; diff --git a/Code/pico_multi_booter/picomite/Memory.c b/Code/pico_multi_booter/picomite/Memory.c index 0ae5fe2..c2d621a 100644 --- a/Code/pico_multi_booter/picomite/Memory.c +++ b/Code/pico_multi_booter/picomite/Memory.c @@ -55,20 +55,25 @@ extern const uint8_t *flash_progmemory; unsigned char __attribute__ ((aligned (4096))) AllMemory[HEAP_MEMORY_SIZE+256+320*240*2]; unsigned char *FRAMEBUFFER=AllMemory+HEAP_MEMORY_SIZE+256; uint32_t framebuffersize=320*240*2; - #else - unsigned char __attribute__ ((aligned (256))) AllMemory[HEAP_MEMORY_SIZE+256]; - #endif - unsigned char *MMHeap=AllMemory; + unsigned char *MMHeap=AllMemory; #else + unsigned char __attribute__ ((aligned (256))) AllMemory[HEAP_MEMORY_SIZE+256]; + unsigned char *MMHeap=AllMemory; + uint32_t framebuffersize=0; + unsigned char *FRAMEBUFFER=NULL; + #endif +#else #ifdef PICOMITEVGA unsigned char __attribute__ ((aligned (4096))) Heap[HEAP_MEMORY_SIZE+256]; unsigned char __attribute__ ((aligned (256))) video[640*480/8]; unsigned char *FRAMEBUFFER=video; uint32_t framebuffersize=640*480/8; unsigned char *MMHeap=Heap; - #else + #else unsigned char __attribute__ ((aligned (256))) AllMemory[HEAP_MEMORY_SIZE+256]; unsigned char *MMHeap=AllMemory; + uint32_t framebuffersize=0; + unsigned char *FRAMEBUFFER=NULL; #endif #endif diff --git a/Code/pico_multi_booter/picomite/PicoMite.c b/Code/pico_multi_booter/picomite/PicoMite.c index 53acc71..6df45ce 100644 --- a/Code/pico_multi_booter/picomite/PicoMite.c +++ b/Code/pico_multi_booter/picomite/PicoMite.c @@ -497,7 +497,6 @@ void __not_in_flash_func(routinechecks)(void){ if(clocktimer==0 && Option.RTC){ if(classicread==0 && nunchuckread==0){ RtcGetTime(0); - clocktimer=(1000*60*60); } } #ifndef USBKEYBOARD @@ -3282,16 +3281,16 @@ void MIPS32 __not_in_flash_func(HDMIloop3)(void){ case SCREENMODE2: //400 X 300 x 4bit-colour mapped to 256 or 424 X 240 x 4bit-colour mapped to 256 { uint16_t *p=(uint16_t *)HDMIlines[line_to_load]; - uint8_t l,d,s; + uint8_t l,d; int pp= (Line_dup)*vgaloop4; for(int i=0; i>=4;l>>=4;s>>=4; + d>>=4;l>>=4; if((l&0xf)!=transparent){ *p++=map16d[l&0xf]; } else { @@ -4095,16 +4094,6 @@ int MIPS16 main(){ LoadOptions(); #ifdef rp2350 if(rom_get_last_boot_type()==BOOT_TYPE_FLASH_UPDATE)restart_reason=0xFFFFFFFC; -// if(Option.PSRAM_CS_PIN){ -// gpio_init(47); -// gpio_set_dir(47, GPIO_OUT); -// gpio_put(47,GPIO_PIN_SET); -//} -// if(!rp2350a){ -// gpio_init(47); -// gpio_set_dir(47, GPIO_OUT); -// gpio_put(47,GPIO_PIN_SET); -// } #else if(restart_reason==0x10001 || restart_reason==0x101)restart_reason=0xFFFFFFFC; #endif @@ -4637,7 +4626,7 @@ autorun: i=0; WatchdogSet=savewatchdog; CommandToken tkn=commandtbl_decode(tknbuf); - if(tkn==GetCommandValue((unsigned char *)"RUN"))i=1; + if(tkn==GetCommandValue((unsigned char *)"RUN") || tkn==GetCommandValue((unsigned char *)"EDIT") || tkn==GetCommandValue((unsigned char *)"AUTOSAVE"))i=1; if (setjmp(jmprun) != 0) { PrepareProgram(false); CurrentLinePtr = 0; diff --git a/Code/pico_multi_booter/picomite/README.md b/Code/pico_multi_booter/picomite/README.md index e610c5c..8371430 100644 --- a/Code/pico_multi_booter/picomite/README.md +++ b/Code/pico_multi_booter/picomite/README.md @@ -31,10 +31,15 @@ SETUP PICOCALC FIRMWARE mkdir -p ~/picocalc && cd ~/picocalc git clone https://github.com/madcock/PicoMiteAllVersions.git cd PicoMiteAllVersions -mv ~/pico/pico-sdk/src/rp2_common/hardware_flash/flash.c ~/pico/pico-sdk/src/rp2_common/hardware_flash/flash.bak -ln -s ~/picocalc/PicoMiteAllVersions/flash.c ~/pico/pico-sdk/src/rp2_common/hardware_flash/flash.c mv ~/pico/pico-sdk/src/rp2_common/hardware_gpio/gpio.c ~/pico/pico-sdk/src/rp2_common/hardware_gpio/gpio.bak ln -s ~/picocalc/PicoMiteAllVersions/gpio.c ~/pico/pico-sdk/src/rp2_common/hardware_gpio/gpio.c +mv ~/pico/pico-sdk/src/rp2_common/hardware_gpio/include/hardware/gpio.h ~/pico/pico-sdk/src/rp2_common/hardware_gpio/include/hardware/gpio.bak +ln -s ~/picocalc/PicoMiteAllVersions/gpio.h ~/pico/pico-sdk/src/rp2_common/hardware_gpio/include/hardware/gpio.h +mv ~/pico/pico-sdk/src/rp2_common/pico_float/float_sci_m33_vfp.S ~/pico/pico-sdk/src/rp2_common/pico_float/float_sci_m33_vfp.bak +ln -s ~/picocalc/PicoMiteAllVersions/float_sci_m33_vfp.S ~/pico/pico-sdk/src/rp2_common/pico_float/float_sci_m33_vfp.S +mv ~/pico/pico-sdk/src/rp2_common/hardware_flash/flash.c ~/pico/pico-sdk/src/rp2_common/hardware_flash/flash.bak +ln -s ~/picocalc/PicoMiteAllVersions/flash.c ~/pico/pico-sdk/src/rp2_common/hardware_flash/flash.c + ``` EDIT ``~/picocalc/PicoMiteAllVersions/CMakeLists.txt`` TO CHOOSE TARGET ----------------------------------------------------------------------- @@ -62,9 +67,11 @@ make (_original readme follows..._) # PicoMiteRP2350 -This contains files to build MMbasic V6.00.02RC23 to run on both RP2040 and RP2350
+This contains files to build MMbasic V6.00.02 to run on both RP2040 and RP2350
Compile with GCC 13.3.1 arm-none-eabi
-Build with sdk V2.1.1 but replace gpio.c and flash.c with the ones included here
+ + Build with sdk V2.1.1 but replace gpio.c, gpio.h, float_sci_m33_vfp.S, and flash.c with the ones included here
+ Change CMakeLists.txt line 4 to determine which variant to build

RP2040
diff --git a/Code/pico_multi_booter/picomite/SPI-111.c b/Code/pico_multi_booter/picomite/SPI-111.c new file mode 100644 index 0000000..d9e0f78 --- /dev/null +++ b/Code/pico_multi_booter/picomite/SPI-111.c @@ -0,0 +1,532 @@ +/*********************************************************************************************************************** +PicoMite MMBasic + +SPI-LCD.c + + Geoff Graham, Peter Mather +Copyright (c) 2021, All rights reserved. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the distribution. +3. The name MMBasic be used when referring to the interpreter in any documentation and promotional material and the original copyright message be displayed + on the console at startup (additional copyright messages may be added). +4. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed + by the . +5. Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software + without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +************************************************************************************************************************/ + +#include +#include "MMBasic_Includes.h" +#include "Hardware_Includes.h" + +const uint32_t maskSPI111[32]={0x00000001,0x00000003,0x00000007,0x0000000f,0x0000001f,0x0000003f,0x0000007f,0x000000ff, + 0x000001ff,0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff,0x00007fff,0x0000ffff, + 0x0001ffff,0x0003ffff,0x0007ffff,0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff, + 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff}; +const uint32_t rmaskSPI111[32]={0x80000000,0xC0000000,0xe0000000,0xf0000000,0xf8000000,0xfc000000,0xfe000000,0xff000000, + 0xff800000,0xffC00000,0xffe00000,0xfff00000,0xfff80000,0xfffc0000,0xfffe0000,0xffff0000, + 0xffff8000,0xffffC000,0xffffe000,0xfffff000,0xfffff800,0xfffffc00,0xfffffe00,0xffffff00, + 0xffffff80,0xffffffC0,0xffffffe0,0xfffffff0,0xfffffff8,0xfffffffc,0xfffffffe,0xffffffff}; + + +uint32_t *VideoBufRed = NULL; // Image buffer for red +uint32_t *VideoBufGrn = NULL; // Image buffer for green +uint32_t *VideoBufBlu = NULL; // Image buffer for blue +volatile int lcnt; +volatile int VCount; // counter for the number of lines in a frame +volatile int VState; // the state of the state machine +volatile int showbuffer = 0; // the next counter table (initialise in initVideo() below) +void SPI111hline(int x0, int x1, int y, int con, int which); +inline void plot(int x, int y, int con) ; + +void SPI111init(void){ +// if(Option.DISPLAY_TYPE !=SPI111) return; + DrawRectangle = DrawRectangleSPI111; + DrawBitmap = DrawBitmapSPI111; + ScrollLCD = ScrollSPI111; + DrawBuffer=DrawBufferSPI111; + ReadBuffer=ReadBufferSPI111; +} +void DrawRectangleSPI111(int x1, int y1, int x2, int y2, int c){ + int i, t; + int col=0; + if(c & 0xFF0000)col =1; + if(c & 0xFF00)col +=2; + if(c & 0xFF)col +=4; + // make sure the coordinates are kept within the display area + if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } + if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } + if(x1 < 0) x1 = 0; + if(x1 >= HRes) x1 = HRes - 1; + if(x2 < 0) x2 = 0; + if(x2 >= HRes) x2 = HRes - 1; + if(y1 < 0) y1 = 0; + if(y1 >= VRes) y1 = VRes - 1; + if(y2 < 0) y2 = 0; + if(y2 >= VRes) y2 = VRes - 1; + for(i=y1;i<=y2;i++){ + SPI111hline(x1,x2,i,col,0); + } + +} + +void DrawBitmapSPI111(int x1, int y1, int width, int height, int scale, int fc, int bc, unsigned char *bitmap){ + int i, j, k, m; + unsigned char fcol,bcol; + int vertCoord, horizCoord, XStart, XEnd, YEnd; + + // adjust when part of the bitmap is outside the displayable coordinates + vertCoord = y1; if(y1 < 0) y1 = 0; // the y coord is above the top of the screen + XStart = x1; if(XStart < 0) XStart = 0; // the x coord is to the left of the left marginn + XEnd = x1 + (width * scale) - 1; if(XEnd >= HRes) XEnd = HRes - 1; // the width of the bitmap will extend beyond the right margin + YEnd = y1 + (height * scale) - 1; if(YEnd >= VRes) YEnd = VRes - 1;// the height of the bitmap will extend beyond the bottom margin + fcol=0; bcol=0; + if(fc & 0xFF0000)fcol =1; + if(fc & 0xFF00)fcol +=2; + if(fc & 0xFF)fcol +=4; + if(bc!=-1){ + if(bc & 0xFF0000)bcol =1; + if(bc & 0xFF00)bcol +=2; + if(bc & 0xFF)bcol +=4; + } else bcol=0xff; + + for(i = 0; i < height; i++) { // step thru the font scan line by line + for(j = 0; j < scale; j++) { // repeat lines to scale the font + if(vertCoord++ < 0) continue; // we are above the top of the screen + if(vertCoord > VRes) return; // we have extended beyond the bottom of the screen + horizCoord = x1; + for(k = 0; k < width; k++) { // step through each bit in a scan line + for(m = 0; m < scale; m++) { // repeat pixels to scale in the x axis + if(horizCoord++ < 0) continue; // we have not reached the left margin + if(horizCoord > HRes) continue; // we are beyond the right margin + if((bitmap[((i * width) + k)/8] >> (((height * width) - ((i * width) + k) - 1) %8)) & 1) { + plot(horizCoord-1,vertCoord-1,fcol); + } else { + if(bcol!=0xff)plot(horizCoord-1,vertCoord-1,bcol); + } + + } + } + } + } + +} + +void SPI111hline(int x0, int x1, int y, int con, int which) { //draw a horizontal line + uint32_t w1, xx1, w0, xx0, x, xn, i; + const uint32_t a[]={0xFFFFFFFF,0x7FFFFFFF,0x3FFFFFFF,0x1FFFFFFF,0xFFFFFFF,0x7FFFFFF,0x3FFFFFF,0x1FFFFFF, + 0xFFFFFF,0x7FFFFF,0x3FFFFF,0x1FFFFF,0xFFFFF,0x7FFFF,0x3FFFF,0x1FFFF, + 0xFFFF,0x7FFF,0x3FFF,0x1FFF,0xFFF,0x7FF,0x3FF,0x1FF, + 0xFF,0x7F,0x3F,0x1F,0x0F,0x07,0x03,0x01}; + const uint32_t b[]={0x80000000,0xC0000000,0xe0000000,0xf0000000,0xf8000000,0xfc000000,0xfe000000,0xff000000, + 0xff800000,0xffC00000,0xffe00000,0xfff00000,0xfff80000,0xfffc0000,0xfffe0000,0xffff0000, + 0xffff8000,0xffffC000,0xffffe000,0xfffff000,0xfffff800,0xfffffc00,0xfffffe00,0xffffff00, + 0xffffff80,0xffffffC0,0xffffffe0,0xfffffff0,0xfffffff8,0xfffffffc,0xfffffffe,0xffffffff}; + uint32_t *br, *bg, *bb; + br=VideoBufRed; + bg=VideoBufGrn; + bb=VideoBufBlu; + + w0 = y * (SPIints_per_line) + x0/32; + xx0 = (x0 & 0x1F); + w1 = y * (SPIints_per_line) + x1/32; + xx1 = (x1 & 0x1F); + if(w1==w0){ //special case both inside same word + x=(a[xx0] & b[xx1]); + xn=~x; + if(con & 1) br[w0] |= x; else br[w0] &= xn; // turn on the red pixel + if(con & 2) bg[w0] |= x; else bg[w0] &= xn; // turn on the green pixel + if(con & 4) bb[w0] |= x; else bb[w0] &= xn; // turn on the blue pixel + } else { + if(w1-w0>1){ //first deal with full words + for(i=w0+1;i>(x & 0x1f)); + xxn=~xx; + xd=x>>5; + w = c1 + xd; + // draw the pixel + if(y>=0 && y=0 && x 0x80){ + bb[w] |= xx; + } else { + bb[w] &= xxn; + }// turn on the blue pixel + if(*p++ > 0x80){ + bg[w] |= xx; + } else { + bg[w] &= xxn; + }// turn on the green pixel + if(*p++ > 0x80){ + br[w] |= xx; + } else { + br[w] &= xxn; + }// turn on the red pixel + } else p+=3; + } + } +} +void ReadBufferSPI111(int x1, int y1, int x2, int y2, unsigned char* p) { + int t,x,y, w, xx, xd, c1; + // make sure the coordinates are kept within the display area + if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } + if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } + for(y=y1;y<=y2;y++){ + c1=y * (SPIints_per_line); + for(x=x1;x<=x2;x++){ + xx=(0x80000000>>(x & 0x1f)); + xd=x>>5; + w = c1 + xd; + if(y>=0 && y=0 && x>(x & 0x1f)); + xd=x>>5; + w = y * (SPIints_per_line) + xd; + // draw the pixel + xxn = ~xx; + if(con & 1) br[w] |= xx; else br[w] &= xxn; // turn on the red pixel + if(con & 6) bg[w] |= xx; else bg[w] &= xxn; // turn on the green pixel + if(con & 8) bb[w] |= xx; else bb[w] &= xxn; // turn on the blue pixel +} + +inline void plot(int x, int y, int con) { + int w, xx,xxn, xd; + uint32_t *br, *bg, *bb; + br=VideoBufRed, bg=VideoBufGrn, bb=VideoBufBlu; + xx = (0x80000000>>(x & 0x1f)); + xd=x>>5; + w = y * (SPIints_per_line) + xd; + // draw the pixel + xxn = ~xx; + if(con & 1) br[w] |= xx; else br[w] &= xxn; // turn on the red pixel + if(con & 2) bg[w] |= xx; else bg[w] &= xxn; // turn on the green pixel + if(con & 4) bb[w] |= xx; else bb[w] &= xxn; // turn on the blue pixel +} + +void copyframetoscreen(uint8_t *s,int xstart, int xend, int ystart, int yend, int odd){ + int c; + int i=(xend-xstart+1)*(yend-ystart+1); + int x=xstart,y=ystart; + if(odd){ + c=(*s & 0xF0)>>4; + plot121(x,y,c); + if(x==xend){ + x=xstart; + y++; + } else x++; + + + s++; + i--; + } + while(i>0){ + c=*s & 0xF; + plot121(x,y,c); + if(x==xend){ + x=xstart; + y++; + } else x++; + if(i>1){ + c=(*s & 0xF0)>>4; + plot121(x,y,c); + if(x==xend){ + x=xstart; + y++; + } else x++; + s++; + i-=2; + } + } +} + +void ScrollSPI111sideways(int lines){ + int i, j; + uint32_t k, l, prevr=0, prevg=0, prevb=0; + uint32_t *pdr,*pdg,*pdb; + uint32_t *br, *bg, *bb; + br=VideoBufRed, bg=VideoBufGrn, bb=VideoBufBlu; + int m1=0x0; + int m2=0x0; + if(lines > 0) { + for(j=0; j> lines; + l |= prevr; + if(i==0)l &= m1; + if(i==HRes/32)l &= m2; + *pdr++ = l; + prevr=k<<(32-lines); + + l = *pdg; + k= l & maskSPI111[lines-1]; + l = l >> lines; + l |= prevg; + if(i==0)l &= m1; + if(i==HRes/32)l &= m2; + *pdg++ = l; + prevg=k<<(32-lines); + + l = *pdb; + k=l & maskSPI111[lines-1]; + l = l >>lines; + l |= prevb; + if(i==0)l &= m1; + if(i==HRes/32)l &= m2; + *pdb++ = l; + prevb=k<<(32-lines); + } + } + } else { + int m=-lines; + for(j=0; j=0;i--){ + l = *pdr; + k=l & rmaskSPI111[m]; + l = l << m; + l |= prevr; + if(i==0)l &= m1; + if(i==HRes/32)l &= m2; + *pdr-- = l; + prevr=k>>(32-m); + + l = *pdg; + k= l & rmaskSPI111[m]; + l = l << m; + l |= prevg; + if(i==0)l &= m1; + if(i==HRes/32)l &= m2; + *pdg-- = l; + prevg=k>>(32-m); + + l = *pdb; + k=l & rmaskSPI111[m]; + l = l << m; + l |= prevb; + if(i==0)l &= m1; + if(i==HRes/32)l &= m2; + *pdb-- = l; + prevb=k>>(32-m); + } + } + } +} +void ScrollSPI111(int lines) { + int i,amount; + uint32_t *pdr,*pdg,*pdb; + uint32_t *psr,*psg,*psb; + uint32_t *br, *bg, *bb; + br=VideoBufRed, bg=VideoBufGrn, bb=VideoBufBlu; + if(lines >= 0) { + amount = SPIints_per_line * (VRes - lines); + pdr = br; + psr = pdr + SPIints_per_line * lines; + pdg = bg; + psg = pdg + SPIints_per_line * lines; + pdb = bb; + psb = pdb + SPIints_per_line * lines; + for(i=0; i < amount; i+=8) { + *pdr++ = *psr++; // scroll up + *pdr++ = *psr++; // scroll up + *pdr++ = *psr++; // scroll up + *pdr++ = *psr++; // scroll up + *pdr++ = *psr++; // scroll up + *pdr++ = *psr++; // scroll up + *pdr++ = *psr++; // scroll up + *pdr++ = *psr++; // scroll up + *pdg++ = *psg++; + *pdg++ = *psg++; + *pdg++ = *psg++; + *pdg++ = *psg++; + *pdg++ = *psg++; + *pdg++ = *psg++; + *pdg++ = *psg++; + *pdg++ = *psg++; + *pdb++ = *psb++; + *pdb++ = *psb++; + *pdb++ = *psb++; + *pdb++ = *psb++; + *pdb++ = *psb++; + *pdb++ = *psb++; + *pdb++ = *psb++; + *pdb++ = *psb++; + } + DrawRectangle(0, VRes-lines, HRes - 1, VRes - 1, gui_bcolour); // erase the lines introduced at the bottom + } else { + lines = -lines; + amount = SPIints_per_line * (VRes - lines); + psr = br + SPIints_per_line * (VRes - lines); + pdr = psr + SPIints_per_line * lines; + psg = bg + SPIints_per_line * (VRes - lines); + pdg = psg + SPIints_per_line * lines; + psb = bb + SPIints_per_line * (VRes - lines); + pdb = psb + SPIints_per_line * lines; + for(i=0; i < amount; i+=8){ + *--pdr = *--psr; // scroll down + *--pdr = *--psr; // scroll down + *--pdr = *--psr; // scroll down + *--pdr = *--psr; // scroll down + *--pdr = *--psr; // scroll down + *--pdr = *--psr; // scroll down + *--pdr = *--psr; // scroll down + *--pdr = *--psr; // scroll down + *--pdg = *--psg; + *--pdg = *--psg; + *--pdg = *--psg; + *--pdg = *--psg; + *--pdg = *--psg; + *--pdg = *--psg; + *--pdg = *--psg; + *--pdg = *--psg; + *--pdb = *--psb; + *--pdb = *--psb; + *--pdb = *--psb; + *--pdb = *--psb; + *--pdb = *--psb; + *--pdb = *--psb; + *--pdb = *--psb; + *--pdb = *--psb; + } + DrawRectangle(0, 0, HRes - 1, lines-1 , gui_bcolour); // erase the lines introduced at the top + } +} +void ScrollSPI111vertical(int lines, int blank) { + int i,amount; + uint32_t *pdr,*pdg,*pdb; + uint32_t *psr,*psg,*psb; + uint32_t *br, *bg, *bb; + br=VideoBufRed, bg=VideoBufGrn, bb=VideoBufBlu; + if(lines >= 0) { + amount = SPIints_per_line * (VRes - lines); + pdr = br; + psr = pdr + SPIints_per_line * lines; + pdg = bg; + psg = pdg + SPIints_per_line * lines; + pdb = bb; + psb = pdb + SPIints_per_line * lines; + for(i=0; i < amount; i+=8) { + *pdr++ = *psr++; // scroll up + *pdr++ = *psr++; // scroll up + *pdr++ = *psr++; // scroll up + *pdr++ = *psr++; // scroll up + *pdr++ = *psr++; // scroll up + *pdr++ = *psr++; // scroll up + *pdr++ = *psr++; // scroll up + *pdr++ = *psr++; // scroll up + *pdg++ = *psg++; + *pdg++ = *psg++; + *pdg++ = *psg++; + *pdg++ = *psg++; + *pdg++ = *psg++; + *pdg++ = *psg++; + *pdg++ = *psg++; + *pdg++ = *psg++; + *pdb++ = *psb++; + *pdb++ = *psb++; + *pdb++ = *psb++; + *pdb++ = *psb++; + *pdb++ = *psb++; + *pdb++ = *psb++; + *pdb++ = *psb++; + *pdb++ = *psb++; + } + } else { + lines = -lines; + amount = SPIints_per_line * (VRes - lines); + psr = br + SPIints_per_line * (VRes - lines); + pdr = psr + SPIints_per_line * lines; + psg = bg + SPIints_per_line * (VRes - lines); + pdg = psg + SPIints_per_line * lines; + psb = bb + SPIints_per_line * (VRes - lines); + pdb = psb + SPIints_per_line * lines; + for(i=0; i < amount; i+=8){ + *--pdr = *--psr; // scroll down + *--pdr = *--psr; // scroll down + *--pdr = *--psr; // scroll down + *--pdr = *--psr; // scroll down + *--pdr = *--psr; // scroll down + *--pdr = *--psr; // scroll down + *--pdr = *--psr; // scroll down + *--pdr = *--psr; // scroll down + *--pdg = *--psg; + *--pdg = *--psg; + *--pdg = *--psg; + *--pdg = *--psg; + *--pdg = *--psg; + *--pdg = *--psg; + *--pdg = *--psg; + *--pdg = *--psg; + *--pdb = *--psb; + *--pdb = *--psb; + *--pdb = *--psb; + *--pdb = *--psb; + *--pdb = *--psb; + *--pdb = *--psb; + *--pdb = *--psb; + *--pdb = *--psb; + } + } +} diff --git a/Code/pico_multi_booter/picomite/SPI-LCD.c b/Code/pico_multi_booter/picomite/SPI-LCD.c index 15fd12b..a613c3c 100644 --- a/Code/pico_multi_booter/picomite/SPI-LCD.c +++ b/Code/pico_multi_booter/picomite/SPI-LCD.c @@ -46,46 +46,47 @@ const struct Displays display_details[]={ {14,"ST7789_320", 50000000, 320, 240, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, {15,"ILI9488W", LCD_SPI_SPEED, 480, 320, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, {16,"ST7796S", 50000000, 480, 320, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, - {17,"ST7735S_W", LCD_SPI_SPEED, 128, 128, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, - {18,"GC9A01", LCD_SPI_SPEED, 240, 240, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, - {19,"ILI9481IPS", 12000000, 480, 320, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, - {20,"N5110", NOKIA_SPI_SPEED, 84, 48, 1, 1, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, - {21,"SSD1306SPI", LCD_SPI_SPEED, 128, 64, 1, 1, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, - {22,"ST7920", ST7920_SPI_SPEED, 128, 64, 1, 1, SPI_POLARITY_HIGH, SPI_PHASE_2EDGE}, - {23,"", TOUCH_SPI_SPEED, 0, 0, 0, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, - {24,"SPIReadSpeed", 12000000, 480, 320, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, - {25,"ST7789RSpeed", 6000000, 320, 240, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, - {26,"", SLOW_TOUCH_SPEED, 0, 0, 0, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, - {27,"User", 0, 0, 0, 0, 0, 0 ,0}, - {28,"Dummy", 0, 0, 0, 0, 0, 0 ,0}, + {17,"ST7796SP",50000000, 320, 320, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, + {18,"ST7735S_W", LCD_SPI_SPEED, 128, 128, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, + {19,"GC9A01", LCD_SPI_SPEED, 240, 240, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, + {20,"ILI9481IPS", 12000000, 480, 320, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, + {21,"N5110", NOKIA_SPI_SPEED, 84, 48, 1, 1, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, + {22,"SSD1306SPI", LCD_SPI_SPEED, 128, 64, 1, 1, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, + {23,"ST7920", ST7920_SPI_SPEED, 128, 64, 1, 1, SPI_POLARITY_HIGH, SPI_PHASE_2EDGE}, + {24,"", TOUCH_SPI_SPEED, 0, 0, 0, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, + {25,"SPIReadSpeed", 12000000, 480, 320, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, + {26,"ST7789RSpeed", 6000000, 320, 240, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, + {27,"", SLOW_TOUCH_SPEED, 0, 0, 0, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, + {28,"User", 0, 0, 0, 0, 0, 0 ,0}, {29,"Dummy", 0, 0, 0, 0, 0, 0 ,0}, {30,"Dummy", 0, 0, 0, 0, 0, 0 ,0}, {31,"Dummy", 0, 0, 0, 0, 0, 0 ,0}, {32,"Dummy", 0, 0, 0, 0, 0, 0 ,0}, {33,"Dummy", 0, 0, 0, 0, 0, 0 ,0}, {34,"Dummy", 0, 0, 0, 0, 0, 0 ,0}, - {35,"SSD1963_4", 0, 0, 0, 0, 0, 0 ,0}, - {36,"SSD1963_5", 0, 0, 0, 0, 0, 0 ,0}, - {37,"SSD1963_5A", 0, 0, 0, 0, 0, 0 ,0}, - {38,"SSD1963_7", 0, 0, 0, 0, 0, 0 ,0}, - {39,"SSD1963_7A", 0, 0, 0, 0, 0, 0 ,0}, - {40,"SSD1963_8", 0, 0, 0, 0, 0, 0 ,0}, - {41,"ILI9341_8", 0, 0, 0, 0, 0, 0 ,0}, - {42,"SSD1963_4_16", 0, 0, 0, 0, 0, 0 ,0}, - {43,"SSD1963_5_16", 0, 0, 0, 0, 0, 0 ,0}, - {44,"SSD1963_5A_16" , 0, 0, 0, 0, 0, 0 ,0}, - {45,"SSD1963_7_16", 0, 0, 0, 0, 0, 0 ,0}, - {46,"SSD1963_7A_16", 0, 0, 0, 0, 0, 0 ,0}, - {47,"SSD1963_8_16", 0, 0, 0, 0, 0, 0 ,0}, - {48,"ILI9341_16", 0, 0, 0, 0, 0, 0 ,0}, - {49,"IPS_4_16", 0, 0, 0, 0, 0, 0 ,0}, - {50,"SSD1963_5E_16", 0, 0, 0, 0, 0, 0 ,0}, - {51,"SSD1963_7E_16", 0, 0, 0, 0, 0, 0 ,0}, - {52,"ILI9486_16", 0, 0, 0, 0, 0, 0 ,0}, - {53,"VIRTUAL_C", 0, 320, 240, 0, 0, 0, 0}, - {54,"VIRTUAL_M", 0, 640, 480, 0, 0, 0, 0}, - {55,"VS1053slow", 200000, 0, 0, 0, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, - {56,"VS1053fast", 4000000, 0, 0, 0, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, + {35,"Dummy", 0, 0, 0, 0, 0, 0 ,0}, + {36,"SSD1963_4", 0, 0, 0, 0, 0, 0 ,0}, + {37,"SSD1963_5", 0, 0, 0, 0, 0, 0 ,0}, + {38,"SSD1963_5A", 0, 0, 0, 0, 0, 0 ,0}, + {39,"SSD1963_7", 0, 0, 0, 0, 0, 0 ,0}, + {40,"SSD1963_7A", 0, 0, 0, 0, 0, 0 ,0}, + {41,"SSD1963_8", 0, 0, 0, 0, 0, 0 ,0}, + {42,"ILI9341_8", 0, 0, 0, 0, 0, 0 ,0}, + {43,"SSD1963_4_16", 0, 0, 0, 0, 0, 0 ,0}, + {44,"SSD1963_5_16", 0, 0, 0, 0, 0, 0 ,0}, + {45,"SSD1963_5A_16" , 0, 0, 0, 0, 0, 0 ,0}, + {46,"SSD1963_7_16", 0, 0, 0, 0, 0, 0 ,0}, + {47,"SSD1963_7A_16", 0, 0, 0, 0, 0, 0 ,0}, + {48,"SSD1963_8_16", 0, 0, 0, 0, 0, 0 ,0}, + {49,"ILI9341_16", 0, 0, 0, 0, 0, 0 ,0}, + {50,"IPS_4_16", 0, 0, 0, 0, 0, 0 ,0}, + {51,"SSD1963_5E_16", 0, 0, 0, 0, 0, 0 ,0}, + {52,"SSD1963_7E_16", 0, 0, 0, 0, 0, 0 ,0}, + {53,"ILI9486_16", 0, 0, 0, 0, 0, 0 ,0}, + {54,"VIRTUAL_C", 0, 320, 240, 0, 0, 0, 0}, + {55,"VIRTUAL_M", 0, 640, 480, 0, 0, 0, 0}, + {56,"VS1053slow", 200000, 0, 0, 0, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, + {57,"VS1053fast", 4000000, 0, 0, 0, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE}, }; void __not_in_flash_func(spi_write_fast)(spi_inst_t *spi, const uint8_t *src, size_t len) { @@ -115,8 +116,6 @@ void __not_in_flash_func(spi_finish)(spi_inst_t *spi){ int LCD_CS_PIN=0; int LCD_CD_PIN=0; int LCD_Reset_PIN=0; -static bool ST7796Swritestate=true; -#define ST7796Schangetowrite 1600 unsigned char LCDBuffer[1440]={0}; void DefineRegionSPI(int xstart, int ystart, int xend, int yend, int rw); @@ -153,6 +152,7 @@ void MIPS16 ConfigDisplaySPI(unsigned char *p) { char code,CD,RESET,CS=0; uint8_t BACKLIGHT=0; int DISPLAY_TYPE=0; + int orientation=1; getargs(&p, 13, (unsigned char *)","); if(checkstring(argv[0], (unsigned char *)"ILI9163")) { DISPLAY_TYPE = ILI9163; @@ -180,6 +180,8 @@ void MIPS16 ConfigDisplaySPI(unsigned char *p) { DISPLAY_TYPE = ILI9488W; } else if(checkstring(argv[0], (unsigned char *)"ST7796S")) { DISPLAY_TYPE = ST7796S; + } else if(checkstring(argv[0], (unsigned char *)"ST7796SP")) { + DISPLAY_TYPE = ST7796SP; } else if(checkstring(argv[0], (unsigned char *)"ILI9341")) { DISPLAY_TYPE = ILI9341; } else if(checkstring(argv[0], (unsigned char *)"ST7735S_W")) { @@ -195,15 +197,18 @@ void MIPS16 ConfigDisplaySPI(unsigned char *p) { } else return; if(!Option.SYSTEM_CLK)error("System SPI not configured"); if(!(argc == 7 || argc == 9 || argc==11 || argc==13)) error("Argument count"); - if(checkstring(argv[2], (unsigned char *)"L") || checkstring(argv[2], (unsigned char *)"LANDSCAPE")) - Option.DISPLAY_ORIENTATION = LANDSCAPE; - else if(checkstring(argv[2], (unsigned char *)"P") || checkstring(argv[2], (unsigned char *)"PORTRAIT")) - Option.DISPLAY_ORIENTATION = PORTRAIT; - else if(checkstring(argv[2], (unsigned char *)"RL") || checkstring(argv[2], (unsigned char *)"RLANDSCAPE")) - Option.DISPLAY_ORIENTATION = RLANDSCAPE; - else if(checkstring(argv[2], (unsigned char *)"RP") || checkstring(argv[2], (unsigned char *)"RPORTRAIT")) - Option.DISPLAY_ORIENTATION = RPORTRAIT; - else error("Orientation"); + if(*argv[2]){ + if(checkstring(argv[2], (unsigned char *)"L") || checkstring(argv[2], (unsigned char *)"LANDSCAPE")) + orientation = LANDSCAPE; + else if(checkstring(argv[2], (unsigned char *)"P") || checkstring(argv[2], (unsigned char *)"PORTRAIT")) + orientation = PORTRAIT; + else if(checkstring(argv[2], (unsigned char *)"RL") || checkstring(argv[2], (unsigned char *)"RLANDSCAPE")) + orientation = RLANDSCAPE; + else if(checkstring(argv[2], (unsigned char *)"RP") || checkstring(argv[2], (unsigned char *)"RPORTRAIT")) + orientation = RPORTRAIT; + else error("Orientation"); + } + Option.DISPLAY_ORIENTATION=orientation; if(DISPLAY_TYPE==ST7789 || DISPLAY_TYPE == ST7789A|| DISPLAY_TYPE == ST7789A)Option.DISPLAY_ORIENTATION=(Option.DISPLAY_ORIENTATION+2) % 4; if(!(code=codecheck(argv[4])))argv[4]+=2; CD = getinteger(argv[4]); @@ -266,7 +271,7 @@ void MIPS16 InitDisplaySPI(int InitOnly) { DrawPixel = DrawPixelNormal; ScrollLCD = ScrollLCDSPISCR; DrawBLITBuffer = DrawBufferSPISCR; - if(Option.DISPLAY_TYPE == ILI9341 || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE == ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE == ST7789B){ + if(Option.DISPLAY_TYPE == ILI9341 || Option.DISPLAY_TYPE == ST7796SP || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE == ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE == ST7789B){ ReadBuffer = ReadBufferSPISCR; ReadBLITBuffer = ReadBufferSPISCR; } @@ -276,7 +281,7 @@ void MIPS16 InitDisplaySPI(int InitOnly) { DrawBuffer = DrawBufferSPI; DrawBLITBuffer = DrawBufferSPI; DrawPixel = DrawPixelNormal; - if(Option.DISPLAY_TYPE == ILI9341 || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE == ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE == ST7789B){ + if(Option.DISPLAY_TYPE == ILI9341 || Option.DISPLAY_TYPE == ST7796SP || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE == ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE == ST7789B){ ReadBLITBuffer = ReadBufferSPI; ReadBuffer = ReadBufferSPI; ScrollLCD = ScrollLCDSPI; @@ -296,6 +301,7 @@ void MIPS16 InitDisplaySPI(int InitOnly) { // the initialisation sequences and the SPI driver code was written by Peter Mather (matherp on The Back Shed forum) switch(Option.DISPLAY_TYPE) { case ST7796S: + case ST7796SP: ResetController(); spi_write_cd(0xC5, 1, 0x1C); //VCOM Control 1 [1C] spi_write_cd(0x3A, 1, 0x55); //565 @@ -303,6 +309,8 @@ void MIPS16 InitDisplaySPI(int InitOnly) { uSec(150000); //0xB1, 2, 0xB0, 0x11, //Frame Rate Control [A0 10] spi_write_cd(0xB4, 1, 0x01); //Inversion Control [01] + if(Option.BGR)spi_write_command(0x21); + else spi_write_command(0x20); spi_write_cd(0xB6, 3, 0x80, 0x02, 0x3B); // Display Function Control [80 02 3B] .kbv SS=1, NL=480 spi_write_cd(0xB7, 1, 0xC6); //Entry Mode [06] // 0xF7, 4, 0xA9, 0x51, 0x2C, 0x82, //Adjustment Control 3 [A9 51 2C 82] @@ -315,12 +323,17 @@ void MIPS16 InitDisplaySPI(int InitOnly) { case RLANDSCAPE: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Landscape180); break; case RPORTRAIT: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Portrait180); break; } + if(Option.DISPLAY_TYPE==ST7796SP){ + spi_write_cd(0x33,6,0x00,0x00,0x01,0x40,0x00,0xA0); + } else { + spi_write_cd(0x33,6,0x00,0x00,0x01,0xE0,0x00,0x00); + } spi_write_command(0x11); uSec(150000); spi_write_command(0x29); //Display on uSec(150000); break; - case ILI9488: + case ILI9488: case ILI9488P: case ILI9488W: ResetController(); @@ -1138,10 +1151,6 @@ void spisendfast(unsigned char *n, int i){ void DrawRectangleSPI(int x1, int y1, int x2, int y2, int c){ // convert the colours to 565 format unsigned char col[3]; - if(Option.DISPLAY_TYPE==ST7796S && !ST7796Swritestate){ - uSec(ST7796Schangetowrite); - ST7796Swritestate=true; - } if(x1==x2 && y1==y2){ if(x1 < 0) return; if(x1 >= HRes) return; @@ -1262,10 +1271,6 @@ void DrawRectangleSPISCR(int x1, int y1, int x2, int y2, int c){ // convert the colours to 565 format int t; // make sure the coordinates are kept within the display area - if(Option.DISPLAY_TYPE==ST7796S && !ST7796Swritestate){ - uSec(ST7796Schangetowrite); - ST7796Swritestate=true; - } if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } if(x1 < 0) x1 = 0; @@ -1304,11 +1309,7 @@ void DrawBitmapSPI(int x1, int y1, int width, int height, int scale, int fc, int } c; if(bc == -1 && (void *)ReadBuffer == (void *)DisplayNotSet) bc = 0x0; if(x1>=HRes || y1>=VRes || x1+width*scale<0 || y1+height*scale<0)return; - if(Option.DISPLAY_TYPE==ST7796S && !ST7796Swritestate){ - uSec(ST7796Schangetowrite); - ST7796Swritestate=true; - } - // adjust when part of the bitmap is outside the displayable coordinates + // adjust when part of the bitmap is outside the displayable coordinates vertCoord = y1; if(y1 < 0) y1 = 0; // the y coord is above the top of the screen XStart = x1; if(XStart < 0) XStart = 0; // the x coord is to the left of the left marginn XEnd = x1 + (width * scale) - 1; if(XEnd >= HRes) XEnd = HRes - 1; // the width of the bitmap will extend beyond the right margin @@ -1318,8 +1319,6 @@ void DrawBitmapSPI(int x1, int y1, int width, int height, int scale, int fc, int j = width * height * scale * scale * 3; p = GetMemory(j); //allocate some temporary memory ReadBuffer(XStart, y1, XEnd, YEnd, (unsigned char *)p); - uSec(ST7796Schangetowrite); - ST7796Swritestate=true; } // convert the colours to 565 format if(Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ILI9481IPS ){ @@ -1421,10 +1420,6 @@ void DrawBitmapSPISCR(int x1, int y1, int width, int height, int scale, int fc, } if(bc == -1 && (void *)ReadBuffer == (void *)DisplayNotSet) bc = 0x0; if(x1>=HRes || y1>=VRes || x1+width*scale<0 || y1+height*scale<0)return; - if(Option.DISPLAY_TYPE==ST7796S && !ST7796Swritestate){ - uSec(ST7796Schangetowrite); - ST7796Swritestate=true; - } // adjust when part of the bitmap is outside the displayable coordinates vertCoord = y1; if(y1 < 0) y1 = 0; // the y coord is above the top of the screen XStart = x1; if(XStart < 0) XStart = 0; // the x coord is to the left of the left marginn @@ -1433,8 +1428,6 @@ void DrawBitmapSPISCR(int x1, int y1, int width, int height, int scale, int fc, j = width * height * scale * scale * 3; p = GetMemory(j); //allocate some temporary memory ReadBuffer(XStart, y1, XEnd, (y1 + (height * scale) - 1) , (unsigned char *)p); - uSec(ST7796Schangetowrite); - ST7796Swritestate=true; } yt = y = (y1 + ScrollStart) % VRes; YEnd=(y + (height * scale) - 1) % VRes; @@ -1492,9 +1485,6 @@ const unsigned char map32[256]; void ReadBufferSPI(int x1, int y1, int x2, int y2, unsigned char* p) { int r, N, t; unsigned char h,l; - if(Option.DISPLAY_TYPE==ST7796S && ST7796Swritestate){ - ST7796Swritestate=false; - } // SInt(x1);SIntComma(y1);SIntComma(x2);SIntComma(y2);SRet(); // make sure the coordinates are kept within the display area if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } @@ -1507,7 +1497,7 @@ void ReadBufferSPI(int x1, int y1, int x2, int y2, unsigned char* p) { if(y1 >= VRes) y1 = VRes - 1; if(y2 < 0) y2 = 0; if(y2 >= VRes) y2 = VRes - 1; - N=(x2- x1+1) * (y2- y1+1) * (Option.DISPLAY_TYPE==ST7796S ? 2 : 3); + N=(x2- x1+1) * (y2- y1+1) * ((Option.DISPLAY_TYPE==ST7796S || Option.DISPLAY_TYPE == ST7796SP)? 2 : 3); if(Option.DISPLAY_TYPE==ILI9341 || Option.DISPLAY_TYPE==ST7789B )spi_write_cd(ILI9341_PIXELFORMAT,1,0x66); //change to RGB666 for read DefineRegionSPI(x1, y1, x2, y2, 0); SPISpeedSet( (Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ST7789B || Option.DISPLAY_TYPE==ILI9481IPS) ? ST7789RSpeed : SPIReadSpeed); //need to slow SPI for read on this display @@ -1520,7 +1510,7 @@ void ReadBufferSPI(int x1, int y1, int x2, int y2, unsigned char* p) { // revert to non enhanced SPI mode if(Option.DISPLAY_TYPE==ILI9341 || Option.DISPLAY_TYPE==ST7789B )spi_write_cd(ILI9341_PIXELFORMAT,1,0x55); //change back to rdb565 r=0; - if(Option.DISPLAY_TYPE==ST7796S){ + if(Option.DISPLAY_TYPE==ST7796S || Option.DISPLAY_TYPE == ST7796SP){ int n=(x2- x1+1) * (y2- y1+1)*3; while(N){ h=p[N-2]; @@ -1548,9 +1538,6 @@ void ReadBufferSPISCR(int x1, int y1, int x2, int y2, unsigned char* p) { unsigned char h,l; // PInt(x1);PIntComma(y1);PIntComma(x2);PIntComma(y2);PRet(); // make sure the coordinates are kept within the display area - if(Option.DISPLAY_TYPE==ST7796S && ST7796Swritestate){ - ST7796Swritestate=false; - } if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } if(x1 < 0) x1 = 0; @@ -1566,7 +1553,7 @@ void ReadBufferSPISCR(int x1, int y1, int x2, int y2, unsigned char* p) { y1 = (y1 + ScrollStart) % VRes; y2 = y1 + t; if(y2 >= VRes) { - N=(x2- x1+1) * (y2- VRes) * (Option.DISPLAY_TYPE==ST7796S ? 2 : 3); + N=(x2- x1+1) * (y2- VRes) * ((Option.DISPLAY_TYPE==ST7796S || Option.DISPLAY_TYPE == ST7796SP) ? 2 : 3); DefineRegionSPI(x1, y1, x2, VRes - 1,0); SPISpeedSet( (Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ST7789B || Option.DISPLAY_TYPE==ILI9481IPS) ? ST7789RSpeed : SPIReadSpeed); //need to slow SPI for read on this display rcvr_byte_multi((uint8_t *)p, 1); @@ -1576,7 +1563,7 @@ void ReadBufferSPISCR(int x1, int y1, int x2, int y2, unsigned char* p) { ClearCS(Option.LCD_CS); //set CS high SPISpeedSet(Option.DISPLAY_TYPE); p+=N; - N=(x2- x1+1) * (y2 - VRes) * (Option.DISPLAY_TYPE==ST7796S ? 2 : 3); + N=(x2- x1+1) * (y2 - VRes) * ((Option.DISPLAY_TYPE==ST7796S || Option.DISPLAY_TYPE == ST7796SP) ? 2 : 3); DefineRegionSPI(x1, 0, x2, y2 - VRes,0); SPISpeedSet( (Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ST7789B || Option.DISPLAY_TYPE==ILI9481IPS) ? ST7789RSpeed : SPIReadSpeed); //need to slow SPI for read on this display rcvr_byte_multi((uint8_t *)p, 1); @@ -1587,7 +1574,7 @@ void ReadBufferSPISCR(int x1, int y1, int x2, int y2, unsigned char* p) { SPISpeedSet(Option.DISPLAY_TYPE); N=(x2- x1+1) * (y2- y1+1) * 3; } else { - N=(x2- x1+1) * (y2- y1+1) * (Option.DISPLAY_TYPE==ST7796S ? 2 : 3); + N=(x2- x1+1) * (y2- y1+1) * ((Option.DISPLAY_TYPE==ST7796S || Option.DISPLAY_TYPE == ST7796SP) ? 2 : 3); DefineRegionSPI(x1, y1, x2, y2, 0); SPISpeedSet( (Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ST7789B || Option.DISPLAY_TYPE==ILI9481IPS) ? ST7789RSpeed : SPIReadSpeed); //need to slow SPI for read on this display rcvr_byte_multi((uint8_t *)p, 1); @@ -1600,7 +1587,7 @@ void ReadBufferSPISCR(int x1, int y1, int x2, int y2, unsigned char* p) { } if(Option.DISPLAY_TYPE==ILI9341 || Option.DISPLAY_TYPE==ST7789B )spi_write_cd(ILI9341_PIXELFORMAT,1,0x55); //change back to rdb565 r=0; - if(Option.DISPLAY_TYPE==ST7796S){ + if(Option.DISPLAY_TYPE==ST7796S || Option.DISPLAY_TYPE == ST7796SP){ N=(x2- x1+1) * (y2- y1+1)*2; int n=(x2- x1+1) * (y2- y1+1)*3; while(N){ @@ -1634,10 +1621,6 @@ void DrawBufferSPI(int x1, int y1, int x2, int y2, unsigned char* p) { } c; unsigned char q[3]; int i,t; - if(Option.DISPLAY_TYPE==ST7796S && !ST7796Swritestate){ - uSec(ST7796Schangetowrite); - ST7796Swritestate=true; - } if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } if(x1 < 0) x1 = 0; @@ -1680,10 +1663,6 @@ void DrawBufferSPISCR(int x1, int y1, int x2, int y2, unsigned char* p) { } c; unsigned char q[3]; int i,t; - if(Option.DISPLAY_TYPE==ST7796S && !ST7796Swritestate){ - uSec(ST7796Schangetowrite); - ST7796Swritestate=true; - } if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } if(x1 < 0) x1 = 0; @@ -2054,6 +2033,7 @@ void ST7920SetXY(int x, int y){ void Display_Refresh(void){ if(!(Option.DISPLAY_TYPE<=I2C_PANEL || Option.DISPLAY_TYPE>=BufferedPanel)) return; unsigned char* p=(void *)((unsigned int)LCDBuffer); + if(low_x==2000 && high_x==-1 && low_y==2000 && high_y==-1)return; //Nothing to do if(low_x<0)low_x=0; if(low_y<0)low_y=0; if(high_x>DisplayHRes)high_x=DisplayHRes-1; @@ -2065,18 +2045,15 @@ void Display_Refresh(void){ SetCS(); gpio_put(LCD_CD_PIN,GPIO_PIN_SET); xmit_byte_multi(p+(y*DisplayHRes)+low_x,high_x-low_x+1); -// HAL_SPI_Transmit(&hspi3,p+(y*DisplayHRes)+low_x,high_x-low_x+1,500); ClearCS(Option.LCD_CS); } - } - if(Option.DISPLAY_TYPE<=I2C_PANEL){ + } else if(Option.DISPLAY_TYPE<=I2C_PANEL){ int y; for(y=low_y/8;y<(high_y & 0xf8)/8+1;y++){ SSD1306I2CSetXY(Option.I2Coffset+low_x,y); I2C_Send_Data(p+(y*DisplayHRes)+low_x,high_x-low_x+1); } - } - if(Option.DISPLAY_TYPE==SSD1306SPI){ + } else if(Option.DISPLAY_TYPE==SSD1306SPI){ int y; for(y=low_y/8;y<(high_y & 0xf8)/8+1;y++){ SSD1306SPISetXY(Option.I2Coffset+low_x,y); @@ -2086,8 +2063,7 @@ void Display_Refresh(void){ // HAL_SPI_Transmit(&hspi3,p+(y*DisplayHRes)+low_x,high_x-low_x+1,500); ClearCS(Option.LCD_CS); } - } - if(Option.DISPLAY_TYPE==ST7920){ + } else if(Option.DISPLAY_TYPE==ST7920){ int y,i; unsigned char x_array[33]; unsigned char *q; @@ -2105,7 +2081,7 @@ void Display_Refresh(void){ ClearCS(Option.LCD_CD); } } - low_y=2000; high_y=0; low_x=2000; high_x=0; + low_y=2000; high_y=-1; low_x=2000; high_x=-1; } #endif diff --git a/Code/pico_multi_booter/picomite/SPI-LCD.h b/Code/pico_multi_booter/picomite/SPI-LCD.h index c35d9b2..0911a51 100644 --- a/Code/pico_multi_booter/picomite/SPI-LCD.h +++ b/Code/pico_multi_booter/picomite/SPI-LCD.h @@ -284,58 +284,61 @@ extern void __not_in_flash_func(spi_finish)(spi_inst_t *spi); #define ST7789B 14 #define ILI9488W 15 #define ST7796S 16 -#define ST7735S_W 17 -#define GC9A01 18 -#define ILI9481IPS 19 -#define N5110 20 +#define ST7796SP 17 +#define ST7735S_W 18 +#define GC9A01 19 +#define ILI9481IPS 20 +#define N5110 21 #define BufferedPanel N5110 -#define SSD1306SPI 21 -#define ST7920 22 -#define TOUCH 23 -#define SPIReadSpeed 24 -#define ST7789RSpeed 25 -#define SLOWTOUCH 26 -#define DISP_USER 27 -#define SCREENMODE1 28 +#define SSD1306SPI 22 +#define ST7920 23 +#define TOUCH 24 +#define SPIReadSpeed 25 +#define ST7789RSpeed 26 +#define SLOWTOUCH 27 +#define DISP_USER 28 +#define SCREENMODE1 29 #define VGADISPLAY SCREENMODE1 -#define SCREENMODE2 29 -#define SCREENMODE3 30 -#define SCREENMODE4 31 -#define SCREENMODE5 32 -#define SCREENMODE6 33 -#define SCREENMODE7 34 -#define SSD1963_4 35 +#define SCREENMODE2 30 +#define SCREENMODE3 31 +#define SCREENMODE4 32 +#define SCREENMODE5 33 +#define SCREENMODE6 34 +#define SCREENMODE7 35 +#define SSD1963_4 36 #define SSDPANEL SSD1963_4 -#define SSD1963_5 36 -#define SSD1963_5A 37 -#define SSD1963_7 38 -#define SSD1963_7A 39 -#define SSD1963_8 40 -#define ILI9341_8 41 +#define SSD1963_5 37 +#define SSD1963_5A 38 +#define SSD1963_7 39 +#define SSD1963_7A 40 +#define SSD1963_8 41 +#define ILI9341_8 42 #define SSD_PANEL_8 ILI9341_8 -#define SSD1963_4_16 42 -#define SSD1963_5_16 43 -#define SSD1963_5A_16 44 -#define SSD1963_7_16 45 -#define SSD1963_7A_16 46 -#define SSD1963_8_16 47 -#define ILI9341_16 48 -#define IPS_4_16 49 -#define SSD1963_5ER_16 50 -#define SSD1963_7ER_16 51 -#define ILI9486_16 52 -#define VIRTUAL_C 53 +#define SSD1963_4_16 43 +#define SSD1963_5_16 44 +#define SSD1963_5A_16 45 +#define SSD1963_7_16 46 +#define SSD1963_7A_16 47 +#define SSD1963_8_16 48 +#define ILI9341_16 49 +#define IPS_4_16 50 +#define SSD1963_5ER_16 51 +#define SSD1963_7ER_16 52 +#define ILI9486_16 53 +#define VIRTUAL_C 54 #define VIRTUAL VIRTUAL_C -#define VIRTUAL_M 54 -#define VS1053slow 55 -#define VS1053fast 56 +#define VIRTUAL_M 55 +#define VS1053slow 56 +#define VS1053fast 57 +#define NEXTGEN1 58 +#define NEXTGEN NEXTGEN1 #define TFT_NOP 0x00 #define TFT_SWRST 0x01 #define SSDTYPE (Option.DISPLAY_TYPE>=SSDPANEL && Option.DISPLAY_TYPESSD_PANEL_8 && Option.DISPLAY_TYPE>16)&0xffff +.endm + +float_section frrcore_v +.p2align 2 +// 1/2π to plenty of accuracy +.long 0 @ this allows values of e down to -32 +rtwopi: +.long 0,0 +.long 0x28BE60DB, 0x9391054A, 0x7F09D5F4, 0x7D4D3770, 0x36D8A566, 0x4F10E410 + +@ input: +@ r0 mantissa m Q23 +@ r1 exponent e>=-32, typically offset by +9 +@ output: +@ r0..r1 preserved +@ r6 range reduced result in revolutions Q32 +@ r2,r3,r4,r5 trashed +.thumb_func +frr_core: + adr r2,rtwopi + asrs r3,r1,#5 @ k=e/32, k<=5 for e offsets up to 9+32 + add r2,r2,r3,lsl#2 @ p + and r3,r1,#31 @ s=e%32 + mov r4,#1 + lsls r4,r4,r3 @ 1<>19 rounded, preserving flags + bic r3,#7 + + ldrd r2,r3,[r3] + mul r0,r0,r2 @ ε + vmov s0,s1,r3,r0 @ s0=-log u, s1=ε + + vcvt.f32.s32 s1,s1,#32 + vmul.f32 s2,s1,s1 @ power series in ε + sbc r1,r1,#0x7e @ ... and here + vmul.f32 s3,s1,s2 + lsls r1,#23 @ e Q23 + vmul.f32 s4,s2,s2 @ to ε⁴ +@ movlong r2,0x58b90bfc @ log 2 Q31, more accurate than we deserve + movw r2,0x0bfc + vmul.f32 s2,s2,s8 + movt r2,0x58b9 + vmul.f32 s3,s3,s9 + smmulr r1,r1,r2 @ Q22 + vmul.f32 s4,s4,s10 + vmov s7,r1 + vsub.f32 s3,s3,s4 + vcvt.f32.s32 s7,s7,#22 + vsub.f32 s2,s2,s3 + vsub.f32 s1,s1,s2 + vadd.f32 s0,s0,s1 @ log ε - log u + vadd.f32 s0,s0,s7 @ e log 2 + log ε - log u + vmov r0,s0 + bx r14 + +1: + bgt 3f @ +NaN? + beq 10f @ +Inf? +2: + cmp r0,#0x80800000 @ -0? + blo 11f + cmp r0,#0xff800000 @ -NaN/-Inf? +3: + orr r0,#0x00400000 + bhi 10f + movlong r0,0xffc00000 +10: + bx r14 +11: + movlong r0,0xff800000 + bx r14 + +.p2align 3 +k_log3: +.float 0.5 +.float 0.333333333333333 +.float 0.25 +.float 0 @ alignment + +logtab3: +@ u=64/[48:2:96]; u Q8, -log u F32 +.word 0x0155,0xbe92cb01 @ 00003e9b..00004145 +.word 0x0148,0xbe7dc8c3 @ 00003ec8..00004158 +.word 0x013b,0xbe545f68 @ 00003ec1..00004137 +.word 0x012f,0xbe2c99c7 @ 00003ebb..00004119 +.word 0x0125,0xbe0a3c2c @ 00003ef3..0000413d +.word 0x011a,0xbdc61a2f @ 00003eca..000040fe +.word 0x0111,0xbd83acc2 @ 00003eeb..0000410d +.word 0x0108,0xbcfc14d8 @ 00003ee8..000040f8 +.word 0x0100,0x00000000 @ 00003f00..00004100 +.word 0x00f8,0x3d020aec @ 00003ef8..000040e8 +.word 0x00f1,0x3d77518e @ 00003f13..000040f5 +.word 0x00ea,0x3db80698 @ 00003f12..000040e6 +.word 0x00e4,0x3ded393b @ 00003f3c..00004104 +.word 0x00dd,0x3e168b08 @ 00003f05..000040bf +.word 0x00d8,0x3e2dfa03 @ 00003f48..000040f8 +.word 0x00d2,0x3e4ad2d7 @ 00003f2a..000040ce +.word 0x00cd,0x3e637fde @ 00003f43..000040dd +.word 0x00c8,0x3e7cc8e3 @ 00003f48..000040d8 +.word 0x00c3,0x3e8b5ae6 @ 00003f39..000040bf +.word 0x00bf,0x3e95f784 @ 00003f6b..000040e9 +.word 0x00ba,0x3ea38c6e @ 00003f36..000040aa +.word 0x00b6,0x3eaeadef @ 00003f46..000040b2 +.word 0x00b2,0x3eba0ec4 @ 00003f46..000040aa +.word 0x00ae,0x3ec5b1cd @ 00003f36..00004092 +.word 0x00ab,0x3ece995f @ 00003f75..000040cb + +float_wrapper_section fsin_fcos + +30: + lsls r1,r0,#9 + bne 1f @ NaN? return it + orrs r0,r0,#0x80000000 @ Inf: make a NaN +1: + orrs r0,r0,#0x00400000 @ set top mantissa bit of NaN + bx r14 + +@ heavy-duty range reduction +@ here x≥256, -e in r1 +40: + push {r4-r7,r14} + movs r3,#1 + bfi r0,r3,#23,#9 @ insert implied 1 in mantissa, clear sign + rsb r1,#9 @ e+9 + mov r7,#0x7e @ this will be the exponent of the reduced angle - 1 +42: + bl frr_core +@ here r6 is revolutions Q32 + lsrs r3,r6,#30 @ quadrant count + adcs r3,r3,#0 @ rounded + add r12,r12,r3 + subs r6,r6,r3,lsl#30 @ reduced angle/2π Q32 -.125≤x<+.125 +@ comment out from here... + lsls r2,r6,#2 @ Q34 + it cs + rsbcs r2,r2,#0 @ absolute value + cmp r2,#1<<28 @ big enough for accuracy? + bhs 41f +@ ... to here for slightly better accuracy +43: + adds r1,r1,#2 @ try again with increased exponent + bl frr_core + eors r2,r6,r6,asr#32 @ absolute value + adc r2,r2,#0 + cmp r2,#1<<28 @ big enough yet? + bhs 44f + subs r7,r7,#2 + bpl 43b @ safety net +44: + +41: + ldr r4,=0xC90FDAA2 @ 2π Q29 + umull r2,r4,r2,r4 @ r4 has reduced angle Q34+Q29-Q32=Q31 +@ add r4,r4,r2,lsr#31 + clz r2,r4 @ normalise + lsls r4,r4,r2 + lsrs r4,r4,#8 + sub r2,r7,r2 + adc r0,r4,r2,lsl#23 @ with rounding + lsrs r1,r0,#23 @ re-extract exponent as there may have been a carry into it + rsbs r1,r1,#0x7f @ prepare exponent for re-entry + lsrs r6,r6,#31 + add r3,r0,r6,lsl#31 @ apply sign of reduced angle + pop {r4-r7,r14} + b 5f @ re-enter with no risk of looping + +.ltorg + +@ light-duty range reduction +@ here argument ≥1 +@ r0: argument +@ r1: -e +@ r12: quadrant count +@ required result is sin(r0+r12*π/2) +10: + cmn r1,#0x80 + beq 30b @ Inf/NaN + bics r2,r0,r12,lsl#31 @ negative argument,doing sin -> +2 quadrants + it mi + addmi r12,r12,#2 + bic r0,r0,#0x80000000 @ make positive: original sign is now captured in quadrant count in r12 + +@ this may not actually be faster than doing it in integer registers + vmov s0,r0 + adr r2,k_sc4 + vldmia r2!,{s5-s7} +@ vmul.f32 s4,s4,s0 @ this accurate calculation of the quadrant count does not seem necessary +@ vfma.f32 s4,s5,s0 + vmul.f32 s4,s5,s0 @ this is BALGE + cmn r1,#8 @ ≥256? + vrintn.f32.f32 s4,s4 @ round to quadrant count: x<256 so count≤163 + ble 40b @ then do heavy-duty range reduction + vfms.f32 s0,s4,s7 + vfms.f32 s0,s4,s6 + vmov r3,s0 @ reduced angle + vcvt.s32.f32 s3,s4 + ubfx r2,r3,#23,#8 @ get exponent + cmp r2,#0x78 + blo 40b @ very small result? use heavy-duty reduction to get a more accurate answer + rsbs r1,r2,#0x7f @ ready for re-entry + vmov r2,s3 @ integer quadrant count + add r12,r12,r2 +@ prepare to re-enter with no risk of looping + b 5f + +k_sc4: +@ 2/π=0.A2F9836E4E441529FC... +.word 0x3f22f983 @ 2/π +@ π/2=1.921FB54442D1846989... +.word 0xb695777a,0x3fc91000 @ these two add up to π/2 with error ~1.6e-13 + +wrapper_func sincosf + + push {r0-r2,r14} + ubfx r1,r0,#23,#8 + cmp r1,#0xff @ Inf/NaN? + beq 2f + bl cosf_entry @ this will exit via 1f or 2f... + pop {r1-r2,r14} + str r0,[r14] +@ here C is still set from lsrs r12,r12,#1 + bcs 1f + mvns r1,r1 + eor r12,r12,r1,lsr#31 +@ this is fsc_costail: +@ here calculate cos φ+ε = cosθ + vmul.f32 s5,s7,s1 @ sinφ sinε + vfma.f32 s5,s2,s6 @ sinφ sinε + cosφ(1-cosε) + vsub.f32 s5,s6,s5 @ cosφ - (sinφ sinε + cosφ(1-cosε)) = cosφ cosε - sinφ sinε + vmov.f32 r0,s5 + eor r0,r0,r12,lsl#31 + str r0,[r2] + pop {r15} + +1: + eor r12,r12,r1,lsr#31 +@ this is fsc_sintail: +@ here calculate sin φ+ε = sinθ + vmul.f32 s4,s2,s7 @ sinφ(1-cosε) + vfms.f32 s4,s6,s1 @ sinφ(1-cosε) - cosφ sinε + eor r1,r12,r3,lsr#31 @ flip sign if (reduced) argument was negative + vsub.f32 s4,s7,s4 @ cosφ sinε + sinφ cosε + vmov.f32 r0,s4 + eor r0,r0,r1,lsl#31 + str r0,[r2] @ save cos result + pop {r15} + +@ sincos of Inf or NaN +2: + lsls r1,r0,#9 + pop {r1-r3,r14} + bne 1f @ NaN? return it + orrs r0,r0,#0x80000000 @ Inf: make a NaN +1: + orrs r0,r0,#0x00400000 @ set top mantissa bit of NaN + str r0,[r2] @ both sin and cos results + str r0,[r3] + bx r14 + +wrapper_func sinf +@ r12b1..0: quadrant count + movs r12,#0 + b 1f + +wrapper_func cosf +.thumb_func +cosf_entry: + movs r12,#1 @ cos -> +1 quadrant +1: + ubfx r1,r0,#23,#8 @ get exponent + cbz r1,20f @ 0/denormal? +22: + rsbs r1,r1,#0x7f + bls 10b @ argument ≥1? needs reduction; also Inf/NaN handling + bic r3,r0,r12,lsl#31 @ this would mess up NaNs so do it here +5: +@ here we have a quadrant count in r12 and a signed offset r0 from r12*π/2 + bic r0,r3,#0x80000000 @ this would mess up NaNs so do it here + vmov s0,r0 + ubfx r0,r0,#18,#5 @ extract top of mantissa + adds r0,r0,#32 @ insert implied 1 + lsrs r1,r0,r1 @ to fixed point Q5 + ldr r2,=k_sc3 + adcs r1,r1,#0 @ rounding + vldmia r2!,{s8-s9} + add r2,r2,r1,lsl#2 @ 12 bytes per entry + add r2,r2,r1,lsl#3 + + vldmia r2,{s5-s7} @ φ, cosφ, sinφ + vsub.f32 s1,s0,s5 @ ε + vmul.f32 s2,s1,s1 @ ε² + lsrs r12,r12,#1 @ computing cosine? + vmul.f32 s3,s2,s1 @ ε³ + bcs 2f + + vmul.f32 s2,s2,s8 @ ε²/2! ~ 1-cosε + vmul.f32 s3,s3,s9 @ ε³/3! + vsub.f32 s1,s1,s3 @ ε-ε³/3! ~ sinε + +@ here: +@ s1: sinε +@ s2: 1-cosε +@ s6: cosφ +@ s7: sinφ +@ r12: quadrant count +fsc_sintail: +@ here calculate sin φ+ε = sinθ + vmul.f32 s4,s2,s7 @ sinφ(1-cosε) + vfms.f32 s4,s6,s1 @ sinφ(1-cosε) - cosφ sinε + eor r1,r12,r3,lsr#31 @ flip sign if (reduced) argument was negative + vsub.f32 s4,s7,s4 @ cosφ sinε + sinφ cosε + vmov.f32 r0,s4 + eor r0,r0,r1,lsl#31 + bx r14 + +20: + and r0,r0,#0x80000000 @ make signed zero + b 22b + +.p2align 2 +2: + vmul.f32 s3,s3,s9 @ ε³/3! + vsub.f32 s1,s1,s3 @ ε-ε³/3! ~ sinε + vmul.f32 s2,s2,s8 @ ε²/2! ~ 1-cosε +fsc_costail: +@ here calculate cos φ+ε = cosθ + vmul.f32 s5,s7,s1 @ sinφ sinε + vfma.f32 s5,s2,s6 @ sinφ sinε + cosφ(1-cosε) + vsub.f32 s5,s6,s5 @ cosφ - (sinφ sinε + cosφ(1-cosε)) = cosφ cosε - sinφ sinε + vmov.f32 r0,s5 + eor r0,r0,r12,lsl#31 + bx r14 + +.p2align 3 +k_sc3: +.word 0x3EFFFEC1 @ ~ 1/2! with PMC +.word 0x3e2aaa25 @ ~ 1/3! with PMC + +trigtab2: +// φ cos φ sin φ +.word 0x00000000,0x3f800000,0x00000000 +.word 0x3cfcc961,0x3f7fe0cd,0x3cfcbf1c @ φ=0.03085774 : cos φ=3feffc199ff28ef4 33.3b; sin φ=3f9f97e38006c678 39.2b +.word 0x3d810576,0x3f7f7dfe,0x3d80ef9e @ φ=0.06299870 : cos φ=3fefefbfc00d6b6d 33.3b; sin φ=3fb01df3c000dfd5 40.2b +.word 0x3dbf0c09,0x3f7ee30f,0x3dbec522 @ φ=0.09328467 : cos φ=3fefdc61dff4f58e 33.5b; sin φ=3fb7d8a43ffdf9ac 39.0b +.word 0x3dff24b6,0x3f7e0414,0x3dfe7be2 @ φ=0.12458174 : cos φ=3fefc0827fdaf90f 31.8b; sin φ=3fbfcf7c3ff9dd0c 37.4b +.word 0x3e1f0713,0x3f7ceb48,0x3e1e63a0 @ φ=0.15530042 : cos φ=3fef9d68ffe680a0 32.3b; sin φ=3fc3cc73fffa6d09 36.5b +.word 0x3e40306d,0x3f7b811d,0x3e3f1015 @ φ=0.18768473 : cos φ=3fef70239fe32301 32.1b; sin φ=3fc7e2029ffdbc2c 37.8b +.word 0x3e60ada2,0x3f79dccf,0x3e5ee13e @ φ=0.21941236 : cos φ=3fef3b99e023f5aa 31.8b; sin φ=3fcbdc27bffe216d 38.1b +.word 0x3e800d7b,0x3f7808fa,0x3e7d7196 @ φ=0.25010285 : cos φ=3fef011f401572a6 32.6b; sin φ=3fcfae32c00328bb 37.3b +.word 0x3e8f986e,0x3f75ff65,0x3e8db868 @ φ=0.28045982 : cos φ=3feebfeca0aaaf99 29.6b; sin φ=3fd1b70cfffc1468 36.0b +.word 0x3e9fe1f4,0x3f739e93,0x3e9d4bfd @ φ=0.31227076 : cos φ=3fee73d25fbf733b 31.0b; sin φ=3fd3a97fa0002ced 40.5b +.word 0x3eb054c6,0x3f70f7ae,0x3eacddb3 @ φ=0.34439677 : cos φ=3fee1ef5bfcf70cb 31.4b; sin φ=3fd59bb65fff5c30 38.6b +.word 0x3ebf89c5,0x3f6e4b60,0x3ebb1a0a @ φ=0.37409797 : cos φ=3fedc96bffdebb8a 31.9b; sin φ=3fd763414003344b 36.3b +.word 0x3ecfc426,0x3f6b35ca,0x3eca1c63 @ φ=0.40579337 : cos φ=3fed66b93fe27dc6 32.1b; sin φ=3fd9438c5ffe5d45 37.3b +.word 0x3ee054f2,0x3f67d166,0x3ed93907 @ φ=0.43814808 : cos φ=3fecfa2cbffc16e9 35.0b; sin φ=3fdb2720dffef5b6 37.9b +.word 0x3eeff0dd,0x3f64664b,0x3ee74116 @ φ=0.46863452 : cos φ=3fec8cc95f714272 29.8b; sin φ=3fdce822c00479ad 35.8b +.word 0x3f002b31,0x3f609488,0x3ef5c30f @ φ=0.50065905 : cos φ=3fec1290ffc99208 31.2b; sin φ=3fdeb861dfff3932 38.4b +.word 0x3f07e407,0x3f5cc5a2,0x3f01992b @ φ=0.53082317 : cos φ=3feb98b44034cd46 31.3b; sin φ=3fe033255ffff628 41.7b +.word 0x3f101fc5,0x3f587d8f,0x3f08a165 @ φ=0.56298476 : cos φ=3feb0fb1e0ceda6f 29.3b; sin φ=3fe1142c9ffd5ae4 35.6b +.word 0x3f17f68a,0x3f5434b5,0x3f0f31ca @ φ=0.59360564 : cos φ=3fea8696a038a06f 31.2b; sin φ=3fe1e639400269fb 35.7b +.word 0x3f1fffe2,0x3f4f9b59,0x3f15c8d7 @ φ=0.62499821 : cos φ=3fe9f36b1f428363 29.4b; sin φ=3fe2b91ae001d55d 36.1b +.word 0x3f280646,0x3f4acf6b,0x3f1c37c4 @ φ=0.65634573 : cos φ=3fe959ed61449f08 28.7b; sin φ=3fe386f87ffd9617 35.7b +.word 0x3f303041,0x3f45b9e0,0x3f229ae4 @ φ=0.68823630 : cos φ=3fe8b73c0047ae7a 30.8b; sin φ=3fe4535c7ffdf1ac 36.0b +.word 0x3f381da7,0x3f4098ca,0x3f28a620 @ φ=0.71920246 : cos φ=3fe81319402ae6e1 31.6b; sin φ=3fe514c3ffff423c 37.4b +.word 0x3f3fc72f,0x3f3b76ac,0x3f2e564a @ φ=0.74913305 : cos φ=3fe76ed5809d419f 29.7b; sin φ=3fe5cac93fffaf1d 38.7b +.word 0x3f4813db,0x3f35b6cc,0x3f34526b @ φ=0.78155297 : cos φ=3fe6b6d9800e8b52 33.1b; sin φ=3fe68a4d5ffe89fc 36.5b +.word 0x3f4fc779,0x3f30352f,0x3f39b4d0 @ φ=0.81163746 : cos φ=3fe606a5dfdc2b5b 31.8b; sin φ=3fe73699fffd7fc8 35.7b +.word 0x3f57dd52,0x3f2a4170,0x3f3f2d91 @ φ=0.84322083 : cos φ=3fe5482e011ba752 28.9b; sin φ=3fe7e5b21ffcb223 35.3b +.word 0x3f5fce26,0x3f243e9f,0x3f445dc3 @ φ=0.87423933 : cos φ=3fe487d3e0b9864b 29.5b; sin φ=3fe88bb85ffde6d5 35.9b +.word 0x3f6825f1,0x3f1dc250,0x3f499d1c @ φ=0.90682894 : cos φ=3fe3b849ffea9b8f 32.6b; sin φ=3fe933a38002730d 35.7b +.word 0x3f703be1,0x3f175041,0x3f4e7ebf @ φ=0.93841368 : cos φ=3fe2ea0820791b4e 30.1b; sin φ=3fe9cfd7e0053e65 34.6b +.word 0x3f781078,0x3f10ed71,0x3f5306af @ φ=0.96900129 : cos φ=3fe21dae1fdea23e 31.9b; sin φ=3fea60d5e001b90b 36.2b +.word 0x3f7ff4d4,0x3f0a5aa7,0x3f57649b @ φ=0.99982953 : cos φ=3fe14b54deeaa407 28.9b; sin φ=3feaec9360012825 36.8b + +float_wrapper_section tanf + +wrapper_func tanf + push {r0,r14} + ubfx r1,r0,#23,#8 + cmp r1,#0xff @ Inf/NaN? + beq 2f + bl cosf_entry @ this will exit via sintail or costail... + ldr r1,[sp,#0] +@ here C is still set from lsrs r12,r12,#1 + bcs 1f +@ we exited via sintail +@ this is fsc_costail: +@ here calculate cos φ+ε = cosθ + vmul.f32 s5,s7,s1 @ sinφ sinε + vfma.f32 s5,s2,s6 @ sinφ sinε + cosφ(1-cosε) + eors r1,r1,r3 + vsub.f32 s5,s6,s5 @ cosφ - (sinφ sinε + cosφ(1-cosε)) = cosφ cosε - sinφ sinε + vdiv.f32 s0,s5,s4 + vmov.f32 r0,s0 + it pl + eorpl r0,r0,#0x80000000 + pop {r1,r15} + +1: +@ we exited via costail +@ this is fsc_sintail: +@ here calculate sin φ+ε = sinθ + vmul.f32 s4,s2,s7 @ sinφ(1-cosε) + vfms.f32 s4,s6,s1 @ sinφ(1-cosε) - cosφ sinε + eors r1,r1,r3 + vsub.f32 s4,s7,s4 @ cosφ sinε + sinφ cosε + vdiv.f32 s0,s4,s5 + vmov.f32 r0,s0 + it mi + eormi r0,r0,#0x80000000 + pop {r1,r15} + +@ tan of Inf or NaN +2: + lsls r1,r0,#9 + bne 1f @ NaN? return it + orrs r0,r0,#0x80000000 @ Inf: make a NaN +1: + orrs r0,r0,#0x00400000 @ set top mantissa bit of NaN + pop {r3,r15} + + +float_wrapper_section atan2f + +50: +60: + orrs r0,r1,#0x00400000 + bx r14 + +51: + bne 52f @ NaN? + cmp r3,#0x7f800000 @ y an infinity; x an infinity too? + bne 55f @ no: carry on +@ here x and y are both infinities + b 66f + +52: +62: + orrs r0,r0,#0x00400000 + bx r14 + +61: + bne 62b @ NaN? + cmp r3,#0x7f800000 @ y an infinity; x an infinity too? + bne 65f @ no: carry on +66: +@ here x and y are both infinities + subs r0,r0,#1 @ make both finite (and equal) with same sign and retry + subs r1,r1,#1 + b 86f + +70: + and r3,#0x80000000 + cmp r2,#0x00800000 + bhs 72f @ y 0 or denormal? +@ here both x and y are zeros + b 85f +71: + and r2,#0x80000000 +72: + vmov s0,s1,r2,r3 + vdiv.f32 s2,s0,s1 @ restart the division + b 73f @ and go back and check for NaNs + +80: + and r3,#0x80000000 + cmp r2,#0x00800000 + bhs 82f @ y 0 or denormal? +85: +@ here both x and y are zeros + orr r1,r1,0x3f800000 @ retry with x replaced by ~1 with appropriate sign + b 86f + +81: + and r2,#0x80000000 +82: + vmov s0,s1,r2,r3 + vdiv.f32 s2,s1,s0 @ restart the division + b 83f @ and go back and check for NaNs + +wrapper_func atan2f +86: + bic r2,r0,#0x80000000 + bic r3,r1,#0x80000000 + vmov s0,s1,r2,r3 + cmp r2,r3 @ |y| vs. |x| + bhi 1f +@ here |x|≥|y| so we need |y|/|x|; octant/xs/ys: 0++,3-+,4--,7+- + vdiv.f32 s2,s0,s1 @ get this division started; result ≤1 + cmp r3,#0x00800000 + blo 70b @ x 0 or denormal? + cmp r2,#0x00800000 + blo 71b @ y 0 or denormal? +73: + cmp r3,#0x7f800000 + bhi 50b @ x NaN? + cmp r2,#0x7f800000 + bhs 51b @ y Inf or NaN? +55: + cmp r1,#0 + ite mi + ldrmi r12,pi @ if x<0, need two extra quadrants + movpl r12,#0 + @ inner negation is the sign of x + b 2f + +1: +@ here |x|<|y| so we need |x|/|y|; octant/xs/ys: 1++,2-+,5--,6+- + vdiv.f32 s2,s1,s0 @ result <1 + cmp r3,#0x00800000 + blo 80b @ x 0 or denormal? + cmp r2,#0x00800000 + blo 81b @ y 0 or denormal? +83: + cmp r3,#0x7f800000 + bhi 60b @ x NaN? + cmp r2,#0x7f800000 + bhs 61b @ y Inf or NaN? +65: + ldr r12,piover2 @ always one extra quadrant in this path + eors r1,r1,#0x80000000 @ inner negation is the complement of the sign of x + +2: +@ here +@ r0 y +@ r1 ±x +@ r2 |y| +@ r3 |x| +@ s0,s1 = |x|,|y| +@ s2=s0/s1 or s1/s0, 0≤s2≤1 +@ r12=quadrant count * π/2 +@ where the final result is +@ ± (r12 ± atn s2) where the inner negation is given by r1b31 and the outer negation by r0b31 + + adr r2,trigtab3 + vmov.f32 s3,s2 + vcvt.u32.f32 s3,s3,#6 + vmov.f32 r3,s3 + lsrs r3,r3,#1 + adcs r3,r3,#0 @ rounding; set Z if in φ==0 case + add r2,r2,r3,lsl#3 + vldr s5,[r2,#4] @ t=tanφ + vmul.f32 s0,s5,s2 @ ty + vsub.f32 s1,s2,s5 @ y-t + vmov.f32 s5,#1.0 + vadd.f32 s0,s5,s0 @ 1+ty + beq 9f @ did we look up zeroth table entry? + +@ now (s0,s1) = (x,y) + vdiv.f32 s0,s1,s0 @ ε + ldr r2,[r2] @ φ Q29 +@ result is now ±(r12±(r2+atn(s0)) + cmp r1,#0 @ inner negation + it mi + rsbmi r2,r2,#0 + add r2,r12,r2 @ Q29 + cmp r0,#0 @ outer negation + it mi + rsbmi r2,r2,#0 + cmp r2,#0 + bpl 1f + rsbs r2,r2,#0 + clz r3,r2 + lsls r2,r2,r3 + beq 3f + rsb r3,#0x180 + b 2f +1: + clz r3,r2 + lsls r2,r2,r3 + beq 3f + rsb r3,#0x80 +2: + lsrs r2,r2,#8 @ rounding bit to carry + adc r2,r2,r3,lsl#23 @ with rounding +3: + vmul.f32 s2,s0,s0 @ ε² + vldr.f32 s3,onethird + vmul.f32 s2,s2,s0 @ ε³ + teq r0,r1 + vmul.f32 s2,s2,s3 @ ε³/3 + vmov.f32 s4,r2 + vsub.f32 s0,s0,s2 @ ~atn(ε) + ite pl + vaddpl.f32 s0,s4,s0 + vsubmi.f32 s0,s4,s0 + vmov.f32 r0,s0 + bx r14 + +9: @ we looked up the zeroth table entry; we could generate slightly more accurate results here +@ now (s0,s1) = (x,y) + vdiv.f32 s0,s1,s0 @ ε +@ result is now ±(r12±(0+atn(s0)) + mov r2,r12 @ Q29; in fact r12 is only ±π/2 or ±π so can probably simplify this + cmp r0,#0 @ outer negation + it mi + rsbmi r2,r2,#0 + cmp r2,#0 + bpl 1f + rsbs r2,r2,#0 + clz r3,r2 + lsls r2,r2,r3 + beq 3f + rsb r3,#0x180 + b 2f +1: + clz r3,r2 + lsls r2,r2,r3 + beq 3f + rsb r3,#0x80 +2: + lsrs r2,r2,#8 @ rounding bit to carry + adc r2,r2,r3,lsl#23 @ with rounding +3: + vmul.f32 s2,s0,s0 @ ε² + vldr.f32 s3,onethird + vmul.f32 s2,s2,s0 @ ε³ + teq r0,r1 + vmul.f32 s2,s2,s3 @ ε³/3 + vmov.f32 s4,r2 + vsub.f32 s0,s0,s2 @ ~atn(ε) + ite pl + vaddpl.f32 s0,s4,s0 + vsubmi.f32 s0,s4,s0 + vmov.f32 r0,s0 + tst r0,#0x7f800000 @ about to return a denormal? + it ne + bxne r14 + and r0,r0,#0x80000000 @ make it zero + bx r14 + +piover2: .word 0x3243f6a9 @ Q29 +pi: .word 0x6487ed51 @ Q29 +onethird: .float 0.33333333 + +trigtab3: +// φ Q29 tan φ SP +.word 0x00000000,0x00000000 +.word 0x00ffee23,0x3d0001bb @ φ=0.03124148 : tan φ=3fa000375fffff9d 50.4b +.word 0x01fe88dc,0x3d7f992a @ φ=0.06232112 : tan φ=3faff3253fffea1f 44.5b +.word 0x02fe0a70,0x3dc01203 @ φ=0.09351084 : tan φ=3fb8024060002522 42.8b +.word 0x03fad228,0x3e000368 @ φ=0.12436779 : tan φ=3fc0006cfffffc90 45.2b +.word 0x04f5ab70,0x3e1ffdea @ φ=0.15498897 : tan φ=3fc3ffbd400014d5 42.6b +.word 0x05ed56f8,0x3e3fdddc @ φ=0.18522213 : tan φ=3fc7fbbb80000beb 43.4b +.word 0x06e4cfa0,0x3e601425 @ φ=0.21543103 : tan φ=3fcc02849fffe817 42.4b +.word 0x07d8d3e0,0x3e80215d @ φ=0.24521822 : tan φ=3fd0042b9ffff89f 43.1b +.word 0x08c60460,0x3e9000a5 @ φ=0.27417201 : tan φ=3fd20014a000182b 41.4b +.word 0x09b26770,0x3ea01492 @ φ=0.30302784 : tan φ=3fd402923ffff932 43.2b +.word 0x0a996d50,0x3eb01377 @ φ=0.33122888 : tan φ=3fd6026ee0001062 42.0b +.word 0x0b7a6d10,0x3ebff4a0 @ φ=0.35869458 : tan φ=3fd7fe93ffff8c38 39.1b +.word 0x0c593ce0,0x3ed0019f @ φ=0.38589329 : tan φ=3fda0033e0001354 41.7b +.word 0x0d33ebd0,0x3ee01bbc @ φ=0.41258803 : tan φ=3fdc0377800162a1 37.5b +.word 0x0e087ab0,0x3ef01fbd @ φ=0.43853506 : tan φ=3fde03f79fffddf2 40.9b +.word 0x0ed56180,0x3effef98 @ φ=0.46354747 : tan φ=3fdffdf30000767d 39.1b +.word 0x0fa1de80,0x3f080ebf @ φ=0.48850942 : tan φ=3fe101d7dfffb9fc 38.9b +.word 0x10639d00,0x3f0fec31 @ φ=0.51215982 : tan φ=3fe1fd862000aad5 37.6b +.word 0x112690e0,0x3f180cfd @ φ=0.53595775 : tan φ=3fe3019fa00069ea 38.3b +.word 0x11e014c0,0x3f200065 @ φ=0.55860364 : tan φ=3fe4000ca00022e5 39.9b +.word 0x129651e0,0x3f2808be @ φ=0.58084959 : tan φ=3fe50117c00015a7 40.6b +.word 0x1346d400,0x3f300a7d @ φ=0.60239601 : tan φ=3fe6014f9fffa020 38.4b +.word 0x13efc7c0,0x3f37ee2f @ φ=0.62302005 : tan φ=3fe6fdc5dfff98d7 38.3b +.word 0x14988960,0x3f400c32 @ φ=0.64362019 : tan φ=3fe801863fffff81 46.0b +.word 0x1537a8c0,0x3f47ef42 @ φ=0.66304433 : tan φ=3fe8fde8400062a4 38.4b +.word 0x15d4cc60,0x3f4ff630 @ φ=0.68222636 : tan φ=3fe9fec5ffff76e2 37.9b +.word 0x166ef280,0x3f581534 @ φ=0.70104337 : tan φ=3feb02a680004e91 38.7b +.word 0x16ff75c0,0x3f5fef1e @ φ=0.71868408 : tan φ=3febfde3c0001404 40.7b +.word 0x179116a0,0x3f68184d @ φ=0.73646098 : tan φ=3fed03099ffed6e5 36.8b +.word 0x181b5aa0,0x3f701722 @ φ=0.75333911 : tan φ=3fee02e43fffd351 39.5b +.word 0x18a10560,0x3f781071 @ φ=0.76965588 : tan φ=3fef020e20005c05 38.5b +.word 0x19214060,0x3f7ff451 @ φ=0.78530902 : tan φ=3feffe8a1fffe11b 40.1b + +#endif diff --git a/Code/pico_multi_booter/picomite/gpio.h b/Code/pico_multi_booter/picomite/gpio.h new file mode 100644 index 0000000..bc03b62 --- /dev/null +++ b/Code/pico_multi_booter/picomite/gpio.h @@ -0,0 +1,1441 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _HARDWARE_GPIO_H +#define _HARDWARE_GPIO_H + +#include "pico.h" +#include "hardware/structs/sio.h" +#include "hardware/structs/pads_bank0.h" +#include "hardware/structs/io_bank0.h" +#include "hardware/irq.h" + +// PICO_CONFIG: PICO_USE_GPIO_COPROCESSOR, Enable/disable use of the GPIO coprocessor for GPIO access, type=bool, default=1, group=hardware_gpio +#if !defined(PICO_USE_GPIO_COPROCESSOR) && HAS_GPIO_COPROCESSOR +#define PICO_USE_GPIO_COPROCESSOR 1 +#endif + +#if PICO_USE_GPIO_COPROCESSOR +#include "hardware/gpio_coproc.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_HARDWARE_GPIO, Enable/disable assertions in the hardware_gpio module, type=bool, default=0, group=hardware_gpio +#ifndef PARAM_ASSERTIONS_ENABLED_HARDWARE_GPIO +#ifdef PARAM_ASSERTIONS_ENABLED_GPIO // backwards compatibility with SDK < 2.0.0 +#define PARAM_ASSERTIONS_ENABLED_HARDWARE_GPIO PARAM_ASSERTIONS_ENABLED_GPIO +#else +#define PARAM_ASSERTIONS_ENABLED_HARDWARE_GPIO 0 +#endif +#endif + +/** \file gpio.h + * \defgroup hardware_gpio hardware_gpio + * + * \brief General Purpose Input/Output (GPIO) API + * + * RP-series microcontrollers have two banks of General Purpose Input / Output (GPIO) pins, which are assigned as follows: + * + * \if rp2040_specific + * RP2040 has 30 user GPIO pins in bank 0, and 6 QSPI pins in the QSPI bank 1 (QSPI_SS, QSPI_SCLK and QSPI_SD0 to QSPI_SD3). The QSPI + * pins are used to execute code from an external flash device, leaving the User bank (GPIO0 to GPIO29) for the programmer to use. + * \endif + * + * \if rp2350_specific + * The number of GPIO pins available depends on the package. There are 30 user GPIOs in bank 0 in the QFN-60 package (RP2350A), or 48 user GPIOs + * in the QFN-80 package. Bank 1 contains the 6 QSPI pins and the USB DP/DM pins. + * \endif + * + * All GPIOs support digital input and output, but a subset can also be used as inputs to the chip’s Analogue to Digital + * Converter (ADC). The allocation of GPIO pins to the ADC depends on the packaging. + * + * RP2040 and RP2350 QFN-60 GPIO, ADC pins are 26-29. + * RP2350 QFN-80, ADC pins are 40-47. + * + * Each GPIO can be controlled directly by software running on the processors, or by a number of other functional blocks. + * + * The function allocated to each GPIO is selected by calling the \ref gpio_set_function function. \note Not all functions + * are available on all pins. + * + * Each GPIO can have one function selected at a time. Likewise, each peripheral input (e.g. UART0 RX) should only be selected on + * one _GPIO_ at a time. If the same peripheral input is connected to multiple GPIOs, the peripheral sees the logical OR of these + * GPIO inputs. Please refer to the datasheet for more information on GPIO function select. + * + * ### Function Select Table + * + * \if rp2040_specific + * On RP2040 the function selects are: + * + * | GPIO | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | + * |--------|----------|-----------|----------|--------|-----|------|------|---------------|---------------| + * | 0 | SPI0 RX | UART0 TX | I2C0 SDA | PWM0 A | SIO | PIO0 | PIO1 | | USB OVCUR DET | + * | 1 | SPI0 CSn | UART0 RX | I2C0 SCL | PWM0 B | SIO | PIO0 | PIO1 | | USB VBUS DET | + * | 2 | SPI0 SCK | UART0 CTS | I2C1 SDA | PWM1 A | SIO | PIO0 | PIO1 | | USB VBUS EN | + * | 3 | SPI0 TX | UART0 RTS | I2C1 SCL | PWM1 B | SIO | PIO0 | PIO1 | | USB OVCUR DET | + * | 4 | SPI0 RX | UART1 TX | I2C0 SDA | PWM2 A | SIO | PIO0 | PIO1 | | USB VBUS DET | + * | 5 | SPI0 CSn | UART1 RX | I2C0 SCL | PWM2 B | SIO | PIO0 | PIO1 | | USB VBUS EN | + * | 6 | SPI0 SCK | UART1 CTS | I2C1 SDA | PWM3 A | SIO | PIO0 | PIO1 | | USB OVCUR DET | + * | 7 | SPI0 TX | UART1 RTS | I2C1 SCL | PWM3 B | SIO | PIO0 | PIO1 | | USB VBUS DET | + * | 8 | SPI1 RX | UART1 TX | I2C0 SDA | PWM4 A | SIO | PIO0 | PIO1 | | USB VBUS EN | + * | 9 | SPI1 CSn | UART1 RX | I2C0 SCL | PWM4 B | SIO | PIO0 | PIO1 | | USB OVCUR DET | + * | 10 | SPI1 SCK | UART1 CTS | I2C1 SDA | PWM5 A | SIO | PIO0 | PIO1 | | USB VBUS DET | + * | 11 | SPI1 TX | UART1 RTS | I2C1 SCL | PWM5 B | SIO | PIO0 | PIO1 | | USB VBUS EN | + * | 12 | SPI1 RX | UART0 TX | I2C0 SDA | PWM6 A | SIO | PIO0 | PIO1 | | USB OVCUR DET | + * | 13 | SPI1 CSn | UART0 RX | I2C0 SCL | PWM6 B | SIO | PIO0 | PIO1 | | USB VBUS DET | + * | 14 | SPI1 SCK | UART0 CTS | I2C1 SDA | PWM7 A | SIO | PIO0 | PIO1 | | USB VBUS EN | + * | 15 | SPI1 TX | UART0 RTS | I2C1 SCL | PWM7 B | SIO | PIO0 | PIO1 | | USB OVCUR DET | + * | 16 | SPI0 RX | UART0 TX | I2C0 SDA | PWM0 A | SIO | PIO0 | PIO1 | | USB VBUS DET | + * | 17 | SPI0 CSn | UART0 RX | I2C0 SCL | PWM0 B | SIO | PIO0 | PIO1 | | USB VBUS EN | + * | 18 | SPI0 SCK | UART0 CTS | I2C1 SDA | PWM1 A | SIO | PIO0 | PIO1 | | USB OVCUR DET | + * | 19 | SPI0 TX | UART0 RTS | I2C1 SCL | PWM1 B | SIO | PIO0 | PIO1 | | USB VBUS DET | + * | 20 | SPI0 RX | UART1 TX | I2C0 SDA | PWM2 A | SIO | PIO0 | PIO1 | CLOCK GPIN0 | USB VBUS EN | + * | 21 | SPI0 CSn | UART1 RX | I2C0 SCL | PWM2 B | SIO | PIO0 | PIO1 | CLOCK GPOUT0 | USB OVCUR DET | + * | 22 | SPI0 SCK | UART1 CTS | I2C1 SDA | PWM3 A | SIO | PIO0 | PIO1 | CLOCK GPIN1 | USB VBUS DET | + * | 23 | SPI0 TX | UART1 RTS | I2C1 SCL | PWM3 B | SIO | PIO0 | PIO1 | CLOCK GPOUT1 | USB VBUS EN | + * | 24 | SPI1 RX | UART1 TX | I2C0 SDA | PWM4 A | SIO | PIO0 | PIO1 | CLOCK GPOUT2 | USB OVCUR DET | + * | 25 | SPI1 CSn | UART1 RX | I2C0 SCL | PWM4 B | SIO | PIO0 | PIO1 | CLOCK GPOUT3 | USB VBUS DET | + * | 26 | SPI1 SCK | UART1 CTS | I2C1 SDA | PWM5 A | SIO | PIO0 | PIO1 | | USB VBUS EN | + * | 27 | SPI1 TX | UART1 RTS | I2C1 SCL | PWM5 B | SIO | PIO0 | PIO1 | | USB OVCUR DET | + * | 28 | SPI1 RX | UART0 TX | I2C0 SDA | PWM6 A | SIO | PIO0 | PIO1 | | USB VBUS DET | + * | 29 | SPI1 CSn | UART0 RX | I2C0 SCL | PWM6 B | SIO | PIO0 | PIO1 | | USB VBUS EN | + * \endif + * \if rp2350_specific + * On RP2350 the function selects are: + * + * | GPIO | F0 | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | + * |-------|------|----------|-----------|----------|--------|-----|------|------|------|--------------|---------------|----------| + * | 0 | | SPI0 RX | UART0 TX | I2C0 SDA | PWM0 A | SIO | PIO0 | PIO1 | PIO2 | XIP_CS1n | USB OVCUR DET | | + * | 1 | | SPI0 CSn | UART0 RX | I2C0 SCL | PWM0 B | SIO | PIO0 | PIO1 | PIO2 | TRACECLK | USB VBUS DET | | + * | 2 | | SPI0 SCK | UART0 CTS | I2C1 SDA | PWM1 A | SIO | PIO0 | PIO1 | PIO2 | TRACEDATA0 | USB VBUS EN | UART0 TX | + * | 3 | | SPI0 TX | UART0 RTS | I2C1 SCL | PWM1 B | SIO | PIO0 | PIO1 | PIO2 | TRACEDATA1 | USB OVCUR DET | UART0 RX | + * | 4 | | SPI0 RX | UART1 TX | I2C0 SDA | PWM2 A | SIO | PIO0 | PIO1 | PIO2 | TRACEDATA2 | USB VBUS DET | | + * | 5 | | SPI0 CSn | UART1 RX | I2C0 SCL | PWM2 B | SIO | PIO0 | PIO1 | PIO2 | TRACEDATA3 | USB VBUS EN | | + * | 6 | | SPI0 SCK | UART1 CTS | I2C1 SDA | PWM3 A | SIO | PIO0 | PIO1 | PIO2 | | USB OVCUR DET | UART1 TX | + * | 7 | | SPI0 TX | UART1 RTS | I2C1 SCL | PWM3 B | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS DET | UART1 RX | + * | 8 | | SPI1 RX | UART1 TX | I2C0 SDA | PWM4 A | SIO | PIO0 | PIO1 | PIO2 | XIP_CS1n | USB VBUS EN | | + * | 9 | | SPI1 CSn | UART1 RX | I2C0 SCL | PWM4 B | SIO | PIO0 | PIO1 | PIO2 | | USB OVCUR DET | | + * | 10 | | SPI1 SCK | UART1 CTS | I2C1 SDA | PWM5 A | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS DET | UART1 TX | + * | 11 | | SPI1 TX | UART1 RTS | I2C1 SCL | PWM5 B | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS EN | UART1 RX | + * | 12 | HSTX | SPI1 RX | UART0 TX | I2C0 SDA | PWM6 A | SIO | PIO0 | PIO1 | PIO2 | CLOCK GPIN0 | USB OVCUR DET | | + * | 13 | HSTX | SPI1 CSn | UART0 RX | I2C0 SCL | PWM6 B | SIO | PIO0 | PIO1 | PIO2 | CLOCK GPOUT0 | USB VBUS DET | | + * | 14 | HSTX | SPI1 SCK | UART0 CTS | I2C1 SDA | PWM7 A | SIO | PIO0 | PIO1 | PIO2 | CLOCK GPIN1 | USB VBUS EN | UART0 TX | + * | 15 | HSTX | SPI1 TX | UART0 RTS | I2C1 SCL | PWM7 B | SIO | PIO0 | PIO1 | PIO2 | CLOCK GPOUT1 | USB OVCUR DET | UART0 RX | + * | 16 | HSTX | SPI0 RX | UART0 TX | I2C0 SDA | PWM0 A | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS DET | | + * | 17 | HSTX | SPI0 CSn | UART0 RX | I2C0 SCL | PWM0 B | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS EN | | + * | 18 | HSTX | SPI0 SCK | UART0 CTS | I2C1 SDA | PWM1 A | SIO | PIO0 | PIO1 | PIO2 | | USB OVCUR DET | UART0 TX | + * | 19 | HSTX | SPI0 TX | UART0 RTS | I2C1 SCL | PWM1 B | SIO | PIO0 | PIO1 | PIO2 | XIP_CS1n | USB VBUS DET | UART0 RX | + * | 20 | | SPI0 RX | UART1 TX | I2C0 SDA | PWM2 A | SIO | PIO0 | PIO1 | PIO2 | CLOCK GPIN0 | USB VBUS EN | | + * | 21 | | SPI0 CSn | UART1 RX | I2C0 SCL | PWM2 B | SIO | PIO0 | PIO1 | PIO2 | CLOCK GPOUT0 | USB OVCUR DET | | + * | 22 | | SPI0 SCK | UART1 CTS | I2C1 SDA | PWM3 A | SIO | PIO0 | PIO1 | PIO2 | CLOCK GPIN1 | USB VBUS DET | UART1 TX | + * | 23 | | SPI0 TX | UART1 RTS | I2C1 SCL | PWM3 B | SIO | PIO0 | PIO1 | PIO2 | CLOCK GPOUT1 | USB VBUS EN | UART1 RX | + * | 24 | | SPI1 RX | UART1 TX | I2C0 SDA | PWM4 A | SIO | PIO0 | PIO1 | PIO2 | CLOCK GPOUT2 | USB OVCUR DET | | + * | 25 | | SPI1 CSn | UART1 RX | I2C0 SCL | PWM4 B | SIO | PIO0 | PIO1 | PIO2 | CLOCK GPOUT3 | USB VBUS DET | | + * | 26 | | SPI1 SCK | UART1 CTS | I2C1 SDA | PWM5 A | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS EN | UART1 TX | + * | 27 | | SPI1 TX | UART1 RTS | I2C1 SCL | PWM5 B | SIO | PIO0 | PIO1 | PIO2 | | USB OVCUR DET | UART1 RX | + * | 28 | | SPI1 RX | UART0 TX | I2C0 SDA | PWM6 A | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS DET | | + * | 29 | | SPI1 CSn | UART0 RX | I2C0 SCL | PWM6 B | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS EN | | + * + * GPIOs 30 through 47 are QFN-80 only: + * + * | GPIO | F0 | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | + * |------|----|----------|----------|-----------|---------|-----|------|------|------|----------|---------------|----------| + * | 30 | | SPI1 SCK | UART0 CTS | I2C1 SDA | PWM7 A | SIO | PIO0 | PIO1 | PIO2 | | USB OVCUR DET | UART0 TX | + * | 31 | | SPI1 TX | UART0 RTS | I2C1 SCL | PWM7 B | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS DET | UART0 RX | + * | 32 | | SPI0 RX | UART0 TX | I2C0 SDA | PWM8 A | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS EN | | + * | 33 | | SPI0 CSn | UART0 RX | I2C0 SCL | PWM8 B | SIO | PIO0 | PIO1 | PIO2 | | USB OVCUR DET | | + * | 34 | | SPI0 SCK | UART0 CTS | I2C1 SDA | PWM9 A | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS DET | UART0 TX | + * | 35 | | SPI0 TX | UART0 RTS | I2C1 SCL | PWM9 B | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS EN | UART0 RX | + * | 36 | | SPI0 RX | UART1 TX | I2C0 SDA | PWM10 A | SIO | PIO0 | PIO1 | PIO2 | | USB OVCUR DET | | + * | 37 | | SPI0 CSn | UART1 RX | I2C0 SCL | PWM10 B | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS DET | | + * | 38 | | SPI0 SCK | UART1 CTS | I2C1 SDA | PWM11 A | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS EN | UART1 TX | + * | 39 | | SPI0 TX | UART1 RTS | I2C1 SCL | PWM11 B | SIO | PIO0 | PIO1 | PIO2 | | USB OVCUR DET | UART1 RX | + * | 40 | | SPI1 RX | UART1 TX | I2C0 SDA | PWM8 A | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS DET | | + * | 41 | | SPI1 CSn | UART1 RX | I2C0 SCL | PWM8 B | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS EN | | + * | 42 | | SPI1 SCK | UART1 CTS | I2C1 SDA | PWM9 A | SIO | PIO0 | PIO1 | PIO2 | | USB OVCUR DET | UART1 TX | + * | 43 | | SPI1 TX | UART1 RTS | I2C1 SCL | PWM9 B | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS DET | UART1 RX | + * | 44 | | SPI1 RX | UART0 TX | I2C0 SDA | PWM10 A | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS EN | | + * | 45 | | SPI1 CSn | UART0 RX | I2C0 SCL | PWM10 B | SIO | PIO0 | PIO1 | PIO2 | | USB OVCUR DET | | + * | 46 | | SPI1 SCK | UART0 CTS | I2C1 SDA | PWM11 A | SIO | PIO0 | PIO1 | PIO2 | | USB VBUS DET | UART0 TX | + * | 47 | | SPI1 TX | UART0 RTS | I2C1 SCL | PWM11 B | SIO | PIO0 | PIO1 | PIO2 | XIP_CS1n | USB VBUS EN | UART0 RX | + * + * \endif + */ + +enum gpio_dir { + GPIO_OUT = 1u, ///< set GPIO to output + GPIO_IN = 0u, ///< set GPIO to input +}; + +/*! \brief GPIO Interrupt level definitions (GPIO events) + * \ingroup hardware_gpio + * \brief GPIO Interrupt levels + * + * An interrupt can be generated for every GPIO pin in 4 scenarios: + * + * * Level High: the GPIO pin is a logical 1 + * * Level Low: the GPIO pin is a logical 0 + * * Edge High: the GPIO has transitioned from a logical 0 to a logical 1 + * * Edge Low: the GPIO has transitioned from a logical 1 to a logical 0 + * + * The level interrupts are not latched. This means that if the pin is a logical 1 and the level high interrupt is active, it will + * become inactive as soon as the pin changes to a logical 0. The edge interrupts are stored in the INTR register and can be + * cleared by writing to the INTR register. + */ +enum gpio_irq_level { + GPIO_IRQ_LEVEL_LOW = 0x1u, ///< IRQ when the GPIO pin is a logical 0 + GPIO_IRQ_LEVEL_HIGH = 0x2u, ///< IRQ when the GPIO pin is a logical 1 + GPIO_IRQ_EDGE_FALL = 0x4u, ///< IRQ when the GPIO has transitioned from a logical 1 to a logical 0 + GPIO_IRQ_EDGE_RISE = 0x8u, ///< IRQ when the GPIO has transitioned from a logical 0 to a logical 1 +}; + +/*! Callback function type for GPIO events + * \ingroup hardware_gpio + * + * \param gpio Which GPIO caused this interrupt + * \param event_mask Which events caused this interrupt. See \ref gpio_irq_level for details. + * \sa gpio_set_irq_enabled_with_callback() + * \sa gpio_set_irq_callback() + */ +typedef void (*gpio_irq_callback_t)(uint gpio, uint32_t event_mask); + +enum gpio_override { + GPIO_OVERRIDE_NORMAL = 0, ///< peripheral signal selected via \ref gpio_set_function + GPIO_OVERRIDE_INVERT = 1, ///< invert peripheral signal selected via \ref gpio_set_function + GPIO_OVERRIDE_LOW = 2, ///< drive low/disable output + GPIO_OVERRIDE_HIGH = 3, ///< drive high/enable output +}; + +/*! \brief Slew rate limiting levels for GPIO outputs + * \ingroup hardware_gpio + * + * Slew rate limiting increases the minimum rise/fall time when a GPIO output + * is lightly loaded, which can help to reduce electromagnetic emissions. + * \sa gpio_set_slew_rate + */ +enum gpio_slew_rate { + GPIO_SLEW_RATE_SLOW = 0, ///< Slew rate limiting enabled + GPIO_SLEW_RATE_FAST = 1 ///< Slew rate limiting disabled +}; + +/*! \brief Drive strength levels for GPIO outputs + * \ingroup hardware_gpio + * + * Drive strength levels for GPIO outputs. + * \sa gpio_set_drive_strength + */ +enum gpio_drive_strength { + GPIO_DRIVE_STRENGTH_2MA = 0, ///< 2 mA nominal drive strength + GPIO_DRIVE_STRENGTH_4MA = 1, ///< 4 mA nominal drive strength + GPIO_DRIVE_STRENGTH_8MA = 2, ///< 8 mA nominal drive strength + GPIO_DRIVE_STRENGTH_12MA = 3 ///< 12 mA nominal drive strength +}; + +static inline void check_gpio_param(__unused uint gpio) { + invalid_params_if(HARDWARE_GPIO, gpio >= NUM_BANK0_GPIOS); +} + +// ---------------------------------------------------------------------------- +// Pad Controls + IO Muxing +// ---------------------------------------------------------------------------- +// Declarations for gpio.c + +/*! \brief Select GPIO function + * \ingroup hardware_gpio + * + * \param gpio GPIO number + * \param fn Which GPIO function select to use from list \ref gpio_function_t + */ +void gpio_set_function(uint gpio, gpio_function_t fn); + +/*! \brief Select the function for multiple GPIOs + * \ingroup hardware_gpio + * + * \sa gpio_set_function + * \param gpio_mask Mask with 1 bit per GPIO number to set the function for + * \param fn Which GPIO function select to use from list \ref gpio_function_t +*/ +void gpio_set_function_masked(uint32_t gpio_mask, gpio_function_t fn); + +/*! \brief Select the function for multiple GPIOs + * \ingroup hardware_gpio + * + * \sa gpio_set_function + * \param gpio_mask Mask with 1 bit per GPIO number to set the function for + * \param fn Which GPIO function select to use from list \ref gpio_function_t +*/ +void gpio_set_function_masked64(uint64_t gpio_mask, gpio_function_t fn); + +/*! \brief Determine current GPIO function + * \ingroup hardware_gpio + * + * \param gpio GPIO number + * \return Which GPIO function is currently selected from list \ref gpio_function_t + */ +gpio_function_t gpio_get_function(uint gpio); + +/*! \brief Select up and down pulls on specific GPIO + * \ingroup hardware_gpio + * + * \param gpio GPIO number + * \param up If true set a pull up on the GPIO + * \param down If true set a pull down on the GPIO + * + * \note On the RP2040, setting both pulls enables a "bus keep" function, + * i.e. a weak pull to whatever is current high/low state of GPIO. + */ +void gpio_set_pulls(uint gpio, bool up, bool down); + +/*! \brief Set specified GPIO to be pulled up. + * \ingroup hardware_gpio + * + * \param gpio GPIO number + */ +static inline void gpio_pull_up(uint gpio) { + gpio_set_pulls(gpio, true, false); +} + +/*! \brief Determine if the specified GPIO is pulled up. + * \ingroup hardware_gpio + * + * \param gpio GPIO number + * \return true if the GPIO is pulled up + */ +static inline bool gpio_is_pulled_up(uint gpio) { + return (pads_bank0_hw->io[gpio] & PADS_BANK0_GPIO0_PUE_BITS) != 0; +} + +/*! \brief Set specified GPIO to be pulled down. + * \ingroup hardware_gpio + * + * \param gpio GPIO number + */ +static inline void gpio_pull_down(uint gpio) { + gpio_set_pulls(gpio, false, true); +} + +/*! \brief Determine if the specified GPIO is pulled down. + * \ingroup hardware_gpio + * + * \param gpio GPIO number + * \return true if the GPIO is pulled down + */ +static inline bool gpio_is_pulled_down(uint gpio) { + return (pads_bank0_hw->io[gpio] & PADS_BANK0_GPIO0_PDE_BITS) != 0; +} + +/*! \brief Disable pulls on specified GPIO + * \ingroup hardware_gpio + * + * \param gpio GPIO number + */ +static inline void gpio_disable_pulls(uint gpio) { + gpio_set_pulls(gpio, false, false); +} + +/*! \brief Set GPIO IRQ override + * \ingroup hardware_gpio + * + * Optionally invert a GPIO IRQ signal, or drive it high or low + * + * \param gpio GPIO number + * \param value See \ref gpio_override + */ +void gpio_set_irqover(uint gpio, uint value); + +/*! \brief Set GPIO output override + * \ingroup hardware_gpio + * + * \param gpio GPIO number + * \param value See \ref gpio_override + */ +void gpio_set_outover(uint gpio, uint value); + +/*! \brief Select GPIO input override + * \ingroup hardware_gpio + * + * \param gpio GPIO number + * \param value See \ref gpio_override + */ +void gpio_set_inover(uint gpio, uint value); + +/*! \brief Select GPIO output enable override + * \ingroup hardware_gpio + * + * \param gpio GPIO number + * \param value See \ref gpio_override + */ +void gpio_set_oeover(uint gpio, uint value); + +/*! \brief Enable GPIO input + * \ingroup hardware_gpio + * + * \param gpio GPIO number + * \param enabled true to enable input on specified GPIO + */ +void gpio_set_input_enabled(uint gpio, bool enabled); + +/*! \brief Enable/disable GPIO input hysteresis (Schmitt trigger) + * \ingroup hardware_gpio + * + * Enable or disable the Schmitt trigger hysteresis on a given GPIO. This is + * enabled on all GPIOs by default. Disabling input hysteresis can lead to + * inconsistent readings when the input signal has very long rise or fall + * times, but slightly reduces the GPIO's input delay. + * + * \sa gpio_is_input_hysteresis_enabled + * \param gpio GPIO number + * \param enabled true to enable input hysteresis on specified GPIO + */ +void gpio_set_input_hysteresis_enabled(uint gpio, bool enabled); + +/*! \brief Determine whether input hysteresis is enabled on a specified GPIO + * \ingroup hardware_gpio + * + * \sa gpio_set_input_hysteresis_enabled + * \param gpio GPIO number + */ +bool gpio_is_input_hysteresis_enabled(uint gpio); + +/*! \brief Set slew rate for a specified GPIO + * \ingroup hardware_gpio + * + * \sa gpio_get_slew_rate + * \param gpio GPIO number + * \param slew GPIO output slew rate + */ +void gpio_set_slew_rate(uint gpio, enum gpio_slew_rate slew); + +/*! \brief Determine current slew rate for a specified GPIO + * \ingroup hardware_gpio + * + * \sa gpio_set_slew_rate + * \param gpio GPIO number + * \return Current slew rate of that GPIO + */ +enum gpio_slew_rate gpio_get_slew_rate(uint gpio); + +/*! \brief Set drive strength for a specified GPIO + * \ingroup hardware_gpio + * + * \sa gpio_get_drive_strength + * \param gpio GPIO number + * \param drive GPIO output drive strength + */ +void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive); + +/*! \brief Determine current drive strength for a specified GPIO + * \ingroup hardware_gpio + * + * \sa gpio_set_drive_strength + * \param gpio GPIO number + * \return Current drive strength of that GPIO + */ +enum gpio_drive_strength gpio_get_drive_strength(uint gpio); + +/*! \brief Enable or disable specific interrupt events for specified GPIO + * \ingroup hardware_gpio + * + * This function sets which GPIO events cause a GPIO interrupt on the calling core. See + * \ref gpio_set_irq_callback, \ref gpio_set_irq_enabled_with_callback and + * \ref gpio_add_raw_irq_handler to set up a GPIO interrupt handler to handle the events. + * + * \note The IO IRQs are independent per-processor. This configures the interrupt events for + * the processor that calls the function. + * + * \param gpio GPIO number + * \param event_mask Which events will cause an interrupt + * \param enabled Enable or disable flag + * + * Events is a bitmask of the following \ref gpio_irq_level values: + * + * bit | constant | interrupt + * ----|---------------------|------------------------------------ + * 0 | GPIO_IRQ_LEVEL_LOW | Continuously while level is low + * 1 | GPIO_IRQ_LEVEL_HIGH | Continuously while level is high + * 2 | GPIO_IRQ_EDGE_FALL | On each transition from high to low + * 3 | GPIO_IRQ_EDGE_RISE | On each transition from low to high + * + * which are specified in \ref gpio_irq_level + */ +void gpio_set_irq_enabled(uint gpio, uint32_t event_mask, bool enabled); + +// PICO_CONFIG: GPIO_IRQ_CALLBACK_ORDER_PRIORITY, IRQ priority order of the default IRQ callback, min=0, max=255, default=PICO_SHARED_IRQ_HANDLER_LOWEST_ORDER_PRIORITY, group=hardware_gpio +#ifndef GPIO_IRQ_CALLBACK_ORDER_PRIORITY +#define GPIO_IRQ_CALLBACK_ORDER_PRIORITY PICO_SHARED_IRQ_HANDLER_LOWEST_ORDER_PRIORITY +#endif + +// PICO_CONFIG: GPIO_RAW_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY, IRQ priority order of raw IRQ handlers if the priority is not specified, min=0, max=255, default=PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY, group=hardware_gpio +#ifndef GPIO_RAW_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY +#define GPIO_RAW_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY +#endif + +/*! \brief Set the generic callback used for GPIO IRQ events for the current core + * \ingroup hardware_gpio + * + * This function sets the callback used for all GPIO IRQs on the current core that are not explicitly + * hooked via \ref gpio_add_raw_irq_handler or other gpio_add_raw_irq_handler_ functions. + * + * This function is called with the GPIO number and event mask for each of the (not explicitly hooked) + * GPIOs that have events enabled and that are pending (see \ref gpio_get_irq_event_mask). + * + * \note The IO IRQs are independent per-processor. This function affects + * the processor that calls the function. + * + * \param callback default user function to call on GPIO irq. Note only one of these can be set per processor. + */ +void gpio_set_irq_callback(gpio_irq_callback_t callback); + +/*! \brief Convenience function which performs multiple GPIO IRQ related initializations + * \ingroup hardware_gpio + * + * This method is a slightly eclectic mix of initialization, that: + * + * \li Updates whether the specified events for the specified GPIO causes an interrupt on the calling core based + * on the enable flag. + * + * \li Sets the callback handler for the calling core to callback (or clears the handler if the callback is NULL). + * + * \li Enables GPIO IRQs on the current core if enabled is true. + * + * This method is commonly used to perform a one time setup, and following that any additional IRQs/events are enabled + * via \ref gpio_set_irq_enabled. All GPIOs/events added in this way on the same core share the same callback; for multiple + * independent handlers for different GPIOs you should use \ref gpio_add_raw_irq_handler and related functions. + * + * This method is equivalent to: + * + * \code{.c} + * gpio_set_irq_enabled(gpio, event_mask, enabled); + * gpio_set_irq_callback(callback); + * if (enabled) irq_set_enabled(IO_IRQ_BANK0, true); + * \endcode + * + * \note The IO IRQs are independent per-processor. This method affects only the processor that calls the function. + * + * \param gpio GPIO number + * \param event_mask Which events will cause an interrupt. See \ref gpio_irq_level for details. + * \param enabled Enable or disable flag + * \param callback user function to call on GPIO irq. if NULL, the callback is removed + */ +void gpio_set_irq_enabled_with_callback(uint gpio, uint32_t event_mask, bool enabled, gpio_irq_callback_t callback); + +/*! \brief Enable dormant wake up interrupt for specified GPIO and events + * \ingroup hardware_gpio + * + * This configures IRQs to restart the XOSC or ROSC when they are + * disabled in dormant mode + * + * \param gpio GPIO number + * \param event_mask Which events will cause an interrupt. See \ref gpio_irq_level for details. + * \param enabled Enable/disable flag + */ +void gpio_set_dormant_irq_enabled(uint gpio, uint32_t event_mask, bool enabled); + +/*! \brief Return the current interrupt status (pending events) for the given GPIO + * \ingroup hardware_gpio + * + * \param gpio GPIO number + * \return Bitmask of events that are currently pending for the GPIO. See \ref gpio_irq_level for details. + * \sa gpio_acknowledge_irq + */ +static inline uint32_t gpio_get_irq_event_mask(uint gpio) { + check_gpio_param(gpio); + io_bank0_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ? + &io_bank0_hw->proc1_irq_ctrl : &io_bank0_hw->proc0_irq_ctrl; + io_ro_32 *status_reg = &irq_ctrl_base->ints[gpio >> 3u]; + return (*status_reg >> (4 * (gpio & 7u))) & 0xfu; +} + +/*! \brief Acknowledge a GPIO interrupt for the specified events on the calling core + * \ingroup hardware_gpio + * + * \note This may be called with a mask of any of valid bits specified in \ref gpio_irq_level, however + * it has no effect on \a level sensitive interrupts which remain pending while the GPIO is at the specified + * level. When handling \a level sensitive interrupts, you should generally disable the interrupt (see + * \ref gpio_set_irq_enabled) and then set it up again later once the GPIO level has changed (or to catch + * the opposite level). + * + * \param gpio GPIO number + * + * \note For callbacks set with \ref gpio_set_irq_enabled_with_callback, or \ref gpio_set_irq_callback, this function is called automatically. + * \param event_mask Bitmask of events to clear. See \ref gpio_irq_level for details. + */ +void gpio_acknowledge_irq(uint gpio, uint32_t event_mask); + +/*! \brief Adds a raw GPIO IRQ handler for the specified GPIOs on the current core + * \ingroup hardware_gpio + * + * In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback), + * it is possible to add explicit GPIO IRQ handlers which are called independent of the default callback. The order + * relative to the default callback can be controlled via the order_priority parameter (the default callback has the priority + * \ref GPIO_IRQ_CALLBACK_ORDER_PRIORITY which defaults to the lowest priority with the intention of it running last). + * + * This method adds such an explicit GPIO IRQ handler, and disables the "default" callback for the specified GPIOs. + * + * \note Multiple raw handlers should not be added for the same GPIOs, and this method will assert if you attempt to. + * Internally, this function calls \ref irq_add_shared_handler, which will assert if the maximum number of shared handlers + * (configurable via PICO_MAX_IRQ_SHARED_HANDLERS) would be exceeded. + * + * A raw handler should check for whichever GPIOs and events it handles, and acknowledge them itself; it might look something like: + * + * \code{.c} + * void my_irq_handler(void) { + * if (gpio_get_irq_event_mask(my_gpio_num) & my_gpio_event_mask) { + * gpio_acknowledge_irq(my_gpio_num, my_gpio_event_mask); + * // handle the IRQ + * } + * if (gpio_get_irq_event_mask(my_gpio_num2) & my_gpio_event_mask2) { + * gpio_acknowledge_irq(my_gpio_num2, my_gpio_event_mask2); + * // handle the IRQ + * } + * } + * \endcode + * + * @param gpio_mask a bit mask of the GPIO numbers that will no longer be passed to the default callback for this core + * @param handler the handler to add to the list of GPIO IRQ handlers for this core + * @param order_priority the priority order to determine the relative position of the handler in the list of GPIO IRQ handlers for this core. + */ +void gpio_add_raw_irq_handler_with_order_priority_masked(uint32_t gpio_mask, irq_handler_t handler, uint8_t order_priority); + +/*! \brief Adds a raw GPIO IRQ handler for the specified GPIOs on the current core + * \ingroup hardware_gpio + * + * In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback), + * it is possible to add explicit GPIO IRQ handlers which are called independent of the default callback. The order + * relative to the default callback can be controlled via the order_priority parameter (the default callback has the priority + * \ref GPIO_IRQ_CALLBACK_ORDER_PRIORITY which defaults to the lowest priority with the intention of it running last). + * + * This method adds such an explicit GPIO IRQ handler, and disables the "default" callback for the specified GPIOs. + * + * \note Multiple raw handlers should not be added for the same GPIOs, and this method will assert if you attempt to. + * Internally, this function calls \ref irq_add_shared_handler, which will assert if the maximum number of shared handlers + * (configurable via PICO_MAX_IRQ_SHARED_HANDLERS) would be exceeded. + * + * A raw handler should check for whichever GPIOs and events it handles, and acknowledge them itself; it might look something like: + * + * \code{.c} + * void my_irq_handler(void) { + * if (gpio_get_irq_event_mask(my_gpio_num) & my_gpio_event_mask) { + * gpio_acknowledge_irq(my_gpio_num, my_gpio_event_mask); + * // handle the IRQ + * } + * if (gpio_get_irq_event_mask(my_gpio_num2) & my_gpio_event_mask2) { + * gpio_acknowledge_irq(my_gpio_num2, my_gpio_event_mask2); + * // handle the IRQ + * } + * } + * \endcode + * + * @param gpio_mask a bit mask of the GPIO numbers that will no longer be passed to the default callback for this core + * @param handler the handler to add to the list of GPIO IRQ handlers for this core + * @param order_priority the priority order to determine the relative position of the handler in the list of GPIO IRQ handlers for this core. + */ +void gpio_add_raw_irq_handler_with_order_priority_masked64(uint64_t gpio_mask, irq_handler_t handler, uint8_t order_priority); + +/*! \brief Adds a raw GPIO IRQ handler for a specific GPIO on the current core + * \ingroup hardware_gpio + * + * In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback), + * it is possible to add explicit GPIO IRQ handlers which are called independent of the default callback. The order + * relative to the default callback can be controlled via the order_priority parameter(the default callback has the priority + * \ref GPIO_IRQ_CALLBACK_ORDER_PRIORITY which defaults to the lowest priority with the intention of it running last). + * + * This method adds such a callback, and disables the "default" callback for the specified GPIO. + * + * \note Multiple raw handlers should not be added for the same GPIO, and this method will assert if you attempt to. + * Internally, this function calls \ref irq_add_shared_handler, which will assert if the maximum number of shared handlers + * (configurable via PICO_MAX_IRQ_SHARED_HANDLERS) would be exceeded. + * + * A raw handler should check for whichever GPIOs and events it handles, and acknowledge them itself; it might look something like: + * + * \code{.c} + * void my_irq_handler(void) { + * if (gpio_get_irq_event_mask(my_gpio_num) & my_gpio_event_mask) { + * gpio_acknowledge_irq(my_gpio_num, my_gpio_event_mask); + * // handle the IRQ + * } + * } + * \endcode + * + * @param gpio the GPIO number that will no longer be passed to the default callback for this core + * @param handler the handler to add to the list of GPIO IRQ handlers for this core + * @param order_priority the priority order to determine the relative position of the handler in the list of GPIO IRQ handlers for this core. + */ +static inline void gpio_add_raw_irq_handler_with_order_priority(uint gpio, irq_handler_t handler, uint8_t order_priority) { + check_gpio_param(gpio); +#if NUM_BANK0_GPIOS > 32 + gpio_add_raw_irq_handler_with_order_priority_masked64(1ull << gpio, handler, order_priority); +#else + gpio_add_raw_irq_handler_with_order_priority_masked(1u << gpio, handler, order_priority); +#endif +} + +/*! \brief Adds a raw GPIO IRQ handler for the specified GPIOs on the current core + * \ingroup hardware_gpio + * + * In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback), + * it is possible to add explicit GPIO IRQ handlers which are called independent of the default event callback. + * + * This method adds such a callback, and disables the "default" callback for the specified GPIOs. + * + * \note Multiple raw handlers should not be added for the same GPIOs, and this method will assert if you attempt to. + * Internally, this function calls \ref irq_add_shared_handler, which will assert if the maximum number of shared handlers + * (configurable via PICO_MAX_IRQ_SHARED_HANDLERS) would be exceeded. + * + * A raw handler should check for whichever GPIOs and events it handles, and acknowledge them itself; it might look something like: + * + * \code{.c} + * void my_irq_handler(void) { + * if (gpio_get_irq_event_mask(my_gpio_num) & my_gpio_event_mask) { + * gpio_acknowledge_irq(my_gpio_num, my_gpio_event_mask); + * // handle the IRQ + * } + * if (gpio_get_irq_event_mask(my_gpio_num2) & my_gpio_event_mask2) { + * gpio_acknowledge_irq(my_gpio_num2, my_gpio_event_mask2); + * // handle the IRQ + * } + * } + * \endcode + * + * @param gpio_mask a bit mask of the GPIO numbers that will no longer be passed to the default callback for this core + * @param handler the handler to add to the list of GPIO IRQ handlers for this core + */ +void gpio_add_raw_irq_handler_masked(uint32_t gpio_mask, irq_handler_t handler); + +/*! \brief Adds a raw GPIO IRQ handler for the specified GPIOs on the current core + * \ingroup hardware_gpio + * + * In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback), + * it is possible to add explicit GPIO IRQ handlers which are called independent of the default event callback. + * + * This method adds such a callback, and disables the "default" callback for the specified GPIOs. + * + * \note Multiple raw handlers should not be added for the same GPIOs, and this method will assert if you attempt to. + * Internally, this function calls \ref irq_add_shared_handler, which will assert if the maximum number of shared handlers + * (configurable via PICO_MAX_IRQ_SHARED_HANDLERS) would be exceeded. + * + * A raw handler should check for whichever GPIOs and events it handles, and acknowledge them itself; it might look something like: + * + * \code{.c} + * void my_irq_handler(void) { + * if (gpio_get_irq_event_mask(my_gpio_num) & my_gpio_event_mask) { + * gpio_acknowledge_irq(my_gpio_num, my_gpio_event_mask); + * // handle the IRQ + * } + * if (gpio_get_irq_event_mask(my_gpio_num2) & my_gpio_event_mask2) { + * gpio_acknowledge_irq(my_gpio_num2, my_gpio_event_mask2); + * // handle the IRQ + * } + * } + * \endcode + * + * @param gpio_mask a 64 bit mask of the GPIO numbers that will no longer be passed to the default callback for this core + * @param handler the handler to add to the list of GPIO IRQ handlers for this core + */ +void gpio_add_raw_irq_handler_masked64(uint64_t gpio_mask, irq_handler_t handler); + +/*! \brief Adds a raw GPIO IRQ handler for a specific GPIO on the current core + * \ingroup hardware_gpio + * + * In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback), + * it is possible to add explicit GPIO IRQ handlers which are called independent of the default event callback. + * + * This method adds such a callback, and disables the "default" callback for the specified GPIO. + * + * \note Multiple raw handlers should not be added for the same GPIO, and this method will assert if you attempt to. + * Internally, this function calls \ref irq_add_shared_handler, which will assert if the maximum number of shared handlers + * (configurable via PICO_MAX_IRQ_SHARED_HANDLERS) would be exceeded. + * + * A raw handler should check for whichever GPIOs and events it handles, and acknowledge them itself; it might look something like: + * + * \code{.c} + * void my_irq_handler(void) { + * if (gpio_get_irq_event_mask(my_gpio_num) & my_gpio_event_mask) { + * gpio_acknowledge_irq(my_gpio_num, my_gpio_event_mask); + * // handle the IRQ + * } + * } + * \endcode + * + * @param gpio the GPIO number that will no longer be passed to the default callback for this core + * @param handler the handler to add to the list of GPIO IRQ handlers for this core + */ +static inline void gpio_add_raw_irq_handler(uint gpio, irq_handler_t handler) { + check_gpio_param(gpio); +#if NUM_BANK0_GPIOS > 32 + gpio_add_raw_irq_handler_masked64(1ull << gpio, handler); +#else + gpio_add_raw_irq_handler_masked(1u << gpio, handler); +#endif +} + +/*! \brief Removes a raw GPIO IRQ handler for the specified GPIOs on the current core + * \ingroup hardware_gpio + * + * In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback), + * it is possible to add explicit GPIO IRQ handlers which are called independent of the default event callback. + * + * This method removes such a callback, and enables the "default" callback for the specified GPIOs. + * + * @param gpio_mask a bit mask of the GPIO numbers that will now be passed to the default callback for this core + * @param handler the handler to remove from the list of GPIO IRQ handlers for this core + */ +void gpio_remove_raw_irq_handler_masked(uint32_t gpio_mask, irq_handler_t handler); + +/*! \brief Removes a raw GPIO IRQ handler for the specified GPIOs on the current core + * \ingroup hardware_gpio + * + * In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback), + * it is possible to add explicit GPIO IRQ handlers which are called independent of the default event callback. + * + * This method removes such a callback, and enables the "default" callback for the specified GPIOs. + * + * @param gpio_mask a bit mask of the GPIO numbers that will now be passed to the default callback for this core + * @param handler the handler to remove from the list of GPIO IRQ handlers for this core + */ +void gpio_remove_raw_irq_handler_masked64(uint64_t gpio_mask, irq_handler_t handler); + +/*! \brief Removes a raw GPIO IRQ handler for the specified GPIO on the current core + * \ingroup hardware_gpio + * + * In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback), + * it is possible to add explicit GPIO IRQ handlers which are called independent of the default event callback. + * + * This method removes such a callback, and enables the "default" callback for the specified GPIO. + * + * @param gpio the GPIO number that will now be passed to the default callback for this core + * @param handler the handler to remove from the list of GPIO IRQ handlers for this core + */ +static inline void gpio_remove_raw_irq_handler(uint gpio, irq_handler_t handler) { + check_gpio_param(gpio); +#if NUM_BANK0_GPIOS > 32 + gpio_remove_raw_irq_handler_masked64(1ull << gpio, handler); +#else + gpio_remove_raw_irq_handler_masked(1u << gpio, handler); +#endif +} + +/*! \brief Initialise a GPIO for (enabled I/O and set func to GPIO_FUNC_SIO) + * \ingroup hardware_gpio + * + * Clear the output enable (i.e. set to input). + * Clear any output value. + * + * \param gpio GPIO number + */ +void gpio_init(uint gpio); + +/*! \brief Resets a GPIO back to the NULL function, i.e. disables it. + * \ingroup hardware_gpio + * + * \param gpio GPIO number + */ +void gpio_deinit(uint gpio); + +/*! \brief Initialise multiple GPIOs (enabled I/O and set func to GPIO_FUNC_SIO) + * \ingroup hardware_gpio + * + * Clear the output enable (i.e. set to input). + * Clear any output value. + * + * \param gpio_mask Mask with 1 bit per GPIO number to initialize + */ +void gpio_init_mask(uint gpio_mask); +// ---------------------------------------------------------------------------- +// Input +// ---------------------------------------------------------------------------- + +/*! \brief Get state of a single specified GPIO + * \ingroup hardware_gpio + * + * \param gpio GPIO number + * \return Current state of the GPIO. 0 for low, non-zero for high + */ +static inline bool gpio_get(uint gpio) { +#if NUM_BANK0_GPIOS <= 32 + return sio_hw->gpio_in & (1u << gpio); +#else + if (gpio < 32) { + return sio_hw->gpio_in & (1u << gpio); + } else { + return sio_hw->gpio_hi_in & (1u << (gpio - 32)); + } +#endif +} + +/*! \brief Get raw value of all GPIOs + * \ingroup hardware_gpio + * + * \return Bitmask of raw GPIO values + */ +static inline uint32_t gpio_get_all(void) { +#if PICO_USE_GPIO_COPROCESSOR + return gpioc_lo_in_get(); +#else + return sio_hw->gpio_in; +#endif +} + +/*! \brief Get raw value of all GPIOs + * \ingroup hardware_gpio + * + * \return Bitmask of raw GPIO values + */ +static inline uint64_t gpio_get_all64(void) { +#if PICO_USE_GPIO_COPROCESSOR + return gpioc_hilo_in_get(); +#elif NUM_BANK0_GPIOS <= 32 + return sio_hw->gpio_in; +#else + return sio_hw->gpio_in | (((uint64_t)sio_hw->gpio_hi_in) << 32u); +#endif +} +static inline uint64_t gpio_get_out_level_all64(void) { +#if NUM_BANK0_GPIOS <= 32 + return sio_hw->gpio_out; +#else + return sio_hw->gpio_out | (((uint64_t)sio_hw->gpio_hi_out) << 32u); +#endif +} +// ---------------------------------------------------------------------------- +// Output +// ---------------------------------------------------------------------------- + +/*! \brief Drive high every GPIO appearing in mask + * \ingroup hardware_gpio + * + * \param mask Bitmask of GPIO values to set + */ +static inline void gpio_set_mask(uint32_t mask) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_lo_out_set(mask); +#else + sio_hw->gpio_set = mask; +#endif +} + +/*! \brief Drive high every GPIO appearing in mask + * \ingroup hardware_gpio + * + * \param mask Bitmask of GPIO values to set + */ +static inline void gpio_set_mask64(uint64_t mask) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_hilo_out_set(mask); +#elif NUM_BANK0_GPIOS <= 32 + sio_hw->gpio_set = (uint32_t)mask; +#else + sio_hw->gpio_set = (uint32_t)mask; + sio_hw->gpio_hi_set = (uint32_t)(mask >> 32u); +#endif +} + +/*! \brief Drive high every GPIO appearing in mask + * \ingroup hardware_gpio + * + * \param n the base GPIO index of the mask to update. n == 0 means 0->31, n == 1 mean 32->63 etc. + * \param mask Bitmask of 32 GPIO values to set + */ +static inline void gpio_set_mask_n(uint n, uint32_t mask) { + if (!n) { + gpio_set_mask(mask); + } else if (n == 1) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_hi_out_set(mask); +#elif NUM_BANK0_GPIOS >= 32 + sio_hw->gpio_hi_set = mask; +#endif + } +} + +/*! \brief Drive low every GPIO appearing in mask + * \ingroup hardware_gpio + * + * \param mask Bitmask of GPIO values to clear + */ +static inline void gpio_clr_mask(uint32_t mask) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_lo_out_clr(mask); +#else + sio_hw->gpio_clr = mask; +#endif +} + +/*! \brief Drive low every GPIO appearing in mask +* \ingroup hardware_gpio +* +* \param mask Bitmask of GPIO values to clear +*/ +static inline void gpio_clr_mask64(uint64_t mask) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_hilo_out_clr(mask); +#elif NUM_BANK0_GPIOS <= 32 + sio_hw->gpio_clr = (uint32_t)mask; +#else + sio_hw->gpio_clr = (uint32_t)mask; + sio_hw->gpio_hi_clr = (uint32_t)(mask >> 32u); +#endif +} + + +/*! \brief Drive low every GPIO appearing in mask + * \ingroup hardware_gpio + * + * \param n the base GPIO index of the mask to update. n == 0 means 0->31, n == 1 mean 32->63 etc. + * \param mask Bitmask of 32 GPIO values to clear + */ +static inline void gpio_clr_mask_n(uint n, uint32_t mask) { + if (!n) { + gpio_clr_mask(mask); + } else if (n == 1) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_hi_out_clr(mask); +#elif NUM_BANK0_GPIOS >= 32 + sio_hw->gpio_hi_clr = mask; +#endif + } +} + +/*! \brief Toggle every GPIO appearing in mask + * \ingroup hardware_gpio + * + * \param mask Bitmask of GPIO values to toggle + */ +static inline void gpio_xor_mask(uint32_t mask) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_lo_out_xor(mask); +#else + sio_hw->gpio_togl = mask; +#endif +} + +/*! \brief Toggle every GPIO appearing in mask + * \ingroup hardware_gpio + * + * \param mask Bitmask of GPIO values to toggle + */ +static inline void gpio_xor_mask64(uint64_t mask) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_hilo_out_xor(mask); +#elif NUM_BANK0_GPIOS <= 32 + sio_hw->gpio_togl = (uint32_t)mask; +#else + sio_hw->gpio_togl = (uint32_t)mask; + sio_hw->gpio_hi_togl = (uint32_t)(mask >> 32u); +#endif +} + +/*! \brief Toggle every GPIO appearing in mask + * \ingroup hardware_gpio + * + * \param n the base GPIO index of the mask to update. n == 0 means 0->31, n == 1 mean 32->63 etc. + * \param mask Bitmask of 32 GPIO values to toggle + */ +static inline void gpio_xor_mask_n(uint n, uint32_t mask) { + if (!n) { + gpio_xor_mask(mask); + } else if (n == 1) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_hi_out_xor(mask); +#elif NUM_BANK0_GPIOS >= 32 + sio_hw->gpio_hi_togl = mask; +#endif + } +} + +/*! \brief Drive GPIOs high/low depending on parameters + * \ingroup hardware_gpio + * + * \param mask Bitmask of GPIO values to change + * \param value Value to set + * + * For each 1 bit in \p mask, drive that pin to the value given by + * corresponding bit in \p value, leaving other pins unchanged. + * Since this uses the TOGL alias, it is concurrency-safe with e.g. an IRQ + * bashing different pins from the same core. + */ +static inline void gpio_put_masked(uint32_t mask, uint32_t value) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_lo_out_xor((gpioc_lo_out_get() ^ value) & mask); +#else + sio_hw->gpio_togl = (sio_hw->gpio_out ^ value) & mask; +#endif +} + +/*! \brief Drive GPIOs high/low depending on parameters + * \ingroup hardware_gpio + * + * \param mask Bitmask of GPIO values to change + * \param value Value to set + * + * For each 1 bit in \p mask, drive that pin to the value given by + * corresponding bit in \p value, leaving other pins unchanged. + * Since this uses the TOGL alias, it is concurrency-safe with e.g. an IRQ + * bashing different pins from the same core. + */ +static inline void gpio_put_masked64(uint64_t mask, uint64_t value) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_hilo_out_xor((gpioc_hilo_out_get() ^ value) & mask); +#elif NUM_BANK0_GPIOS <= 32 + sio_hw->gpio_togl = (sio_hw->gpio_out ^ (uint32_t)value) & (uint32_t)mask; +#else + sio_hw->gpio_togl = (sio_hw->gpio_out ^ (uint32_t)value) & (uint32_t)mask; + sio_hw->gpio_hi_togl = (sio_hw->gpio_hi_out ^ (uint32_t)(value>>32u)) & (uint32_t)(mask>>32u); +#endif +} + +/*! \brief Drive GPIOs high/low depending on parameters + * \ingroup hardware_gpio + * + * \param n the base GPIO index of the mask to update. n == 0 means 0->31, n == 1 mean 32->63 etc. + * \param mask Bitmask of GPIO values to change + * \param value Value to set + * + * For each 1 bit in \p mask, drive that pin to the value given by + * corresponding bit in \p value, leaving other pins unchanged. + * Since this uses the TOGL alias, it is concurrency-safe with e.g. an IRQ + * bashing different pins from the same core. + */ +static inline void gpio_put_masked_n(uint n, uint32_t mask, uint32_t value) { + if (!n) { + gpio_put_masked(mask, value); + } else if (n == 1) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_hi_out_xor((gpioc_hi_out_get() ^ value) & mask); +#else + sio_hw->gpio_hi_togl = (sio_hw->gpio_hi_out ^ value) & mask; +#endif + } +} + +/*! \brief Drive all pins simultaneously + * \ingroup hardware_gpio + * + * \param value Bitmask of GPIO values to change + */ +static inline void gpio_put_all(uint32_t value) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_lo_out_put(value); +#else + sio_hw->gpio_out = value; +#endif +} + +/*! \brief Drive all pins simultaneously + * \ingroup hardware_gpio + * + * \param value Bitmask of GPIO values to change + */ +static inline void gpio_put_all64(uint64_t value) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_hilo_out_put(value); +#elif NUM_BANK0_GPIOS <= 32 + sio_hw->gpio_out = (uint32_t)value; +#else + sio_hw->gpio_out = (uint32_t)value; + sio_hw->gpio_hi_out = (uint32_t)(value >> 32u); +#endif +} + +/*! \brief Drive a single GPIO high/low + * \ingroup hardware_gpio + * + * \param gpio GPIO number + * \param value If false clear the GPIO, otherwise set it. + */ +static inline void gpio_put(uint gpio, bool value) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_bit_out_put(gpio, value); +#elif NUM_BANK0_GPIOS <= 32 + uint32_t mask = 1ul << gpio; + if (value) + gpio_set_mask(mask); + else + gpio_clr_mask(mask); +#else + uint32_t mask = 1ul << (gpio & 0x1fu); + if (gpio < 32) { + if (value) { + sio_hw->gpio_set = mask; + } else { + sio_hw->gpio_clr = mask; + } + } else { + if (value) { + sio_hw->gpio_hi_set = mask; + } else { + sio_hw->gpio_hi_clr = mask; + } + } +#endif +} + +/*! \brief Determine whether a GPIO is currently driven high or low + * \ingroup hardware_gpio + * + * This function returns the high/low output level most recently assigned to a + * GPIO via gpio_put() or similar. This is the value that is presented outward + * to the IO muxing, *not* the input level back from the pad (which can be + * read using gpio_get()). + * + * To avoid races, this function must not be used for read-modify-write + * sequences when driving GPIOs -- instead functions like gpio_put() should be + * used to atomically update GPIOs. This accessor is intended for debug use + * only. + * + * \param gpio GPIO number + * \return true if the GPIO output level is high, false if low. + */ +static inline bool gpio_get_out_level(uint gpio) { +#if NUM_BANK0_GPIOS <= 32 + return sio_hw->gpio_out & (1u << gpio); +#else + uint32_t bits = gpio < 32 ? sio_hw->gpio_out : sio_hw->gpio_hi_out; + return bits & (1u << (gpio & 0x1fu)); +#endif +} + +// ---------------------------------------------------------------------------- +// Direction +// ---------------------------------------------------------------------------- + +/*! \brief Set a number of GPIOs to output + * \ingroup hardware_gpio + * + * Switch all GPIOs in "mask" to output + * + * \param mask Bitmask of GPIO to set to output + */ +static inline void gpio_set_dir_out_masked(uint32_t mask) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_lo_oe_set(mask); +#else + sio_hw->gpio_oe_set = mask; +#endif +} + +/*! \brief Set a number of GPIOs to output + * \ingroup hardware_gpio + * + * Switch all GPIOs in "mask" to output + * + * \param mask Bitmask of GPIO to set to output + */ +static inline void gpio_set_dir_out_masked64(uint64_t mask) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_hilo_oe_set(mask); +#elif NUM_BANK0_GPIOS <= 32 + sio_hw->gpio_oe_set = mask; +#else + sio_hw->gpio_oe_set = (uint32_t)mask; + sio_hw->gpio_hi_oe_set = (uint32_t)(mask >> 32u); +#endif +} + +/*! \brief Set a number of GPIOs to input + * \ingroup hardware_gpio + * + * \param mask Bitmask of GPIO to set to input + */ +static inline void gpio_set_dir_in_masked(uint32_t mask) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_lo_oe_clr(mask); +#else + sio_hw->gpio_oe_clr = mask; +#endif +} + +/*! \brief Set a number of GPIOs to input + * \ingroup hardware_gpio + * + * \param mask Bitmask of GPIO to set to input + */ +static inline void gpio_set_dir_in_masked64(uint64_t mask) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_hilo_oe_clr(mask); +#elif NUM_BANK0_GPIOS <= 32 + sio_hw->gpio_oe_clr = mask; +#else + sio_hw->gpio_oe_clr = (uint32_t)mask; + sio_hw->gpio_hi_oe_clr = (uint32_t)(mask >> 32u); +#endif +} + +/*! \brief Set multiple GPIO directions + * \ingroup hardware_gpio + * + * \param mask Bitmask of GPIO to set to input, as bits 0-29 + * \param value Values to set + * + * For each 1 bit in "mask", switch that pin to the direction given by + * corresponding bit in "value", leaving other pins unchanged. + * E.g. gpio_set_dir_masked(0x3, 0x2); -> set pin 0 to input, pin 1 to output, + * simultaneously. + */ +static inline void gpio_set_dir_masked(uint32_t mask, uint32_t value) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_lo_oe_xor((gpioc_lo_oe_get() ^ value) & mask); +#else + sio_hw->gpio_oe_togl = (sio_hw->gpio_oe ^ value) & mask; +#endif +} + +/*! \brief Set multiple GPIO directions + * \ingroup hardware_gpio + * + * \param mask Bitmask of GPIO to set to input, as bits 0-29 + * \param value Values to set + * + * For each 1 bit in "mask", switch that pin to the direction given by + * corresponding bit in "value", leaving other pins unchanged. + * E.g. gpio_set_dir_masked(0x3, 0x2); -> set pin 0 to input, pin 1 to output, + * simultaneously. + */ +static inline void gpio_set_dir_masked64(uint64_t mask, uint64_t value) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_hilo_oe_xor((gpioc_hilo_oe_get() ^ value) & mask); +#elif NUM_BANK0_GPIOS <= 32 + sio_hw->gpio_oe_togl = (sio_hw->gpio_oe ^ (uint32_t)value) & (uint32_t)mask; +#else + sio_hw->gpio_oe_togl = (sio_hw->gpio_oe ^ (uint32_t)value) & (uint32_t)mask; + sio_hw->gpio_hi_oe_togl = (sio_hw->gpio_hi_oe ^ (uint32_t)(value >> 32u)) & (uint32_t)(mask >> 32u); +#endif +} + + +/*! \brief Set direction of all pins simultaneously. + * \ingroup hardware_gpio + * + * \param values individual settings for each gpio; for GPIO N, bit N is 1 for out, 0 for in + */ +static inline void gpio_set_dir_all_bits(uint32_t values) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_lo_oe_put(values); +#else + sio_hw->gpio_oe = values; +#endif +} + +/*! \brief Set direction of all pins simultaneously. + * \ingroup hardware_gpio + * + * \param values individual settings for each gpio; for GPIO N, bit N is 1 for out, 0 for in + */ +static inline void gpio_set_dir_all_bits64(uint64_t values) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_hilo_oe_put(values); +#elif NUM_BANK0_GPIOS <= 32 + sio_hw->gpio_oe = (uint32_t)values; +#else + sio_hw->gpio_oe = (uint32_t)values; + sio_hw->gpio_hi_oe = (uint32_t)(values >> 32u); +#endif +} + +/*! \brief Set a single GPIO direction + * \ingroup hardware_gpio + * + * \param gpio GPIO number + * \param out true for out, false for in + */ +static inline void gpio_set_dir(uint gpio, bool out) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_bit_oe_put(gpio, out); +#elif PICO_RP2040 || NUM_BANK0_GPIOS <= 32 + uint32_t mask = 1ul << gpio; + if (out) + gpio_set_dir_out_masked(mask); + else + gpio_set_dir_in_masked(mask); +#else + uint32_t mask = 1u << (gpio & 0x1fu); + if (gpio < 32) { + if (out) { + sio_hw->gpio_oe_set = mask; + } else { + sio_hw->gpio_oe_clr = mask; + } + } else { + if (out) { + sio_hw->gpio_hi_oe_set = mask; + } else { + sio_hw->gpio_hi_oe_clr = mask; + } + } +#endif +} + +/*! \brief Check if a specific GPIO direction is OUT + * \ingroup hardware_gpio + * + * \param gpio GPIO number + * \return true if the direction for the pin is OUT + */ +static inline bool gpio_is_dir_out(uint gpio) { +#if NUM_BANK0_GPIOS <= 32 + return sio_hw->gpio_oe & (1u << (gpio)); +#else + uint32_t bits = gpio < 32 ? sio_hw->gpio_oe : sio_hw->gpio_hi_oe; + return bits & (1u << (gpio & 0x1fu)); +#endif +} + +/*! \brief Get a specific GPIO direction + * \ingroup hardware_gpio + * + * \param gpio GPIO number + * \return 1 for out, 0 for in + */ +static inline uint gpio_get_dir(uint gpio) { + return gpio_is_dir_out(gpio); // note GPIO_OUT is 1/true and GPIO_IN is 0/false anyway +} + +#if PICO_SECURE +static inline void gpio_assign_to_ns(uint gpio, bool ns) { + check_gpio_param(gpio); + if (ns) hw_set_bits(&accessctrl_hw->gpio_nsmask[gpio/32], 1u << (gpio & 0x1fu)); + else hw_clear_bits(&accessctrl_hw->gpio_nsmask[gpio/32], 1u << (gpio & 0x1fu)); +} +#endif +extern void gpio_debug_pins_init(void); + +#ifdef __cplusplus +} +#endif + + +// PICO_CONFIG: PICO_DEBUG_PIN_BASE, First pin to use for debug output (if enabled), min=0, max=31 on RP2350B, 29 otherwise, default=19, group=hardware_gpio +#ifndef PICO_DEBUG_PIN_BASE +#define PICO_DEBUG_PIN_BASE 19u +#endif + +// PICO_CONFIG: PICO_DEBUG_PIN_COUNT, Number of pins to use for debug output (if enabled), min=1, max=32 on RP2350B, 30 otherwise, default=3, group=hardware_gpio +#ifndef PICO_DEBUG_PIN_COUNT +#define PICO_DEBUG_PIN_COUNT 3u +#endif + +#ifndef __cplusplus +// note these two macros may only be used once per and only apply per compilation unit (hence the CU_) +#define CU_REGISTER_DEBUG_PINS(...) enum __unused DEBUG_PIN_TYPE { _none = 0, __VA_ARGS__ }; static enum DEBUG_PIN_TYPE __selected_debug_pins; +#define CU_SELECT_DEBUG_PINS(x) static enum DEBUG_PIN_TYPE __selected_debug_pins = (x); +#define DEBUG_PINS_ENABLED(p) (__selected_debug_pins == (p)) +#else +#define CU_REGISTER_DEBUG_PINS(p...) \ + enum DEBUG_PIN_TYPE { _none = 0, p }; \ + template class __debug_pin_settings { \ + public: \ + static inline bool enabled() { return false; } \ + }; +#define CU_SELECT_DEBUG_PINS(x) template<> inline bool __debug_pin_settings::enabled() { return true; }; +#define DEBUG_PINS_ENABLED(p) (__debug_pin_settings

::enabled()) +#endif +#define DEBUG_PINS_SET(p, v) if (DEBUG_PINS_ENABLED(p)) gpio_set_mask((unsigned)(v)< FLASH + + /* The bootrom will enter the image at the point indicated in your + IMAGE_DEF, which is usually the reset handler of your vector table. + + The debugger will use the ELF entry point, which is the _entry_point + symbol, and in our case is *different from the bootrom's entry point.* + This is used to go back through the bootrom on debugger launches only, + to perform the same initial flash setup that would be performed on a + cold boot. + */ + + .text : { + __logical_binary_start = .; + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + KEEP (*(.reset)) + /* TODO revisit this now memset/memcpy/float in ROM */ + /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from + * FLASH ... we will include any thing excluded here in .data below by default */ + *(.init) + *libgcc.a:cmse_nonsecure_call.o + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(SORT(.preinit_array.*))) + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.eh_frame*) + . = ALIGN(4); + } > FLASH + + /* Note the boot2 section is optional, and should be discarded if there is + no reference to it *inside* the binary, as it is not called by the + bootrom. (The bootrom performs a simple best-effort XIP setup and + leaves it to the binary to do anything more sophisticated.) However + there is still a size limit of 256 bytes, to ensure the boot2 can be + stored in boot RAM. + + Really this is a "XIP setup function" -- the name boot2 is historic and + refers to its dual-purpose on RP2040, where it also handled vectoring + from the bootrom into the user image. + */ + + .boot2 : { + __boot2_start__ = .; + *(.boot2) + __boot2_end__ = .; + } > FLASH + + ASSERT(__boot2_end__ - __boot2_start__ <= 256, + "ERROR: Pico second stage bootloader must be no more than 256 bytes in size") + + .rodata : { + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) + *(.srodata*) + . = ALIGN(4); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > FLASH + __binary_info_end = .; + . = ALIGN(4); + + .ram_vector_table (NOLOAD): { + *(.ram_vector_table) + } > RAM + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + + .data : { + __data_start__ = .; + *(vtable) + + *(.time_critical*) + + /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ + *(.text*) + . = ALIGN(4); + *(.rodata*) + . = ALIGN(4); + + *(.data*) + *(.sdata*) + + . = ALIGN(4); + *(.after_data.*) + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__mutex_array_start = .); + KEEP(*(SORT(.mutex_array.*))) + KEEP(*(.mutex_array)) + PROVIDE_HIDDEN (__mutex_array_end = .); + + *(.jcr) + . = ALIGN(4); + } > RAM AT> FLASH + + .tdata : { + . = ALIGN(4); + *(.tdata .tdata.* .gnu.linkonce.td.*) + /* All data end */ + __tdata_end = .; + } > RAM AT> FLASH + PROVIDE(__data_end__ = .); + + /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ + __etext = LOADADDR(.data); + + .tbss (NOLOAD) : { + . = ALIGN(4); + __bss_start__ = .; + __tls_base = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + + __tls_end = .; + } > RAM + + .bss (NOLOAD) : { + . = ALIGN(4); + __tbss_end = .; + + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + PROVIDE(__global_pointer$ = . + 2K); + *(.sbss*) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (NOLOAD): + { + __end__ = .; + end = __end__; + KEEP(*(.heap*)) + /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however + to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ + . = ORIGIN(RAM) + LENGTH(RAM); + __HeapLimit = .; + } > RAM + + /* Start and end symbols must be word-aligned */ + .scratch_x : { + __scratch_x_start__ = .; + *(.scratch_x.*) + . = ALIGN(4); + __scratch_x_end__ = .; + } > SCRATCH_X AT > FLASH + __scratch_x_source__ = LOADADDR(.scratch_x); + + .scratch_y : { + __scratch_y_start__ = .; + *(.scratch_y.*) + . = ALIGN(4); + __scratch_y_end__ = .; + } > SCRATCH_Y AT > FLASH + __scratch_y_source__ = LOADADDR(.scratch_y); + + /* .stack*_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later + * + * stack1 section may be empty/missing if platform_launch_core1 is not used */ + + /* by default we put core 0 stack at the end of scratch Y, so that if core 1 + * stack is not used then all of SCRATCH_X is free. + */ + .stack1_dummy (NOLOAD): + { + *(.stack1*) + } > SCRATCH_X + .stack_dummy (NOLOAD): + { + KEEP(*(.stack*)) + } > SCRATCH_Y + + .flash_end : { + KEEP(*(.embedded_end_block*)) + PROVIDE(__flash_binary_end = .); + } > FLASH =0xaa + + /* stack limit is poorly named, but historically is maximum heap ptr */ + __StackLimit = ORIGIN(RAM) + LENGTH(RAM); + __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); + __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); + __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); + __StackBottom = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* picolibc and LLVM */ + PROVIDE (__heap_start = __end__); + PROVIDE (__heap_end = __HeapLimit); + PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); + PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); + PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); + + /* llvm-libc */ + PROVIDE (_end = __end__); + PROVIDE (__llvm_libc_heap_limit = __HeapLimit); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") + + ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary") + ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded block must be in first 4096 bytes of the binary") + + /* todo assert on extra code */ +} \ No newline at end of file diff --git a/Code/pico_multi_booter/picomite/mmc_stm32.c b/Code/pico_multi_booter/picomite/mmc_stm32.c index 4efd3f1..205410f 100644 --- a/Code/pico_multi_booter/picomite/mmc_stm32.c +++ b/Code/pico_multi_booter/picomite/mmc_stm32.c @@ -1504,11 +1504,7 @@ void InitReservedIO(void) { I2C_enabled=1; I2C0SDApin=Option.SYSTEM_I2C_SDA; I2C0SCLpin=Option.SYSTEM_I2C_SCL; -#ifdef PICOCALC - I2C_Timeout=500; -#else - I2C_Timeout=2; -#endif + I2C_Timeout=SystemI2CTimeout; } else { I2C1locked=1; #ifdef PICOCALC @@ -1521,11 +1517,7 @@ void InitReservedIO(void) { I2C2_enabled=1; I2C1SDApin=Option.SYSTEM_I2C_SDA; I2C1SCLpin=Option.SYSTEM_I2C_SCL; -#ifdef PICOCALC - I2C2_Timeout=500; -#else - I2C2_Timeout=2; -#endif + I2C2_Timeout=SystemI2CTimeout; } if(Option.RTC)RtcGetTime(1); #ifndef USBKEYBOARD diff --git a/Code/pico_multi_booter/sd_boot/config.h b/Code/pico_multi_booter/sd_boot/config.h index c7ddd23..bbe907b 100644 --- a/Code/pico_multi_booter/sd_boot/config.h +++ b/Code/pico_multi_booter/sd_boot/config.h @@ -36,7 +36,7 @@ // According to the applink.map ,with combined PicoMite, here is 920k // This offset is used to ensure that the bootloader does not get overwritten // when loading a new application from the SD card -#define SD_BOOT_FLASH_OFFSET (200 * 1024) +#define SD_BOOT_FLASH_OFFSET (188 * 1024) // Maximum size of the application that can be loaded // This ensures we don't overwrite the bootloader itself diff --git a/Code/pico_multi_booter/sd_boot/main.c b/Code/pico_multi_booter/sd_boot/main.c index 20f0d5c..ae0b9d7 100644 --- a/Code/pico_multi_booter/sd_boot/main.c +++ b/Code/pico_multi_booter/sd_boot/main.c @@ -285,7 +285,7 @@ void final_selection_callback(const char *path) if(path == NULL) { //load default app from flash - snprintf(status_message, sizeof(status_message), "SEL: %s", "FLASH+200k"); + snprintf(status_message, sizeof(status_message), "SEL: %s", "FLASH+188k"); text_directory_ui_set_status(status_message); sleep_ms(200); load_firmware_by_path(path);