Compare commits

...

3 Commits

Author SHA1 Message Date
Phil Howard
da4cbd989f LiPo: Add powman and wakeup modules.
These are useful for dealing with low power situations, though
powman's time keeping leaves a little to be desired.
2025-06-06 15:35:39 +01:00
Phil Howard
9ec3001410 Add Pimoroni Pico LiPo 2XL W. 2025-06-06 09:47:45 +01:00
Phil Howard
31419eeb80 Add Pimoroni Pico LiPo 2. 2025-06-05 16:59:16 +01:00
23 changed files with 1151 additions and 1 deletions

View File

@ -20,6 +20,8 @@ jobs:
- name: pimoroni_plasma2350
- name: pimoroni_tiny2350
- name: pimoroni_pico_plus2
- name: pimoroni_pico_lipo2
- name: pimoroni_pico_lipo2xl_w
env:
# MicroPython version will be contained in github.event.release.tag_name for releases
@ -99,4 +101,4 @@ jobs:
if: github.event_name == 'release'
uses: softprops/action-gh-release@v2
with:
files: ${{ env.CI_BUILD_ROOT }}/${{ env.CI_RELEASE_FILENAME }}-with-filesystem.uf2
files: ${{ env.CI_BUILD_ROOT }}/${{ env.CI_RELEASE_FILENAME }}-with-filesystem.uf2

View File

@ -0,0 +1,8 @@
include("$(PORT_DIR)/boards/manifest.py")
require("bundle-networking")
# Bluetooth
require("aioble")
include("../manifest_pico2.py")

View File

@ -0,0 +1,19 @@
# cmake file for Pimoroni Pico LiPo
set(PICO_BOARD "pimoroni_pico_lipo2")
set(PICO_PLATFORM "rp2350")
set(PICO_BOARD_HEADER_DIRS ${CMAKE_CURRENT_LIST_DIR})
# To change the gpio count for QFN-80
set(PICO_NUM_GPIOS 48)
# Links micropy_lib_lwip and sets MICROPY_PY_LWIP = 1
# Picked up and expanded upon in mpconfigboard.h
set(MICROPY_PY_LWIP ON)
include(enable_cyw43.cmake)
# Board specific version of the frozen manifest
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
include(${CMAKE_CURRENT_LIST_DIR}/../common.cmake)

View File

@ -0,0 +1,18 @@
// Board and hardware specific configuration
#define MICROPY_HW_BOARD_NAME "Pimoroni Pico LiPo 2"
#define MICROPY_HW_FLASH_STORAGE_BYTES (PICO_FLASH_SIZE_BYTES - 1024 * 1024 * 2)
#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "PicoLiPo2"
// Enable PPP
#define MICROPY_PY_NETWORK_PPP_LWIP (1)
#include "enable_cyw43.h"
#undef MICROPY_HW_PIN_RESERVED
#define MICROPY_HW_PIN_RESERVED(i) (false)
// PSRAM Settings
#define MICROPY_HW_ENABLE_PSRAM (1)
#define MICROPY_HW_PSRAM_CS_PIN PIMORONI_PICO_LIPO2_PSRAM_CS_PIN
#define MICROPY_GC_SPLIT_HEAP (1)

View File

