Notifications
Clear all

A $5 Function Generator with ESP32

8 Posts
3 Users
2 Likes
12.2 K Views
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

   
YurkshireLad reacted
Quote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

Further testing revealed that both square and triangle wave frequencies were quite accurate (less than 0.5%) but the sine wave frequency was off to about +2.5%.

I tested this at 8kHz, 40kHz and 80kHZ. The resulting sine wave frequency was measured to be 8.2KHz, 41.1kHz and 82.1kHz respectively.

So I tweaked the SINFAKT constant from 127.0 to 130.0 and this has corrected the error.

This tweak had no noticeable effect on the square and triangle wave frequencies.

I also noticed that the square wave was producing about 21% overshoot and undershoot but a small capacitor in the pF range should be enough to compensate for this.


   
YurkshireLad reacted
ReplyQuote
(@yurkshirelad)
Member
Joined: 3 years ago
Posts: 493
 

I think I'll try this out - I need a basic sine wave generator with a low frequency. Thanks!


   
ReplyQuote
(@yurkshirelad)
Member
Joined: 3 years ago
Posts: 493
 

I ran the article through Google translate:

In this article we want to build a function generator with an ESP32 that uses 100 percent of the hardware of the ESP32. The software is only used for operation. Since the waveforms are generated by the built-in hardware of the ESP32, there are no interference with the program flow.

The function generator supplies sine and square wave signals with a frequency of 20Hz to 200kHz, as well as triangular signals with a frequency of 40Hz to 20kHz. The pulse duty factor can be set between 0 and 100% for rectangles and triangles. The output voltage is only positive between 0 and 3.3 V. The signal can be taken from GPIO26 of the ESP32. It is operated via the serial interface.

In the second part, the function generator receives a display and operation via joystick and, of course, a housing from the 3D printer.

The sine generator

The ESP32 has a built-in sine wave generator that can output its signal at the two digital to analog converter outputs (GPIO25 and GPIO26). A period can be divided into up to 65536 steps. The internal 8MHz clock is used as the clock. This means that for one step per cycle the frequency would have to be 8,000,000 / 65536 = 122 Hz. Tests have shown, however, that the frequency with this setting is 127 Hz. Thus the internal clock is higher than 8MHz.

To set the frequency, the step size per cycle can be set. That means the frequency = 127 * step size. The frequency can thus be set in 127 Hz steps. Since this is too imprecise for low frequencies, there is a second setting option. The measure can be divided by 1 to 8. This means that the lowest frequency is 127/8 = 15.9 Hz. The entire frequency formula is therefore frequency = 127 / prescaler * increment. For small frequencies it looks like this.

You can see that in order to approximate a desired frequency as closely as possible, one has to try out one of the two variables, step size or prescaler. Since the increment 65536 possibilities, but the prescaler only has eight possibilities, it is obvious to try out the prescaler.

To set the frequency, we calculate the step size for each of the possible prescaler settings and use the one at which the smallest frequency deviation occurs. In order to achieve a nice sinusoidal shape, the step size should not be larger than 1024. A sine wave is thus composed of 64 steps.

Since there is no complete library for the sine wave generator, the corresponding bits must be set in the control registers of the ESP32. Anyone who is interested in how this works in detail will receive the necessary information from

ESP32 Technical Reference Manual

and to control the registers from the Arduino IDE

https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/soc/soc/soc.h

The rectangle generator

The ESP32 has internal timers with which square-wave signals with an adjustable duty cycle can be generated at any GPIO pin. These signals are primarily intended to generate pulse width modulation, but can also be used as a square wave generator with a variable duty cycle.

With the function ledcAttachPin (26,1) GPIO26 is defined as a signal output for timer 1. The function ledcSetup (1, frequency, 7) sets the frequency for Timer1 and the resolution for the duty cycle to 7 bits. The function ledcWrite (1,127.0 * ratio / 100) sets the duty cycle of Timer1. 127 is the maximum number of steps with 7 bits. The variable ratio contains the duty cycle in percent. The connection GPIO26 is released again with ledcDetachPin (26).

The triangle generator

The built-in I2S interface was used for the triangle generator. An operating mode of the I2S interface enables audio data, for example from a WAV file, to be output to the two analog outputs GPIO25 and GPIO26.

The output takes place as a stereo signal, namely the right channel on GPIO25 and the left on GPO26. Each sample has 32 bits. The more significant 16 bits contain the right and the less significant the left channel. Other settings for 1-channel output and 8-bit are possible, but do not work. A FiFo (First in, First out) buffer is used for output.

Now the trick that we use to create a triangle generator with it. If the entire FiFo buffer is filled with exactly one period of the triangular signal and no further writing takes place, the I2S interface outputs the contents of the FiFo buffer again and again at the set sampling rate.

Experiments have shown that the sampling rate can be between 5.2 kHz and 650 kHz. If we use 128 samples for a period, this results in a frequency range of 5200/128 = 40.6 Hz to 5.1 kHz. For higher frequencies, the number of samples per period must be reduced. With 64 samples you get 10kHz with 32 samples 20kHz and with 16 samples 40kHz. However, the shape of the curve becomes worse and worse as the number of samples decreases. See second figure with 16 steps per period.

The duty cycle can be used to create a sawtooth instead of a triangle signal. Depending on the pulse duty factor, the sampled values are divided per period. With a pulse duty factor of 20%, 0.2 * 128 = 26 steps are used for the rise and 102 steps for the falling edge.

The software

(Source Code)

Service

It is operated via the serial interface. At the top of the serial monitor is a line in which the commands can be entered. With the "Send" button, the text is sent to the serial interface.

The following commands are possible:

MS sinus
MR rectangle
MT triangle
F #### frequency in heart
R ## duty cycle in percent

Lower case letters can also be used. # stands for number entry.

Here is the whole article for download.


   
ReplyQuote
(@yurkshirelad)
Member
Joined: 3 years ago
Posts: 493
 
This post was modified 2 years ago by YurkshireLad

   
ReplyQuote
(@yurkshirelad)
Member
Joined: 3 years ago
Posts: 493
 

I need to work out how to reduce the amplitude to somewhere around 500mV-1V peak to peak max.


   
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 5 years ago
Posts: 2042
 

@yurkshirelad 

Comments translated (I don't know how to enable syntax highlighting):

The important thing is you have the indents.  When it is copied and pasted into an IDE the highlights will appear as set for that IDE.

With the Arduino IDE you can Select All and the Save as HTML.  In your post hit the enter key a few times and then click the {;} button in the top bar. Insert between a <p></p> pair.

 

 


   
ReplyQuote
(@yurkshirelad)
Member
Joined: 3 years ago
Posts: 493
 

Thanks, I'll try to remember that for next time. 👍 


   
ReplyQuote