add a .clang-format file (#9154)
This commit is contained in:
@@ -19,11 +19,11 @@ extern "C" {
|
||||
*
|
||||
* 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, you’ll likely want to switch to this as your reference clock as soon as possible, because the frequency is
|
||||
* more accurate than the ring oscillator.
|
||||
* 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, you’ll 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
|
||||
@@ -68,22 +68,15 @@ 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 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 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());
|
||||
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());
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -12,59 +12,50 @@
|
||||
|
||||
// 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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_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_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_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_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_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))
|
||||
;
|
||||
}
|
||||
@@ -10,148 +10,133 @@
|
||||
|
||||
static bool awake;
|
||||
|
||||
static void sleep_callback(void)
|
||||
{
|
||||
awake = true;
|
||||
static void sleep_callback(void) { awake = true; }
|
||||
|
||||
void epoch_to_datetime(time_t epoch, datetime_t *dt) {
|
||||
struct tm *tm_info;
|
||||
|
||||
tm_info = gmtime(&epoch);
|
||||
dt->year = tm_info->tm_year;
|
||||
dt->month = tm_info->tm_mon + 1;
|
||||
dt->day = tm_info->tm_mday;
|
||||
dt->dotw = tm_info->tm_wday;
|
||||
dt->hour = tm_info->tm_hour;
|
||||
dt->min = tm_info->tm_min;
|
||||
dt->sec = tm_info->tm_sec;
|
||||
}
|
||||
|
||||
void epoch_to_datetime(time_t epoch, datetime_t *dt)
|
||||
{
|
||||
struct tm *tm_info;
|
||||
|
||||
tm_info = gmtime(&epoch);
|
||||
dt->year = tm_info->tm_year;
|
||||
dt->month = tm_info->tm_mon + 1;
|
||||
dt->day = tm_info->tm_mday;
|
||||
dt->dotw = tm_info->tm_wday;
|
||||
dt->hour = tm_info->tm_hour;
|
||||
dt->min = tm_info->tm_min;
|
||||
dt->sec = tm_info->tm_sec;
|
||||
void debug_date(datetime_t t) {
|
||||
LOG_DEBUG("%d %d %d %d %d %d %d", t.year, t.month, t.day, t.hour, t.min, t.sec, t.dotw);
|
||||
uart_default_tx_wait_blocking();
|
||||
}
|
||||
|
||||
void debug_date(datetime_t t)
|
||||
{
|
||||
LOG_DEBUG("%d %d %d %d %d %d %d", t.year, t.month, t.day, t.hour, t.min, t.sec, t.dotw);
|
||||
uart_default_tx_wait_blocking();
|
||||
}
|
||||
void cpuDeepSleep(uint32_t msecs) {
|
||||
|
||||
void cpuDeepSleep(uint32_t msecs)
|
||||
{
|
||||
time_t seconds = (time_t)(msecs / 1000);
|
||||
datetime_t t_init, t_alarm;
|
||||
|
||||
time_t seconds = (time_t)(msecs / 1000);
|
||||
datetime_t t_init, t_alarm;
|
||||
awake = false;
|
||||
// Start the RTC
|
||||
rtc_init();
|
||||
epoch_to_datetime(0, &t_init);
|
||||
rtc_set_datetime(&t_init);
|
||||
epoch_to_datetime(seconds, &t_alarm);
|
||||
// debug_date(t_init);
|
||||
// debug_date(t_alarm);
|
||||
uart_default_tx_wait_blocking();
|
||||
sleep_run_from_dormant_source(DORMANT_SOURCE_ROSC);
|
||||
sleep_goto_sleep_until(&t_alarm, &sleep_callback);
|
||||
|
||||
awake = false;
|
||||
// Start the RTC
|
||||
rtc_init();
|
||||
epoch_to_datetime(0, &t_init);
|
||||
rtc_set_datetime(&t_init);
|
||||
epoch_to_datetime(seconds, &t_alarm);
|
||||
// debug_date(t_init);
|
||||
// debug_date(t_alarm);
|
||||
uart_default_tx_wait_blocking();
|
||||
sleep_run_from_dormant_source(DORMANT_SOURCE_ROSC);
|
||||
sleep_goto_sleep_until(&t_alarm, &sleep_callback);
|
||||
// Make sure we don't wake
|
||||
while (!awake) {
|
||||
delay(1);
|
||||
}
|
||||
|
||||
// Make sure we don't wake
|
||||
while (!awake) {
|
||||
delay(1);
|
||||
}
|
||||
/* For now, I don't know how to revert this state
|
||||
We just reboot in order to get back operational */
|
||||
rp2040.reboot();
|
||||
|
||||
/* For now, I don't know how to revert this state
|
||||
We just reboot in order to get back operational */
|
||||
rp2040.reboot();
|
||||
|
||||
/* Set RP2040 in dormant mode. Will not wake up. */
|
||||
// xosc_dormant();
|
||||
/* Set RP2040 in dormant mode. Will not wake up. */
|
||||
// xosc_dormant();
|
||||
}
|
||||
|
||||
#else
|
||||
void cpuDeepSleep(uint32_t msecs)
|
||||
{
|
||||
/* Set RP2040 in dormant mode. Will not wake up. */
|
||||
xosc_dormant();
|
||||
void cpuDeepSleep(uint32_t msecs) {
|
||||
/* Set RP2040 in dormant mode. Will not wake up. */
|
||||
xosc_dormant();
|
||||
}
|
||||
#endif
|
||||
|
||||
void setBluetoothEnable(bool enable)
|
||||
{
|
||||
// not needed
|
||||
void setBluetoothEnable(bool enable) {
|
||||
// not needed
|
||||
}
|
||||
|
||||
void updateBatteryLevel(uint8_t level)
|
||||
{
|
||||
// not needed
|
||||
void updateBatteryLevel(uint8_t level) {
|
||||
// not needed
|
||||
}
|
||||
|
||||
void getMacAddr(uint8_t *dmac)
|
||||
{
|
||||
pico_unique_board_id_t src;
|
||||
pico_get_unique_board_id(&src);
|
||||
dmac[5] = src.id[7];
|
||||
dmac[4] = src.id[6];
|
||||
dmac[3] = src.id[5];
|
||||
dmac[2] = src.id[4];
|
||||
dmac[1] = src.id[3];
|
||||
dmac[0] = src.id[2];
|
||||
void getMacAddr(uint8_t *dmac) {
|
||||
pico_unique_board_id_t src;
|
||||
pico_get_unique_board_id(&src);
|
||||
dmac[5] = src.id[7];
|
||||
dmac[4] = src.id[6];
|
||||
dmac[3] = src.id[5];
|
||||
dmac[2] = src.id[4];
|
||||
dmac[1] = src.id[3];
|
||||
dmac[0] = src.id[2];
|
||||
}
|
||||
|
||||
void rp2040Setup()
|
||||
{
|
||||
/* Sets a random seed to make sure we get different random numbers on each boot.
|
||||
Taken from CPU cycle counter and ROSC oscillator, so should be pretty random.
|
||||
*/
|
||||
randomSeed(rp2040.hwrand32());
|
||||
void rp2040Setup() {
|
||||
/* Sets a random seed to make sure we get different random numbers on each boot.
|
||||
Taken from CPU cycle counter and ROSC oscillator, so should be pretty random.
|
||||
*/
|
||||
randomSeed(rp2040.hwrand32());
|
||||
|
||||
#ifdef RP2040_SLOW_CLOCK
|
||||
uint f_pll_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY);
|
||||
uint f_pll_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY);
|
||||
uint f_rosc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC);
|
||||
uint f_clk_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS);
|
||||
uint f_clk_peri = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_PERI);
|
||||
uint f_clk_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_USB);
|
||||
uint f_clk_adc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC);
|
||||
uint f_clk_rtc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_RTC);
|
||||
uint f_pll_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY);
|
||||
uint f_pll_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY);
|
||||
uint f_rosc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC);
|
||||
uint f_clk_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS);
|
||||
uint f_clk_peri = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_PERI);
|
||||
uint f_clk_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_USB);
|
||||
uint f_clk_adc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC);
|
||||
uint f_clk_rtc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_RTC);
|
||||
|
||||
LOG_INFO("Clock speed:");
|
||||
LOG_INFO("pll_sys = %dkHz", f_pll_sys);
|
||||
LOG_INFO("pll_usb = %dkHz", f_pll_usb);
|
||||
LOG_INFO("rosc = %dkHz", f_rosc);
|
||||
LOG_INFO("clk_sys = %dkHz", f_clk_sys);
|
||||
LOG_INFO("clk_peri = %dkHz", f_clk_peri);
|
||||
LOG_INFO("clk_usb = %dkHz", f_clk_usb);
|
||||
LOG_INFO("clk_adc = %dkHz", f_clk_adc);
|
||||
LOG_INFO("clk_rtc = %dkHz", f_clk_rtc);
|
||||
LOG_INFO("Clock speed:");
|
||||
LOG_INFO("pll_sys = %dkHz", f_pll_sys);
|
||||
LOG_INFO("pll_usb = %dkHz", f_pll_usb);
|
||||
LOG_INFO("rosc = %dkHz", f_rosc);
|
||||
LOG_INFO("clk_sys = %dkHz", f_clk_sys);
|
||||
LOG_INFO("clk_peri = %dkHz", f_clk_peri);
|
||||
LOG_INFO("clk_usb = %dkHz", f_clk_usb);
|
||||
LOG_INFO("clk_adc = %dkHz", f_clk_adc);
|
||||
LOG_INFO("clk_rtc = %dkHz", f_clk_rtc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void enterDfuMode()
|
||||
{
|
||||
reset_usb_boot(0, 0);
|
||||
}
|
||||
void enterDfuMode() { reset_usb_boot(0, 0); }
|
||||
|
||||
/* Init in early boot state. */
|
||||
#ifdef RP2040_SLOW_CLOCK
|
||||
void initVariant()
|
||||
{
|
||||
/* Set the system frequency to 18 MHz. */
|
||||
set_sys_clock_khz(18 * KHZ, false);
|
||||
/* The previous line automatically detached clk_peri from clk_sys, and
|
||||
attached it to pll_usb. We need to attach clk_peri back to system PLL to keep SPI
|
||||
working at this low speed.
|
||||
For details see https://github.com/jgromes/RadioLib/discussions/938
|
||||
*/
|
||||
clock_configure(clk_peri,
|
||||
0, // No glitchless mux
|
||||
CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, // System PLL on AUX mux
|
||||
18 * MHZ, // Input frequency
|
||||
18 * MHZ // Output (must be same as no divider)
|
||||
);
|
||||
/* Run also ADC on lower clk_sys. */
|
||||
clock_configure(clk_adc, 0, CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, 18 * MHZ, 18 * MHZ);
|
||||
/* Run RTC from XOSC since USB clock is off */
|
||||
clock_configure(clk_rtc, 0, CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC, 12 * MHZ, 47 * KHZ);
|
||||
/* Turn off USB PLL */
|
||||
pll_deinit(pll_usb);
|
||||
void initVariant() {
|
||||
/* Set the system frequency to 18 MHz. */
|
||||
set_sys_clock_khz(18 * KHZ, false);
|
||||
/* The previous line automatically detached clk_peri from clk_sys, and
|
||||
attached it to pll_usb. We need to attach clk_peri back to system PLL to keep SPI
|
||||
working at this low speed.
|
||||
For details see https://github.com/jgromes/RadioLib/discussions/938
|
||||
*/
|
||||
clock_configure(clk_peri,
|
||||
0, // No glitchless mux
|
||||
CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, // System PLL on AUX mux
|
||||
18 * MHZ, // Input frequency
|
||||
18 * MHZ // Output (must be same as no divider)
|
||||
);
|
||||
/* Run also ADC on lower clk_sys. */
|
||||
clock_configure(clk_adc, 0, CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, 18 * MHZ, 18 * MHZ);
|
||||
/* Run RTC from XOSC since USB clock is off */
|
||||
clock_configure(clk_rtc, 0, CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC, 12 * MHZ, 47 * KHZ);
|
||||
/* Turn off USB PLL */
|
||||
pll_deinit(pll_usb);
|
||||
}
|
||||
#endif
|
||||
@@ -42,18 +42,12 @@ void sleep_run_from_dormant_source(dormant_source_t dormant_source);
|
||||
/*! \brief Set the dormant clock source to be the crystal oscillator
|
||||
* \ingroup hardware_sleep
|
||||
*/
|
||||
static inline void sleep_run_from_xosc(void)
|
||||
{
|
||||
sleep_run_from_dormant_source(DORMANT_SOURCE_XOSC);
|
||||
}
|
||||
static inline void sleep_run_from_xosc(void) { sleep_run_from_dormant_source(DORMANT_SOURCE_XOSC); }
|
||||
|
||||
/*! \brief Set the dormant clock source to be the ring oscillator
|
||||
* \ingroup hardware_sleep
|
||||
*/
|
||||
static inline void sleep_run_from_rosc(void)
|
||||
{
|
||||
sleep_run_from_dormant_source(DORMANT_SOURCE_ROSC);
|
||||
}
|
||||
static inline void sleep_run_from_rosc(void) { sleep_run_from_dormant_source(DORMANT_SOURCE_ROSC); }
|
||||
|
||||
/*! \brief Send system to sleep until the specified time
|
||||
* \ingroup hardware_sleep
|
||||
@@ -83,10 +77,7 @@ void sleep_goto_dormant_until_pin(uint gpio_pin, bool edge, bool high);
|
||||
*
|
||||
* \param gpio_pin The pin to provide the wake up
|
||||
*/
|
||||
static inline void sleep_goto_dormant_until_edge_high(uint gpio_pin)
|
||||
{
|
||||
sleep_goto_dormant_until_pin(gpio_pin, true, true);
|
||||
}
|
||||
static inline void sleep_goto_dormant_until_edge_high(uint gpio_pin) { sleep_goto_dormant_until_pin(gpio_pin, true, true); }
|
||||
|
||||
/*! \brief Send system to sleep until a high level is detected on GPIO
|
||||
* \ingroup hardware_sleep
|
||||
@@ -95,10 +86,7 @@ static inline void sleep_goto_dormant_until_edge_high(uint gpio_pin)
|
||||
*
|
||||
* \param gpio_pin The pin to provide the wake up
|
||||
*/
|
||||
static inline void sleep_goto_dormant_until_level_high(uint gpio_pin)
|
||||
{
|
||||
sleep_goto_dormant_until_pin(gpio_pin, false, true);
|
||||
}
|
||||
static inline void sleep_goto_dormant_until_level_high(uint gpio_pin) { sleep_goto_dormant_until_pin(gpio_pin, false, true); }
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -33,123 +33,118 @@
|
||||
|
||||
static 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);
|
||||
bool dormant_source_valid(dormant_source_t dormant_source) {
|
||||
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:
|
||||
// either the xosc or rosc with no PLLs running. This means we disable the USB and ADC clocks
|
||||
// and all PLLs
|
||||
void sleep_run_from_dormant_source(dormant_source_t dormant_source)
|
||||
{
|
||||
assert(dormant_source_valid(dormant_source));
|
||||
_dormant_source = dormant_source;
|
||||
void sleep_run_from_dormant_source(dormant_source_t dormant_source) {
|
||||
assert(dormant_source_valid(dormant_source));
|
||||
_dormant_source = dormant_source;
|
||||
|
||||
// FIXME: Just defining average rosc freq here.
|
||||
uint src_hz = (dormant_source == DORMANT_SOURCE_XOSC) ? XOSC_HZ : 6.5 * MHZ;
|
||||
uint clk_ref_src = (dormant_source == DORMANT_SOURCE_XOSC) ? CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC
|
||||
: CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH;
|
||||
// FIXME: Just defining average rosc freq here.
|
||||
uint src_hz = (dormant_source == DORMANT_SOURCE_XOSC) ? XOSC_HZ : 6.5 * MHZ;
|
||||
uint clk_ref_src =
|
||||
(dormant_source == DORMANT_SOURCE_XOSC) ? CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC : CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH;
|
||||
|
||||
// CLK_REF = XOSC or ROSC
|
||||
clock_configure(clk_ref, clk_ref_src,
|
||||
0, // No aux mux
|
||||
src_hz, src_hz);
|
||||
// CLK_REF = XOSC or ROSC
|
||||
clock_configure(clk_ref, clk_ref_src,
|
||||
0, // No aux mux
|
||||
src_hz, src_hz);
|
||||
|
||||
// CLK SYS = CLK_REF
|
||||
clock_configure(clk_sys, CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF,
|
||||
0, // Using glitchless mux
|
||||
src_hz, src_hz);
|
||||
// CLK SYS = CLK_REF
|
||||
clock_configure(clk_sys, CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF,
|
||||
0, // Using glitchless mux
|
||||
src_hz, src_hz);
|
||||
|
||||
// CLK USB = 0MHz
|
||||
clock_stop(clk_usb);
|
||||
// CLK USB = 0MHz
|
||||
clock_stop(clk_usb);
|
||||
|
||||
// CLK ADC = 0MHz
|
||||
clock_stop(clk_adc);
|
||||
// CLK ADC = 0MHz
|
||||
clock_stop(clk_adc);
|
||||
|
||||
// CLK RTC = ideally XOSC (12MHz) / 256 = 46875Hz but could be rosc
|
||||
uint clk_rtc_src = (dormant_source == DORMANT_SOURCE_XOSC) ? CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC
|
||||
: CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH;
|
||||
// CLK RTC = ideally XOSC (12MHz) / 256 = 46875Hz but could be rosc
|
||||
uint clk_rtc_src =
|
||||
(dormant_source == DORMANT_SOURCE_XOSC) ? CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC : CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH;
|
||||
|
||||
clock_configure(clk_rtc,
|
||||
0, // No GLMUX
|
||||
clk_rtc_src, src_hz, 46875);
|
||||
clock_configure(clk_rtc,
|
||||
0, // No GLMUX
|
||||
clk_rtc_src, src_hz, 46875);
|
||||
|
||||
// CLK PERI = clk_sys. Used as reference clock for Peripherals. No dividers so just select and enable
|
||||
clock_configure(clk_peri, 0, CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS, src_hz, src_hz);
|
||||
// CLK PERI = clk_sys. Used as reference clock for Peripherals. No dividers so just select and enable
|
||||
clock_configure(clk_peri, 0, CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS, src_hz, src_hz);
|
||||
|
||||
pll_deinit(pll_sys);
|
||||
pll_deinit(pll_usb);
|
||||
pll_deinit(pll_sys);
|
||||
pll_deinit(pll_usb);
|
||||
|
||||
// Assuming both xosc and rosc are running at the moment
|
||||
if (dormant_source == DORMANT_SOURCE_XOSC) {
|
||||
// Can disable rosc
|
||||
rosc_disable();
|
||||
} else {
|
||||
// Can disable xosc
|
||||
xosc_disable();
|
||||
}
|
||||
// Assuming both xosc and rosc are running at the moment
|
||||
if (dormant_source == DORMANT_SOURCE_XOSC) {
|
||||
// Can disable rosc
|
||||
rosc_disable();
|
||||
} else {
|
||||
// Can disable xosc
|
||||
xosc_disable();
|
||||
}
|
||||
|
||||
// Reconfigure uart with new clocks
|
||||
/* This dones not work with our current core */
|
||||
// setup_default_uart();
|
||||
// Reconfigure uart with new clocks
|
||||
/* This dones not work with our current core */
|
||||
// setup_default_uart();
|
||||
}
|
||||
|
||||
// Go to sleep until woken up by the RTC
|
||||
void sleep_goto_sleep_until(datetime_t *t, rtc_callback_t callback)
|
||||
{
|
||||
// We should have already called the sleep_run_from_dormant_source function
|
||||
assert(dormant_source_valid(_dormant_source));
|
||||
void sleep_goto_sleep_until(datetime_t *t, rtc_callback_t callback) {
|
||||
// We should have already called the sleep_run_from_dormant_source function
|
||||
assert(dormant_source_valid(_dormant_source));
|
||||
|
||||
// Turn off all clocks when in sleep mode except for RTC
|
||||
clocks_hw->sleep_en0 = CLOCKS_SLEEP_EN0_CLK_RTC_RTC_BITS;
|
||||
clocks_hw->sleep_en1 = 0x0;
|
||||
// Turn off all clocks when in sleep mode except for RTC
|
||||
clocks_hw->sleep_en0 = CLOCKS_SLEEP_EN0_CLK_RTC_RTC_BITS;
|
||||
clocks_hw->sleep_en1 = 0x0;
|
||||
|
||||
rtc_set_alarm(t, callback);
|
||||
rtc_set_alarm(t, callback);
|
||||
|
||||
uint save = scb_hw->scr;
|
||||
// Enable deep sleep at the proc
|
||||
scb_hw->scr = save | M0PLUS_SCR_SLEEPDEEP_BITS;
|
||||
uint save = scb_hw->scr;
|
||||
// Enable deep sleep at the proc
|
||||
scb_hw->scr = save | M0PLUS_SCR_SLEEPDEEP_BITS;
|
||||
|
||||
// Go to sleep
|
||||
__wfi();
|
||||
// Go to sleep
|
||||
__wfi();
|
||||
}
|
||||
|
||||
static void _go_dormant(void)
|
||||
{
|
||||
assert(dormant_source_valid(_dormant_source));
|
||||
static void _go_dormant(void) {
|
||||
assert(dormant_source_valid(_dormant_source));
|
||||
|
||||
if (_dormant_source == DORMANT_SOURCE_XOSC) {
|
||||
xosc_dormant();
|
||||
} else {
|
||||
rosc_set_dormant();
|
||||
}
|
||||
if (_dormant_source == DORMANT_SOURCE_XOSC) {
|
||||
xosc_dormant();
|
||||
} else {
|
||||
rosc_set_dormant();
|
||||
}
|
||||
}
|
||||
|
||||
void sleep_goto_dormant_until_pin(uint gpio_pin, bool edge, bool high)
|
||||
{
|
||||
bool low = !high;
|
||||
bool level = !edge;
|
||||
void sleep_goto_dormant_until_pin(uint gpio_pin, bool edge, bool high) {
|
||||
bool low = !high;
|
||||
bool level = !edge;
|
||||
|
||||
// Configure the appropriate IRQ at IO bank 0
|
||||
assert(gpio_pin < NUM_BANK0_GPIOS);
|
||||
// Configure the appropriate IRQ at IO bank 0
|
||||
assert(gpio_pin < NUM_BANK0_GPIOS);
|
||||
|
||||
uint32_t event = 0;
|
||||
uint32_t event = 0;
|
||||
|
||||
if (level && low)
|
||||
event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_LEVEL_LOW_BITS;
|
||||
if (level && high)
|
||||
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;
|
||||
if (level && low)
|
||||
event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_LEVEL_LOW_BITS;
|
||||
if (level && high)
|
||||
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);
|
||||
|
||||
_go_dormant();
|
||||
// Execution stops here until woken up
|
||||
_go_dormant();
|
||||
// Execution stops here until woken up
|
||||
|
||||
// Clear the irq so we can go back to dormant mode again if we want
|
||||
gpio_acknowledge_irq(gpio_pin, event);
|
||||
// Clear the irq so we can go back to dormant mode again if we want
|
||||
gpio_acknowledge_irq(gpio_pin, event);
|
||||
}
|
||||
Reference in New Issue
Block a user