Posthumous tronkination

This commit is contained in:
Ben Meadors 2024-10-08 05:33:38 -05:00
parent a0dd7b43d5
commit a05b009379
6 changed files with 79 additions and 69 deletions

View File

@ -55,7 +55,7 @@ typedef struct {
PacketHeader header; PacketHeader header;
/** The payload, of maximum length minus the header, aligned just to be sure */ /** The payload, of maximum length minus the header, aligned just to be sure */
uint8_t payload[MAX_LORA_PAYLOAD_LEN + 1 - sizeof(PacketHeader)] __attribute__ ((__aligned__)); uint8_t payload[MAX_LORA_PAYLOAD_LEN + 1 - sizeof(PacketHeader)] __attribute__((__aligned__));
} RadioBuffer; } RadioBuffer;
@ -105,7 +105,7 @@ class RadioInterface
/** /**
* A temporary buffer used for sending/receiving packets, sized to hold the biggest buffer we might need * A temporary buffer used for sending/receiving packets, sized to hold the biggest buffer we might need
* */ * */
RadioBuffer radioBuffer __attribute__ ((__aligned__)); RadioBuffer radioBuffer __attribute__((__aligned__));
/** /**
* Enqueue a received packet for the registered receiver * Enqueue a received packet for the registered receiver
*/ */

View File

