Thursday, May 31, 2018

ESP32 and the CWTD 'Test Gadget' Update 6/3/18

I have several projects in the early stages of development that I am working on.  Most of them require more program and sram memory then available in the Nano or Pro-Mini that I have been using for my projects.  This has led me to do some testing of a  several Arduino compatible boards.  I tried the Mega2560 and the Mega mini, but decided that the form factor would be hard to work with in my projects.  I also did some experimenting with the STM32 'Blue Pill' and was very satisfied with the results I found.  For around $2 it is a very powerful board.  Recently I saw some information on  ESP32 development boards that look really interesting.  Along with WiFi and Bluetooth capabilities they have an amazing amount of IO capabilities.  I found one from that appears to have just about any IO type you could need.
Here is a list of what is available on the module.  Of course many of the pins are multipurpose so all of these functions are not available at the same time.  The module can be programmed directly from the Arduino environment without pushing any buttons.  The upload speed is 921600 bps, which makes program upload very fast.
  • 240 MHz dual core Tensilica LX6 microcontroller with 600 DMIPS  
  • Integrated 802.11BGN HT40 Wi-Fi transceiver, baseband, stack and LWIP   
  • Integrated dual mode Bluetooth (classic and BLE) 
  • 4 MByte flash 
  • 3 x UARTs, including hardware flow control 
  • 3 x SPI
  • 2 x I2S
  • 12 x ADC input channels
  • 2 x DAC
  • 2 x I2C
  • PWM/timer input/output available on every GPIO pin
  • SDIO master/slave 50 MHz
  • SD-card interface support
What I liked about this version is that all the IO pins are brought out to single row headers on each side of the module, that is only slightly larger than a Nano.  That and the fact that they are under $10, made this something I wanted to try.

I ordered ordered one and after it arrived I configured my Arduino IDE environment to support the ESP32.   I first compiled an empty sketch to see just how much program and variable space is available.  I was a little surprised at first to see how large the core  was that it compiled. 
Sketch uses 159060 bytes (12%) of program storage space. Maximum is 1310720 bytes.
Global variables use 10756 bytes (3%) of dynamic memory, leaving 284156 bytes for local variables. Maximum is 294912 bytes.
But after checking around several sites, I found that this includes all the functions associated with Wifi and Bluetooth and most of the functions available in the ESP32 SDK.  It also includes FreeRTOS, a real time operating system that allows you to do multi-tasking and  use both cores at the same time.  So even though it takes nearly 160K program space and around 11K sram, there is still over 1.1 MB program space and  280K sram available for variables.  I think it will take a while before I can come up with a program to use all of that. 

Next I attached a 2.8"  320 x 240 TFT display to see how fast it was.  Using the Adafruit graphic library and drivers the speed for the standard graphics test using the SPI bus was about the same as using a 8 bit interface on a Nano.  Not going to be any problem with display speed that I can see.  

Looking around for information on the ESP32, I found a great series of YouTube videos by G6EJDThey range from basic Arduino IDE install and setup to advanced web servers.  There are many other great YouTube videos available from others that cover many advanced topics.

I have been following a series of podcasts from 'Chatting with the Designers'  CWTD.ORG that cover building simple Arduino based test equipment.  I decided that this would make a nice way to get into development with the ESP32.  The CWTD 'Test Gadget' is basically an Arduino Nano with a 2 line LCD display, and a breadboard area where small modules can be plugged in to make different types of instruments.  My version will use the ESP32 and the TFT display.  I am also replacing their rotary encoder with a joystick for the user interface device.  I am bringing all the pins from the ESP32 module out to two pairs of female headers, that should allow me to plug in two small modules at the same time.  I also added a couple extra pins to the headers to supply 12 V. to the modules and a couple pins that allow signals from one module to be connected to another with out having to run jumper wires.  The use of female headers will also allow me to connect to a wireless breadboard for initial testing of module prototypes.

I designed a simple board to provide two pairs of headers so I could plug in two  4x6 or 5x7 cm. modules at a time, or allow the use of a single 8x12 cm. module.  To keep the size down I have the ESP32 module mounted on the back of the board along with a 5 V regulator to bring the 12 V supply I plan on using down to  5 V to power the ESP32 board.  This allowed me to keep the board size down to the 10x10 cm. size that qualifies for the inexpensive rate from multiple Chinese board houses.

After the boards arrived, I quickly built one up.  I found that I had to make a small change and add a jumper to get the display to work properly, also needed to add a pull-up resistor for the switch on the joystick.  While I was waiting for the boards to arrive, I had designed and 3D printed a  small case to hold everything.  I had a bezel and mounting plate I had previously done for the TFT display and joystick, so designed the case to use that.  After it was assembled, I wrote a quick sketch to see what the unit will look like with the display active.  

Now I just need to wire up some simple modules and write some code to see how everything will work. If everything goes as I hope using the TFT display, I will think about enabling the WiFi .  This could possibly lead to having some simple Web based instrumentation.  As always I will keep you informed of my progress.

Update 6/3/18
Just a few notes on the 'Test Gadget' mother board for a couple of those who asked.  I have added a schematic of the mother board, and a couple things I had to do to get everything working the way I wanted it to.  
First problem I ran into was with the RESET on the TFT display.  I wanted save the use of a pin on the ESP32, so originally tied the RESET pin on the display to 5V.  I could not get the display to start up consistently.  I removed the pull-up I had on the board and ran a jumper to the LED pin.  It appears that RESET wants to be closer to 3.3 volts.  The only other problem I found was that I had to add a 10K pull-up from the joystick switch to 3.3 volts.  Some joystick modules have pads for this purpose, but I just added an external resistor across  the appropriate contacts on the mother board.
Power to the board is 12 volts that goes to a 1117-5 5 volt regulator.  The 5 volts goes to the VIN on the ESP32 board and to pins on the module connectors.  The 12 volts is also brought out to another pin on the module connectors for use by any analog circuitry that requires a larger voltage.
In most of my previous projects, I used a rotary encoder for the User Interface device.  For this I am going with a small Joystick with switch.  From some of the testing I have done with this, I find it to offer more versatility and speed of use than a Rotary Encoder. The ReadJoystick function stores the V, H and SW values in global variables, and if any changes occur a global status variable is set.  The V and H values are +- 1 or 2 depending on direction and degree of movement.  The SW values are either  1 for a short press or -1 for a long press of over .5 seconds.  
In the setup()  routine the center H and V values are read and used to set a 'deadband' area that determines the how far the Joystick must be moved to get a reading.  This value is also used set the amount of movement required for the two movement values.

void ReadJoyStick() {
  int jsVin;          // variables to hold raw input from joystick
  int jsHin;
  int jsSWin;
  jstick = false;     // clear all global variables
  jstickV = 0;
  jstickH = 0;
  jstickSW = 0;
  // look for input opn vertical axis
  jsVin = analogRead( jsVPin);
  if ( jsVin > jsVcenter + jsDeadBand) {              // maintain dead spot around center position
    jstickV = 1;
    if ( jsVin > jsVcenter + jsX2)                    // large movement so bigger value
      jstickV = 2;
    jstick = true;                                     // set joystick value changed flag
  else if ( jsVin < jsVcenter - jsDeadBand) {              // maintain dead spot around center position
    jstickV = -1;
    if ( jsVin < jsVcenter - jsX2)
      jstickV = -2;                                        // large movement so bigger value
    jstick = true;                                         // set joystick value changed flag
   delay(100);                                           // to prevent noise issues
  // do the same thing for Horizontal axis
  jsHin = analogRead( jsHPin);
  if ( jsHin > jsHcenter + jsDeadBand) {              // maintain dead spot around center position
    jstickH = 1;
    if ( jsHin > jsHcenter + jsX2)
      jstickH = 2;
    jstick = true;
  else if ( jsHin < jsHcenter - jsDeadBand) {              // maintain dead spot around center position
    jstickH = -2;
    if ( jsHin > jsHcenter - jsX2)
      jstickH = -1;
    jstick = true;
   delay(100);                                         // to prevent noise issues
  // check for switch pushed
  jsSWin = digitalRead(jsSWPin);              
  if ( jsSWin == LOW) {
    jstickSW = ShortPress;                              // 1 if short press
    jstick = true;
    delay(500);                               // delay half second to
    jsSWin = digitalRead( jsSWPin);           // see if it was a long press
    if ( jsSWin == LOW)
      jstickSW = LongPress;                  // -1 for a long press
 delay(100);                                         // to prevent noise issues
This function is called  repeatedly in the program any time a input is allowed.  After the input is processed the status variable needs to be cleared.  For now this routine is just called from the main program code as needed.  Later when I start playing around with the multitasking  and dual core functionality, I might change this to a background task that runs all the time.