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_*
**/.*
gui/stmdspgui
*.o
**/*.o
perf*

@ -177,7 +177,7 @@
#define STM32_GPT_USE_TIM2 FALSE
#define STM32_GPT_USE_TIM3 FALSE
#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_TIM7 FALSE
#define STM32_GPT_USE_TIM8 FALSE

@ -1,6 +1,6 @@
/**
* @file adc.cpp
* @brief Wrapper for ChibiOS's ADCDriver.
* @brief Manages signal reading through the ADC.
*
* Copyright (C) 2020 Clyne Sullivan
*
@ -11,77 +11,96 @@
#include "adc.hpp"
const GPTConfig ADCd::m_gpt_config = {
.frequency = 1000000,
.callback = NULL,
.cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
.dier = 0
constexpr static const auto adcd = &ADCD1;
constexpr static const auto gptd = &GPTD4;
constexpr static const ADCConfig adc_config = {
.difsel = 0
};
void ADCd::start()
{
initPins();
gptStart(m_gptd, &m_gpt_config);
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
}
};
m_adc_config.difsel = 0;
m_adc_config.adcdinst = this;
constexpr static const GPTConfig gpt_config = {
.frequency = 1000000,
.callback = nullptr,
.cr2 = TIM_CR2_MMS_1, /* TRGO */
.dier = 0
};
static bool adc_is_read_finished = false;
void adc_init()
{
palSetPadMode(GPIOA, 0, PAL_MODE_INPUT_ANALOG);
adcStart(m_adcd, &m_adc_config);
adcSTM32EnableVREF(m_adcd);
gptStart(gptd, &gpt_config);
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;
adcStartConversion(m_adcd, &m_adc_group_config, buffer, count);
gptStartContinuous(m_gptd, 100); // 10kHz
while (!m_is_adc_finished);
adc_is_read_finished = false;
adcStartConversion(adcd, &adc_group_config, buffer, count);
gptStartContinuous(gptd, 100); // 10kHz
while (!adc_is_read_finished);
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;
switch (rate) {
case ADCdRate::R2P5:
case ADCRate::R2P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_2P5);
break;
case ADCdRate::R6P5:
case ADCRate::R6P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_6P5);
break;
case ADCdRate::R12P5:
case ADCRate::R12P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_12P5);
break;
case ADCdRate::R24P5:
case ADCRate::R24P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_24P5);
break;
case ADCdRate::R47P5:
case ADCRate::R47P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_47P5);
break;
case ADCdRate::R92P5:
case ADCRate::R92P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_92P5);
break;
case ADCdRate::R247P5:
case ADCRate::R247P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_247P5);
break;
case ADCdRate::R640P5:
case ADCRate::R640P5:
val = ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_640P5);
break;
}
m_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;
adc_group_config.smpr[0] = val;
}

@ -1,6 +1,6 @@
/**
* @file adc.hpp
* @brief Wrapper for ChibiOS's ADCDriver.
* @brief Manages signal reading through the ADC.
*
* Copyright (C) 2020 Clyne Sullivan
*
@ -14,14 +14,7 @@
#include "hal.h"
class ADCd;
struct ADCdConfig : public ADCConfig
{
ADCd *adcdinst;
};
enum class ADCdRate : unsigned int {
enum class ADCRate {
R2P5,
R6P5,
R12P5,
@ -32,84 +25,9 @@ enum class ADCdRate : unsigned int {
R640P5
};
class ADCd
{
public:
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
}
};
};
void adc_init();
adcsample_t *adc_read(adcsample_t *buffer, size_t count);
void adc_set_rate(ADCRate rate);
#endif // STMDSP_ADC_HPP_

@ -1,6 +1,6 @@
/**
* @file dac.cpp
* @brief Wrapper for ChibiOS's DACDriver.
* @brief Manages signal creation using the DAC.
*
* Copyright (C) 2020 Clyne Sullivan
*
@ -11,28 +11,47 @@
#include "dac.hpp"
//static const DACConversionGroup dacGroupConfig = {
// .num_channels = 1,
// .end_cb = NULL,
// .error_cb = NULL,
// .trigger = DAC_TRG(0)
//};
constexpr static const auto dacd = &DACD1;
constexpr static const auto gptd = &GPTD5;
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();
dacStart(m_driver, &m_config);
palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG);
//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)
dacPutChannelX(m_driver, channel, value);
dacStartConversion(dacd, &dac_group_config, buffer, count);
gptStartContinuous(gptd, 1);
}
void DACd::initPins()
void dac_write_stop()
{
palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG); // DAC out1, out2
palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
gptStopTimer(gptd);
dacStopConversion(dacd);
}

@ -1,6 +1,6 @@
/**
* @file dac.hpp
* @brief Wrapper for ChibiOS's DACDriver.
* @brief Manages signal creation using the DAC.
*
* Copyright (C) 2020 Clyne Sullivan
*
@ -14,22 +14,9 @@
#include "hal.h"
class DACd
{
public:
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();
};
void dac_init();
void dac_write_start(dacsample_t *buffer, size_t count);
void dac_write_stop();
#endif // STMDSP_DAC_HPP_

@ -24,6 +24,7 @@ static_assert(sizeof(adcsample_t) == sizeof(uint16_t));
CC_ALIGN(CACHE_LINE_SIZE)
#endif
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()
{
@ -32,35 +33,39 @@ int main()
palSetPadMode(GPIOA, 5, PAL_MODE_OUTPUT_PUSHPULL); // LED
ADCd adc (ADCD1, GPTD4);
adc.start();
//DACd dac (DACD1, {
// .init = 0,
// .datamode = DAC_DHRM_12BIT_RIGHT,
// .cr = 0
//});
//dac.start();
//dac.write(0, 1024);
USBSeriald usbd (SDU1);
usbd.start();
adc_init();
dac_init();
usbserial_init();
static unsigned int dac_sample_count = 2048;
while (true) {
if (usbd.active()) {
if (usbserial_is_active()) {
// 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]) {
case 'r': // Read in analog signal
if (usbd.read(&cmd[1], 2) < 2)
if (usbserial_read(&cmd[1], 2) < 2)
break;
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);
usbd.write(adc_samples.data(), count * sizeof(adcsample_t));
adc_read(&adc_samples[0], count);
usbserial_write(adc_samples.data(), count * sizeof(adcsample_t));
}
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
usbd.write("stmdsp", 6);
usbserial_write("stmdsp", 6);
break;
default:
break;

@ -11,14 +11,17 @@
#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);
sduStart(m_driver, &serusbcfg);
sduObjectInit(sdud);
sduStart(sdud, &serusbcfg);
// Reconnect bus so device can re-enumerate on reset
usbDisconnectBus(serusbcfg.usbp);
@ -27,26 +30,20 @@ void USBSeriald::start()
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);
}
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);
}
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_
#define STMDSP_USBSERIAL_HPP_
#include "usbcfg.h"
#include "hal.h"
#include <cstddef>
class USBSeriald
{
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();
};
void usbserial_init();
bool usbserial_is_active();
size_t usbserial_read(void *buffer, size_t count);
size_t usbserial_write(const void *buffer, size_t count);
#endif // STMDSP_USBSERIAL_HPP_

Loading…
Cancel
Save