/**\r
* @brief PLL1 DIVP field.\r
*/\r
-#if ((STM32_PLL1_DIVP_VALUE >= 2) && (STM32_PLL1_DIVP_VALUE <= 128) && \\r
- ((STM32_PLL1_DIVP_VALUE & 1U) == 0U)) || \\r
+#if ((STM32_PLL1_DIVP_VALUE >= 1) && (STM32_PLL1_DIVP_VALUE <= 128) && \\r
+ ((STM32_PLL1_DIVP_VALUE & 1U) == 0U || STM32_PLL1_DIVP_VALUE == 1)) || \\r
defined(__DOXYGEN__)\r
#define STM32_PLL1_DIVP ((STM32_PLL1_DIVP_VALUE - 1U) << 9U)\r
#else\r
#define STM32_HSI48_ENABLED TRUE\r
#define STM32_HSE_ENABLED FALSE\r
#define STM32_LSE_ENABLED FALSE\r
-#define STM32_HSIDIV STM32_HSIDIV_DIV8 // 8\r
+#define STM32_HSIDIV STM32_HSIDIV_DIV8 // HSI = 8MHz\r
\r
/*\r
* PLLs static settings.\r
#define STM32_PLL1_P_ENABLED TRUE\r
#define STM32_PLL1_Q_ENABLED FALSE\r
#define STM32_PLL1_R_ENABLED FALSE\r
-#define STM32_PLL1_DIVM_VALUE 4 // 2\r
-#define STM32_PLL1_DIVN_VALUE 384 // 2(384)\r
+#define STM32_PLL1_DIVM_VALUE 4 // 8 / 4 = 2MHz\r
+#define STM32_PLL1_DIVN_VALUE 240 // = 2 * 240\r
#define STM32_PLL1_FRACN_VALUE 0\r
-#define STM32_PLL1_DIVP_VALUE 2 // 384\r
+#define STM32_PLL1_DIVP_VALUE 1 // = 480MHz\r
#define STM32_PLL1_DIVQ_VALUE 16\r
#define STM32_PLL1_DIVR_VALUE 8\r
-#define STM32_PLL2_ENABLED TRUE\r
+#define STM32_PLL2_ENABLED TRUE // PLL2 adjusted by adc.cpp\r
#define STM32_PLL2_P_ENABLED TRUE\r
#define STM32_PLL2_Q_ENABLED FALSE\r
#define STM32_PLL2_R_ENABLED FALSE\r
#define STM32_PLL2_DIVM_VALUE 4\r
-#define STM32_PLL2_DIVN_VALUE 384\r
+#define STM32_PLL2_DIVN_VALUE 80\r
#define STM32_PLL2_FRACN_VALUE 0\r
-#define STM32_PLL2_DIVP_VALUE 32\r
+#define STM32_PLL2_DIVP_VALUE 20\r
#define STM32_PLL2_DIVQ_VALUE 8\r
#define STM32_PLL2_DIVR_VALUE 8\r
#define STM32_PLL3_ENABLED FALSE\r
#define STM32_SW STM32_SW_PLL1_P_CK\r
#define STM32_RTCSEL STM32_RTCSEL_LSI_CK\r
#define STM32_D1CPRE STM32_D1CPRE_DIV1\r
-#define STM32_D1HPRE STM32_D1HPRE_DIV2\r
+#define STM32_D1HPRE STM32_D1HPRE_DIV2 // /2 = 240MHz\r
#define STM32_D1PPRE3 STM32_D1PPRE3_DIV2\r
-#define STM32_D2PPRE1 STM32_D2PPRE1_DIV2 // 192\r
+#define STM32_D2PPRE1 STM32_D2PPRE1_DIV2\r
#define STM32_D2PPRE2 STM32_D2PPRE2_DIV2\r
#define STM32_D3PPRE4 STM32_D3PPRE4_DIV2\r
\r
#define STM32_ADC_ADC3_IRQ_PRIORITY 5\r
#define STM32_ADC_ADC12_CLOCK_MODE ADC_CCR_CKMODE_AHB_DIV4\r
#define STM32_ADC_ADC3_CLOCK_MODE ADC_CCR_CKMODE_ADCCK\r
-#define STM32_ADC_ADC3_PRESC (5 << ADC_CCR_PRESC_Pos) // div10\r
+#define STM32_ADC_ADC3_PRESC (5 << ADC_CCR_PRESC_Pos) // /10\r
\r
/*\r
* CAN driver system settings.\r
*/\r
#define STM32_DAC_DUAL_MODE FALSE\r
#define STM32_DAC_USE_DAC1_CH1 TRUE\r
-#define STM32_DAC_USE_DAC1_CH2 FALSE\r
+#define STM32_DAC_USE_DAC1_CH2 TRUE\r
#define STM32_DAC_DAC1_CH1_IRQ_PRIORITY 10\r
#define STM32_DAC_DAC1_CH2_IRQ_PRIORITY 10\r
#define STM32_DAC_DAC1_CH1_DMA_PRIORITY 2\r
#include "adc.hpp"
ADCDriver *ADC::m_driver = &ADCD3;
-GPTDriver *ADC::m_timer = &GPTD6;
const ADCConfig ADC::m_config = {
.difsel = 0,
.calibration = 0,
};
-ADCConversionGroup ADC::m_group_config = {
+const ADCConversionGroup ADC::m_group_config = {
.circular = true,
.num_channels = 1,
.end_cb = ADC::conversionCallback,
.error_cb = nullptr,
.cfgr = ADC_CFGR_EXTEN_RISING | ADC_CFGR_EXTSEL_SRC(13), /* TIM6_TRGO */
- .cfgr2 = 0,//ADC_CFGR2_ROVSE | ADC_CFGR2_OVSR_0 | ADC_CFGR2_OVSS_1, // Oversampling 2x
+ .cfgr2 = ADC_CFGR2_ROVSE | ADC_CFGR2_OVSR_0 | ADC_CFGR2_OVSS_1, // Oversampling 2x
.ccr = 0,
.pcsel = 0,
.ltr1 = 0, .htr1 = 0x0FFF,
},
};
-const GPTConfig ADC::m_timer_config = {
- .frequency = 4800000,
- .callback = nullptr,
- .cr2 = TIM_CR2_MMS_1, /* TRGO */
- .dier = 0
-};
-
-std::array<std::array<uint32_t, 4>, 6> ADC::m_rate_presets = {{
- // Rate PLLSAI2N R OVERSAMPLE 2x? GPT_DIV
- {/* 8k */ 16, 3, 1, 4500},
- {/* 16k */ 32, 3, 1, 2250},
- {/* 20k */ 40, 3, 1, 1800},
- {/* 32k */ 64, 3, 1, 1125},
- {/* 48k */ 24, 3, 0, 750},
- {/* 96k */ 48, 3, 0, 375}
+std::array<std::array<uint32_t, 2>, 6> ADC::m_rate_presets = {{
+ // Rate PLL N PLL P
+ {/* 8k */ 80, 20},
+ {/* 16k */ 80, 10},
+ {/* 20k */ 80, 8},
+ {/* 32k */ 80, 5},
+ {/* 48k */ 96, 4},
+ {/* 96k */ 96, 2}
}};
adcsample_t *ADC::m_current_buffer = nullptr;
size_t ADC::m_current_buffer_size = 0;
ADC::Operation ADC::m_operation = nullptr;
-unsigned int ADC::m_timer_divisor = 50;
-
void ADC::begin()
{
palSetPadMode(GPIOF, 3, PAL_MODE_INPUT_ANALOG);
adcStart(m_driver, &m_config);
adcSTM32EnableVREF(m_driver);
- gptStart(m_timer, &m_timer_config);
- //setRate(Rate::R32K);
+ setRate(SClock::Rate::R32K);
}
void ADC::start(adcsample_t *buffer, size_t count, Operation operation)
m_operation = operation;
adcStartConversion(m_driver, &m_group_config, buffer, count);
- gptStartContinuous(m_timer, m_timer_divisor);
+ SClock::start();
}
void ADC::stop()
{
- gptStopTimer(m_timer);
+ SClock::stop();
adcStopConversion(m_driver);
m_current_buffer = nullptr;
m_operation = nullptr;
}
-void ADC::setRate(ADC::Rate rate)
+void ADC::setRate(SClock::Rate rate)
{
-// auto& preset = m_rate_presets[static_cast<int>(rate)];
-// auto pllnr = (preset[0] << RCC_PLLSAI2CFGR_PLLSAI2N_Pos) |
-// (preset[1] << RCC_PLLSAI2CFGR_PLLSAI2R_Pos);
-// bool oversample = preset[2] != 0;
-// m_timer_divisor = preset[3];
-
-// adcStop(m_driver);
-//
-// // Adjust PLLSAI2
-// RCC->CR &= ~(RCC_CR_PLLSAI2ON);
-// while ((RCC->CR & RCC_CR_PLLSAI2RDY) == RCC_CR_PLLSAI2RDY);
-// RCC->PLLSAI2CFGR = (RCC->PLLSAI2CFGR & ~(RCC_PLLSAI2CFGR_PLLSAI2N_Msk | RCC_PLLSAI2CFGR_PLLSAI2R_Msk)) | pllnr;
-// RCC->CR |= RCC_CR_PLLSAI2ON;
-// while ((RCC->CR & RCC_CR_PLLSAI2RDY) != RCC_CR_PLLSAI2RDY);
-//
-// // Set 2x oversampling
-// m_group_config.cfgr2 = oversample ? ADC_CFGR2_ROVSE | ADC_CFGR2_OVSR_0 | ADC_CFGR2_OVSS_1 : 0;
-//
-// adcStart(m_driver, &m_config);
+ auto& preset = m_rate_presets[static_cast<unsigned int>(rate)];
+ auto pllbits = (preset[0] << RCC_PLL2DIVR_N2_Pos) |
+ (preset[1] << RCC_PLL2DIVR_P2_Pos);
+
+ adcStop(m_driver);
+
+ // Adjust PLL2
+ RCC->CR &= ~(RCC_CR_PLL2ON);
+ while ((RCC->CR & RCC_CR_PLL2RDY) == RCC_CR_PLL2RDY);
+ auto pll2divr = RCC->PLL2DIVR &
+ ~(RCC_PLL2DIVR_N2_Msk | RCC_PLL2DIVR_P2_Msk);
+ pll2divr |= pllbits;
+ RCC->PLL2DIVR = pll2divr;
+ RCC->CR |= RCC_CR_PLL2ON;
+ while ((RCC->CR & RCC_CR_PLL2RDY) != RCC_CR_PLL2RDY);
+
+ adcStart(m_driver, &m_config);
}
void ADC::setOperation(ADC::Operation operation)
m_operation = operation;
}
-int ADC::getRate()
-{
- for (unsigned int i = 0; i < m_rate_presets.size(); i++) {
- if (m_timer_divisor == m_rate_presets[i][3])
- return i;
- }
-
- return -1;
-}
-
-unsigned int ADC::getTimerDivisor()
-{
- return m_timer_divisor;
-}
-
void ADC::conversionCallback(ADCDriver *driver)
{
if (m_operation != nullptr) {
#define STMDSP_ADC_HPP_
#include "hal.h"
+#include "sclock.hpp"
#include <array>
public:
using Operation = void (*)(adcsample_t *buffer, size_t count);
- enum class Rate : int {
- R8K = 0,
- R16K,
- R20K,
- R32K,
- R48K,
- R96K
- };
-
static void begin();
static void start(adcsample_t *buffer, size_t count, Operation operation);
static void stop();
- static void setRate(Rate rate);
+ static void setRate(SClock::Rate rate);
static void setOperation(Operation operation);
- static int getRate();
- static unsigned int getTimerDivisor();
-
private:
static ADCDriver *m_driver;
- static GPTDriver *m_timer;
static const ADCConfig m_config;
- static /*const*/ ADCConversionGroup m_group_config;
- static const GPTConfig m_timer_config;
+ static const ADCConversionGroup m_group_config;
- static std::array<std::array<uint32_t, 4>, 6> m_rate_presets;
+ static std::array<std::array<uint32_t, 2>, 6> m_rate_presets;
static adcsample_t *m_current_buffer;
static size_t m_current_buffer_size;
static Operation m_operation;
- static unsigned int m_timer_divisor;
-
static void conversionCallback(ADCDriver *);
};
* If not, see <https://www.gnu.org/licenses/>.
*/
-#include "adc.hpp" // ADC::getTimerDivisor
#include "dac.hpp"
+#include "sclock.hpp"
DACDriver *DAC::m_driver[2] = {
- &DACD1, nullptr/*&DACD2*/
+ &DACD1, &DACD2
};
-GPTDriver *DAC::m_timer = nullptr;//&GPTD7;
-int DAC::m_timer_user_count = 0;
const DACConfig DAC::m_config = {
.init = 0,
.num_channels = 1,
.end_cb = nullptr,
.error_cb = nullptr,
- .trigger = 5
-};
-
-const GPTConfig DAC::m_timer_config = {
- .frequency = 4800000,
- .callback = nullptr,
- .cr2 = TIM_CR2_MMS_1, /* TRGO */
- .dier = 0
+ .trigger = 5 // TIM6_TRGO
};
void DAC::begin()
palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
dacStart(m_driver[0], &m_config);
- //dacStart(m_driver[1], &m_config);
- //gptStart(m_timer, &m_timer_config);
+ dacStart(m_driver[1], &m_config);
}
void DAC::start(int channel, dacsample_t *buffer, size_t count)
{
- if (channel >= 0 && channel < 1) {
+ if (channel >= 0 && channel < 2) {
dacStartConversion(m_driver[channel], &m_group_config, buffer, count);
-
- //if (m_timer_user_count == 0)
- // gptStartContinuous(m_timer, ADC::getTimerDivisor());
- //m_timer_user_count++;
+ SClock::start();
}
}
void DAC::stop(int channel)
{
- if (channel >= 0 && channel < 1) {
+ if (channel >= 0 && channel < 2) {
dacStopConversion(m_driver[channel]);
-
- //if (--m_timer_user_count == 0)
- // gptStopTimer(m_timer);
+ SClock::stop();
}
}
private:
static DACDriver *m_driver[2];
- static GPTDriver *m_timer;
- static int m_timer_user_count;
static const DACConfig m_config;
static const DACConversionGroup m_group_config;
- static const GPTConfig m_timer_config;
};
#endif // STMDSP_DAC_HPP_
#include "adc.hpp"\r
#include "dac.hpp"\r
#include "elf_load.hpp"\r
+#include "sclock.hpp"\r
#include "usbserial.hpp"\r
\r
#include <array>\r
case 'r':\r
if (EM.assert(USBSerial::read(&cmd[1], 1) == 1, Error::BadParamSize)) {\r
if (cmd[1] == 0xFF) {\r
- unsigned char r = static_cast<unsigned char>(ADC::getRate());\r
+ unsigned char r = SClock::getRate();\r
USBSerial::write(&r, 1);\r
} else {\r
- ADC::setRate(static_cast<ADC::Rate>(cmd[1]));\r
+ auto r = static_cast<SClock::Rate>(cmd[1]);\r
+ SClock::setRate(r);\r
+ ADC::setRate(r);\r
}\r
}\r
break;\r
--- /dev/null
+#include "sclock.hpp"
+
+GPTDriver *SClock::m_timer = &GPTD6;
+unsigned int SClock::m_div = 1;
+unsigned int SClock::m_runcount = 0;
+
+const GPTConfig SClock::m_timer_config = {
+ .frequency = 4800000,
+ .callback = nullptr,
+ .cr2 = TIM_CR2_MMS_1, /* TRGO */
+ .dier = 0
+};
+
+const std::array<unsigned int, 6> SClock::m_rate_divs = {{
+ /* 8k */ 600,
+ /* 16k */ 300,
+ /* 20k */ 240,
+ /* 32k */ 150,
+ /* 48k */ 100,
+ /* 96k */ 50
+}};
+
+void SClock::begin()
+{
+ gptStart(m_timer, &m_timer_config);
+}
+
+void SClock::start()
+{
+ if (m_runcount++ == 0)
+ gptStartContinuous(m_timer, m_div);
+}
+
+void SClock::stop()
+{
+ if (--m_runcount == 0)
+ gptStopTimer(m_timer);
+}
+
+void SClock::setRate(SClock::Rate rate)
+{
+ m_div = m_rate_divs[static_cast<unsigned int>(rate)];
+}
+
+unsigned int SClock::getRate()
+{
+ for (unsigned int i = 0; i < m_rate_divs.size(); ++i) {
+ if (m_rate_divs[i] == m_div)
+ return i;
+ }
+
+ return static_cast<unsigned int>(-1);
+}
+
--- /dev/null
+#ifndef SCLOCK_HPP_
+#define SCLOCK_HPP_
+
+#include "hal.h"
+
+#include <array>
+
+class SClock
+{
+public:
+ enum class Rate : unsigned int {
+ R8K = 0,
+ R16K,
+ R20K,
+ R32K,
+ R48K,
+ R96K
+ };
+
+ static void begin();
+ static void start();
+ static void stop();
+
+ static void setRate(Rate rate);
+ static unsigned int getRate();
+
+private:
+ static GPTDriver *m_timer;
+ static unsigned int m_div;
+ static unsigned int m_runcount;
+ static const GPTConfig m_timer_config;
+ static const std::array<unsigned int, 6> m_rate_divs;
+};
+
+#endif // SCLOCK_HPP_
+