Table of Contents
Today, we will take an in-depth look at the new Arduino GIGA Display Shield. This useful peripheral adds a touchscreen GUI to your Arduino GIGA board, along with a microphone, IMU, and a handy connection for a video camera.
Introduction
We have already looked at the Arduino GIGA board, an incredibly powerful microcontroller in the same format as the classic Arduino Mega 2560. Today we will look at an upgrade for the GIGA, a “shield” that is actually more of a “reverse shield” (this will make more sense as you read on, trust me!).
This new board will allow you to construct great-looking user interfaces for your projects. It makes a powerful combination when added to the GIGA’s already impressive list of features.
Arduino GIGA Display Shield
The GIGA Display Shield is a 480 x 800 touchscreen display that snaps onto the back of the Arduino GIGA.
There is a silk-screened outline on the back of the display board to assist you in orienting the GIGA correctly. This is a different mounting arrangement from that used by “regular” shields that mount on the female Dupont connectors on the top of the board. You can still mount conventional shields on the board with the display installed.
In addition to the display, the GIGA Display Shield also has an onboard MEMS microphone. This allows for the construction of point-of-entry terminals and audio analysis tools.
The board also has an IMU capable of sensing motion and acceleration. You can use this to adjust display orientation or even to build a game.
An onboard RGB LED, as is an extension for the SPI camera connector, is also included. The latter is compatible with a number of Arducam camera modules.
Getting Started
Let’s get started with your new display!
Before starting working with the display, we must ensure that our system is set up correctly for the Arduino GIGA WiFi boards. We must also install several libraries to utilize all the display features fully.
Setting up the Arduino GIGA WiFi
We have covered working with the Arduino GIGA WiFi board in the video and article dedicated to it, so I’ll refer you to that if you want some additional information.
Otherwise, installing the Arduino GIGA board manager is the only step you need to take. Search for “GIGA” in the Arduino IDE Boards Manager window and install the resulting file. The board manager will also install many example sketches, a few of which we will use later.
If you are on Linux, you may encounter an error when uploading to the GIGA board. This known bug can be resolved by creating a simple text file. You will find all the details in the previous GIGA article.
Installing the Libraries
In addition to the files installed by the board manager, we will need to install some libraries. Lots of libraries. Nine, to be exact!
But don’t worry, it’s not as much work as you might expect, as one of the libraries will also install seven more. So, you only need to perform two installations if you execute them correctly.
All the libraries can be installed using the Library Manager in the Arduino IDE. Open it up and search for the “Arduino_GigaDisplay” library. You will get a list of items; install the first one.
You will also be prompted to install some other libraries upon which the Arduino_GigaDisplay” library is dependent. In total, you will be installing the following libraries:
- Arduino_GigaDisplay
- Adafruit BusIO
- Adafruit GFX Library
- ArduinoGraphics
- Arduino_BMI270_BMM150
- Arduino_GigaDisplayTouch
- Arduino_GigaDisplay_GFX
- lvgl
Note that you may already have some of these libraries installed in your IDE; only the missing ones will be installed. Ensure that any existing installed libraries are updated to the most recent version.
Once you have everything installed, we can start testing the display shield!
Testing the IMU
The Bosch BMI270 6 Axis IMU (Inertial Measurement Unit) is well suited for use on the GIGA display, as it can provide precise acceleration and angular rate measurement. It also has on-chip motion-triggered interrupt features.
We can use the IMU to control the display orientation to behave like a phone or tablet. It could also be very useful if you want to design a game or create an interactive controller.
To measure acceleration, we can use the Arduino_BMI270_BMM150 library. It provides a very simple method of getting acceleration data for all three of the axis measurements.
Here is a sketch that will provide this data:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
/* Arduino GIGA Display - IMU Acceleration Demo gigadisplay-imu-test.ino Demonstrates operation of builtin IMU Displays acceleration on serial monitor Requires rduino_BMI270_BMM150 library Code provided by Arduino DroneBot Workshop 2023 https://dronebotworkshop.com */ // Include libraries #include "Arduino_BMI270_BMM150.h" // Define IMU object on second I2C bus BoschSensorClass imu(Wire1); void setup() { // Start serial monitor Serial.begin(115200); // Start IMU imu.begin(); } void loop() { // Variables for X, Y and Z axis float x, y, z; if (imu.accelerationAvailable()) { // Read acceleration values imu.readAcceleration(x, y, z); // Print to serial monitor Serial.print(x); Serial.print('\t'); Serial.print(y); Serial.print('\t'); Serial.println(z); } } |
We start the sketch by including the library and then defining an IMU object. Note that we use the Wire1 interface, the second I2C bus.
In Setup, we start the Serial Monitor and also start the IMU.
In the Loop, we simply define variables for the X, Y, and Z axis and then read and print the values.
Load the sketch and move the display around while observing the serial monitor readings. You should see that they correlate to the movements you are making.
Working with the RGB LED
The display module also has a surface-mount RGB LED, which can be controlled through the Arduino_GigaDisplay library.
Here is a sketch that demonstrates its operation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
/* Arduino GIGA Display - RGB LED Test gigadisplay-rgb.ino Demonstrates operation of onboard RGB LED Requires Arduino_GigaDisplay Library DroneBot Workshop 2023 https://dronebotworkshop.com */ // Include library #include <Arduino_GigaDisplay.h> // Create RGB object GigaDisplayRGB rgb; void setup() { // Initialize the RGB object rgb.begin(); } void loop() { // Turn on red pixel rgb.on(255, 0, 0); delay(1000); // Turn off all pixels rgb.off(); delay(1000); // Turn on green pixel rgb.on(0, 255, 0); delay(1000); // Turn off all pixels rgb.off(); delay(1000); // Turn on blue pixel rgb.on(0, 0, 255); delay(1000); // Turn off all pixels rgb.off(); delay(1000); // Turn on all pixels rgb.on(255, 255, 255); delay(1000); // Turn off all pixels rgb.off(); delay(1000); } |
This is a very simple sketch that uses the Arduino_GigaDisplay library. We include the library and then define an RGB object. In Setup, we simply initialize that object.
The Loop is where we manipulate the three segments of the display, and it is pretty self-explanatory.
We can turn the display on and pass it RGB values to select the color. Or we can turn the display off.
Otherwise, the sketch is really just like an advanced “blink” sketch, turning the LED on and off every second in a different color.
The RGB LED would make a good status display for your project.
Microphone with Level Display
Another peripheral included with the Arduino GIGA Display Module is a microphone. This is an MP34DT06JTR MEMS microphone module, an omnidirectional capacitive-sensing device with low noise and high sensitivity.
The output of the microphone is PDM or Pulse Density Modulation. Arduino has a PDM Library for working with devices like this.
Until now, we have demonstrated the GIGA Display components by showing their output on the serial monitor. We could continue this trend with the microphone, displaying its output level on the monitor, but that’s a bit boring. And as we have a display to evaluate, why not use it instead of the serial monitor?
The following sketch, using code provided by Arduino, will do the trick. It will display the microphone output level on a bargraph on the display.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
/* Arduino GIGA Display - Microphone Demo gigadisplay-microphone.ino Demonstrates operation of builtin microphone Displays audio level on bargraph Requires PDM, Arduino_H7_Video and lvgl library Code provided by Arduino DroneBot Workshop 2023 https://dronebotworkshop.com */ // Include libraries #include <PDM.h> #include "Arduino_H7_Video.h" #include "lvgl.h" // Create display object Arduino_H7_Video Display(800, 480, GigaDisplayShield); // Slider static void set_slider_val(void *bar, int32_t val) { lv_bar_set_value((lv_obj_t *)bar, val, LV_ANIM_ON); } // Default number of output channels static const char channels = 1; // Default PCM output frequency static const int frequency = 16000; // Buffer to read samples into, each sample is 16-bits short sampleBuffer[512]; // Number of audio samples read volatile int samplesRead; lv_obj_t *obj; lv_anim_t a; int micValue; void setup() { // Initialize Display Display.begin(); // Setup callback PDM.onReceive(onPDMdata); // Start PDM if (!PDM.begin(channels, frequency)) { Serial.println("Failed to start PDM!"); while (1) ; } // Create the bar obj = lv_bar_create(lv_scr_act()); lv_obj_set_size(obj, 600, 50); lv_obj_center(obj); lv_bar_set_value(obj, 500, LV_ANIM_OFF); // Create the animation for the bar lv_anim_init(&a); lv_anim_set_exec_cb(&a, set_slider_val); lv_anim_set_time(&a, 300); lv_anim_set_playback_time(&a, 300); lv_anim_set_var(&a, obj); } void loop() { // Wait for samples to be read if (samplesRead) { // Print samples to the serial monitor or plotter for (int i = 0; i < samplesRead; i++) { Serial.println(sampleBuffer[i]); micValue = sampleBuffer[i]; micValue = micValue / 10; // Adjust divisor for sensitivity if (micValue > 500) { micValue = 500; } lv_anim_set_values(&a, 0, micValue); lv_anim_start(&a); } // Clear the read count samplesRead = 0; delay(10); } lv_timer_handler(); } // Callback function to process the data from the PDM microphone. void onPDMdata() { // Query the number of available bytes int bytesAvailable = PDM.available(); // Read into the sample buffer PDM.read(sampleBuffer, bytesAvailable); // 16-bit, 2 bytes per sample samplesRead = bytesAvailable / 2; } |
The code includes the PDM Library for working with digital audio and the Arduino H7 video library. The LVGL library is also included to provide the graphics (we will learn more about LVGL in a bit).
This is filled by a function that sets the slider value.
We then define some audio parameters; then we move to the Setup.
In Setup, we initialize the display. We then set the PDM object to have a callback function, which will be called every time that audio is received. After that, we start the PDM.
We also set up both the bargraph and the animation for the bar.
In the Loop, we check whether any samples have been read. If they have, we create an array with the samples. We then read that array, one element at a time, and use the value to operate the bargraph.
We then clear the samples, add a short delay, and wait again.
Note that the final line in the Loop, a call to the lv_timer_handler, is required for LVGL. We will see more of that later.
The onPDMData function is the callback handler, called whenever data is available. It reads the data into a sample buffer, 2 bytes at a time, as it is 16-bit.
You’ll see a bargraph on the display when you load up the sketch. Make some noise, and you should see the bar move. You can adjust the divisor on line 79 (current value is 10) to increase or decrease the sensitivity.
Using the Display for Graphics
So, now that we have looked at the included peripherals, it’s time to focus on the display itself. And by that, I mean we need to learn how to place graphics, images, and text onto the screen.
There are three graphics libraries that you can use to work with the display:
- ArduinoGraphics Library
- GFX Library
- LVGL Library & Framework
Graphics 1 – ArduinoGraphics Library
The ArduinoGraphics library allows you to draw and write on the display with “graphical primitives,” basic shapes like circles and rectangles.
This library has syntax similar to the Processing 3 GUI design tool.
ArduinoGraphics Simple Demo
To illustrate just how easy it is to use the ArduinoGraphics library, I have put together a very simple demonstration. Here is the sketch:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
/* Arduino GIGA Display - ArduinoGraphics Demo gigadisplay-arduinographics.ino Demonstrates ArduinoGraphics library functions Uses Arduino_H7_Video and ArduinoGraphics libraries DroneBot Workshop 2023 https://dronebotworkshop.com */ // Include required libraries #include "Arduino_H7_Video.h" #include "ArduinoGraphics.h" // Create a display object Arduino_H7_Video Display(800, 480, GigaDisplayShield); void setup() { // Initialize display Display.begin(); // Draw a red rectangle that covers the entire display Display.beginDraw(); Display.clear(); Display.noStroke(); Display.fill(255, 0, 0); Display.rect(0, 0, Display.width(), Display.height()); // Draw a 200px blue circle at coordinates 200,200 Display.fill(0, 0, 255); Display.circle(200, 200, 200); // Draw a 300px green circle at coordinates 500,300 Display.fill(0, 255, 0); Display.circle(500, 300, 300); // Finish drawing Display.endDraw(); } void loop() { } |
The sketch starts by including the two libraries we need. The Arduino_H7_Video library is the library that drives the GIGA Display.
We then create an object to represent the display.
From here on, everything is done in the Setup routine. We start by initializing the display and then begin our drawing.
After that, we draw a rectangle that fits the entire display; this is a method of changing the background color.
The line “Display.fill(255, 0, 0)” sets the color. You can change the RGB values if you want a different color. Currently, it is set to red. The Display.rect command draws a rectangle with bottom left coordinates at 0,0, and the size of the rectangle which is equal to the display screen size.
Next is a circle. All that is required here is to fill the display with the desired color, which, in this case, is blue. We then use a Display.circle to create our circle, specifying the diameter and the location of the circle’s center.
After that, we repeat the circle process, this time with a 300px green circle at coordinates 500,300.
Finally, we finish drawing with Display.endDraw(). This will complete the job and print on the display.
That finishes the program; there is nothing in the Loop.
Here is what the final result is.
Displaying Images with ArduinoGraphics
Another thing we can do with the ArduinoGraphics library is to display images.
We will use the ArduinoLogo example installed when you added the GIGA Boards Manager. You will find it at this location:
File/Examples/Examples for Arduino Giga R1/Arduino_H7_Video/ArduinoLogo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
/* ArduinoLogo created 17 Apr 2023 by Leonardo Cavagnis */ #include "Arduino_H7_Video.h" #include "ArduinoGraphics.h" #include "img_arduinologo.h" // Alternatively, any raw RGB565 image can be included on demand using this macro // Online image converter: https://lvgl.io/tools/imageconverter (Output format: Binary RGB565) /* #define INCBIN_PREFIX #include "incbin.h" INCBIN(test, "/home/user/Downloads/test.bin"); */ Arduino_H7_Video Display(800, 480, GigaDisplayShield); //Arduino_H7_Video Display(1024, 768, USBCVideo); Image img_arduinologo(ENCODING_RGB16, (uint8_t *) texture_raw, 300, 300); void setup() { Display.begin(); Display.beginDraw(); Display.image(img_arduinologo, (Display.width() - img_arduinologo.width())/2, (Display.height() - img_arduinologo.height())/2); Display.endDraw(); } void loop() { } |
The sketch is pretty simple; it loads the same two libraries we used earlier. It also includes the “img_arduinologo.h” file; this is the actual Arduino logo graphic converted to a C file.
The file incbin.h is also included but isn’t actually used to display the Arduino Logo. It’s used when displaying binary graphics files, which we will do in a moment when we substitute the Arduino logo for an image of our own.
Once again, we set up a display object. We also set up an image object, pointing to the “img_arduinologo.h” file.
In Setup, the display is started, and we begin the drawing. We then use the Display.image command to display the image, providing the image, its width and height, and the position we want to place it.
We finish the same way we did before, with Display.endDraw().
The results are shown here:
Displaying Your Own Image
Displaying the Arduino logo is fine, but I’m sure you would rather display your own images. The sketch we just used can be modified to do that. You’ll note some instructions in the remarks at the beginning of the code.
Before you run the next sketch, you must prepare your image. It will need to be correctly sized to fit onto the display, and it will also have to be converted into a binary format.
You can use any photo editor to resize the image if it’s necessary; the screen is 480×800. Make note of the actual image size, as you will need that in the code.
To convert it to a binary format, you can use the LVGL Graphics Converter. Although it is provided for use with LVGL, it can also be used to convert graphics for other libraries.
Use the graphics converter as follows:
- Use the Browse button to select your BMP, JPG, PNG, or SVG graphic file.
- Leave the Color Format at CF_TRUE_COLOR.
- Change the Output Format to Binary RGB565.
- Click the Convert button. You’ll get an image to download to your local drive.
The resulting file will be a binary file with a “.bin” extension. Ensure you note where it has been saved, as you’ll need the file path when you create the code.
The ArduinoLogo that we just looked at has instructions for using your own file. Here is a sketch written using those examples:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/* Arduino GIGA Display - Display Image gigadisplay-display-image.ino Demonstrates operation of onboard RGB LED Requires Arduino_H7_Video and ArduinoGraphics Libraries Requires incbin.h by Dale Weiler Code example "ArduinoLogo" by Leonardo Cavagnis DroneBot Workshop 2023 https://dronebotworkshop.com */ // Include required libraries #include "Arduino_H7_Video.h" #include "ArduinoGraphics.h" // Any raw RGB565 image can be included on demand using this macro // Online image converter: https://lvgl.io/tools/imageconverter (Output format: Binary RGB565) // Download *.bin file and note file path #define INCBIN_PREFIX #include "incbin.h" // Replace with path to your *.bin file INCBIN(test, "/home/dronebotworkshop/Downloads/robot-redarms-358x422.bin"); // Create display object Arduino_H7_Video Display(800, 480, GigaDisplayShield); // Define image variable with parameters (edit size parameter as required) Image img_robot(ENCODING_RGB16, (uint8_t *) testData, 358, 422); void setup() { // Start display Display.begin(); // Draw image in center of display Display.beginDraw(); Display.image(img_robot, (Display.width() - img_robot.width())/2, (Display.height() - img_robot.height())/2); Display.endDraw(); } void loop() { } |
Note that you will still need the cabin.h file; however, you no longer need the Arduino logo file.
The method of calling the binary file is a bit different from the previous example; it’s actually very simple. Here is what you need to change to use it with your graphic file:
- On line 24, you must change the file’s location to your downloaded file location.
- On line 32, change the size dimensions of the image to match your image.
You can also change the coordinates used by Display.image to move the image away from the display center.
If all is well, you should be rewarded with a display of your custom image!
Graphics 2 – GFX Library
Another method of manipulating the display is to use the popular GFX Graphics Library. This graphics library by Adafruit is a highly popular and versatile tool for creating graphical interfaces and displays for microcontroller-based projects.
Initially, the GFX Graphics Library only supported Adafruit displays; however, it has now been expanded to work with a wide range of displays from multiple manufacturers, including OLEDs, TFTs, and LCDs.
Running the GFX Graphics Demo
A great way to become familiar with the GFX Graphics Library is to run the demo sketch. This is a standard demonstration that cycles the display through a number of shapes and functions. We have used this sketch with other displays, so it’s a great way to see how to adapt other GFX codes to the Arduino GIGA Display Shield.
You can grab the sketch from the following location:
File/Examples/Examples From Custom Libraries/Arduino_GigaDisplay_GFX/Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
#include "Arduino_GigaDisplay_GFX.h" GigaDisplay_GFX tft; #define GC9A01A_CYAN 0x07FF #define GC9A01A_RED 0xf800 #define GC9A01A_BLUE 0x001F #define GC9A01A_GREEN 0x07E0 #define GC9A01A_MAGENTA 0xF81F #define GC9A01A_WHITE 0xffff #define GC9A01A_BLACK 0x0000 #define GC9A01A_YELLOW 0xFFE0 void setup() { Serial.begin(9600); Serial.println("GC9A01A Test!"); tft.begin(); Serial.println(F("Benchmark Time (microseconds)")); delay(10); Serial.print(F("Screen fill ")); Serial.println(testFillScreen()); delay(500); Serial.print(F("Text ")); Serial.println(testText()); delay(3000); Serial.print(F("Lines ")); Serial.println(testLines(GC9A01A_CYAN)); delay(500); Serial.print(F("Horiz/Vert Lines ")); Serial.println(testFastLines(GC9A01A_RED, GC9A01A_BLUE)); delay(500); Serial.print(F("Rectangles (outline) ")); Serial.println(testRects(GC9A01A_GREEN)); delay(500); Serial.print(F("Rectangles (filled) ")); Serial.println(testFilledRects(GC9A01A_YELLOW, GC9A01A_MAGENTA)); delay(500); Serial.print(F("Circles (filled) ")); Serial.println(testFilledCircles(10, GC9A01A_MAGENTA)); Serial.print(F("Circles (outline) ")); Serial.println(testCircles(10, GC9A01A_WHITE)); delay(500); Serial.print(F("Triangles (outline) ")); Serial.println(testTriangles()); delay(500); Serial.print(F("Triangles (filled) ")); Serial.println(testFilledTriangles()); delay(500); Serial.print(F("Rounded rects (outline) ")); Serial.println(testRoundRects()); delay(500); Serial.print(F("Rounded rects (filled) ")); Serial.println(testFilledRoundRects()); delay(500); Serial.println(F("Done!")); } void loop(void) { for (uint8_t rotation = 0; rotation < 4; rotation++) { tft.setRotation(rotation); testText(); delay(1000); } } unsigned long testFillScreen() { unsigned long start = micros(); tft.fillScreen(GC9A01A_BLACK); yield(); tft.fillScreen(GC9A01A_RED); yield(); tft.fillScreen(GC9A01A_GREEN); yield(); tft.fillScreen(GC9A01A_BLUE); yield(); tft.fillScreen(GC9A01A_BLACK); yield(); return micros() - start; } unsigned long testText() { tft.fillScreen(GC9A01A_BLACK); unsigned long start = micros(); tft.setCursor(0, 0); tft.setTextColor(GC9A01A_WHITE); tft.setTextSize(1); tft.println("Hello World!"); tft.setTextColor(GC9A01A_YELLOW); tft.setTextSize(2); tft.println(1234.56); tft.setTextColor(GC9A01A_RED); tft.setTextSize(3); tft.println(0xDEADBEEF, HEX); tft.println(); tft.setTextColor(GC9A01A_GREEN); tft.setTextSize(5); tft.println("Groop"); tft.setTextSize(2); tft.println("I implore thee,"); tft.setTextSize(1); tft.println("my foonting turlingdromes."); tft.println("And hooptiously drangle me"); tft.println("with crinkly bindlewurdles,"); tft.println("Or I will rend thee"); tft.println("in the gobberwarts"); tft.println("with my blurglecruncheon,"); tft.println("see if I don't!"); return micros() - start; } unsigned long testLines(uint16_t color) { unsigned long start, t; int x1, y1, x2, y2, w = tft.width(), h = tft.height(); tft.fillScreen(GC9A01A_BLACK); yield(); x1 = y1 = 0; y2 = h - 1; start = micros(); for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color); x2 = w - 1; for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color); t = micros() - start; // fillScreen doesn't count against timing yield(); tft.fillScreen(GC9A01A_BLACK); yield(); x1 = w - 1; y1 = 0; y2 = h - 1; start = micros(); for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color); x2 = 0; for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color); t += micros() - start; yield(); tft.fillScreen(GC9A01A_BLACK); yield(); x1 = 0; y1 = h - 1; y2 = 0; start = micros(); for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color); x2 = w - 1; for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color); t += micros() - start; yield(); tft.fillScreen(GC9A01A_BLACK); yield(); x1 = w - 1; y1 = h - 1; y2 = 0; start = micros(); for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color); x2 = 0; for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color); yield(); return micros() - start; } unsigned long testFastLines(uint16_t color1, uint16_t color2) { unsigned long start; int x, y, w = tft.width(), h = tft.height(); tft.fillScreen(GC9A01A_BLACK); start = micros(); for (y = 0; y < h; y += 5) tft.drawFastHLine(0, y, w, color1); for (x = 0; x < w; x += 5) tft.drawFastVLine(x, 0, h, color2); return micros() - start; } unsigned long testRects(uint16_t color) { unsigned long start; int n, i, i2, cx = tft.width() / 2, cy = tft.height() / 2; tft.fillScreen(GC9A01A_BLACK); n = min(tft.width(), tft.height()); start = micros(); for (i = 2; i < n; i += 6) { i2 = i / 2; tft.drawRect(cx - i2, cy - i2, i, i, color); } return micros() - start; } unsigned long testFilledRects(uint16_t color1, uint16_t color2) { unsigned long start, t = 0; int n, i, i2, cx = tft.width() / 2 - 1, cy = tft.height() / 2 - 1; tft.fillScreen(GC9A01A_BLACK); n = min(tft.width(), tft.height()); for (i = n; i > 0; i -= 6) { i2 = i / 2; start = micros(); tft.fillRect(cx - i2, cy - i2, i, i, color1); t += micros() - start; // Outlines are not included in timing results tft.drawRect(cx - i2, cy - i2, i, i, color2); yield(); } return t; } unsigned long testFilledCircles(uint8_t radius, uint16_t color) { unsigned long start; int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2; tft.fillScreen(GC9A01A_BLACK); start = micros(); for (x = radius; x < w; x += r2) { for (y = radius; y < h; y += r2) { tft.fillCircle(x, y, radius, color); } } return micros() - start; } unsigned long testCircles(uint8_t radius, uint16_t color) { unsigned long start; int x, y, r2 = radius * 2, w = tft.width() + radius, h = tft.height() + radius; // Screen is not cleared for this one -- this is // intentional and does not affect the reported time. start = micros(); for (x = 0; x < w; x += r2) { for (y = 0; y < h; y += r2) { tft.drawCircle(x, y, radius, color); } } return micros() - start; } unsigned long testTriangles() { unsigned long start; int n, i, cx = tft.width() / 2 - 1, cy = tft.height() / 2 - 1; tft.fillScreen(GC9A01A_BLACK); n = min(cx, cy); start = micros(); for (i = 0; i < n; i += 5) { tft.drawTriangle( cx , cy - i, // peak cx - i, cy + i, // bottom left cx + i, cy + i, // bottom right tft.color565(i, i, i)); } return micros() - start; } unsigned long testFilledTriangles() { unsigned long start, t = 0; int i, cx = tft.width() / 2 - 1, cy = tft.height() / 2 - 1; tft.fillScreen(GC9A01A_BLACK); start = micros(); for (i = min(cx, cy); i > 10; i -= 5) { start = micros(); tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, tft.color565(0, i * 10, i * 10)); t += micros() - start; tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, tft.color565(i * 10, i * 10, 0)); yield(); } return t; } unsigned long testRoundRects() { unsigned long start; int w, i, i2, cx = tft.width() / 2 - 1, cy = tft.height() / 2 - 1; tft.fillScreen(GC9A01A_BLACK); w = min(tft.width(), tft.height()); start = micros(); for (i = 0; i < w; i += 6) { i2 = i / 2; tft.drawRoundRect(cx - i2, cy - i2, i, i, i / 8, tft.color565(i, 0, 0)); } return micros() - start; } unsigned long testFilledRoundRects() { unsigned long start; int i, i2, cx = tft.width() / 2 - 1, cy = tft.height() / 2 - 1; tft.fillScreen(GC9A01A_BLACK); start = micros(); for (i = min(tft.width(), tft.height()); i > 20; i -= 6) { i2 = i / 2; tft.fillRoundRect(cx - i2, cy - i2, i, i, i / 8, tft.color565(0, i, 0)); yield(); } return micros() - start; } |
The sketch uses the Arduino_GigaDisplay_GFX Library.
We start by defining an object to represent the display, followed by a number of color definitions.
Then we move to Setup. Here, we start the serial monitor and the display; then, we call a number of functions. These functions, defined at the bottom of the sketch, cycle the display through various patterns and sequences.
You can examine each function to see the commands used to create the display pattern.
After running through Setup, we finish in the Loop. Here, we display some test text (Vogon poetry from The Hitchhiker’s Guide to the Galaxy) in different fonts. The display will cycle through this text in different orientations until it is reset or powered off.
Load it up and watch it work. Then, try modifying the code and observe the results.
You can learn more about working with this library in the Arduino GIGA Display Shield GFX Guide.
Graphics 3 – LVGL
The Light and Versatile Graphics Library, or LVGL, is more than just a library. This is a complete graphics framework that can be used to create some very sophisticated displays.
LVGL has over 30 built-in widgets, a layout manager, and a style system. It also integrates with SquareLine Studio, a professional GUI design application with a drag-and-drop editor.
LVGL Demo
Once again, we will run a sketch demonstrating this graphics library’s capabilities. This demo produces an interface screen divided into quadrants. Each section has different controls – an image, a working slider, some buttons and checkboxes, and a bargraph.
You’ll find the demonstration sketch at this location in the Arduino IDE:
File/Examples/Examples for Arduino Giga R1/Arduino_H7_Video/LVGLDemo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
/* LVGLDemo created 17 Apr 2023 by Leonardo Cavagnis */ #include "Arduino_H7_Video.h" #include "Arduino_GigaDisplayTouch.h" #include "lvgl.h" Arduino_H7_Video Display(800, 480, GigaDisplayShield); /* Arduino_H7_Video Display(1024, 768, USBCVideo); */ Arduino_GigaDisplayTouch TouchDetector; /* Button click event callback */ static void btn_event_cb(lv_event_t * e) { static uint32_t cnt = 1; lv_obj_t * btn = lv_event_get_target(e); lv_obj_t * label = lv_obj_get_child(btn, 0); lv_label_set_text_fmt(label, "%"LV_PRIu32, cnt); cnt++; } /* Slider update value handler */ static void set_slider_val(void * bar, int32_t val) { lv_bar_set_value((lv_obj_t *)bar, val, LV_ANIM_ON); } void setup() { Serial.begin(115200); Display.begin(); TouchDetector.begin(); /* Create a container with grid 2x2 */ static lv_coord_t col_dsc[] = {370, 370, LV_GRID_TEMPLATE_LAST}; static lv_coord_t row_dsc[] = {215, 215, LV_GRID_TEMPLATE_LAST}; lv_obj_t * cont = lv_obj_create(lv_scr_act()); lv_obj_set_grid_dsc_array(cont, col_dsc, row_dsc); lv_obj_set_size(cont, Display.width(), Display.height()); lv_obj_set_style_bg_color(cont, lv_color_hex(0x03989e), LV_PART_MAIN); lv_obj_center(cont); lv_obj_t * label; lv_obj_t * obj; /* [0;0] - Image */ obj = lv_obj_create(cont); lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, 0, 1, LV_GRID_ALIGN_STRETCH, 0, 1); LV_IMG_DECLARE(img_arduinologo); lv_obj_t * img1 = lv_img_create(obj); lv_img_set_src(img1, &img_arduinologo); lv_obj_align(img1, LV_ALIGN_CENTER, 0, 0); lv_obj_set_size(img1, 200, 150); /* [1;0] - Checkboxes and button */ obj = lv_obj_create(cont); lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_STRETCH, 0, 1); lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN); lv_obj_t * cb; cb = lv_checkbox_create(obj); lv_checkbox_set_text(cb, "Apple"); cb = lv_checkbox_create(obj); lv_checkbox_set_text(cb, "Banana"); lv_obj_add_state(cb, LV_STATE_CHECKED); static lv_style_t style_radio; static lv_style_t style_radio_chk; lv_style_init(&style_radio); lv_style_set_radius(&style_radio, LV_RADIUS_CIRCLE); lv_style_init(&style_radio_chk); lv_style_set_bg_img_src(&style_radio_chk, NULL); cb = lv_checkbox_create(obj); lv_checkbox_set_text(cb, "Lemon"); lv_obj_add_flag(cb, LV_OBJ_FLAG_EVENT_BUBBLE); lv_obj_add_style(cb, &style_radio, LV_PART_INDICATOR); lv_obj_add_style(cb, &style_radio_chk, LV_PART_INDICATOR | LV_STATE_CHECKED); cb = lv_checkbox_create(obj); lv_checkbox_set_text(cb, "Melon"); lv_obj_add_flag(cb, LV_OBJ_FLAG_EVENT_BUBBLE); lv_obj_add_style(cb, &style_radio, LV_PART_INDICATOR); lv_obj_add_style(cb, &style_radio_chk, LV_PART_INDICATOR | LV_STATE_CHECKED); lv_obj_add_state(cb, LV_STATE_CHECKED); lv_obj_t * btn = lv_btn_create(obj); lv_obj_set_size(btn, 100, 40); lv_obj_center(btn); lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_CLICKED, NULL); label = lv_label_create(btn); lv_label_set_text(label, "Click me!"); lv_obj_center(label); /* [0;1] - Slider */ obj = lv_obj_create(cont); lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, 0, 1, LV_GRID_ALIGN_STRETCH, 1, 1); lv_obj_t * slider = lv_slider_create(obj); lv_slider_set_value(slider, 75, LV_ANIM_OFF); lv_obj_center(slider); label = lv_label_create(obj); lv_label_set_text(label, "Drag me!"); lv_obj_align_to(label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10); /* [1;1] - Bar */ obj = lv_obj_create(cont); lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_STRETCH, 1, 1); lv_obj_t * bar = lv_bar_create(obj); lv_obj_set_size(bar, 200, 20); lv_obj_center(bar); lv_bar_set_value(bar, 70, LV_ANIM_OFF); lv_anim_t a; lv_anim_init(&a); lv_anim_set_exec_cb(&a, set_slider_val); lv_anim_set_time(&a, 3000); lv_anim_set_playback_time(&a, 3000); lv_anim_set_var(&a, bar); lv_anim_set_values(&a, 0, 100); lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE); lv_anim_start(&a); } void loop() { /* Feed LVGL engine */ lv_timer_handler(); } |
The sketch makes use of three libraries:
- Arduino_H7_Video – The library for the GIGA Display Shield.
- Arduino_GigaDisplayTouch – The touchscreen library
- lvgl – The LVGL Library
We start by defining both the display and the touch detector.
The next bit of code is a callback function, called whenever the button control is clicked. The function that follows sets the value of the slider control.
We then move into Setup, where most of the code is executed. After starting the serial monitor, display and touch detector, we define a container with a 2×2 grid. This is the container for our graphics display.
Next, we specify the objects that go into each segment of the display grid.
- Grid 0,0 – An Arduino logo image is displayed here.
- Grid 1,0 – A couple of checkboxes, some radio buttons, and a pushbutton.
- Grid 0,1 – A working slider control.
- Grid 1,1 – An animated bargraph.
You can examine the LVGL code statements to see how these objects are created.
The Loop only contains one function, but it is an important one. The call to lv_timer_handler() is performed periodically to keep the graphics engine functioning. You will need to include this in any code you write that uses e LVGL.
Load the code to the GIGA and observe the display. You should have a professional looking interface with working controls.
LVGL with IMU
We can combine the display with the IMU readings to perform special effects. In this example, we will use the IMU to keep the display level, even when it is tilted.
You’ll find this example in the Arduino IDE at File/Examples/Examples From Custom Libraries/Arduino_GigaDisplay/lvgl/imu_orientation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#include "Arduino_BMI270_BMM150.h" #include "Arduino_H7_Video.h" #include "lvgl.h" Arduino_H7_Video Display(800, 480, GigaDisplayShield); /* Arduino_H7_Video Display(1024, 768, USBCVideo); */ BoschSensorClass imu(Wire1); LV_IMG_DECLARE(img_arduinologo); lv_obj_t * img; void setup() { Serial.begin(115200); Display.begin(); imu.begin(); img = lv_img_create(lv_scr_act()); lv_img_set_src(img, &img_arduinologo); lv_obj_align(img, LV_ALIGN_CENTER, 0, 0); lv_img_set_pivot(img, (img_arduinologo.header.w)/2, (img_arduinologo.header.h)/2); /* Rotate around the center of the image */ } uint8_t rotation = 0; void loop() { float x, y, z; if (imu.accelerationAvailable()) { imu.readAcceleration(x, y, z); if ( z < 0.8 && z > -0.8) { if (x < -0.8) { rotation = 0; } else if (x > 0.8) { rotation = 2; } else if (y < -0.8) { rotation = 1; } else if (y > 0.8) { rotation = 3; } int16_t rot_angle = 900 - atan(x / y) * 180.0 / M_PI * 10; lv_img_set_angle(img, rot_angle); } } lv_timer_handler(); } |
The sketch includes a second file, the Arduino logo image we are displaying.
Three libraries are used, including the library for the IMU. After including the libraries, we create objects to represent the display, IMU, and the image itself.
In Setup, we start the serial monitor, display, and IMU. We then define the image and set its position and orientation.
In the Loop, we get the IMU values and determine the rotation value for the x, y, and z-axis. We then use those values to calculate the correct image orientation.
Once again, the lv_timer_handler() is called to keep the LVGL graphics operational.
Load the sketch to the Arduino GIGA and observe the image. Now try rotating the display. The image should track the rotation and steady itself.
This technique has applications for both interfaces and games.
Using the Touch Screen
The Arduino GIGA Display Shield employs a Goodix GT911 capacitive touch controller. This provides up to five concurrent touchpoints, allowing for advanced controls such as gestures.
The touch screen can operate in either a polled or interrupt-driven mode. We will look at code samples for each mode.
Touch Screen – Polling Mode
In polling mode, we continuously check the touch screen to see if it has been touched. If it has, we grab up to five sets of coordinates.
Open the sample code at File/Examples/Examples From Custom Libraries/Arduino_GigaDisplayTouch/Touch_Polling
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/* Touch_Polling created 03 May 2023 by Leonardo Cavagnis */ #include "Arduino_GigaDisplayTouch.h" Arduino_GigaDisplayTouch touchDetector; void setup() { Serial.begin(115200); while(!Serial) {} if (touchDetector.begin()) { Serial.print("Touch controller init - OK"); } else { Serial.print("Touch controller init - FAILED"); while(1) ; } } void loop() { uint8_t contacts; GDTpoint_t points[5]; contacts = touchDetector.getTouchPoints(points); if (contacts > 0) { Serial.print("Contacts: "); Serial.println(contacts); for (uint8_t i = 0; i < contacts; i++) { Serial.print(points[i].x); Serial.print(" "); Serial.println(points[i].y); } } delay(1); } |
As you can see, this is pretty straightforward code. It uses the Arduino_GigaDisplayTouch library, which is used to create an object representing the touch detector.
In Setup, we start the serial monitor and detector.
In the Loop, we define an array to represent up to five contact coordinates. Then, we simply use the touchDetector.getTouchPoints function to populate that array if there are indeed points to record.
After that, we cycle through the array, displaying the coordinates on the serial monitor.
Load the sketch and give it a try. See what happens when you press more than one point.
Touch Screen – Interrupt Mode
Another method of using the touch screen is interrupt mode. In this mode, an interrupt is generated every time the screen is touched.
This method has many advantages over polling mode, especially in a large sketch where polling could produce erratic results.
Our example is located at File/Examples/Examples From Custom Libraries/Arduino_GigaDisplayTouch/Touch_IRQ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
/* Touch_IRQ created 03 May 2023 by Leonardo Cavagnis */ #include "Arduino_GigaDisplayTouch.h" Arduino_GigaDisplayTouch touchDetector; void gigaTouchHandler(uint8_t contacts, GDTpoint_t* points) { Serial.print("Contacts: "); Serial.println(contacts); if (contacts > 0) { /* First touch point */ Serial.print(points[0].x); Serial.print(" "); Serial.println(points[0].y); } } void setup() { Serial.begin(115200); while(!Serial) {} if (touchDetector.begin()) { Serial.println("Touch controller init - OK"); } else { Serial.println("Touch controller init - FAILED"); while(1) ; } touchDetector.onDetect(gigaTouchHandler); } void loop() { } |
The sketch starts off identically to the polling example. One difference is that there is a function defined as a “callback function.” This is called every time that a touch has been detected. In the callback, you will grab the coordinates to be used in your code.
The gigaTouchHandler function is our callback. In this demo, it just prints the number of touchpoints plus the coordinates of the first one.
Since the handler contains the bulk of the code, Setup is pretty simple. We start the serial monitor and touch display, then set the callback function. And there is no code in the Loop at all!
Load the sketch and go through the same exercise you did for the last sketch. The results will be similar. Note that only the first coordinate is printed when multiple points are touched; this is done to reduce the time the sketch spends inside the callback function.
Using the Video Camera
The Arduino GIGA Display Shield has an extension for the existing Arducam-compatible camera connector. This allows you to mount a camera facing the display operator.
There are currently four Arducam cameras that can be used with the display:
HM01B0
HM0360
GC2145
OV7675
To demonstrate the camera, we can use the sketch found here:
File/Examples/Examples from Custom Libraries/Arduino_GigaDisplay/camera/display_camera
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
#include "arducam_dvp.h" #include "Arduino_H7_Video.h" #include "dsi.h" #include "SDRAM.h" // This example only works with Greyscale cameras (due to the palette + resize&rotate algo) #define ARDUCAM_CAMERA_HM01B0 #ifdef ARDUCAM_CAMERA_HM01B0 #include "Himax_HM01B0/himax.h" HM01B0 himax; Camera cam(himax); #define IMAGE_MODE CAMERA_GRAYSCALE #elif defined(ARDUCAM_CAMERA_HM0360) #include "Himax_HM0360/hm0360.h" HM0360 himax; Camera cam(himax); #define IMAGE_MODE CAMERA_GRAYSCALE #elif defined(ARDUCAM_CAMERA_OV767X) #include "OV7670/ov767x.h" // OV7670 ov767x; OV7675 ov767x; Camera cam(ov767x); #define IMAGE_MODE CAMERA_RGB565 #error "Unsupported camera (at the moment :) )" #elif defined(ARDUCAM_CAMERA_GC2145) #include "GC2145/gc2145.h" GC2145 galaxyCore; Camera cam(galaxyCore); #define IMAGE_MODE CAMERA_RGB565 #error "Unsupported camera (at the moment :) )" #endif // The buffer used to capture the frame FrameBuffer fb; // The buffer used to rotate and resize the frame FrameBuffer outfb; // The buffer used to rotate and resize the frame Arduino_H7_Video Display(800, 480, GigaDisplayShield); void blinkLED(uint32_t count = 0xFFFFFFFF) { pinMode(LED_BUILTIN, OUTPUT); while (count--) { digitalWrite(LED_BUILTIN, LOW); // turn the LED on (HIGH is the voltage level) delay(50); // wait for a second digitalWrite(LED_BUILTIN, HIGH); // turn the LED off by making the voltage LOW delay(50); // wait for a second } } uint32_t palette[256]; void setup() { // Init the cam QVGA, 30FPS if (!cam.begin(CAMERA_R320x240, IMAGE_MODE, 30)) { blinkLED(); } // Setup the palette to convert 8 bit greyscale to 32bit greyscale for (int i = 0; i < 256; i++) { palette[i] = 0xFF000000 | (i << 16) | (i << 8) | i; } Display.begin(); dsi_configueCLUT((uint32_t*)palette); outfb.setBuffer((uint8_t*)SDRAM.malloc(1024*1024)); // clear the display (gives a nice black background) dsi_lcdClear(0); dsi_drawCurrentFrameBuffer(); dsi_lcdClear(0); dsi_drawCurrentFrameBuffer(); } void loop() { // Grab frame and write to another framebuffer if (cam.grabFrame(fb, 3000) == 0) { // double the resolution and transpose (rotate by 90 degrees) in the same step // this only works if the camera feed is 320x240 and the area where we want to display is 640x480 for (int i = 0; i < 320; i++) { for (int j = 0; j < 240; j++) { ((uint8_t*)outfb.getBuffer())[j * 2 + (i * 2) * 480] = ((uint8_t*)fb.getBuffer())[i + j * 320]; ((uint8_t*)outfb.getBuffer())[j * 2 + (i * 2) * 480 + 1] = ((uint8_t*)fb.getBuffer())[i + j * 320]; ((uint8_t*)outfb.getBuffer())[j * 2 + (i * 2 + 1) * 480] = ((uint8_t*)fb.getBuffer())[i + j * 320]; ((uint8_t*)outfb.getBuffer())[j * 2 + (i * 2 + 1) * 480 + 1] = ((uint8_t*)fb.getBuffer())[i + j * 320]; } } dsi_lcdDrawImage((void*)outfb.getBuffer(), (void*)dsi_getCurrentFrameBuffer(), 480, 640, DMA2D_INPUT_L8); dsi_drawCurrentFrameBuffer(); } else { blinkLED(20); } } |
The sketch is written for the Arducam HM01B0 camera but can be modified to use one of the other three cameras. To modify the sketch for a different camera, change line 8 as follows:
- HM01B0: #define ARDUCAM_CAMERA_HM01B0
- HM0360: #define ARDUCAM_CAMERA_HM0360
- GC2145: #define ARDUCAM_CAMERA_GC2145
- OV7675: #define ARDUCAM_CAMERA_OV767x
The code creates a buffer and dumps frames of video into the buffer. These are then moved to a second display buffer and then shown on the display.
When I tried the sketch with an Arducam OV7675 it worked, but the video I displayed was upside down and mirror imaged (I can see why the mirroring would be desirable, but the upside down is an error). I tried two cameras with the same results.
Nonetheless, the code does work and illustrates how you can incorporate a camera into your projects that use the Arduino GIGA Display Shield.
Conclusion
The Arduino GIGA Display Shield is undoubtedly a high-performance display. When coupled with the powerful Arduino GIGA R1, it can be used to create some very sophisticated designs. Using LVGL, you can easily create a GUI rivaling commercial devices.
The downside of this display is, of course, its price. While it isn’t too expensive considering its features, it can only be used with the relatively expensive Arduino GIGA R1. Similar LCD solutions that use the Mega 2560 are much less expensive, but they are also not as powerful.
If you need a high-performance display and can justify the price tag, then the Arduino GIGA Display Shield certainty fits the bill. It’s easy to use and even leaves the standard Arduino GIGA connectors available for additional shields.
All in all, it’s an impressive device!
Parts List
Here are some components you might need to complete the experiments in this article.
Arduino GIGA Display Shield Arduino Store
Arduino GIGA R1 Arduino Store
Arducam OV7675 Camera Arduino Store
Resources
Code Samples – All the code used in this article in one easy-to-use ZIP file!
Article PDF – A PDF version of this article in a ZIP file.
GIGA Display Documentation – Arduino guide to using the GIGA Display Shield.
LVGL – The Light and Versatile Graphics Library.
SquareLine Studio – GUI design utility.