reorganized code; added dac support

pull/3/head
Clyne 4 years ago
parent 17cda07f3e
commit 7f59ca704b

2
.gitignore vendored

@ -2,6 +2,6 @@ build
ChibiOS_* ChibiOS_*
**/.* **/.*
gui/stmdspgui gui/stmdspgui
*.o **/*.o
perf* perf*

@ -177,7 +177,7 @@
#define STM32_GPT_USE_TIM2 FALSE #define STM32_GPT_USE_TIM2 FALSE
#define STM32_GPT_USE_TIM3 FALSE #define STM32_GPT_USE_TIM3 FALSE
#define STM32_GPT_USE_TIM4 TRUE #define STM32_GPT_USE_TIM4 TRUE
#define STM32_GPT_USE_TIM5 FALSE #define STM32_GPT_USE_TIM5 TRUE
#define STM32_GPT_USE_TIM6 FALSE #define STM32_GPT_USE_TIM6 FALSE
#define STM32_GPT_USE_TIM7 FALSE #define STM32_GPT_USE_TIM7 FALSE
#define STM32_GPT_USE_TIM8 FALSE #define STM32_GPT_USE_TIM8 FALSE

@ -1,6 +1,6 @@
/** /**
* @file adc.cpp * @file adc.cpp
* @brief Wrapper for ChibiOS's ADCDriver. * @brief Manages signal reading through the ADC.
* *
* Copyright (C) 2020 Clyne Sullivan * Copyright (C) 2020 Clyne Sullivan
* *
@ -11,77 +11,96 @@
#include "adc.hpp" #include "adc.hpp"
const GPTConfig ADCd::m_gpt_config = { constexpr static const auto adcd = &ADCD1;
constexpr static const auto gptd = &GPTD4;
constexpr static const ADCConfig adc_config = {
.difsel = 0
};
void adc_read_callback(ADCDriver *);
/*constexpr*/ static ADCConversionGroup adc_group_config = {
.circular = false,
.num_channels = 1,
.end_cb = adc_read_callback,
.error_cb = nullptr,
.cfgr = ADC_CFGR_EXTEN_RISING | ADC_CFGR_EXTSEL_SRC(12), /* TIM4_TRGO */
.cfgr2 = 0,
.tr1 = ADC_TR(0, 4095),
.smpr = {
ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_247P5), 0
},
.sqr = {
ADC_SQR1_SQ1_N(ADC_CHANNEL_IN5),
0, 0, 0
}
};
constexpr static const GPTConfig gpt_config = {
.frequency = 1000000, .frequency = 1000000,
.callback = NULL, .callback = nullptr,
.cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */ .cr2 = TIM_CR2_MMS_1, /* TRGO */
.dier = 0 .dier = 0
}; };
void ADCd::start() static bool adc_is_read_finished = false;
{
initPins();
gptStart(m_gptd, &m_gpt_config);
m_adc_config.difsel = 0; void adc_init()
m_adc_config.adcdinst = this; {
palSetPadMode(GPIOA, 0, PAL_MODE_INPUT_ANALOG);
adcStart(m_adcd, &m_adc_config); gptStart(gptd, &gpt_config);
adcSTM32EnableVREF(m_adcd); adcStart(adcd, &adc_config);
adcSTM32EnableVREF(adcd);
} }
adcsample_t *ADCd::getSamples(adcsample_t *buffer, size_t count) adcsample_t *adc_read(adcsample_t *buffer, size_t count)
{ {
m_is_adc_finished = false; adc_is_read_finished = false;
adcStartConversion(m_adcd, &m_adc_group_config, buffer, count); adcStartConversion(adcd, &adc_group_config, buffer, count);
gptStartContinuous(m_gptd, 100); // 10kHz gptStartContinuous(gptd, 100); // 10kHz
while (!m_is_adc_finished); while (!adc_is_read_finished);
return buffer; return buffer;
} }
void ADCd::setSampleRate(ADCdRate rate) void adc_read_callback([[maybe_unused]] ADCDriver *driver)
{
gptStopTimer(gptd);
adc_is_read_finished = true;
}
void adc_set_rate(ADCRate rate)
{ {
uint32_t val = 0; uint32_t val = 0;
switch (rate) { switch (rate) {
case ADCdRate::R2P5: case ADCRate::R2P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_2P5); val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_2P5);
break; break;
case ADCdRate::R6P5: case ADCRate::R6P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_6P5); val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_6P5);
break; break;
case ADCdRate::R12P5: case ADCRate::R12P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_12P5); val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_12P5);
break; break;
case ADCdRate::R24P5: case ADCRate::R24P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_24P5); val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_24P5);
break; break;
case ADCdRate::R47P5: case ADCRate::R47P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_47P5); val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_47P5);
break; break;
case ADCdRate::R92P5: case ADCRate::R92P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_92P5); val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_92P5);
break; break;
case ADCdRate::R247P5: case ADCRate::R247P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_247P5); val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_247P5);
break; break;
case ADCdRate::R640P5: case ADCRate::R640P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_640P5); val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_640P5);
break; break;
} }
m_adc_group_config.smpr[0] = val; adc_group_config.smpr[0] = val;
}
void ADCd::initPins()
{
palSetPadMode(GPIOA, 0, PAL_MODE_INPUT_ANALOG);
}
void ADCd::adcEndCallback(ADCDriver *adcd)
{
auto *_this = reinterpret_cast<const ADCdConfig *>(adcd->config)->adcdinst;
gptStopTimer(_this->m_gptd);
_this->m_is_adc_finished = true;
} }

