// // 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 120000) { encode_wspr(); last_wspr = HAL_GetTick(); } if(HAL_GetTick() - led_timer > 100) { HAL_GPIO_TogglePin(LED_BLUE); led_timer = HAL_GetTick(); } if(HAL_GetTick() - last_gps > 3000) { // gps_process(); 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); }