Adds a 12K OTA stub 3rd stage bootloader, which reads new firmware from the LittleFS filesystem and flashes on reboot. By storing the OTA commands in a file in flash, it is possible to recover from a power failure during OTA programming. On power resume, the OTA block will simply re-program from the beginning. Support cryptographic signed OTA updates, if desired. Includes host-side signing logic via openssl. Add PicoOTA library which encapsulates the file format for the updater, including CRC32 checking. Add LEAmDNS support to allow Arduino IDE discovery Add ArduinoOTA class for IDE uploads Add MD5Builder class Add Updater class which supports writing and validating cryptographically signed binaries from any source (http, Ethernet, WiFi, Serial, etc.) Add documentation and readmes.
178 lines
6.2 KiB
C
178 lines
6.2 KiB
C
/*
|
|
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
/* This file taken from the Pico SDK. clocks_init will now not require 64-bit division code */
|
|
|
|
|
|
#include "pico.h"
|
|
#include "hardware/regs/clocks.h"
|
|
#include "hardware/platform_defs.h"
|
|
#include "hardware/clocks.h"
|
|
#include "hardware/watchdog.h"
|
|
#include "hardware/pll.h"
|
|
#include "hardware/xosc.h"
|
|
#include "hardware/irq.h"
|
|
#include "hardware/gpio.h"
|
|
|
|
// Clock muxing consists of two components:
|
|
// - A glitchless mux, which can be switched freely, but whose inputs must be
|
|
// free-running
|
|
// - An auxiliary (glitchy) mux, whose output glitches when switched, but has
|
|
// no constraints on its inputs
|
|
// Not all clocks have both types of mux.
|
|
static inline bool has_glitchless_mux(enum clock_index clk_index) {
|
|
return clk_index == clk_sys || clk_index == clk_ref;
|
|
}
|
|
|
|
/// \tag::clock_configure[]
|
|
bool _clock_configure(enum clock_index clk_index, uint32_t src, uint32_t auxsrc, uint32_t src_freq, uint32_t freq, uint32_t div) {
|
|
//uint32_t div;
|
|
|
|
assert(src_freq >= freq);
|
|
|
|
if (freq > src_freq)
|
|
return false;
|
|
|
|
// Div register is 24.8 int.frac divider so multiply by 2^8 (left shift by 8)
|
|
//div = freq; //(uint32_t) (((uint64_t) src_freq << 8) / freq);
|
|
|
|
clock_hw_t *clock = &clocks_hw->clk[clk_index];
|
|
|
|
// If increasing divisor, set divisor before source. Otherwise set source
|
|
// before divisor. This avoids a momentary overspeed when e.g. switching
|
|
// to a faster source and increasing divisor to compensate.
|
|
if (div > clock->div)
|
|
clock->div = div;
|
|
|
|
// If switching a glitchless slice (ref or sys) to an aux source, switch
|
|
// away from aux *first* to avoid passing glitches when changing aux mux.
|
|
// Assume (!!!) glitchless source 0 is no faster than the aux source.
|
|
if (has_glitchless_mux(clk_index) && src == CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX) {
|
|
hw_clear_bits(&clock->ctrl, CLOCKS_CLK_REF_CTRL_SRC_BITS);
|
|
while (!(clock->selected & 1u))
|
|
tight_loop_contents();
|
|
}
|
|
// If no glitchless mux, cleanly stop the clock to avoid glitches
|
|
// propagating when changing aux mux. Note it would be a really bad idea
|
|
// to do this on one of the glitchless clocks (clk_sys, clk_ref).
|
|
else {
|
|
// Disable clock. On clk_ref and clk_sys this does nothing,
|
|
// all other clocks have the ENABLE bit in the same position.
|
|
hw_clear_bits(&clock->ctrl, CLOCKS_CLK_GPOUT0_CTRL_ENABLE_BITS);
|
|
}
|
|
|
|
// Set aux mux first, and then glitchless mux if this clock has one
|
|
hw_write_masked(&clock->ctrl,
|
|
(auxsrc << CLOCKS_CLK_SYS_CTRL_AUXSRC_LSB),
|
|
CLOCKS_CLK_SYS_CTRL_AUXSRC_BITS
|
|
);
|
|
|
|
if (has_glitchless_mux(clk_index)) {
|
|
hw_write_masked(&clock->ctrl,
|
|
src << CLOCKS_CLK_REF_CTRL_SRC_LSB,
|
|
CLOCKS_CLK_REF_CTRL_SRC_BITS
|
|
);
|
|
while (!(clock->selected & (1u << src)))
|
|
tight_loop_contents();
|
|
}
|
|
|
|
// Enable clock. On clk_ref and clk_sys this does nothing,
|
|
// all other clocks have the ENABLE bit in the same position.
|
|
hw_set_bits(&clock->ctrl, CLOCKS_CLK_GPOUT0_CTRL_ENABLE_BITS);
|
|
|
|
// Now that the source is configured, we can trust that the user-supplied
|
|
// divisor is a safe value.
|
|
clock->div = div;
|
|
|
|
// Store the configured frequency
|
|
//configured_freq[clk_index] = (uint32_t)(((uint64_t) src_freq << 8) / div);
|
|
|
|
return true;
|
|
}
|
|
/// \end::clock_configure[]
|
|
|
|
void __wrap_clocks_init(void) {
|
|
// Start tick in watchdog
|
|
watchdog_start_tick(XOSC_MHZ);
|
|
|
|
// Disable resus that may be enabled from previous software
|
|
clocks_hw->resus.ctrl = 0;
|
|
|
|
// Enable the xosc
|
|
xosc_init();
|
|
|
|
// Before we touch PLLs, switch sys and ref cleanly away from their aux sources.
|
|
hw_clear_bits(&clocks_hw->clk[clk_sys].ctrl, CLOCKS_CLK_SYS_CTRL_SRC_BITS);
|
|
while (clocks_hw->clk[clk_sys].selected != 0x1)
|
|
tight_loop_contents();
|
|
hw_clear_bits(&clocks_hw->clk[clk_ref].ctrl, CLOCKS_CLK_REF_CTRL_SRC_BITS);
|
|
while (clocks_hw->clk[clk_ref].selected != 0x1)
|
|
tight_loop_contents();
|
|
|
|
/// \tag::pll_settings[]
|
|
// Configure PLLs
|
|
// REF FBDIV VCO POSTDIV
|
|
// PLL SYS: 12 / 1 = 12MHz * 125 = 1500MHz / 6 / 2 = 125MHz
|
|
// PLL USB: 12 / 1 = 12MHz * 100 = 1200MHz / 5 / 5 = 48MHz
|
|
/// \end::pll_settings[]
|
|
|
|
/// \tag::pll_init[]
|
|
pll_init(pll_sys, 1, 1500 * MHZ, 6, 2);
|
|
pll_init(pll_usb, 1, 1200 * MHZ, 5, 5);
|
|
/// \end::pll_init[]
|
|
|
|
// Configure clocks
|
|
// CLK_REF = XOSC (12MHz) / 1 = 12MHz
|
|
_clock_configure(clk_ref,
|
|
CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC,
|
|
0, // No aux mux
|
|
12 * MHZ,
|
|
12 * MHZ,
|
|
1 << 8);
|
|
|
|
/// \tag::configure_clk_sys[]
|
|
// CLK SYS = PLL SYS (125MHz) / 1 = 125MHz
|
|
_clock_configure(clk_sys,
|
|
CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
|
|
CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
|
|
125 * MHZ,
|
|
125 * MHZ,
|
|
1 << 8);
|
|
/// \end::configure_clk_sys[]
|
|
|
|
// CLK USB = PLL USB (48MHz) / 1 = 48MHz
|
|
_clock_configure(clk_usb,
|
|
0, // No GLMUX
|
|
CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
|
|
48 * MHZ,
|
|
48 * MHZ,
|
|
1 << 8);
|
|
|
|
// CLK ADC = PLL USB (48MHZ) / 1 = 48MHz
|
|
_clock_configure(clk_adc,
|
|
0, // No GLMUX
|
|
CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
|
|
48 * MHZ,
|
|
48 * MHZ,
|
|
1 << 8);
|
|
|
|
// CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz
|
|
_clock_configure(clk_rtc,
|
|
0, // No GLMUX
|
|
CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
|
|
48 * MHZ,
|
|
46875,
|
|
32 << 8);
|
|
|
|
// CLK PERI = clk_sys. Used as reference clock for Peripherals. No dividers so just select and enable
|
|
// Normally choose clk_sys or clk_usb
|
|
_clock_configure(clk_peri,
|
|
0,
|
|
CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS,
|
|
125 * MHZ,
|
|
125 * MHZ,
|
|
1 << 8);
|
|
}
|