From aa74f4e28142f45ad1765935b01019781c5679d6 Mon Sep 17 00:00:00 2001 From: Kai Lauterbach Date: Mon, 12 Feb 2024 11:07:33 +0100 Subject: [PATCH] The waveform generator is now configurable by the serial interface and meas script --- firmware/command_ctrl.ino | 87 ++++++++++++++++++++++++++++++++-- firmware/globals.h | 22 +++++++++ firmware/waveformgenerator.ino | 67 ++++++++++++++++++-------- firmware/waveforms.h | 1 + tools/meas.py | 41 ++++++++++++++++ 5 files changed, 193 insertions(+), 25 deletions(-) diff --git a/firmware/command_ctrl.ino b/firmware/command_ctrl.ino index f5d304c..29bc208 100644 --- a/firmware/command_ctrl.ino +++ b/firmware/command_ctrl.ino @@ -55,6 +55,10 @@ uint8_t cc_commands[] = { CC_CMD_SAV_DFLT, CC_CMD_SET_CLK_CORR, CC_CMD_GET_CLK_CORR, + CC_CMD_SET_WF_FREQ, + CC_CMD_SET_WF, + CC_CMD_SET_WF_DC, + CC_CMD_EN_WF, }; void (*cc_cmd_functions[])() = { @@ -70,6 +74,10 @@ void (*cc_cmd_functions[])() = { CC_CMD_SAV_DFLT_FUNC, CC_CMD_SET_CLK_CORR_FUNC, CC_CMD_GET_CLK_CORR_FUNC, + CC_CMD_SET_WF_FREQ_FUNC, + CC_CMD_SET_WF_FUNC, + CC_CMD_SET_WF_DC_FUNC, + CC_CMD_SET_EN_WF_FUNC, }; uint8_t cc_cmd_data_to_read[] = { @@ -85,6 +93,10 @@ uint8_t cc_cmd_data_to_read[] = { CC_CMD_SAV_DFLT_DATA_TO_READ, CC_CMD_SET_CLK_CORR_DATA_TO_READ, CC_CMD_GET_CLK_CORR_DATA_TO_READ, + CC_CMD_SET_WF_FREQ_DATA_TO_READ, + CC_CMD_SET_WF_DATA_TO_READ, + CC_CMD_SET_WF_DC_DATA_TO_READ, + CC_CMD_SET_EN_WF_DATA_TO_READ, }; uint8_t cc_read_data[CC_READ_DATA_MAX]; @@ -226,12 +238,21 @@ void cc_startMeasurement() uint32_t a1_sum = 0; uint16_t i = 0; - if (freq < 8000) + // TODO an diesem punkt muss unterschieden werden ob eine waveform ausgegeben werden soll oder eine frequenz, und welche Art von Kurve + if (freq < WF_FREQ_MAX_HZ) { - setWaveformFrequency(freq); - setWaveform(WAVEFORM_SINUS); + if (freq > PWM_MAX_VALUE) + { + setWaveform(WAVEFORM_SINUS); + setWaveformFrequency(freq); + } else { + setWaveform(WAVEFORM_DUTYCYCLE); + setWaveformDC((uint8_t)(freq & 0xff)); + } enableWaveformOutput(); + pollWaveformGenerator(); // manually poll the waveformgenerator si5351.output_enable(SI5351_CLK0, 0); // disable clock output 0 + delay(1); } else { disableWaveformOutput(); si5351.set_freq((uint64_t)freq * 100, SI5351_PLL_FIXED, SI5351_CLK0); @@ -269,6 +290,7 @@ void cc_startMeasurement() send16BitValue(a1_sum); sendEOM(); + disableWaveformOutput(); si5351.output_enable(SI5351_CLK0, 0); // disable clock output 0 if (freq >= end_freq) @@ -304,9 +326,16 @@ void cc_enableClk(void) sendSOM(); if (cc_read_data[0] == SI5351_CLK0) { - if (start_freq < 8000) + if (start_freq < WF_FREQ_MAX_HZ) // < 8kHz { - setWaveformFrequency(start_freq); + if (start_freq > PWM_MAX_VALUE) // > 8 bit pwm value + { + setWaveform(WAVEFORM_SINUS); + setWaveformFrequency(start_freq); + } else { + setWaveform(WAVEFORM_DUTYCYCLE); + setWaveformDC((uint8_t)(start_freq & 0xff)); + } enableWaveformOutput(); si5351.output_enable(SI5351_CLK0, 0); } else { @@ -394,6 +423,54 @@ void cc_getClkCorrection(void) sendEOM(); } +void cc_setWFFreq(void) +{ + uint16_t tmp_freq = read16BitDataFromBuffer(0); + + setWaveformFrequency(tmp_freq); + + sendSOM(); + Serial.write(MSG_TYPE_ANSWER_OK); + sendEOM(); +} + +void cc_setWF(void) +{ + uint8_t tmp_wf = cc_read_data[0]; + + setWaveform(tmp_wf); + + sendSOM(); + Serial.write(MSG_TYPE_ANSWER_OK); + sendEOM(); +} + +void cc_setWFDC(void) +{ + uint8_t tmp_dc = cc_read_data[0]; + + setWaveformDC(tmp_dc); + + sendSOM(); + Serial.write(MSG_TYPE_ANSWER_OK); + sendEOM(); +} +void cc_enableWF(void) +{ + uint8_t tmp_en = cc_read_data[0]; + + if (tmp_en == 0) + { + disableWaveformOutput(); + } else { + enableWaveformOutput(); + } + + sendSOM(); + Serial.write(MSG_TYPE_ANSWER_OK); + sendEOM(); +} + /*****************************************************************************/ void cc_init() diff --git a/firmware/globals.h b/firmware/globals.h index 3b8a4fc..72f8e43 100644 --- a/firmware/globals.h +++ b/firmware/globals.h @@ -1,6 +1,16 @@ /*****************************************************************************/ +#define WF_FREQ_MAX_HZ 8000 + +/*****************************************************************************/ + +#define PWM_BIT_WIDTH 8 +#define PWM_PIN 5 // PWM-Pin für DAC0 auf dem Arduino Nano 328 +#define PWM_MAX_VALUE ((1 << PWM_BIT_WIDTH)-1) + +/*****************************************************************************/ + #define MEAS_LOOP_CNT 20 #define MAIN_LOOP_DELAY_US 63 // 1/63us = ~16kHz @@ -49,6 +59,10 @@ #define CC_CMD_SAV_DFLT 0x22 #define CC_CMD_SET_CLK_CORR 0x23 #define CC_CMD_GET_CLK_CORR 0x24 +#define CC_CMD_SET_WF_FREQ 0x30 +#define CC_CMD_SET_WF 0x31 +#define CC_CMD_SET_WF_DC 0x32 +#define CC_CMD_EN_WF 0x33 /*****************************************************************************/ @@ -64,6 +78,10 @@ #define CC_CMD_SAV_DFLT_FUNC &cc_saveDefaults #define CC_CMD_SET_CLK_CORR_FUNC &cc_setClkCorrection #define CC_CMD_GET_CLK_CORR_FUNC &cc_getClkCorrection +#define CC_CMD_SET_WF_FREQ_FUNC &cc_setWFFreq +#define CC_CMD_SET_WF_FUNC &cc_setWF +#define CC_CMD_SET_WF_DC_FUNC &cc_setWFDC +#define CC_CMD_SET_EN_WF_FUNC &cc_enableWF /*****************************************************************************/ @@ -79,6 +97,10 @@ #define CC_CMD_SAV_DFLT_DATA_TO_READ 0 #define CC_CMD_SET_CLK_CORR_DATA_TO_READ 4 #define CC_CMD_GET_CLK_CORR_DATA_TO_READ 0 +#define CC_CMD_SET_WF_FREQ_DATA_TO_READ 2 +#define CC_CMD_SET_WF_DATA_TO_READ 1 +#define CC_CMD_SET_WF_DC_DATA_TO_READ 1 +#define CC_CMD_SET_EN_WF_DATA_TO_READ 1 /*****************************************************************************/ diff --git a/firmware/waveformgenerator.ino b/firmware/waveformgenerator.ino index bce820e..2f26d3e 100644 --- a/firmware/waveformgenerator.ino +++ b/firmware/waveformgenerator.ino @@ -1,17 +1,16 @@ #include "Waveforms.h" -#define PWM_BIT_WIDTH 8 -#define PWM_PIN 5 // PWM-Pin für DAC0 auf dem Arduino Nano 328 - -uint8_t wf_wave0 = 0; -uint8_t wf_pos = 0; -uint16_t wf_freq = 0; +uint8_t wf_wave0 = 0; +uint8_t wf_pos = 0; +uint16_t wf_freq = 0; +uint8_t wf_dutyCycle = 0; unsigned long wf_sample_us = 0; unsigned long wf_prevMicros = 0; -bool wf_outputEnabled = true; // Variable to control waveform output state +bool wf_outputEnabled = true; // Variable to control waveform output state +bool wf_pwm_needs_disabling = true; void initWaveformGenerator() { @@ -19,22 +18,24 @@ void initWaveformGenerator() setWaveform(WAVEFORM_SINUS); // Call the function to set default frequency, here you might want to specify a default frequency setWaveformFrequency(WAVEFORM_DEFAULT_FREQ_HZ); + setWaveformDC(0); + analogWrite(PWM_PIN, 0); } void setWaveform(uint8_t waveform0) { if (waveform0 >= 0 and waveform0 < WAVEFORM_MAXWAVEFORM_NUM) { - // Set default waveforms wf_wave0 = waveform0; } else { + // Set default waveforms wf_wave0 = WAVEFORM_SINUS; } } void setWaveformFrequency(uint16_t frequency) { - if (frequency >= 1 and frequency < 8000) + if (frequency >= 1 and frequency < WF_FREQ_MAX_HZ) { wf_freq = frequency; } else { @@ -43,6 +44,11 @@ void setWaveformFrequency(uint16_t frequency) wf_sample_us = 1000000UL / ((unsigned long)wf_freq * WAVEFORM_MAX_SAMPLES_NUM); } +void setWaveformDC(uint8_t dc) +{ + wf_dutyCycle = dc; +} + void enableWaveformOutput() { wf_outputEnabled = true; @@ -53,27 +59,48 @@ void disableWaveformOutput() wf_outputEnabled = false; } +bool isWaveformEnabled() +{ + return wf_outputEnabled; +} + void pollWaveformGenerator() { if (wf_outputEnabled) { - unsigned long currentMicros = micros(); // Aktuelle Zeit abrufen - if (currentMicros - wf_prevMicros >= wf_sample_us) + + if (wf_wave0 != WAVEFORM_DUTYCYCLE) { - wf_prevMicros = currentMicros; + unsigned long currentMicros = micros(); // Aktuelle Zeit abrufen + if (currentMicros - wf_prevMicros >= wf_sample_us) + { + wf_prevMicros = currentMicros; - uint16_t sample = map(waveformsTable[wf_wave0][wf_pos], 0, 0xfff, 0, (1 << PWM_BIT_WIDTH)-1); - sample = constrain(sample, 0, (1 << PWM_BIT_WIDTH)-1); - analogWrite(PWM_PIN, sample); // write the selected waveform on DAC0 - // analogWrite(PWM_PIN, 128); // write the selected waveform on DAC0 + uint16_t sample = map(waveformsTable[wf_wave0][wf_pos], 0, 0xfff, 0, PWM_MAX_VALUE); + sample = constrain(sample, 0, PWM_MAX_VALUE); + // TODO write the selected waveform on DAC0 + analogWrite(PWM_PIN, sample); - wf_pos++; - if (wf_pos == WAVEFORM_MAX_SAMPLES_NUM) // Reset the counter to repeat the wave - wf_pos = 0; + wf_pos++; + if (wf_pos == WAVEFORM_MAX_SAMPLES_NUM) // Reset the counter to repeat the wave + wf_pos = 0; + } + } else { + // WAVEFORM_DUTYCYCLE + if (analogRead(PWM_PIN) != wf_dutyCycle) + analogWrite(PWM_PIN, wf_dutyCycle); } + + if (!wf_pwm_needs_disabling) + wf_pwm_needs_disabling = true; + } else { - analogWrite(PWM_PIN, 0); + if (wf_pwm_needs_disabling) + { + analogWrite(PWM_PIN, 0); + wf_pwm_needs_disabling = false; + } } } diff --git a/firmware/waveforms.h b/firmware/waveforms.h index 19fcced..05685b0 100644 --- a/firmware/waveforms.h +++ b/firmware/waveforms.h @@ -10,6 +10,7 @@ #define WAVEFORM_SINUS 0 #define WAVEFORM_TRIANGULAR 1 #define WAVEFORM_SAWTOOTH 2 +#define WAVEFORM_DUTYCYCLE 3 static int waveformsTable[WAVEFORM_MAXWAVEFORM_NUM][WAVEFORM_MAX_SAMPLES_NUM] = { // Sin wave diff --git a/tools/meas.py b/tools/meas.py index a3905ae..d437c48 100644 --- a/tools/meas.py +++ b/tools/meas.py @@ -43,6 +43,14 @@ parser.add_argument("-c", "--get_config", default=False, help="", action='store_ parser.add_argument("-l", "--enable_clk", type=int, help="") # disable clk parser.add_argument("-L", "--disable_clk", type=int, help="") +# enable/disable WaveForm +parser.add_argument("-W", "--enable_wf", type=int, help="") +# WaveForm form (0 sinus, 1 triangular, 2 sawtooth) +parser.add_argument("-w", "--form_wf", type=int, help="") +# WaveForm frequency (not related to PWM frequency) +parser.add_argument("-q", "--freq_wf", type=int, help="") +# WaveForm PWM duty cycle +parser.add_argument("-D", "--dc_wf", type=int, help="") # save default config parser.add_argument("-S", "--save_config", default=False, help="", action='store_true') @@ -75,6 +83,10 @@ CC_CMD_GET_CONFIG = 0x10 CC_CMD_EN_CLK = 0x20 CC_CMD_DIS_CLK = 0x21 CC_CMD_SAV_DFLT = 0x22 +CC_CMD_SET_WF_FREQ = 0x30 +CC_CMD_SET_WF = 0x31 +CC_CMD_SET_WF_DC = 0x32 +CC_CMD_EN_WF = 0x33 ############################################################################### @@ -626,6 +638,35 @@ if __name__ == "__main__": sendSerialData([CC_CMD_DIS_CLK, args.disable_clk]) dataSend = dataSend + 1 + if args.enable_wf != None: + if args.enable_wf < 0 or args.enable_wf > 1: + args.enable_wf = 0 + print(("Disabling" if args.enable_wf == 0 else "Enabling") + " wave form output") + sendSerialData([CC_CMD_EN_WF, args.enable_wf]) + dataSend = dataSend + 1 + + if args.form_wf != None: + if args.form_wf < 0 or args.form_wf > 3: + args.form_wf = 0 + print("Wave form type is set to %d" % (args.form_wf)) + sendSerialData([CC_CMD_SET_WF, args.form_wf]) + dataSend = dataSend + 1 + + if args.freq_wf != None: + if args.freq_wf < 0 or args.freq_wf > 7999: + args.freq_wf = 0 + print("Wave frequency set to %d" % (args.freq_wf)) + sendSerialData([CC_CMD_SET_WF_FREQ, (args.freq_wf & 0x0000ff00) >> 8, + (args.freq_wf & 0x000000ff)]) + dataSend = dataSend + 1 + + if args.dc_wf != None: + if args.dc_wf < 0 or args.dc_wf > 255: + args.dc_wf = 0 + print("PWM duty cycle set to %d" % (args.dc_wf)) + sendSerialData([CC_CMD_SET_WF_DC, args.dc_wf]) + dataSend = dataSend + 1 + if args.save_config == True: print("Save default configuration values...") sendSerialData([CC_CMD_SAV_DFLT])