kopia lustrzana https://github.com/RPiks/pico-hf-oscillator
Initial release.
rodzic
cfcb7ba717
commit
ed69251907
|
@ -34,7 +34,6 @@ pico_generate_pio_header(pico-DCO-test ${CMAKE_CURRENT_LIST_DIR}/piodco/dco.pio)
|
|||
target_sources(pico-DCO-test PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/lib/assert.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/piodco/piodco.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/dcoisr/dcoisr.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/test.c
|
||||
)
|
||||
|
||||
|
@ -55,6 +54,7 @@ target_link_libraries(
|
|||
pico-DCO-test
|
||||
pico_stdlib
|
||||
pico_sync
|
||||
pico_multicore
|
||||
hardware_timer
|
||||
hardware_clocks
|
||||
hardware_pio
|
||||
|
|
51
README.md
51
README.md
|
@ -1,2 +1,51 @@
|
|||
# pico-DCO
|
||||
Digital controlled oscillator for raspberry pi pico (DC to ~30MHz frequency band)
|
||||
# Digital controlled radio frequency oscillator for Raspberry Pi Pico
|
||||
|
||||
The library for Raspberry Pi Pico includes the headers and source code and all
|
||||
necessary build files to build a custom application which turns pico into
|
||||
precise PLL digital frequency oscillator of the portion of HF radio spectrum
|
||||
1.1 to 9.4MHz with high resolution.
|
||||
|
||||
# Precise frequency resolution
|
||||
The library provides 1 Hz frequency resolution in initialize function. This
|
||||
resolution can be easily increased to 23 millihertz, which is limited by
|
||||
24-bit register which is used in algorithm.
|
||||
Currently the upper freq. limit is about 9.8 MHz and it is achieved only using
|
||||
pi pico overclocking to 270MHz.
|
||||
|
||||
# Phased locked loop in C
|
||||
The DCO uses phase locked loop principle programmed in C.
|
||||
|
||||
# Integer arithmetic
|
||||
The DCO does *NOT* use any floating point operations - all time-critical
|
||||
instructions run in 1 CPU cycle.
|
||||
|
||||
# Radio transmitters
|
||||
Owing to the meager frequency step, it is possible to use 3, 5, or 7th harmonics
|
||||
of generated frequency. Such solution completely cover all HF and low band up to
|
||||
65.8 MHz.
|
||||
|
||||
# For what?
|
||||
This is an experimental project of amateur radio class and it is devised by me on
|
||||
the free will base in order to experiment with QRP narrowband digital modes.
|
||||
|
||||
# Feedback
|
||||
I gracefully appreciate any thoughts or comments on that matter.
|
||||
|
||||
# Quick-start
|
||||
1. Install Raspberry Pi Pico SDK. Configure environment variables. Test whether
|
||||
it is built successfully.
|
||||
|
||||
2. git clone this repository. cd pico-DCO ; ./build.sh
|
||||
Check whether output file ./build/pico-DCO.uf2 appears.
|
||||
|
||||
3. Prepare the surrogate antenna (if you possess an SSB receiver) or pin-out
|
||||
for an oscilloscope or a spectrum analyser. The default output pin is GPIO6.
|
||||
|
||||
4. Load the .uf2 file (2) into the Pico.
|
||||
|
||||
5. Initialy the running frequency is 9.4 MHz.
|
||||
|
||||
6. Set any other frequency ranging from 1.1 to 9.4 MHz by #define GEN_FRQ_HZ and build the project.
|
||||
|
||||
7. Provide the feedback by clicking like on the github page of the project.
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// DESCRIPTION
|
||||
//
|
||||
// The oscillator provides precise generation of any frequency ranging
|
||||
// from 1.5 to 9.8 MHz with tenth's of millihertz resolution (please note that
|
||||
// from 1.1 to 9.4 MHz with tenth's of millihertz resolution (please note that
|
||||
// this is relative resolution owing to the fact that the absolute accuracy of
|
||||
// onboard crystal of pi pico is limited).
|
||||
// The DCO uses phase locked loop principle programmed in C.
|
||||
|
@ -66,6 +66,8 @@
|
|||
|
||||
#include "build/dco.pio.h"
|
||||
|
||||
int32_t si32precise_cycles;
|
||||
|
||||
/// @brief Initializes DCO context and prepares PIO hardware.
|
||||
/// @param pdco Ptr to DCO context.
|
||||
/// @param gpio The GPIO of DCO output.
|
||||
|
@ -105,16 +107,15 @@ int PioDCOSetFreq(PioDco *pdco, uint32_t ui32_frq_hz)
|
|||
assert_(pdco);
|
||||
assert(pdco->_clkfreq_hz);
|
||||
|
||||
if(pdco->_clkfreq_hz / ui32_frq_hz < 27)
|
||||
{
|
||||
//return -1;
|
||||
}
|
||||
ui32_frq_hz <<= 1;
|
||||
|
||||
/* RPix: Calculate an accurate value of phase increment of the freq
|
||||
per 1 tick of CPU clock, here 2^24 is scaling coefficient. */
|
||||
pdco->_frq_cycles_per_pi = (int32_t)(((int64_t)pdco->_clkfreq_hz * (int64_t)(1<<24)
|
||||
+ (ui32_frq_hz>>1)) / (int64_t)ui32_frq_hz);
|
||||
|
||||
si32precise_cycles = pdco->_frq_cycles_per_pi;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -138,7 +139,6 @@ void PioDCOStop(PioDco *pdco)
|
|||
/// @brief the dedicated pi pico core.
|
||||
/// @param pDCO Ptr to DCO context.
|
||||
/// @return No return. It spins forever.
|
||||
static int32_t si32precise_cycles;
|
||||
void RAM (PioDCOWorker)(PioDco *pDCO)
|
||||
{
|
||||
assert_(pDCO);
|
||||
|
@ -150,9 +150,10 @@ void RAM (PioDCOWorker)(PioDco *pDCO)
|
|||
|
||||
register uint32_t *preg32 = pDCO->_ui32_pioreg;
|
||||
register uint8_t *pu8reg = (uint8_t *)preg32;
|
||||
si32precise_cycles = pDCO->_frq_cycles_per_pi;
|
||||
//si32precise_cycles = pDCO->_frq_cycles_per_pi;
|
||||
for(;;)
|
||||
{
|
||||
const register int32_t i32reg = si32precise_cycles;
|
||||
/* RPix: Load the next precise value of CPU CLK cycles per DCO cycle,
|
||||
scaled by 2^24. It yields about 24 millihertz resolution at @10MHz
|
||||
DCO frequency. */
|
||||
|
@ -160,13 +161,13 @@ void RAM (PioDCOWorker)(PioDco *pDCO)
|
|||
{
|
||||
/* RPix: Calculate the integer number of CPU CLK cycles per next
|
||||
DCO cycle, corrected by accumulated error (feedback of the PLL). */
|
||||
const int32_t i32wc = iSAR(si32precise_cycles - i32acc_error + (1<<23), 24);
|
||||
const int32_t i32wc = iSAR(i32reg - i32acc_error + (1<<23), 24);
|
||||
|
||||
/* RPix: Calculate the difference btw calculated value scaled to
|
||||
`fine` state and precise value of DCO cycles per CPU CLK cycle.
|
||||
This forms a phase locked loop which provides precise freq
|
||||
on long run. */
|
||||
i32acc_error += (i32wc<<24) - si32precise_cycles;
|
||||
i32acc_error += (i32wc<<24) - i32reg;
|
||||
|
||||
/* RPix: Set PIO array contents corrected by pio program delay
|
||||
of N CPU CLK cycles owing to pio asm instructions. */
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// DESCRIPTION
|
||||
//
|
||||
// The oscillator provides precise generation of any frequency ranging
|
||||
// from 1.5 to 9.8 MHz with tenth's of millihertz resolution (please note that
|
||||
// from 1.1 to 9.4 MHz with tenth's of millihertz resolution (please note that
|
||||
// this is relative resolution owing to the fact that the absolute accuracy of
|
||||
// onboard crystal of pi pico is limited).
|
||||
// The DCO uses phase locked loop principle programmed in C.
|
||||
|
|
146
test.c
146
test.c
|
@ -1,3 +1,68 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Roman Piksaykin [piksaykin@gmail.com], R2BDY
|
||||
// https://www.qrz.com/db/r2bdy
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
//
|
||||
// test.c - Simple test of digital controlled radio freq oscillator based on PIO.
|
||||
//
|
||||
//
|
||||
// DESCRIPTION
|
||||
//
|
||||
// The oscillator provides precise generation of any frequency ranging
|
||||
// from 1.1 to 9.4 MHz with tenth's of millihertz resolution (please note that
|
||||
// this is relative resolution owing to the fact that the absolute accuracy of
|
||||
// onboard crystal of pi pico is limited).
|
||||
// The DCO uses phase locked loop principle programmed in C.
|
||||
// The DCO does *NOT* use any floating point operations - all time-critical
|
||||
// instructions run in 1 CPU cycle.
|
||||
// Currently the upper freq. limit is about 9.8 MHz and it is achieved only
|
||||
// using pi pico overclocking to 270MHz.
|
||||
// Owing to the meager frequency step, it is possible to use 3, 5, or 7th
|
||||
// harmonics of generated frequency. Such solution completely cover all HF and
|
||||
// low band up to about 66 MHz.
|
||||
// This is an experimental project of amateur radio class and it is devised
|
||||
// by me on the free will base in order to experiment with QRP narrowband
|
||||
// digital modes.
|
||||
// I gracefully appreciate any thoughts or comments on that matter.
|
||||
//
|
||||
// HOWTOSTART
|
||||
// Set frequency by #define GEN_FRQ_HZ and build the project. The default
|
||||
// output pin is GPIO6.
|
||||
//
|
||||
// PLATFORM
|
||||
// Raspberry Pi pico.
|
||||
//
|
||||
// REVISION HISTORY
|
||||
//
|
||||
// Rev 0.1 05 Nov 2023
|
||||
// Initial release.
|
||||
//
|
||||
// LICENCE
|
||||
// MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
//
|
||||
// Copyright (c) 2023 by Roman Piksaykin
|
||||
//
|
||||
// Permission is hereby granted, free of charge,to any person obtaining a copy
|
||||
// of this software and associated documentation files (the Software), to deal
|
||||
// in the Software without restriction,including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY,WHETHER IN AN ACTION OF CONTRACT,TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -6,67 +71,66 @@
|
|||
#include "piodco/piodco.h"
|
||||
#include "build/dco.pio.h"
|
||||
#include "hardware/vreg.h"
|
||||
#include "pico/multicore.h"
|
||||
|
||||
#include "./lib/assert.h"
|
||||
#include "hwdefs.h"
|
||||
#include "./dcoisr/dcoisr.h"
|
||||
|
||||
void __not_in_flash_func (WorkerCycle)(PioDco *pDCO, const int32_t i32frq_in_clk, uint32_t *preg32)
|
||||
#define GEN_FRQ_HZ 9400000L
|
||||
|
||||
PioDco DCO;
|
||||
|
||||
/* This is the code of dedicated core.
|
||||
We deal with extremely precise real-time task. */
|
||||
void core1_entry()
|
||||
{
|
||||
register int32_t acc_phase_error = 0;
|
||||
register uint8_t *preg8 = (uint8_t *)preg32;
|
||||
register PIO pio = pDCO->_pio;
|
||||
register uint sm = pDCO->_ism;
|
||||
const uint32_t clkhz = PLL_SYS_MHZ * 1000000L;
|
||||
const uint32_t freq_hz = GEN_FRQ_HZ;
|
||||
|
||||
pio_sm_set_enabled(pio, sm, true);
|
||||
/* Initialize DCO */
|
||||
assert_(0 == PioDCOInit(&DCO, 6, clkhz));
|
||||
|
||||
for(;;)
|
||||
{
|
||||
preg8 = (uint8_t *)preg32;
|
||||
for(int i = 0; i < 32; ++i)
|
||||
{
|
||||
register const int32_t i32wc = (i32frq_in_clk - acc_phase_error + (1<<23)) >> 24;
|
||||
acc_phase_error += (i32wc<<24) - i32frq_in_clk;
|
||||
/* Run DCO. */
|
||||
PioDCOStart(&DCO);
|
||||
|
||||
*preg8++ = i32wc - PIOASM_DELAY_CYCLES;
|
||||
/* Set initial freq. */
|
||||
assert_(0 == PioDCOSetFreq(&DCO, freq_hz));
|
||||
|
||||
/* Run the main DCO algorithm. It spins forever. */
|
||||
PioDCOWorker(&DCO);
|
||||
}
|
||||
|
||||
dco_program_puts(pio, sm, preg32);
|
||||
void RAM (Spinner)(void)
|
||||
{
|
||||
int i = 0;
|
||||
for(;;)
|
||||
{
|
||||
/* This example sets new frequency every ~500 ms.
|
||||
Frequency shift is 5 Hz for each step.
|
||||
*/
|
||||
PioDCOSetFreq(&DCO, GEN_FRQ_HZ - 5*i);
|
||||
|
||||
/* LED signal */
|
||||
gpio_put(PICO_DEFAULT_LED_PIN, 1);
|
||||
sleep_ms(500);
|
||||
gpio_put(PICO_DEFAULT_LED_PIN, 0);
|
||||
sleep_ms(500);
|
||||
|
||||
/* Return to initial freq after 20 steps (100 Hz). */
|
||||
if(++i == 20)
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
PioDco DCO;
|
||||
//DcoIsrContext ISRC;
|
||||
|
||||
const uint32_t clkhz = PLL_SYS_MHZ * 1000000L;
|
||||
set_sys_clock_khz(clkhz / 1000L, true);
|
||||
|
||||
gpio_init(PICO_DEFAULT_LED_PIN);
|
||||
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
||||
|
||||
const uint32_t freq_hz = 2*10000000L;
|
||||
multicore_launch_core1(core1_entry);
|
||||
|
||||
assert_(0 == PioDCOInit(&DCO, 6, clkhz));
|
||||
PioDCOStart(&DCO);
|
||||
assert_(0 == PioDCOSetFreq(&DCO, freq_hz));
|
||||
PioDCOWorker(&DCO);
|
||||
|
||||
/*
|
||||
//DcoIsrInit(&ISRC, &DCO);
|
||||
|
||||
uint32_t preg32[8] = {0};
|
||||
uint8_t *preg8 = (uint8_t *)preg32;
|
||||
|
||||
//const uint64_t frqhz = 2*(3573000L);
|
||||
//const uint64_t frqhz = 2*7074000L + 1;
|
||||
const uint64_t frqhz = 2*10000000L;
|
||||
//const uint64_t frqhz = 2*10136000L;
|
||||
//const int64_t frqhz = 2*(14074000L);
|
||||
const int64_t i64frq_in_clk = ((int64_t)clkhz * (int64_t)(1<<24) + (frqhz>>1)) / frqhz;
|
||||
const int32_t i32frq_in_clk = i64frq_in_clk;
|
||||
|
||||
WorkerCycle(&DCO, i32frq_in_clk, preg32);
|
||||
*/
|
||||
Spinner();
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue