Files @ b295af18d965
Branch filter:

Location: FeatherHAB/wsprhab/src/main.c

Ethan Zonca
Start transmitting on all even minutes!
//
// WSPRHAB: Minimal high-altitude balloon tracker with WSPR telemetry
//

#include "stm32f0xx_hal.h"
#include "si5351.h"
#include "jtencode.h"
#include "adc.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"
#include "gps.h"

#define WSPR_DEFAULT_FREQ 10140100UL
#define WSPR_TONE_SPACING 146 // ~1.46 Hz
#define WSPR_CTC 10672 // CTC value for WSPR

// Private functions
void sysclk_init(void);
void enter_sleep(void);
void enter_deepsleep(void);

// Test stuff
char call[7] = "KD8TDF";
char loc[5] = "EN72";
uint8_t dbm = 10;
uint8_t tx_buffer[255];

// Frequencies and channel info
uint32_t freq = WSPR_DEFAULT_FREQ;
uint8_t symbol_count = WSPR_SYMBOL_COUNT;
uint16_t ctc = WSPR_CTC;
uint16_t tone_spacing = WSPR_TONE_SPACING;
volatile uint8_t proceed = 0;

// Bring up TCXO and oscillator IC
void encode_wspr(void)
{
    HAL_GPIO_WritePin(OSC_NOTEN, 0);
    HAL_GPIO_WritePin(TCXO_EN, 1);
    HAL_Delay(100);

    // Bring up the chip
    si5351_init(i2c_get(), SI5351_CRYSTAL_LOAD_8PF, 0);
    si5351_set_correction(0);
    //si5351_set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
    //si5351_set_ms_source(SI5351_CLK0, SI5351_PLLA);
    si5351_set_freq(WSPR_DEFAULT_FREQ * 100, 0, SI5351_CLK0);
    si5351_drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); // Set for max power if desired (8ma max)
    si5351_output_enable(SI5351_CLK0, 1);
    //si5351_pll_reset(SI5351_PLLA);

    // Make sure the other outputs of the SI5351 are disabled
    si5351_output_enable(SI5351_CLK1, 0); // Disable the clock initially
    si5351_output_enable(SI5351_CLK2, 0); // Disable the clock initially

    // disable clock powers
    si5351_set_clock_pwr(SI5351_CLK1, 0);
    si5351_set_clock_pwr(SI5351_CLK2, 0);


    // Encode message to transmit
    wspr_encode(call, loc, dbm, tx_buffer);

    // Key transmitter
    si5351_output_enable(SI5351_CLK0, 1);

    // Loop through and transmit symbols TODO: Do this from an ISR or ISR-triggered main loop function call (optimal)
    uint8_t i;
    for(i=0; i<symbol_count; i++)
    {
        uint32_t freq2 = (freq * 100) + (tx_buffer[i] * tone_spacing);
        si5351_set_freq(freq2, 0, SI5351_CLK0);
        HAL_GPIO_TogglePin(LED_BLUE);

        proceed = 0;
        while(!proceed);
    }

    // Disable transmitter
    si5351_output_enable(SI5351_CLK0, 0);

    HAL_GPIO_WritePin(OSC_NOTEN, 1);
    HAL_GPIO_WritePin(TCXO_EN, 0);
}


TIM_HandleTypeDef htim1;

int main(void)
{
    HAL_Init();

    sysclk_init();
    gpio_init();
    adc_init();
    i2c_init();
    gps_init();

    //jtencode_init();

    HAL_Delay(300);

    // Turn GPS on
    HAL_GPIO_WritePin(GPS_NOTEN, 0);

    // Disable ICs
    HAL_GPIO_WritePin(OSC_NOTEN, 1);
    HAL_GPIO_WritePin(TCXO_EN, 0);

    HAL_GPIO_TogglePin(LED_BLUE);

    // Start timer for WSPR
    __TIM1_CLK_ENABLE();
    htim1.Instance = TIM1;
    htim1.Init.Prescaler = 512; // gives 64uS ticks from 8MHz ahbclk
    htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim1.Init.Period = ctc; // Count up to this value (how many 64uS ticks per symbol)
    htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim1.Init.RepetitionCounter = 0;
    HAL_TIM_Base_Init(&htim1);
    HAL_TIM_Base_Start_IT(&htim1);
    HAL_NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);


    uint32_t led_timer = HAL_GetTick();
    uint32_t last_gps  = HAL_GetTick();
    uint32_t last_wspr  = HAL_GetTick(); //0xfffff; // start immediately.

    HAL_GPIO_TogglePin(LED_BLUE);
    HAL_Delay(100);
    HAL_GPIO_TogglePin(LED_BLUE);
    HAL_Delay(100);
    HAL_GPIO_TogglePin(LED_BLUE);
    HAL_Delay(100);
    HAL_GPIO_TogglePin(LED_BLUE);
    HAL_Delay(100);

    uint8_t lastMinute = 0;

    while (1)
    {
        if(HAL_GetTick() - last_wspr > 500)
        {
            volatile uint8_t minute = get_timestamp()[3] - 0x30;

            // If last minute was odd and this minute is even (transition)
            if(lastMinute%2 == 1 && minute%2 == 0)
                encode_wspr();

            lastMinute = minute;
            last_wspr = HAL_GetTick();
        }

        if(HAL_GetTick() - led_timer > 100)
        {
            HAL_GPIO_TogglePin(LED_BLUE);
            led_timer = HAL_GetTick();
        }
        if(HAL_GetTick() - last_gps > 10)
        {
            parse_gps_transmission();
            last_gps = HAL_GetTick();
        }

        //enter_sleep();
    }
}


void enter_sleep(void)
{
    //HAL_SuspendTick();
    HAL_TIM_Base_Stop_IT(&htim1);
    HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
    HAL_TIM_Base_Start_IT(&htim1);
    //HAL_ResumeTick();
}


void enter_deepsleep(void) 
{
    // Request to enter STOP mode with regulator in low power mode
    HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
    // After wake-up from STOP reconfigure the PLL
    sysclk_init();
}


// Initialize system clocks
void sysclk_init(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct;
    RCC_ClkInitTypeDef RCC_ClkInitStruct;
    RCC_PeriphCLKInitTypeDef PeriphClkInit;

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSI14;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.HSI14State = RCC_HSI14_ON;
    RCC_OscInitStruct.HSICalibrationValue = 16;
    RCC_OscInitStruct.HSI14CalibrationValue = 16;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                                |RCC_CLOCKTYPE_PCLK1;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);

    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_I2C1;
    PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_SYSCLK; //RCC_USART1CLKSOURCE_PCLK1;
    PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_SYSCLK;
    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);

    HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

    __SYSCFG_CLK_ENABLE();
    // SysTick_IRQn interrupt configuration 
    HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}