| Both sides previous revisionPrevious revisionNext revision | Previous revision |
| en:edu:zmitac:s2:aih:lab:gfxonsite [2022/11/22 08:55] – [M5 Stack ESP32 Core Ink DEVKIT] pczekalski | en:edu:zmitac:s2:aih:lab:gfxonsite [2023/11/10 10:14] (current) – pczekalski |
|---|
| ====== Laboratory on the Internet of Things - Advanced IoT Hardware - on-site ====== | ====== Laboratory on the Internet of Things - Advanced IoT Hardware - on-site edition ====== |
| Laboratory guide for IoT AIH students on ESP32 graphical display programming: | Laboratory guide for IoT AIH students on ESP32 graphical display programming: |
| * ESP32 WROVER DEVKIT module - that includes (among others) dot-matrix LCD TFT display | * ESP32 WROVER DEVKIT module - that includes (among others) dot-matrix LCD TFT display |
| * M5 Stack CORE Ink DEVKIT Module - treat contains (among others) dot-matrix e-paper (e-ink) display | * M5 Stack CORE Ink DEVKIT Module - treat contains (among others) dot-matrix e-paper (e-ink) display |
| |
| |
| |
| |
| |
| ===== Hardware ===== | ===== Hardware ===== |
| * ESP32 PICO D4 M5 Stack with e-Paper (e-Ink) module | * ESP32 PICO D4 M5 Stack with e-Paper (e-Ink) module |
| |
| Below we present hardware details on those two modules: | Below, we present hardware details on those two modules: |
| ==== ESP32 WROVER DEVKIT ==== | ==== ESP32 WROVER DEVKIT ==== |
| This board is double-sided; on one side, you will find an LCD screen (so-called **back**) on the other side (**front**), there are GPIOs connectors you connect sensors and actuators to, TF (microSD) card slot with SPI reader and an RGB LED (among others).\\ | This board is double-sided; on one side, you will find an LCD screen (so-called **back**); on the other side (**front**), there are GPIO connectors you connect sensors and actuators to, TF (microSD) card slot with SPI reader and an RGB LED (among others).\\ |
| |
| <figure ESPWRoverDevKitFront> | <figure ESPWRoverDevKitFront> |
| </figure> | </figure> |
| |
| ESP32 provides a number of GPIOs to the developers, but some of them are hard-bound to their features as connected on the development board. | ESP32 provides many GPIOs to the developers, but some are hard-bound to their features as connected on the development board. |
| |
| <note important>Some of the GPIOs are dedicated to implementing a limited number of features, while some are dedicated to using a particular protocol on this development board. As this development board contains some peripherals (RGB LED, LCD, TF card reader), do not use GPIOs that are controlling them.</note> | <note important>Some GPIOs are dedicated to implementing a limited number of features, while some are dedicated to using a particular protocol on this development board. As this development board contains some peripherals (RGB LED, LCD, TF card reader), do not use GPIOs that are controlling them.</note> |
| The following list presents GPIOs used with the integrated hardware: | The following list presents GPIOs used with the integrated hardware: |
| <table tabWROVER> | <table tabWROVER> |
| |
| |
| It is also necessary to configure the serial port name that is used for uploading your firmware and monitoring. In the case of this microcontroller, it is the same port, so the ''platformio.ini'' file should be modified with the following (assuming the serial port is, i.e. ''COM3''): | Configuring the serial port name used for uploading your firmware and monitoring is also necessary. In the case of this microcontroller, it is the same port, so the ''platformio.ini'' file should be modified with the following: |
| <code> | <code> |
| ... | ... |
| upload_port = COM3 | upload_port = <some port name comes here> |
| monitor_port = COM3 | monitor_port = <some port name comes here> |
| ... | ... |
| </code> | </code> |
| Type the textual "Hello World" on the screen. Then, you're welcome to decorate it, change colours, size, orientation, etc. | Type the textual "Hello World" on the screen. Then, you're welcome to decorate it, change colours, size, orientation, etc. |
| |
| To use LCD, you must include the correct libraries for this LCD model. The includes section of your source code file may then look more-less following way: | You must include the correct libraries for this LCD model to use LCD. The includes section of your source code file may then look the following way: |
| <code c> | <code c> |
| ... | ... |
| </code> | </code> |
| |
| Then define a controller class that manages your LCD: | Then, define a controller class that manages your LCD: |
| <code c> | <code c> |
| ... | ... |
| <note tip>Have a minute and jump into the ''WROVER_KIT_LCD.h'' and ''Adafruit_GFX.h'' headers to find more useful functions, i.e. drawing a bitmap, scrolling the display, etc.</note> | <note tip>Have a minute and jump into the ''WROVER_KIT_LCD.h'' and ''Adafruit_GFX.h'' headers to find more useful functions, i.e. drawing a bitmap, scrolling the display, etc.</note> |
| ==== M5 Stack ESP32 Core Ink DEVKIT ==== | ==== M5 Stack ESP32 Core Ink DEVKIT ==== |
| This M5 Stack module is an integrated ESP32 microcontroller (PICO D4 version, full [[https://www.espressif.com/sites/default/files/documentation/esp32-pico-d4_datasheet_en.pdf|specification]] is available on the manufacturer's page). This module, even if compact in size, also contains expansion ports, an internal battery powering RTC (BM8563) when no external power is present, 3 physical buttons: reset, power and programmable, a green LED and a passive buzzer.\\ | This M5 Stack module is an integrated ESP32 microcontroller (PICO D4 version, full [[https://www.espressif.com/sites/default/files/documentation/esp32-pico-d4_datasheet_en.pdf|specification]] is available on the manufacturer's page). This module, even if compact, also contains expansion ports, an internal battery powering RTC (BM8563) when no external power is present, 3 physical buttons: reset, power and programmable, a green LED and a passive buzzer.\\ |
| |
| <figure label> | <figure m5stack1> |
| {{:en:edu:zmitac:s2:aih:lab:m5stack_core_ink.jpg?400|}} | {{:en:edu:zmitac:s2:aih:lab:m5stack_core_ink.jpg?400|}} |
| <caption>M5 Stack ESP32 Core Ink DEVKIT</caption> | <caption>M5 Stack ESP32 Core Ink DEVKIT</caption> |
| </figure> | </figure> |
| |
| ESP32 provides a number of GPIOs to the developers, but some of them are hard-bound to their features as connected on the development board. | ESP32 provides many GPIOs to the developers, but some are hard-bound to their features as connected on the development board. |
| |
| <note>Following GPIOS are exposed: G25, G26, G36, G23, G34, G18, G21, G22, G14, G13</note> | <note>Following GPIOS are exposed: G25, G26, G36, G23, G34, G18, G21, G22, G14, G13</note> |
| |
| <note important>Some of the GPIOs are dedicated to implementing a limited number of features, while some are dedicated to using a particular protocol on this development board. This development board contains some peripherals (RGB LED, LCD, TF card reader) that do not use GPIOs that are controlling them.</note> | <figure m5stack2> |
| | {{:en:edu:zmitac:s2:aih:lab:m5stack_core_ink2.jpg?200|}} |
| | <caption>M5 Stack ESP32 Core Ink DEVKIT GPIOs</caption> |
| | </figure> |
| | |
| | <note important>Some GPIOs are dedicated to implementing a limited number of features, while some are dedicated to using a particular protocol on this development board. This development board contains some peripherals (RGB LED, LCD, TF card reader) that do not use GPIOs to control them.</note> |
| |
| <table tabTTGO> | <table tabTTGO> |
| === Configuring VREL - platformio.ini === | === Configuring VREL - platformio.ini === |
| Correct configuration is necessary to build and deploy your code.\\ | Correct configuration is necessary to build and deploy your code.\\ |
| For M5 Stack Core Ink Development Kit, a good starting point is the following content for the ''platformio.ini'' file: | For the M5 Stack Core Ink Development Kit, a good starting point is the following content for the ''platformio.ini'' file: |
| <code> | <code> |
| [env:m5stack-core-esp32] | [env:m5stack-core-esp32] |
| |
| |
| It is also necessary to configure the serial port name that is used for uploading your firmware and monitoring. In the case of this microcontroller, it is the same port, so the ''platformio.ini'' file should be modified with the following (assuming the serial port is, i.e. ''COM3''): | Configuring the serial port name used for uploading your firmware and monitoring is also necessary. In the case of this microcontroller, it is the same port, so the ''platformio.ini'' file should be modified with the following: |
| <code> | <code> |
| ... | ... |
| upload_port = COM3 | upload_port = <some port name comes here> |
| monitor_port = COM3 | monitor_port = <some port name comes here> |
| ... | ... |
| </code> | </code> |
| == Practice: handling e-Paper display == | == Practice: handling e-Paper display == |
| Write Hello World on the e-Paper screen textual, then present any image (be respectful when choosing one, please :) ). \\ | Write Hello World on the e-Paper screen textual, then present any image (be respectful when choosing one, please :) ). \\ |
| To start using e-Paper display easily, you may use a library that can handle display operations. So your source code includes section may look somehow like this: | To start using e-Paper display easily, you may use a library that can handle display operations. So your source code includes a section that may look somehow like this: |
| |
| <code c> | <code c> |
| </code> | </code> |
| |
| The display initialisation uses a singleton class controller of the M5 stack, including an e-Paper display (static object, already present in the library, you do not need to declare any variable of its type): | The display initialisation uses a singleton class controller of the M5 stack, including an e-Paper display (static object, already present in the library; you do not need to declare any variable of its type): |
| <code c> | <code c> |
| M5.begin(); | M5.begin(); |
| </note> | </note> |
| |
| This library uses (among others) a "sprite" approach to handle the display layout. A sprite is simply a buffer that you draw virtually all graphics you want to draw; it is still located in the RAM memory. Once your composition is ready, you can make it visible all at once by simply pushing it to the display's memory. it enables you to easily handle updates of the part of the display rather than the whole area, as e-Paper (e-Ink) displays are slow in displaying, according to their nature.\\ | This library uses (among others) a "sprite" approach to handle the display layout. A sprite is simply a buffer that you draw virtually all graphics you want to draw; it is still located in the RAM. Once your composition is ready, you can make it visible all at once, by simply uploading it to the display's memory. it enables you to easily handle updates of the part of the display rather than the whole area, as e-Paper (e-Ink) displays are slow in displaying, according to their nature.\\ |
| To define a sprite, use its starting coordinates (x,y), width and height. The following "sprite" definition creates a full-screen one: | To define a sprite, use its starting coordinates (x,y), width and height. The following "sprite" definition creates a full-screen one: |
| <code c> | <code c> |
| </code> | </code> |
| |
| There is a number of functions to handle a variety of tasks so that M5 Stack does not split HAL and GFX layers separately but instead integrates them into a single library. Sample calls to "draw" into the sprite (note it does not show anything on display, just draws virtually to the sprite's memory are presented below: | There are several functions to handle various tasks so that M5 Stack does not split HAL and GFX layers separately but instead integrates them into a single library. Sample calls to "draw" into the sprite (note it does not show anything on display, draws virtually to the sprite's memory are presented below: |
| <code c> | <code c> |
| ... | ... |
| |
| ==== A special note on PWM in ESP32 ==== | ==== A special note on PWM in ESP32 ==== |
| PWM is frequently used to control analogue-style, efficient voltage on the GPIO pin. Instead of using a resistance driver, PWM uses pulses to change adequate power delivered to the actuator. It applies to motors but also to LEDs, bulbs, heaters, and indirectly to the servos (but that works actually another way, see lectures).\\ | PWM frequently controls analogue-style, efficient voltage on the GPIO pin. Instead of a resistance driver, PWM uses pulses to change adequate power delivered to the actuator. It applies to motors and LEDs, bulbs, heaters, and indirectly to the servos (but that works another way; see lectures).\\ |
| The classical ''analogWrite'' method known as Arduino (Uno, Mega) and ESP8266 do not work here.\\ | The classical ''analogWrite'' method known as Arduino (Uno, Mega) and ESP8266 do not work here.\\ |
| ESP32 has sixteen (0 to 15) PWM channels (controllers) that can be freely bound to any of the regular GPIOs.\\ Moreover, ESP32 can use various "resolutions" of the PWM: from 8-bit (0..255) to 15bit (0..32767), while regular Arduino uses only 8-bit one. | ESP32 has sixteen (0 to 15) PWM channels (controllers) that can be freely bound to any of the regular GPIOs.\\ Moreover, ESP32 can use various "resolutions" of the PWM: from 8-bit (0..255) to 15-bit (0..32767), while regular Arduino uses only 8-bit one. |
| |
| To use PWM in ESP32, one must perform the following steps: | To use PWM in ESP32, one must perform the following steps: |
| * Bind the controller to the GPIO pin | * Bind the controller to the GPIO pin |
| * Write to the controller (not to the PIN!) providing a duty cycle related to the resolution selected above - every call persistently sets the PWM duty cycle until there is the next call to the function setting duty cycle. | * Write to the controller (not to the PIN!) providing a duty cycle related to the resolution selected above - every call persistently sets the PWM duty cycle until there is the next call to the function setting duty cycle. |
| | <pagebreak> |
| ===== Laboratory scenarios ===== | ===== Laboratory scenarios ===== |
| In general, you will program using the Arduino framework. \\ | In general, you will program using the Arduino framework. \\ |
| As presented during the lecture, you will also use FreeRTOS functions to handle multicore parallel programming to perform tasks, as demonstrated during the lecture. | As presented during the lecture, you will also use FreeRTOS functions to handle multicore parallel programming to perform tasks, as demonstrated during the lecture. |
| |
| <note warning>ESP32 framework uses C++ optimiser while compiling the source code. It is common that C++ traces unused code and removes/optimises it, to minimise CPU effort. As your tasks to be completed, involve integer and floating-point performance evaluation, it is essential to use the result somewhere, i.e. do a dummy display of the final value on the screen. Otherwise, the C++ compiler may remove this section of the code, and you won't be able to obtain reasonable results, because your code may be already trunk and not executed at all!</note> | <note warning>ESP32 framework uses C++ optimiser while compiling the source code. It is common that C++ traces unused code and removes/optimises it to minimise CPU effort. As your tasks to be completed involve integer and floating-point performance evaluation, it is essential to use the result somewhere, i.e. do a dummy display of the final value on the screen. Otherwise, the C++ compiler may remove this section of the code, and you won't be able to obtain reasonable results because your code may be already trunk and not executed at all!</note> |
| |
| <note important>FreeRTOS, once the task is created and scheduled for execution, executes the task infinitely! It means, your function implementing the task will be executed again and again. If you intended to run a looped task, that is pretty OK. If you intended to run the one-off task, then you need explicitly call: | <note important>FreeRTOS, once the task is created and scheduled for execution, executes the task infinitely! It means your function implementing the task will be executed again and again. If you intended to run a looped task, that is pretty OK. If you intend to run the one-off task, then you need to call explicitly: |
| <code c> | <code c> |
| ... | ... |
| </code> | </code> |
| as a last line of your function implementing the task.</note> | as a last line of your function implementing the task.</note> |
| | |
| | ==== Task 0 ==== |
| | This warm-up lab scenario lets you understand and prepare a code for presenting your data on the display (LCD and e-Paper).\\ |
| | Implement a program that on the first screen presents, alternatively (each for 5s), your team number and names of the team members then presents a picture of choice. (logo, photo, meme). |
| | |
| ==== Task 1 ==== | ==== Task 1 ==== |
| Evaluate single-core performance for integer computation. Perform two experiments: with task bound to the APP core and separately to the PRO core. First, observe if there is a difference in measurements. Then, propose an algorithm that can generate a complexity of integer computation observable and measurable. | Evaluate single-core performance for integer computation. Perform two experiments: with the task bound to the APP core and separately to the PRO core. First, observe if there is a difference in measurements. Then, propose an algorithm that can generate a complexity of integer computation observable and measurable. |
| Perform at least 10 measurements for each experiment. Consider using parts of code for the Dhrystone benchmark [[https://en.wikipedia.org/wiki/Dhrystone|https://en.wikipedia.org/wiki/Dhrystone]]. | Perform at least 10 measurements for each experiment. Consider using parts of code for the Dhrystone benchmark [[https://en.wikipedia.org/wiki/Dhrystone|https://en.wikipedia.org/wiki/Dhrystone]]. |
| |
| ==== Task 2 ==== | ==== Task 2 ==== |
| Evaluate multicore performance for integer computation. Perform single-core computation, running at least 4 times (any even number works here) your algorithm. Then execute in parallel (2x2). Observe if there is a difference in measurements. Propose an algorithm that can generate a complexity of integer computation observable and measurable. | Evaluate multicore performance for integer computation. Perform single-core computation, running your algorithm at least 4 times (any even number works here). Then execute in parallel (2x2). Observe if there is a difference in measurements. Propose an algorithm to generate a complex, observable, measurable integer computation. |
| Perform at least 20 measurements for each experiment (10 serial + 10 parallel). Consider using parts of code for the Dhrystone benchmark [[https://en.wikipedia.org/wiki/Dhrystone|https://en.wikipedia.org/wiki/Dhrystone]]. | Perform at least 20 measurements for each experiment (10 serial + 10 parallel). Consider using parts of code for the Dhrystone benchmark [[https://en.wikipedia.org/wiki/Dhrystone|https://en.wikipedia.org/wiki/Dhrystone]]. |
| |
| ==== Task 3 ==== | ==== Task 3 ==== |
| Evaluate single-core performance for floating-point computation. Perform two experiments: with task bound to the APP core and separately to the PRO core. First, observe if there is a difference in measurements. Then, propose an algorithm that can generate a complex-enough floating points computation that is observable and measurable. | Evaluate single-core performance for floating-point computation. Perform two experiments: with the task bound to the APP core and separately to the PRO core. First, observe if there is a difference in measurements. Then, propose an algorithm that can generate a complex enough floating points computation that is observable and measurable. |
| Perform at least 10 measurements for each experiment. Consider using FP parts of code for Whetstone benchmark [[https://en.wikipedia.org/wiki/Whetstone_(benchmark)|https://en.wikipedia.org/wiki/Whetstone_(benchmark)]]. | Perform at least 10 measurements for each experiment. Consider using FP parts of code for the Whetstone benchmark [[https://en.wikipedia.org/wiki/Whetstone_(benchmark)|https://en.wikipedia.org/wiki/Whetstone_(benchmark)]]. |
| |
| ==== Task 4 ==== | ==== Task 4 ==== |
| Evaluate multicore performance for floating-point computation. First, perform single-core computation, running your algorithm at least 4 times (any even number works here) your algorithm. Then execute in parallel (i.e. 2x2). Finally, propose an algorithm that can generate a complex-enough floating-point computation that is observable and measurable. | Evaluate multicore performance for floating-point computation. First, perform single-core computation, running your algorithm at least 4 times (any even number works here) your algorithm. Then execute in parallel (i.e. 2x2). Finally, propose an algorithm to generate a complex enough floating-point, observable and measurable computation. |
| Perform at least 20 measurements for each experiment (10 serial + 10 parallel). Consider using FP parts of code for Whetstone benchmark [[https://en.wikipedia.org/wiki/Whetstone_(benchmark)|https://en.wikipedia.org/wiki/Whetstone_(benchmark)]]. | Perform at least 20 measurements for each experiment (10 serial + 10 parallel). Consider using FP parts of code for the Whetstone benchmark [[https://en.wikipedia.org/wiki/Whetstone_(benchmark)|https://en.wikipedia.org/wiki/Whetstone_(benchmark)]]. |
| |
| |
| ==== Report ==== | ==== Report ==== |
| Include algorithm definition and measurements, along with statistical analysis of the results (at least average and standard deviation) and a summary. | Task 0: besides the general description, include source code and screenshots. |
| | Tasks 1 and onwards: include algorithm definition and measurements, statistical analysis of the results (at least average and standard deviation) and a summary. |
| |
| | <pagebreak> |
| ===== Resources ===== | ===== Resources ===== |
| - [[https://www.espressif.com/en/products/hardware/esp-wrover-kit/resources|ESP32 WROVER kit starting page]] | - [[https://www.espressif.com/en/products/hardware/esp-wrover-kit/resources|ESP32 WROVER kit starting page]] |
| - [[https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-wrover-kit.html|Hardware definition (pinouts, gpios, etc.)]] | - [[https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-wrover-kit.html|Hardware definition (pinouts, GPIOs, etc.)]] |
| - [[https://dl.espressif.com/dl/schematics/ESP-WROVER-KIT_V4_1.pdf|ESP-WROVER-KIT V4.1 schematic]] | - [[https://dl.espressif.com/dl/schematics/ESP-WROVER-KIT_V4_1.pdf|ESP-WROVER-KIT V4.1 schematic]] |
| - [[https://docs.m5stack.com/en/core/coreink|M5 Stack Core Ink (e-Paper) module documentation]] | - [[https://docs.m5stack.com/en/core/coreink|M5 Stack Core Ink (e-Paper) module documentation]] |
| - [[https://javl.github.io/image2cpp/|On-line bitmap (image) to memory content (cpp) converter]] | - [[https://javl.github.io/image2cpp/|On-line bitmap (image) to memory content (cpp) converter]] |
| - [[https://savjee.be/2020/01/multitasking-esp32-arduino-freertos/|FreeRTOS - multitasking with ESP32 explained]] | - [[https://savjee.be/2020/01/multitasking-esp32-arduino-freertos/|FreeRTOS - multitasking with ESP32 explained]] |