kopia lustrzana https://github.com/RPiks/pico-WSPR-tx
First WSPR-modulated emission. Start checking.
rodzic
6c5ad458ce
commit
78a9431387
|
@ -29,13 +29,18 @@ pico_sdk_init()
|
|||
|
||||
add_executable(pico-wspr-tx)
|
||||
|
||||
pico_generate_pio_header(pico-wspr-tx ${CMAKE_CURRENT_LIST_DIR}/pico-hf-oscillator/piodco/dco.pio)
|
||||
|
||||
target_sources(pico-wspr-tx PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-hf-oscillator/lib/assert.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/pico-hf-oscillator/piodco/piodco.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/TxChannel/TxChannel.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/WSPRbeacon/thirdparty/WSPRutility.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/WSPRbeacon/thirdparty/nhash.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/WSPRbeacon/WSPRbeacon.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/debug/logutils.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/init.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/core1.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/main.c
|
||||
)
|
||||
|
||||
|
|
|
@ -49,22 +49,28 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "TxChannel.h"
|
||||
|
||||
TxChannelContext *pTX = NULL;
|
||||
|
||||
void __not_in_flash_func (TxChannelISR)(void)
|
||||
static TxChannelContext *spTX = NULL;
|
||||
static void __not_in_flash_func (TxChannelISR)(void)
|
||||
{
|
||||
if(!pTX)
|
||||
PioDco *pDCO = spTX->_p_oscillator;
|
||||
|
||||
uint8_t byte;
|
||||
const int n2send = TxChannelPop(spTX, &byte);
|
||||
if(n2send)
|
||||
{
|
||||
pTX->_tm_future_call += 500LL;
|
||||
goto EXIT;
|
||||
PioDCOSetFreq(pDCO, spTX->_u32_dialfreqhz,
|
||||
byte * FREQ_STEP_MILLIHERTZ);
|
||||
}
|
||||
|
||||
pTX->_pf_modulator(FREQ_STEP_MILLIHERTZ, pTX->_u8byte_buffer[pTX->_ix_output++]);
|
||||
pTX->_tm_future_call += pTX->_bit_period_us;
|
||||
spTX->_tm_future_call += spTX->_bit_period_us;
|
||||
|
||||
EXIT:
|
||||
hw_clear_bits(&timer_hw->intr, 1U<<pTX->_timer_alarm_num);
|
||||
timer_hw->alarm[pTX->_timer_alarm_num] = (uint32_t)pTX->_tm_future_call;
|
||||
hw_clear_bits(&timer_hw->intr, 1U<<spTX->_timer_alarm_num);
|
||||
timer_hw->alarm[spTX->_timer_alarm_num] = (uint32_t)spTX->_tm_future_call;
|
||||
|
||||
/* LED debug signal */
|
||||
static int tick = 0;
|
||||
gpio_put(PICO_DEFAULT_LED_PIN, ++tick & 1);
|
||||
}
|
||||
|
||||
/// @brief Initializes a TxChannel context. Starts ISR.
|
||||
|
@ -73,25 +79,70 @@ EXIT:
|
|||
/// @param pfmodulator Ptr to low level real-time modulator function.
|
||||
/// @return the Context.
|
||||
TxChannelContext *TxChannelInit(const uint32_t bit_period_us, uint8_t timer_alarm_num,
|
||||
void *pfmodulator)
|
||||
PioDco *pDCO)
|
||||
{
|
||||
assert_(pfmodulator);
|
||||
assert_(pDCO);
|
||||
assert_(bit_period_us > 10);
|
||||
|
||||
TxChannelContext *p = calloc(1, sizeof(TxChannelContext));
|
||||
assert_(p);
|
||||
|
||||
spTX = p;
|
||||
|
||||
p->_bit_period_us = bit_period_us;
|
||||
p->_timer_alarm_num = timer_alarm_num;
|
||||
p->_pf_modulator = pfmodulator;
|
||||
p->_p_oscillator = pDCO;
|
||||
|
||||
hw_set_bits(&timer_hw->inte, 1U << p->_timer_alarm_num);
|
||||
irq_set_exclusive_handler(TIMER_IRQ_0, TxChannelISR);
|
||||
irq_set_priority(TIMER_IRQ_0, 0x00);
|
||||
irq_set_enabled(TIMER_IRQ_0, true);
|
||||
|
||||
p->_tm_future_call = timer_hw->timerawl + 500LL;
|
||||
p->_tm_future_call = timer_hw->timerawl + 10000LL;
|
||||
timer_hw->alarm[p->_timer_alarm_num] = (uint32_t)p->_tm_future_call;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
uint8_t TxChannelPending(TxChannelContext *pctx)
|
||||
{
|
||||
return 256 + pctx->_ix_input - pctx->_ix_output;
|
||||
}
|
||||
|
||||
int TxChannelPush(TxChannelContext *pctx, uint8_t *psrc, int n)
|
||||
{
|
||||
uint8_t *pdst = pctx->_pbyte_buffer;
|
||||
while(n-- && pctx->_ix_input != pctx->_ix_output)
|
||||
{
|
||||
pdst[pctx->_ix_input++] = *psrc++;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int TxChannelPop(TxChannelContext *pctx, uint8_t *pdst)
|
||||
{
|
||||
if(pctx->_ix_input != pctx->_ix_output)
|
||||
{
|
||||
*pdst = pctx->_pbyte_buffer[pctx->_ix_output++];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TxChannelClear(TxChannelContext *pctx)
|
||||
{
|
||||
pctx->_ix_input = pctx->_ix_output = 0;
|
||||
}
|
||||
|
||||
void TxChannelStart(TxChannelContext *pctx)
|
||||
{
|
||||
pctx->_b_allowtx = YES;
|
||||
}
|
||||
|
||||
void TxChannelStop(TxChannelContext *pctx)
|
||||
{
|
||||
pctx->_b_allowtx = NO;
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "hardware/clocks.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include "../pico-hf-oscillator/lib/assert.h"
|
||||
#include <piodco.h>
|
||||
|
||||
#define FREQ_STEP_MILLIHERTZ 1465
|
||||
|
||||
|
@ -64,17 +65,24 @@ typedef struct
|
|||
uint32_t _bit_period_us;
|
||||
|
||||
uint8_t _timer_alarm_num;
|
||||
uint8_t _b_allowtx;
|
||||
|
||||
uint8_t _u8byte_buffer[256];
|
||||
uint8_t _ix_input, _ix_output;
|
||||
uint8_t _pbyte_buffer[256];
|
||||
|
||||
int (*_pf_modulator)(uint32_t frq_step, uint8_t shift_val);
|
||||
int (*_pf_setPTT)(uint8_t bptt_state);
|
||||
PioDco *_p_oscillator;
|
||||
uint32_t _u32_dialfreqhz;
|
||||
|
||||
} TxChannelContext;
|
||||
|
||||
TxChannelContext *TxChannelInit(const uint32_t bit_period_us, uint8_t timer_alarm_num,
|
||||
void *pfmodulator);
|
||||
void __not_in_flash_func (TxChannelISR)(void);
|
||||
TxChannelContext *TxChannelInit(const uint32_t bit_period_us,
|
||||
uint8_t timer_alarm_num, PioDco *pDCO);
|
||||
|
||||
uint8_t TxChannelPending(TxChannelContext *pctx);
|
||||
int TxChannelPush(TxChannelContext *pctx, uint8_t *psrc, int n);
|
||||
int TxChannelPop(TxChannelContext *pctx, uint8_t *pdst);
|
||||
void TxChannelClear(TxChannelContext *pctx);
|
||||
void TxChannelStart(TxChannelContext *pctx);
|
||||
void TxChannelStop(TxChannelContext *pctx);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
#include <WSPRutility.h>
|
||||
|
||||
WSPRbeaconContext *WSPRbeaconInit(const char *pcallsign, const char *pgridsquare, int txpow_dbm,
|
||||
void *pfsk4modulator)
|
||||
PioDco *pdco)
|
||||
{
|
||||
assert_(pdco);
|
||||
|
||||
WSPRbeaconContext *p = calloc(1, sizeof(WSPRbeaconContext));
|
||||
assert_(p);
|
||||
|
||||
|
@ -12,7 +14,7 @@ WSPRbeaconContext *WSPRbeaconInit(const char *pcallsign, const char *pgridsquare
|
|||
strncpy(p->_pu8_locator, pgridsquare, sizeof(p->_pu8_locator));
|
||||
p->_u8_txpower = txpow_dbm;
|
||||
|
||||
p->_pTX = TxChannelInit(682667, 0, pfsk4modulator);
|
||||
p->_pTX = TxChannelInit(682667, 0, pdco);
|
||||
assert_(p->_pTX);
|
||||
|
||||
return p;
|
||||
|
@ -21,7 +23,7 @@ WSPRbeaconContext *WSPRbeaconInit(const char *pcallsign, const char *pgridsquare
|
|||
void WSPRbeaconSetDialFreq(WSPRbeaconContext *pctx, uint32_t freq_hz)
|
||||
{
|
||||
assert_(pctx);
|
||||
pctx->_u32_dialfreqhz = freq_hz;
|
||||
pctx->_pTX->_u32_dialfreqhz = freq_hz;
|
||||
}
|
||||
|
||||
int WSPRbeaconCreatePacket(WSPRbeaconContext *pctx)
|
||||
|
@ -30,3 +32,13 @@ int WSPRbeaconCreatePacket(WSPRbeaconContext *pctx)
|
|||
|
||||
wspr_encode(pctx->_pu8_callsign, pctx->_pu8_locator, pctx->_u8_txpower, pctx->_pu8_outbuf);
|
||||
}
|
||||
|
||||
int WSPRbeaconSendPacket(const WSPRbeaconContext *pctx)
|
||||
{
|
||||
assert_(pctx);
|
||||
assert_(pctx->_pTX);
|
||||
assert_(pctx->_pTX->_u32_dialfreqhz > 1100 * kHz);
|
||||
|
||||
memcpy(pctx->_pTX->_pbyte_buffer, pctx->_pu8_outbuf, WSPR_SYMBOL_COUNT);
|
||||
pctx->_pTX->_ix_input += WSPR_SYMBOL_COUNT;
|
||||
}
|
||||
|
|
|
@ -14,16 +14,13 @@ typedef struct
|
|||
uint8_t _pu8_outbuf[256];
|
||||
|
||||
TxChannelContext *_pTX;
|
||||
uint32_t _u32_dialfreqhz;
|
||||
|
||||
} WSPRbeaconContext;
|
||||
|
||||
WSPRbeaconContext *WSPRbeaconInit(const char *pcallsign, const char *pgridsquare, int txpow_dbm,
|
||||
void *pfsk4modulator);
|
||||
PioDco *pdco);
|
||||
void WSPRbeaconSetDialFreq(WSPRbeaconContext *pctx, uint32_t freq_hz);
|
||||
int WSPRbeaconCreatePacket(WSPRbeaconContext *pctx);
|
||||
int WSPRbeaconSendPacket(const WSPRbeaconContext *pctx);
|
||||
|
||||
//int WSPRbeaconFSK4mod(uint8_t bits_per_sample, uint8_t sample_val);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "pico-hf-oscillator/lib/assert.h"
|
||||
#include <piodco.h>
|
||||
#include "defines.h"
|
||||
|
||||
extern PioDco DCO;
|
||||
|
||||
/* This is the code of dedicated core.
|
||||
We deal with extremely precise real-time task. */
|
||||
void Core1Entry()
|
||||
{
|
||||
const uint32_t clkhz = PLL_SYS_MHZ * MHz;
|
||||
const uint32_t freq_hz = WSPR_DIAL_FREQ_HZ + WSPR_SHIFT_FREQ_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);
|
||||
}
|
32
defines.h
32
defines.h
|
@ -9,4 +9,36 @@
|
|||
#define DEBUGPRINTF(x) { }
|
||||
#endif
|
||||
|
||||
#define FALSE 0 /* Something is false. */
|
||||
#define TRUE 1 /* Something is true. */
|
||||
#define BAD 0 /* Something is bad. */
|
||||
#define GOOD 1 /* Something is good. */
|
||||
#define INVALID 0 /* Something is invalid. */
|
||||
#define VALID 1 /* Something is valid. */
|
||||
#define NO 0 /* The answer is no. */
|
||||
#define YES 1 /* The answer is yes. */
|
||||
#define OFF 0 /* Turn something off. */
|
||||
#define ON 1 /* Turn something on. */
|
||||
|
||||
#define RAM __not_in_flash_func /* Place time-critical func in RAM */
|
||||
#define RAM_A __not_in_flash("A") /* Place time-critical var in RAM */
|
||||
|
||||
/* A macro for arithmetic right shifts, with casting of the argument. */
|
||||
#define iSAR(arg, rcount) (((int32_t)(arg)) >> (rcount))
|
||||
|
||||
/* A macro of multiplication guarantees of doing so using 1 ASM command. */
|
||||
#define iMUL32ASM(a,b) __mul_instruction((int32_t)(a), (int32_t)(b))
|
||||
|
||||
/* Performing the square by ASM. */
|
||||
#define iSquare32ASM(x) (iMUL32ASM((x), (x)))
|
||||
|
||||
/* Hardware defs. */
|
||||
#define kHz 1000UL
|
||||
#define MHz 1000000UL
|
||||
#define PLL_SYS_MHZ 270UL
|
||||
|
||||
/* WSPR defs. */
|
||||
#define WSPR_DIAL_FREQ_HZ 7040000UL
|
||||
#define WSPR_SHIFT_FREQ_HZ 88UL
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/clocks.h"
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
void InitPicoHW(void)
|
||||
{
|
||||
gpio_init(PICO_DEFAULT_LED_PIN);
|
||||
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
||||
|
||||
const uint32_t clkhz = PLL_SYS_MHZ * 1000000L;
|
||||
set_sys_clock_khz(clkhz / kHz, true);
|
||||
|
||||
clock_configure(clk_peri, 0,
|
||||
CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
|
||||
PLL_SYS_MHZ * MHZ,
|
||||
PLL_SYS_MHZ * MHZ);
|
||||
}
|
44
main.c
44
main.c
|
@ -61,7 +61,11 @@
|
|||
|
||||
#include "debug/logutils.h"
|
||||
|
||||
PioDco DCO;
|
||||
|
||||
int FSK4mod(uint32_t frq_step_millihz, uint8_t shift_index);
|
||||
void InitPicoHW(void);
|
||||
void Core1Entry(void);
|
||||
|
||||
int main()
|
||||
{
|
||||
|
@ -69,36 +73,25 @@ int main()
|
|||
sleep_ms(1000);
|
||||
DEBUGPRINTF("Pico-WSPR-tx start.");
|
||||
|
||||
DEBUGPRINTF("WSPR beacon init...");
|
||||
WSPRbeaconContext *pWB = WSPRbeaconInit("R2BDY", "KO85", 6, FSK4mod);
|
||||
DEBUGPRINTF("OK");
|
||||
InitPicoHW();
|
||||
|
||||
DEBUGPRINTF("WSPR beacon init...");
|
||||
WSPRbeaconContext *pWB = WSPRbeaconInit("R2BDY/QRPX", "KO85", 6, &DCO);
|
||||
WSPRbeaconSetDialFreq(pWB, WSPR_DIAL_FREQ_HZ + WSPR_SHIFT_FREQ_HZ);
|
||||
DEBUGPRINTF("OK");
|
||||
|
||||
DEBUGPRINTF("Create packet...");
|
||||
WSPRbeaconCreatePacket(pWB);
|
||||
DEBUGPRINTF("OK");
|
||||
|
||||
sleep_ms(100);
|
||||
|
||||
int row = 0;
|
||||
do
|
||||
{
|
||||
for(int i = 0; i < 16; ++i)
|
||||
{
|
||||
const int j = i + row * 16;
|
||||
printf("%X ", pWB->_pu8_outbuf[j]);
|
||||
if(161 == j)
|
||||
{
|
||||
row = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
if(-1 == row)
|
||||
break;
|
||||
++row;
|
||||
DEBUGPRINTF("Start oscillator on Core #1...");
|
||||
multicore_launch_core1(Core1Entry);
|
||||
DEBUGPRINTF("OK");
|
||||
|
||||
DEBUGPRINTF("Sending WSPR packet...");
|
||||
WSPRbeaconSendPacket(pWB);
|
||||
|
||||
} while (true);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
DEBUGPRINTF("tick.");
|
||||
|
@ -108,6 +101,7 @@ int main()
|
|||
|
||||
int FSK4mod(uint32_t frq_step_millihz, uint8_t shift_index)
|
||||
{
|
||||
|
||||
PioDCOSetFreq(&DCO, WSPR_DIAL_FREQ_HZ + WSPR_SHIFT_FREQ_HZ,
|
||||
frq_step_millihz * shift_index);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue