Thursday, December 28, 2017

uBITX TFT display update 1/10/2018

I had a little time over Christmas weekend while everyone else was watching football to work on the TFT display for the uBITX.  I grabbed a 2.4" TFT display from another project and connected it to the Nano I am using as a test bed.  Just to be sure about the logic levels the display wanted I fed the control lines through a voltage divider made up of a 4K7 and 10K resistors.  This display gave me a much larger area to work with, and I could add some of the features that several other people suggested.  One of them was the display of the A: and B: VFO frequencies.   I decided to display the active VFO frequency in a larger font, with the alternate in a smaller font and a different color. 


 Another suggestion I uses was, when the RIT function was active, I displayed the offset from the transmit frequency.  I also changed the RIT tuning steps to 50 Hz. instead of 100.  I still have several other settings I need to display on the screen, but it is starting to take shape.


One other thing I wanted to do was add was an analog meter.  Mainly to use as a s-meter, but possibly as a power meter that will switch between modes on receive or transmit.  I looked at and tried the code from several versions I found, but they were fairly large in code size and required quite a bit of processing to compute the needle movement.  I decided I wanted top try something a little simpler.  Instead of using sin and cos functions to compute the angular position of the needle, I would treat  everything as a straight line value.  This lets me just draw a line from a pivot point for the needle to some point near the top of the meter face.  The line length would vary, but the effect would look close enough to an actual meter.  This resulted in two very simple functions, one to draw the meter itself and the other to plot the needle.  To move the needle, first it is drawn in the face color of the meter to erase the old value and then redrawn in the desired needle color.
The function to draw the meter is very simple 


void drawMeter(int x, int y, int w, int h, int face_c, int bar_c, char *txt) {
  tft.fillRoundRect(x, y, w, h, 5, face_c);
  tft.fillRoundRect(x + 1, y + 1, w - 2, h / 5, 3, bar_c);
  tft.drawRoundRect(x, y, w, h, 5, YELLOW);
  tft.setTextSize(1);
  tft.setTextColor(YELLOW);
  tft.setCursor(x + 2, (y + (h/5))-12);
  tft.print(txt);
}

Draw a  filled rectangle with rounded corners at the desired position and size, then draw another that will serve as the background color for the meter scale.  I also added another empty rectangle around the main one to highlight the meter.  Then position the cursor and print the meter scale.  I did not add auto sizing of the meter, so the actual size of the main rectangle, will have to be determined manually from the desired text on the meter scale.  To draw the basic meter without needle is to give it a position, size , colors needed, and scale text.

// define some values for the meter position and size
#define  MTR_X   160
#define  MTR_Y   108
#define  MTR_W   155

#define  MTR_H   100

drawMeter(MTR_X, MTR_Y, MTR_W, MTR_H, WHITE, RED,"0  2  4  6  9 +20 +40 +60");


Plotting the needle was simpler than I had expected.  Since I was treating the meter range as a straight line value.  I pass the function the same parameters for position and size as the drawMeter function, and add the value, max_value and color to draw the needle.  
void plotNeedle(int x, int y, int w, int h, int value,int max_value,int color)
{
  int tw;
  int w2 = w/2;
  tw = map(value, 0, max_value, 3, w-3 );
  tft.drawLine(x + w2 ,   y + h - 4,  x+tw ,    y + (h / 5)+4, color);
  tft.drawLine(x + w2+1,  y + h - 4,  x+tw+1  ,  y + (h / 5)+4, color);
  tft.drawLine(x + w2+2,  y + h - 4,  x+tw +2 , y + (h / 5)+4, color);
}
Then I used the Arduino map() function to return a value that represented the position along the meter scale based on the value read and the maximum value.  Then just plot a straight line from the pivot point for the needle to just below the meter scale, which I compute depending on scale size.  I draw this three times with a slight offset to make the needle more visible as it moves. 


Since the only available Analog pin is A7, wrote a little code to read that value and display the meter reading. 
  meter_reading=analogRead(A7)/2;
  plotNeedle(MTR_X, MTR_Y, MTR_W, MTR_H,last_meter,1023,WHITE);
  plotNeedle(MTR_X, MTR_Y, MTR_W, 1MTR_H,meter_reading,1023,BLACK);
  last_meter=meter_reading;

Next I will see about building something to get a signal from the uBITX to display.  I might start with a simple voltage doubler off the top of the volume control just to see how well it works.  Later I will probably tap into the IF chain to get an actual S-Meter .  Also thinking about adding a pickup off the antenna lead to measure power output, I can probably use the PTT signal to allow switching between meter readings from receive to transmit.

Update 1/10/2018

After playing around with several different versions of the display screen, I have come up with something I like.  Following a couple of suggestions from N6QW, I now show options available in Cyan and any active settings in Yellow.  On the screen you can see the second VFO frequency, and that RIT is optional.   

Below the frequency read out, I have an area to display the command prompts from the uBITX, such as band change, VFO selection, RIT on/off. 



When RIT is turned on the offset from transmit frequency is displayed. I did make a change to the original code to change in 50 Hz. steps instead of 100 Hz.  



Finally I added a transmit indicator, and also checked the CW keying line and changed the mode display while a keying is present.

I am happy with the way the display looks, now to put everything in a box and see how it works.  I think I will re-write the code I have for the BITX40 and use one of the VFO/BFO boards I designed.  With that I have more Analog input pins available and should be able to implement power and SWR readings on the screen.


UPDATE 1/29/18 

I have received several questions about the display I used on my uBIX.  The ones that I am most interested in are the ones that use a  ILI9340 or ILI9341 controller.   They are available in 2.4" or 2.8 " models.  I have found the response to be very fast using the standard SPI interface.  


The main issue with them is that they usually require 3.3 volt logic levels instead of the 5 volt from Arduino, I have found a simple voltage divider does well in this application.  I usually power the LED pin through a 100 ohm resistor to 5V.  If a PWM pin was available, I would add backlight intensity control instead.  Software changes in the main sketch  ubitx_20 were fairly simple, and then I replaced the ubitx_ui  file with a modified ubitx_tft_ui file.  Changes to the ubitx_20 file are made in the declarations 

/*
Comment out the original display driver  and replace with the Adafruit drivers
#include <LiquidCrystal.h>
  LiquidCrystal lcd(8,9,10,11,12,13);
/*

// WE ARE GOING TO USE A TFT DISPLAY

#include <Adafruit_GFX.h>
#include "Adafruit_ILI9340.h"
#define _sclk 13
#define _miso 12
#define _mosi 11
#define _cs 8
#define _dc 10
#define _rst 9

#define CALLSIGN  "KV4QB"

// Color definitions
#define BLACK   0x0000
#define BLUE    0x001F
#define GRAY    0x3333
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFF6

Adafruit_ILI9340 tft = Adafruit_ILI9340(_cs, _dc, _rst);

and then in the setup code make these changes
  // lcd.begin(16, 2);   // using tft instead of lcd

  // setup the tft display and draw basic display screen
  tft.begin();
  //tft.initR(INITR_BLACKTAB);  //ST7735 depends on exact one used
  tft.setRotation(1); // landsacape versus portrait

  tft.fillScreen(BLUE);

  //we print this line so this shows up even if the raduino
  //crashes later in the code

  printLine1("uBITX v0.20");

  tft.setTextSize(3);
  tft.setTextColor(YELLOW, BLUE);
  tft.setCursor(22, 20);
  tft.print("uBITX v0.20");
  delay(1500);
  tft.setCursor(22, 20);
  tft.print("           ");
    drawDisplay();

With the updated ubitx_tft_ui code I tried to keep the code in the other files as unchanged as possible.  Except for the display, nothing else has been changed.

Here is a link to my modified uBITX sketch to support a TFT display instead of the normal 2 line LCD display.  Hardware change  is a small board with the voltage dividers that has a connector for the TFT display.  Only the first 8 pins are used.  Then there is a short cable that plugs in where the existing display plugs in on the Raduino board.

https://www.dropbox.com/sh/hhqxprggo9rct3v/AACrI9ceAKDYNnFPBH29Ig5ta?dl=0









2 comments:

  1. Nicely done DuWayne.

    73, Peter
    ve3poa

    ReplyDelete
  2. DuWayne, this is very well done. It looks great. I wonder how you are interfacing to the display. A couple of us have been discussing approaches and were considering using a display with serial interface to free up pins for other purposes, but we are concerned that I2C interface speeds may be too slow for redrawing the display suitably - especially when tuning or if we were to follow your lead and include a graphical 'analog meter'.

    73... Paul (VE3PS)

    ReplyDelete