Page Contents
System Overview
Project details for the hardware can be found here
Required Kicad Hardware library: https://github.com/cracked-machine/KicadLibrary
For details of the MCU configuration and firmware refer to FunctionGeneratorCortexM4_SW
Note, RevB was the final design. RevC was not built and is an untested future proposal.
Features
This STM32-based instrument has the following features:
- Output signal with synchronized auxiliary output for re-triggering.
- Input signal trigger using frequency or voltage.
- User-modifiable output attributes including function, frequency, gain and DC offset.
- Frequency Sweep mode.
- RGB colour TFT LCD display.
- Small form factor.
Specification
Attribute | Limits |
---|---|
Power Supply | 9 Volts, 163 mA DC, Center-positive 2.1mm barrel jack, Reverse-polarity protected |
Input/Output connectors | BNC, 400W TVS protection |
Function | Sine, Square, Ramp, Reverse Ramp, Triangle, Pulse, PWM (aux output only) |
Frequency | 0.1Hz – 100KHz |
Gain | 40 dbmV – 79.8 dbmV, 0.1 Vpp – 9 Vpp |
DC offset | +/- 9V |
Output Noise (100KHz) | -76 db (10KΩ), 60 db (500Ω), 11 nV/√Hz |
Output Current | 10 mA nominal, 20 mA peak |
Sweep | 12.5 sec per step (max), 0.59 nanosec per step (min) |
Input trigger range | See “Voltage Measurements” section |
Dimensions | Height: 70mm, Width: 170mm, Depth: 170mm |
Theory of Operation
Input signals can be used as a trigger, capturing on voltage level or edge detection.
DAC1 synthesises the main output signal waveform and sends it to a voltage gain amplifier (LTC6910-3). The signal is then mixed with the DC offset signal from DAC2. The signal is then passes through a lowpass filter to remove any high frequency noise.
DAC2 is a DC signal 0-3.3V. This is sent to a buffer and inverting buffer. Either output is selected using the MCU-controlled SPDT switch IC (TS12A12511DCNR). This applies a software configurable DC offset between +3.3V and -3.3V to the main output signal.
DAC3 is an output signal synchronised to DAC1 to be used for triggering purposes.
System Design
Event Manager
EventManager.h defines system states and events for the menu display and user controls (buttons and rotary encoder).
Active event and state are held in global variables eNextState and eNewEvent, respectively.
Interrupts triggered by the buttons and rotary encoder are processed by InterruptManager.c, which sets the global event variable to the appropriate event.
The EM_ProcessEvent function is periodically called by Timer #17.
EM_ProcessEvent selects the current state and calls the related event handler for the new event. A simplified version is shown below:
void EM_ProcessEvent()
{
switch(eNextState)
{
case someState1:
if(eNewEvent == evSomeEvent1)
eNextState = doSomeEventHandler1();
break;
if(eNewEvent == evSomeEventN)
eNextState = doSomeEventHandlerN();
break;
case someStateN:
....
}
}
The Event handler for the new event is called and returns the next system state.
Business logic for Top level menu, Function menu, Frequency menu, Gain menu and Offset Bias menu are delegated to separate files.
List of system states and events
System State | System Event |
---|---|
Toplevel_Main_Menu_State | evIdle |
Toplevel_Output_Menu_State | evBlueBtn |
Toplevel_Input_Menu_State | evGreenBtn |
Func_Main_Menu_State | evYellowBtn |
Func_Signal_Menu_State | evRedBtn |
Func_Aux_Menu_State | evEncoderSet |
Gain_Main_Menu_State | evEncoderPush |
Gain_Signal_Menu_State | evSweepEnableBtn |
Gain_Aux_Menu_State | evSweepModeBtn |
Freq_Main_Menu_State | evSweepSpeedBtn |
Freq_Preset_Menu_State | evSweepLimitBtn |
Freq_Adjust_Menu_State | |
Freq_Sweep_Menu_State | |
Freq_Prescaler_Menu_State | |
Bias_Menu_State | |
Idle_State = Toplevel_Main_Menu_State |
Display Manager
DisplayManager.h defines a standard colour palette used by the graphics library.
The ILI9341 LCD driver IC has a very low refresh rate. To avoid flicker, the background is redrawn only on eSystemState change (when the user navigates to a different menu screen). All text is periodically redrawn by Timer15, which executes DM_UpdateDisplay() function. To avoid flicker, text strings must be positioned so that they do not overlap.
The DisplayManager queries the active system state and determines which menu is to be enabled. The business logic of drawing the menus is delegated to seperate files. The system state variable is passed to the file for further sub-menu delegation.
Output signal
The output function of the device is generated through a series of wavetables.
These wavetables are generated using python scripts into C source files.
The python scripts and wavetable source files can be found in the WaveTableGeneration directory.
The wavetables are generated at 120 samples per second and offset above the zero point.
The wavetable data is loaded into DAC1 Channel 1 via DMA, which is triggered via Timer 8. This timer must have its auto-reload preload enabled so that the DMA peripheral is not interruped mid-cycle. Interrupting the DMA peripherla mid-cycle can cause the DAC output to randomly fail.
DC voltage is output from DAC1 Channel 2. This offset is (optionally) inverted and mixed with the output signal from DAC1 Channel 1 to provide DC offset at the device output.
A PGA was included in the HW design to provide gain at the device output. However, the settling time of the PGA was insufficient, which caused significant “jitter”. Therefore, the PGA is left at maximum gain, whilst realtime gain adjustments are achieved in SW by modifying the amplitude of the wavetable data.
An auxiliary output is also provided on pin PA6 using DAC2 Channel1. This aux output uses the same trigger timer (TIM8) as DAC1 and so is syncronized with the main output signal.
The auxiliary output provides same signal functions plus a pulse width modulated function. This is achieved by disabling the DAC2 Channel1 output and redirecting the Output Compare register of TIM3 on pin PA6.
The output frequency of all outputs are adjusted simulataneously by modifying the reload register of the trigger timer (TIM8).
A frequency sweep feature is also implemented.
Input Trigger
Input trigger function including external multiplexing, DMA callbacks, frequency and voltage measurements are handled by InputTrigger.c
External Multiplexer
An external “TS5A3357” SP3T switch (datasheet) selects the input signal path into the microcontroller.
IN1 | IN2 | FUNCTION |
---|---|---|
H | L | TIM2 (PA0) |
L | H | COMP (PA1) |
H | H | ADC (PA2) |
TS5A3357 pins IN1 and IN2 are set/reset by microcontroller pins PC8 and PC9, respectively.
Frequency Measurement
In “Time Mode” the input signal frequency is measured using reciprocal counting methods with TIM2.
- When this mode is enabled TIM2 is enabled and begins counting to 0xFFFF.
- The input signal is externally multiplexed into port PA0 (set to alt. function TIM2_CH1).
- This is internally multiplexed using the interconnect to “tim_ti1_in0”.
- A rising edge detected on the input signal triggers a “tim_ti1_fp1” signal to Input Capture Channel 1 and the slave controller.
- TIM2 is configured to reset its count on “tim_ti1_fp1” trigger signal. This sends an write request to the DMA controller and contents of CCR1 is written to memory.
- On timer capture callback, the frequency in hertz is then calculated:
Freq = MCLK / (TIM2->PSC * TIM2->CCR1)
-
Longer processing delays for input frequencies lower than 50Hz are expected.
- At these lower frequencies the input trigger automatically enters “LF Mode” and adjusts the prescaler to improve resolution/accuracy.
Voltage Measurements
The ADC measures the voltage level of the input signal and compares it – within the nearest 0.05V – to the values in the following lookup table:
note | volts | hertz | period |
---|---|---|---|
C0 | 0.08 | 16.35 | 42813 |
C#0 | 0.17 | 17.32 | 40416 |
D0 | 0.25 | 18.35 | 38147 |
D#0 | 0.33 | 19.45 | 35990 |
E0 | 0.42 | 20.60 | 33981 |
F0 | 0.50 | 21.83 | 32066 |
F#0 | 0.58 | 23.12 | 30277 |
G0 | 0.67 | 24.50 | 28571 |
G#0 | 0.75 | 25.96 | 26965 |
A0 | 0.83 | 27.50 | 25455 |
A#0 | 0.92 | 29.14 | 24022 |
B0 | 1.00 | 30.87 | 22676 |
C1 | 1.08 | 32.70 | 21407 |
C#1 | 1.17 | 34.65 | 20202 |
D1 | 1.25 | 36.71 | 19068 |
D#1 | 1.33 | 38.89 | 17999 |
E1 | 1.42 | 41.20 | 16990 |
F1 | 1.50 | 43.65 | 16037 |
F#1 | 1.58 | 46.25 | 15135 |
G1 | 1.67 | 49.00 | 14286 |
G#1 | 1.75 | 51.91 | 13485 |
A1 | 1.83 | 55.00 | 12727 |
A#1 | 1.92 | 58.27 | 12013 |
B1 | 2.00 | 61.74 | 11338 |
C2 | 2.08 | 65.41 | 10702 |
C#2 | 2.17 | 69.30 | 10101 |
D2 | 2.25 | 73.42 | 9534 |
D#2 | 2.33 | 77.78 | 9000 |
E2 | 2.42 | 82.41 | 8494 |
F2 | 2.50 | 87.31 | 8017 |
F#2 | 2.58 | 92.50 | 7568 |
G2 | 2.67 | 98.00 | 7143 |
G#2 | 2.75 | 103.83 | 6742 |
A2 | 2.83 | 110.00 | 6364 |
A#2 | 2.92 | 116.54 | 6007 |
B2 | 3.00 | 123.47 | 5669 |
C3 | 3.08 | 130.81 | 5351 |
C#3 | 3.17 | 138.59 | 5051 |
D3 | 3.25 | 146.83 | 4767 |
D#3 | 3.33 | 155.56 | 4500 |
Timer function assignment
List of timer peripherals and their system functions:
Timer | Function | Notes |
---|---|---|
TIM1 | Rotary Encoder | Encoder Mode TI2 |
TIM2 | Input Trigger | Input Capture Direct Mode (see Input Trigger section). Preload Enabled |
TIM3 | PWM function | AUX output only |
TIM5 | Frequency Sweep | Both outputs (32bit timer) |
TIM8 | DAC Trigger | Update Event. Preload Enabled |
TIM15 | Display Manager | Calls DM_UpdateDisplay() |
TIM16 | Button debounce | |
TIM17 | Event Manager | Called EM_ProcessEvent() |
Graphics library
This project contains a modified and optimized ILI9341 Library: Optimized_STM32_ILI9341
- Optimized to use direct-to-register SPI for single- and multi-byte transfers (MOSI only). This offers a noticeable performance boost over HAL API.
- Draw functions were modified to use x,y,width,height parameters.
- Additional draw functions from STMBasicGUI were included.
The original version of the STM32-ILI9341 library.
STM32G474RE pin mapping
Full STM32Cube report be found here.
Daughter boards
The display, controls and i/o connectors are connected via daughter boards to the main board via ribbon cable. An example of the display daughter board and its ribbon cable can be seen in the video below:
https://www.instagram.com/p/CA5NSdBhmBY/?utm_source=ig_web_copy_link
Power supply
Current Consumption:
Component | Type | Current |
---|---|---|
STM32G4 | MCU | 42mA (max) |
TL972 | OPAMP | 3.2mA (per amplifier) |
LTC6910-3 | PGA | 4.9mA |
TS12A12511 | SPDT | 1uA |
74LVC1G3157 | SPDT | 35uA |
LCD TFT | display | 60mA |
Total | 120mA |
The 9V input is regulated down to 3.3V and 5V for the MCU and LCD display.
Dual supply for the VGA and opamps are provided using multiple TPS60400 charge pumps. TPS60400 are rated at 60mA output but in testing was found to be less. Therefore, multiple TPS60400 were required to provide “point-of-load” regulation.
Additional filtering is provided at the MCU supply pins with L1 and L2 ferrite beads and C1-C12 bypass capacitors.
A midpoint reference 2.5V voltage is provided to the LTC6910-3 VGA using a TL431DBZ precision programmable reference.
Limitations
The power supply limits the output to 9Vp-p. The output swing of the VGA limits this further.
The VGA output current is limited to ~25mA. This is also limited by the power supply.
Due to the settling time of the VGA, smooth sweeps between output amplitude levels using this IC was not possible. As such, the output is fixed to the maximum VGA level. Output amplitude control was handled by the firmware instead.