element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
DIY Test Instrumentation
  • Challenges & Projects
  • Project14
  • DIY Test Instrumentation
  • More
  • Cancel
DIY Test Instrumentation
Blog SSFG - Simple stupid function generator
  • Blog
  • Forum
  • Documents
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join DIY Test Instrumentation to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: amgalbu
  • Date Created: 11 Aug 2021 7:25 AM Date Created
  • Views 2043 views
  • Likes 14 likes
  • Comments 10 comments
  • stupid simple function generator
  • ssfg
  • project14
Related
Recommended

SSFG - Simple stupid function generator

amgalbu
amgalbu
11 Aug 2021

I recently went through this blog post

Creating a function generator from an Arduino board that can be programmed by means of a VT100 serial terminal looks a good idea to. After all, it's a very common scenario to have a PC on your workbench and, if you don't have a PC, you have a Raspberry Pi or another Linuxe-based board. So it makes a lot of sense to use the PC as your instrument's user interface. And if the user interface is available through a VT100 serial connection, than you have created the universal user interface!

 

 

ANSI escape sequences

When I say "VT100 serial connection", it's not 100% correct. Actually VT100 is just one of the first terminals to support ANSI escape codes to control cursor, change text and background color, and perform many other tasks that allows you to create a very basic graphic UI, However the VT100 added a number of extended codes to support special features light controlling the keyboard LEDs that led this proprietary version to uptake the standard version of the ANSI escape codes and become the de-facto standard of terminal emulators

 

 

