Some final stages of work ere release.

gpstest
roman 2023-11-26 23:00:47 +03:00
rodzic 735698ec94
commit e319558b9c
11 zmienionych plików z 259 dodań i 68 usunięć

Wyświetl plik

@ -9,8 +9,6 @@ set(CMAKE_CXX_STANDARD 17)
# Initialise pico_sdk from installed location
# (note this can come from environment, CMake cache etc)
# set(PICO_SDK_PATH "/home/jabba/pico-sdk")
set(PICO_BOARD pico CACHE STRING "Board type")
# Pull in Raspberry Pi Pico SDK (must be before project)
@ -25,33 +23,30 @@ project(pico-hf-oscillator-test C CXX ASM)
# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()
# Add executable. Default name is the project name, version 0.1
add_executable(pico-hf-oscillator-test)
pico_generate_pio_header(pico-hf-oscillator-test ${CMAKE_CURRENT_LIST_DIR}/piodco/dco.pio)
target_sources(pico-hf-oscillator-test PUBLIC
${CMAKE_CURRENT_LIST_DIR}/lib/assert.c
${CMAKE_CURRENT_LIST_DIR}/lib/assert.c
${CMAKE_CURRENT_LIST_DIR}/lib/thirdparty/strnstr.c
# ${CMAKE_CURRENT_LIST_DIR}/lib/thirdparty/strptime.c
# ${CMAKE_CURRENT_LIST_DIR}/lib/thirdparty/timegm.c
${CMAKE_CURRENT_LIST_DIR}/piodco/piodco.c
${CMAKE_CURRENT_LIST_DIR}/gpstime/GPStime.c
${CMAKE_CURRENT_LIST_DIR}/debug/logutils.c
${CMAKE_CURRENT_LIST_DIR}/test.c
)
pico_set_program_name(pico-hf-oscillator-test "pico-hf-oscillator-test")
pico_set_program_version(pico-hf-oscillator-test "0.9")
pico_enable_stdio_uart(pico-hf-oscillator-test 1)
pico_enable_stdio_uart(pico-hf-oscillator-test 0)
pico_enable_stdio_usb(pico-hf-oscillator-test 1)
# Add the standard include files to the build
target_include_directories(pico-hf-oscillator-test PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/gpstime
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required
${CMAKE_CURRENT_LIST_DIR}/..
)
# Add any user requested libraries
@ -63,7 +58,7 @@ target_link_libraries(
hardware_timer
hardware_clocks
hardware_pio
hardware_vreg
#hardware_vreg
)
pico_add_extra_outputs(pico-hf-oscillator-test)

87
debug/logutils.c 100644
Wyświetl plik

@ -0,0 +1,87 @@
///////////////////////////////////////////////////////////////////////////////
//
// Roman Piksaykin [piksaykin@gmail.com], R2BDY
// https://www.qrz.com/db/r2bdy
//
///////////////////////////////////////////////////////////////////////////////
//
//
// logutils.h - A set of utilities for logging/debugging.
//
// DESCRIPTION
// -
//
// HOWTOSTART
// -
//
// PLATFORM
// Raspberry Pi pico.
//
// REVISION HISTORY
// -
//
// PROJECT PAGE
// https://github.com/RPiks/pico-WSPR-tx
//
// 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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "hardware/clocks.h"
#include "pico/stdlib.h"
void StampPrintf(const char* pformat, ...)
{
static uint32_t sTick = 0;
if(!sTick)
{
stdio_init_all();
}
uint64_t tm_us = to_us_since_boot(get_absolute_time());
const uint32_t tm_day = (uint32_t)(tm_us / 86400000000ULL);
tm_us -= (uint64_t)tm_day * 86400000000ULL;
const uint32_t tm_hour = (uint32_t)(tm_us / 3600000000ULL);
tm_us -= (uint64_t)tm_hour * 3600000000ULL;
const uint32_t tm_min = (uint32_t)(tm_us / 60000000ULL);
tm_us -= (uint64_t)tm_min * 60000000ULL;
const uint32_t tm_sec = (uint32_t)(tm_us / 1000000ULL);
tm_us -= (uint64_t)tm_sec * 1000000ULL;
printf("%02lud%02lu:%02lu:%02lu.%06llu [%04lu] ", tm_day, tm_hour, tm_min, tm_sec, tm_us, sTick++);
va_list argptr;
va_start(argptr, pformat);
vprintf(pformat, argptr);
va_end(argptr);
printf("\n");
}

