Code generation for Arduino (Direct Digital Synthesis)¶
This example presents a model for direct digital synthesis (DDS) of signals with subsequent execution on an Arduino.
Introduction¶
The task of direct digital synthesis is to generate signals of a given shape at the output of an oscillator with adjustable parameters. In this example, switching by an external discrete signal between five output waveforms - positive and negative slope sawtooth, triangular, sine and meander - will be realised. Two external analogue signals will control the frequency and amplitude of the output signal.
Hardware¶
In this example, the Arduino MEGA 2560 debug board is used as the target device. The output signal is generated at output #9. The digital-to-analogue conversion of the signal is performed using a PWM and RC low-pass filter. PWM frequency is $f_{PWM} = 62.5 кГц$, RC filter cut-off frequency is $f_{c} = 14.185 кГц$, filter order is 2. RC circuit parameters: $R_ф = 330 Ом ,\ C_ф = 34 нФ$.
The output waveform switching signal is fed to digital input No. 2 from the pushbutton contact with the debouncing circuit on the pull-up resistor $R_п = 10 кОм$ and shunt capacitor $C_ш = 75 нФ$.
To control the frequency and amplitude of the output signal, potentiometers with resistance $R_{reg} = 10 кОм$ are connected to analogue inputs A0 and A1 of the Arduino debug board.
The connection diagram of the elements is shown in the figure below.
The output signal is taken with an oscilloscope Hantec DSO at the output of the low-pass filter. Also, a 3.5mm audio output socket is connected after the filter via a current limiting resistor $R_д = 10 кОм$ to output the signal to the speaker.
Model description¶
The arduino_dds
model uses four blocks to communicate with the controller peripherals C Function
:
DigitalInput_Mode
- initialises digital input #2, polls the input status. When modelled in Engee, it generates a periodic sawtooth signal to provide a negative edge at the counter block inputModeCounter
and switch the output waveform.AnalogInput_Freq
- polls the frequency value at the analogue input A0. When modelling in Engee it sets the conditional frequency of the output signal $frequency = 0.5$.AnalogInput_Amp
- interrogates the amplitude value on analogue input A1. When modelling in Engee sets the conditional amplitude of the output signal $amplitude = 1.0$.HFPWM_Output
- initialises the PWM operation at output No. 9 with the maximum available frequency (62.5 kHz) and sends the new value of the pulse width to the PWM controller module.
Details on the operation of peripheral blocks are given in the comments to the code in these blocks.
The algorithms for calculating five given waveforms are defined in subsystems: PositiveSaw
- sawtooth with positive slope, NegativeSaw
- sawtooth with negative slope, Triangle
- triangular, Sinusoidal
- sinusoidal and Square
- meander with 50 % slope. To switch between the algorithms of the output signal shape is used block Multiport Switch
, control to which comes from the subsystem ModeCounter
. In the subsystem ModeCounter
the negative edge of the input signal is highlighted and the number of presses on the button contact is counted.
Thus, when modelling in Engee the output signal with unchanging frequency and amplitude settings will periodically switch between the specified waveforms.
Modelling results¶
Let's load and execute the created model:
Pkg.add(["WAV"])
if "arduino_dds" in [m.name for m in engee.get_all_models()]
m = engee.open( "arduino_dds" );
else
m = engee.load( "$(@__DIR__)/arduino_dds.engee" );
end
data = engee.run(m);
From the obtained model data, plot the generated signal:
using Plots
plotlyjs()
plot(data["pwmduty"].time, data["pwmduty"].value,
legend=false, size=(900,300), lw=2, st=:step)
xlabel!("Время, сек")
ylabel!("Значение")
As can be seen, approximately every 0.2 seconds the output signal changes its shape.
Code generation for Arduino¶
To upload to Arduino you need to generate code from the developed model:
engee.generate_code( "$(@__DIR__)/arduino_dds.engee",
"$(@__DIR__)/arduino_dds_code")
We will connect the files generated in the specified directory in the user sketch arduino_dds.ino
. Download these files and load them into Arduino MEGA using Arduino IDE.
The attached sketch defines macros and global variables, connects user-generated files and third-party libraries, calls initialisation functions and cyclic calculation of the model. The sketch also contains comments to explain how the code works.
Working of the programme on Arduino¶
After successful compilation and loading the sketch into the target device, connect a digital oscilloscope Hantec DSO to the RC-filter output and take a picture of the generated signal waveform. The measurement experience shows switching between the generated waveforms, then generation of a sawtooth signal with adjustable frequency, after that - with adjustable amplitude.
To make the DDS model more representative, a speaker was connected to the output of the RC-chain, and the resulting sound was recorded in the file arduino_dds_audio.wav
. The next code cell allows you to load the received audio file into the script and play it. Play the audio track to make sure that the developed model works. It records the sound at successive switching of the output signal waveform and then adjusting the frequency and amplitude of the sawtooth signal with a positive slope.
using WAV, Base64
x, fs = wavread( "$(@__DIR__)/arduino_dds_audio.wav" );
buf = IOBuffer();
wavwrite(x, buf; Fs=fs);
data = base64encode(unsafe_string(pointer(buf.data), buf.size));
markup = """<audio controls="controls" {autoplay}>
<source src="data:audio/wav;base64,$data" type="audio/wav" />
Your browser does not support the audio element.
</audio>"""
display( "text/html", markup );