diff --git a/CMakeLists.txt b/CMakeLists.txt index 11b7072..4f8ffdc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 ) diff --git a/TxChannel/TxChannel.c b/TxChannel/TxChannel.c index ca5ed08..4b5c96e 100644 --- a/TxChannel/TxChannel.c +++ b/TxChannel/TxChannel.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<_timer_alarm_num); - timer_hw->alarm[pTX->_timer_alarm_num] = (uint32_t)pTX->_tm_future_call; + hw_clear_bits(&timer_hw->intr, 1U<_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; +} diff --git a/TxChannel/TxChannel.h b/TxChannel/TxChannel.h index ec0d3cd..a0d027f 100644 --- a/TxChannel/TxChannel.h +++ b/TxChannel/TxChannel.h @@ -55,6 +55,7 @@ #include "hardware/clocks.h" #include "pico/stdlib.h" #include "../pico-hf-oscillator/lib/assert.h" +#include #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 diff --git a/WSPRbeacon/WSPRbeacon.c b/WSPRbeacon/WSPRbeacon.c index 34b83d4..22b8a4f 100644 --- a/WSPRbeacon/WSPRbeacon.c +++ b/WSPRbeacon/WSPRbeacon.c @@ -3,8 +3,10 @@ #include 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; +} diff --git a/WSPRbeacon/WSPRbeacon.h b/WSPRbeacon/WSPRbeacon.h index 004a62c..40ad7a1 100644 --- a/WSPRbeacon/WSPRbeacon.h +++ b/WSPRbeacon/WSPRbeacon.h @@ -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 diff --git a/core1.c b/core1.c new file mode 100644 index 0000000..462c48b --- /dev/null +++ b/core1.c @@ -0,0 +1,28 @@ + +#include + +#include "pico-hf-oscillator/lib/assert.h" +#include +#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); +} diff --git a/defines.h b/defines.h index b79cc40..292a693 100644 --- a/defines.h +++ b/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 diff --git a/init.c b/init.c new file mode 100644 index 0000000..2f7ecbf --- /dev/null +++ b/init.c @@ -0,0 +1,22 @@ +#include +#include +#include + +#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); +} diff --git a/main.c b/main.c index 2deab71..132f180 100644 --- a/main.c +++ b/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; -} \ No newline at end of file +}