From 5503b329e894d7f51a45fd78d59ca47db28ba770 Mon Sep 17 00:00:00 2001 From: Rob Riggs Date: Sun, 23 Feb 2020 15:58:08 -0600 Subject: [PATCH] Add passall setter. Move battery level code to demodulators because they own the ADC. --- TNC/Afsk1200Demodulator.cpp | 74 +++++++++++++++++++++++++++++++- TNC/Afsk1200Demodulator.hpp | 10 +++-- TNC/AudioInput.cpp | 85 +++++-------------------------------- TNC/AudioInput.hpp | 6 +-- TNC/Demodulator.cpp | 3 +- TNC/Demodulator.hpp | 5 ++- TNC/Fsk9600Demodulator.cpp | 73 ++++++++++++++++++++++++++++++- TNC/Fsk9600Demodulator.hpp | 12 +++--- TNC/HdlcDecoder.hpp | 4 ++ 9 files changed, 180 insertions(+), 92 deletions(-) diff --git a/TNC/Afsk1200Demodulator.cpp b/TNC/Afsk1200Demodulator.cpp index ccbef19..2d4277d 100644 --- a/TNC/Afsk1200Demodulator.cpp +++ b/TNC/Afsk1200Demodulator.cpp @@ -4,6 +4,7 @@ #include "Afsk1200Demodulator.hpp" #include "Goertzel.h" #include "AudioInput.hpp" +#include "GPIO.hpp" namespace mobilinkd { namespace tnc { @@ -85,7 +86,6 @@ hdlc::IoFrame* Afsk1200Demodulator::operator()(const q15_t* samples) float Afsk1200Demodulator::readTwist() { DEBUG("enter Afsk1200Demodulator::readTwist"); - constexpr uint32_t channel = AUDIO_IN; float g1200 = 0.0f; float g2200 = 0.0f; @@ -137,6 +137,78 @@ float Afsk1200Demodulator::readTwist() return result; } +uint32_t Afsk1200Demodulator::readBatteryLevel() +{ + DEBUG("enter Afsk1200Demodulator::readBatteryLevel"); + + ADC_ChannelConfTypeDef sConfig; + + sConfig.Channel = ADC_CHANNEL_VREFINT; + sConfig.Rank = ADC_REGULAR_RANK_1; + sConfig.SingleDiff = ADC_SINGLE_ENDED; + sConfig.SamplingTime = ADC_SAMPLETIME_92CYCLES_5; + sConfig.OffsetNumber = ADC_OFFSET_NONE; + sConfig.Offset = 0; + if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) + CxxErrorHandler(); + + htim6.Init.Period = 48000; + if (HAL_TIM_Base_Init(&htim6) != HAL_OK) CxxErrorHandler(); + + if (HAL_TIM_Base_Start(&htim6) != HAL_OK) + CxxErrorHandler(); + + if (HAL_ADC_Start(&hadc1) != HAL_OK) CxxErrorHandler(); + if (HAL_ADC_PollForConversion(&hadc1, 3) != HAL_OK) CxxErrorHandler(); + auto vrefint = HAL_ADC_GetValue(&hadc1); + if (HAL_ADC_Stop(&hadc1) != HAL_OK) CxxErrorHandler(); + + // Disable battery charging while measuring battery voltage. + auto usb_ce = gpio::USB_CE::get(); + gpio::USB_CE::on(); + + gpio::BAT_DIVIDER::off(); + HAL_Delay(1); + + sConfig.Channel = ADC_CHANNEL_15; + if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) + CxxErrorHandler(); + + uint32_t vbat = 0; + if (HAL_ADC_Start(&hadc1) != HAL_OK) CxxErrorHandler(); + for (size_t i = 0; i != 8; ++i) + { + if (HAL_ADC_PollForConversion(&hadc1, 1) != HAL_OK) CxxErrorHandler(); + vbat += HAL_ADC_GetValue(&hadc1); + } + + vbat /= 8; + + if (HAL_ADC_Stop(&hadc1) != HAL_OK) CxxErrorHandler(); + if (HAL_TIM_Base_Stop(&htim6) != HAL_OK) + CxxErrorHandler(); + + gpio::BAT_DIVIDER::on(); + + // Restore battery charging state. + if (!usb_ce) gpio::USB_CE::off(); + + INFO("Vref = %lu", vrefint); + INFO("Vbat = %lu (raw)", vbat); + + // Order of operations is important to avoid underflow. + vbat *= 6600; + vbat /= (vrefint + 1); + + uint32_t vref = (vrefint * 3300) + (VREF / 2) / VREF; + + INFO("Vref = %lumV", vref) + INFO("Vbat = %lumV", vbat); + + DEBUG("exit Afsk1200Demodulator::readBatteryLevel"); + return vbat; +} + const q15_t Afsk1200Demodulator::bpf_coeffs[FILTER_TAP_NUM] = { 4, 0, -5, -10, -13, -12, -9, -4, -2, -4, -12, -26, -41, -52, -51, -35, -3, 39, 83, 117, 131, 118, 83, 36, diff --git a/TNC/Afsk1200Demodulator.hpp b/TNC/Afsk1200Demodulator.hpp index 57dd59f..c78dee1 100644 --- a/TNC/Afsk1200Demodulator.hpp +++ b/TNC/Afsk1200Demodulator.hpp @@ -109,6 +109,8 @@ struct Afsk1200Demodulator : IDemodulator float readTwist() override; + uint32_t readBatteryLevel() override; + bool locked() const override { return locked_; @@ -119,11 +121,11 @@ struct Afsk1200Demodulator : IDemodulator return ADC_BLOCK_SIZE; } - void passall(bool enable) override + void passall(bool enabled) override { - demod1.hdlc_decoder_.passall = enable; - demod2.hdlc_decoder_.passall = enable; - demod3.hdlc_decoder_.passall = enable; + demod1.hdlc_decoder_.setPassall(enabled); + demod2.hdlc_decoder_.setPassall(enabled); + demod3.hdlc_decoder_.setPassall(enabled); } }; diff --git a/TNC/AudioInput.cpp b/TNC/AudioInput.cpp index 042f93a..8c8cb89 100644 --- a/TNC/AudioInput.cpp +++ b/TNC/AudioInput.cpp @@ -12,6 +12,7 @@ #include "PortInterface.hpp" #include "Goertzel.h" #include "DCD.h" +#include "ModulatorTask.hpp" #include "arm_math.h" #include "stm32l4xx_hal.h" @@ -113,6 +114,7 @@ extern "C" void startAudioInputTask(void const*) { case UPDATE_SETTINGS: DEBUG("UPDATE_SETTINGS"); setAudioInputLevels(); + updateModulator(); break; case IDLE: DEBUG("IDLE"); @@ -126,9 +128,9 @@ extern "C" void startAudioInputTask(void const*) { namespace mobilinkd { namespace tnc { namespace audio { uint32_t adc_buffer[ADC_BUFFER_SIZE]; // Two samples per element. -uint32_t adc_block_size = ADC_BUFFER_SIZE; // Based on demodulator. -uint32_t dma_transfer_size = adc_block_size * 2; // Transfer size in bytes. -uint32_t half_buffer_size = adc_block_size / 2; // Transfer size in words / 2. +volatile uint32_t adc_block_size = ADC_BUFFER_SIZE; // Based on demodulator. +volatile uint32_t dma_transfer_size = adc_block_size * 2; // Transfer size in bytes. +volatile uint32_t half_buffer_size = adc_block_size / 2; // Transfer size in words / 2. adc_pool_type adcPool; void set_adc_block_size(uint32_t block_size) @@ -208,7 +210,7 @@ void demodulatorTask() { } -void streamLevels(uint32_t channel, uint8_t cmd) { +void streamLevels(uint8_t cmd) { // Stream out Vpp, Vavg, Vmin, Vmax as four 16-bit values, left justified. @@ -307,7 +309,7 @@ levels_type readLevels(uint32_t) uint16_t pp = vmax - vmin; uint16_t avg = iaccum / BLOCKS; - DEBUG("exit readLevels"); + INFO("exit readLevels"); return levels_type(pp, avg, vmin, vmax); } @@ -352,7 +354,6 @@ float readTwist() void pollInputTwist() { DEBUG("enter pollInputTwist"); - constexpr uint32_t channel = AUDIO_IN; float g1200 = 0.0f; float g2200 = 0.0f; @@ -411,7 +412,7 @@ void pollInputTwist() void streamAmplifiedInputLevels() { DEBUG("enter streamAmplifiedInputLevels"); - streamLevels(AUDIO_IN, kiss::hardware::POLL_INPUT_LEVEL); + streamLevels(kiss::hardware::POLL_INPUT_LEVEL); DEBUG("exit streamAmplifiedInputLevels"); } @@ -441,72 +442,9 @@ void pollAmplifiedInputLevel() { DEBUG("exit pollAmplifiedInputLevel"); } -void pollBatteryLevel() { - DEBUG("enter pollBatteryLevel"); - - ADC_ChannelConfTypeDef sConfig; - - sConfig.Channel = ADC_CHANNEL_VREFINT; - sConfig.Rank = ADC_REGULAR_RANK_1; - sConfig.SingleDiff = ADC_SINGLE_ENDED; - sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5; - sConfig.OffsetNumber = ADC_OFFSET_NONE; - sConfig.Offset = 0; - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) - CxxErrorHandler(); - - htim6.Init.Period = 48000; - if (HAL_TIM_Base_Init(&htim6) != HAL_OK) CxxErrorHandler(); - - if (HAL_TIM_Base_Start(&htim6) != HAL_OK) - CxxErrorHandler(); - - if (HAL_ADC_Start(&hadc1) != HAL_OK) CxxErrorHandler(); - if (HAL_ADC_PollForConversion(&hadc1, 3) != HAL_OK) CxxErrorHandler(); - auto vrefint = HAL_ADC_GetValue(&hadc1); - if (HAL_ADC_Stop(&hadc1) != HAL_OK) CxxErrorHandler(); - - // Disable battery charging while measuring battery voltage. - auto usb_ce = gpio::USB_CE::get(); - gpio::USB_CE::on(); - - gpio::BAT_DIVIDER::off(); - HAL_Delay(1); - - sConfig.Channel = ADC_CHANNEL_15; - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) - CxxErrorHandler(); - - uint32_t vbat = 0; - if (HAL_ADC_Start(&hadc1) != HAL_OK) CxxErrorHandler(); - for (size_t i = 0; i != 8; ++i) - { - if (HAL_ADC_PollForConversion(&hadc1, 1) != HAL_OK) CxxErrorHandler(); - vbat += HAL_ADC_GetValue(&hadc1); - } - - vbat /= 8; - - if (HAL_ADC_Stop(&hadc1) != HAL_OK) CxxErrorHandler(); - if (HAL_TIM_Base_Stop(&htim6) != HAL_OK) - CxxErrorHandler(); - - htim6.Init.Period = 1817; - if (HAL_TIM_Base_Init(&htim6) != HAL_OK) CxxErrorHandler(); - - HAL_Delay(1); - - gpio::BAT_DIVIDER::on(); - if (!usb_ce) gpio::USB_CE::off(); // Restore battery charging state. - - INFO("Vref = %lu", vrefint); - INFO("Vbat = %lu (raw)", vbat); - - // Order of operations is important to avoid underflow. - vbat *= 6600; - vbat /= (vref + 1); - - INFO("Vbat = %lumV", vbat); +void pollBatteryLevel() +{ + auto vbat = getDemodulator()->readBatteryLevel(); uint8_t data[3]; data[0] = kiss::hardware::GET_BATTERY_LEVEL; @@ -514,7 +452,6 @@ void pollBatteryLevel() { data[2] = (vbat & 0xFF); ioport->write(data, 3, 6, 10); - DEBUG("exit pollBatteryLevel"); } #if 0 diff --git a/TNC/AudioInput.hpp b/TNC/AudioInput.hpp index 5ede020..0dcf990 100644 --- a/TNC/AudioInput.hpp +++ b/TNC/AudioInput.hpp @@ -87,9 +87,9 @@ enum AdcState { const size_t ADC_BUFFER_SIZE = 384; extern uint32_t adc_buffer[]; // Two int16_t samples per element. -extern uint32_t adc_block_size; -extern uint32_t dma_transfer_size; -extern uint32_t half_buffer_size; +extern volatile uint32_t adc_block_size; +extern volatile uint32_t dma_transfer_size; +extern volatile uint32_t half_buffer_size; // 1kB typedef memory::Pool<8, ADC_BUFFER_SIZE * 2> adc_pool_type; diff --git a/TNC/Demodulator.cpp b/TNC/Demodulator.cpp index 4aa2bd7..06311c4 100644 --- a/TNC/Demodulator.cpp +++ b/TNC/Demodulator.cpp @@ -23,7 +23,6 @@ void IDemodulator::startADC(uint32_t period, uint32_t block_size) audio::set_adc_block_size(block_size); htim6.Init.Period = period; - htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim6) != HAL_OK) { CxxErrorHandler(); @@ -35,7 +34,7 @@ void IDemodulator::startADC(uint32_t period, uint32_t block_size) } if (HAL_ADC_Start_DMA(&hadc1, audio::adc_buffer, - block_size * 2) != HAL_OK) + audio::dma_transfer_size) != HAL_OK) { CxxErrorHandler(); } diff --git a/TNC/Demodulator.hpp b/TNC/Demodulator.hpp index a7ab9ec..6a5a926 100644 --- a/TNC/Demodulator.hpp +++ b/TNC/Demodulator.hpp @@ -24,6 +24,7 @@ struct IDemodulator virtual void stop() = 0; virtual hdlc::IoFrame* operator()(const q15_t* samples) = 0; virtual float readTwist() = 0; + virtual uint32_t readBatteryLevel() = 0; virtual bool locked() const = 0; virtual size_t size() const = 0; @@ -33,10 +34,10 @@ struct IDemodulator * are frames which consist of an even multiple of eight bits and are * up to 330 bytes, but which do not have a valid checksum. * - * @param enable is true when enabled and false when disabled. The + * @param enabled is true when enabled and false when disabled. The * default state is disabled. */ - virtual void passall(bool enable) = 0; + virtual void passall(bool enabled) = 0; virtual ~IDemodulator() {} diff --git a/TNC/Fsk9600Demodulator.cpp b/TNC/Fsk9600Demodulator.cpp index 8ec4ecb..e15cd2b 100644 --- a/TNC/Fsk9600Demodulator.cpp +++ b/TNC/Fsk9600Demodulator.cpp @@ -4,6 +4,7 @@ #include "Fsk9600Demodulator.hpp" #include "Goertzel.h" #include "AudioInput.hpp" +#include "GPIO.hpp" namespace mobilinkd { namespace tnc { @@ -45,7 +46,6 @@ hdlc::IoFrame* Fsk9600Demodulator::operator()(const q15_t* samples) float Fsk9600Demodulator::readTwist() { DEBUG("enter Fsk9600Demodulator::readTwist"); - constexpr uint32_t channel = AUDIO_IN; float g120 = 0.0f; float g4800 = 0.0f; @@ -97,6 +97,77 @@ float Fsk9600Demodulator::readTwist() return result; } +uint32_t Fsk9600Demodulator::readBatteryLevel() +{ + DEBUG("enter Fsk9600Demodulator::readBatteryLevel"); + + ADC_ChannelConfTypeDef sConfig; + + sConfig.Channel = ADC_CHANNEL_VREFINT; + sConfig.Rank = ADC_REGULAR_RANK_1; + sConfig.SingleDiff = ADC_SINGLE_ENDED; + sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5; + sConfig.OffsetNumber = ADC_OFFSET_NONE; + sConfig.Offset = 0; + if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) + CxxErrorHandler(); + + htim6.Init.Period = 48000; + if (HAL_TIM_Base_Init(&htim6) != HAL_OK) CxxErrorHandler(); + + if (HAL_TIM_Base_Start(&htim6) != HAL_OK) + CxxErrorHandler(); + + if (HAL_ADC_Start(&hadc1) != HAL_OK) CxxErrorHandler(); + if (HAL_ADC_PollForConversion(&hadc1, 3) != HAL_OK) CxxErrorHandler(); + auto vrefint = HAL_ADC_GetValue(&hadc1); + if (HAL_ADC_Stop(&hadc1) != HAL_OK) CxxErrorHandler(); + + // Disable battery charging while measuring battery voltage. + auto usb_ce = gpio::USB_CE::get(); + gpio::USB_CE::on(); + + gpio::BAT_DIVIDER::off(); + HAL_Delay(1); + + sConfig.Channel = ADC_CHANNEL_15; + if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) + CxxErrorHandler(); + + uint32_t vbat = 0; + if (HAL_ADC_Start(&hadc1) != HAL_OK) CxxErrorHandler(); + for (size_t i = 0; i != 8; ++i) + { + if (HAL_ADC_PollForConversion(&hadc1, 1) != HAL_OK) CxxErrorHandler(); + vbat += HAL_ADC_GetValue(&hadc1); + } + + vbat /= 8; + + if (HAL_ADC_Stop(&hadc1) != HAL_OK) CxxErrorHandler(); + if (HAL_TIM_Base_Stop(&htim6) != HAL_OK) + CxxErrorHandler(); + + gpio::BAT_DIVIDER::on(); + + // Restore battery charging state. + if (!usb_ce) gpio::USB_CE::off(); + + INFO("Vref = %lu", vrefint); + INFO("Vbat = %lu (raw)", vbat); + + // Order of operations is important to avoid underflow. + vbat *= 6600; + vbat /= (vrefint + 1); + + uint32_t vref = (vrefint * 3300) + (VREF / 2) / VREF; + + INFO("Vref = %lumV", vref) + INFO("Vbat = %lumV", vbat); + + DEBUG("exit Fsk9600Demodulator::readBatteryLevel"); + return vbat; +} const Fsk9600Demodulator::bpf_bank_type Fsk9600Demodulator::bpf_bank = {{ // -3dB diff --git a/TNC/Fsk9600Demodulator.hpp b/TNC/Fsk9600Demodulator.hpp index 880ed51..2283cc6 100644 --- a/TNC/Fsk9600Demodulator.hpp +++ b/TNC/Fsk9600Demodulator.hpp @@ -29,9 +29,11 @@ struct Fsk9600Demodulator : IDemodulator { static constexpr size_t FILTER_TAP_NUM = 132; static constexpr uint32_t ADC_BLOCK_SIZE = 384; - static constexpr uint32_t SAMPLE_RATE = 192000; static_assert(audio::ADC_BUFFER_SIZE >= ADC_BLOCK_SIZE); + static constexpr uint32_t SAMPLE_RATE = 192000; + static constexpr uint16_t VREF = 16383; + using bpf_coeffs_type = std::array; using bpf_bank_type = std::array; using audio_filter_t = Q15FirFilter; @@ -80,13 +82,13 @@ struct Fsk9600Demodulator : IDemodulator void stop() override { stopADC(); -// INFO("Setting 4MHz SysClock."); -// SysClock48(); locked_ = false; } float readTwist() override; + uint32_t readBatteryLevel() override; + hdlc::IoFrame* operator()(const q15_t* samples) override; bool locked() const override @@ -99,9 +101,9 @@ struct Fsk9600Demodulator : IDemodulator return ADC_BLOCK_SIZE; } - void passall(bool enable) override + void passall(bool enabled) override { - hdlc_decoder_.passall = enable; + hdlc_decoder_.setPassall(enabled); } }; diff --git a/TNC/HdlcDecoder.hpp b/TNC/HdlcDecoder.hpp index 82ac73e..bece5f2 100644 --- a/TNC/HdlcDecoder.hpp +++ b/TNC/HdlcDecoder.hpp @@ -54,6 +54,10 @@ struct NewDecoder optional_result_type operator()(bool input, bool pll_lock); uint8_t process(bool input, bool pll_lock); + void setPassall(bool enabled) + { + passall = enabled; + } }; }}} // mobilinkd::tnc::hdlc