kopia lustrzana https://github.com/RPiks/pico-hf-oscillator
Some final stages of work ere release.
rodzic
735698ec94
commit
e319558b9c
|
@ -9,8 +9,6 @@ set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
# Initialise pico_sdk from installed location
|
# Initialise pico_sdk from installed location
|
||||||
# (note this can come from environment, CMake cache etc)
|
# (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")
|
set(PICO_BOARD pico CACHE STRING "Board type")
|
||||||
|
|
||||||
# Pull in Raspberry Pi Pico SDK (must be before project)
|
# 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
|
# Initialise the Raspberry Pi Pico SDK
|
||||||
pico_sdk_init()
|
pico_sdk_init()
|
||||||
|
|
||||||
# Add executable. Default name is the project name, version 0.1
|
|
||||||
|
|
||||||
add_executable(pico-hf-oscillator-test)
|
add_executable(pico-hf-oscillator-test)
|
||||||
|
|
||||||
pico_generate_pio_header(pico-hf-oscillator-test ${CMAKE_CURRENT_LIST_DIR}/piodco/dco.pio)
|
pico_generate_pio_header(pico-hf-oscillator-test ${CMAKE_CURRENT_LIST_DIR}/piodco/dco.pio)
|
||||||
|
|
||||||
target_sources(pico-hf-oscillator-test PUBLIC
|
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/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}/piodco/piodco.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/gpstime/GPStime.c
|
${CMAKE_CURRENT_LIST_DIR}/gpstime/GPStime.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/debug/logutils.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/test.c
|
${CMAKE_CURRENT_LIST_DIR}/test.c
|
||||||
)
|
)
|
||||||
|
|
||||||
pico_set_program_name(pico-hf-oscillator-test "pico-hf-oscillator-test")
|
pico_set_program_name(pico-hf-oscillator-test "pico-hf-oscillator-test")
|
||||||
pico_set_program_version(pico-hf-oscillator-test "0.9")
|
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)
|
pico_enable_stdio_usb(pico-hf-oscillator-test 1)
|
||||||
|
|
||||||
# Add the standard include files to the build
|
# Add the standard include files to the build
|
||||||
target_include_directories(pico-hf-oscillator-test PRIVATE
|
target_include_directories(pico-hf-oscillator-test PRIVATE
|
||||||
${CMAKE_CURRENT_LIST_DIR}
|
${CMAKE_CURRENT_LIST_DIR}
|
||||||
${CMAKE_CURRENT_LIST_DIR}/gpstime
|
${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
|
# Add any user requested libraries
|
||||||
|
@ -63,7 +58,7 @@ target_link_libraries(
|
||||||
hardware_timer
|
hardware_timer
|
||||||
hardware_clocks
|
hardware_clocks
|
||||||
hardware_pio
|
hardware_pio
|
||||||
hardware_vreg
|
#hardware_vreg
|
||||||
)
|
)
|
||||||
|
|
||||||
pico_add_extra_outputs(pico-hf-oscillator-test)
|
pico_add_extra_outputs(pico-hf-oscillator-test)
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
|
@ -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 |
|
@ -63,22 +63,25 @@
|
||||||
static GPStimeContext *spGPStimeContext = NULL;
|
static GPStimeContext *spGPStimeContext = NULL;
|
||||||
static GPStimeData *spGPStimeData = 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)
|
GPStimeContext *GPStimeInit(int uart_id, int uart_baud, int pps_gpio)
|
||||||
{
|
{
|
||||||
ASSERT_(0 == uart_id || 1 == uart_id);
|
ASSERT_(0 == uart_id || 1 == uart_id);
|
||||||
ASSERT_(uart_baud <= 115200);
|
ASSERT_(uart_baud <= 115200);
|
||||||
ASSERT_(pps_gpio < 29);
|
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);
|
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 ? 8 : 12, GPIO_FUNC_UART);
|
||||||
gpio_set_function(uart_id ? 9 : 13, GPIO_FUNC_UART);
|
gpio_set_function(uart_id ? 9 : 13, GPIO_FUNC_UART);
|
||||||
|
|
||||||
GPStimeContext *pgt = calloc(1, sizeof(GPStimeContext));
|
GPStimeContext *pgt = calloc(1, sizeof(GPStimeContext));
|
||||||
ASSERT_(pgt);
|
ASSERT_(pgt);
|
||||||
|
|
||||||
pgt->_uart_id = uart_id;
|
pgt->_uart_id = uart_id;
|
||||||
pgt->_uart_baudrate = uart_baud;
|
pgt->_uart_baudrate = uart_baud;
|
||||||
pgt->_pps_gpio = pps_gpio;
|
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_dir(pps_gpio, GPIO_IN);
|
||||||
gpio_set_irq_enabled_with_callback(pps_gpio, GPIO_IRQ_EDGE_RISE, true, &GPStimePPScallback);
|
gpio_set_irq_enabled_with_callback(pps_gpio, GPIO_IRQ_EDGE_RISE, true, &GPStimePPScallback);
|
||||||
|
|
||||||
irq_set_exclusive_handler(UART0_IRQ, GPStimeUartRxIsr);
|
irq_set_exclusive_handler(uart_id ? UART1_IRQ : UART0_IRQ, GPStimeUartRxIsr);
|
||||||
irq_set_enabled(UART0_IRQ, true);
|
irq_set_enabled(uart_id ? UART1_IRQ : UART0_IRQ, true);
|
||||||
uart_set_irq_enables(uart0, true, false);
|
uart_set_irq_enables(uart_id ? uart1 : uart0, true, false);
|
||||||
|
|
||||||
return pgt;
|
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)
|
void GPStimeDestroy(GPStimeContext **pp)
|
||||||
{
|
{
|
||||||
ASSERT_(pp);
|
ASSERT_(pp);
|
||||||
|
@ -107,7 +113,9 @@ void GPStimeDestroy(GPStimeContext **pp)
|
||||||
*pp = NULL;
|
*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();
|
const uint64_t tm64 = GetUptime64();
|
||||||
if(spGPStimeData)
|
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 pg Ptr to the context.
|
||||||
/// @param u32_tmdst Ptr to destination unixtime val.
|
/// @param u32_tmdst Ptr to destination unixtime val.
|
||||||
/// @return 0 if OK.
|
/// @return 0 if OK.
|
||||||
|
@ -177,7 +185,8 @@ int GPStimeGetTime(const GPStimeContext *pg, uint32_t *u32_tmdst)
|
||||||
return 0;
|
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)
|
if(spGPStimeContext)
|
||||||
{
|
{
|
||||||
|
@ -194,11 +203,17 @@ void __not_in_flash_func (GPStimeUartRxIsr)()
|
||||||
{
|
{
|
||||||
spGPStimeContext->_u8_ixw = 0;
|
spGPStimeContext->_u8_ixw = 0;
|
||||||
spGPStimeContext->_i32_error_count -= GPStimeProcNMEAsentence(spGPStimeContext);
|
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)
|
int GPStimeProcNMEAsentence(GPStimeContext *pg)
|
||||||
{
|
{
|
||||||
assert_(pg);
|
assert_(pg);
|
||||||
|
@ -207,7 +222,6 @@ int GPStimeProcNMEAsentence(GPStimeContext *pg)
|
||||||
if(prmc)
|
if(prmc)
|
||||||
{
|
{
|
||||||
uint64_t tm_fix = GetUptime64();
|
uint64_t tm_fix = GetUptime64();
|
||||||
|
|
||||||
uint8_t u8ixcollector[16] = {0};
|
uint8_t u8ixcollector[16] = {0};
|
||||||
uint8_t chksum = 0;
|
uint8_t chksum = 0;
|
||||||
for(uint8_t u8ix = 0, i = 0; u8ix != sizeof(pg->_pbytebuff); ++u8ix)
|
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._u32_utime_nmea_last = GPStime2UNIX(prmc + u8ixcollector[8], prmc + u8ixcollector[0]);
|
||||||
pg->_time_data._u64_sysclk_nmea_last = tm_fix;
|
pg->_time_data._u64_sysclk_nmea_last = tm_fix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
++pg->_time_data._u32_nmea_gprmc_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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)
|
uint32_t GPStime2UNIX(const char *pdate, const char *ptime)
|
||||||
{
|
{
|
||||||
assert_(pdate);
|
assert_(pdate);
|
||||||
|
@ -291,17 +307,18 @@ uint32_t GPStime2UNIX(const char *pdate, const char *ptime)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Dumps the GPS data struct to stdio.
|
||||||
|
/// @param pd Ptr to Context.
|
||||||
void GPStimeDump(const GPStimeData *pd)
|
void GPStimeDump(const GPStimeData *pd)
|
||||||
{
|
{
|
||||||
assert_(pd);
|
assert_(pd);
|
||||||
|
|
||||||
static int tick = 0;
|
printf("\nGPS solution is active:%u\n", pd->_u8_is_solution_active);
|
||||||
|
printf("GPRMC count:%lu\n", pd->_u32_nmea_gprmc_count);
|
||||||
printf("%u\nActive:%u\n", tick++, pd->_u8_is_solution_active);
|
printf("NMEA unixtime last:%lu\n", pd->_u32_utime_nmea_last);
|
||||||
printf("NMEA utime last:%lu\n", pd->_u32_utime_nmea_last);
|
printf("NMEA sysclock last:%llu\n", pd->_u64_sysclk_nmea_last);
|
||||||
printf("SYSCKL NMEA last:%llu\n", pd->_u64_sysclk_nmea_last);
|
printf("GPS Latitude:%lld Longtitude:%lld\n", pd->_i64_lat_100k, pd->_i64_lon_100k);
|
||||||
printf("Lat:%lld Lon:%lld\n", pd->_i64_lat_100k, pd->_i64_lon_100k);
|
printf("PPS sysclock last:%llu\n", pd->_u64_sysclk_pps_last);
|
||||||
printf("SYSCKL PPS last:%llu\n", pd->_u64_sysclk_pps_last);
|
printf("PPS period *1e6:%llu\n", (pd->_u64_pps_period_1M + (eSlidingLen>>1)) / eSlidingLen);
|
||||||
printf("PPS period e6:%llu\n", (pd->_u64_pps_period_1M + (eSlidingLen>>1)) / eSlidingLen);
|
printf("FRQ correction ppb:%lld\n\n", pd->_i32_freq_shift_ppb);
|
||||||
printf("FRQ corr ppb:%lld\n\n", pd->_i32_freq_shift_ppb);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,6 +89,7 @@ typedef struct
|
||||||
uint32_t _u32_utime_nmea_last; /* The last unix time received from GPS. */
|
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. */
|
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. */
|
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_sysclk_pps_last; /* The sysclk of the last rising edge of PPS. */
|
||||||
uint64_t _u64_pps_period_1M; /* The PPS avg. period *1e6, filtered. */
|
uint64_t _u64_pps_period_1M; /* The PPS avg. period *1e6, filtered. */
|
||||||
|
@ -120,8 +121,8 @@ void GPStimeDestroy(GPStimeContext **pp);
|
||||||
|
|
||||||
int GPStimeProcNMEAsentence(GPStimeContext *pg);
|
int GPStimeProcNMEAsentence(GPStimeContext *pg);
|
||||||
|
|
||||||
void __not_in_flash_func (GPStimePPScallback)(uint gpio, uint32_t events);
|
void RAM (GPStimePPScallback)(uint gpio, uint32_t events);
|
||||||
void __not_in_flash_func (GPStimeUartRxIsr)();
|
void RAM (GPStimeUartRxIsr)();
|
||||||
|
|
||||||
int GPStimeGetTime(const GPStimeContext *pg, uint32_t *u32_tmdst);
|
int GPStimeGetTime(const GPStimeContext *pg, uint32_t *u32_tmdst);
|
||||||
uint32_t GPStime2UNIX(const char *pdate, const char *ptime);
|
uint32_t GPStime2UNIX(const char *pdate, const char *ptime);
|
||||||
|
|
|
@ -27,4 +27,11 @@ inline uint32_t DecimalStr2ToNumber(const char *p)
|
||||||
return 10U * (p[0] - '0') + (p[1] - '0');
|
return 10U * (p[0] - '0') + (p[1] - '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void PRN32(uint32_t *val)
|
||||||
|
{
|
||||||
|
*val ^= *val << 13;
|
||||||
|
*val ^= *val >> 17;
|
||||||
|
*val ^= *val << 5;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
|
|
||||||
#include "build/dco.pio.h"
|
#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.
|
/// @brief Initializes DCO context and prepares PIO hardware.
|
||||||
/// @param pdco Ptr to DCO context.
|
/// @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.
|
/// @brief Sets DCO working frequency in Hz: Fout = ui32_frq_hz + ui32_frq_millihz * 1e-3.
|
||||||
/// @param pdco Ptr to DCO context.
|
/// @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].
|
/// @param ui32_frq_millihz The `fine` part of frequency [Hz].
|
||||||
/// @return 0 if OK. -1 invalid freq.
|
/// @return 0 if OK. -1 invalid freq.
|
||||||
/// @attention The func can be called while DCO running.
|
/// @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);
|
||||||
assert(pdco->_clkfreq_hz);
|
assert(pdco->_clkfreq_hz);
|
||||||
|
@ -121,6 +121,38 @@ int PioDCOSetFreq(PioDco *pdco, uint32_t ui32_frq_hz, uint32_t ui32_frq_millihz)
|
||||||
return 0;
|
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.
|
/// @brief Starts the DCO.
|
||||||
/// @param pdco Ptr to DCO context.
|
/// @param pdco Ptr to DCO context.
|
||||||
void PioDCOStart(PioDco *pdco)
|
void PioDCOStart(PioDco *pdco)
|
||||||
|
@ -163,10 +195,9 @@ void RAM (PioDCOWorker)(PioDco *pDCO)
|
||||||
DCO cycle, corrected by accumulated error (feedback of the PLL). */
|
DCO cycle, corrected by accumulated error (feedback of the PLL). */
|
||||||
const int32_t i32wc = iSAR32(i32reg - i32acc_error + (1<<23), 24);
|
const int32_t i32wc = iSAR32(i32reg - i32acc_error + (1<<23), 24);
|
||||||
|
|
||||||
/* RPix: Calculate the difference btw calculated value scaled to
|
/* RPix: Calculate the difference betwixt calculated value scaled to
|
||||||
`fine` state and precise value of DCO cycles per CPU CLK cycle.
|
fine resolution back and precise value of DCO cycles per CPU CLK cycle.
|
||||||
This forms a phase locked loop which provides precise freq
|
This forms a phase locked loop which provides precise freq */
|
||||||
on long run. */
|
|
||||||
i32acc_error += (i32wc<<24) - i32reg;
|
i32acc_error += (i32wc<<24) - i32reg;
|
||||||
|
|
||||||
/* RPix: Set PIO array contents corrected by pio program delay
|
/* RPix: Set PIO array contents corrected by pio program delay
|
||||||
|
@ -181,9 +212,23 @@ void RAM (PioDCOWorker)(PioDco *pDCO)
|
||||||
/// @brief Sets DCO running mode.
|
/// @brief Sets DCO running mode.
|
||||||
/// @param pdco Ptr to DCO context.
|
/// @param pdco Ptr to DCO context.
|
||||||
/// @param emode Desired mode.
|
/// @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)
|
void PioDCOSetMode(PioDco *pdco, enum PioDcoMode emode)
|
||||||
{
|
{
|
||||||
assert_(pdco);
|
assert_(pdco);
|
||||||
pdco->_mode = emode;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,12 +72,12 @@
|
||||||
|
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
|
|
||||||
|
#include "../gpstime/GPStime.h"
|
||||||
|
|
||||||
enum PioDcoMode
|
enum PioDcoMode
|
||||||
{
|
{
|
||||||
eDCOMODE_IDLE = 0,
|
eDCOMODE_IDLE = 0, /* No output. */
|
||||||
eDCOMODE_FREERUN = 1,
|
eDCOMODE_GPS_COMPENSATED= 2 /* Internally compensated, if GPS available. */
|
||||||
eDCOMODE_GPS_REFERENCE = 2,
|
|
||||||
eDCOMODE_THERMO_COMPENSATION = 3
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -97,10 +97,13 @@ typedef struct
|
||||||
|
|
||||||
uint32_t _clkfreq_hz; /* CPU CLK freq, Hz. */
|
uint32_t _clkfreq_hz; /* CPU CLK freq, Hz. */
|
||||||
|
|
||||||
|
GPStimeContext *_pGPStime; /* Ptr to GPS time context. */
|
||||||
|
|
||||||
} PioDco;
|
} PioDco;
|
||||||
|
|
||||||
int PioDCOInit(PioDco *pdco, int gpio, int cpuclkhz);
|
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 PioDCOStart(PioDco *pdco);
|
||||||
void PioDCOStop(PioDco *pdco);
|
void PioDCOStop(PioDco *pdco);
|
||||||
|
|
66
test.c
66
test.c
|
@ -79,14 +79,14 @@
|
||||||
#include "pico/stdio/driver.h"
|
#include "pico/stdio/driver.h"
|
||||||
|
|
||||||
#include "./lib/assert.h"
|
#include "./lib/assert.h"
|
||||||
|
#include "./debug/logutils.h"
|
||||||
#include "hwdefs.h"
|
#include "hwdefs.h"
|
||||||
|
|
||||||
#include <GPStime.h>
|
#include <GPStime.h>
|
||||||
|
|
||||||
#define GEN_FRQ_HZ 9400000L
|
#define GEN_FRQ_HZ 9400000L
|
||||||
|
|
||||||
PioDco DCO;
|
PioDco DCO; /* External in order to access in both cores. */
|
||||||
void PRN32(uint32_t *val);
|
|
||||||
|
|
||||||
/* This is the code of dedicated core.
|
/* This is the code of dedicated core.
|
||||||
We deal with extremely precise real-time task. */
|
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()
|
int main()
|
||||||
{
|
{
|
||||||
const uint32_t clkhz = PLL_SYS_MHZ * 1000000L;
|
const uint32_t clkhz = PLL_SYS_MHZ * 1000000L;
|
||||||
|
@ -218,14 +259,8 @@ int main()
|
||||||
stdio_init_all();
|
stdio_init_all();
|
||||||
sleep_ms(1000);
|
sleep_ms(1000);
|
||||||
printf("Start\n");
|
printf("Start\n");
|
||||||
|
|
||||||
GPStimeContext *pGPS = GPStimeInit(0, 9600, 2);
|
/*
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
GPStimeDump(&(pGPS->_time_data));
|
|
||||||
sleep_ms(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
char ch = uart_getc(uart0);
|
char ch = uart_getc(uart0);
|
||||||
|
@ -236,22 +271,17 @@ int main()
|
||||||
stdio_set_driver_enabled(&stdio_uart, true);
|
stdio_set_driver_enabled(&stdio_uart, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
gpio_init(PICO_DEFAULT_LED_PIN);
|
gpio_init(PICO_DEFAULT_LED_PIN);
|
||||||
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
||||||
|
|
||||||
multicore_launch_core1(core1_entry);
|
multicore_launch_core1(core1_entry);
|
||||||
|
|
||||||
//SpinnerSweepTest();
|
//SpinnerSweepTest();
|
||||||
SpinnerMFSKTest();
|
//SpinnerMFSKTest();
|
||||||
//SpinnerRTTYTest();
|
//SpinnerRTTYTest();
|
||||||
//SpinnerMilliHertzTest();
|
//SpinnerMilliHertzTest();
|
||||||
//SpinnerWide4FSKTest();
|
//SpinnerWide4FSKTest();
|
||||||
|
SpinnerGPSreferenceTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PRN32(uint32_t *val)
|
|
||||||
{
|
|
||||||
*val ^= *val << 13;
|
|
||||||
*val ^= *val >> 17;
|
|
||||||
*val ^= *val << 5;
|
|
||||||
}
|
|
||||||
|
|
Ładowanie…
Reference in New Issue