@ -1,6 +1,6 @@
/** /**
* @file adc.hpp * @file adc.hpp
* @brief Wrapper for ChibiOS's ADCDriver. * @brief Manages signal reading through the ADC.
* *
* Copyright (C) 2020 Clyne Sullivan * Copyright (C) 2020 Clyne Sullivan
* *
@ -14,14 +14,7 @@
#include "hal.h" #include "hal.h"
class ADCd; enum class ADCRate {
struct ADCdConfig : public ADCConfig
{
ADCd *adcdinst;
};
enum class ADCdRate : unsigned int {
R2P5, R2P5,
R6P5, R6P5,
R12P5, R12P5,
@ -32,84 +25,9 @@ enum class ADCdRate : unsigned int {
R640P5 R640P5
}; };
class ADCd void adc_init();
{ adcsample_t *adc_read(adcsample_t *buffer, size_t count);
public: void adc_set_rate(ADCRate rate);
constexpr static const unsigned int CLOCK_RATE = 40000000;
constexpr static unsigned int SAMPLES_PER_SECOND(ADCdRate rate) {
unsigned int sps = 0;
switch (rate) {
case ADCdRate::R2P5:
sps = 15;
break;
case ADCdRate::R6P5:
sps = 19;
break;
case ADCdRate::R12P5:
sps = 25;
break;
case ADCdRate::R24P5:
sps = 37;
break;
case ADCdRate::R47P5:
sps = 60;
break;
case ADCdRate::R92P5:
sps = 105;
break;
case ADCdRate::R247P5:
sps = 260;
break;
case ADCdRate::R640P5:
sps = 653;
break;
}
return static_cast<unsigned int>(1.f / (sps / static_cast<float>(CLOCK_RATE)));
}
constexpr explicit ADCd(ADCDriver& adcd, GPTDriver& gptd) :
m_adcd(&adcd), m_gptd(&gptd), m_adc_config{},
m_adc_group_config(ADC_GROUP_CONFIG),
m_is_adc_finished(false) {}
void start();
adcsample_t *getSamples(adcsample_t *buffer, size_t count);
void setSampleRate(ADCdRate rate);
private:
static const GPTConfig m_gpt_config;
ADCDriver *m_adcd;
GPTDriver *m_gptd;
ADCdConfig m_adc_config;
ADCConversionGroup m_adc_group_config;
bool m_is_adc_finished;
void initPins();
//void selectPins(bool a0, bool a1);
static void adcEndCallback(ADCDriver *adcd);
constexpr static const ADCConversionGroup ADC_GROUP_CONFIG = {
.circular = false,
.num_channels = 1,
.end_cb = ADCd::adcEndCallback,
.error_cb = nullptr,
.cfgr = ADC_CFGR_EXTEN_RISING |
ADC_CFGR_EXTSEL_SRC(12), /* TIM4_TRGO */
.cfgr2 = 0,
.tr1 = ADC_TR(0, 4095),
.smpr = {
ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_247P5), 0
},
.sqr = {
ADC_SQR1_SQ1_N(ADC_CHANNEL_IN5),
0, 0, 0
}
};
};
#endif // STMDSP_ADC_HPP_ #endif // STMDSP_ADC_HPP_