6
debug/logutils.h 100644
Wyświetl plik

@ -0,0 +1,6 @@
#ifndef LOGUTILS_H_
#define LOGUTILS_H_
void StampPrintf(const char* pformat, ...);
#endif

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 219 KiB

Wyświetl plik

@ -63,22 +63,25 @@
static GPStimeContext *spGPStimeContext = NULL;
static GPStimeData *spGPStimeData = NULL;
/// @brief Initializes GPS time module Context.
/// @param uart_id UART id to which GPS receiver is connected, 0 OR 1.
/// @param uart_baud UART baudrate, 115200 max.
/// @param pps_gpio GPIO pin of PPS (second pulse) from GPS receiver.
/// @return the new GPS time Context.
GPStimeContext *GPStimeInit(int uart_id, int uart_baud, int pps_gpio)
{
ASSERT_(0 == uart_id || 1 == uart_id);
ASSERT_(uart_baud <= 115200);
ASSERT_(pps_gpio < 29);
// Set up our UART with the required speed.
// Set up our UART with the required speed & assign pins.
uart_init(uart_id ? uart1 : uart0, uart_baud);
// Set the TX and RX pins by using the function select on the GPIO
// Set datasheet for more information on function select
gpio_set_function(uart_id ? 8 : 12, GPIO_FUNC_UART);
gpio_set_function(uart_id ? 9 : 13, GPIO_FUNC_UART);
GPStimeContext *pgt = calloc(1, sizeof(GPStimeContext));
ASSERT_(pgt);
pgt->_uart_id = uart_id;
pgt->_uart_baudrate = uart_baud;
pgt->_pps_gpio = pps_gpio;
@ -90,13 +93,16 @@ GPStimeContext *GPStimeInit(int uart_id, int uart_baud, int pps_gpio)
gpio_set_dir(pps_gpio, GPIO_IN);
gpio_set_irq_enabled_with_callback(pps_gpio, GPIO_IRQ_EDGE_RISE, true, &GPStimePPScallback);
irq_set_exclusive_handler(UART0_IRQ, GPStimeUartRxIsr);
irq_set_enabled(UART0_IRQ, true);
uart_set_irq_enables(uart0, true, false);
irq_set_exclusive_handler(uart_id ? UART1_IRQ : UART0_IRQ, GPStimeUartRxIsr);
irq_set_enabled(uart_id ? UART1_IRQ : UART0_IRQ, true);
uart_set_irq_enables(uart_id ? uart1 : uart0, true, false);
return pgt;
}
/// @brief Deinits the GPS module and destroys allocated resources.
/// @param pp Ptr to Ptr of the Context.
/// @attention *NOT* implemented completely so far. !FIXME!
void GPStimeDestroy(GPStimeContext **pp)
{
ASSERT_(pp);
@ -107,7 +113,9 @@ void GPStimeDestroy(GPStimeContext **pp)
*pp = NULL;
}
void __not_in_flash_func (GPStimePPScallback)(uint gpio, uint32_t events)
/// @brief The PPS interrupt service subroutine.
/// @param gpio The GPIO pin of Pico which is connected to PPS output of GPS rec.
void RAM (GPStimePPScallback)(uint gpio, uint32_t events)
{
const uint64_t tm64 = GetUptime64();
if(spGPStimeData)
@ -145,7 +153,7 @@ void __not_in_flash_func (GPStimePPScallback)(uint gpio, uint32_t events)
}
}
/// @brief Calculates current unixtime using information available.
/// @brief Calculates current unixtime using data available.
/// @param pg Ptr to the context.
/// @param u32_tmdst Ptr to destination unixtime val.
/// @return 0 if OK.
@ -177,7 +185,8 @@ int GPStimeGetTime(const GPStimeContext *pg, uint32_t *u32_tmdst)
return 0;
}
void __not_in_flash_func (GPStimeUartRxIsr)()
/// @brief UART FIFO ISR. Processes another N chars receiver from GPS rec.
void RAM (GPStimeUartRxIsr)()
{
if(spGPStimeContext)
{
@ -194,11 +203,17 @@ void __not_in_flash_func (GPStimeUartRxIsr)()
{
spGPStimeContext->_u8_ixw = 0;
spGPStimeContext->_i32_error_count -= GPStimeProcNMEAsentence(spGPStimeContext);
//printf("err: %ld\n", spGPStimeContext->_i32_error_count);
}
}
}
/// @brief Processes a NMEA sentence GPRMC.
/// @param pg Ptr to Context.
/// @return 0 OK.
/// @return -2 Error: bad lat format.
/// @return -3 Error: bad lon format.
/// @return -4 Error: no final '*' char ere checksum value.
/// @attention Checksum validation is not implemented so far. !FIXME!
int GPStimeProcNMEAsentence(GPStimeContext *pg)
{
assert_(pg);
@ -207,7 +222,6 @@ int GPStimeProcNMEAsentence(GPStimeContext *pg)
if(prmc)
{
uint64_t tm_fix = GetUptime64();
uint8_t u8ixcollector[16] = {0};
uint8_t chksum = 0;
for(uint8_t u8ix = 0, i = 0; u8ix != sizeof(pg->_pbytebuff); ++u8ix)
@ -259,15 +273,17 @@ int GPStimeProcNMEAsentence(GPStimeContext *pg)
pg->_time_data._u32_utime_nmea_last = GPStime2UNIX(prmc + u8ixcollector[8], prmc + u8ixcollector[0]);
pg->_time_data._u64_sysclk_nmea_last = tm_fix;
}
++pg->_time_data._u32_nmea_gprmc_count;
}
return 0;
/*
"$GPRMC,105954.000,A,3150.6731,N,11711.9399,E,0.00,96.10,250313,,,A*53";
*/
}
/// @brief Converts GPS time and date strings to unix time.
/// @param pdate Date string, 6 chars in work.
/// @param ptime Time string, 6 chars in work.
/// @return Unix timestamp (epoch). 0 if bad imput format.
uint32_t GPStime2UNIX(const char *pdate, const char *ptime)
{
assert_(pdate);
@ -291,17 +307,18 @@ uint32_t GPStime2UNIX(const char *pdate, const char *ptime)
return 0;
}
/// @brief Dumps the GPS data struct to stdio.
/// @param pd Ptr to Context.
void GPStimeDump(const GPStimeData *pd)
{
assert_(pd);
static int tick = 0;
printf("%u\nActive:%u\n", tick++, pd->_u8_is_solution_active);
printf("NMEA utime last:%lu\n", pd->_u32_utime_nmea_last);
printf("SYSCKL NMEA last:%llu\n", pd->_u64_sysclk_nmea_last);
printf("Lat:%lld Lon:%lld\n", pd->_i64_lat_100k, pd->_i64_lon_100k);
printf("SYSCKL PPS last:%llu\n", pd->_u64_sysclk_pps_last);
printf("PPS period e6:%llu\n", (pd->_u64_pps_period_1M + (eSlidingLen>>1)) / eSlidingLen);
printf("FRQ corr ppb:%lld\n\n", pd->_i32_freq_shift_ppb);
printf("\nGPS solution is active:%u\n", pd->_u8_is_solution_active);
printf("GPRMC count:%lu\n", pd->_u32_nmea_gprmc_count);
printf("NMEA unixtime last:%lu\n", pd->_u32_utime_nmea_last);
printf("NMEA sysclock last:%llu\n", pd->_u64_sysclk_nmea_last);
printf("GPS Latitude:%lld Longtitude:%lld\n", pd->_i64_lat_100k, pd->_i64_lon_100k);
printf("PPS sysclock last:%llu\n", pd->_u64_sysclk_pps_last);
printf("PPS period *1e6:%llu\n", (pd->_u64_pps_period_1M + (eSlidingLen>>1)) / eSlidingLen);
printf("FRQ correction ppb:%lld\n\n", pd->_i32_freq_shift_ppb);
}

Wyświetl plik

@ -89,6 +89,7 @@ typedef struct
uint32_t _u32_utime_nmea_last; /* The last unix time received from GPS. */
uint64_t _u64_sysclk_nmea_last; /* The sysclk of the last unix time received. */
int64_t _i64_lat_100k, _i64_lon_100k; /* The lat, lon, degrees, multiplied by 1e5. */
uint32_t _u32_nmea_gprmc_count; /* The count of $GPRMC sentences received */
uint64_t _u64_sysclk_pps_last; /* The sysclk of the last rising edge of PPS. */
uint64_t _u64_pps_period_1M; /* The PPS avg. period *1e6, filtered. */
@ -120,8 +121,8 @@ void GPStimeDestroy(GPStimeContext **pp);
int GPStimeProcNMEAsentence(GPStimeContext *pg);
void __not_in_flash_func (GPStimePPScallback)(uint gpio, uint32_t events);
void __not_in_flash_func (GPStimeUartRxIsr)();
void RAM (GPStimePPScallback)(uint gpio, uint32_t events);
void RAM (GPStimeUartRxIsr)();
int GPStimeGetTime(const GPStimeContext *pg, uint32_t *u32_tmdst);
uint32_t GPStime2UNIX(const char *pdate, const char *ptime);

Wyświetl plik