Escape sequences are commands prefixed by the character sequence

     ESC [

This sequence is also called Control Sequence Introducer (CSI). CSI is follwed by a number of character that defines the command to execute and eventually the command parameters. For example, to move the cursor down the device the terminal emulator is connected to will send the following sequence of characters

     ESC [ 1 B

or

     CSI 1 B

"1" is a parameter that tells the terminal the number of cells to move the cursor. The complete list of escape sequences is available here

So from this short explanation it's clear that terminal emulator must be able to interpret correctly escape sequences. This means you need to install a terminal emulation software on your PC. I think MobaXTerm is really great project and worth to be evaluated

 

Arduino and VT100

I found a complete "server-side" implementation of VT100 protocol here. This library can not be installed from the Arduino IDE's library manager. To install, just

  • download the source code as a zip file
  • unzip in c:\Users\<Your user>\Documents\arduino\libraries
  • Restart the Arduino IDE

Using the VT100 terminal functions, is quite easy

  • define the BasicTerm object

#include <BasicTerm.h>
BasicTerm term(&Serial);

 

  • Initialize the Arduino serial port

    Serial.begin(115200);

 

  • initalize the terminal

    term.init();

 

  • start using the terminal object

    term.cls();
    term.show_cursor(false);

 

 

Implementing the user interface

By leveraging the terminal functions, I created some simple classes that implement the UI basic components. Currently I implemented only the components I need for this specific project but the software has been designed to be extended. Currently, the following classes are available

  • label
  • input field to enter a numeric value
  • combo box
  • "button"
  • form, that draws the frame and some other graphical elements and supervises the UI components it contains

Each UI component is derived from a base class, called VTItem so that all UI components can be handled by the form with no regard of the actual UI component type. In software engineering jargon, VTItem is the interface and here we are applying the Liskov Substitution Principle (aka LSP). The VTItem interface expses the following methods

 

    virtual void draw()

     draw the UI component

 

    virtual void apply()

     confirm the value being edited

 

    virtual bool handleKey(int key)

     handles the key and update the UI accordingly

 

    virtual bool canFocus()

     return true if the UI component can take the focus, false otherwise (e.g. a label)

 

    virtual void setFocus(bool focus)

     gives focus to or gets focus from the UI component

 

All derived UI components need to implement a specialized version of these function

 

The user interface

With the above-mentioned components, I created the following forms

 

image

 

At the top, there are 5 lines to configure the function to generate on each PIN. In this case, I am using a Arduino Nano 33 IoT and I selected 5 of the pins that support PWM.

 

image

https://github.com/ostaquet/Arduino-Nano-33-IoT-Ultimate-Guide

 

 

From the combo box, you can select the waveform to generate, namely

  • None (pin not used)
  • Square
  • Triangle
  • Sawtooth
  • User defined

For square, triangle and sawtooth, one can enter the desired frequency. Note that the square waveform is not generated using a PWM, but by driving the pin

Triangle and sawtooth waveforms are generated using PWM and the TurboPWM library. More details are below

"User defined" waveform is created as a sequence of "high" and "low" logical states. Such steps are configured by means of the following form

 

image

 

PWM and analog signals

The Arduino Nano does not have a DAC converter to generate the analog values of a sinusoidal waveform. The solution is to use PWM and a low-pass filter.

You can find a great explanation at this link

https://create.arduino.cc/projecthub/Arduino_Scuola/build-a-simple-dac-for-your-arduino-4c00bd

 

The Arduino Nano's PWM peripherals (and, in general, all the SAMD21-based Arduino boards) can be programmed by means of the TurboPWM library, which allows you to generate PWM signals with any frequency. According to the TurboPWM documentation,

  • For the Arduino Nano 33 IoT, you need to initialise timer 1 for pins 4 and 7, timer 0 for pins 5, 6, 8, and 12, and timer 2 for pins 11 and 13;
  • For the Arduino Zero (untested), you need to initialise timer 0 for pins 3, 4, 10 and 12, timer 1 for pins 8 and 9, and timer 2 for pins 11 and 13;
  • For the Arduino MKR series (untested), you need to initialise timer 1 for pins 2 and 3, timer 0 for pins 4, 5, 6 and 7, and timer 2 for pins 8 and 9;
  • For the Adafruit Trinket M0, you need to initialise timer 0 for pins 0 and 2, and timer 1 for pins 3 and 4.

 

I am going to use a passive filter, because I expect to have loads that takes less than 10mA. So the circuit for the low-pass filter is very simple:

image

The cut-off frequency is given by the formula

image

When designing the low-pass filter, there is a fundamental trade-off to consider:

     A lower cutoff frequency means less ripple and longer settling time; a higher cutoff frequency means more ripple and shorter settling time. So we have to think about your application and decide if you want a DAC that is more responsive or less subject to output ripple.

 

I will configure the PWM to have a frequency of 2 kHz

 

  pwm.setClockDivider(1, false);
  pwm.timer(0, 1, 750, false);
  pwm.enable(0, true);

 

and I will design a low pass filter that about 10 Hz. With R = 6,8 kOhm and C = 2.2 uF, the cut-off frequency is 10,64 Hz, which is good

Back to the code, the analog waveforms are generated using lookup tables generated using this site

https://www.daycounter.com/Calculators/

 

The Arduino application will update the PWM, as time passes, with the values in the lookup table

 

  // get the current microseconds since start
  long us = micros();  
  
  // how many microseconds since the run command?
  long usDelta = us - runStart;

  // usStep is the number of microseconds for each of the 128 steps in the
  // lookup table. usStep is calculated as the waveform period divided by 128
  long lIndex = usDelta / ps->usStep;

  // get the index to the lookup table
  int index = (int)(lIndex & 0x7F);

  // get value from table
  int value = table[index];

  // write to PWM
  if (value != ps->value)
  {
    int ivalue = value * 1000 / 255;
    pwm.analogWrite(pin, ivalue);
    //analogWrite(pin, value);
    ps->value = value;
    ps->index = index;
  }

 

The final setup is shown in picture below: I have just the Arduino Nano and the low-pass filter

 

image

 

 

This is the output for a 10 Hz triangle waveform

 

image

Looks good, but the ripple is quite high (about 100 mV)

 

image

 

Here is video with the SSFG in action

 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

 

Conclusions

The final outcome of this project is not very satisfactory and a lot of work needs to be done to implement a better low-pass filter and to shift level of the waveforms (the desired RMS value for a sine wave is 0V...)

However I think I achieved two major goals with this project

  1. I created a framework to will allow to create user interfaces using ASCII escape codes
  2. I created an interesting tool to simulate specific sequences of logical signals. This could be very useful when you are developing an application and want to stimulate it with a given sequence of 1s and 0s. It would be interested to add some logic like "switch output x to high 100 ms after input y switches to low"ù

 

Source code is available at

https://github.com/ambrogio-galbusera/ssfg

  • Sign in to reply

Top Comments

  • amgalbu
    amgalbu over 4 years ago in reply to javagoza +3
    Thank you Enrique! I missed that detail. I see just now in the official pinout that pin a0 can be configured as a DAC I can program the A0 as DAC and keep PWM + low-pass filter on other pins Thanks for…
  • amgalbu
    amgalbu over 4 years ago in reply to navadeepganeshu +2
    navadeepganeshu Thanks for your feedback! The waveforms are not perfectly smooth (ripple is consistent), I will try a second-order low-pass filter to minimize this problem and post conclusions Ambrogi…
  • amgalbu
    amgalbu over 4 years ago in reply to navadeepganeshu +2
    Hello navadeepganeshu Thanks for your comment but this is a software filter to filter out an input analog signal. What I have to build is instead an hardware low-pass filter to convert a pwm signal into…
  • kevinmp
    kevinmp 9 months ago

    have a look at dac function generator  https://github.com/RobTillaart/FunctionGenerator

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • amgalbu
    amgalbu over 4 years ago in reply to javagoza

    Thank you Enrique!

    I missed that detail. I see just now in the official pinout that pin a0 can be configured as a DAC

    I can program the A0 as DAC and keep PWM + low-pass filter on other pins

     

    Thanks for your suggestion

    Ambrogio

    • Cancel
    • Vote Up +3 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • dubbie
    dubbie over 4 years ago

    amgalbu ,

     

    Great project. I've tried using escape codes with an Arduino to control a PC display, but without much success, so I might have to look into the VT100 library that you have identified if I ever need to do this again.

     

    Dubbie

     

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • javagoza
    javagoza over 4 years ago

    Hi, amgalbu the Arduino Nano 33 IoT has a digital-to-analog converter (DAC) attached to pin A0.

     

      // set DAC resolution to 10-bit:
      analogWriteResolution(10);

    then

     

      // set the DAC using the analog in level:
      analogWrite(A0, level);

     

    https://content.arduino.cc/assets/mkr-microchip_samd21_family_full_datasheet-ds40001882d.pdf

    The Analog-to-Digital Converter (ADC) converts analog signals to digital values. The ADC has 12-bit resolution, and is capable of converting up to 350ksps. The input selection is flexible, and both differential and single-ended measurements can be performed. An optional gain stage is available to increase the dynamic range. In addition, several internal signal inputs are available. The ADC can provide both signed and unsigned results. ADC measurements can be started by either application software or an incoming event from another peripheral in the device. ADC measurements can be started with predictable timing, and without software intervention. Both internal and external reference voltages can be used. An integrated temperature sensor is available for use with the ADC. The bandgap voltage as well as the scaled I/O and core voltages can also be measured by the ADC. The ADC has a compare function for accurate monitoring of user-defined thresholds, with minimum software intervention required. The ADC may be configured for 8-, 10- or 12-bit results, reducing the conversion time. ADC conversion results are provided left- or right-adjusted, which eases calculation when the result is represented as a signed value. It is possible to use DMA to move ADC results directly to memory or peripherals when conversions are done.

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • amgalbu
    amgalbu over 4 years ago in reply to shabaz

    Thank you shabaz!

    Usability has to be improved, but it's a starting point

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube