*/\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
m_serial.write("S");
}
+ void device::siggen_upload(dacsample_t *buffer, unsigned int size) {
+ if (connected()) {
+ uint8_t request[3] = {
+ 'D',
+ static_cast<uint8_t>(size),
+ static_cast<uint8_t>(size >> 8)
+ };
+ m_serial.write(request, 3);
+
+ m_serial.write((uint8_t *)buffer, size * sizeof(dacsample_t));
+ }
+ }
+
+ void device::siggen_start() {
+ if (connected())
+ m_serial.write("W");
+ }
+
+ void device::siggen_stop() {
+ if (connected())
+ m_serial.write("w");
+ }
+
void device::upload_filter(unsigned char *buffer, size_t size) {
if (connected()) {
uint8_t request[3] = {
};
using adcsample_t = uint16_t;
+ using dacsample_t = uint16_t;
class device
{
//std::vector<adcsample_t> sample(unsigned long int count = 1);
+ void continuous_set_buffer_size(unsigned int size);
void continuous_start();
void continuous_start_measure();
uint32_t continuous_start_get_measurement();
std::vector<adcsample_t> continuous_read();
void continuous_stop();
+ void siggen_upload(dacsample_t *buffer, unsigned int size);
+ void siggen_start();
+ void siggen_stop();
+
+ // buffer is ELF binary
void upload_filter(unsigned char *buffer, size_t size);
void unload_filter();
#include <wx/sizer.h>
#include <wx/splitter.h>
#include <wx/statusbr.h>
+#include <wx/textdlg.h>
+
+#include <vector>
enum Id {
MeasureTimer = 1,
MRunMeasure,
MRunUpload,
MRunUnload,
+ MRunGenUpload,
+ MRunGenStart,
MCodeCompile,
MCodeDisassemble
};
Bind(wxEVT_MENU, &MainFrame::onRunUnload, this, Id::MRunUnload, wxID_ANY,
menuRun->Append(MRunUnload, "U&nload code"));
+ menuRun->AppendSeparator();
+ Bind(wxEVT_MENU, &MainFrame::onRunGenUpload, this, Id::MRunGenUpload, wxID_ANY,
+ menuRun->Append(MRunGenUpload, "&Load signal generator..."));
+ Bind(wxEVT_MENU, &MainFrame::onRunGenStart, this, Id::MRunGenStart, wxID_ANY,
+ menuRun->AppendCheckItem(MRunGenStart, "Start &generator"));
+
Bind(wxEVT_MENU, &MainFrame::onRunCompile, this, Id::MCodeCompile, wxID_ANY,
menuCode->Append(MCodeCompile, "&Compile code"));
Bind(wxEVT_MENU, &MainFrame::onCodeDisassemble, this, Id::MCodeDisassemble, wxID_ANY,
}
}
+void MainFrame::onRunGenUpload([[maybe_unused]] wxCommandEvent&)
+{
+ if (m_device != nullptr && m_device->connected()) {
+ wxTextEntryDialog dialog (this, "Enter generator values", "Hey");
+ if (dialog.ShowModal() == wxID_OK) {
+ if (wxString values = dialog.GetValue(); !values.IsEmpty()) {
+ std::vector<stmdsp::dacsample_t> samples;
+ while (!values.IsEmpty()) {
+ if (auto number_end = values.find_first_not_of("0123456789");
+ number_end != wxString::npos && number_end > 0)
+ {
+ auto number = values.Left(number_end);
+ if (unsigned long n; number.ToULong(&n))
+ samples.push_back(n & 4095);
+
+ if (auto next = values.find_first_of("0123456789", number_end + 1);
+ next != wxString::npos)
+ {
+ values = values.Mid(next);
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ m_device->siggen_upload(&samples[0], samples.size());
+ }
+ }
+ } else {
+ wxMessageBox("No device connected!", "Run", wxICON_WARNING);
+ m_status_bar->SetStatusText("Please connect.");
+ }
+}
+
+void MainFrame::onRunGenStart(wxCommandEvent& ce)
+{
+ auto menuItem = dynamic_cast<wxMenuItem *>(ce.GetEventUserData());
+ if (m_device != nullptr && m_device->connected()) {
+ if (menuItem->IsChecked()) {
+ m_device->siggen_start();
+ menuItem->SetItemLabel("Stop &generator");
+ } else {
+ m_device->siggen_stop();
+ menuItem->SetItemLabel("Start &generator");
+ }
+ } else {
+ wxMessageBox("No device connected!", "Run", wxICON_WARNING);
+ m_status_bar->SetStatusText("Please connect.");
+ }
+}
+
void MainFrame::onRunUpload([[maybe_unused]] wxCommandEvent&)
{
if (auto file = compileEditorCode(); !file.IsEmpty()) {
void onRunStart(wxCommandEvent&);
void onRunUpload(wxCommandEvent&);
void onRunUnload(wxCommandEvent&);
+ void onRunGenUpload(wxCommandEvent&);
+ void onRunGenStart(wxCommandEvent&);
void onRunCompile(wxCommandEvent&);
void onCodeDisassemble(wxCommandEvent&);
#include "dac.hpp"
constexpr static const auto dacd = &DACD1;
+constexpr static const auto dacd2 = &DACD2;
constexpr static const auto gptd = &GPTD6;
constexpr static const DACConfig dac_config = {
.dier = 0
};
+static unsigned int dacs_running = 0;
+
namespace dac
{
void init()
{
palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG);
- //palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
+ palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
dacStart(dacd, &dac_config);
+ dacStart(dacd2, &dac_config);
gptStart(gptd, &gpt_config);
}
-
- void write_start(dacsample_t *buffer, size_t count)
+
+ void write_start(unsigned int channel, dacsample_t *buffer, size_t count)
{
- dacStartConversion(dacd, &dac_group_config, buffer, count);
- gptStartContinuous(gptd, 25);
+ if (channel < 2) {
+ dacStartConversion(channel == 0 ? dacd : dacd2, &dac_group_config, buffer, count);
+
+ if (dacs_running == 0)
+ gptStartContinuous(gptd, 25);
+ dacs_running |= 1 << channel;
+ }
}
- void write_stop()
+ void write_stop(unsigned int channel)
{
- gptStopTimer(gptd);
- dacStopConversion(dacd);
+ if (channel < 2) {
+ dacStopConversion(channel == 0 ? dacd : dacd2);
+
+ dacs_running &= ~(1 << channel);
+ if (dacs_running == 0)
+ gptStopTimer(gptd);
+ }
}
}
namespace dac
{
void init();
- void write_start(dacsample_t *buffer, size_t count);
- void write_stop();
+ void write_start(unsigned int channel, dacsample_t *buffer, size_t count);
+ void write_stop(unsigned int channel);
}
#endif // STMDSP_DAC_HPP_
CC_ALIGN(CACHE_LINE_SIZE)
#endif
static std::array<dacsample_t, CACHE_SIZE_ALIGN(dacsample_t, MAX_SAMPLE_BUFFER_SIZE)> dac_samples;
+#if CACHE_LINE_SIZE > 0
+CC_ALIGN(CACHE_LINE_SIZE)
+#endif
+static std::array<dacsample_t, CACHE_SIZE_ALIGN(dacsample_t, MAX_SAMPLE_BUFFER_SIZE)> dac2_samples;
static uint8_t elf_file_store[MAX_ELF_FILE_SIZE];
static elf::entry_t elf_entry = nullptr;
}
static unsigned int dac_sample_count = MAX_SAMPLE_BUFFER_SIZE;
+static unsigned int dac2_sample_count = MAX_SAMPLE_BUFFER_SIZE;
static unsigned int adc_sample_count = MAX_SAMPLE_BUFFER_SIZE;
static bool adc_preloaded = false;
static bool dac_preloaded = false;
usbserial::read(&adc_samples[0], adc_sample_count * sizeof(adcsample_t));
break;
+ case 'b':
+ break;
case 'B':
if (run_status == RunStatus::Idle) {
if (usbserial::read(&cmd[1], 2) == 2) {
usbserial::write(dac_samples.data(), dac_sample_count * sizeof(dacsample_t));
break;
case 'D':
- usbserial::read(&dac_samples[0], dac_sample_count * sizeof(dacsample_t));
+ if (usbserial::read(&cmd[1], 2) == 2) {
+ unsigned int count = cmd[1] | (cmd[2] << 8);
+ if (count <= MAX_SAMPLE_BUFFER_SIZE / 2) {
+ dac2_sample_count = count;
+ usbserial::read(&dac2_samples[0], dac2_sample_count * sizeof(dacsample_t));
+ } else {
+ error_queue_add(Error::BadParam);
+ }
+ } else {
+ error_queue_add(Error::BadParamSize);
+ }
break;
// 'E' - Reads in and loads the compiled conversion code binary from USB.
if (!adc_preloaded)
adc::read_start(signal_operate_measure, &adc_samples[0], adc_sample_count);
if (!dac_preloaded)
- dac::write_start(&dac_samples[0], dac_sample_count);
+ dac::write_start(0, &dac_samples[0], dac_sample_count);
} else {
error_queue_add(Error::NotIdle);
}
if (!adc_preloaded)
adc::read_start(signal_operate, &adc_samples[0], adc_sample_count);
if (!dac_preloaded)
- dac::write_start(&dac_samples[0], dac_sample_count);
+ dac::write_start(0, &dac_samples[0], dac_sample_count);
} else {
error_queue_add(Error::NotIdle);
}
case 'S':
if (run_status == RunStatus::Running) {
if (!dac_preloaded)
- dac::write_stop();
+ dac::write_stop(0);
if (!adc_preloaded)
adc::read_stop();
run_status = RunStatus::Idle;
}
break;
+ case 'W':
+ dac::write_start(1, &dac2_samples[0], dac2_sample_count);
+ break;
+ case 'w':
+ dac::write_stop(1);
+ break;
+
default:
break;
}
{
elf_entry = nullptr;
if (!dac_preloaded)
- dac::write_stop();
+ dac::write_stop(0);
if (!adc_preloaded)
adc::read_stop();
error_queue_add(Error::ConversionAborted);