@ -27,4 +27,11 @@ inline uint32_t DecimalStr2ToNumber(const char *p)
return 10U * (p[0] - '0') + (p[1] - '0');
}
inline void PRN32(uint32_t *val)
{
*val ^= *val << 13;
*val ^= *val >> 17;
*val ^= *val << 5;
}
#endif

Wyświetl plik

@ -69,7 +69,7 @@
#include "build/dco.pio.h"
int32_t si32precise_cycles;
int32_t si32precise_cycles; /* External in order to support ISR. */
/// @brief Initializes DCO context and prepares PIO hardware.
/// @param pdco Ptr to DCO context.
@ -101,11 +101,11 @@ int PioDCOInit(PioDco *pdco, int gpio, int cpuclkhz)
/// @brief Sets DCO working frequency in Hz: Fout = ui32_frq_hz + ui32_frq_millihz * 1e-3.
/// @param pdco Ptr to DCO context.
/// @param ui32_frq_hz The `coarse` part of frequency [Hz].
/// @param i32_frq_hz The `coarse` part of frequency [Hz]. Might be negative.
/// @param ui32_frq_millihz The `fine` part of frequency [Hz].
/// @return 0 if OK. -1 invalid freq.
/// @attention The func can be called while DCO running.
int PioDCOSetFreq(PioDco *pdco, uint32_t ui32_frq_hz, uint32_t ui32_frq_millihz)
int PioDCOSetFreq(PioDco *pdco, uint32_t ui32_frq_hz, int32_t ui32_frq_millihz)
{
assert_(pdco);
assert(pdco->_clkfreq_hz);
@ -121,6 +121,38 @@ int PioDCOSetFreq(PioDco *pdco, uint32_t ui32_frq_hz, uint32_t ui32_frq_millihz)
return 0;
}
/// @brief Obtains the frequency shift [milliHz] which is calculated for a given frequency.
/// @param pdco Ptr to Context.
/// @param u64_desired_frq_millihz The frequency for which we want to calculate correction.
/// @return The value of correction we need to subtract from desired freq. to compensate
/// @return Pico's reference clock shift. 2854974.
int32_t PioDCOGetFreqShiftMilliHertz(const PioDco *pdco, uint64_t u64_desired_frq_millihz)
{
assert_(pdco);
if(!pdco->_pGPStime)
{
return 0U;
}
static int64_t i64_last_correction = 0;
const int64_t dt = pdco->_pGPStime->_time_data._i32_freq_shift_ppb; /* Parts per billion. */
if(dt)
{
i64_last_correction = dt;
}
int32_t i32ret_millis;
if(i64_last_correction)
{
int64_t i64corr_coeff = (u64_desired_frq_millihz + 500000LL) / 1000000LL;
i32ret_millis = (i64_last_correction * i64corr_coeff + 50000LL) / 1000000LL;
return i32ret_millis;
}
return 0U;
}
/// @brief Starts the DCO.
/// @param pdco Ptr to DCO context.
void PioDCOStart(PioDco *pdco)
@ -163,10 +195,9 @@ void RAM (PioDCOWorker)(PioDco *pDCO)
DCO cycle, corrected by accumulated error (feedback of the PLL). */
const int32_t i32wc = iSAR32(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. */
/* RPix: Calculate the difference betwixt calculated value scaled to
fine resolution back and precise value of DCO cycles per CPU CLK cycle.
This forms a phase locked loop which provides precise freq */
i32acc_error += (i32wc<<24) - i32reg;
/* RPix: Set PIO array contents corrected by pio program delay
@ -181,9 +212,23 @@ void RAM (PioDCOWorker)(PioDco *pDCO)
/// @brief Sets DCO running mode.
/// @param pdco Ptr to DCO context.
/// @param emode Desired mode.
/// @attention Not actual so far. User-independent freq. correction not impl'd yet. !FIXME!
void PioDCOSetMode(PioDco *pdco, enum PioDcoMode emode)
{
assert_(pdco);
pdco->_mode = emode;
eDCOMODE_IDLE == emode ? PioDCOStop(pdco) : PioDCOStart(pdco);
switch(emode)
{
case eDCOMODE_IDLE:
PioDCOStop(pdco);
break;
case eDCOMODE_GPS_COMPENSATED:
PioDCOStart(pdco);
break;
default:
break;
}
}

Wyświetl plik

@ -72,12 +72,12 @@
#include "defines.h"
#include "../gpstime/GPStime.h"
enum PioDcoMode
{
eDCOMODE_IDLE = 0,
eDCOMODE_FREERUN = 1,
eDCOMODE_GPS_REFERENCE = 2,
eDCOMODE_THERMO_COMPENSATION = 3
eDCOMODE_IDLE = 0, /* No output. */
eDCOMODE_GPS_COMPENSATED= 2 /* Internally compensated, if GPS available. */
};
typedef struct
@ -97,10 +97,13 @@ typedef struct
uint32_t _clkfreq_hz; /* CPU CLK freq, Hz. */
GPStimeContext *_pGPStime; /* Ptr to GPS time context. */
} PioDco;
int PioDCOInit(PioDco *pdco, int gpio, int cpuclkhz);
int PioDCOSetFreq(PioDco *pdco, uint32_t ui32_frq_hz, uint32_t ui32_frq_millihz);
int PioDCOSetFreq(PioDco *pdco, uint32_t u32_frq_hz, int32_t u32_frq_millihz);
int32_t PioDCOGetFreqShiftMilliHertz(const PioDco *pdco, uint64_t u64_desired_frq_millihz);
void PioDCOStart(PioDco *pdco);
void PioDCOStop(PioDco *pdco);

66
test.c
Wyświetl plik

@ -79,14 +79,14 @@
#include "pico/stdio/driver.h"
#include "./lib/assert.h"
#include "./debug/logutils.h"
#include "hwdefs.h"
#include <GPStime.h>
#define GEN_FRQ_HZ 9400000L
PioDco DCO;
void PRN32(uint32_t *val);
PioDco DCO; /* External in order to access in both cores. */
/* This is the code of dedicated core.
We deal with extremely precise real-time task. */
@ -210,6 +210,47 @@ void RAM (SpinnerWide4FSKTest)(void)
}
}
/* This example sets the OUT frequency to 5.555 MHz.
Next every ~1 sec the shift of the OUT frequency relative to GPS
reference is calculated and the OUT frequency is corrected.
The example is working only when GPS receiver provides an
accurate PPS output (pulse per second). If no such option,
the correction parameter is zero.
*/
void RAM (SpinnerGPSreferenceTest)(void)
{
const uint32_t ku32_freq = 5555000UL;
const int kigps_pps_pin = 2;
int32_t i32_compensation_millis = 0;
GPStimeContext *pGPS = GPStimeInit(0, 9600, kigps_pps_pin);
assert_(pGPS);
DCO._pGPStime = pGPS;
int tick = 0;
for(;;)
{
PioDCOSetFreq(&DCO, ku32_freq, -2*i32_compensation_millis);
/* LED signal */
gpio_put(PICO_DEFAULT_LED_PIN, 1);
sleep_ms(500);
i32_compensation_millis =
PioDCOGetFreqShiftMilliHertz(&DCO, (uint64_t)(ku32_freq * 1000LL));
StampPrintf("GPS solution status: %s | GPS-based freq compensation: %ld milliHz",
pGPS->_time_data._u8_is_solution_active ? "Active" : "No solution",
i32_compensation_millis);
gpio_put(PICO_DEFAULT_LED_PIN, 0);
sleep_ms(500);
if(0 == ++tick % 30)
GPStimeDump(&(pGPS->_time_data));
}
}
int main()
{
const uint32_t clkhz = PLL_SYS_MHZ * 1000000L;
@ -218,14 +259,8 @@ int main()
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);
@ -236,22 +271,17 @@ int main()
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();
//SpinnerMFSKTest();
//SpinnerRTTYTest();
//SpinnerMilliHertzTest();
//SpinnerWide4FSKTest();
SpinnerGPSreferenceTest();
}
void PRN32(uint32_t *val)
{
*val ^= *val << 13;
*val ^= *val >> 17;
*val ^= *val << 5;
}