pico-hf-oscillator/test.c

258 wiersze
7.1 KiB
C

///////////////////////////////////////////////////////////////////////////////
//
// 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
// Rev 0.2 18 Nov 2023
//
// PROJECT PAGE
// https://github.com/RPiks/pico-hf-oscillator
//
// 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>
#include <stdio.h>
#include "defines.h"
#include "piodco/piodco.h"
#include "build/dco.pio.h"
#include "hardware/vreg.h"
#include "pico/multicore.h"
#include "pico/stdio/driver.h"
#include "./lib/assert.h"
#include "hwdefs.h"
#include <GPStime.h>
#define GEN_FRQ_HZ 9400000L
PioDco DCO;
void PRN32(uint32_t *val);
/* This is the code of dedicated core.
We deal with extremely precise real-time task. */
void core1_entry()
{
const uint32_t clkhz = PLL_SYS_MHZ * 1000000L;
const uint32_t freq_hz = GEN_FRQ_HZ;
/* Initialize DCO */
assert_(0 == PioDCOInit(&DCO, 6, clkhz));
/* Run DCO. */
PioDCOStart(&DCO);
/* Set initial freq. */
assert_(0 == PioDCOSetFreq(&DCO, freq_hz, 0u));
/* Run the main DCO algorithm. It spins forever. */
PioDCOWorker(&DCO);
}
void RAM (SpinnerMFSKTest)(void)
{
uint32_t rndval = 77777777;
for(;;)
{
/* This example sets new RND frequency every ~250 ms.
Frequency shift is 5 Hz for each step.
*/
PioDCOSetFreq(&DCO, GEN_FRQ_HZ - 5*(rndval & 7), 0u);
/* LED signal */
gpio_put(PICO_DEFAULT_LED_PIN, 1);
sleep_ms(250);
gpio_put(PICO_DEFAULT_LED_PIN, 0);
sleep_ms(250);
PRN32(&rndval);
}
}
void RAM (SpinnerSweepTest)(void)
{
int i = 0;
for(;;)
{
/* This example sets new frequency every ~250 ms.
Frequency shift is 5 Hz for each step.
*/
PioDCOSetFreq(&DCO, GEN_FRQ_HZ - 5*i, 0u);
/* LED signal */
gpio_put(PICO_DEFAULT_LED_PIN, 1);
sleep_ms(250);
gpio_put(PICO_DEFAULT_LED_PIN, 0);
sleep_ms(250);
/* Return to initial freq after 20 steps (100 Hz). */
if(++i == 20)
i = 0;
}
}
void RAM (SpinnerRTTYTest)(void)
{
int32_t df = 170; /* 170 Hz freq diff. */
uint32_t rndval = 77777777;
for(;;)
{
/* This example sets new PRN frequency every ~22 ms.
Note: You should use precise timing while building a real transmitter.
*/
PioDCOSetFreq(&DCO, GEN_FRQ_HZ - df*(rndval & 1), 0u);
/* LED signal */
gpio_put(PICO_DEFAULT_LED_PIN, 1);
sleep_ms(22);
gpio_put(PICO_DEFAULT_LED_PIN, 0);
sleep_ms(22);
PRN32(&rndval);
}
}
void RAM (SpinnerMilliHertzTest)(void)
{
int i = 0;
for(;;)
{
/* This example sets new frequency every ~1s.
Frequency shift is 0.99 Hz for each step.
*/
PioDCOSetFreq(&DCO, GEN_FRQ_HZ, 990*(++i&1));
/* LED signal */
gpio_put(PICO_DEFAULT_LED_PIN, 1);
sleep_ms(1000);
gpio_put(PICO_DEFAULT_LED_PIN, 0);
sleep_ms(1000);
}
}
void RAM (SpinnerWide4FSKTest)(void)
{
int32_t df = 100; /* 100 Hz freq diff * 4 = 400 Hz. */
uint32_t rndval = 77777777;
for(;;)
{
/* This example sets new PRN frequency every ~20 ms.
Note: You should use precise timing while building a real transmitter.
*/
PioDCOSetFreq(&DCO, GEN_FRQ_HZ - df*(rndval & 3), 0u);
/* LED signal */
gpio_put(PICO_DEFAULT_LED_PIN, 1);
sleep_ms(20);
gpio_put(PICO_DEFAULT_LED_PIN, 0);
sleep_ms(20);
PRN32(&rndval);
}
}
int main()
{
const uint32_t clkhz = PLL_SYS_MHZ * 1000000L;
set_sys_clock_khz(clkhz / 1000L, true);
stdio_init_all();
sleep_ms(1000);
printf("Start\n");
GPStimeContext *pGPS = GPStimeInit(0, 9600, 2);
for(;;)
{
GPStimeDump(&(pGPS->_time_data));
sleep_ms(1000);
}
for(;;)
{
char ch = uart_getc(uart0);
if(ch)
{
stdio_set_driver_enabled(&stdio_uart, false);
printf("%c", ch);
stdio_set_driver_enabled(&stdio_uart, true);
}
}
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
multicore_launch_core1(core1_entry);
//SpinnerSweepTest();
SpinnerMFSKTest();
//SpinnerRTTYTest();
//SpinnerMilliHertzTest();
//SpinnerWide4FSKTest();
}
void PRN32(uint32_t *val)
{
*val ^= *val << 13;
*val ^= *val >> 17;
*val ^= *val << 5;
}