* @note The default is @p FALSE.\r
*/\r
#if !defined(CH_DBG_ENABLE_CHECKS)\r
-#define CH_DBG_ENABLE_CHECKS FALSE\r
+#define CH_DBG_ENABLE_CHECKS TRUE\r
#endif\r
\r
/**\r
* @note The default is @p FALSE.\r
*/\r
#if !defined(CH_DBG_ENABLE_ASSERTS)\r
-#define CH_DBG_ENABLE_ASSERTS FALSE\r
+#define CH_DBG_ENABLE_ASSERTS TRUE\r
#endif\r
\r
/**\r
#define STM32_PLLSAI1R_VALUE 4\r
#define STM32_PLLSAI2N_VALUE 24\r
#define STM32_PLLSAI2P_VALUE 7\r
-#define STM32_PLLSAI2R_VALUE 2\r
+#define STM32_PLLSAI2R_VALUE 8\r
\r
/*\r
* Peripherals clock sources.\r
#define STM32_SAI1SEL STM32_SAI1SEL_OFF\r
#define STM32_SAI2SEL STM32_SAI2SEL_OFF\r
#define STM32_CLK48SEL STM32_CLK48SEL_PLLSAI1\r
-#define STM32_ADCSEL STM32_ADCSEL_PLLSAI1\r
+#define STM32_ADCSEL STM32_ADCSEL_PLLSAI2\r
#define STM32_SWPMI1SEL STM32_SWPMI1SEL_PCLK1\r
#define STM32_DFSDMSEL STM32_DFSDMSEL_PCLK2\r
#define STM32_RTCSEL STM32_RTCSEL_LSI\r
}
}
+ unsigned int device::get_sample_rate() {
+ unsigned char result = 0xFF;
+
+ if (connected()) {
+ uint8_t request[2] = {
+ 'r', 0xFF
+ };
+ m_serial.write(request, 2);
+ m_serial.read(&result, 1);
+ }
+
+ return result;
+ }
+
void device::continuous_start() {
if (connected())
m_serial.write("R");
void continuous_set_buffer_size(unsigned int size);
void set_sample_rate(unsigned int id);
+ unsigned int get_sample_rate();
void continuous_start();
void continuous_start_measure();
uint32_t continuous_start_get_measurement();
#include "wxmain.hpp"
+#include <wx/combobox.h>
#include <wx/dir.h>
#include <wx/filename.h>
#include <wx/filedlg.h>
MainFrame::MainFrame() : wxFrame(nullptr, wxID_ANY, "stmdspgui", wxPoint(50, 50), wxSize(640, 800))
{
auto splitter = new wxSplitterWindow(this, wxID_ANY);
+ auto panelToolbar = new wxPanel(this, wxID_ANY);
auto panelCode = new wxPanel(splitter, wxID_ANY);
auto panelOutput = new wxPanel(splitter, wxID_ANY);
+ auto sizerToolbar = new wxBoxSizer(wxHORIZONTAL);
auto sizerCode = new wxBoxSizer(wxVERTICAL);
auto sizerOutput = new wxBoxSizer(wxVERTICAL);
auto sizerSplitter = new wxBoxSizer(wxVERTICAL);
// Member initialization
m_status_bar = new wxStatusBar(this);
- m_text_editor = new wxStyledTextCtrl(panelCode, wxID_ANY, wxDefaultPosition, wxSize(620, 500));
+ m_text_editor = new wxStyledTextCtrl(panelCode, wxID_ANY, wxDefaultPosition, wxSize(620, 440));
m_compile_output = new wxTextCtrl(panelOutput, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxSize(620, 250), wxTE_READONLY | wxTE_MULTILINE | wxHSCROLL);
m_measure_timer = new wxTimer(this, Id::MeasureTimer);
splitter->SetSashGravity(0.5);
splitter->SetMinimumPaneSize(20);
+ auto comp = new wxButton(panelToolbar, Id::MCodeCompile, "Compile");
+ static const wxString srateValues[] = {
+ "16 kS/s",
+ "48 kS/s",
+ "96 kS/s",
+ "100 kS/s",
+ "200 kS/s",
+ "1 MS/s",
+ "2 MS/s"
+ };
+ m_rate_select = new wxComboBox(panelToolbar, wxID_ANY,
+ wxEmptyString, wxDefaultPosition, wxDefaultSize,
+ 7, srateValues, wxCB_READONLY);
+ m_rate_select->Disable();
+
+ sizerToolbar->Add(comp, 0, wxLEFT, 4);
+ sizerToolbar->Add(m_rate_select, 0, wxLEFT, 12);
+ panelToolbar->SetSizer(sizerToolbar);
+ Bind(wxEVT_BUTTON, &MainFrame::onRunCompile, this, Id::MCodeCompile, wxID_ANY, comp);
+ Bind(wxEVT_COMBOBOX, &MainFrame::onToolbarSampleRate, this, wxID_ANY, wxID_ANY, m_rate_select);
+
prepareEditor();
- sizerCode->Add(m_text_editor, 1, wxEXPAND | wxALL, 0);
+ sizerCode->Add(panelToolbar, 0, wxTOP | wxBOTTOM, 4);
+ sizerCode->Add(m_text_editor, 1, wxEXPAND, 0);
panelCode->SetSizer(sizerCode);
m_compile_output->SetBackgroundColour(wxColour(0, 0, 0));
sizerOutput->Add(m_compile_output, 1, wxEXPAND | wxALL, 0);
panelOutput->SetSizer(sizerOutput);
- splitter->SplitHorizontally(panelCode, panelOutput, 500);
+ splitter->SplitHorizontally(panelCode, panelOutput, 440);
sizerSplitter->Add(splitter, 1, wxEXPAND, 5);
SetSizer(sizerSplitter);
menuRun->Append(MRunUnload, "U&nload code"));
Bind(wxEVT_MENU, &MainFrame::onRunEditBSize, this, Id::MRunEditBSize, wxID_ANY,
menuRun->Append(MRunEditBSize, "Set &buffer size..."));
- Bind(wxEVT_MENU, &MainFrame::onRunEditSRate, this, Id::MRunEditSRate, wxID_ANY,
- menuRun->Append(MRunEditSRate, "Set sample &rate..."));
menuRun->AppendSeparator();
Bind(wxEVT_MENU, &MainFrame::onRunGenUpload, this, Id::MRunGenUpload, wxID_ANY,
--remove-section .comment \
--remove-section .noinit \
$0.o
+ arm-none-eabi-size $0.o
)make";
static wxString file_header (R"cpp(
if (result == 0) {
m_status_bar->SetStatusText("Compilation succeeded.");
- m_compile_output->ChangeValue("");
return m_temp_file_name + ".o";
} else {
m_status_bar->SetStatusText("Compilation failed.");
- m_compile_output->LoadFile(make_output);
return "";
}
}
m_open_file_path = openDialog.GetPath();
m_text_editor->SetText(buffer);
m_text_editor->DiscardEdits();
+ m_compile_output->ChangeValue("");
m_status_bar->SetStatusText("Ready.");
}
delete[] buffer;
if (auto devices = scanner.scan(); devices.size() > 0) {
m_device = new stmdsp::device(devices.front());
if (m_device->connected()) {
+ auto rate = m_device->get_sample_rate();
+ m_rate_select->SetSelection(rate);
+ m_rate_select->Enable();
+
menuItem->SetItemLabel("&Disconnect");
m_status_bar->SetStatusText("Connected.");
} else {
delete m_device;
m_device = nullptr;
+
+ m_rate_select->Disable();
menuItem->SetItemLabel("&Connect");
m_status_bar->SetStatusText("Failed to connect.");
}
}
}
-void MainFrame::onRunEditSRate([[maybe_unused]] wxCommandEvent&)
+void MainFrame::onToolbarSampleRate(wxCommandEvent& ce)
{
if (m_device != nullptr && m_device->connected()) {
- wxTextEntryDialog dialog (this, "Enter new sample rate id:", "Set Sample Rate");
- if (dialog.ShowModal() == wxID_OK) {
- if (wxString value = dialog.GetValue(); !value.IsEmpty()) {
- if (unsigned long n; value.ToULong(&n)) {
- if (n < 20) {
- m_device->set_sample_rate(n);
- } else {
- m_status_bar->SetStatusText("Error: Invalid sample rate.");
- }
- } else {
- m_status_bar->SetStatusText("Error: Invalid sample rate.");
- }
- } else {
- m_status_bar->SetStatusText("Ready.");
- }
- } else {
- m_status_bar->SetStatusText("Ready.");
- }
+ auto combo = dynamic_cast<wxComboBox *>(ce.GetEventUserData());
+ m_device->set_sample_rate(combo->GetCurrentSelection());
+ m_status_bar->SetStatusText("Ready.");
} else {
wxMessageBox("No device connected!", "Run", wxICON_WARNING);
m_status_bar->SetStatusText("Please connect.");
void onRunUpload(wxCommandEvent&);
void onRunUnload(wxCommandEvent&);
void onRunEditBSize(wxCommandEvent&);
- void onRunEditSRate(wxCommandEvent&);
void onRunGenUpload(wxCommandEvent&);
void onRunGenStart(wxCommandEvent&);
+ void onToolbarSampleRate(wxCommandEvent&);
+
void onRunCompile(wxCommandEvent&);
void onCodeDisassemble(wxCommandEvent&);
wxTimer *m_measure_timer = nullptr;
wxStatusBar *m_status_bar = nullptr;
wxMenuBar *m_menu_bar = nullptr;
+ wxComboBox *m_rate_select = nullptr;
wxFileOutputStream *m_conv_result_log = nullptr;
wxString m_open_file_path;
wxString m_temp_file_name;
};
constexpr static const GPTConfig gpt_config = {
- .frequency = 14400000,
+ .frequency = 36000000,
.callback = nullptr,
.cr2 = TIM_CR2_MMS_1, /* TRGO */
.dier = 0
};
+#define ADC_CCR_PRESC_DIV1 (0)
+#define ADC_SAMPLE_RATE_SETTINGS_COUNT (7)
static uint32_t adc_sample_rate_settings[] = {
- 10, ADC_SMPR_SMP_47P5, 4608, // 3125
- 11, ADC_SMPR_SMP_12P5, 3840, // 3750
- 9, ADC_SMPR_SMP_47P5, 2304, // 6250
- 10, ADC_SMPR_SMP_12P5, 1920, // 7500
- 8, ADC_SMPR_SMP_47P5, 1152, // 12K5
- 9, ADC_SMPR_SMP_12P5, 960, // 15K
- 7, ADC_SMPR_SMP_47P5, 576, // 25K
- 8, ADC_SMPR_SMP_12P5, 480, // 30K
- 5, ADC_SMPR_SMP_47P5, 360, // 40K
- 4, ADC_SMPR_SMP_47P5, 288, // 50K
- 7, ADC_SMPR_SMP_12P5, 240, // 60K
- 6, ADC_SMPR_SMP_12P5, 180, // 80K
- 5, ADC_SMPR_SMP_12P5, 150, // 96K
- 2, ADC_SMPR_SMP_47P5, 144, // 100K
- 4, ADC_SMPR_SMP_12P5, 120, // 120K
- 3, ADC_SMPR_SMP_12P5, 90, // 160K
- 1, ADC_SMPR_SMP_47P5, 72, // 200K
- 2, ADC_SMPR_SMP_12P5, 60, // 240K
- 0, ADC_SMPR_SMP_47P5, 36, // 400K
- 1, ADC_SMPR_SMP_12P5, 30, // 480K
- 1, ADC_SMPR_SMP_2P5, 18, // 800K
- 0, ADC_SMPR_SMP_12P5, 15, // 960K
- 0, ADC_SMPR_SMP_2P5, 9 // 1M6
+ // Rate PLLSAI2N ADC_PRESC ADC_SMPR GPT_DIV
+ /* 16k */ 8, ADC_CCR_PRESC_DIV10, ADC_SMPR_SMP_12P5, 2250,
+ /* 48k */ 24, ADC_CCR_PRESC_DIV10, ADC_SMPR_SMP_12P5, 750,
+ /* 96k */ 48, ADC_CCR_PRESC_DIV10, ADC_SMPR_SMP_12P5, 375,
+ /* 100k */ 40, ADC_CCR_PRESC_DIV8, ADC_SMPR_SMP_12P5, 360,
+ /* 400k */ 40, ADC_CCR_PRESC_DIV2, ADC_SMPR_SMP_12P5, 90,
+ /* 1M */ 38, ADC_CCR_PRESC_DIV1, ADC_SMPR_SMP_6P5, 36,
+ /* 2M */ 76, ADC_CCR_PRESC_DIV1, ADC_SMPR_SMP_6P5, 18
};
static bool adc_is_read_finished = false;
void set_rate(rate new_rate)
{
auto index = static_cast<unsigned int>(new_rate);
- auto presc = adc_sample_rate_settings[index * 3] << 18;
- auto smp = adc_sample_rate_settings[index * 3 + 1];
- adc_gpt_divisor = adc_sample_rate_settings[index * 3 + 2];
+ auto plln = adc_sample_rate_settings[index * 4] << RCC_PLLSAI2CFGR_PLLSAI2N_Pos;
+ auto presc = adc_sample_rate_settings[index * 4 + 1] << ADC_CCR_PRESC_Pos;
+ auto smp = adc_sample_rate_settings[index * 4 + 2];
+ adc_gpt_divisor = adc_sample_rate_settings[index * 4 + 3];
adcStop(adcd);
+
+ // Adjust PLLSAI2
+ RCC->CR &= ~(RCC_CR_PLLSAI2ON);
+ while ((RCC->CR & RCC_CR_PLLSAI2RDY) == RCC_CR_PLLSAI2RDY);
+ RCC->PLLSAI2CFGR = (RCC->PLLSAI2CFGR & ~(RCC_PLLSAI2CFGR_PLLSAI2N_Msk)) | plln;
+ RCC->CR |= RCC_CR_PLLSAI2ON;
+
// Set ADC prescaler
- adcd->adcc->CCR = (adcd->adcc->CCR & ~(0xF << 18)) | presc;
+ adcd->adcc->CCR = (adcd->adcc->CCR & ~(ADC_CCR_PRESC_Msk)) | presc;
// Set sampling time
adc_group_config.smpr[0] = ADC_SMPR1_SMP_AN5(smp);
adcStart(adcd, &adc_config);
}
+
+ unsigned int get_rate()
+ {
+ for (unsigned int i = 0; i < ADC_SAMPLE_RATE_SETTINGS_COUNT; i++) {
+ if (adc_gpt_divisor == adc_sample_rate_settings[i * 3 + 3])
+ return i;
+ }
+
+ return 0xFF;
+ }
unsigned int get_gpt_divisor()
{
using operation_t = void (*)(adcsample_t *buffer, size_t count);
enum class rate : unsigned int {
- R3125 = 0,
- R3750,
- R6250,
- R7500,
- R12K5,
- R15K,
- R25K,
- R30K,
- R40K,
- R50K,
- R60K,
- R80K,
+ R16K = 0,
+ R48K,
R96K,
R100K,
- R120K,
- R160K,
- R200K,
- R240K,
R400K,
- R480K,
- R800K,
- R960K,
- R1M6
+ R1M,
+ R2M
};
void init();
void set_rate(rate new_rate);
+ unsigned int get_rate();
unsigned int get_gpt_divisor();
adcsample_t *read(adcsample_t *buffer, size_t count);
void read_start(operation_t operation_func, adcsample_t *buffer, size_t count);
};
constexpr static const GPTConfig gpt_config = {
- .frequency = 14400000,
+ .frequency = 36000000,
.callback = nullptr,
.cr2 = TIM_CR2_MMS_1, /* TRGO */
.dier = 0
break;
case 'r':
- if (usbserial::read(&cmd[1], 1) == 1)
- adc::set_rate(static_cast<adc::rate>(cmd[1]));
- else
+ if (usbserial::read(&cmd[1], 1) == 1) {
+ if (cmd[1] == 0xFF) {
+ unsigned char r = static_cast<unsigned char>(adc::get_rate());
+ usbserial::write(&r, 1);
+ } else {
+ adc::set_rate(static_cast<adc::rate>(cmd[1]));
+ }
+ } else {
error_queue_add(Error::BadParamSize);
+ }
break;
// 'S' - Stops the continuous sampling/conversion.
case 's':
if (dac_samples_new != nullptr) {
+ auto samps = reinterpret_cast<const uint8_t *>(
+ const_cast<const dacsample_t *>(dac_samples_new));
+ dac_samples_new = nullptr;
+
unsigned char buf[2] = {
static_cast<unsigned char>(dac_sample_count / 2 & 0xFF),
static_cast<unsigned char>(((dac_sample_count / 2) >> 8) & 0xFF)
unsigned int total = dac_sample_count / 2 * sizeof(dacsample_t);
unsigned int offset = 0;
unsigned char unused;
- auto samps = reinterpret_cast<const uint8_t *>(
- const_cast<const dacsample_t *>(dac_samples_new));
while (total > 512) {
usbserial::write(samps + offset, 512);
while (usbserial::read(&unused, 1) == 0);
}
usbserial::write(samps + offset, total);
while (usbserial::read(&unused, 1) == 0);
- dac_samples_new = nullptr;
} else {
usbserial::write("\0\0", 2);
}