@ -0,0 +1,163 @@
/*
* Copyright (c) 2024 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// -----------------------------------------------------
// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
// -----------------------------------------------------
// This header may be included by other board headers as "boards/pimoroni_pico_lipo2.h"
// pico_cmake_set PICO_PLATFORM=rp2350
// pico_cmake_set PICO_CYW43_SUPPORTED = 1
#ifndef _BOARDS_PICO2_W_H
#define _BOARDS_PICO2_W_H
// For board detection
#define PIMORONI_PICO_LIPO2_RP2350
// --- BOARD SPECIFIC ---
#define SPICE_SPI 0
#define SPICE_TX_MISO_PIN 32
#define SPICE_RX_CS_PIN 33
#define SPICE_NETLIGHT_SCK_PIN 34
#define SPICE_RESET_MOSI_PIN 35
#define SPICE_PWRKEY_BL_PIN 36
#define PIMORONI_PICO_LIPO2_USER_SW_PIN 45
#define PIMORONI_PICO_LIPO2_PSRAM_CS_PIN 47
// --- RP2350 VARIANT ---
// not PICO_RP2350A
// --- UART ---
#ifndef PICO_DEFAULT_UART
#define PICO_DEFAULT_UART 0
#endif
#ifndef PICO_DEFAULT_UART_TX_PIN
#define PICO_DEFAULT_UART_TX_PIN SPICE_TX_MISO_PIN
#endif
#ifndef PICO_DEFAULT_UART_RX_PIN
#define PICO_DEFAULT_UART_RX_PIN SPICE_RX_CS_PIN
#endif
// --- LED ---
// no PICO_DEFAULT_LED_PIN - LED is on Wireless chip
// no PICO_DEFAULT_WS2812_PIN
// --- I2C ---
#ifndef PICO_DEFAULT_I2C
#define PICO_DEFAULT_I2C 0
#endif
#ifndef PICO_DEFAULT_I2C_SDA_PIN
#define PICO_DEFAULT_I2C_SDA_PIN 4
#endif
#ifndef PICO_DEFAULT_I2C_SCL_PIN
#define PICO_DEFAULT_I2C_SCL_PIN 5
#endif
// --- SPI ---
#ifndef PICO_DEFAULT_SPI
#define PICO_DEFAULT_SPI 0
#endif
#ifndef PICO_DEFAULT_SPI_SCK_PIN
#define PICO_DEFAULT_SPI_SCK_PIN SPICE_NETLIGHT_SCK_PIN
#endif
#ifndef PICO_DEFAULT_SPI_TX_PIN
#define PICO_DEFAULT_SPI_TX_PIN SPICE_RESET_MOSI_PIN
#endif
#ifndef PICO_DEFAULT_SPI_RX_PIN
#define PICO_DEFAULT_SPI_RX_PIN SPICE_TX_MISO_PIN
#endif
#ifndef PICO_DEFAULT_SPI_CSN_PIN
#define PICO_DEFAULT_SPI_CSN_PIN SPICE_RX_CS_PIN
#endif
// --- FLASH ---
#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
#ifndef PICO_FLASH_SPI_CLKDIV
#define PICO_FLASH_SPI_CLKDIV 2
#endif
// pico_cmake_set_default PICO_FLASH_SIZE_BYTES = (4 * 1024 * 1024)
#ifndef PICO_FLASH_SIZE_BYTES
#define PICO_FLASH_SIZE_BYTES (4 * 1024 * 1024)
#endif
// Drive high to force power supply into PWM mode (lower ripple on 3V3 at light loads)
// note the SMSP mode pin is on WL_GPIO1
#ifndef CYW43_WL_GPIO_COUNT
#define CYW43_WL_GPIO_COUNT 3
#endif
#ifndef CYW43_WL_GPIO_LED_PIN
// no CYW43_WL_GPIO_LED_PIN 0
#endif
// If CYW43_WL_GPIO_VBUS_PIN is defined then a CYW43 GPIO has to be used to read VBUS.
// This can be passed to cyw43_arch_gpio_get to determine if the device is battery powered.
// PICO_VBUS_PIN and CYW43_WL_GPIO_VBUS_PIN should not both be defined.
#ifndef CYW43_WL_GPIO_VBUS_PIN
// no CYW43_WL_GPIO_VBUS_PIN 2
#endif
// If CYW43_USES_VSYS_PIN is defined then CYW43 uses the VSYS GPIO (defined by PICO_VSYS_PIN) for other purposes.
// If this is the case, to use the VSYS GPIO it's necessary to ensure CYW43 is not using it.
// This can be achieved by wrapping the use of the VSYS GPIO in cyw43_thread_enter / cyw43_thread_exit.
#ifndef CYW43_USES_VSYS_PIN
// no CYW43_USES_VSYS_PIN
#endif
// The GPIO Pin used to monitor VSYS. Typically you would use this with ADC.
// There is an example in adc/read_vsys in pico-examples.
#ifndef PICO_VSYS_PIN
// no PICO_VSYS_PIN
#endif
// pico_cmake_set_default PICO_RP2350_A2_SUPPORTED = 1
#ifndef PICO_RP2350_A2_SUPPORTED
#define PICO_RP2350_A2_SUPPORTED 1
#endif
// cyw43 SPI pins can't be changed at runtime
#ifndef CYW43_PIN_WL_DYNAMIC
#define CYW43_PIN_WL_DYNAMIC 0
#endif
// gpio pin to power up the cyw43 chip
#ifndef CYW43_DEFAULT_PIN_WL_REG_ON
#define CYW43_DEFAULT_PIN_WL_REG_ON SPICE_TX_MISO_PIN
#endif
// gpio pin for spi data out to the cyw43 chip
#ifndef CYW43_DEFAULT_PIN_WL_DATA_OUT
#define CYW43_DEFAULT_PIN_WL_DATA_OUT SPICE_RESET_MOSI_PIN
#endif
// gpio pin for spi data in from the cyw43 chip
#ifndef CYW43_DEFAULT_PIN_WL_DATA_IN
#define CYW43_DEFAULT_PIN_WL_DATA_IN SPICE_RESET_MOSI_PIN
#endif
// gpio (irq) pin for the irq line from the cyw43 chip
#ifndef CYW43_DEFAULT_PIN_WL_HOST_WAKE
#define CYW43_DEFAULT_PIN_WL_HOST_WAKE SPICE_RESET_MOSI_PIN
#endif
// gpio pin for the spi clock line to the cyw43 chip
#ifndef CYW43_DEFAULT_PIN_WL_CLOCK
#define CYW43_DEFAULT_PIN_WL_CLOCK SPICE_NETLIGHT_SCK_PIN
#endif
// gpio pin for the spi chip select to the cyw43 chip
#ifndef CYW43_DEFAULT_PIN_WL_CS
#define CYW43_DEFAULT_PIN_WL_CS SPICE_RX_CS_PIN
#endif
#endif

View File

@ -0,0 +1,57 @@
GP0,GPIO0
GP1,GPIO1
GP2,GPIO2
GP3,GPIO3
GP4,GPIO4
GP5,GPIO5
GP6,GPIO6
GP7,GPIO7
GP8,GPIO8
GP9,GPIO9
GP10,GPIO10
GP11,GPIO11
GP12,GPIO12
GP13,GPIO13
GP14,GPIO14
GP15,GPIO15
GP16,GPIO16
GP17,GPIO17
GP18,GPIO18
GP19,GPIO19
GP20,GPIO20
GP21,GPIO21
GP22,GPIO22
GP25,GPIO25
GP26,GPIO26
GP27,GPIO27
GP28,GPIO28
GP29,GPIO29
GP30,GPIO30
GP31,GPIO31
GP32,GPIO32
GP33,GPIO33
GP34,GPIO34
GP35,GPIO35
GP36,GPIO36
GP37,GPIO37
GP38,GPIO38
GP39,GPIO39
GP40,GPIO40
GP41,GPIO41
GP42,GPIO42
GP43,GPIO43
GP44,GPIO44
GP45,GPIO45
GP46,GPIO46
GP47,GPIO47
WL_GPIO0,EXT_GPIO0
WL_GPIO1,EXT_GPIO1
WL_GPIO2,EXT_GPIO2
VBAT_SENSE,GPIO24
LED,GPIO25
SPICE_TX_MISO,GPIO32
SPICE_RX_CS,GPIO33
SPICE_NETLIGHT_SCK,GPIO34
SPICE_RESET_MOSI,GPIO35
SPICE_PWRKEY_BL,GPIO36
PSRAM_CS,GPIO47
1 GP0 GPIO0
2 GP1 GPIO1
3 GP2 GPIO2
4 GP3 GPIO3
5 GP4 GPIO4
6 GP5 GPIO5
7 GP6 GPIO6
8 GP7 GPIO7
9 GP8 GPIO8
10 GP9 GPIO9
11 GP10 GPIO10
12 GP11 GPIO11
13 GP12 GPIO12
14 GP13 GPIO13
15 GP14 GPIO14
16 GP15 GPIO15
17 GP16 GPIO16
18 GP17 GPIO17
19 GP18 GPIO18
20 GP19 GPIO19
21 GP20 GPIO20
22 GP21 GPIO21
23 GP22 GPIO22
24 GP25 GPIO25
25 GP26 GPIO26
26 GP27 GPIO27
27 GP28 GPIO28
28 GP29 GPIO29
29 GP30 GPIO30
30 GP31 GPIO31
31 GP32 GPIO32
32 GP33 GPIO33
33 GP34 GPIO34
34 GP35 GPIO35
35 GP36 GPIO36
36 GP37 GPIO37
37 GP38 GPIO38
38 GP39 GPIO39
39 GP40 GPIO40
40 GP41 GPIO41
41 GP42 GPIO42
42 GP43 GPIO43
43 GP44 GPIO44
44 GP45 GPIO45
45 GP46 GPIO46
46 GP47 GPIO47
47 WL_GPIO0 EXT_GPIO0
48 WL_GPIO1 EXT_GPIO1
49 WL_GPIO2 EXT_GPIO2
50 VBAT_SENSE GPIO24
51 LED GPIO25
52 SPICE_TX_MISO GPIO32
53 SPICE_RX_CS GPIO33
54 SPICE_NETLIGHT_SCK GPIO34
55 SPICE_RESET_MOSI GPIO35
56 SPICE_PWRKEY_BL GPIO36
57 PSRAM_CS GPIO47

View File

@ -0,0 +1,10 @@
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../")
# Wakeup module for early GPIO latch
include(modules/c/wakeup/micropython)
# Powman example for low power sleep
include(modules/c/powman/micropython)
include(usermod-common)

View File

@ -0,0 +1,8 @@
include("$(PORT_DIR)/boards/manifest.py")
require("bundle-networking")
# Bluetooth
require("aioble")
include("../manifest_pico2.py")

View File

@ -0,0 +1,19 @@
# cmake file for Pimoroni Pico LiPo
set(PICO_BOARD "pimoroni_pico_lipo2xl_w")
set(PICO_PLATFORM "rp2350")
set(PICO_BOARD_HEADER_DIRS ${CMAKE_CURRENT_LIST_DIR})
# To change the gpio count for QFN-80
set(PICO_NUM_GPIOS 48)
# Links micropy_lib_lwip and sets MICROPY_PY_LWIP = 1
# Picked up and expanded upon in mpconfigboard.h
set(MICROPY_PY_LWIP ON)
include(enable_cyw43.cmake)
# Board specific version of the frozen manifest
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
include(${CMAKE_CURRENT_LIST_DIR}/../common.cmake)

View File

@ -0,0 +1,15 @@
// Board and hardware specific configuration
#define MICROPY_HW_BOARD_NAME "Pimoroni Pico LiPo 2XL W"
#define MICROPY_HW_FLASH_STORAGE_BYTES (PICO_FLASH_SIZE_BYTES - 1024 * 1024 * 2)
#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "PicoLiPo2XLW"
// Enable PPP
#define MICROPY_PY_NETWORK_PPP_LWIP (1)
#include "enable_cyw43.h"
// PSRAM Settings
#define MICROPY_HW_ENABLE_PSRAM (1)
#define MICROPY_HW_PSRAM_CS_PIN PIMORONI_PICO_LIPO2_PSRAM_CS_PIN
#define MICROPY_GC_SPLIT_HEAP (1)

View File

@ -0,0 +1,163 @@
/*
* Copyright (c) 2024 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// -----------------------------------------------------
// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
// -----------------------------------------------------
// This header may be included by other board headers as "boards/pimoroni_pico_lipo2xl_w.h"
// pico_cmake_set PICO_PLATFORM=rp2350
// pico_cmake_set PICO_CYW43_SUPPORTED = 1
#ifndef _BOARDS_PICO2_W_H
#define _BOARDS_PICO2_W_H
// For board detection
#define PIMORONI_PICO_LIPO2_RP2350
// --- BOARD SPECIFIC ---
#define SPICE_SPI 0
#define SPICE_TX_MISO_PIN 32
#define SPICE_RX_CS_PIN 33
#define SPICE_NETLIGHT_SCK_PIN 34
#define SPICE_RESET_MOSI_PIN 35
#define SPICE_PWRKEY_BL_PIN 36
#define PIMORONI_PICO_LIPO2_USER_SW_PIN 30
#define PIMORONI_PICO_LIPO2_PSRAM_CS_PIN 47
// --- RP2350 VARIANT ---
// not PICO_RP2350A
// --- UART ---
#ifndef PICO_DEFAULT_UART
#define PICO_DEFAULT_UART 0
#endif
#ifndef PICO_DEFAULT_UART_TX_PIN
#define PICO_DEFAULT_UART_TX_PIN SPICE_TX_MISO_PIN
#endif
#ifndef PICO_DEFAULT_UART_RX_PIN
#define PICO_DEFAULT_UART_RX_PIN SPICE_RX_CS_PIN
#endif
// --- LED ---
// no PICO_DEFAULT_LED_PIN - LED is on Wireless chip
// no PICO_DEFAULT_WS2812_PIN
// --- I2C ---
#ifndef PICO_DEFAULT_I2C
#define PICO_DEFAULT_I2C 0
#endif
#ifndef PICO_DEFAULT_I2C_SDA_PIN
#define PICO_DEFAULT_I2C_SDA_PIN 4
#endif
#ifndef PICO_DEFAULT_I2C_SCL_PIN
#define PICO_DEFAULT_I2C_SCL_PIN 5
#endif
// --- SPI ---
#ifndef PICO_DEFAULT_SPI
#define PICO_DEFAULT_SPI 0
#endif
#ifndef PICO_DEFAULT_SPI_SCK_PIN
#define PICO_DEFAULT_SPI_SCK_PIN SPICE_NETLIGHT_SCK_PIN
#endif
#ifndef PICO_DEFAULT_SPI_TX_PIN
#define PICO_DEFAULT_SPI_TX_PIN SPICE_RESET_MOSI_PIN
#endif
#ifndef PICO_DEFAULT_SPI_RX_PIN
#define PICO_DEFAULT_SPI_RX_PIN SPICE_TX_MISO_PIN
#endif
#ifndef PICO_DEFAULT_SPI_CSN_PIN
#define PICO_DEFAULT_SPI_CSN_PIN SPICE_RX_CS_PIN
#endif
// --- FLASH ---
#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
#ifndef PICO_FLASH_SPI_CLKDIV
#define PICO_FLASH_SPI_CLKDIV 2
#endif
// pico_cmake_set_default PICO_FLASH_SIZE_BYTES = (4 * 1024 * 1024)
#ifndef PICO_FLASH_SIZE_BYTES
#define PICO_FLASH_SIZE_BYTES (4 * 1024 * 1024)
#endif
// Drive high to force power supply into PWM mode (lower ripple on 3V3 at light loads)
// note the SMSP mode pin is on WL_GPIO1
#ifndef CYW43_WL_GPIO_COUNT
#define CYW43_WL_GPIO_COUNT 3
#endif
#ifndef CYW43_WL_GPIO_LED_PIN
#define CYW43_WL_GPIO_LED_PIN 0
#endif
// If CYW43_WL_GPIO_VBUS_PIN is defined then a CYW43 GPIO has to be used to read VBUS.
// This can be passed to cyw43_arch_gpio_get to determine if the device is battery powered.
// PICO_VBUS_PIN and CYW43_WL_GPIO_VBUS_PIN should not both be defined.
#ifndef CYW43_WL_GPIO_VBUS_PIN
#define CYW43_WL_GPIO_VBUS_PIN 2
#endif
// If CYW43_USES_VSYS_PIN is defined then CYW43 uses the VSYS GPIO (defined by PICO_VSYS_PIN) for other purposes.
// If this is the case, to use the VSYS GPIO it's necessary to ensure CYW43 is not using it.
// This can be achieved by wrapping the use of the VSYS GPIO in cyw43_thread_enter / cyw43_thread_exit.
#ifndef CYW43_USES_VSYS_PIN
// no CYW43_USES_VSYS_PIN
#endif
// The GPIO Pin used to monitor VSYS. Typically you would use this with ADC.
// There is an example in adc/read_vsys in pico-examples.
#ifndef PICO_VSYS_PIN
// no PICO_VSYS_PIN
#endif
// pico_cmake_set_default PICO_RP2350_A2_SUPPORTED = 1
#ifndef PICO_RP2350_A2_SUPPORTED
#define PICO_RP2350_A2_SUPPORTED 1
#endif
// cyw43 SPI pins can't be changed at runtime
#ifndef CYW43_PIN_WL_DYNAMIC
#define CYW43_PIN_WL_DYNAMIC 0
#endif
// gpio pin to power up the cyw43 chip
#ifndef CYW43_DEFAULT_PIN_WL_REG_ON
#define CYW43_DEFAULT_PIN_WL_REG_ON 23
#endif
// gpio pin for spi data out to the cyw43 chip
#ifndef CYW43_DEFAULT_PIN_WL_DATA_OUT
#define CYW43_DEFAULT_PIN_WL_DATA_OUT 24
#endif
// gpio pin for spi data in from the cyw43 chip
#ifndef CYW43_DEFAULT_PIN_WL_DATA_IN
#define CYW43_DEFAULT_PIN_WL_DATA_IN 24
#endif
// gpio (irq) pin for the irq line from the cyw43 chip
#ifndef CYW43_DEFAULT_PIN_WL_HOST_WAKE
#define CYW43_DEFAULT_PIN_WL_HOST_WAKE 24
#endif
// gpio pin for the spi clock line to the cyw43 chip
#ifndef CYW43_DEFAULT_PIN_WL_CLOCK
#define CYW43_DEFAULT_PIN_WL_CLOCK 29
#endif
// gpio pin for the spi chip select to the cyw43 chip
#ifndef CYW43_DEFAULT_PIN_WL_CS
#define CYW43_DEFAULT_PIN_WL_CS 25
#endif
#endif

View File

@ -0,0 +1,58 @@
GP0,GPIO0
GP1,GPIO1
GP2,GPIO2
GP3,GPIO3
GP4,GPIO4
GP5,GPIO5
GP6,GPIO6
GP7,GPIO7
GP8,GPIO8
GP9,GPIO9
GP10,GPIO10
GP11,GPIO11
GP12,GPIO12
GP13,GPIO13
GP14,GPIO14
GP15,GPIO15
GP16,GPIO16
GP17,GPIO17
GP18,GPIO18
GP19,GPIO19
GP20,GPIO20
GP21,GPIO21
GP22,GPIO22
GP25,GPIO25
GP26,GPIO26
GP27,GPIO27
GP28,GPIO28
GP29,GPIO29
GP30,GPIO30
GP31,GPIO31
GP32,GPIO32
GP33,GPIO33
GP34,GPIO34
GP35,GPIO35
GP36,GPIO36
GP37,GPIO37
GP38,GPIO38
GP39,GPIO39
GP40,GPIO40
GP41,GPIO41
GP42,GPIO42
GP43,GPIO43
GP44,GPIO44
GP45,GPIO45
GP46,GPIO46
GP47,GPIO47
WL_GPIO0,EXT_GPIO0
WL_GPIO1,EXT_GPIO1
WL_GPIO2,EXT_GPIO2
LED,EXT_GPIO0
VBUS_SENSE,EXT_GPIO2
SPICE_TX_MISO,GPIO32
SPICE_RX_CS,GPIO33
SPICE_NETLIGHT_SCK,GPIO34
SPICE_RESET_MOSI,GPIO35
SPICE_PWRKEY_BL,GPIO36
VBAT_SENSE,GPIO43
PSRAM_CS,GPIO47
1 GP0 GPIO0
2 GP1 GPIO1
3 GP2 GPIO2
4 GP3 GPIO3
5 GP4 GPIO4
6 GP5 GPIO5
7 GP6 GPIO6
8 GP7 GPIO7
9 GP8 GPIO8
10 GP9 GPIO9
11 GP10 GPIO10
12 GP11 GPIO11
13 GP12 GPIO12
14 GP13 GPIO13
15 GP14 GPIO14
16 GP15 GPIO15
17 GP16 GPIO16
18 GP17 GPIO17
19 GP18 GPIO18
20 GP19 GPIO19
21 GP20 GPIO20
22 GP21 GPIO21
23 GP22 GPIO22
24 GP25 GPIO25
25 GP26 GPIO26
26 GP27 GPIO27
27 GP28 GPIO28
28 GP29 GPIO29
29 GP30 GPIO30
30 GP31 GPIO31
31 GP32 GPIO32
32 GP33 GPIO33
33 GP34 GPIO34
34 GP35 GPIO35
35 GP36 GPIO36
36 GP37 GPIO37
37 GP38 GPIO38
38 GP39 GPIO39
39 GP40 GPIO40
40 GP41 GPIO41
41 GP42 GPIO42
42 GP43 GPIO43
43 GP44 GPIO44
44 GP45 GPIO45
45 GP46 GPIO46
46 GP47 GPIO47
47 WL_GPIO0 EXT_GPIO0
48 WL_GPIO1 EXT_GPIO1
49 WL_GPIO2 EXT_GPIO2
50 LED EXT_GPIO0
51 VBUS_SENSE EXT_GPIO2
52 SPICE_TX_MISO GPIO32
53 SPICE_RX_CS GPIO33
54 SPICE_NETLIGHT_SCK GPIO34
55 SPICE_RESET_MOSI GPIO35
56 SPICE_PWRKEY_BL GPIO36
57 VBAT_SENSE GPIO43
58 PSRAM_CS GPIO47

View File

@ -0,0 +1,10 @@
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../")
# Wakeup module for early GPIO latch
include(modules/c/wakeup/micropython)
# Powman example for low power sleep
include(modules/c/powman/micropython)
include(usermod-common)

150
modules/c/powman/bindings.c Normal file
View File

@ -0,0 +1,150 @@
#include <time.h>
#include <sys/time.h>
#include "pico/stdlib.h"
#include "pico/util/datetime.h"
#include "powman.h"
#include "mphalport.h"
#include "py/runtime.h"
#include "shared/timeutils/timeutils.h"
#define GPIO_I2C_POWER 2
#define GPIO_WAKE 3
#define GPIO_EXT_CLK 12
#define GPIO_LED_A 10
enum {
WAKE_BUTTON_A = 0x00,
WAKE_BUTTON_B,
WAKE_BUTTON_C,
WAKE_TIMER = 0xf0,
WAKE_UNKNOWN = 0xff,
};
mp_obj_t _sleep_get_wake_reason(void) {
uint8_t wake_reason = powman_get_wake_reason();
if(wake_reason & POWMAN_WAKE_ALARM) {
return MP_ROM_INT(WAKE_TIMER);
}
if(wake_reason & POWMAN_WAKE_PWRUP0) return MP_ROM_INT(WAKE_BUTTON_A);
if(wake_reason & POWMAN_WAKE_PWRUP1) return MP_ROM_INT(WAKE_BUTTON_B);
if(wake_reason & POWMAN_WAKE_PWRUP2) return MP_ROM_INT(WAKE_BUTTON_C);
return MP_ROM_INT(WAKE_UNKNOWN);
}
static MP_DEFINE_CONST_FUN_OBJ_0(_sleep_get_wake_reason_obj, _sleep_get_wake_reason);
/*! \brief Send system to sleep until the specified GPIO changes
*
* \param gpio_pin The pin to provide the wake up
* \param edge true for leading edge, false for trailing edge
* \param high true for active high, false for active low
* \param timeout wakeup after timeout milliseconds if no edge occurs
*/
mp_obj_t _sleep_goto_dormant_until_pin(size_t n_args, const mp_obj_t *args) {
enum { ARG_pin, ARG_edge, ARG_high, ARG_timeout };
uint pin = UINT16_MAX;
if(args[ARG_pin] != mp_const_none) {
pin = mp_hal_get_pin_obj(args[ARG_pin]);
}
bool edge = mp_obj_is_true(args[ARG_edge]);
bool high = mp_obj_is_true(args[ARG_high]);
uint64_t timeout_ms = 0;
if (n_args == 4) {
timeout_ms = (uint64_t)mp_obj_get_float(args[ARG_timeout]) * 1000;
}
powman_init();
if (pin != UINT16_MAX) {
powman_setup_gpio_wakeup(POWMAN_WAKE_PWRUP0_CH, pin, edge, high, 1000);
} else {
int err = 0;
err = powman_setup_gpio_wakeup(POWMAN_WAKE_PWRUP0_CH, 12, edge, high, 1000); // Tufty Button A
if (err == -1) {mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Timeout waiting for Button A"));}
err = powman_setup_gpio_wakeup(POWMAN_WAKE_PWRUP1_CH, 13, edge, high, 1000); // Tufty Button B
if (err == -1) {mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Timeout waiting for Button B"));}
err = powman_setup_gpio_wakeup(POWMAN_WAKE_PWRUP2_CH, 14, edge, high, 1000); // Tufty Button C
if (err == -1) {mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Timeout waiting for Button C"));}
}
// power off
int rc = 0;
if (timeout_ms > 0) {
absolute_time_t timeout = make_timeout_time_ms(timeout_ms);
rc = powman_off_until_time(timeout);
} else {
rc = powman_off();
}
hard_assert(rc == PICO_OK);
hard_assert(false); // should never get here!
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(_sleep_goto_dormant_until_pin_obj, 3, 4, _sleep_goto_dormant_until_pin);
/*! \brief Send system to dormant until the specified time, note for RP2040 the RTC must be driven by an external clock
*
* \param ts The time to wake up
* \param callback Function to call on wakeup.
*/
mp_obj_t _sleep_goto_dormant_until(mp_obj_t absolute_time_in) {
// Borrowed from https://github.com/micropython/micropython/blob/master/ports/rp2/machine_rtc.c#L83C1-L96
mp_obj_t *items;
mp_obj_get_array_fixed_n(absolute_time_in, 8, &items);
timeutils_struct_time_t tm = {
.tm_year = mp_obj_get_int(items[0]),
.tm_mon = mp_obj_get_int(items[1]),
.tm_mday = mp_obj_get_int(items[2]),
.tm_hour = mp_obj_get_int(items[4]),
.tm_min = mp_obj_get_int(items[5]),
.tm_sec = mp_obj_get_int(items[6]),
};
struct timespec ts = { 0, 0 };
ts.tv_sec = timeutils_seconds_since_epoch(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
int rc = powman_off_until_time(timespec_to_ms(&ts));
hard_assert(rc == PICO_OK);
hard_assert(false); // should never get here!
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_1(_sleep_goto_dormant_until_obj, _sleep_goto_dormant_until);
/*! \brief Send system to dormant until the specified time, note for RP2040 the RTC must be driven by an external clock
*
* \param ts The time to wake up
* \param callback Function to call on wakeup.
*/
mp_obj_t _sleep_goto_dormant_for(mp_obj_t time_seconds_in) {
uint64_t ms = (uint64_t)(mp_obj_get_float(time_seconds_in) * 1000);
int rc = powman_off_for_ms(ms);
hard_assert(rc == PICO_OK);
hard_assert(false); // should never get here!
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_1(_sleep_goto_dormant_for_obj, _sleep_goto_dormant_for);
static const mp_map_elem_t sleep_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_powman) },
{ MP_ROM_QSTR(MP_QSTR_goto_dormant_until_pin), MP_ROM_PTR(&_sleep_goto_dormant_until_pin_obj) },
{ MP_ROM_QSTR(MP_QSTR_goto_dormant_until), MP_ROM_PTR(&_sleep_goto_dormant_until_obj) },
{ MP_ROM_QSTR(MP_QSTR_goto_dormant_for), MP_ROM_PTR(&_sleep_goto_dormant_for_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_wake_reason), MP_ROM_PTR(&_sleep_get_wake_reason_obj) },
{ MP_ROM_QSTR(MP_QSTR_WAKE_BUTTON_A), MP_ROM_INT(WAKE_BUTTON_A) },
{ MP_ROM_QSTR(MP_QSTR_WAKE_BUTTON_B), MP_ROM_INT(WAKE_BUTTON_B) },
{ MP_ROM_QSTR(MP_QSTR_WAKE_BUTTON_C), MP_ROM_INT(WAKE_BUTTON_C) },
{ MP_ROM_QSTR(MP_QSTR_WAKE_TIMER), MP_ROM_INT(WAKE_TIMER) }, // TODO: Rename to ALARM?
{ MP_ROM_QSTR(MP_QSTR_WAKE_UNKNOWN), MP_ROM_INT(WAKE_UNKNOWN) },
};
static MP_DEFINE_CONST_DICT(mp_module_sleep_globals, sleep_globals_table);
const mp_obj_module_t sleep_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_sleep_globals,
};
MP_REGISTER_MODULE(MP_QSTR_powman, sleep_user_cmodule);

View File

@ -0,0 +1,27 @@
add_library(usermod_sleep INTERFACE)
target_sources(usermod_sleep INTERFACE
${CMAKE_CURRENT_LIST_DIR}/bindings.c
${CMAKE_CURRENT_LIST_DIR}/powman.c
${CMAKE_CURRENT_LIST_DIR}/rosc.c
)
target_include_directories(usermod_sleep INTERFACE
${CMAKE_CURRENT_LIST_DIR}
)
target_link_libraries(usermod_sleep INTERFACE hardware_powman hardware_gpio)
target_link_libraries(usermod INTERFACE usermod_sleep)
#set_source_files_properties(
# ${CMAKE_CURRENT_LIST_DIR}/sleep.c
# PROPERTIES COMPILE_FLAGS
# "-Wno-maybe-uninitialized"
#)
set_source_files_properties(
${CMAKE_CURRENT_LIST_DIR}/bindings.c
PROPERTIES COMPILE_FLAGS
"-Wno-discarded-qualifiers"
)

150
modules/c/powman/powman.c Normal file
View File

@ -0,0 +1,150 @@
#include "powman.h"
static powman_power_state off_state;
static powman_power_state on_state;
//#define DEBUG
uint8_t powman_get_wake_reason(void) {
// 0 = chip reset, for the source of the last reset see POWMAN_CHIP_RESET
// 1 = pwrup0 (GPIO interrupt 0)
// 2 = pwrup1 (GPIO interrupt 1)
// 3 = pwrup2 (GPIO interrupt 2)
// 4 = pwrup3 (GPIO interrupt 3)
// 5 = coresight_pwrup
// 6 = alarm_pwrup (timeout or alarm wakeup)
return powman_hw->last_swcore_pwrup & 0x7f;
}
void powman_init() {
uint64_t abs_time_ms = 1746057600000; // 2025/05/01 - Milliseconds since epoch
// Run everything from pll_usb pll and stop pll_sys
set_sys_clock_48mhz();
// Use the 32768 Hz clockout from the RTC to keep time accurately
//clock_configure_gpin(clk_ref, 12, 32.768f * KHZ, 32.768f * KHZ);
//clock_configure_gpin(clk_sys, 12, 32.768f * KHZ, 32.768f * KHZ);
//clock_configure_undivided(clk_peri, 0, CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS, 32.768f * KHZ);
//powman_timer_set_1khz_tick_source_lposc_with_hz(32768);
powman_timer_set_1khz_tick_source_lposc();
pll_deinit(pll_sys);
// Set all pins to input (as far as SIO is concerned)
gpio_set_dir_all_bits(0);
for (int i = 0; i < NUM_BANK0_GPIOS; ++i) {
gpio_set_function(i, GPIO_FUNC_SIO);
if (i > NUM_BANK0_GPIOS - NUM_ADC_CHANNELS) {
gpio_disable_pulls(i);
gpio_set_input_enabled(i, false);
}
}
// Unlock the VREG control interface
hw_set_bits(&powman_hw->vreg_ctrl, POWMAN_PASSWORD_BITS | POWMAN_VREG_CTRL_UNLOCK_BITS);
// Turn off USB PHY and apply pull downs on DP & DM
usb_hw->phy_direct = USB_USBPHY_DIRECT_TX_PD_BITS | USB_USBPHY_DIRECT_RX_PD_BITS | USB_USBPHY_DIRECT_DM_PULLDN_EN_BITS | USB_USBPHY_DIRECT_DP_PULLDN_EN_BITS;
usb_hw->phy_direct_override = USB_USBPHY_DIRECT_RX_DM_BITS | USB_USBPHY_DIRECT_RX_DP_BITS | USB_USBPHY_DIRECT_RX_DD_BITS |
USB_USBPHY_DIRECT_OVERRIDE_TX_DIFFMODE_OVERRIDE_EN_BITS | USB_USBPHY_DIRECT_OVERRIDE_DM_PULLUP_OVERRIDE_EN_BITS | USB_USBPHY_DIRECT_OVERRIDE_TX_FSSLEW_OVERRIDE_EN_BITS |
USB_USBPHY_DIRECT_OVERRIDE_TX_PD_OVERRIDE_EN_BITS | USB_USBPHY_DIRECT_OVERRIDE_RX_PD_OVERRIDE_EN_BITS | USB_USBPHY_DIRECT_OVERRIDE_TX_DM_OVERRIDE_EN_BITS |
USB_USBPHY_DIRECT_OVERRIDE_TX_DP_OVERRIDE_EN_BITS | USB_USBPHY_DIRECT_OVERRIDE_TX_DM_OE_OVERRIDE_EN_BITS | USB_USBPHY_DIRECT_OVERRIDE_TX_DP_OE_OVERRIDE_EN_BITS |
USB_USBPHY_DIRECT_OVERRIDE_DM_PULLDN_EN_OVERRIDE_EN_BITS | USB_USBPHY_DIRECT_OVERRIDE_DP_PULLDN_EN_OVERRIDE_EN_BITS | USB_USBPHY_DIRECT_OVERRIDE_DP_PULLUP_EN_OVERRIDE_EN_BITS |
USB_USBPHY_DIRECT_OVERRIDE_DM_PULLUP_HISEL_OVERRIDE_EN_BITS | USB_USBPHY_DIRECT_OVERRIDE_DP_PULLUP_HISEL_OVERRIDE_EN_BITS;
// start powman and set the time
powman_timer_start();
powman_timer_set_ms(abs_time_ms);
// Allow power down when debugger connected
powman_set_debug_power_request_ignored(true);
// Power states
powman_power_state P1_7 = POWMAN_POWER_STATE_NONE;
powman_power_state P0_3 = POWMAN_POWER_STATE_NONE;
P0_3 = powman_power_state_with_domain_on(P0_3, POWMAN_POWER_DOMAIN_SWITCHED_CORE);
P0_3 = powman_power_state_with_domain_on(P0_3, POWMAN_POWER_DOMAIN_XIP_CACHE);
off_state = P1_7;
on_state = P0_3;
}
// Initiate power off
int __no_inline_not_in_flash_func(powman_off)(void) {
// Set power states
bool valid_state = powman_configure_wakeup_state(off_state, on_state);
if (!valid_state) {
return PICO_ERROR_INVALID_STATE;
}
// reboot to main
powman_hw->boot[0] = 0;
powman_hw->boot[1] = 0;
powman_hw->boot[2] = 0;
powman_hw->boot[3] = 0;
// Switch to required power state
int rc = powman_set_power_state(off_state);
if (rc != PICO_OK) {
return rc;
}
// Power down
while (true) __wfi();
}
int powman_setup_gpio_wakeup(int hw_wakeup, int gpio, bool edge, bool high, uint64_t timeout_ms) {
gpio_init(gpio);
gpio_set_dir(gpio, false);
gpio_set_input_enabled(gpio, true);
// Must set pulls here, or our pin may never go into its idle state
gpio_set_pulls(gpio, !high, high);
// If the pin is currently in a triggered state, wait for idle
absolute_time_t timeout = make_timeout_time_ms(timeout_ms);
if (gpio_get(gpio) == high) {
while(gpio_get(gpio) == high) {
sleep_ms(10);
if(time_reached(timeout)) return -1;
}
}
powman_enable_gpio_wakeup(hw_wakeup, gpio, edge, high);
return 0;
}
// Power off until a gpio goes high
int powman_off_until_gpio_high(int gpio, bool edge, bool high, uint64_t timeout_ms) {
powman_init();
powman_setup_gpio_wakeup(POWMAN_WAKE_PWRUP0_CH, gpio, edge, high, 1000);
if (timeout_ms > 0) {
uint64_t ms = powman_timer_get_ms();
return powman_off_until_time(ms + timeout_ms);
} else {
return powman_off();
}
}
// Power off until an absolute time
int powman_off_until_time(uint64_t absolute_time_ms) {
powman_init();
// Start powman timer and turn off
powman_enable_alarm_wakeup_at_ms(absolute_time_ms);
return powman_off();
}
// Power off for a number of milliseconds
int powman_off_for_ms(uint64_t duration_ms) {
powman_init();
uint64_t ms = powman_timer_get_ms();
return powman_off_until_time(ms + duration_ms);
}

37
modules/c/powman/powman.h Normal file
View File

@ -0,0 +1,37 @@
#include <stdio.h>
#include <inttypes.h>
#include "pico/stdio.h"
#include "pico/sync.h"
#include "hardware/gpio.h"
#include "hardware/powman.h"
#include "hardware/clocks.h"
#include "hardware/pll.h"
#include "hardware/adc.h"
#include "hardware/structs/usb.h"
#include "hardware/structs/xosc.h"
#include "hardware/vreg.h"
#include "hardware/flash.h"
#include "hardware/structs/qmi.h"
#define POWMAN_WAKE_PWRUP0_CH 0
#define POWMAN_WAKE_PWRUP1_CH 1
#define POWMAN_WAKE_PWRUP2_CH 2
#define POWMAN_WAKE_RESET 0b00000001
#define POWMAN_WAKE_PWRUP0 0b00000010
#define POWMAN_WAKE_PWRUP1 0b00000100
#define POWMAN_WAKE_PWRUP2 0b00001000
#define POWMAN_WAKE_PWRUP3 0b00010000
#define POWMAN_WAKE_CORESI 0b00100000
#define POWMAN_WAKE_ALARM 0b01000000
int powman_off_until_gpio_high(int gpio, bool edge, bool high, uint64_t timeout_ms);
int powman_off_until_time(uint64_t absolute_time_ms);
int powman_off_for_ms(uint64_t duration_ms);
uint8_t powman_get_wake_reason(void);
void powman_init();
int powman_setup_gpio_wakeup(int hw_wakeup, int gpio, bool edge, bool high, uint64_t timeout_ms);
int powman_off(void);

71
modules/c/powman/rosc.c Normal file
View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// Vendored from: https://github.com/raspberrypi/pico-extras/blob/4ccfef6fe068bbae8106d0d1f072c7f997472040/src/rp2_common/hardware_rosc/rosc.c
#include "pico.h"
// For MHZ definitions etc
#include "hardware/clocks.h"
#include "rosc.h"
// Given a ROSC delay stage code, return the next-numerically-higher code.
// Top result bit is set when called on maximum ROSC code.
uint32_t next_rosc_code(uint32_t code) {
return ((code | 0x08888888u) + 1u) & 0xf7777777u;
}
uint rosc_find_freq(uint32_t low_mhz, uint32_t high_mhz) {
// TODO: This could be a lot better
rosc_set_div(1);
for (uint32_t code = 0; code <= 0x77777777u; code = next_rosc_code(code)) {
rosc_set_freq(code);
uint rosc_mhz = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC) / 1000;
if ((rosc_mhz >= low_mhz) && (rosc_mhz <= high_mhz)) {
return rosc_mhz;
}
}
return 0;
}
void rosc_set_div(uint32_t div) {
assert(div <= 31 && div >= 1);
rosc_write(&rosc_hw->div, ROSC_DIV_VALUE_PASS + div);
}
void rosc_set_freq(uint32_t code) {
rosc_write(&rosc_hw->freqa, (ROSC_FREQA_PASSWD_VALUE_PASS << ROSC_FREQA_PASSWD_LSB) | (code & 0xffffu));
rosc_write(&rosc_hw->freqb, (ROSC_FREQA_PASSWD_VALUE_PASS << ROSC_FREQA_PASSWD_LSB) | (code >> 16u));
}
void rosc_set_range(uint range) {
// Range should use enumvals from the headers and thus have the password correct
rosc_write(&rosc_hw->ctrl, (ROSC_CTRL_ENABLE_VALUE_ENABLE << ROSC_CTRL_ENABLE_LSB) | range);
}
void rosc_disable(void) {
uint32_t tmp = rosc_hw->ctrl;
tmp &= (~ROSC_CTRL_ENABLE_BITS);
tmp |= (ROSC_CTRL_ENABLE_VALUE_DISABLE << ROSC_CTRL_ENABLE_LSB);
rosc_write(&rosc_hw->ctrl, tmp);
// Wait for stable to go away
while(rosc_hw->status & ROSC_STATUS_STABLE_BITS);
}
void rosc_set_dormant(void) {
// WARNING: This stops the rosc until woken up by an irq
rosc_write(&rosc_hw->dormant, ROSC_DORMANT_VALUE_DORMANT);
// Wait for it to become stable once woken up
while(!(rosc_hw->status & ROSC_STATUS_STABLE_BITS));
}
void rosc_enable(void) {
//Re-enable the rosc
rosc_write(&rosc_hw->ctrl, ROSC_CTRL_ENABLE_BITS);
//Wait for it to become stable once restarted
while (!(rosc_hw->status & ROSC_STATUS_STABLE_BITS));
}

94
modules/c/powman/rosc.h Normal file
View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// Vendored from: https://github.com/raspberrypi/pico-extras/blob/4ccfef6fe068bbae8106d0d1f072c7f997472040/src/rp2_common/hardware_rosc/include/hardware/rosc.h
#ifndef _HARDWARE_ROSC_H_
#define _HARDWARE_ROSC_H_
#include "pico.h"
#include "hardware/structs/rosc.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \file rosc.h
* \defgroup hardware_rosc hardware_rosc
*
* Ring Oscillator (ROSC) API
*
* A Ring Oscillator is an on-chip oscillator that requires no external crystal. Instead, the output is generated from a series of
* inverters that are chained together to create a feedback loop. RP2040 boots from the ring oscillator initially, meaning the
* first stages of the bootrom, including booting from SPI flash, will be clocked by the ring oscillator. If your design has a
* crystal oscillator, youll likely want to switch to this as your reference clock as soon as possible, because the frequency is
* more accurate than the ring oscillator.
*/
/*! \brief Set frequency of the Ring Oscillator
* \ingroup hardware_rosc
*
* \param code The drive strengths. See the RP2040 datasheet for information on this value.
*/
void rosc_set_freq(uint32_t code);
/*! \brief Set range of the Ring Oscillator
* \ingroup hardware_rosc
*
* Frequency range. Frequencies will vary with Process, Voltage & Temperature (PVT).
* Clock output will not glitch when changing the range up one step at a time.
*
* \param range 0x01 Low, 0x02 Medium, 0x03 High, 0x04 Too High.
*/
void rosc_set_range(uint range);
/*! \brief Disable the Ring Oscillator
* \ingroup hardware_rosc
*
*/
void rosc_disable(void);
/*! \brief Put Ring Oscillator in to dormant mode.
* \ingroup hardware_rosc
*
* The ROSC supports a dormant mode,which stops oscillation until woken up up by an asynchronous interrupt.
* This can either come from the RTC, being clocked by an external clock, or a GPIO pin going high or low.
* If no IRQ is configured before going into dormant mode the ROSC will never restart.
*
* PLLs should be stopped before selecting dormant mode.
*/
void rosc_set_dormant(void);
// FIXME: Add doxygen
uint32_t next_rosc_code(uint32_t code);
uint rosc_find_freq(uint32_t low_mhz, uint32_t high_mhz);
void rosc_set_div(uint32_t div);
inline static void rosc_clear_bad_write(void) {
hw_clear_bits(&rosc_hw->status, ROSC_STATUS_BADWRITE_BITS);
}
inline static bool rosc_write_okay(void) {
return !(rosc_hw->status & ROSC_STATUS_BADWRITE_BITS);
}
inline static void rosc_write(io_rw_32 *addr, uint32_t value) {
rosc_clear_bad_write();
assert(rosc_write_okay());
*addr = value;
assert(rosc_write_okay());
};
void rosc_enable(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,18 @@
add_library(usermod_wakeup INTERFACE)
target_sources(usermod_wakeup INTERFACE
${CMAKE_CURRENT_LIST_DIR}/wakeup.c
${CMAKE_CURRENT_LIST_DIR}/wakeup.cpp
)
target_include_directories(usermod_wakeup INTERFACE
${CMAKE_CURRENT_LIST_DIR}
)
target_link_libraries(usermod INTERFACE usermod_wakeup)
set_source_files_properties(
${CMAKE_CURRENT_LIST_DIR}/wakeup.c
PROPERTIES COMPILE_FLAGS
"-Wno-discarded-qualifiers"
)

21
modules/c/wakeup/wakeup.c Normal file
View File

@ -0,0 +1,21 @@
#include "wakeup.h"
#include "hardware/gpio.h"
#include "pico/runtime_init.h"
static MP_DEFINE_CONST_FUN_OBJ_1(Wakeup_get_gpio_state_obj, Wakeup_get_gpio_state);
static MP_DEFINE_CONST_FUN_OBJ_0(Wakeup_reset_gpio_state_obj, Wakeup_reset_gpio_state);
static const mp_map_elem_t wakeup_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_wakeup) },
{ MP_ROM_QSTR(MP_QSTR_get_gpio_state), MP_ROM_PTR(&Wakeup_get_gpio_state_obj) },
{ MP_ROM_QSTR(MP_QSTR_reset_gpio_state), MP_ROM_PTR(&Wakeup_reset_gpio_state_obj) },
};
static MP_DEFINE_CONST_DICT(mp_module_wakeup_globals, wakeup_globals_table);
const mp_obj_module_t wakeup_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_wakeup_globals,
};
MP_REGISTER_MODULE(MP_QSTR_wakeup, wakeup_user_cmodule);

View File

@ -0,0 +1,27 @@
#include "pico/stdlib.h"
#include "hardware/gpio.h"
uint64_t gpio_state = 0;
static void __attribute__((constructor(101))) latch_inputs() {
gpio_set_function_masked64(0xffffffffffffffff, GPIO_FUNC_SIO);
gpio_state = gpio_get_all64();
sleep_ms(5);
gpio_state |= gpio_get_all64();
}
extern "C" {
#include "wakeup.h"
mp_obj_t Wakeup_get_gpio_state(mp_obj_t button_in) {
int button = mp_obj_get_int(button_in);
return (gpio_state & (1 << button)) ? mp_const_true : mp_const_false;
}
mp_obj_t Wakeup_reset_gpio_state() {
gpio_state = 0;
return mp_const_none;
}
}

View File

@ -0,0 +1,5 @@
#include "py/runtime.h"
#include "py/objstr.h"
extern mp_obj_t Wakeup_get_gpio_state(mp_obj_t button_in);
extern mp_obj_t Wakeup_reset_gpio_state();