From 3668d168288ef085724f0c48bd7a4123599f2719 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Thu, 4 Feb 2021 21:14:19 -0500 Subject: [PATCH] firmware cleanup, thread optimizing; make buffer size refs consistent --- gui/wxmain.cpp | 11 +- source/main.cpp | 261 ++++++++++++++++++++++++---------------- source/samplebuffer.hpp | 2 +- 3 files changed, 166 insertions(+), 108 deletions(-) diff --git a/gui/wxmain.cpp b/gui/wxmain.cpp index 10e5d7a..c7acddf 100644 --- a/gui/wxmain.cpp +++ b/gui/wxmain.cpp @@ -581,7 +581,7 @@ void MainFrame::onRunLogResults(wxCommandEvent& ce) void MainFrame::onRunEditBSize(wxCommandEvent&) { - wxTextEntryDialog dialog (this, "Enter new buffer size (100-3000)", "Set Buffer Size"); + wxTextEntryDialog dialog (this, "Enter new buffer size (100-4000)", "Set Buffer Size"); if (dialog.ShowModal() == wxID_OK) { if (wxString value = dialog.GetValue(); !value.IsEmpty()) { if (unsigned long n; value.ToULong(&n)) { @@ -610,8 +610,9 @@ void MainFrame::onToolbarSampleRate(wxCommandEvent& ce) void MainFrame::onRunGenUpload(wxCommandEvent&) { - wxTextEntryDialog dialog (this, "Enter generator values below. Values must be whole numbers " - "between zero and 4095.", "Enter Generator Values"); + wxTextEntryDialog dialog (this, "Enter up to 8000 generator values below. " + "Values must be whole numbers between zero and 4095.", + "Enter Generator Values"); if (dialog.ShowModal() == wxID_OK) { if (wxString values = dialog.GetValue(); !values.IsEmpty()) { if (values[0] == '/') { @@ -625,7 +626,7 @@ void MainFrame::onRunGenUpload(wxCommandEvent&) } } else { std::vector samples; - while (!values.IsEmpty()) { + while (!values.IsEmpty() && samples.size() <= stmdsp::SAMPLES_MAX * 2) { if (auto number_end = values.find_first_not_of("0123456789"); number_end != wxString::npos && number_end > 0) { @@ -649,7 +650,7 @@ void MainFrame::onRunGenUpload(wxCommandEvent&) m_device->siggen_upload(&samples[0], samples.size()); m_status_bar->SetStatusText("Generator ready."); } else { - m_status_bar->SetStatusText("Error: Too many samples."); + m_status_bar->SetStatusText("Error: Too many samples (max is 8000)."); } } } else { diff --git a/source/main.cpp b/source/main.cpp index d94f694..0dfc0e7 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -51,24 +51,29 @@ static MAILBOX_DECL(conversionMB, conversionMBBuffer, 2); // Thread for LED status and wakeup hold __attribute__((section(".stacks"))) -static THD_WORKING_AREA(monitorThreadWA, 1024); +static THD_WORKING_AREA(monitorThreadWA, 4096); static THD_FUNCTION(monitorThread, arg); + // Thread for managing the conversion task __attribute__((section(".stacks"))) -static THD_WORKING_AREA(conversionThreadMonitorWA, 1024); +static THD_WORKING_AREA(conversionThreadMonitorWA, 4096); static THD_FUNCTION(conversionThreadMonitor, arg); +static thread_t *conversionThreadHandle = nullptr; + // Thread for unprivileged algorithm execution __attribute__((section(".stacks"))) -static THD_WORKING_AREA(conversionThreadWA, 1024); +static THD_WORKING_AREA(conversionThreadWA, 128); // All we do is enter unprivileged mode. static THD_FUNCTION(conversionThread, arg); __attribute__((section(".convdata"))) static THD_WORKING_AREA(conversionThreadUPWA, 62 * 1024); - -static thread_t *conversionThreadHandle = nullptr; __attribute__((section(".convdata"))) static thread_t *conversionThreadMonitorHandle = nullptr; -__attribute__((section(".convdata"))) +// Thread for USB monitoring +__attribute__((section(".stacks"))) +static THD_WORKING_AREA(communicationThreadWA, 4096); +static THD_FUNCTION(communicationThread, arg); + static time_measurement_t conversion_time_measurement; __attribute__((section(".convdata"))) static SampleBuffer samplesIn (reinterpret_cast(0x38000000)); // 16k @@ -81,9 +86,13 @@ static unsigned char elf_file_store[MAX_ELF_FILE_SIZE]; __attribute__((section(".convdata"))) static ELF::Entry elf_entry = nullptr; +__attribute__((section(".convcode"))) +static void conversion_unprivileged_main(); + +static void mpu_setup(); +static void conversion_abort(); static void signal_operate(adcsample_t *buffer, size_t count); static void signal_operate_measure(adcsample_t *buffer, size_t count); -static void main_loop(); int main() { @@ -91,31 +100,10 @@ int main() halInit(); chSysInit(); - palSetLineMode(LINE_BUTTON, PAL_MODE_INPUT); - - // Enable FPU - SCB->CPACR |= 0xF << 20; - - // Set up MPU for user algorithm - // Region 2: Data for algorithm manager thread - mpuConfigureRegion(MPU_REGION_2, - 0x20000000, - MPU_RASR_ATTR_AP_RW_RW | MPU_RASR_ATTR_NON_CACHEABLE | - MPU_RASR_SIZE_64K | - MPU_RASR_ENABLE); - // Region 3: Code for algorithm manager thread - mpuConfigureRegion(MPU_REGION_3, - 0x0807F800, - MPU_RASR_ATTR_AP_RO_RO | MPU_RASR_ATTR_NON_CACHEABLE | - MPU_RASR_SIZE_2K | - MPU_RASR_ENABLE); - // Region 4: Algorithm code - mpuConfigureRegion(MPU_REGION_4, - 0x00000000, - MPU_RASR_ATTR_AP_RW_RW | MPU_RASR_ATTR_NON_CACHEABLE | - MPU_RASR_SIZE_64K | - MPU_RASR_ENABLE); + SCB->CPACR |= 0xF << 20; // Enable FPU + mpu_setup(); + palSetLineMode(LINE_BUTTON, PAL_MODE_INPUT); ADC::begin(); DAC::begin(); SClock::begin(); @@ -126,21 +114,31 @@ int main() ADC::setRate(SClock::Rate::R32K); chTMObjectInit(&conversion_time_measurement); - chThdCreateStatic(monitorThreadWA, sizeof(monitorThreadWA), - NORMALPRIO, monitorThread, nullptr); + chThdCreateStatic( + monitorThreadWA, sizeof(monitorThreadWA), + LOWPRIO, + monitorThread, nullptr); conversionThreadMonitorHandle = chThdCreateStatic( - conversionThreadMonitorWA, sizeof(conversionThreadMonitorWA), - NORMALPRIO, conversionThreadMonitor, nullptr); + conversionThreadMonitorWA, sizeof(conversionThreadMonitorWA), + NORMALPRIO + 1, + conversionThreadMonitor, nullptr); conversionThreadHandle = chThdCreateStatic( - conversionThreadWA, sizeof(conversionThreadWA), - NORMALPRIO + 1, conversionThread, nullptr); - - main_loop(); + conversionThreadWA, sizeof(conversionThreadWA), + HIGHPRIO, + conversionThread, + reinterpret_cast(reinterpret_cast(conversionThreadUPWA) + 62 * 1024)); + chThdCreateStatic( + communicationThreadWA, sizeof(communicationThreadWA), + NORMALPRIO, + communicationThread, nullptr); + + chThdExit(0); + return 0; } -void main_loop() +THD_FUNCTION(communicationThread, arg) { - + (void)arg; while (1) { if (USBSerial::isActive()) { // Attempt to receive a command packet @@ -148,6 +146,24 @@ void main_loop() // Packet received, first byte represents the desired command/action switch (cmd[0]) { + // 'a' - Read contents of ADC buffer. + // 'A' - Write contents of ADC buffer. + // 'B' - Set ADC/DAC buffer size. + // 'd' - Read contents of DAC buffer. + // 'D' - Set siggen size and write to its buffer. + // 'E' - Load algorithm binary. + // 'e' - Unload algorithm. + // 'i' - Read "stmdsp" identifier string. + // 'I' - Read status information. + // 'M' - Begin conversion, measure algorithm execution time. + // 'm' - Read last algorithm execution time. + // 'R' - Begin conversion. + // 'r' - Read or write sample rate. + // 'S' - Stop conversion. + // 's' - Get latest block of conversion results. + // 'W' - Start signal generator (siggen). + // 'w' - Stop siggen. + case 'a': USBSerial::write(samplesIn.bytedata(), samplesIn.bytesize()); break; @@ -159,6 +175,8 @@ void main_loop() if (EM.assert(run_status == RunStatus::Idle, Error::NotIdle) && EM.assert(USBSerial::read(&cmd[1], 2) == 2, Error::BadParamSize)) { + // count is multiplied by two since this command receives size of buffer + // for each algorithm application. unsigned int count = (cmd[1] | (cmd[2] << 8)) * 2; if (EM.assert(count <= MAX_SAMPLE_BUFFER_SIZE, Error::BadParam)) { samplesIn.setSize(count); @@ -308,17 +326,6 @@ void main_loop() } } -void conversion_abort() -{ - elf_entry = nullptr; - DAC::stop(0); - ADC::stop(); - EM.add(Error::ConversionAborted); - - chMBReset(&conversionMB); - run_status = RunStatus::Idle; -} - THD_FUNCTION(conversionThreadMonitor, arg) { (void)arg; @@ -333,22 +340,57 @@ THD_FUNCTION(conversionThreadMonitor, arg) } } -__attribute__((section(".convcode"))) -static void convThdMain(); +THD_FUNCTION(conversionThread, stack) +{ + elf_entry = nullptr; + port_unprivileged_jump(reinterpret_cast(conversion_unprivileged_main), + reinterpret_cast(stack)); +} -THD_FUNCTION(conversionThread, arg) +THD_FUNCTION(monitorThread, arg) { (void)arg; - elf_entry = nullptr; - port_unprivileged_jump(reinterpret_cast(convThdMain), - reinterpret_cast(conversionThreadUPWA) + 256); + + bool erroron = false; + while (1) { + bool isidle = run_status == RunStatus::Idle; + auto led = isidle ? LINE_LED_GREEN : LINE_LED_YELLOW; + auto delay = isidle ? 500 : 250; + + palSetLine(led); + chThdSleepMilliseconds(delay); + palClearLine(led); + chThdSleepMilliseconds(delay); + + if (run_status == RunStatus::Idle && palReadLine(LINE_BUTTON)) { + palSetLine(LINE_LED_RED); + palSetLine(LINE_LED_YELLOW); + chSysLock(); + while (palReadLine(LINE_BUTTON)) + asm("nop"); + while (!palReadLine(LINE_BUTTON)) + asm("nop"); + chSysUnlock(); + palClearLine(LINE_LED_RED); + palClearLine(LINE_LED_YELLOW); + chThdSleepMilliseconds(500); + } + + if (auto err = EM.hasError(); err ^ erroron) { + erroron = err; + if (err) + palSetLine(LINE_LED_RED); + else + palClearLine(LINE_LED_RED); + } + } } -void convThdMain() +void conversion_unprivileged_main() { while (1) { msg_t message; - asm("svc 0; mov %0, r0" : "=r" (message)); + asm("svc 0; mov %0, r0" : "=r" (message)); // sleep until next message if (message != 0) { auto samples = MSG_FOR_FIRST(message) ? samplesIn.data() : samplesIn.middata(); auto size = samplesIn.size() / 2; @@ -357,9 +399,9 @@ void convThdMain() if (!MSG_FOR_MEASURE(message)) { samples = elf_entry(samples, size); } else { - //chTMStartMeasurementX(&conversion_time_measurement); + asm("eor r0, r0; svc 2"); // start measurement samples = elf_entry(samples, size); - //chTMStopMeasurementX(&conversion_time_measurement); + asm("mov r0, #1; svc 2"); // stop measurement } } @@ -371,6 +413,40 @@ void convThdMain() } } +void mpu_setup() +{ + // Set up MPU for user algorithm + // Region 2: Data for algorithm manager thread + mpuConfigureRegion(MPU_REGION_2, + 0x20000000, + MPU_RASR_ATTR_AP_RW_RW | MPU_RASR_ATTR_NON_CACHEABLE | + MPU_RASR_SIZE_64K | + MPU_RASR_ENABLE); + // Region 3: Code for algorithm manager thread + mpuConfigureRegion(MPU_REGION_3, + 0x0807F800, + MPU_RASR_ATTR_AP_RO_RO | MPU_RASR_ATTR_NON_CACHEABLE | + MPU_RASR_SIZE_2K | + MPU_RASR_ENABLE); + // Region 4: Algorithm code + mpuConfigureRegion(MPU_REGION_4, + 0x00000000, + MPU_RASR_ATTR_AP_RW_RW | MPU_RASR_ATTR_NON_CACHEABLE | + MPU_RASR_SIZE_64K | + MPU_RASR_ENABLE); +} + +void conversion_abort() +{ + elf_entry = nullptr; + DAC::stop(0); + ADC::stop(); + EM.add(Error::ConversionAborted); + + chMBReset(&conversionMB); + run_status = RunStatus::Idle; +} + void signal_operate(adcsample_t *buffer, size_t) { chSysLockFromISR(); @@ -387,51 +463,13 @@ void signal_operate(adcsample_t *buffer, size_t) void signal_operate_measure(adcsample_t *buffer, [[maybe_unused]] size_t count) { chSysLockFromISR(); - chMBPostI(&conversionMB, buffer == samplesIn.data() ? MSG_CONVFIRST_MEASURE : MSG_CONVSECOND_MEASURE); + chMBPostI(&conversionMB, buffer == samplesIn.data() ? MSG_CONVFIRST_MEASURE + : MSG_CONVSECOND_MEASURE); chSysUnlockFromISR(); ADC::setOperation(signal_operate); } -THD_FUNCTION(monitorThread, arg) -{ - (void)arg; - - bool erroron = false; - while (1) { - bool isidle = run_status == RunStatus::Idle; - auto led = isidle ? LINE_LED_GREEN : LINE_LED_YELLOW; - auto delay = isidle ? 500 : 250; - - palSetLine(led); - chThdSleepMilliseconds(delay); - palClearLine(led); - chThdSleepMilliseconds(delay); - - if (run_status == RunStatus::Idle && palReadLine(LINE_BUTTON)) { - palSetLine(LINE_LED_RED); - palSetLine(LINE_LED_YELLOW); - chSysLock(); - while (palReadLine(LINE_BUTTON)) - asm("nop"); - while (!palReadLine(LINE_BUTTON)) - asm("nop"); - chSysUnlock(); - palClearLine(LINE_LED_RED); - palClearLine(LINE_LED_YELLOW); - chThdSleepMilliseconds(500); - } - - if (auto err = EM.hasError(); err ^ erroron) { - erroron = err; - if (err) - palSetLine(LINE_LED_RED); - else - palClearLine(LINE_LED_RED); - } - } -} - extern "C" { __attribute__((naked)) @@ -466,6 +504,19 @@ void port_syscall(struct port_extctx *ctxp, uint32_t n) } } break; + case 2: + if (ctxp->r0 == 0) { + chTMStartMeasurementX(&conversion_time_measurement); + } else { + chTMStopMeasurementX(&conversion_time_measurement); + // Subtract measurement overhead from the result. + // Running an empty algorithm ("bx lr") takes 196 cycles as of 2/4/21. + // Only measures algorithm code time (loading args/storing result takes 9 cycles). + constexpr rtcnt_t measurement_overhead = 196 - 1; + if (conversion_time_measurement.last > measurement_overhead) + conversion_time_measurement.last -= measurement_overhead; + } + break; default: while (1); break; @@ -475,6 +526,12 @@ void port_syscall(struct port_extctx *ctxp, uint32_t n) while (1); } +__attribute__((naked)) +void MemManage_Handler() +{ + while (1); +} + __attribute__((naked)) void HardFault_Handler() { diff --git a/source/samplebuffer.hpp b/source/samplebuffer.hpp index 9aabfdd..334c048 100644 --- a/source/samplebuffer.hpp +++ b/source/samplebuffer.hpp @@ -6,7 +6,7 @@ using Sample = uint16_t; -// gives 8000 +// gives 8000 (8192) constexpr unsigned int MAX_SAMPLE_BUFFER_BYTESIZE = 16384; constexpr unsigned int MAX_SAMPLE_BUFFER_SIZE = MAX_SAMPLE_BUFFER_BYTESIZE / sizeof(Sample);