initial commit
This commit is contained in:
+1
@@ -0,0 +1 @@
|
||||
pico_simple_hardware_target(rosc)
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#if defined(ARDUINO_ARCH_RP2350) || defined(PICO_RP2350) || \
|
||||
defined(TARGET_RP2350)
|
||||
|
||||
#ifndef _HARDWARE_ROSC_H_
|
||||
#define _HARDWARE_ROSC_H_
|
||||
|
||||
#include "hardware/structs/rosc.h"
|
||||
#include "pico.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, 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
|
||||
* \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 // _HARDWARE_ROSC_H_
|
||||
#endif // ARDUINO_ARCH_RP2350
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#if defined(ARDUINO_ARCH_RP2350)
|
||||
#include "pico.h"
|
||||
|
||||
// For MHZ definitions etc
|
||||
#include "hardware/clocks.h"
|
||||
#include "include/hardware/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))
|
||||
;
|
||||
}
|
||||
|
||||
#endif // ARDUINO_ARCH_RP2350
|
||||
Reference in New Issue
Block a user