The code run on NodeMCU-32S (ESP32 in Arduino framework) capture analog input in background base on timer interrupt, display on SPI ILI9341 screen graphically.
The timer interrupt is prepared in setup(), refer to Arduino IDE Examples > ESP32 > Timer > RepeatTimer.
bfr[][] is a 2x300 double buffer to store captured analog data. When one page (300 elements) is filled in interrupt service routine, it will switch to fill the another page and set bfr_filled flag to display the filled page in main loop(). Such that the main loop have to finish display within one page filled, 300 x sampling interval.
#include "SPI.h"
#include "TFT_eSPI.h"
#define TFT_GREY 0x7BEF
TFT_eSPI myGLCD = TFT_eSPI();
#define FRAME_TOPX 10
#define FRAME_TOPY 5
#define FRAME_WIDTH 300
#define FRAME_HEIGHT 200
#define FRAME_BOTTOMY FRAME_TOPY + FRAME_HEIGHT
#define LAMP_PLOTTING_X FRAME_TOPX+290
#define LAMP_PLOTTING_Y FRAME_BOTTOMY+10
#define LAMP_PLOTTING_R 5
#define NO_OF_BFR_PAGE 2
#define NO_OF_BFR_ELE 300
unsigned int bfr[NO_OF_BFR_PAGE][NO_OF_BFR_ELE];
volatile int bfr_page;
volatile int bfr_idx;
volatile bool bfr_filled;
volatile int bfr_filled_page;
volatile bool bfr_run = false;
volatile int updateDot = -1;
volatile unsigned long prvSamplingTime;
#define PrgressDot_X FRAME_TOPX
#define PrgressDot_Y FRAME_BOTTOMY+4
#define PinAnalogIn 36
unsigned long previousTime = 0;
hw_timer_t * timer = NULL;
volatile SemaphoreHandle_t timerSemaphore;
void IRAM_ATTR onTimer(){
toFillBfr();
// Give a semaphore that we can check in the loop
xSemaphoreGiveFromISR(timerSemaphore, NULL);
}
void setup() {
Serial.begin(115200);
myGLCD.init();
myGLCD.setRotation(1);
myGLCD.fillScreen(TFT_BLACK);
delay(500);
myGLCD.fillRect(FRAME_TOPX-1, FRAME_TOPY-1,
FRAME_WIDTH+2, FRAME_HEIGHT+2, TFT_WHITE);
myGLCD.fillRect(FRAME_TOPX, FRAME_TOPY,
FRAME_WIDTH, FRAME_HEIGHT, TFT_GREY);
myGLCD.setTextColor(TFT_WHITE,TFT_BLACK);
myGLCD.drawString("Double Buffer", FRAME_TOPX, FRAME_BOTTOMY+20);
// prepare bfr
bfr_run = false;
bfr_filled = false;
bfr_page = 0;
bfr_idx = 0;
bfr_run = true;
// --- Prepare Timer Intrrupt ---
// Create semaphore to inform us when the timer has fired
timerSemaphore = xSemaphoreCreateBinary();
// Use 1st timer of 4 (counted from zero).
// Set 80 divider for prescaler (see ESP32 Technical Reference Manual for more
// info).
timer = timerBegin(0, 80, true);
// Attach onTimer function to our timer.
timerAttachInterrupt(timer, &onTimer, true);
// Set alarm to call onTimer function every second (value in microseconds).
// Repeat the alarm (third parameter)
timerAlarmWrite(timer, 10000, true); //10ms
//timerAlarmWrite(timer, 1000, true); //1ms
// Start an alarm
timerAlarmEnable(timer);
prvSamplingTime = micros();
// --- End of Prepare Timer Intrrupt ---
Serial.println("\n --- Start ---\n");
Serial.println("CPU Frequency (Mhz): " + String(getCpuFrequencyMhz()));
}
void handle_screen(){
if(bfr_filled){
//unsigned long beforeScreen = micros();
bfr_filled = false;
myGLCD.fillCircle(LAMP_PLOTTING_X, LAMP_PLOTTING_Y, LAMP_PLOTTING_R, TFT_RED);
myGLCD.fillRect(FRAME_TOPX, FRAME_TOPY,
FRAME_WIDTH, FRAME_HEIGHT, TFT_GREY);
int yPrv = bfr[bfr_filled_page][0];
for(int i=1; i<NO_OF_BFR_ELE; i++){
int yCur = bfr[bfr_filled_page][i];
myGLCD.drawLine(FRAME_TOPX+i-1, FRAME_BOTTOMY-yPrv,
FRAME_TOPX+i, FRAME_BOTTOMY-yCur,
TFT_WHITE);
yPrv = yCur;
}
myGLCD.fillCircle(LAMP_PLOTTING_X, LAMP_PLOTTING_Y, LAMP_PLOTTING_R, TFT_GREEN);
myGLCD.drawLine(PrgressDot_X, PrgressDot_Y, PrgressDot_X+299, PrgressDot_Y, TFT_BLACK);
//Serial.println("Fil duration: " + String(micros()-beforeScreen) + " (microsecond)");
}
//to draw alblue line under the graph for indicate the sample progress
if(int x=updateDot){
updateDot = -1;
myGLCD.drawPixel(PrgressDot_X+x, PrgressDot_Y, TFT_BLUE);
}
}
void loop() {
if (xSemaphoreTake(timerSemaphore, 0) == pdTRUE){
handle_screen();
}
}
void toFillBfr(){
//unsigned long beforeFill = micros();
unsigned long int curSamplingTime = micros();
if(bfr_run){
bfr[bfr_page][bfr_idx] = map(analogRead(PinAnalogIn),0, 4096, 0, 200);
updateDot = bfr_idx;
bfr_idx++;
if(bfr_idx >= NO_OF_BFR_ELE){
bfr_filled_page = bfr_page;
bfr_idx=0;
if(bfr_page==0){
bfr_page = 1;
}else{
bfr_page = 0;
}
bfr_filled = true;
}
}
//Send sampling interval to Serial Monitor for evaluation only,
//remove it before finalize.
Serial.println(curSamplingTime - prvSamplingTime);
prvSamplingTime = curSamplingTime;
//Serial.println("Fil duration: " + String(micros()-beforeFill) + " (microsecond)");
}
To setup TFT_eSPI using SPI ILI9342 for ESP32, read the post "ESP32 + 2.4" 320X240 Display (SPI ILI9341), using TFT_eSPI, prepare user setup file".
No comments:
Post a Comment