@ -7,8 +7,8 @@
#ifndef _HARDWARE_ROSC_H_ #ifndef _HARDWARE_ROSC_H_
#define _HARDWARE_ROSC_H_ #define _HARDWARE_ROSC_H_
#include "pico.h"
#include "hardware/structs/rosc.h" #include "hardware/structs/rosc.h"
#include "pico.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -68,15 +68,18 @@ uint rosc_find_freq(uint32_t low_mhz, uint32_t high_mhz);
void rosc_set_div(uint32_t div); void rosc_set_div(uint32_t div);
inline static void rosc_clear_bad_write(void) { inline static void rosc_clear_bad_write(void)
{
hw_clear_bits(&rosc_hw->status, ROSC_STATUS_BADWRITE_BITS); hw_clear_bits(&rosc_hw->status, ROSC_STATUS_BADWRITE_BITS);
} }
inline static bool rosc_write_okay(void) { inline static bool rosc_write_okay(void)
{
return !(rosc_hw->status & ROSC_STATUS_BADWRITE_BITS); return !(rosc_hw->status & ROSC_STATUS_BADWRITE_BITS);
} }
inline static void rosc_write(io_rw_32 *addr, uint32_t value) { inline static void rosc_write(io_rw_32 *addr, uint32_t value)
{
rosc_clear_bad_write(); rosc_clear_bad_write();
assert(rosc_write_okay()); assert(rosc_write_okay());
*addr = value; *addr = value;

View File

@ -12,11 +12,13 @@
// Given a ROSC delay stage code, return the next-numerically-higher code. // Given a ROSC delay stage code, return the next-numerically-higher code.
// Top result bit is set when called on maximum ROSC code. // Top result bit is set when called on maximum ROSC code.
uint32_t next_rosc_code(uint32_t code) { uint32_t next_rosc_code(uint32_t code)
{
return ((code | 0x08888888u) + 1u) & 0xf7777777u; return ((code | 0x08888888u) + 1u) & 0xf7777777u;
} }
uint rosc_find_freq(uint32_t low_mhz, uint32_t high_mhz) { uint rosc_find_freq(uint32_t low_mhz, uint32_t high_mhz)
{
// TODO: This could be a lot better // TODO: This could be a lot better
rosc_set_div(1); rosc_set_div(1);
for (uint32_t code = 0; code <= 0x77777777u; code = next_rosc_code(code)) { for (uint32_t code = 0; code <= 0x77777777u; code = next_rosc_code(code)) {
@ -29,33 +31,40 @@ uint rosc_find_freq(uint32_t low_mhz, uint32_t high_mhz) {
return 0; return 0;
} }
void rosc_set_div(uint32_t div) { void rosc_set_div(uint32_t div)
{
assert(div <= 31 && div >= 1); assert(div <= 31 && div >= 1);
rosc_write(&rosc_hw->div, ROSC_DIV_VALUE_PASS + div); rosc_write(&rosc_hw->div, ROSC_DIV_VALUE_PASS + div);
} }
void rosc_set_freq(uint32_t code) { 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->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)); rosc_write(&rosc_hw->freqb, (ROSC_FREQA_PASSWD_VALUE_PASS << ROSC_FREQA_PASSWD_LSB) | (code >> 16u));
} }
void rosc_set_range(uint range) { void rosc_set_range(uint range)
{
// Range should use enumvals from the headers and thus have the password correct // 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); rosc_write(&rosc_hw->ctrl, (ROSC_CTRL_ENABLE_VALUE_ENABLE << ROSC_CTRL_ENABLE_LSB) | range);
} }
void rosc_disable(void) { void rosc_disable(void)
{
uint32_t tmp = rosc_hw->ctrl; uint32_t tmp = rosc_hw->ctrl;
tmp &= (~ROSC_CTRL_ENABLE_BITS); tmp &= (~ROSC_CTRL_ENABLE_BITS);
tmp |= (ROSC_CTRL_ENABLE_VALUE_DISABLE << ROSC_CTRL_ENABLE_LSB); tmp |= (ROSC_CTRL_ENABLE_VALUE_DISABLE << ROSC_CTRL_ENABLE_LSB);
rosc_write(&rosc_hw->ctrl, tmp); rosc_write(&rosc_hw->ctrl, tmp);
// Wait for stable to go away // Wait for stable to go away
while(rosc_hw->status & ROSC_STATUS_STABLE_BITS); while (rosc_hw->status & ROSC_STATUS_STABLE_BITS)
;
} }
void rosc_set_dormant(void) { void rosc_set_dormant(void)
{
// WARNING: This stops the rosc until woken up by an irq // WARNING: This stops the rosc until woken up by an irq
rosc_write(&rosc_hw->dormant, ROSC_DORMANT_VALUE_DORMANT); rosc_write(&rosc_hw->dormant, ROSC_DORMANT_VALUE_DORMANT);
// Wait for it to become stable once woken up // Wait for it to become stable once woken up
while(!(rosc_hw->status & ROSC_STATUS_STABLE_BITS)); while (!(rosc_hw->status & ROSC_STATUS_STABLE_BITS))
;
} }

View File

@ -2,9 +2,9 @@
#include "hardware/xosc.h" #include "hardware/xosc.h"
#include <hardware/clocks.h> #include <hardware/clocks.h>
#include <hardware/pll.h> #include <hardware/pll.h>
#include <pico/sleep.h>
#include <pico/stdlib.h> #include <pico/stdlib.h>
#include <pico/unique_id.h> #include <pico/unique_id.h>
#include <pico/sleep.h>
void setBluetoothEnable(bool enable) void setBluetoothEnable(bool enable)
{ {
@ -13,11 +13,13 @@ void setBluetoothEnable(bool enable)
static bool awake; static bool awake;
static void sleep_callback(void) { static void sleep_callback(void)
{
awake = true; awake = true;
} }
void epoch_to_datetime(time_t epoch, datetime_t *dt) { void epoch_to_datetime(time_t epoch, datetime_t *dt)
{
struct tm *tm_info; struct tm *tm_info;
tm_info = gmtime(&epoch); tm_info = gmtime(&epoch);
@ -39,7 +41,7 @@ void debug_date(datetime_t t)
void cpuDeepSleep(uint32_t msecs) void cpuDeepSleep(uint32_t msecs)
{ {
time_t seconds = (time_t)(msecs/1000); time_t seconds = (time_t)(msecs / 1000);
datetime_t t_init, t_alarm; datetime_t t_init, t_alarm;
awake = false; awake = false;
@ -54,7 +56,7 @@ void cpuDeepSleep(uint32_t msecs)
sleep_run_from_dormant_source(DORMANT_SOURCE_ROSC); sleep_run_from_dormant_source(DORMANT_SOURCE_ROSC);
sleep_goto_sleep_until(&t_alarm, &sleep_callback); sleep_goto_sleep_until(&t_alarm, &sleep_callback);
// Make sure we don't wake // Make sure we don't wake
while (!awake) { while (!awake) {
delay(1); delay(1);
} }

View File

@ -7,8 +7,8 @@
#ifndef _PICO_SLEEP_H_ #ifndef _PICO_SLEEP_H_
#define _PICO_SLEEP_H_ #define _PICO_SLEEP_H_
#include "pico.h"
#include "hardware/rtc.h" #include "hardware/rtc.h"
#include "pico.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -30,11 +30,7 @@ extern "C" {
* \include hello_sleep.c * \include hello_sleep.c
*/ */
typedef enum { typedef enum { DORMANT_SOURCE_NONE, DORMANT_SOURCE_XOSC, DORMANT_SOURCE_ROSC } dormant_source_t;
DORMANT_SOURCE_NONE,
DORMANT_SOURCE_XOSC,
DORMANT_SOURCE_ROSC
} dormant_source_t;
/*! \brief Set all clock sources to the the dormant clock source to prepare for sleep. /*! \brief Set all clock sources to the the dormant clock source to prepare for sleep.
* \ingroup hardware_sleep * \ingroup hardware_sleep
@ -46,14 +42,16 @@ void sleep_run_from_dormant_source(dormant_source_t dormant_source);
/*! \brief Set the dormant clock source to be the crystal oscillator /*! \brief Set the dormant clock source to be the crystal oscillator
* \ingroup hardware_sleep * \ingroup hardware_sleep
*/ */
static inline void sleep_run_from_xosc(void) { static inline void sleep_run_from_xosc(void)
{
sleep_run_from_dormant_source(DORMANT_SOURCE_XOSC); sleep_run_from_dormant_source(DORMANT_SOURCE_XOSC);
} }
/*! \brief Set the dormant clock source to be the ring oscillator /*! \brief Set the dormant clock source to be the ring oscillator
* \ingroup hardware_sleep * \ingroup hardware_sleep
*/ */
static inline void sleep_run_from_rosc(void) { static inline void sleep_run_from_rosc(void)
{
sleep_run_from_dormant_source(DORMANT_SOURCE_ROSC); sleep_run_from_dormant_source(DORMANT_SOURCE_ROSC);
} }
@ -85,7 +83,8 @@ void sleep_goto_dormant_until_pin(uint gpio_pin, bool edge, bool high);
* *
* \param gpio_pin The pin to provide the wake up * \param gpio_pin The pin to provide the wake up
*/ */
static inline void sleep_goto_dormant_until_edge_high(uint gpio_pin) { static inline void sleep_goto_dormant_until_edge_high(uint gpio_pin)
{
sleep_goto_dormant_until_pin(gpio_pin, true, true); sleep_goto_dormant_until_pin(gpio_pin, true, true);
} }
@ -96,7 +95,8 @@ static inline void sleep_goto_dormant_until_edge_high(uint gpio_pin) {
* *
* \param gpio_pin The pin to provide the wake up * \param gpio_pin The pin to provide the wake up
*/ */
static inline void sleep_goto_dormant_until_level_high(uint gpio_pin) { static inline void sleep_goto_dormant_until_level_high(uint gpio_pin)
{
sleep_goto_dormant_until_pin(gpio_pin, false, true); sleep_goto_dormant_until_pin(gpio_pin, false, true);
} }

View File

@ -6,22 +6,22 @@
#include "pico.h" #include "pico.h"
#include "pico/stdlib.h"
#include "pico/sleep.h" #include "pico/sleep.h"
#include "pico/stdlib.h"
#include "hardware/rtc.h"
#include "hardware/pll.h"
#include "hardware/clocks.h" #include "hardware/clocks.h"
#include "hardware/xosc.h" #include "hardware/pll.h"
#include "hardware/rosc.h"
#include "hardware/regs/io_bank0.h" #include "hardware/regs/io_bank0.h"
#include "hardware/rosc.h"
#include "hardware/rtc.h"
#include "hardware/xosc.h"
// For __wfi // For __wfi
#include "hardware/sync.h" #include "hardware/sync.h"
// For scb_hw so we can enable deep sleep // For scb_hw so we can enable deep sleep
#include "hardware/structs/scb.h" #include "hardware/structs/scb.h"
// when using old SDK this macro is not defined // when using old SDK this macro is not defined
#ifndef XOSC_HZ #ifndef XOSC_HZ
#define XOSC_HZ 12000000u #define XOSC_HZ 12000000u
#endif #endif
// The difference between sleep and dormant is that ALL clocks are stopped in dormant mode, // The difference between sleep and dormant is that ALL clocks are stopped in dormant mode,
// until the source (either xosc or rosc) is started again by an external event. // until the source (either xosc or rosc) is started again by an external event.
@ -29,41 +29,37 @@
// block. For example you could keep clk_rtc running. Some destinations (proc0 and proc1 wakeup logic) // block. For example you could keep clk_rtc running. Some destinations (proc0 and proc1 wakeup logic)
// can't be stopped in sleep mode otherwise there wouldn't be enough logic to wake up again. // can't be stopped in sleep mode otherwise there wouldn't be enough logic to wake up again.
// TODO: Optionally, memories can also be powered down. // TODO: Optionally, memories can also be powered down.
static dormant_source_t _dormant_source; static dormant_source_t _dormant_source;
bool dormant_source_valid(dormant_source_t dormant_source) { bool dormant_source_valid(dormant_source_t dormant_source)
{
return (dormant_source == DORMANT_SOURCE_XOSC) || (dormant_source == DORMANT_SOURCE_ROSC); return (dormant_source == DORMANT_SOURCE_XOSC) || (dormant_source == DORMANT_SOURCE_ROSC);
} }
// In order to go into dormant mode we need to be running from a stoppable clock source: // In order to go into dormant mode we need to be running from a stoppable clock source:
// either the xosc or rosc with no PLLs running. This means we disable the USB and ADC clocks // either the xosc or rosc with no PLLs running. This means we disable the USB and ADC clocks
// and all PLLs // and all PLLs
void sleep_run_from_dormant_source(dormant_source_t dormant_source) { void sleep_run_from_dormant_source(dormant_source_t dormant_source)
{
assert(dormant_source_valid(dormant_source)); assert(dormant_source_valid(dormant_source));
_dormant_source = dormant_source; _dormant_source = dormant_source;
// FIXME: Just defining average rosc freq here. // FIXME: Just defining average rosc freq here.
uint src_hz = (dormant_source == DORMANT_SOURCE_XOSC) ? XOSC_HZ : 6.5 * MHZ; uint src_hz = (dormant_source == DORMANT_SOURCE_XOSC) ? XOSC_HZ : 6.5 * MHZ;
uint clk_ref_src = (dormant_source == DORMANT_SOURCE_XOSC) ? uint clk_ref_src = (dormant_source == DORMANT_SOURCE_XOSC) ? CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC
CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC : : CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH;
CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH;
// CLK_REF = XOSC or ROSC // CLK_REF = XOSC or ROSC
clock_configure(clk_ref, clock_configure(clk_ref, clk_ref_src,
clk_ref_src,
0, // No aux mux 0, // No aux mux
src_hz, src_hz, src_hz);
src_hz);
// CLK SYS = CLK_REF // CLK SYS = CLK_REF
clock_configure(clk_sys, clock_configure(clk_sys, CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF,
CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF,
0, // Using glitchless mux 0, // Using glitchless mux
src_hz, src_hz, src_hz);
src_hz);
// CLK USB = 0MHz // CLK USB = 0MHz
clock_stop(clk_usb); clock_stop(clk_usb);
@ -72,22 +68,15 @@ void sleep_run_from_dormant_source(dormant_source_t dormant_source) {
clock_stop(clk_adc); clock_stop(clk_adc);
// CLK RTC = ideally XOSC (12MHz) / 256 = 46875Hz but could be rosc // CLK RTC = ideally XOSC (12MHz) / 256 = 46875Hz but could be rosc
uint clk_rtc_src = (dormant_source == DORMANT_SOURCE_XOSC) ? uint clk_rtc_src = (dormant_source == DORMANT_SOURCE_XOSC) ? CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC
CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC : : CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH;
CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH;
clock_configure(clk_rtc, clock_configure(clk_rtc,
0, // No GLMUX 0, // No GLMUX
clk_rtc_src, clk_rtc_src, src_hz, 46875);
src_hz,
46875);
// CLK PERI = clk_sys. Used as reference clock for Peripherals. No dividers so just select and enable // CLK PERI = clk_sys. Used as reference clock for Peripherals. No dividers so just select and enable
clock_configure(clk_peri, clock_configure(clk_peri, 0, CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS, src_hz, src_hz);
0,
CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS,
src_hz,
src_hz);
pll_deinit(pll_sys); pll_deinit(pll_sys);
pll_deinit(pll_usb); pll_deinit(pll_usb);
@ -103,11 +92,12 @@ void sleep_run_from_dormant_source(dormant_source_t dormant_source) {
// Reconfigure uart with new clocks // Reconfigure uart with new clocks
/* This dones not work with our current core */ /* This dones not work with our current core */
//setup_default_uart(); // setup_default_uart();
} }
// Go to sleep until woken up by the RTC // Go to sleep until woken up by the RTC
void sleep_goto_sleep_until(datetime_t *t, rtc_callback_t callback) { void sleep_goto_sleep_until(datetime_t *t, rtc_callback_t callback)
{
// We should have already called the sleep_run_from_dormant_source function // We should have already called the sleep_run_from_dormant_source function
assert(dormant_source_valid(_dormant_source)); assert(dormant_source_valid(_dormant_source));
@ -125,7 +115,8 @@ void sleep_goto_sleep_until(datetime_t *t, rtc_callback_t callback) {
__wfi(); __wfi();
} }
static void _go_dormant(void) { static void _go_dormant(void)
{
assert(dormant_source_valid(_dormant_source)); assert(dormant_source_valid(_dormant_source));
if (_dormant_source == DORMANT_SOURCE_XOSC) { if (_dormant_source == DORMANT_SOURCE_XOSC) {
@ -135,7 +126,8 @@ static void _go_dormant(void) {
} }
} }
void sleep_goto_dormant_until_pin(uint gpio_pin, bool edge, bool high) { void sleep_goto_dormant_until_pin(uint gpio_pin, bool edge, bool high)
{
bool low = !high; bool low = !high;
bool level = !edge; bool level = !edge;
@ -144,10 +136,14 @@ void sleep_goto_dormant_until_pin(uint gpio_pin, bool edge, bool high) {
uint32_t event = 0; uint32_t event = 0;
if (level && low) event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_LEVEL_LOW_BITS; if (level && low)
if (level && high) event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_LEVEL_HIGH_BITS; event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_LEVEL_LOW_BITS;
if (edge && high) event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_EDGE_HIGH_BITS; if (level && high)
if (edge && low) event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_EDGE_LOW_BITS; event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_LEVEL_HIGH_BITS;
if (edge && high)
event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_EDGE_HIGH_BITS;
if (edge && low)
event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_EDGE_LOW_BITS;
gpio_set_dormant_irq_enabled(gpio_pin, event, true); gpio_set_dormant_irq_enabled(gpio_pin, event, true);