@ -1,6 +1,6 @@
/** /**
* @file dac.cpp * @file dac.cpp
* @brief Wrapper for ChibiOS's DACDriver. * @brief Manages signal creation using the DAC.
* *
* Copyright (C) 2020 Clyne Sullivan * Copyright (C) 2020 Clyne Sullivan
* *
@ -11,28 +11,47 @@
#include "dac.hpp" #include "dac.hpp"
//static const DACConversionGroup dacGroupConfig = { constexpr static const auto dacd = &DACD1;
// .num_channels = 1, constexpr static const auto gptd = &GPTD5;
// .end_cb = NULL,
// .error_cb = NULL,
// .trigger = DAC_TRG(0)
//};
void DACd::init() constexpr static const DACConfig dac_config = {
.init = 0,
.datamode = DAC_DHRM_12BIT_RIGHT,
.cr = 0
};
constexpr static const DACConversionGroup dac_group_config = {
.num_channels = 1,
.end_cb = nullptr,
.error_cb = nullptr,
.trigger = DAC_TRG(3)
};
constexpr static const GPTConfig gpt_config = {
.frequency = 500000,
.callback = nullptr,
.cr2 = TIM_CR2_MMS_1, /* TRGO */
.dier = 0
};
void dac_init()
{ {
initPins(); palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG);
dacStart(m_driver, &m_config); //palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
dacStart(dacd, &dac_config);
gptStart(gptd, &gpt_config);
} }
void DACd::write(unsigned int channel, uint16_t value) void dac_write_start(dacsample_t *buffer, size_t count)
{ {
if (channel < 2) dacStartConversion(dacd, &dac_group_config, buffer, count);
dacPutChannelX(m_driver, channel, value); gptStartContinuous(gptd, 1);
} }
void DACd::initPins() void dac_write_stop()
{ {
palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG); // DAC out1, out2 gptStopTimer(gptd);
palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG); dacStopConversion(dacd);
} }

