diff --git a/cfg/mcuconf.h b/cfg/mcuconf.h index 520d609..8b49f7a 100644 --- a/cfg/mcuconf.h +++ b/cfg/mcuconf.h @@ -164,7 +164,7 @@ */ #define STM32_DAC_DUAL_MODE FALSE #define STM32_DAC_USE_DAC1_CH1 TRUE -#define STM32_DAC_USE_DAC1_CH2 FALSE +#define STM32_DAC_USE_DAC1_CH2 TRUE #define STM32_DAC_DAC1_CH1_IRQ_PRIORITY 10 #define STM32_DAC_DAC1_CH2_IRQ_PRIORITY 10 #define STM32_DAC_DAC1_CH1_DMA_PRIORITY 2 diff --git a/gui/stmdsp.cpp b/gui/stmdsp.cpp index 8f19065..87b608d 100644 --- a/gui/stmdsp.cpp +++ b/gui/stmdsp.cpp @@ -77,6 +77,29 @@ namespace stmdsp m_serial.write("S"); } + void device::siggen_upload(dacsample_t *buffer, unsigned int size) { + if (connected()) { + uint8_t request[3] = { + 'D', + static_cast(size), + static_cast(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] = { diff --git a/gui/stmdsp.hpp b/gui/stmdsp.hpp index 2d336c5..a9b8b7e 100644 --- a/gui/stmdsp.hpp +++ b/gui/stmdsp.hpp @@ -24,6 +24,7 @@ namespace stmdsp }; using adcsample_t = uint16_t; + using dacsample_t = uint16_t; class device { @@ -40,12 +41,18 @@ namespace stmdsp //std::vector 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 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(); diff --git a/gui/wxmain.cpp b/gui/wxmain.cpp index 58f0d37..aa57066 100644 --- a/gui/wxmain.cpp +++ b/gui/wxmain.cpp @@ -10,6 +10,9 @@ #include #include #include +#include + +#include enum Id { MeasureTimer = 1, @@ -25,6 +28,8 @@ enum Id { MRunMeasure, MRunUpload, MRunUnload, + MRunGenUpload, + MRunGenStart, MCodeCompile, MCodeDisassemble }; @@ -99,6 +104,12 @@ MainFrame::MainFrame() : wxFrame(nullptr, wxID_ANY, "stmdspgui", wxPoint(50, 50) 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, @@ -398,6 +409,59 @@ void MainFrame::onRunStart(wxCommandEvent& ce) } } +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 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(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()) { diff --git a/gui/wxmain.hpp b/gui/wxmain.hpp index ce3e5a5..0da0b79 100644 --- a/gui/wxmain.hpp +++ b/gui/wxmain.hpp @@ -36,6 +36,8 @@ public: void onRunStart(wxCommandEvent&); void onRunUpload(wxCommandEvent&); void onRunUnload(wxCommandEvent&); + void onRunGenUpload(wxCommandEvent&); + void onRunGenStart(wxCommandEvent&); void onRunCompile(wxCommandEvent&); void onCodeDisassemble(wxCommandEvent&); diff --git a/source/dac.cpp b/source/dac.cpp index 74b69e3..c39da38 100644 --- a/source/dac.cpp +++ b/source/dac.cpp @@ -12,6 +12,7 @@ #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 = { @@ -34,27 +35,40 @@ constexpr static const GPTConfig gpt_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); + } } } diff --git a/source/dac.hpp b/source/dac.hpp index 9d529bf..dec1b36 100644 --- a/source/dac.hpp +++ b/source/dac.hpp @@ -17,8 +17,8 @@ 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_ diff --git a/source/main.cpp b/source/main.cpp index c46685f..63bd66b 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -77,6 +77,10 @@ static std::array dac_samples; +#if CACHE_LINE_SIZE > 0 +CC_ALIGN(CACHE_LINE_SIZE) +#endif +static std::array dac2_samples; static uint8_t elf_file_store[MAX_ELF_FILE_SIZE]; static elf::entry_t elf_entry = nullptr; @@ -112,6 +116,7 @@ int main() } 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; @@ -133,6 +138,8 @@ void main_loop() 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) { @@ -155,7 +162,17 @@ void main_loop() 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. @@ -211,7 +228,7 @@ void main_loop() 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); } @@ -232,7 +249,7 @@ void main_loop() 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); } @@ -251,13 +268,20 @@ void main_loop() 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; } @@ -272,7 +296,7 @@ void conversion_abort() { elf_entry = nullptr; if (!dac_preloaded) - dac::write_stop(); + dac::write_stop(0); if (!adc_preloaded) adc::read_stop(); error_queue_add(Error::ConversionAborted);