@ -1,6 +1,6 @@
/** /**
* @file dac.hpp * @file dac.hpp
* @brief Wrapper for ChibiOS's DACDriver. * @brief Manages signal creation using the DAC.
* *
* Copyright (C) 2020 Clyne Sullivan * Copyright (C) 2020 Clyne Sullivan
* *
@ -14,22 +14,9 @@
#include "hal.h" #include "hal.h"
class DACd void dac_init();
{ void dac_write_start(dacsample_t *buffer, size_t count);
public: void dac_write_stop();
constexpr explicit DACd(DACDriver& driver, const DACConfig& config) :
m_driver(&driver), m_config(config) {}
void init();
void write(unsigned int channel, uint16_t value);
private:
DACDriver *m_driver;
DACConfig m_config;
void initPins();
};
#endif // STMDSP_DAC_HPP_ #endif // STMDSP_DAC_HPP_

@ -24,6 +24,7 @@ static_assert(sizeof(adcsample_t) == sizeof(uint16_t));
CC_ALIGN(CACHE_LINE_SIZE) CC_ALIGN(CACHE_LINE_SIZE)
#endif #endif
static std::array<adcsample_t, CACHE_SIZE_ALIGN(adcsample_t, 2048)> adc_samples; static std::array<adcsample_t, CACHE_SIZE_ALIGN(adcsample_t, 2048)> adc_samples;
static std::array<dacsample_t, CACHE_SIZE_ALIGN(dacsample_t, 2048)> dac_samples;
int main() int main()
{ {
@ -32,35 +33,39 @@ int main()
palSetPadMode(GPIOA, 5, PAL_MODE_OUTPUT_PUSHPULL); // LED palSetPadMode(GPIOA, 5, PAL_MODE_OUTPUT_PUSHPULL); // LED
ADCd adc (ADCD1, GPTD4); adc_init();
adc.start(); dac_init();
usbserial_init();
//DACd dac (DACD1, {
// .init = 0,
// .datamode = DAC_DHRM_12BIT_RIGHT,
// .cr = 0
//});
//dac.start();
//dac.write(0, 1024);
USBSeriald usbd (SDU1);
usbd.start();
static unsigned int dac_sample_count = 2048;
while (true) { while (true) {
if (usbd.active()) { if (usbserial_is_active()) {
// Expect to receive a byte command 'packet'. // Expect to receive a byte command 'packet'.
if (char cmd[3]; usbd.read(&cmd, 1) > 0) { if (char cmd[3]; usbserial_read(&cmd, 1) > 0) {
switch (cmd[0]) { switch (cmd[0]) {
case 'r': // Read in analog signal case 'r': // Read in analog signal
if (usbd.read(&cmd[1], 2) < 2) if (usbserial_read(&cmd[1], 2) < 2)
break; break;
if (auto count = std::min(static_cast<unsigned int>(cmd[1] | (cmd[2] << 8)), adc_samples.size()); count > 0) { if (auto count = std::min(static_cast<unsigned int>(cmd[1] | (cmd[2] << 8)), adc_samples.size()); count > 0) {
adc.getSamples(&adc_samples[0], count); adc_read(&adc_samples[0], count);
usbd.write(adc_samples.data(), count * sizeof(adcsample_t)); usbserial_write(adc_samples.data(), count * sizeof(adcsample_t));
} }
break; break;
case 'W':
if (usbserial_read(&cmd[1], 2) < 2)
break;
if (auto count = std::min(static_cast<unsigned int>(cmd[1] | (cmd[2] << 8)), dac_samples.size()); count > 0)
dac_sample_count = count;
else
dac_write_stop();
break;
case 'w':
if (usbserial_read(&dac_samples[0], 2 * dac_sample_count) != 2 * dac_sample_count)
break;
dac_write_start(&dac_samples[0], dac_sample_count);
break;
case 'i': // Identify ourself as an stmdsp device case 'i': // Identify ourself as an stmdsp device
usbd.write("stmdsp", 6); usbserial_write("stmdsp", 6);
break; break;
default: default:
break; break;

@ -11,14 +11,17 @@
#include "usbserial.hpp" #include "usbserial.hpp"
#include "hal.h" #include "usbcfg.h"
void USBSeriald::start() constexpr static const auto sdud = &SDU1;
void usbserial_init()
{ {
initPins(); palSetPadMode(GPIOA, 11, PAL_MODE_ALTERNATE(10));
palSetPadMode(GPIOA, 12, PAL_MODE_ALTERNATE(10));
sduObjectInit(m_driver); sduObjectInit(sdud);
sduStart(m_driver, &serusbcfg); sduStart(sdud, &serusbcfg);
// Reconnect bus so device can re-enumerate on reset // Reconnect bus so device can re-enumerate on reset
usbDisconnectBus(serusbcfg.usbp); usbDisconnectBus(serusbcfg.usbp);
@ -27,26 +30,20 @@ void USBSeriald::start()
usbConnectBus(serusbcfg.usbp); usbConnectBus(serusbcfg.usbp);
} }
bool USBSeriald::active() const bool usbserial_is_active()
{ {
return m_driver->config->usbp->state == USB_ACTIVE; return sdud->config->usbp->state == USB_ACTIVE;
} }
std::size_t USBSeriald::read(void *buffer, std::size_t count) size_t usbserial_read(void *buffer, size_t count)
{ {
auto *bss = reinterpret_cast<BaseSequentialStream *>(m_driver); auto bss = reinterpret_cast<BaseSequentialStream *>(sdud);
return streamRead(bss, static_cast<uint8_t *>(buffer), count); return streamRead(bss, static_cast<uint8_t *>(buffer), count);
} }
std::size_t USBSeriald::write(const void *buffer, std::size_t count) size_t usbserial_write(const void *buffer, size_t count)
{ {
auto *bss = reinterpret_cast<BaseSequentialStream *>(m_driver); auto bss = reinterpret_cast<BaseSequentialStream *>(sdud);
return streamWrite(bss, static_cast<const uint8_t *>(buffer), count); return streamWrite(bss, static_cast<const uint8_t *>(buffer), count);
} }
void USBSeriald::initPins()
{
palSetPadMode(GPIOA, 11, PAL_MODE_ALTERNATE(10));
palSetPadMode(GPIOA, 12, PAL_MODE_ALTERNATE(10));
}

@ -12,28 +12,12 @@
#ifndef STMDSP_USBSERIAL_HPP_ #ifndef STMDSP_USBSERIAL_HPP_
#define STMDSP_USBSERIAL_HPP_ #define STMDSP_USBSERIAL_HPP_
#include "usbcfg.h" #include "hal.h"
#include <cstddef> void usbserial_init();
bool usbserial_is_active();
class USBSeriald size_t usbserial_read(void *buffer, size_t count);
{ size_t usbserial_write(const void *buffer, size_t count);
public:
constexpr explicit USBSeriald(SerialUSBDriver& driver) :
m_driver(&driver) {}
void start();
bool active() const;
std::size_t read(void *buffer, std::size_t count = 1);
std::size_t write(const void *buffer, std::size_t count = 1);
private:
SerialUSBDriver *m_driver;
void initPins();
};
#endif // STMDSP_USBSERIAL_HPP_ #endif // STMDSP_USBSERIAL_HPP_

Loading…
Cancel
Save