ANNEX32 WI-FI RDS

User Manual

Version 2.0.6

© ciccioCB 2025


 

 

COPYRIGHT

 

The Annex firmware, including the AnnexToolKit and this manual, are Copyright 2017-2025 by Francesco Ceccarella (ciccioCB).

 

The compiled object code (the .bin file) for the Annex firmware is free software: you can use or redistribute it as you please except for commercial purposes. It is not allowed to distribute or embed it into products that are sold or for any other activity making or intended to make a profit.

 

The compiled object code (the .exe file) for the AnnexToolKit utility is free software: you can use or redistribute it as you please except for commercial purposes. It is not allowed to distribute or embed it into products that are sold or for any other activity making or intended to make a profit.

 

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even

the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 

This manual is distributed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 France license (CC BY-NC-SA 3.0)

 

The above copyright notice and this permission notice shall be included in all copies or redistributions of the Software in any form.

License and credits

The base of the interpreter comes from the original project "MiniBasic" by Malcom Mclean.

Adafruit BNO055 Orientation Sensor library is written by KTOWN is Copyright © Adafruit Industries. It is released under MIT license.

TFT_eSPI display Library is Copyright ©  2017 Bodmer. It is released under FreeBSD license.

Adafruit PWM Servo Driver Library is Copyright © Adafruit. It is released under MIT license.

Arduino Library for Dallas Temperature ICs is Copyright © Miles Burton <miles@mnetcs.com>. It is released under LGPL license.

OneWire Library is Copyright 1999-2006 Dallas Semiconductor Corporation and Copyright © 2007, Jim Studt.

Adafruit DHT Humidity & Temperature Sensor Library is Copyright © Adafruit. It is released under MIT license.

ESP8266 and ESP32 Oled Driver for SSD1306 display is Copyright © 2016 by Daniel Eichhorn and Copyright © 2016 by Fabrice Weinberg

NeoPixelBus library is Copyright © Michael C. Miller.  It is released under LGPL license.

ESP AsyncTCP library is Copyright © 2016 Hristo Gochkov. It is released under LGPL license.

ESP AsyncWebServer library is Copyright © 2016 Hristo Gochkov. It is released under LGPL license.

IRremote library is Copyright © Sebastien Warin, Mark Szabo, Ken Shirriff, David Conran. It is released under LGPL license.

uRTCLib is is Copyright © 2015 Naguissa (naguissa.com@gmail.com). It is released under LGPL license.

BME280 library is written by Limor Fried/Ladyada for Adafruit Industries. It is released under BSD license,

APDS9960 library is written by Shawn Hymel for Sparkfun Electronics. It is released under Beerware license.

PID Library is written by Brett Beauregard (br3ttb@gmail.com). It  is released under MIT license.

The Javascript Editor  EditArea is  Copyright © 2008 Christophe Dolivet. It is released under BSD license.

The M5Stack library is copyright © 2017 by M5Stack. It is released under MIT license.

The MPU9250 driver is part of the M5Stack Library.

The VL53L0X driver is Copyright © 2017 Pololu. It contains code © 2016 STMicroelectronics.

Some GUI objects come from the library GUIslice Copyright © Calvin Hass that is released under MIT license.

The MFRD522 library is written by Miguel Balboa and is released as free and unencumbered software released into the public domain.

Adafruit GFX is Copyright (c) 2012 Adafruit Industries. It is released under BSD license,

lovyanGFX is Copyright (c) 2020 lovyan03. It is released under Free BSD license.

LVGL is Copyright (c) 2025 LVGL Kft. It is released under MIT license.

 

 

 

 

 

Contributions

A very big thank you to Robin Baker (Electroguard) for his great involvement in the project by supporting all the tests on the real hardware (bought with his money), and all the advices that allowed me to add a lot of functionality, not to mention the Huge work he did while documenting the project on the website.

 

 

 

Revisions / major updates of the document

 

Lovyan GFX Graphics Library

 

Starting from Release 2+, Annex 32 RDS introduces significant advancements, including the integration of the LovyanGFX graphics programming library. This update marks a substantial improvement over the previous TFT_eSPI library and  the Adafruit GFX library by incorporating features such as buffer handling, sprite support, transparency, and image rotation/scaling. These enhancements provide greater flexibility and performance for graphical applications.

 

 

LVGL Graphics Library

 

Starting from Release 2+, Annex 32 RDS incorporates the LVGL (Light and Versatile Graphics Library) into its firmware. This integration makes LVGL a core component of the Annex development environment, enabling developers to create visually appealing and interactive graphical user interfaces with minimal memory usage. Its efficient design is particularly well-suited for resource-constrained ESP32 projects, offering a powerful solution for advanced GUI development.

While the existing "legacy" GUI remains implemented for now, it is planned to be removed in the short term following the full implementation of LVGL, ensuring a more modern and efficient solution for GUI development.


Content :

Introduction: 41

Interpreter: 43

Branch labels. 44

Variables: 45

Arrays: 46

OPTION.BASE 1. 46

LBOUND(array() [, dimension]) : Returns the lower bound of the specified array dimension. 47

UBOUND(array() [, dimension]) : Returns the upper bound of the specified array dimension. 47

Scope of the variables: 48

Bases of the language. 48

OPERATORS AND PRECEDENCE.. 49

Basic internal keywords: 51

IF command : 51

FOR loop. 52

WHILE WEND loop. 53

DO LOOP loop. 53

SELECT CASE.. 54

GOTO.. 56

GOSUB.. 56

DATA.. 56

END.. 58

EXIT. 58

SUB.. 58

Logical / boolean Operations. 60

ERRORS HANDLING.. 61

ONERROR ABORT. 61

ONERROR IGNORE. 61

ONERROR SKIP [nn]. 61

ONERROR CLEAR. 61

ONERROR GOTO [label | OFF]. 61

BAS.ERRLINE. 62

BAS.ERRNUM. 62

BAS.ERRMSG$. 62

HOW the interpreter works with the HTML code and Objects : 62

HTML Objects. 67

TIMERS.. 72

EVENTS.. 72

Button Event 73

OnHtmlChange Event 73

OnHtmlReloadEvent 73

OnInfrared Event 74

OnSerial Event 74

OnSerial2 Event 74

OnTouch Event 75

OnUDP Event 75

OnWgetAsync Event 75

OnUrlMessage Event 76

OnEspNowMsg Event 79

OnEspNowError Event 80

OnMQTT Event 80

OnPlay Event 80

WiFI CONNECTIONS.. 80

PROGRAM AUTORUN.. 83

RECOVERY MODE.. 83

SLEEP mode (low energy) and RTC memory. 83

DATE - TIME timekeeper 84

Unix Time functions. 85

FAT32 File System.. 85

FILE.COPY(filename$, newfile$). 87

FILE.DELETE(filename$). 87

FILE.EXISTS(filename$). 87

FILE.RENAME(oldname$, newname$). 87

FILE.SIZE(filename$). 87

FILE.MKDIR(dirname$). 87

FILE.RMDIR(dirname$). 87

FILE.DIR$(path$). 87

FILE.READ$(filename$, [line_num] | [start, length]). 87

FILE.APPEND filename$, content$. 87

FILE.SAVE filename$, content$. 88

FILE.WRITE filename$, content$. 88

FILE.FROMBASE64 source$, dest$. 88

FILE.TOBASE64 source$, dest$. 88

FILE.SAVE_IOBUFF. 88

FILE.WRITE_IOBUFF. 88

FILE.APPEND_IOBUFF. 88

FILE.READ_IOBUFF. 88

Download files from another module or WEB server 89

Notes: 89

I/O BUFFERS.. 90

Define the Size of an I/O Buffer 90

IOBUFF.DIM(buff_num, size). 90

Fill a Buffer with Predefined Data. 90

IOBUFF.DIM(buff_num, size) = data_list. 90

Release a Buffer 91

IOBUFF.DESTROY(buff_num, size). 91

Get the Size of a Buffer 91

IOBUFF.LEN(buff_num). 91

Read Data from a Buffer 92

IOBUFF.READ(buff_num, position). 92

Write Data to a Buffer 92

IOBUFF.WRITE(buff_num, position, value). 92

Read Operations. 93

Write Operations. 94

Special operations. 95

Advanced operations. 95

IOBUFF.FROMSTRING(buff_num, var$ [, pos]). 95

IOBUFF.TOSTRING$(buff_num, [, start [, size]]). 96

IOBUFF.FROMHEX(buff_num, var$ [, pos]). 97

IOBUFF.TOHEX$(buff_num, [, start [, size]]). 97

Base64 conversion. 98

IOBUFF.TOBASE64(buff_num). 98

IOBUFF.FROMBASE64(buff_num, Base64String$). 99

Cryptography. 99

IOBUFF.ENCRYPT(buff_num, key$). 99

IOBUFF.DECRYPT(buff_num, key$). 100

CRC Function: 100

IOBUFF.CRC(buff_num, nb_bits, polynom, initial_value, ref_in, ref_out, xor_out). 100

Bit Operations on Buffer Data. 104

IObuff.bit(buff_num, position, bit). 104

IObuff.setbit(buff_num, position, bit). 104

IObuff.clearbit(buff_num, position, bit). 105

IObuff.togglebit(buff_num, position, bit). 105

Buffer copy. 106

IObuff.copy(dest_buff_num [,pos]) , (source_buff_num, [, start [, size]]). 106

Code examples : 107

WIRING.. 109

DIGITAL I/O.. 110

PIN.STRENGTH 15, 2. 111

PIN SERIAL SHIFTING.. 111

PIN.SHIFTOUT pin_data, pin_clk, data [, bit_order] [, nb_bits] [, delay_us]. 112

PIN.SHIFTIN( pin_data, pin_clk [, bit_order] [, nb_bits] [, delay_us] ). 113

PIN INTERRUPTS.. 114

Analog inputs. 115

TOUCH inputs. 115

Analog outputs. 116

Hardware interfaces: 116

PWM.. 116

PWM.SETUP pin, channel, default_value,  [,frequency] [,resolution]. 117

PWM.OUT channel, value. 117

SERVO.. 118

I2S BUS.. 119

SPEAKER OUTPUT. 121

SPDIF OUTPUT. 122

I2C BUS.. 122

PCF8574 Module. 123

ADS1115 Module. 125

MCP23017 Module. 127

SPI BUS.. 128

74HC595 Module. 131

MCP23S17 Module. 132

CAN BUS.. 134

CAN.SETUP.. 135

CAN.INIT. 136

CAN.STOP.. 136

CAN.WRITE.. 136

CAN.WRITE_IOBUFF. 137

ONCANBUS.. 137

CANBUS BUFFERS.. 139

RMT Module. 141

Key Features. 141

Memory Management and Synchronisation of RMT Channels. 142

Clock Divider. 142

RMT RAM Composition. 143

Memory Block Extension. 144

RMT Transmit Synchronisation. 145

TX Transmitter Mode. 145

RX Reception Mode. 146

RX Reception Event 146

RMT Command Functions. 146

RMT.SETUP_TX channel, pin [, clk_div] [, mem_block_num] [, idle_level] [, loop_en] [, carrier_en] [, carrier_freq_hz] [, carrier_duty_percent] [, carrier_level]. 146

RMT.WRITE channel, num_items, name [, wait]. 147

RMT.ENCODE channel, num_items, array() [, wait]. 147

RMT.SETUP_RX channel, pin [, clk_div] [, mem_block_num] [, invert] [, filter_en] [, filter_ticks_thresh] [, idle_threshold] [, rm_carrier] [, carrier_freq_hz] [, carrier_duty_percent] [, carrier_level]. 147

RMT.READ array(). 148

RMT.DECODE array(). 148

RMT.ADD_GROUP channel. 148

RMT.DEL_GROUP channel. 148

RMT.END channel. 149

Synchronisation in Groups. 149

Example 1: RMT Transmission of a Pulse Sequence. 149

Example 2: RMT Transmission of a Sinusoidal Pattern. 151

Example 3: Synchronized RMT Transmission of Sinusoidal Patterns. 153

Example 4: Infrared Signal Reception and Decoding with RMT on ESP32. 155

COUNTERS.. 157

PID controllers. 158

SOUND PLAYER.. 160

Metadata Decoding from Mp3 and streaming. 162

SPEECH SYNTHESIS with vintage C64 SAM speaker 163

SPEECH SYNTHESIS using google translate. 164

SPEECH SYNTHESIS using voiceRSS free service. 165

VS1053B Audio Decoder 166

VS1053.SETUP XCS_pin, XDCS_pin, DREQ_pin [,info_enabled] [,SPIfreq] [SCI_CLOCKF]. 168

VS1053.PLAY file$. 168

VS1053.STREAM streaming_url$. 169

VS1053.VOICE "message", "language". 169

VS1053.STOP. 169

VS1053.VOLUME vol. 169

VS1053.RESET. 169

VS1053.INIT patchFile$. 170

VS1053.INIT "/patches/vs1053b-patches-flac.cmd". 170

VS1053.WRITE register, value. 170

VS1053.READ register. 170

VS1053.MIDI_CMD cmd, data1, data2. 170

VS1053.NOTE_ON channel, note, velocity. 170

VS1053.NOTE_OFF channel, note, velocity. 170

LCD DISPLAY USING I2C.. 170

OLED DISPLAY.. 175

ST7920 LCD DISPLAY.. 177

RTC module. 179

PCA9685 (PWM / Servo) Module. 181

TM1637 display module. 182

TM1638 display module. 184

MAX7219 8-Digits 7-segment display. 186

MAX7219 Dot Matrix Display. 187

NeoPixel WS2812B led strips. 189

NEO.SETUP pin, [nb_led]. 191

NEO.STRIP led_start_pos, led_end_pos, R, G, B [, disable]. 191

NEO.STRIP led_start_pos, led_end_pos, COLOR [, disable]. 191

NEO.PIXEL led_pos, R, G, B [, disable]. 191

NEO.PIXEL led_pos, COLOR [, disable]. 191

NEO.RGB(R, G, B). 191

NEO.GETPIXEL(led_pos). 191

NEO.ROTATELEFT num_steps, [led_end_pos, led_end_pos, disable]. 191

NEO.ROTATERIGHT num_steps, [led_end_pos, led_end_pos, disable]. 191

NEO.SHIFTLEFT num_steps, [led_end_pos, led_end_pos, disable]. 191

NEO.SHIFTRIGHT num_steps, [led_end_pos, led_end_pos, disable]. 192

NEO.REFRESH. 192

NEO.DIM(COLOR , Gain). 192

NEO.LIGHTEN(COLOR , Gain). 192

NEO.DARKEN(COLOR , Gain). 192

NEO.LINEARBLEND(COLOR1, COLOR2, progress). 192

NEO.BILINEARBLEND(. 192

Upper_Left_COLOR, Upper_Right_COLOR, Lower_Left_COLOR, Lower_Right_COLOR, x, y). 192

NeoPixel based WS2812b Dot Matrix DIsplay. 193

NEOSCROLL.SETUP nb_devices, nb_lines, pin [,layout] [,width, height, orientation]. 197

NEOSCROLL.DELETE. 197

NEOSCROLL.FILL color, [x, y, width, height]. 197

NEOSCROLL.TEXT.POS x, y. 197

NEOSCROLL.TEXT.FONT font. 197

NEOSCROLL.SHOW x, y. 197

NEOSCROLL.TEXT.BRIGHTNESS brightness. 197

NEOSCROLL.BRIGHTNESS brightness. 197

NEOSCROLL.PRINT text$, color$. 198

NEOSCROLL.SPRITESHEET image$. 198

NEOSCROLL.SPRITE x, y, width, height, x_in_bmp, y_in_bmp. 199

Copy a portion of the SPRITESHEET image into the canvas using the parameters given. 199

NEOSCROLL.LIMITS [x1,] [x2], [y1], [y2]. 199

NEOSCROLL.SYNC. 199

NEOSCROLL.MODE mode. 199

NEOSCROLL.SCROLL. 199

NEOSCROLL.SCROLL. 199

Scroll the image using the current MODE and within the current LIMITS.c. 199

NEOSCROLL.OSCILLATE. 199

NEOSCROLL.OSCILLATE. 199

Oscillate the image using the current MODE and within the current LIMITS.c. 199

NEOSCROLL.X. 199

NEOSCROLL.Y. 199

HUB75 Matrix Displays - DMAMATRIX.. 203

DMAMATRIX.INIT R1, G1, B1, R2, G2, B2, A, B, C, D, E, LAT, OE, CLK [,freq_DMA] [,resolution]. 204

DMAMATRIX.SETUP nb_devices, nb_lines [,layout] [,width, height, orientation]. 204

DMAMATRIX.DELETE. 204

DMAMATRIX.FILL color, [x, y, width, height]. 204

DMAMATRIX.TEXT.POS x, y. 204

DMAMATRIX.TEXT.FONT font. 205

DMAMATRIX.TEXT.COLOR color. 205

DMAMATRIX.SHOW [x, y]. 205

DMAMATRIX.TEXT.BRIGHTNESS brightness. 205

DMAMATRIX.BRIGHTNESS brightness. 205

DMAMATRIX.PRINT text$ [, color$ | color]. 206

DMAMATRIX.SPRITESHEET image$. 206

DMAMATRIX.SPRITE x, y, width, height, x_in_bmp, y_in_bmp. 207

Copy a portion of the SPRITESHEET image into the canvas using the parameters given. 207

DMAMATRIX.LIMITS [x1,] [x2], [y1], [y2]. 207

DMAMATRIX.SYNC. 207

DMAMATRIX.MODE mode. 207

DMAMATRIX.SCROLL. 207

DMAMATRIX.SCROLL. 207

Scroll the image using the current MODE and within the current LIMITS.c. 207

DMAMATRIX.OSCILLATE. 207

DMAMATRIX.OSCILLATE. 207

Oscillate the image using the current MODE and within the current LIMITS.c. 207

DMAMATRIX.PIXEL x, y, color. 207

DMAMATRIX.LINE x1, y1, x2, y1, color. 207

DMAMATRIX.CIRCLE x, y, radius, color [,fill]. 207

DMAMATRIX.RECT x, y, w, h, color [,fill]. 207

DMAMATRIX.X. 207

DMAMATRIX.Y. 208

DMAMATRIX.POSX. 208

DMAMATRIX.POSY. 208

DMAMATRIX.PLAYGIF gif$ [,x , y]. 208

DMAMATRIX.LOADGIF gif$ [,x , y]. 208

DMAMATRIX.FRAMEGIF [do_not_show [,loop]]. 208

SD CARD ADAPTER.. 208

TFT DISPLAY ILI9341. 210

TFT DISPLAY ILI9163. 214

TFT DISPLAY ILI9486. 215

TFT DISPLAY ILI9481. 218

TFT DISPLAY ILI9488. 219

TFT DISPLAY ST7735. 220

TFT DISPLAY ST7796. 221

TFT DISPLAY ST7789. 224

OLED DISPLAY SSD1351 RGB.. 225

TFT DISPLAY GC9A01. 226

TouchScreen. 226

TouchScreen - Resistive. 226

TouchScreen - Capacitive. 227

TFT FONTS.. 228

QR CODES.. 232

GRAPHIC GUI for TFT. 232

GUI Objects. 233

gui.TextLine. 233

gui.Button. 234

gui.Image. 234

gui.ButtonImage. 235

gui.CheckBox. 235

gui.Slider. 236

gui.ProgressBar. 236

gui.Ramp. 237

gui.Gauge. 237

gui.Box. 237

gui.Circle. 238

gui.Rect 238

gui.Line. 239

GUI.TEXTAREA(x, y, width, height, "text", [,font] [,alignment] [,color_text] [,color_back] [,color_frame] [,margin] ). 240

GUI.GETTEXT obj, var$. 241

GUI.VISIBLE obj, visible. 241

GUI Functions. 241

gui.GetValue. 241

gui.Target 241

GUI Commands. 241

gui.INIT.. 241

gui.REDRAW... 241

gui.REFRESH.. 241

gui.AUTOREFRESH.. 241

gui.SETVALUE.. 242

gui.SETTEXT.. 242

gui.SETIMAGE.. 242

gui.SETCOLOR.. 242

gui.SETRANGE.. 243

gui.SETEVENT.. 243

gui.SETSTYLE.. 243

LovyanGFX Graphics Library. 244

Key Features: 244

Implementation Notes. 245

Color Management 245

GFX Functions. 245

TFT.RGB(r, g, b). 245

TFT.COLOR colorName. 245

TFT.WIDTH. 246

TFT.SPRITE.WIDTH spriteNum. 247

TFT.HEIGHT. 247

TFT.SPRITE.HEIGHT spriteNum. 247

TFT.GETPIXEL x, y. 248

TFT.SPRITE.GETPIXEL spriteNum, x, y. 248

TFT.SIZE filename$. 248

TFT.FRAMEGIF [loop = 0]. 248

GFX Commands. 249

TFT.LOADFONT path$, font_num. 249

TFT.INIT [rot]. 249

TFT.SETFREQ freq [, read_freq]. 250

TFT.TEXT.POS x, y. 250

TFT.SPRITE.TEXT_POS spriteNum, x, y. 250

TFT.TEXT.COLOR col [, back]. 250

TFT.SPRITE.TEXT.COLOR spriteNum, col [, back]. 251

TFT.TEXT.SIZE size [, font]. 251

TFT.SPRITE.TEXT.SIZE spriteNum, size [, font]. 251

TFT.PRINT str$ [, x] [, y] [, fontnum]. 252

TFT.SPRITE.PRINT spriteNum, str$ [, x] [, y] [, fontnum]. 252

TFT.BMP filename$ [, x] [, y] [, scale]. 252

TFT.JPG filename$ [, x] [, y] [, scale]. 253

TFT.IMAGE filename$ [, x] [, y] [, zoom] [, x1] [, y1] [, w] [, h]. 253

TFT.SPRITE.IMAGE spriteNum, filename$ [,x] [,y] [,zoom] [,x1] [,y1] [,w] [,h]. 254

TFT.BRIGHTNESS brt. 254

TFT.TEXT.FONT fontnum. 254

TFT.SPRITE.TEXT.FONT spriteNum, fontnum. 255

TFT.TEXT.DRAW str$, x, y [, fontnum]. 255

TFT.SPRITE.TEXT.DRAW spriteNum, str$, x, y [, fontnum]. 255

TFT.TEXT.ALIGN datum. 256

TFT.SPRITE.TEXT.ALIGN spriteNum, datum. 256

TFT.TEXT.PADDING padding. 256

TFT.SPRITE.TEXT.PADDING spriteNum, padding. 256

TFT.QRCODE str$, x, y, w [, version]. 257

TFT.CREATESPRITE spriteNum, w, h. 257

TFT.DELETESPRITE spriteNum. 257

TFT.SPRITE.FROMBMP spriteNum, filename$. 258

TFT.SPRITE.FROMIMG spriteNum, filename$. 258

TFT.LINE x1, y1, x2, y2, col [, radius]. 258

TFT.SPRITE.LINE spriteNum, x1, y1, x2, y2, col [, radius]. 259

TFT.WEDGELINE x1, y1, x2, y2, col, radius1, radius2. 259

TFT.SPRITE.WEDGELINE spriteNum, x1, y1, x2, y2, col, radius1, radius2. 260

TFT.RECT x, y, w, h, col [, fill] [, radius]. 260

TFT.SPRITE.RECT spriteNum, x, y, w, h, col [, fill] [, radius]. 260

TFT.CIRCLE x, y, radius, col [, fill]. 261

TFT.SPRITE.CIRCLE spriteNum, x, y, radius, col [, fill]. 261

TFT.ELLIPSE x, y, radius1, radius2, col [, fill]. 262

TFT.SPRITE.ELLIPSE spriteNum, x, y, radius1, radius2, col [, fill]. 262

TFT.ARC x, y, radius1, radius2, angle1, angle2, col [, fill]. 262

TFT.SPRITE.ARC spriteNum, x, y, radius1, radius2, angle1, angle2, col [, fill]. 263

TFT.TRIANGLE x1, y1, x2, y2, x3, y3, col [, fill]. 263

TFT.SPRITE.TRIANGLE spriteNum, x1, y1, x2, y2, x3, y3, col [, fill]. 264

TFT.PIXEL x, y, col. 264

TFT.SPRITE.PIXEL spriteNum, x, y, col. 264

TFT.FILL col. 265

TFT.SPRITE.FILL spriteNum, col. 265

TFT.AAC. 265

TFT.SAVE filename$ [, spriteDest]. 266

TFT.PIVOT xf, yf. 266

TFT.SPRITE.PIVOT spriteNum, xf, yf. 266

TFT.SPRITE.COPY spriteNum, spriteDest, x, y, w, h, x1, y1 [,col] [,angle] [,zoom]. 267

TFT.PUSH spriteNum, xf, yf [, col] [, angle] [, zoom]. 267

TFT.SPRITE.PUSH spriteNum [, spriteDest] [, xf] [, yf] [, col] [, angle] [, zoom]. 267

TFT.SPRITE.PUSHAA spriteNum [, spriteDest] [, xf] [, yf] [, col] [, angle] [, zoom]. 268

TFT.LOADGIF path$ [, x] [, y]. 268

TFT.PLAYGIF path$ [, x] [, y]. 269

LVGL - Light and Versatile Graphics Library. 269

Core Concepts in Annex32 LVGL. 269

Base Object 269

Parts. 269

States. 269

Flags. 270

Object Relationships, Attributes, Styles, and Events Object 270

Hierarchy. 270

Attributes and Properties. 270

Styles. 270

Events in LVGL (Annex) 270

Colors in LVGL (Annex) 270

Opacity in LVGL (Annex) 271

Usage in Annex. 271

Widgets in LVGL (and Annex): The Building Blocks of User Interfaces. 271

Basic Display Elements: 271

Buttons and Input: 272

Selectors and Indicators: 272

Checkboxes and Radio Buttons: 272

Indicators and Visualizations: 273

Data Display: 273

Groups: 273

Getting Started with Annex. 273

Initializing LVGL and Understanding Memory Allocation. 273

LVGL.INIT: Configuring Memory and Display. 273

Memory Allocation Breakdown: 273

Important Notes on Memory Management. 274

Understanding col_fg and col_bg in LVGL.INIT. 274

Color Representation. 274

LVGL.SET_THEME : Setting the default Theme. 276

Understanding lv_style_selector_t 277

Functions and Commands in LVGL Implementation. 277

LVGL Functions. 278

LVGL.INIT col_fg, col_bg [, buff_size [, buff_count = 1]. 278

LVGL.SET_THEME col_primary, col_secondary, fontnum, dark [, theme_type = 0]. 279

LVGL.REFRESH. 279

LVGL.START [memory = 8192] [, priority = 0] [, core = 0]. 279

LVGL.STOP. 280

LVGL.RESET. 280

LVGL.CLEAN [obj]. 280

LVGL.DELETE obj. 280

LVGL.SCREEN. 281

LVGL.CURSOR. 281

LVGL.DEF_FATHER obj. 281

LVGL.ARC [x [, y [, w [, h]]]]. 281

LVGL.ARC_ROTATE_OBJ_TO_ANGLE arc_obj, obj_to_rotate, radius_offset. 282

LVGL.BASE [x [, y [, w [, h]]]]. 282

LVGL.BAR [x [, y [, w [, h]]]]. 282

LVGL.BUTTON text$ [, x [, y [, w [, h]]]]. 283

LVGL.BUTTONMATRIX but_map$ [, x [, y [, w [, h]]]]. 283

LVGL.CANVAS [x [, y [, w [, h [, col_bg]]]]]. 284

LVGL.CHECKBOX text$ [, x [, y [, w [, h]]]]. 284

LVGL.RADIO text$ [, x [, y [, w [, h]]]]. 284

LVGL.DROPDOWN options$ [, x [, y [, w [, h]]]]. 285

LVGL.GIF path$ [, x [, y [, w [, h]]]]. 285

LVGL.GIF_PLAY obj, play_control. 286

LVGL.IMAGE path$. 286

LVGL.IMAGEBUTTON img1 [, img2]. 286

LVGL.IMAGETOGGLE img1 [, img2]. 287

LVGL.KEYBOARD mode. 287

LVGL.KBD_SET_TEXTAREA kbd_obj, txt_obj. 287

LVGL.LABEL text$ [, x [, y [, w [, h]]]]. 288

LVGL.LED [color [, x [, y [, w [, h]]]]]. 288

LVGL.LIST [x [, y [, w [, h]]]]. 288

LVGL.ADD_BUTTON list_obj, icon, text$. 289

LVGL.ADD_TEXT list_obj, text$. 289

LVGL.MSGBOX title$, msg$. 289

LVGL.MSGBOX_CLOSE msgbox_obj. 290

LVGL.ROLLER options$ [, x [, y [, w [, h]]]]. 290

LVGL.SCALE [x [, y [, w [, h]]]]. 290

LVGL.SET_ANGLE_RANGE obj, val. 291

LVGL.SET_TICKS obj, total, interval. 291

LVGL.SET_LABEL_SHOW obj, val. 291

LVGL.LINE. 292

LVGL.SET_LINE_NEEDLE_VALUE scale_obj, line_obj, length, val. 292

LVGL.SET_IMAGE_NEEDLE_VALUE scale_obj, image_obj, val. 292

LVGL.SLIDER [x [, y [, w [, h]]]]. 292

LVGL.SPINNER anim, angle [, x [, y [, w [, h]]]]. 293

LVGL.SWITCH [x [, y [, w [, h]]]]. 293

LVGL.TABVIEW [x [, y [, w [, h]]]]. 293

LVGL.ADD_TAB tab_view_obj, tab_name$. 294

LVGL.SET_TAB_BAR_POS tab_view_obj, tab_pos. 294

LVGL.SET_ACTIVE obj, idx, [anim]. 294

LVGL.TEXTAREA text$ [, x [, y [, w [, h]]]]. 295

LVGL.ADD_EVENT obj, event, gotoline. 295

LVGL.REMOVE_EVENT obj, event. 295

LVGL.ADD_FLAG obj, flag. 296

LVGL.REMOVE_FLAG obj, flag. 296

LVGL.UPDATE_FLAG obj, val, [flag = 1]. 296

LVGL.GET_FLAG obj. 297

LVGL.ADD_STATE obj, state. 297

LVGL.REMOVE_STATE obj, state. 297

LVGL.SET_STATE obj, val, [state = 1]. 298

LVGL.GET_STATE obj. 298

LVGL.ALIGN_TO obj, obj_base, align [, x [, y]]. 298

LVGL.GET_CHILD obj, idx. 299

LVGL.GET_CHILD_COUNT obj. 299

LVGL.GET_PARENT obj. 299

LVGL.SET_PARENT obj, obj_parent. 300

LVGL.GET_CLASS_ID obj. 300

LVGL.GROUP. 300

LVGL.GROUP_ADD group, obj. 300

LVGL.GROUP_REMOVE obj. 301

LVGL.GROUP_DELETE group. 301

LVGL.GET_GROUP obj. 301

LVGL.GET_TARGET. 301

LVGL.GET_GESTURE. 302

LVGL.GET_VALUE obj. 302

LVGL.LOAD_FONT path$, fontnum. 302

LVGL.SET_FONT obj, fontnum [,style_selector]. 303

LVGL.SET_BG_ANGLES obj, start, end. 303

LVGL.SET_BG_COLOR obj, col_bg [, style_selector]. 304

LVGL.SET_BG_OPA obj, val [, style_selector]. 304

LVGL.SET_BORDER_COLOR obj, color [, style_selector]. 304

LVGL.SET_BORDER_SIDE obj, side [, style_selector]. 305

LVGL.SET_BORDER_WIDTH obj, width [, style_selector]. 305

LVGL.SET_CLIP_CORNER obj, val [, style_selector]. 305

LVGL.SET_ARC_COLOR obj, color [, style_selector]. 306

LVGL.SET_ARC_OPA obj, val [, style_selector]. 306

LVGL.SET_LINE_COLOR obj, color [, style_selector]. 306

LVGL.SET_LINE_OPA obj, val [, style_selector]. 307

LVGL.SET_FLEX_ALIGN obj, main, cross, track_cross. 307

LVGL.SET_FLEX_FLOW obj, flex_flow. 307

LVGL.SET_HEIGHT obj, h. 307

LVGL.SET_IMAGE_RECOLOR obj, color [, style_selector]. 308

LVGL.SET_IMAGE_RECOLOR_OPA obj, val [, style_selector]. 308

LVGL.SET_LAYER obj, layer. 308

LVGL.SET_LENGTH obj, val [, style_selector]. 309

LVGL.SET_LINE_ROUNDED obj, val [, style_selector]. 309

LVGL.SET_LINE_WIDTH obj, val [, style_selector]. 309

LVGL.SET_MARGIN obj, top, [,bottom [,left [,right [,vert [,horiz [, style_selector]]]]]]. 310

LVGL.SET_MODE obj, val. 310

LVGL.SET_PAD obj, top, [,bottom [,left [,right [,vert [,horiz [,row [,column [, style_selector]]]]]]]]. 311

LVGL.SET_PAD_GAP obj, val [, style_selector]. 311

LVGL.SET_POS obj, x, y. 312

LVGL.SET_RANGE obj, start, end. 312

LVGL.SET_RADIUS obj, val [, style_selector]. 312

LVGL.SET_ROTATION obj, angle. 313

LVGL.SET_SCROLL_DIR obj, scroll_dir. 313

LVGL.SET_SIZE obj, w, h. 313

LVGL.SET_SIZE_PCT obj, w_pct, h_pct. 313

LVGL.SET_TEXT obj, str$. 314

LVGL.SET_TEXT_ALIGN obj, align. 314

LVGL.SET_TEXT_COLOR obj, color [, style_selector]. 314

LVGL.SET_TRANSFORM_PIVOT obj, x, y [, style_selector]. 315

LVGL.SET_TRANSFORM_PIVOT_PCT obj, x_pct, y_pct [, style_selector]. 315

LVGL.SET_IMAGE_PIVOT obj, x, y. 315

LVGL.SET_IMAGE_PIVOT_PCT obj, x_pct, y_pct [. 316

LVGL.SET_TRANSFORM_ROTATION obj, angle [, style_selector]. 316

LVGL.SET_TRANSFORM_SCALE obj, x, y [, style_selector]. 316

LVGL.SET_VALUE obj, val [, anim = 1]. 317

LVGL.SET_WIDTH obj, w. 317

LVGL.SPRITE.PUSH canvas_obj, sprite_num [, x [, y]]. 318


LVGL.SWAP obj, obj_base. 318

LVGL.VISIBLE obj, vis. 318

LVGL.RGB(red, green, blue). 318

LVGL.MOUSE_ENABLE. 319

LVGL.MOUSEMOVE mouse_x, mouse_y, mouse_z. 319

LVGL.MOUSE_CURSOR. 319

LVGL.KEYBOARD_ENABLE. 320

LVGL.SET_KEYBOARD_KEY key. 320

LVGL.SET_KEYBOARD_GROUP group. 320

LVGL.SET_IMAGE_SRC obj, src$. 320

LVGL.GET_IMAGE_SRC obj. 321

LVGL.GET_CLASS_NAME$ obj. 321

LVGL.GET_TEXT$ obj. 321

LVGL Tables. 322

Widget States (lv_state_t) 323

Widget Parts (lv_part_t) 324

Object Flags (lv_obj_flag_t) 324

Image Button States (lv_imagebutton_state_t) 326

LVGL Alignment Enums (lv_align_t) 327

LVGL Text Alignment Enums (lv_text_align_t) 328

LVGL Direction Enums (lv_dir_t) 328

LVGL Border Side Enums (lv_border_side_t) 329

Flexbox Layout Options and Enumerations. 329

Flexbox Layout Options. 329

Flex Alignment Options (lv_flex_align_t) 330

Flex Flow Options (lv_flex_flow_t) 330


............................................................................................................................................................................................... 331

Scale modes (lv_scale_mode_t) 331


........................................................................................................................................................................................... 331

Label Long Mode Options (lv_label_long_mode_t) 331


............................................................................................................................................................................................... 332

Keyboard Mode Enums (lv_keyboard_mode_t) 332


............................................................................................................................................................................................... 332

Keyboard Key Enums (lv_key_t) 332


............................................................................................................................................................................................... 333

Event Codes (lv_event_code_t) 333

Symbol Definitions (unicode from FontAwesome) 336

USB HID INTERFACE (Mouse, Keyboard, Gamepad) - ESP32-S3 only. 339

How use the USB devices. 341

USB.SETUP Command. 341

Mouse Input 341

Keyboard Input 341

Associated Events. 342

1.    onMouseMove : Triggered when the mouse moves. 342

2.    onMouseClick: Triggered when a mouse button is clicked. 342

3.    onKeyboard: Triggered when a key is pressed on the keyboard. 342

4.    onGamePad: Triggered when there is a change in the gamepad state. 342

Handling Events. 342

USB HID Mouse / Keyboard Emulation - ESP32-S3 only. 342

Introduction. 342

Commands. 343

USB.START [keymap$]. 343

USB.TYPETEXT text$. 343

USB.KEYPRESS keycode. 343

USB.KEYRELEASE keycode. 343

USB.KEYRELEASEALL. 344

USB.MOUSEMOVE width, height, [wheel [, pan]]. 344

USB.MOUSECLICK button. 344

USB.MOUSEPRESS button. 344

USB.MOUSERELEASE button. 344

Mouse Button Definitions. 345

Keycode Definitions. 346

Keymaps for regional keyboards. 347

INFRARED INTERFACE.. 348

ULTRASONIC DISTANCE SENSOR HC-SR04. 352

DHT xx Temperature / Humidity Sensors. 353

DS18B20 Temperature Sensors. 355

TEMPR$(pin_number, [ID], [resolution]). 356

BNO055 Absolute Orientation Sensor 357

BME280 Combined humidity and pressure sensor 359

BME680 Combined gas, pressure, temperature & humidity sensor 361

FUNCTIONS / COMMANDS.. 363

BME680.BEGIN(address). 364

BME680.SETUP(rate, filename). 364

BME680.SAVE_STATE(filename). 364

BME680.LOAD_STATE(filename). 364

BME680.SET_OFFSET(offset). 364

BME680.RUN. 364

BME680.TEMP. 364

BME680.RAW_TEMP. 364

BME680.HUM. 364

BME680.RAW_HUM. 364

BME680.PRESS. 364

BME680.IAQ. 365

BME680.STATIC_IAQ. 365

BME680.IAQ_ACCURACY. 365

BME680.CO2. 365

BME680.BREATH_VOC. 365

BME680.GAS. 365

BME680.GAS_RES. 365

BME680.BME_STATUS. 365

BME680.BSEC_STATUS. 365

BME680.STAB_STATUS. 365

BME680.RUN_STATUS. 365

HDC1080 High Accuracy Digital Humidity Sensor with Temperature Sensor 366

CCS811 Air Quality Sensor 367

APDS9960 Digital Proximity, Ambient Light, RGB and Gesture Sensor 370

RFID MFRC522 RFID cards reader 373

Writing NUID for UID changeable card (4 byte UID version) 377

VL53L0X TOF (Time Of Flight) Distance Sensor 377

VL53L0X.INIT function. 378

VL53L0X.SETRANGE range. 378

VL53L0X.SETACCURACY accuracy. 378

VL53L0X.DISTANCE. 378

VL53L0X.DISTANCE_N. 378

VL53L0X.CUSTOM signal_rate_limit, VcselPeriodPreRange, VcselPeriodFinalRange, MeasurementTimingBudget. 379

HX711 - Weight Measurement Module. 379

SI5351 Clock Generator Module. 381

SI5351.INIT [capacitor [,crystal]]. 383

SI5351.CALIB correction. 383

SI5351.SETFREQ out_nb, frequency. 383

SI5351.SETFREQ_MAN out_nb, frequency, pll. 383

SI5351.STRENGTH out_nb, strength. 383

SI5351.PHASE out_nb, phase. 383

SI5351.RESET_PLL pll_nb. 383

SI5351.ENABLE out_nb, enable. 383

SI5351.INVERT out_nb, invert. 383

SI5351.LOAD filename$. 384

STEP MOTOR.. 384

STEPPER.SETUP stepper_id, pin_step, pin_dir. 386

STEPPER.SETPARAM stepper_id, speed, acceleration. 386

STEPPER.SETPOSITION stepper_id, position. 386

STEPPER.MOVE stepper_id, position. 386

STEPPER.MOVETO stepper_id, position. 386

STEPPER.STOP stepper_id. 386

STEPPER.FORCESTOP stepper_id. 386

STEPPER.RUNFWD stepper_id. 386

STEPPER.RUNBKD stepper_id. 386

STEPPER.GETPOSITION(stepper_id). 387

STEPPER.GETTARGET(stepper_id). 387

MPU9250. 387

MPU6500  / MPU6050. 389

MPU6886 (For M5 Atom) 391

IMU FUSION FUNCTIONS.. 393

ETHERNET Module W5500. 395

FTP.. 399

BAS.FTP$. 399

Server data requests  (GET, POST and PUT) 400

-      WGET$(server$, port, [,rx_header] [,header$]). 401

-      WGET$(url$ [,rx_header] [,header$]). 401

-      WPOST$(server$, body$, port [,rx_header] [,header$] ). 401

-      WPOST$(url$, body$ [,rx_header] [,header$]). 401

-      WPUT$(server$, body$, port [,rx_header] [,header$] ). 401

-      WPUT$(url$, body$ [,rx_header] [,header$]). 401

-      WGETASYNC[(] server$, port, [,rx_header] [)]. 401

-      WGETASYNC[(] url$,[,rx_header] [)]. 401

MQTT Client 403

MQTT.Setup(server$ [,debug]). 405

MQTT.Certif(cert_pem$ [,client_cert_pem$] [,client_key_pem$]). 405

MQTT.PSK(psk_hint_key$). 405

MQTT.LWT(topic$, message$ [,Qos] [,retain]). 405

MQTT.Connect(login$, pass$ [,id$]). 405

MQTT.Connect("", "" [,id$]). 405

MQTT.Disconnect[()]. 405

MQTT.Publish(topic$, message$ [,Qos] [,retain]). 405

MQTT.Subscribe(topic$ [,Qos]). 405

MQTT.UnSubscribe(topic$). 405

MQTT.Connected[()]. 405

MQTT.Status[()]. 406

MQTT Broker 408

MqttBroker.Setup(port, login$, password$ [, debug]). 409

MqttBroker.Start(ramsize). 409

MqttBroker.Stop. 410

MqttBroker.Restart. 410

MqttBroker.Publish(topic, payload[, qos[, retain]]). 410

MqttBroker.Subscribe(topic$). 410

MqttBroker.UnSubscribe(topic$). 411

MqttBroker.ListTopics[(list$)]. 411

MqttBroker.ClearTopics. 412

MqttBroker.ListClients[(list$)]. 412

OnMQTT Event Handler 412

OnMQTT label. 412

Event Information Variables. 413

Special Event Topics. 413

Disabling ONMQTT. 413

ESP-NOW... 416

EspNow.Begin. 417

EspNow.Stop. 417

EspNow.Add_Peer(MAC_add$ [,interface] [,channel]). 417

EspNow.Del_Peer. 417

EspNow.Write(msg$). 417

EspNow.Write(msg$, MAC_add$). 417

EspNow.READ$. 417

ESPNow.REMOTE$. 417

ESPNow.ERROR$. 417

OnEspNowMsg label. 418

OnEspNowError label. 418

BLUETOOTH Low Energy (BLE) 426

Overview.. 426

Operating Modes. 426

Server Mode. 427

Communication Details. 427

BLE Commands / Functions. 427

BLUETOOTH.SETUP "devicename" [, code]. 427

BLUETOOTH.CLEAR. 428

BLUETOOTH.DELETE. 428

BLUETOOTH.POWER pow. 428

BLUETOOTH.WRITE "text". 428

BLUETOOTH.READ$. 428

BLUETOOTH.LEN. 428

BLUETOOTH.CONNECTED. 428

BLUETOOTH.STATUS. 428

BLUETOOTH.WRITE_IOBUFF(buff_num [, start [, size]]). 428

BLUETOOTH.READ_IOBUFF(buff_num). 428

BLUETOOTH.SCAN time. 428

BLUETOOTH.SCANRESULT$. 428

Client Mode Functions. 429

BLUETOOTH.CLIENT mac, service_UUID, characteristic_UUID. 429

BLUETOOTH.CLWRITE characteristic_UUID, "text". 429

BLUETOOTH.CLWRITE_IOBUFF characteristic_UUID, (buff_num [, start [, size]]). 429

Event Handling. 429

ONBLUETOOTH label. 429

TELEGRAM (messenger) support 433

LORA.. 435

LoRa.Setup ss, reset, dio0. 438

LoRa.Begin(freq). 438

LoRa.End. 438

LoRa.BeginPacket. 438

LoRa.Print. 438

LoRa.EndPacket. 438

LoRa.Receive. 438

LoRa.RSSI. 438

LoRa.SNR. 438

LoRa.Idle. 438

LoRa.Sleep. 438

LoRa.TXpower pow. 438

LoRa.SyncWord word. 439

LoRa.EnableCRC enable. 439

OnLora. 439

LoRa.Message$. 439

Modbus. 441

MODBUS.CONNECT IP$, [port] [,timeout] [,idleTimeout]. 441

MODBUS.DISCONNECT. 442

MODBUS.REQUEST token, serverID, functionCode [,p1] [,p2] [,p3]. 442

Modbus RTU Support 445

MODBUS.SetupRTU RX_pin, TX_pin, RE_DE_pin, ["BBBB,P,D,S"]. 445

MODBUS.requestRTU ….. (see the details in the chapter above) 445

MODBUS RTU wiring. 447

Regular Expressions (RegEx) 448

Patterns. 449

Magic characters. 449

Repetition. 450

Anchor to start and/or end of string. 451

Captures. 451

Frontier patterns. 452

Multiple matches. 452

M5 Tough. 453

M5Tough.BatLevel. 455

M5Tough.BatVoltage. 455

M5Tough.BatCurrent. 455

M5Tough.VinVoltage. 455

M5Tough.VinCurrent. 455

M5Tough.VBusVoltage. 455

M5Tough.VBusCurrent. 455

M5Tough.BatChgCurrent. 455

M5Tough.BatPower. 455

M5Tough.AxpTemp. 455

M5Tough.ApsVoltage. 455

M5Tough.AxpState. 455

M5Tough.TftPower power. 455

M5Tough.SpeakerPower power. 455

M5Tough.SetBusPowerMode mode. 456

M5Tough.PowerOff sec. 456

M5Tough.LightSleep sec. 456

M5Tough.DeepSleep sec. 456

ANNEXCAM.. 456

Functionalities enabled in the ANNEXCAM version. 459

Camera Functions / commands. 460

Using AnnexCam in output page. 463

Control of the camera using URL. 464

Face Recognition. 465

Image / video reception from Annex. 466

ANNEXEPAPER for LILYGO T5 4.7” E-paper module. 468

image......................................................................................................................................... 469

GRAPHIC GUI for E-PAPER.. 471

Functionalities enabled in the E-PAPER version. 478

PEEK and POKE FUNCTIONS.. 480

BAS.PEEK(addr). 480

BAS.PEEK16(addr). 480

BAS.PEEK8(addr). 480

BAS.POKE addr, data. 480

BAS.POKE16 addr, data. 480

BAS.POKE8 addr, data. 480

CONVERSION FUNCTIONS.. 481

CONVERT.DEGC_TO_F(degC). 482

CONVERT.F_TO_DEGC(degF). 482

CONVERT.TO_IEEE754(num). 482

CONVERT.FROM_IEEE754(iee754_bin). 482

CONVERT.MAP(number, fromLow, fromHigh, toLow, toHigh). 482

CONVERT.TO_BCD(number). 482

CONVERT.FROM_BCD(number). 482

CONVERT.LIMITS(number, min, max). 482

BAS CONSTANTS.. 482

BAS.VER. 483

BAS.VER$. 483

BAS.ERRLINE. 483

BAS.ERRNUM. 483

BAS.ERRMSG$. 483

BAS.FILENAME$. 483

BAS.RTCMEM$. 483

BAS.SSID$. 483

BAS.PASSWORD$. 483

BAS.LOAD. 483

BAS.RESETREASON. 484

BAS.WAKEUPREASON. 485

BAS.DEVICE. 486

BAS.TFT. 487

OPTION COMMANDS.. 487

OPTION.BASE 0 | 1. 488

OPTION.CPUFREQ 80|160|240. 488

OPTION.ES8388. 488

OPTION.MAC mac$. 488

OPTION.LOWRAM value. 488

OPTION.NTPSYNC. 488

OPTION.WDT time. 488

OPTION.WDTRESET. 488

OPTION.WLOG value. 488

OPTION.TOUCH value. 489

OPTION.I2S BCLK_pin, WSEL_pin, DOUT_pin. 489

OPTION.PSRAM limit. 489

HALL Sensor (Internal): 489

BAS.HALL. 489

FUNCTIONS: 489

NUMERICAL FUNCTIONS.. 489

ABS(number) 490

ACOS(number) 490

ADC(pin) 490

APDS9960.SETUP (mode) 490

APDS9960.READGESTURE.. 490

APDS9960.AMBIENT. 490

APDS9960.RED.. 490

APDS9960.GREEN.. 490

APDS9960.BLUE.. 491

APDS9960.PROXIMITY.. 491

APDS9960.GESTUREGAIN (gain) 491

APDS9960.GESTURELED (intensity) 491

ASC(string$) 491

ASIN(number) 491

ATAN(number) 491

ATAN2(x, y) 491

BAS.VER.. 491

BAS.ERRLINE.. 492

BAS.ERRNUM.. 492

BME280.SETUP(address) 492

BME280.ALT(qnh) 492

BME280.HUM.. 492

BME280.QFE.. 492

BME280.QNH(altitude) 492

BME280.TEMP.. 492

BNO055.SETUP( address) 492

BNO055.HEADING.. 492

BNO055.PITCH.. 492

BNO055.ROLL. 492

BNO055.VECTOR ( param, axis) 493

BNO055.CALIB [(param)] 493

CINT(number) 494

CONVERT.DEGC_TO_F(degC) 494

CONVERT.F_TO_DEGC(degF) 494

CONVERT.TO_IEEE754(num) 494

CONVERT.FROM_IEEE754(ieee754_bin) 494

CONVERT.MAP(number, fromLow, fromHigh, toLow, toHigh) 494

CONVERT.TO_BCD(number) 494

CONVERT.FROM_BCD(number) 494

COS(number) 494

COUNTER.COUNT (cnt) 494

COUNTER.PERIOD (cnt) 494

DATEUNIX(date$) 494

DHT.TEMP.. 495

DHT.HUM.. 495

DHT.HEATINDEX.. 495

DISTANCE(pin_trig, pin_echo) 495

EMAIL from$, to$, subject$, message$. 495

ESPNOW.ADD_PEER(MAC_add$ [,interface] [,channel]) 495

ESPNOW.BEGIN.. 495

ESPNOW.DEL_PEER(MAC_add$) 495

ESPNOW.STOP.. 495

ESPNOW.WRITE( msg$) 495

ESPNOW.WRITE( msg$,MAC_add$) 495

EXP(number) 495

FIX(number) 496

FILE.DELETE(filename$) 496

FILE.EXISTS(filename$) 496

FILE.SIZE(filename$) 496

FLASHFREE.. 496

FUSION.ANGLE(axis) 496

INSTR([start], string$, pattern$) 496

I2C.LEN.. 496

I2C.READ.. 496

I2C.READREGBYTE (i2c_address, register) 497

I2C.END.. 497

INT(number) 497

LEN(string$) 497

LOG(number) 497

MILLIS.. 497

MQTT.Setup(server$ [,debug]) 497

MQTT.Certif(cert_pem$ [,client_cert_pem$] [,client_key_pem$]) 498

MQTT.PSK(psk_hint_key$) 498

MQTT.LWT(topic$, message$ [,Qos, [,retain]) 498

MQTT.Connect(login$, pass$ [,id$]) 498

MQTT.Connect("", "" [,id$]) 498

MQTT.Disconnect[()] 498

MQTT.Publish(topic$, message$ [,Qos] [,retain]) 498

MQTT.Subscribe(topic$ [,Qos]) 498

MQTT.UnSubscribe(topic$) 498

MQTT.Connected[()] 498

MQTT.Status[()] 498

NEO.GETPIXEL(pos) 499

NEO.RGB(R, G, B) 499

PI 499

PID1.COMPUTE( current_value, target_value) 499

PIN(pin_number) 499

PIN.TOUCH(pin_number) 499

PING(host$) 499

POW(x, y) 499

RAMFREE.. 499

RFID.SETUP(CS_pin, RST_pin) 500

RFID.SETGAIN(gain) 500

RFID.SETKEY(key$) 500

RFID.RESET. 500

RFID.AWAKE.. 500

RFID.SETNUID(NUID$) 500

RFID.WRITE(block, data$) 501

RND(number) 501

SERIAL.LEN.. 501

SERIAL2.LEN.. 501

SGN(number) 501

SIN(number) 501

SPI.BYTE(byte) 501

SQR(number) 501

TAN(number) 501

TFT.RGB(r,g,b) 501

TIMEUNIX(time$) 502

TM1638.BUTTONS.. 502

TOUCH.X.. 502

TOUCH.Y.. 502

VAL(string$) 502

WIFI.CHANNEL. 502

WIFI.MODE.. 502

WIFI.NETWORKS  ( network$ ) 503

WIFI.RSSI 503

WIFI.STATUS.. 503

WORD.COUNT( string$ [,delimiter$]) 503

WORD.FIND( string$, find$ [,delimiter$]) 504

STRING FUNCTIONS.. 505

BAS.ERRMSG$. 506

BAS.FILENAME$. 506

BAS.FTP$( host$, login$, password$, file$, folder$) 506

BAS.PASSWORD$. 506

BAS.RTCMEM$. 506

BAS.SSID$. 506

BAS.VER$. 506

BIN$(number) 506

BUTTON$(name$, label [, id] ) 506

CHECKBOX$( variable [,id]) 506

CHR$(number) 507

CSSID$(object_id, object_style) 507

DATE$[(format)] 507

ESPNOW.ERROR$. 507

ESPNOW.READ$. 507

ESPNOW.REMOTE$. 507

FILE.DIR$[(path$)] 507

FILE.READ$(filename$,[line_num] | [start, length]) 507

HEX$(number) 507

HtmlEventButton$. 507

HtmlEventVar$. 508

IMAGE$(path [,id]) 508

IMAGEBUTTON$(path, label [,id]) 508

IP$. 508

IR.GET$[ (param) ] 508

JSON$(string$, field$) 508

LCASE$(string$) 508

LED$(variable [,id]) 509

LEFT$(string$, num) 509

LISTBOX$(variable$, "option1, option2, option3, ..." [, height]  [,id]) 509

MAC$[ (id) ] 509

METER$(variable, min, max [,id]) 509

MID$(string$, start [,num]) 509

MQTT.Message$. 510

MQTT.Topic$. 510

OCT$(number) 510

PASSWORD$(variable [, id] ) 510

REPLACE$(expression$, find$, replacewith$) 510

RFID.NUID$. 510

RFID.TYPE$. 511

RFID.READ$(block [,key_b]) 511

RIGHT$(string$, num) 511

RTC.DATE$[(format)] 511

RTC.TIME$. 512

SERIAL.CHR$. 512

SERIAL.INPUT$. 512

SERIAL2.CHR$. 512

SERIAL2.INPUT$. 512

SLIDER$(variable, min, max [,step] [,id]) 512

SPACE$(number) 512

SPI.STRING$(data$, len) 512

SPI.HEX$(datahex$, len) 512

STR$ (number [,format$ [,toint]]) 513

STRING$(num, char$) 515

TEMPR$(pin_number [,ID]) 515

TEXTAREA$(variable [, id] ) 516

TEXTBOX$(variable [, id] ) 516

TRIM$(string$) 516

TIME$. 516

UCASE$(string$) 516

UDP.READ$. 516

UDP.REMOTE$. 516

UNIXDATE$(value [,format]) 516

UNIXTIME$(value) 516

URLMSGGET$ ([arg$]) 517

WGET$( http_server$, port [,header] ) 517

WGET$( url$, [,header] ) 517

WGETRESULT$. 517

WORD$(string$, position [,delimiter$]) 517

WORD.DELETE$(string$, position [delimiter$]) 517

WORD.EXTRACT$(string$, lead$, trail$) 518

WORD.GETPARAM$( setting$, parameter$  [,separator$]) 518

WPOST$(server$, body$, port [,header]) 518

WPOST$(url$, body$,  [,header]) 518

COMMANDS: 518

AUTOREFRESH interval 519

BAS.LOAD filename$. 519

BAS.RTCMEM$ = val$. 519

CLS.. 519

CSS style_code$. 519

COMMAND cmd$. 519

COUNTER.RESET cnt 519

COUNTER.SETUP cnt, pin [,mode] 519

CSSEXTERNAL file$. 520

DATA const1 [,const2] ... 520

DHT.SETUP pin, model 521

EMAIL.SETUP server$, port, user_name$, password$ [, debug] 521

EMAILASYNC from$, to$, subject$, message$. 521

FILE.FROMBASE64 source$, dest$. 521

FILE.SAVE filename$, content$. 521

FILE.TOBASE64 source$, dest$. 521

FUSION.INIT. 521

FUSION.MADGWICK ax, ay, az, gx, gy, gz. 522

FUSION.MADGWICK ax, ay, az, gx, gy, gz, mx, my, mz. 522

FUSION.MAHONY ax, ay, az, gx, gy, gz, mx, my, mz. 523

FUSION.BETA =. 523

FUSION.ZETA =. 523

FUSION.KI =. 523

FUSION.KP =. 523

HTML code$. 523

I2C.SETUP sda_pin, scl_pin [,freq ] 523

I2C.BEGIN address. 523

I2C.END.. 524

I2C.REQFROM address, length. 524

I2C.READREGARRAY i2c_address, register, nb_of_bytes, Array() 524

I2C.WRITE value. 524

I2C.WRITEREGBYTE i2c_address,register, value. 525

I2C.WRITEREGARRAY i2c_address, register, nb_of_bytes, Array() 525

INCR var [, increment] 525

INPUT.TIMEOUT timeout 525

INPUT["prompt$";] variable. 525

INTERRUPT pin_no, {OFF | label} [, mode] 526

IR.INIT pin_rx | OFF [, pin_tx] 526

IR.SEND type, code$, bits. 526

JSCALL javaCode$. 526

JSCRIPT script$. 526

JSEXTERNAL file$. 526

LCD.INIT address, cols, rows. 527

LCD.CLS.. 527

LCD.PRINT x, y, text$. 527

LOCAL var1 [,var2], ... 527

MAXDISPLAY.SETUP CS_pin. 527

MAXDISPLAY.PRINT msg$ [,‘brightness] 527

MAXSCROLL.SETUP nb_devices, CS_pin. 527

MAXSCROLL.PRINT msg$. 527

MAXSCROLL.NEXT msg$. 528

MAXSCROLL.TEXT msg$. 528

MAXSCROLL.SHOW pos [, brightness] 528

MAXSCROLL.SCROLL [brightness] 528

MAXSCROLL.OSCILLATE [brightness] 528

NEO.PIXEL led_pos, R, G, B [, disable] 528

NEO.PIXEL led_pos, COLOR [, disable] 528

NEO.SETUP pin [,nb_led] 528

NEO.STRIP led_start_pos, led_end_pos, R, G, B [, disable] 528

NEO.STRIP led_start_pos, led_end_pos, COLOR [, disable] 529

NEOSCROLL.SETUP nb_devices, pin [,serpentine] 529

NEOSCROLL.PRINT msg$. 529

NEOSCROLL.NEXT msg$. 529

NEOSCROLL.COLORS col$. 529

NEOSCROLL. NEXTCOLORS col$. 529

NEOSCROLL.SHOW pos [, brightness] 529

NEOSCROLL.TEXT msg$. 529

NEOSCROLL.SCROLL [‘brightness] 529

NEOSCROLL.OSCILLATE [‘brightness] 529

OLED.CLS.. 530

OLED.INIT orientation [,model] 530

OLED.REFRESH fmt 530

OLED.COLOR color 530

OLED.PIXEL x, y. 530

OLED.LINE x1, y1, x2, y2. 530

OLED.RECT x,y, width, height [,fill] 530

OLED.CIRCLE x, y, radius [, fill] 530

OLED.FONT font_num.. 531

OLED.PRINT x, y, text$ [background] 531

OLED.IMAGE x, y, image$. 531

OLED.BMP x, y, image$. 531

ONERROR ABORT or ONERROR IGNORE or ONERROR SKIP [nn] or ONERROR CLEAR or ONERROR GOTO label 531

ONESPNOWERROR [label | OFF] 531

ONESPNOWMSG [label | OFF] 531

ONGESTURE [label | OFF] 531

ONHTMLCHANGE [label | OFF] 532

ONHTMLRELOAD [label | OFF] 532

ONINFRARED label 532

ONMQTT label 532

ONRFID label 532

ONSERIAL [label | OFF] 532

ONSERIAL2 [label | OFF] 532

ONTOUCH [label | OFF] 532

ONUDP [label | OFF] 532

ONURLMESSAGE [label | OFF] 532

ONWGETASYNC [label | OFF] 532

OPTION.CPUFREQ 80|160|240. 532

OPTION.LOWRAM value. 533

PAUSE delay. 533

PCA9685.SETUP addr 533

PCA9685.SETFREQ freq. 533

PCA9685.PWM pin, value. 533

PID1.INIT Kp, Ki, Kd. 533

PID1.LIMITS min, max. 533

PID1.PERIOD msec. 533

PID1.PARAMS Kp, Ki, Kd. 533

PID1.SETMODE mode. 533

PIN(pin_number) = val 533

PIN.DAC pin_number, value. 534

PIN.MODE pin_number, mode [,PULLUP | PULLDOWN ] 534

PLAY.MP3 mp3$. 534

PLAY.STREAM stream$ [,buffer] 534

PLAY.SETUP dest [,buffer] [,mono] 534

PLAY.SPEAK message$ [, phonetic] 535

PLAY.STOP.. 535

PLAY.VOICE "message", "language" [, "filename"] [, action] 535

PLAY.VOLUME volume. 535

PLAY.WAV.. 535

PRINT expression[[,; ]expression] ... 535

PRINT2 expression [[,; ]expression] ... 535

PWM.SETUP pin, chan, default,  [,freq] [,resol] 536

PWM.SETUP pin, OFF. 536

PWM.OUT chan, value. 536

READ var1 [,var2] ... 536

REBOOT. 536

REFRESH.. 536

RESTORE [label] 536

RTC.SETTIME Year, Month, Day, Hours, Minutes, Seconds. 536

SERIAL.BYTE ch1 [,ch2] . . . 536

SERIAL2.BYTE ch1 [,ch2] . . . 537

SERIAL.MODE baudrate [, bits, parity, stop] 537

SERIAL2.MODE baudrate, pin_tx, pin rx  [, bits, parity, stop] [, TXbuffer, RXbuffer] 537

SETTIME Year, Month, Day, Hours, Minutes, Seconds. 537

SLEEP value [,pin, level] 537

SOCKET client, msg$. 537

SPI.CSPIN pin [, polarity] 537

SPI.SETUP speed [,data_mode [, bit_order]] 538

SPI.STOP.. 538

ST7920.INIT CS_pin. 538

ST7920.CLS.. 538

ST7920.REFRESH fmt 538

ST7920.COLOR color 538

ST7920.PIXEL x, y. 538

ST7920.LINE x1, y1, x2, y2. 538

ST7920.RECT x,y, width, height [,fill] 538

ST7920.CIRCLE x, y, radius [, fill] 538

ST7920.FONT font_num.. 539

ST7920.PRINT x, y, text$ [background] 539

ST7920.IMAGE x, y, image$. 539

ST7920.BMP x, y, image$. 539

TM1637.PRINT msg$ [, brightness ] 539

TM1637.SETUP data_pin, clock_pin [, bit_delay] [, display_type] 539

TM1638.PRINT msg$ [, brightness ]] 539

TM1638.SETUP data_pin, clock_pin, strobe_pin. 539

TM1638.LEDS val 539

TFT.BMP filename$, [x, y [, back_color] ] 540

TFT.BRIGHTNESS val 540

TFT.CIRCLE x, y, radius,color [, fill] 540

TFT.FILL color 540

TFT.IMAGE filename$, [x, y [, back_color] ] 540

TFT.INIT orientation. 541

TFT.JPG filename$, [x, y [, scale] ] 541

TFT.LINE x1, y1, x2, y2, col 541

TFT.PIXEL x, y, col 541

TFT.PRINT expression [[,; ]expression] ... 542

TFT.RECT x, y, width, height, color [ [,fill] ,[round_radius] ] 542

TFT.SETFREQ freq. 542

TFT.TEXT.COLOR color [,backcolor] 542

TFT.TEXT.POS x, y. 542

TFT.TEXT.SIZE size. 542

TIMER0 interval, label 542

TIMER1 interval, label 542

TOUCH.CALIB.. 543

UDP.BEGIN port 543

UDP.REPLY msg$ [,port] 543

UDP.STOP.. 543

UDP.WRITE ip, port, msg$. 543

URLMSGRETURN msg$ [,content_type$] 543

WAIT. 543

WGETASYNC server$, port [,header] 543

WGETASYNC url$, port [,header] 544

WIFI.APMODE SSID$, password$ [, channel] [, IP$ , MASK$] 544

WIFI.AWAKE.. 544

WIFI.CONNECT SSID$, password$ [, BSSID$] [, IP$ , MASK$ [, GATEWAY$]] 544

WIFI.POWER pow.. 544

WIFI.SCAN.. 544

WIFI.SLEEP.. 544

WLOG [text$ | num] 545

WORD.DELPARAM setting$, parameter$, [,separator$] 545

WORD.SETPARAM  setting$, parameter$, value$ [,separator$] 546

BASIC KEYWORDS.. 546

CASE.. 547

DIM array(size) [, …] 547

DO.. 547

ELSE.. 547

ELSEIF. 547

END [IF | SELECT | SUB] 547

ENDIF. 547

EXIT {DO | FOR | SUB} 547

FOR.. 547

GOSUB [label | lab$] 547

GOTO [label | lab$] 547

IF. 547

LET var = expression. 547

LOOP.. 547

NEXT. 547

OFF. 548

OUTPUT. 548

PULLUP.. 548

PULLDOWN.. 548

REM.. 548

RETURN.. 548

SELECT. 548

SPECIAL. 548

STEP.. 548

SUB.. 548

THEN.. 548

TO.. 548

UNTIL. 548

WEND.. 548

WHILE.. 548

 


 

Introduction:

Annex32 WI-Fi RDS (Rapid Development Suite) is a version of the "BASIC" language developed to run on low cost ESP-32 WIFI devices. Annex32 is specifically for the ESP32 range of devices, whose implemented features can vary greatly.

 

To offer some standardisation, Annex32 caters in particular to M5stack devices, which include a micro-SD card slot, TFT display, speaker, 3 user buttons plus a reset button, and a lipo battery, all self-contained in a plastic case offering expansion pin access and designed to accept ‘stackable’ expansion modules.

 

All drivers needed for the M5stack features are already included in the Annex32 firmware, and pre-configured for the M5stack so that features such as TFT display and SDcard work by default.

Similar functionality could be built using alternative TFT display and SD card reader etc, if preferred.

Please refer to the original M5Stack schematics for more details.

 

However, M5stack and its hardware features merely offer a convenient standardised feature set, they are not mandatory - Annex32 works with any ESP32 devices, with or without hardware expansion modules.

Obviously appropriate hardware is needed for any required features - eg: an OLED display could be used, but scripts written for TFT displays will need modifying for the different display.

 

Annex32 can use the internal flash disk space, or an external SD card.

The internal and the external (SDcard) space are mutually exclusive and cannot be accessed at the same time.

By default Annex32 will use the SD, if available, otherwise it will use the internal flash disk space (FATFS).

Both use the same type file system (FAT32), enabling the use of long file names and directories.

Depending on the module flash memory size (4, 8 or 16MB), the internal disk space can be from ~1MB to 13MB.

Using the ESP32 partition scheme it is possible to freely define this space, but modifying it will wipe out all existing files already stored.

 

Annex32 Wi-Fi RDS takes from the original concept of Annex WI-FI RDS for ESP8266 from which it shares essentially the IDE interface and the same command syntax as much as possible.

It should be straightforward switching to Annex32 if coming from Annex, and the same programs should run without (or with minimum) modifications (eg: pin numbers).

Annex32 Wi-Fi RDS benefits from the powerful H/W architecture of the ESP32 using both cores and the RAM memory available. In addition, for modules equipped with PSRAM memory extension, Annex32 can make available to the users this additional RAM space (up to 4MBytes).

 

Functionalities:

-       Includes an internal IDE so can be programmed directly using your web browser (even from your phone/tablet) without any additional utility.

-       Syntax highlighting with context-sensitive Help

-       A programmable web server which includes a file server

-       Supports OTA (over the air) update.

-       Support async events (interrupts, timers, web access, UDP, ….)

-       Breakpoints, immediate execution of commands, display of variables, single step.

-       A basic interpreter with floating point variables (double precision) and string variables, multi-dimensional arrays (float and string), user defined subroutines.

-       Access to any available I/O pin for input/output, PWM and Servo.

-       Errors Handling .

-       Support TCP (HTTP) GET and POST for communications

-       Support for UDP for communications.

-       Support for sending Emails using SMTP SSL servers

-       Support for AJAX communications (GET, POST, PUT) Synchronous and Asynchronous

-       Support for ESP-NOW communications

-       Support for MQTT communications

-       Support for MODBUS communications

-       Support for FTP communications

-       Support for Bluetooth Low Energy (BLE) communications

-       Support for Telegram communications

-       Support for RJ45 wired ethernet using W5500 module

-       Accompanying utility suite includes Flasher, File Manager, HTML Converter, Backup/Restore to bin or zip, integrated Serial Port Monitor, OTA (over the air) update server and UDP Console.

-       IMU / AHRS Fusion algorithms 6 DOF and 9 DOF (Madgwick and Mahony)

-       Play MP3 or WAV sound files or streaming using a speaker or an external I2S DAC

-       Text to Speech using a speaker or an external I2S DAC

-       Support for regular expressions (regex)

 

The following devices are supported directly with dedicated commands / functions :

-       DHT11, DHT21 or DHT22 Temperature / Humidity Sensors

-       DS18B20 Temperature sensor

-       LCD HD44780 with I2C interface module (1, 2 or 4 lines with 16 or 20 chars per line)

-       LCD Display based on chipset ST7920 with 128x64 pixels monochrome

-       OLED Display based on chipset SSD1306 or SH1106 with 128x64 pixels monochrome

-       TFT Display at 16 bits colors based on the following chipset:

-       ILI9341 with 320x240 pixels

-       ILI9163 with several resolutions

-       ST7735 with several resolutions

-       ST7796 with 480x320 pixels

-       ILI9481 with 480x320 pixels

-       ILI9486 with 480x320 pixels

-       ILI9488 with 480x320 pixels

-       ILI7789 with several resolutions

-       SSD1351 with 128x128 pixels

-       GC9A01 with 240x240 pixels

-       TM1637 4 and 6 digits 7-segments display

-       TM1638 8 digits 7-segments display including 8 leds and 8 buttons

-       MAX7219 8 digits 7-segments display

-       MAX7219 8x8 dot matrix display modules

-       Neopixel WS2812 led strips

-       Neopixel WS2812 8x8 dot matrix display

-       PCA9685 PWM/SERVO module

-       Infrared interface with many RC protocols (transmission and reception)

-       RTC module (DS1307 or DS3231)

-       HC-SR04 ultrasonic sensor for distance measurement

-       BNO055 Absolute Orientation Sensor

-       MPU9250 / MPU6500 IMU units

-       MPU6886 IMU unit

-       BME280 Combined humidity and pressure sensor

-       BME680 Combined gas, pressure, temperature & humidity sensor / Air Quality Sensor

-       HDC1080 High Accuracy Digital Humidity Sensor with Temperature Sensor

-       CCS811 Air Quality Sensor

-       APDS9960 Digital Proximity, Ambient Light, RGB and Gesture Sensor

-       W5500 RJ45 wired Ethernet interface

-       VL53L0X TOF (Time Of Flight) Distance Sensor

-       RFID MFRC522 cards reader

-       HX711 - Weight Measurement Module

-       SI5351 Clock Generator Module

-       Any compatible I2S DAC

-       Lora SX127x modules

-       STEP Motors

-       VGA output for ESP32–S3

-       RGB TFT output for ESP32-S3

 

Many ESP32 modules / units  are supported and can be configured using the “CONFIG” menu:

-       Almost all the ESP32 modules including ESP32 devkit, ESP32 wemos mini, ESP32 lolin lite, ...

-       M5Stack

-       M5 Atom

-       M5 Atom matrix

-       M5 Atom Echo

-       ESP32-CAM

-       M5CAMERA

-       ODROID GO

-       M5Tough

-       WIFI LORA 32

-       ESP32-2432S028 (module with a 240x320 2.8” TFT with resistive touchscreen)

-       ESP32-3248S035R (module with 320x480 3.5” TFT with resistive touchscreen)

-       ESP32-3248S035C (module with 320x480 3.5” TFT with capacitive touchscreen)

 

In addition to the ESP32, Annex now extends its support to other family members, including the ESP32-C3, ESP32-S2, and ESP32-S3. This support encompasses both direct USB connection and variants with USB to serial chip. For all of these modules, Annex offers compatibility across different versions, considering the specific type of flash memory installed, including DIO, QIO, and OPI, as well as the presence of PSRAM, with* options for QIO and OPI configurations. As a result of this diverse range of variants, Annex provides distinct firmware releases tailored to each particular configuration. This ensures optimal performance and seamless integration across the ESP32 series.

 

The following modules equipped with ESP32-S3 are also supported and can be configured using the “CONFIG” menu:

-       ESP32-4848S040 (module with a 480x480 4” RGB TFT with capacitive touchscreen)

-       ESP32-8048S070C  (module with a 800x480 7” RGB TFT with capacitive touchscreen)

-       ESP32-8048S043C  (module with a 800x480 4.3” RGB TFT with capacitive touchscreen)

-       Waveshare ESP32-S3-TOUCH-LCD-4.3 (module with a 800x480 4.3” RGB TFT with capacitive touchscreen)

-       Waveshare ESP32-S3-TOUCH-LCD-7 (module with a 800x480 7” RGB TFT with capacitive touchscreen)

-       ESP32-S3-GEEK  (USB plug-in module with a 1.41 “ 240 x 135 IPS LCD screen & 16Mb PSRAM)

 

Interpreter:

The basic interpreter works by reading a script file saved to the esp local disk filing system.

This is the default mode if no external SDcard(s) are connected to the ESP32. In addition, Annex32 can use an external SD card as file system permitting up to 16Gbytes or 32Gbytes of disk space.

 

During the startup, if an external SDcard is detected it will be automatically connected and used as the default file system, in which case the internal filing system will not be used.

 

Because the ESP32 contains a good quantity of RAM,  the user script is copied from the disk into a dedicated area in the RAM memory where it is executed, together with the list of the program lines, the branch labels and the list of the user defined subroutines.

 

This uses more RAM compared to other approaches, but allows faster program execution.

Another performance consideration is that the ESP32 must be capable of executing several activities in the background (web server, file server, etc..) so needs sufficient free memory for running such tasks, and those parallel tasks will obviously have an impact on script performance.

 

So performance-wise, the interpreter is not particularly fast, but it should be fast enough for most tasks you may require. In particular it is around 2 times faster than Annex for ESP8266, considering that many tasks can run in parallel without any appreciable performance impact (such as playing music in the background).

 

Basic program lines :

A typical script line should comply with the following syntax :

[label:] command [argument1 [,argument2 …..]]

 

Script lines may contain several commands on the same line if separated by the colon character ":".

[label:] command1 [argument1 [,argument2 …..]]: command2 [argument1 [,argument2 …..]]

It must be noted that use of several commands on the same line is not recommended and will cause program errors if the line contains GOSUB or user defined subroutine calls.

 

All program jumps (eg: GOTO, GOSUB) are referenced by their branch label names - line numbers are not referenced in scripts, they are merely available in the editor as a programming convenience if wished, and for error references.

 

NOTE : The gosub and the call to user defined subroutines must be used alone on the script line.

Branch labels

Branch labels should not be named the same as a command name, and must follow the same format as variables (see below).

A branch label definition must begin the line, and a colon (":") must terminate the label definition.

Any references to the defined label (GOTOs and GOSUBs etc) do not use a colon.

Example :

 

b = 10

a = 20 : c = 30

GOSUB LABEL1

END

LABEL1:  print "Label1"

RETURN

 

 

Variables:

The interpreter has 2 types of variables:

-          Floating Point (double precision)

-          String

Floating point variables can store numbers with decimal points; they can also store integer numbers with a precision equivalent to 32bits.

 

Strings contain sequences of characters (example "my program") and must be terminated by "$".

The strings are not limited in size, they are only limited by the amount of memory available.

NOTE: The string variables cannot contain the character with ASCII code 0 (zero) because it is used internally as an end of string delimiter.

 

The variables are defined as any name starting with an alpha character (a, b, ..z) followed by any alphanumeric character (a..z, 0..9); it can also include the "_" (underscore).

The case is don’t care, so  ‘’Num"  is equivalent to "nuM".

The variable name length is limited to 31 characters maximum, including the "$" for the strings.

There are no limits in terms of number of variables; the only limit is the RAM memory available.

Example:

 

NUM = 10.56

myString$ = "this is My String"

this_is_my_value$  = "ESP8266"

number = 8826621

 

Numeric variables and string variables are managed separately so the same name can be used; this means that A and A$ are different variables that can coexist at the same time (even if this could lead to confusion).

 

Constants:

The numeric constants can have the following format :

A = 5 : Z = 1.5

B = 1.23456E5   -> same as 123456

C = 1.23456E+5  -> same as 123456

D = 1.23456E-3  -> same as 0.00123456

 

The string constants are simply defined as a text between quotes:

A$ = "This is my string" : B$ = "another string"

 

The strings can include the character " (quote) simply typing it two times :

A$ = "this is ""MY"" string"

 

The | (vertical bar) can also be used as a string literal.

This permit to include the " (quote) easily inside a string constant :

A$ = |this is a "string" constant|

 

The hexadecimal constants can be defined simply prefixing it with &h :

E = &hABCD -> equivalent of decimal 43981  (hexadecimal constant)

F = &hA0   -> equivalent of decimal 160

 

The binary constants can be defined simply prefixing it with &b :

E = &b00000101  -> equivalent of decimal 5  (binary constant)

F = &b10000001   -> equivalent of decimal 129

 

The octal constants can be defined simply prefixing it with &o :

E = &o377  -> equivalent of decimal 255 (octal constant)

F = &o17   -> equivalent of decimal 15

 

Arrays:

Arrays are defined using the DIM command.

Their names follow the same rules as the regular variables and are followed by parenthesis (brackets) containing the index. The subscript starts from 0, but you can adjust the lower limit using

OPTION.BASE 1.

 

The scope of the Arrays is always global (see next paragraph).

Example:

DIM A(100)              define a floating point array with 101 elements (index from 0 to 100)

DIM ABC$(50)          define a string array with 51 elements (index from 0 to 50)

A(15) = 1234.5678

ABC$(49) = "Hi friend!"

 

The arrays can have up to 5 subscripts (dimensions), examples:

DIM A(50,50)  -> create a floating point array with 51*51 elements (2601)

DIM J$(4, 4, 4)  -> create a string array with 5 * 5 * 5 elements (125)

 

If the command  OPTION.BASE 1  is executed the subscripts start from 1 and an error will be raised when trying to use the index 0.

This line OPTION.BASE 1 must be present in the code before array declaration.

In this case

DIM A(100)              define a floating point array with 100 elements (index from 1 to 100)

DIM ABC$(50)          define a string array with 50 elements (index from 1 to 50)

 

Notice that declaring a multi-dimensional array with multiple subscripts uses elements for every possible combination of subscripts, whereas in practice it may be preferable to declare multiple arrays with the same subscript, eg:

users=4

DIM Name$(users)

DIM Address$(users)

DIM Tel$(users)

Which only uses  5 + 5 + 5 elements (15)

 

NOTE:

The numerical Arrays are always initialised at 0 with the command DIM.

The string Arrays are always initialised as null string with the command DIM.

There are no limits to the number of arrays or their size, the only restriction is the RAM memory available.

 

The arrays can be re-dimensioned using the same command DIM.

In this case all the existing elements will maintain the previous value except the new elements that will be initialised at 0 or null string.

 

Example :

DIM A(5)      ' all the elements are initialised at 0

A(0) = 123

Print A(0)   ' print 123

Dim A(10)

Print A(0)  ' print the same value 123

Print A(10) ' print 0

 

In addition the elements of the arrays can be initialised with a given value during the command DIM.

Example :

DIM A(5) = 0, 1, 2, 3, 4, 5   ' set A(0)= 0, A(1)= 1, A(2)=2, ….

If the command  OPTION.BASE 1  is executed before

DIM A(5) = 0, 1, 2, 3, 4, 5   ' set A(1)= 0, A(2)= 1, A(3)=2, ….

 

The same can be done with string arrays.

Example :

DIM A$(5) = "zero", "one", "two", "three", "four", "five"

 

Two additional functions can be used to determine the bound limits of arrays:

LBOUND(array() [, dimension]) : Returns the lower bound of the specified array dimension.
UBOUND(array() [, dimension]) : Returns the upper bound of the specified array dimension.

 

Example :

OPTION.BASE 0

DIM A(100)

print LBOUND(a()) ' print 0 (option.base 0)

print UBOUND(a()) ' print 100

 

OPTION.BASE 1

DIM A(10, 20)

print LBOUND(a(), 1) ' print 1 (option.base 1)

print LBOUND(a(), 1) ' print 1 (option.base 1)

print UBOUND(a(), 1) ' print 10

print UBOUND(a(), 2) ' print 20

 

 

 

Scope of the variables:

Variables and arrays defined in the main code are global, therefore any variable is accessible from any part of the code after it has been previously defined there.

 

Variables and arrays defined  inside “user defined” subroutine (SUB) are visible only inside that sub and inside all the code called by that subroutine; their content (and their memory space) is removed at the end of the SUB

 

The LOCAL command permits defining local variables inside of "user defined" subroutines; this permits to use the same name of an “already existing” variable locally without modifying the original.

 

As for all the variables defined inside SUB, they will disappear at the end of the subroutine.

 

Example:

A = 10

B = 20

C = 30

mysub "Hello"

PRINT A,B, C

END

 

SUB mysub(a$)

  LOCAL A,B

  A = 123

  B = 456

  C = 789

  D = 8888

  PRINT A$, D

END SUB

 

In this example, calling the user-defined subroutine "mysub" will not modify the content of the global variables A and B (defined locally) but will modify the content of the variable C (not defined locally) and the variable D will disappear at the end of the SUB.

 

Bases of the language

The keywords recognized by the interpreter can be defined into 3 classes:

     Operators

     Commands

     Functions

 

The Operators are symbols that tell the compiler to perform specific mathematical or logical manipulations.

Commands and Functions both execute an action, but functions also return a data value.

For example PRINTis a command and SIN() is a function whereas the ‘+’ in a = b + 5 is an operator.

The string functions are always followed by the "$" symbol if they return a string value.

In addition to commands and functions there are all the internal interpreter internal commands that are part of the language itself.

 

OPERATORS AND PRECEDENCE

The following operators are available. These are listed in the following tables by order of precedence. Operators on the same line are processed with a left to right precedence.

 

Arithmetic operators:

^

Power

* /  \  MOD

Multiplication, division, integer division and modulo (remainder of the division)

+ -

Addition and subtraction

 

Shift operators:

x << y    

x >> y

These operate in a special way. << means that the value returned will be the value of x shifted by y bits to the left while >> means the same only right shifted. They are integer functions and any bits shifted off are discarded and any bits introduced are set to zero.

For more information about the kinds of bitwise shifts, see Bitwise shifts.

 

Logical operators:

<>    <   >   <=

  >=    =

Not Equal, less than, greater than, less than or equal to,

greater than or equal to, equal

AND  OR  NOT XOR

Conjunction, disjunction, negation, Exclusive OR

 

String operators:

<>    <   >   <=

  >=    =

Not Equal, less than, greater than, less than or equal to,

greater than or equal to, equal

+   &

Add strings together

 

Bitwise operators:

AND OR  XOR NOT

Binary AND, binary OR, binary exclusive OR, binary negation

For more information about the bitwise operators, see Bitwise Operators

 

 

The operators AND, OR and XOR are integer bitwise operators. For example PRINT (3 AND 6) will output 2.

 

Expressions beginning with open parenthesis ‘(‘ are always considered numerical but the parser is able to determine if an expression is true or false even if the expression represents a string.

 

Each expression representing a comparison, returns a numerical value of 1 if the expression is true or 0 if false. For example 10 = 10 represents a value of 1 whereas 10 = 5 represents a value of 0.

 

The same logic is applied for string expressions where "abc" = "abc" represents a value of 1 and "abc" = "def"  represents a value of 0.

 

This is very useful in the IF command and also in other expressions.

For example the following code :

 

 

A$ = "on"

If A$ = "on" then

   pin(4) = 1

Else

  pin(4) = 0

End if

 

 

Can be replaced by

pin(4) = (a$ = "on")

 

The strings can also be compared to determine the alphabetical order.

To see whether a string is greater than another, Annex uses the so-called “ASCII” order.

In other words, strings are compared letter-by-letter.

 

For example:

("Z" > "A")  is true

("Glow" > "Glee")  is true

("Bee" > "Be")  is true

("Bas" > "Bat")  is false

The algorithm to compare two strings is simple:

 

Compare the first character of both strings.If the first character from the first string is greater (or less) than the other string, then the first string is greater (or less) than the second. We’re done. Otherwise, if both strings’ first characters are the same, compare the second characters the same way. Repeat until the end of either string.

 

If both strings end at the same length, then they are equal. Otherwise, the longer string is greater.

In the examples above, the comparison "Z" > "A" gets to a result at the first step while the strings"Glow" and "Glee" are compared character-by-character:

 

-       G is the same as G.

-       l is the same as l.

-       o is greater than e. Stop here. The first string is greater.

 

The comparison algorithm given above is roughly equivalent to the one used in dictionaries or phone books, but it’s not exactly the same. For instance, case matters. A capital letter "A" is not equal to the lowercase "a". Which one is greater?

The lowercase "a". Why? Because the lowercase character has a greater index in the ASCII table.

 

Basic internal keywords:

IF command :

The IF can have the following syntax :

1)    IF expression THEN statement

2)    IF expression THEN statement1 ELSE statement 2

3)    IF expression THEN

Statements

            ELSE

Statements

            END IF

4)    IF expression THEN

                              Statements

                  ELSEIF expression THEN

                              Statements

                  ELSEIF ……..

                              ………

            ELSE

Statements

            END IF

Example:

IF a > 100 THEN print "a"

 

IF b <a THEN print "b" ELSE print "a"

 

IF c > d THEN

   print "C"

   print "is greater"

ELSE

   print "D"

   print "is greater"

END IF  ' (can also be ENDIF without space between END and IF)

 

IF d = a THEN

   print "d"

   print "is like a"

ELSEIF d = b

   print "d"

   print "is like b"

ELSEIF d = c

   print "d"

   print "is like c"

ELSE

   print "d"

   print "is unknown"

END IF  ' (can also be ENDIF without space between END and IF)

 

 

When the conditional is all on one line it does not need terminating with an END IF

Example       IF a=2 THEN PRINT "ok" ELSE PRINT "not ok"

 

The AND , OR  keywords can be used between the expressions as long as they are in parenthesis.

Example:      IF (a=1) AND (b=2) THEN PRINT "ok"

 

Or

 

          IF ((a=2) AND (b=3) AND (c = 3)) OR (d=4) THEN PRINT "ok"

 

The IF can be nested

Example:

 

IF a=2 THEN

  IF b = 2 THEN

    IF c = 3 THEN

      PRINT "ok"

    END IF

  END IF

END IF

 

The “THEN” keyword can eventually be removed, even if this is not recommended.

Example:       IF a > 100 print "a" else print "b"

 

FOR loop

The FOR loop can have the following syntax :

 

FOR variable=init_value to end_value [step value]

   Statements

NEXT variable

 

The ‘step’ value can be positive or negative

Example:

 

FOR i=1 to 5

  Print i

NEXT i

 

Will print 1, 2, 3, 4, 5

 

FOR i=1 to 3 step 0.5

  Print i

NEXT i

 

Will print 1, 1.5, 2, 2.5, 3

 

FOR i=3 to 1 step -0.5

  Print i

NEXT i

 

Will print 3, 2.5, 2, 1.5, 1

 

The command EXIT FOR can be used to exit from the loop at any time:

 

FOR i=1 to 50

  IF i=10 THEN EXIT FOR

  Print i

NEXT i

Print "end of loop"

 

Optionally, the variable in the NEXT statement can be omitted.

This means that this program is valid :

 

FOR i=1 to 5

  Print i

NEXT

WHILE WEND loop

The WHILE WEND loop can have the following syntax :

WHILE expression

   Statements

WEND

The loop is iterated as long as the expression is true

 

Example:

i = 0

WHILE i < 3

   Print i

   i = i + 1

WEND

 

Will print 0, 1, 2

 

DO LOOP loop

The DOLOOP can have one of the following 4 syntax :

 

DO WHILE expression

     Statements

LOOP

 

DO UNTIL expression

     Statements

LOOP

 

DO

     Statements

LOOP WHILE expression

 

DO

     Statements

LOOP UNTIL expression

 

The command EXIT DO can be used to exit from the loop at any time

 

Example

i = 0

DO

Print i

i = i + 0.5

LOOP UNTIL i >3

Will print 0, 0.5, 1, 1.5, 2, 2.5, 3

 

i = 0

DO

Print i

i = i + 0.5

IF i > 2 THEN EXIT DO

LOOP UNTIL i >3

Will print 0, 0.5, 1, 1.5, 2

 

SELECT CASE

The SELECTcan have the following syntax:

 

SELECT CASE expression

   CASE exp1 [: Statements]

       Statements

   CASE exp2 TO exp3 [: Statements]

       Statements

   CASE exp4 [,exp5], ... [: Statements]

       Statements

   CASE ELSE

       Statements

END SELECT

 

Example:

 

a = 4

SELECT CASE a

   CASE 1

     PRINT "case 1"

   CASE 2 : PRINT "case 2"

   CASE 3 : PRINT "case 3" : PRINT "can continue on same line"

   CASE 4 : PRINT "case 4"

     PRINT "can continue also on next line"

   CASE ELSE:

     PRINT "case else"

END SELECT

 

Multiple cases:

a = 4

SELECT CASE a

   CASE1       : PRINT "case 1"

   CASE 2, 3, 5 : PRINT "case 2 or 3 or 5"

   CASE4       : PRINT "case 4"

   CASE 6 TO 8  : PRINT "case 6 to 8"

   CASE 9 TO 20 : PRINT "case 9 to 20"

   CASE ELSE:

     PRINT "case else"

END SELECT

 

The SELECT CASE can also handle string content:

SELECT CASE a$

   CASE "a" :

     PRINT "case a"

   CASE "a", "b", "c", "d" :

 PRINT "case a, b, c, or d"

   CASE "e" TO "h" :

 PRINT "case e to h"

   CASE ELSE:

     PRINT "case else"

END SELECT

 

GOTO

The GOTOcan have the following syntax :

GOTO [LABEL | LAB$]

 

Example

a = 5

   IF a > 5 THEN GOTO LABEL1

END

....

 

LABEL1:

PRINT "This is label1"

....

 

The goto must be considered as an obsolete command and is provided just for backward compatibility with old style Basic programs.

 

GOSUB

The GOSUBcan have the following syntax :

GOSUB [LABEL | LAB$]

The called function must terminate with the command RETURN

 

Example

a = 5

   IF a > 5 THEN GOSUB LABEL1

END

....

 

LABEL1:

PRINT "This is label1"

RETURN

 

DATA

The command DATA is used to store constant information in the program code, and is associated with the command READ. Each DATA-line can contain one or more constants separated by commas. Expressions containing variables will be also evaluated here. The goal of the DATA is to avoid repetitive variable assignation lines, in particular for arrays.

The DATA values will be read from left to right, beginning with the first line containing a DATA statement. Each time a READ instruction is executed the saved DATA position of the last READ is advanced to the next value. Strings must be written in quotes like string constants. The command RESTORE resets the pointer of the current DATA position, so the next READ will read from the first DATA found from the beginning of the program.

In case READ uses the wrong variable type the error message "Type mismatch" appears while referring to the line number containing the READ statement that triggered the condition.

DATA lines may be scattered throughout the whole program code, but for the sake of clarity they would be better kept together at the beginning of the program.

 

The DATA can have the following syntax :           DATA const1 [,const2] …..

The constants can be Numerical or String.

 

Example :

DATA 1, 55.88, "constant", 99

READ A, B, C$, D

PRINT A, B, C$, D

 

Example without DATA:

dim colors$(5)

colors$(1) = "Red"

colors$(2) = "Green"

colors$(3) = "Blue"

colors$(4) = "Yellow"

colors$(5) = "Magenta"

 

Same example but using  DATA:

DATA "Red", "Green", "Blue", "Yellow", "Magenta"

dim colors$(5)

For i=1 to 5

  Read colors$(i)

Next i

 

The command RESTORE can optionally define a label to set the DATA pointer to a specific point

 

Example

data 0, 1, 2, 3, 4, 5

block2:

data 10, 11, 12, 13, 14, 15

block3:

data 20, 21, 22, 23, 24, 25

block4:

data 30, 31, 32, 33, 34, 35

 

restore block3

for z = 0 to 5

  read a

  print a,

next z

restore block2

print " "

for z = 0 to 5

  read a

  print a,

next z

print "----------"

END

Define the end of the program. With this command the program stops.

It can also be :

END IF -> close the IF command

END SELECT -> closes the SELECT CASE command

END SUB -> closes the user defined SUB

EXIT

Permit to exit from a loop or a user defined SUB.

The syntax is :

EXIT DO  -> exit from a DO loop

EXIT FOR -> exit from a FOR loop

EXIT SUB -> exit from a user defined SUB.

SUB

Define a user-defined subroutine, which the script can use like a command or function.

User-defined subroutines are effectively additional commands, so cannot be used as branch labels.

Permit to create a user defined command with optional parameters.

The syntax is SUB subname[(arg1 [,arg2] …)]

The variables are passed by reference; this means that the arguments, if modified inside the subroutine, will modify the original variable. This can be useful to return values from the subroutine (acting like a function).

It is possible to pass arrays using the syntax array_name().

Using the LOCAL command will permit to define local variables (useful to avoid to modify existing global variables).

 

Example 1 : routine cube

 

SUB cube(x)

  PRINT X ^3

END SUB

 

cube 3 ' will print 27

 

 

Example 2: routine cube with returning argument

 

SUB cube(x,y)

  y = x ^3    ' the value is returned using the 2nd argument

END SUB

 

ret = 0

cube 5, ret

PRINT ret ' will print 125

 

 

Example 3: routine with local variables and returning argument

 

SUB left_trim(s$, ret$)

  LOCAL i

  i = 1

  DO UNTIL i = len(s$)

    IF mid$(s$, i, 1) <> " " THEN EXIT DO

    i = i + 1

  LOOP

  ret$ = mid$(s$, i)

END SUB

 

z$ = ""

FOR i = 1 to 3

  left_trim "  remove space from left ", z$

  PRINT  z$ + "--"

NEXT i

 

Will print

remove space from left          --

remove space from left          --

remove space from left          --

As you can see in this example, the variable i in the FOR loop is not modified by the LOCAL variable i in the subroutine.

 

Example 4: pass arrays

 

SUB pass_array(f(), c$())

  Dim myArray(10)

  myArray(0) = 456 

  Print f(0), c$(0), myArray(0)

  f(1) = 123

  c$(1) = "myText"

END SUB

 

Dim alpha(10)

Dim beta$(10)

alpha(0) = 456

beta$(0) = "testme"

Pass_array alpha(), beta$()

Print alpha(1), beta$(1)

 

In this example, the array alfa() is passed locally to the array f() and the array beta$() is passed locally to the array c$().

Modifying locally these arrays change the value of the original one as their content is passed by reference.

The array “myArray” will disappear at the end of the SUB

Logical / boolean Operations

As the numerical variables are stored internally as double precision floating numbers, it is possible to store numbers with a precision equivalent to 32 bits.

Several boolean operators are available to manipulate these numbers..

 

The first operator is the bit shift; it can be shift left << or shift right >>

This operator permits to shift the number of a specified number of positions to left or right.

 

Example

A = 1

Print A << 3 ' will print 8

 

A = 16

Print A >> 2 ' will print 4

 

The operators AND , OR , XOR are also available :

 

A = 24

A = 15

Print A AND B ' will print 8

 

A = 24

A = 15

Print A OR B ' will print 31

 

A = 24

A = 15

Print A XOR B ' will print 23

 

The unary operator NOT is also available. It inverts all the bits from 0 to 1:

A = 0

Print Hex$(NOT A) ' will print FFFFFFFF

 

For a 32 bits number, assuming 4 bytes ABCD where A is the MSB and D the LSB, the bytes can be extracted as follows :

 

VAR = &h12345678 ' this is a 32 bits variable

 

D = VAR AND &hFF

C = (VAR >>  8) AND &hFF

B = (VAR >> 16) AND &hFF

A = (VAR >> 24) AND &hFF

 

For more information, see Bitwise Operators

 

ERRORS HANDLING

Annex allows to control and manage errors that occur during the execution of the code.

This is managed with the command ONERROR.

This command defines what action is taken when an error occurs, and applies to all errors, including syntax errors.

It can be used in different ways, as specified in the table below:

 

FUNCTIONS / COMMANDS

DESCRIPTION

ONERROR ABORT

Displays the error message then aborts the program.

This is the normal behaviour and is the default when a program starts running.

ONERROR IGNORE

Any error will be simply ignored.

As this can make it very difficult to debug a program it should be used wisely.

ONERROR SKIP [nn]

Ignore an error in the next command(s) executed after the current command (the number of skipped commands depends on whether the number ‘nn’ is specified).

'nn' is optional, the default is  1  if not specified.

After the number of skipped commands has completed (with an error or not) the behaviour will revert to ONERROR ABORT.

ONERROR CLEAR

Reset the eventual pending error

ONERROR GOTO [label | OFF]

Jumps to the error handling routine defined by the label.

It can be removed (hence reverting to ONERROR ABORT) replacing the label with OFF.

Using RETURN inside the error handling routine will continue the execution on the line following the error.

 

When an error occurs, the following constants are available :

 

CONSTANT

DESCRIPTION

BAS.ERRLINE

Returns the line number where the error happened. Value of 0 means no error.

It is reset to 0 with the command ONERROR CLEAR or  running the program or with the command ONERROR IGNORE or ONERROR SKIP.

BAS.ERRNUM

Returns a number where non zero means that there was an error.

It is reset to 0 with the command ONERROR CLEAR or  running the program or with the command ONERROR IGNORE or ONERROR SKIP.

BAS.ERRMSG$

Return a string representing the error message that would have normally been displayed on the console. It is reset to “No Error” running the program or with the command ONERROR CLEAR or ONERROR IGNORE or ONERROR SKIP.

 

Example of error handling using the command ONERROR GOTO :

 

ONERROR GOTO Error_Handler

Print "start"

Print 3/0  ' this generates a divide by zero error

Print space$(60000) ' this generates an out of memory error

End

 

Error_Handler:

Print "Error text "; BAS.ErrMsg$

Print "Error num  "; BAS.ErrNum

Print "Error line "; BAS.ErrLine

Return ' returns to the line following the error

 

 

HOW the interpreter works with the HTML code and Objects :

When a client connects to the module using its IP address, the module will redirect automatically to the url ‘/output?menu’, which sends an empty html page present on the module.

That page contains a bunch of javascript code permitting to interface the page with the module using javascript.

 

image

This page will automatically open a websocket connection with the module; the "squared led" indicates if the connection was successful (green) or not (red).

A mechanism of ping - pong has been implemented into the javascript in order to hold the connection alive all the time. If the connection is lost, the page will try to reconnect automatically without any manual action.

The button "reconnect" permits to force the reconnection if the automatic reconnection fails.

 

As soon as the connection is done with the module, the html page is ready to send and receive messages to / from the module.

Initially the page is empty but its content can be easily filled.

 

To send HTML code to the page, the command HTML is used.

The syntax is : HTML  HTML code.

For example the line

HTML "Hello, world <br>This is my first html content<br>"

 

Will give this result :

image

Continuing with the HTML command, the content can be improved :

HTML "Textbox: <input type='text'><br>"

 

image

 

Continuing again:

HTML "Button:  <button type='button'>Click Here</button>"

 

image

All the html code can be combined and sent with just one HTML command; this is much faster:

 

a$ = "Hello, world <br>This is my first html content<br>"

a$ = a$ + "Textbox: <input type='text'><br>"

a$ = a$ +  "Button:  <button type='button'>Click Here</button>"

HTML a$

 

To clear the content of the page, the command is:      CLSimage

 

Now we can try another example

CLS

a$ = "Now style me, please<br>"

a$ = a$ + "Button1:  <button id='but1' type='button'>ON</button> "

a$ = a$ + "Button2:  <button id='but2' type='button'>OFF</button>"

HTML a$

image

 

Now we will try to style the buttons using css.

This can be done using  command CSS CSSID$()

 

For example the line

CSS CSSID$("but1", "background-color: red;")

Will give this result :

image

 

Combining with the style for the other button:

 

a$ = a$ + cssid$("but1", "background-color: red;")

a$ = a$ + cssid$("but2", "background-color: green;")

CSS a$

 

image

 

A set of functions is included to simplify the creation of HTML pages as we will see later, so no need to worry if you are not familiar with writing HTML code.

 

Now we will mention an important ‘event’ that can be used to automatically fill the content of the page each time a client connects to the module : OnHtmlReload.

This ‘event’ defines a place where the program will jump to as soon as a Websocket connection request is accepted.

Let’s clarify with an example :

OnHtmlReload Fill_Page    ‘will jump to Fill_Page when the page is reloaded

gosub Fill_Page  'load the page for the first time

Wait         ‘pause waiting for the event

Fill_Page:   ‘place where the page begins to be created

CLS

a$ = "Now style me, please<br>"

a$ = a$ + "Button1:  <button id='but1' type='button'>ON</button> "

a$ = a$ + "Button2:  <button id='but2' type='button'>OFF</button>"

HTML a$

a$ = cssid$("but1", "background-color: red;")

a$ = a$ + cssid$("but2", "background-color: green;")

HTML a$

RETURN

 

The result will be:

image

Now try to play with the button "Reconnect"; you’ll see that, at each time the page reconnects to the module, the HTML content is built and sent again. This ensures that each time a client connects to the module it will receive the correct content. At the same time, if other clients are already connected, the content of all the pages will be refreshed simultaneously. This ensures a synchronized content between all the clients.

 

HTML Objects

As said previously, in order to simplify the creation of HTML pages there are several functions available which can generate the html code automatically.

 

Let’s start with the button.  A button is an object that is used to trigger an action each time it is pressed on the web page.

 

The function is BUTTON$.

Let’s explain with an example:

 

CLS

HTML BUTTON$("Button1", jump1)

 

Wait         'pause waiting for the event

 

Jump1:

PRINT "Clicked on Button1"

Return

 

 

 

The result will be:

image

 

Try clicking on the button then checking the result in the terminal console; the message "Clicked on Button1" will be shown at each click.

image

 

To style the button, we need to modify the syntax of the BUTTON$ command slightly; in fact we need to add another parameter to give the button an ID:

 

CLS

HTML BUTTON$("Button1", jump1, "but1")   ' "but1" is the ID

 

Wait         'pause waiting for the event

 

Jump1:

PRINT "Clicked on Button1"

CSS cssid$("but1", "background-color: red;") 'the same ID is used here

Return

 

Clicking on the button now will change its color to red

image

 

Now we can now introduce the LED object. The LED object is a circle that can be filled in red or green depending on the content of a variable. The function is LED$

As usual, let’s start with an example:

 

 

CLS

led = 1    ‘this is the variable associated with the LED. With 0 the led is red, with 1 the led is green

HTML LED$(led)

 

The result will be:

image

 

Let’s also add a button :

 

CLS

led = 0

a$ = BUTTON$("Button1", jump1, "but1")   ' "but1" is the ID

a$ = a$ + LED$(led)

HTML a$

 

Wait         'pause waiting for the event

 

Jump1:

PRINT "Clicked on Button1"

led = 1 - led ' invert the variable

REFRESH ' refresh (update) the variables between the code and the html

Return

 

 

The result will be:

image

 

Clicking on the button will toggle the led between red and green colors.

 

The command REFRESH permits to update (synchronize) the variables in the code with the corresponding objects variables on the web page. It should be run each time a variable is modified.

As a simpler alternative, the command AUTOREFRESH will regularly sync the variables.

The command must be run with the desired refresh timing.

Example

AutoRefresh 500   will refresh the variables each 500 milliseconds.

The interval should not be less than 300 milliseconds (otherwise the module will be too busy).

 

The example :

 

CLS

led = 0

a$ = BUTTON$("Button1", jump1, "but1")   ' "but1" is the ID

a$ = a$ + LED$(led)

HTML a$

AutoRefresh 300   'sync each 300 milliseconds

Wait         'pause waiting for the event

 

Jump1:

PRINT "Clicked on Button1"

led = 1 - led ' invert the variable

 

Return

 

The result will be the same as the previous example.

 

Now it’s time to introduce another object; the TEXTBOX with the corresponding function TEXTBOX$.

The TEXTBOX will display a ‘text box’ on the web page which is linked with a variable. When the variable is modified in the code, the TEXTBOX content will be updated on the web page, and vice-versa.

This lets us introduce another ‘event’, the OnHtmlChange command.

This ‘event’ defines a branch for the program to jump to whenever a variable is modified inside the web page.

As usual, let’s start with an example:

 

 

CLS

text$ = "Change me, please"

HTML TEXTBOX$(text$)

OnHtmlChange Jump1  'will jump to Jump1 when a variable changes on the web page

Wait         'pause waiting for the event

 

Jump1:

Print text$ 'print the content of the variable inside the terminal console

Return

 

 

image

 

Try now to change the content of the textbox and press "Enter" on the keyboard.

Let’s see the result in the terminal console:

image

image

 

 

With the concepts already learned you’ll be able to use the other objects using the similar logic.

Refer to the pages below to understand the syntax of each object.

 

TIMERS

A timer is an "object" that permits the execution of a particular action at regular intervals.

When the given time expires, the normal execution of the program is interrupted while control is passed to the "timer interrupt routine" until after the execution of the return command.

Then the program continues from the point where it was interrupted.

Let’s explain with an example :

 

timer0 1000, mytimer

wait

 

mytimer:

  wlog "mytimer " + time$

return

 

Annex WI-Fi Basic implements 2 timers, Timer0 and Timer1.

The Timer0 has a higher priority against Timer1.

EVENTS

Many of the actions are not executed directly by basic commands but can be executed as asynchronous events. An  "event" is simply an action that can be executed when something happens. For example, pin change interrupts are asynchronous events which can happen at any time without user control.

 

In order to manage the events, a list of commands "ONxxxx" is provided. These commands define the place where the normal execution of the program will branch to when the event occurs.

So, when the "event" happens, the basic interpreter interrupts the normal execution of the code and "jumps" to the location defined by the corresponding command "ONxxx". As soon as the code associated with the "event" is terminated with the command "return", the basic interpreter continues from the previous interrupted location.

Button Event

This is a special event that happens every time aBUTTON$ object is clicked in the HTML pages.

When this happens, a special variable HtmlEventButton$ is created containing the name of the button that was clicked.

This is useful to determine the button within a group of buttons.

Let’s see an example:

 

CLS

HTML Button$("ON", buttonEvent) + " " + Button$("OFF", buttonEvent)

wait

 

buttonEvent:

print "You clicked on "; HtmlEventButton$

return

 

OnHtmlChange Event

This event is triggered when an object present in the HTML output page changes its value.

It is useful to make actions when something changes in the HTML Pages.

When this event happens, a special variable HtmlEventVar$ is created containing the name of the variable that changed its value.

This is useful to determine the object that generated the event.

Let’s see an example :

 

CLS

text$ = "Change me, please"

HTML TEXTBOX$(text$)

OnHtmlChange Jump1  'will jump to Jump1 when a variable changes on the web page

Wait         'pause waiting for the event

 

Jump1:

Print text$ 'print the content of the variable inside the terminal console

Return

 

Note that the special variable HtmlEventVar$ is only created when the OnHtmlChange event populates it due to a html object change, therefore it will cause an error if tested for before an object is changed unless specifically defined beforehand, eg: HtmlEventVar$ = “”  

 

OnHtmlReloadEvent

This event is triggered when a Websocket connection request is accepted.

This can be used to automatically fill the content of the WEB page each time a client connects to the module.

Let’s see an example :

 

CLS

OnHtmlReload Fill_Page   'will jump to Fill_Page when the page is reloaded

gosub Fill_Page  'load the page for the first time

Wait         'pause waiting for the event

Fill_Page:   'place where the page begins to be created

CLS

a$ = "Now style me, please<br>"

a$ = a$ + "Button1:  <button id='but1' type='button'>ON</button> "

a$ = a$ + "Button2:  <button id='but2' type='button'>OFF</button>"

HTML a$

a$ = cssid$("but1", "background-color: red;")

a$ = a$ + cssid$("but2", "background-color: green;")

HTML a$

Return

 

OnInfrared Event

This event is triggered when a code is received by the infrared receiver.

Refer to chapter INFRARED INTERFACE for more details.

 

OnSerial Event

This event is triggered when a message is received on the serial port.

Example:

 

print "Ram Available "; ramfree
onserial rec1
wait

rec1:
'print serial.input$
print serial.chr$;
return

 

 

 

OnSerial2 Event

This event is triggered when a message is received on the serial port #2.

Example

 

serial2.mode 9600, 2, 5 ' set serial port #2 to 9600 pin 2 TX, pin 5 RX
print2 "Ram Available "; ramfree
onserial2 rec2
wait

rec2:
print serial2.input$
return

 

 

OnTouch Event

This event is triggered when the TFT screen is touched.

Refer to the chapter TouchScreen for more details.

 

OnUDP Event

This event is triggered when a UDP message is received.

Example:

 

udp.begin 5001  'set the UDP commmunication using port 5001
onudp goudp
'Write several messages to the port
for i
= 0 to 100
  
udp.write "192.168.1.44", 5001, "Hello " + str$(i)
next i
wait

goudp:
v$
= udp.read$ 'receive the UDP data

print v$
return

 

 

OnWgetAsync Event

This event is triggered when a WgetAsync message is received.

 

This is associated with the command WGETASYNC. The goal of the WGETASYNC command is to start a html get request without the module having to wait for the answer. Because the response is async, this command specifies the location where the program should branch to when a message is received.

 

Example:

 

ONWGETASYNC answer_done

WGETASYNC("www.fakeresponse.com/api/?sleep=5", 80)

For i = 0 to 10000

  ' a kind of sleep just to demonstrate that the code continue to run

  Print i

Next i

Wait

answer_done:

Print WGETRESULT$

Return

 

OnUrlMessage Event

This event is triggered as soon as a web client requests for a web page with the url composed with http://local_ip/msg?param=value. This kind of request is typically called an AJAX request as it permits to exchange in both directions between the client (the web browser) and the server (the ESP module).

 

In fact, in the url request, the client can send parameters in the form of couples of "param=value" separated by the character "&". For example, if the client wants to send 2 parameters, it can send the following request :

http://local_ip/msg?param1=value1&param2=value2.

 

As soon as this message is received by the ESP module, the event OnUrlMessage is triggered; this means that the program will continue from the location defined by the command OnUrlMessage.

As soon as the message is received, the parameters sent by the client can be got with the function UrlMsgGet$ and a message can be sent back to the client with the command UrlMsgReturn.

Let’s see an example :

 

onUrlMessage urlAjax

wait

 

urlAjax:

wlog "message received " + UrlMsgGet$("a") + " " + UrlMsgGet$("b")

UrlMsgReturn "Message sent back " + time$

print UrlMsgGet$("b"), ramfree

return

 

Now using another web browser window, let’s type the following url :

http://esp_local_ip/msg?a=10&b=20

As you can see in the following picture, the message is received by the ESP module

image

 

 

 

At the same time, the client receives the message sent back from the ESP module

image

 

If the program is stopped, the module will answer with the message "STOPPED"

image

Now, let’s see a more complete example :

cls

' this is the default value for pwm out

R = 512

G = 512

B = 512

'Setup the pwm channels

PWM.SETUP 12, 1, R, 10000, 10

PWM.SETUP 15, 2, G, 10000, 10

PWM.SETUP 13, 3, B, 10000, 10

'Set the default values

PWM.OUT 1, R

PWM.OUT 2, G

PWM.OUT 3, B

 

' these are the sliders

a$ = ""

a$ = a$ + |R <input type="range" id="dimmer_R" oninput="setPWM()" onclick="setPWM()" min="0" max="1023" value="| & str$(R) & |"/><br>|

a$ = a$ + |G <input type="range" id="dimmer_G" oninput="setPWM()" onclick="setPWM()" min="0" max="1023" value="| & str$(G) & |"/><br>|

a$ = a$ + |B <input type="range" id="dimmer_B" oninput="setPWM()" onclick="setPWM()" min="0" max="1023" value="| & str$(B) & |"/><br>|

a$ = a$ + |<input type='text' id="txbox" value='---'>|

html a$

'this is the javascript "AJAX" code

fun$ =    |function setPWM() {|

fun$ = fun$ & |r=_$("dimmer_R").value;|

fun$ = fun$ & |g=_$("dimmer_G").value;|

fun$ = fun$ & |b=_$("dimmer_B").value;|

fun$ = fun$ & |var xmlHttp = new XMLHttpRequest();|

fun$ = fun$ & |xmlHttp.open("GET", "msg?r=" + r +"&g=" + g +"&b=" + b, false);|

fun$ = fun$ & |xmlHttp.send(null);|

fun$ = fun$ & |r = xmlHttp.responseText;|

fun$ = fun$ & |_$("txbox").value = r;|

fun$ = fun$ & |return r;}|

 

' this is where the javascript code is inserted into the html

jscript fun$

 

'this is where the prog will jump on slider change

onUrlMessage message

wait

 

message:

print UrlMsgGet$()

 

PWM.OUT 1, val(UrlMsgGet$("r"))

PWM.OUT 2, val(UrlMsgGet$("g"))

PWM.OUT 3, val(UrlMsgGet$("b"))

UrlMsgReturn UrlMsgGet$()

return

 

Open the input page in another window and run the program

 

image

Using an external RGB led, you’ll be able to directly control its color.

 

You’ll see how the exchanges can be fast using AJAX exchanges. This program uses javascript embedded into the code. The javascript works with the function XMLHttpRequest.

 

A good reference for this function is here AJAX - Send a Request To a Server

OnEspNowMsg Event

This event is triggered when a ESP-NOW message is received.

Example:

 

espnow.begin  ' init the ESP-NOW

onEspNowMsg message ' set the place where jump in case of message reception

wait

 

message:

print "Message Received!"

return

 

OnEspNowError Event

This event is triggered when a ESP-NOW transmission error occurs.

This happens, in particular, when the receiver device has not received the message.

 

espnow.begin  ' init the ESP-NOW

espnow.add_peer "60:01:94:51:D0:7D" ' set the MAC address of the receiver

onEspNowError status ' set the place where jump in case of TX error

espnow.write "TX message" ' send the message

wait

 

status:

print "TX error on "; espnow.error$  ' print the error

return

 

OnMQTT Event

This event is generated when a MQTT message is received or an MQTT event happens

Example:

 

....

onmqtt mqtt_msg

 

wait

' receive messages from the server

mqtt_msg:

print "TOPIC  : "; mqtt.topic$

print "MESSAGE: "; mqtt.message$

return

 

OnPlay Event

This event is generated when a “metadata” is decoded when playing mp3 or streaming a web radio.

 

WiFI CONNECTIONS

At startup, the module will try to connect to the router using any parameters specified in the page “Config”.

If no parameters are specified in the “Config” page, or the connection is unsuccessful, it will default to AP (Access Point) mode with IP address 192.168.4.1 with the SSID composed of ESP(+ mac address).  If the connection is successful, the module will use the IP address defined in the “Config” page or, if no IP address is specified, the IP will be given automatically by the Router DHCP server. After the module has connected to the router it will try to reconnect automatically if the connection is lost.

 

There are several commands / functions available to manage the WIFI.

 

The first function is WIFI.STATUS which permits to get the status of the connection.

print WIFI.STATUS ’ print 3 if connected, 6 if disconnected

 

The first useful command is WIFI.CONNECT SSID$, password$ [, BSSID$] [, IP$ , MASK$ [, GATEWAY$]]

 

This command allows you to connect to any WIFI network (STA mode) overriding the parameters defined into the’ “Config” page. This function is async so the connection is done in background, while the program continues to run.

Is then possible to check the status of the connection using the function WIFI.STATUS

Example :

WIFI.CONNECT "HOMENET", "MyPassword"

print "connecting"
While WIFI.STATUS <> 3
 
Print "."
 
pause 500
wend

 

Using the optional parameter BSSID$, will enable the connection to a specific WiFi access point.

The BSSID represents the MAC address of the WiFi access point (the router) and it is defined as 6 bytes in hex format separated by colon, i.e. AA:BB:CC:12:34:56.

 

For stand alone configuration or for ESP-NOW applications, there is another command that puts the module in AP mode.

This command is WIFI.APMODE SSID$, password$ [, channel] [, IP$ , MASK$]

The result is immediate and the status can be checked using the function WIFI.MODE (see below).

The channel is optional and is 1 by default.

IMPORTANT : the password must be at least 9 characters

 

It is eventually possible to control the output power of the module with the command WIFI.POWER pow

WIFI.POWER 5 ’ set the output power at 5 dBm.

 

The module can also be put in WiFi sleep mode. This mode permits to turn off the WiFi reducing the power requirements of the module; this is very useful for battery oriented applications or for applications where the WiFi is not required.

To put the module in “modem-sleep”, the command to execute is WIFI.SLEEP.

The module will stay in that mode until the execution of the command WIFI.AWAKE.

 

After this command, the module will reconnect automatically to the router (the command WIFI.CONNECT is not required).

 

Another function available is WIFI.CHANNEL that shows the current Radio Channel used by the WIFI.

 

Using the function WIFI.RSSI is it possible to get the intensity of the signal received (RSSI)  

 

It is also possible to scan for the WiFi networks accessible around the module.

This can be done using the command WIFI.SCAN and the function WIFI.NETWORKS(network$).

Example :
WIFI.SCAN
While WIFI.NETWORKS(A$) < 0
Wend
Print a$

The result will be :

Vodaphone, 00:50:56:C0:00:08, -50, 5

Orange, 00:50:56:C0:32:07, -70, 5

Xxxx,  00:50:56:C0:86:CA,-78, 12

 

These information represent, in the order :

SSID, BSSID(mac address), RSSI(signal intensity), Channel Radio

 

The function WIFI.MODE returns the current mode of the WIFI connection as below:

 

VALUE

MEANING

0

The WIFI is in sleep mode

1

The WIFI is in STATION mode

2

The WIFI is in AP mode

3

The WIFI in AP+STA mode

 

The WIFI in AP+STA mode can be obtained by configuring the module in AP mode and then using the command WIFI.CONNECT in the program.

 

Using a “fake” SSID / password (example WIFI.CONNECT "A", "" ) can be used to switch the WIFI into the AP+STA mode. This can be useful for mixed ESP32 / ESP8266 ESP-NOW operations.

 

Another Wifi related command is OPTION.MAC mac$ that permits to modify the MAC address of the module.

This is very important for the ESP Now functionality.

Example :

OPTION.MAC "AA:BB:CC:DD:EE:FF"

 

In addition, the functions BAS.SSID$ and BAS.PASSWORD$ returns respectively the login and the password used for the STATION wifi connection.

PROGRAM AUTORUN

If a program is defined to run automatically (“Autorun File” in the config page), the WiFi connection process is slightly different.  If the option “Fast boot” in the config page is selected, the program will be executed immediately and the WiFi will be powered ON after a little delay ( 0.1 sec ).

 

If the command WIFI.SLEEP is executed during the very beginning of the program ( for example as the first line of the program) the WiFi will be simply disabled without using any power. This enhances the use of the module in low power applications (i.e. on battery). The WiFi connection can then be restored later using the commandsWIFI.CONNECT or WIFI.APMODE.

 

If the command WIFI.SLEEP is not executed at the beginning of the program, the WiFi connection will be established by default as described in the previous chapter (WiFI CONNECTIONS).

 

The function BAS.RESETREASON can be used at the beginning of the program to understand the reasons for the restart of the module enabling it to take the appropriate actions.

In addition, the function BAS.WAKEUPREASON can be used to determine the cause of the wakeup from sleep if the module was in deep sleep mode.

RECOVERY MODE

In case of any IP or Autorun problem preventing the module from being accessed, it is possible to temporarily bypass the IP settings of the module and disable the Autorun file by connecting the serial TX and RX pins together (GPIO1 to GPIO3) during the startup phase (power up). This could happen if, for example, a wrong IP address has been set.

 

Doing this action when restarting the module will put it in AP mode with the IP address at 192.168.4.1, just like a module that has not been configured.  A message “Recovery Mode” will be printed on the console, but none of the existing files on the module will be modified, including the internal configuration parameters.

 

In this mode it will be possible to gain access to the module for changing such correct wrong IP parameters using the configuration page.When the TX/RX link is removed, the module can be rebooted to the configured settings at the next restart.

 

SLEEP mode (low energy) and RTC memory

The module can be put into low energy mode to minimise as much as possible the power requirements.

This mode is called deep sleep and should reduce the power consumption to a few µA but this is a function of  each ESP32 module as the power requirement includes the different components installed on the module.

When the module is put into deep sleep all the module activities are stopped, all the memory content of the module is lost except for the RTC memory (this is a special memory block inside the module that holds its content even if the module is reset, but not when the module is powered OFF).

At the end of the sleep period, the module restarts and reloads the program defined as autorun from the beginning (from the first line).

 

To put the module in deep sleep the following command is available :

 

SLEEP value [, pin, level]

This command puts the ESP32 in deep sleep (low energy) for 'value' seconds.

At the end of the period, the unit will reboot and reload the default basic program.

Example

' Sleeps for 600 seconds (10 minutes)

The period can go from 1 second  to several years (1 year = 31,536,000 seconds)

 

Optionally, it is possible to wake up the module using an external signal sent on an input pin

In this case the pin and the level must be specified in addition to the time value.

Example

' Sleeps for 3600 seconds (1 Hour) or until the pin 32 goes to high

SLEEP 3600, 32, 1

 

Only RTC IO can be used as a source for external wake up.

They are pins: 0,2,4,12-15,25-27,32-39.

Level is 1 for wakeup on High and 0 for wakeup on Low

 

Optionally, this command can be also used to wake up the module using the capacitive touch on an input pin.

In this case the command SLEEP maintains the same syntax but level defines the threshold value for the pin.

Only the following pins can be used for that purpose (capacitive touch) : 0, 2, 4, 12, 13, 14, 15, 27 32, 33

Level must be > 1 to enable the touch (0 and 1 are reserved for the wake up on Low or Wake up on High).

Example

' Sleeps for 3600 seconds (1 Hour) or until the pin 15 is touched

SLEEP 3600, 15, 40 ' Threshold at 40

 

The RTC memory will survive after the wake up permitting to take trace of the actions done before the sleep.

 

This memory can be set as below :

BAS.RTCMEM$ = "data to be saved during deep sleep"

 

And can be read as below :

A$ = BAS.RTCMEM$

 

Note : the RTC memory can hold up to 7680 bytes

DATE - TIME timekeeper

The ESP module normally synchronises its date and time from either of two NTP time servers ("pool.ntp.org" and "time.nist.gov"). Optionally an alternative (eg: intranet) time server can be defined using the [CONFIG] page. Using these servers the ESP doesn’t require any date/time setting (except the configuration of the Time Zone and DST done using the [CONFIG] page).

 

The timezone is defined as a string likeCET-1CEST,M3.5.0,M10.5.0/3 that describes how the local time must be managed in terms of time shift and DST (summer / winter time).

 

A complete list of timezone strings can be found here : https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv

 

An internal timekeeper has been included if no time server is available, e.g. no available internet access.

This timekeeper starts from 01/01/1970 00:00:00 and counts the seconds since the power on of the module.

If internet connection becomes available later, the internal timekeeper will sync its time with the NTP servers.

 

The time can be sync with the NTP time server at any moment using the command OPTION.NTPSYNC.

 

This time and date can be manually set using the command SETTIME.

The Syntax is :      SETTIME year, month, day, hours, minutes, seconds

 

Example

Set the date to 02 September 2017 at 13:58:12

 

SETTIME 17, 9, 2, 13, 58, 12

 

The time and date can also be manually synchronised to the computer using the "Time Sync" button in the File Manager window of the computer utility ‘tool’ if it has a websocket connection.

 

WARNING:

In both cases of manual setting, the time and date will default back to 1970 defaults at the next module restart, so will require setting again.

 

For more information about the Time Zones and DST, please consult the following page :

Time Zone and DST   It is also possible to connect an RTC (DS1307 or DS3231) to the module.

See the chapter “RTC Module” for more details.

Unix Time functions

The following functions use the “Unix Time Stamp” format :

DATEUNIX(date$), TIMEUNIX(time$), UNIXDATE$(value [,format]), UNIXTIME$(value)

 

The “Unix Time Stamp” is a way to track time as a running total of seconds. This count starts at the Unix Epoch on January 1st, 1970 at UTC. Therefore, the unix time is merely the number of seconds between a particular date and the Unix Epoch.In synthesis :

-       DATEUNIX("01/01/18") returns the number of seconds from 01/01/1970 to the specified date 01/01/2018  (1514764800)

-       TIMEUNIX("12:30:55") returns the number of second since midnight (45055)

-       UNIXDATE$("1532773308") returns 28/07/18

-       UNIXTIME$(1532773308) returns 10:21:48

FAT32 File System

Annex32 includes a FATFS file system hosted on the flash memory chip.

It “emulates” a disk file system enabling it to save and load files in a transparent way.

Depending on the size of the flash chip, the following free space is available :

 

Flash Chip size

Free space available

4M

1MB

8M

5MB

16M

13MB

 

Annex32 can also use an SD CARD connected as described in the chapter SD CARD ADAPTER.

 

Both the internal FATFS and the SD CARD utilise the FAT32 file system This means that there are no particular limitations in terms of filename length and directories, compared to the SPIFFS file system limitations hosted in the ESP8266.

 

Unlike normal variables, filenames and folders are case sensitive. Annex32 supports SD CARDS up to 16GB.

 

The internal and the external (SDcard) space are mutually exclusive and cannot be accessed at the same time. By default Annex32 will use the SD, if available, otherwise it will use the internal flash disk space (FATFS).

 

Both the internal FATFS and external SD CARD share the same command and functions.

 

All the file related functions share the same prefix FILE. followed by the specific function.

 

FUNCTIONS / COMMANDS

DESCRIPTION

FILE.COPY(filename$, newfile$)

Copy the file filename$ into the file newfile$

Returns 1 in case of success or 0 if error

FILE.DELETE(filename$)

Delete the file specified by filename$

Returns 1 in case of success or 0 if error

FILE.EXISTS(filename$)

Returns 1 if filename$ exists, otherwise returns 0

FILE.RENAME(oldname$, newname$)

Rename the file oldname$ to  newname$

Returns 1 in case of success or 0 if error

FILE.SIZE(filename$)

Returns the size of the file (in bytes) if the file exist, otherwise returns  -1

FILE.MKDIR(dirname$)

Create a directory specified by dirname$

Returns 1 in case of success or 0 if error

FILE.RMDIR(dirname$)

Remote the directory specified by dirname$

Returns 1 in case of success or 0 if error

FILE.DIR$(path$)

Will search for files and return the names of entries found.

path$ represents the directory name.

path$ can include wildcards characters as ‘*’, ‘.’ and ‘?

The function will return the first entry found.

To retrieve subsequent entries use the function with no arguments. ie, FILE.DIR$.

The return of an empty string indicates that there are no more entries to retrieve.

FILE.READ$(filename$, [line_num] | [start, length])
 

Returns the content of the file filename$.

Specifying line_num, only the corresponding line is read from the file.

If start and length options are specified, the file is read from the start position for length characters, otherwise the complete file is read in one go

The line number starts from 1.

If the line is not existing (reached the end of file), the function will return “_EOF_” to indicate the end of the file.

FILE.APPEND filename$, content$

Append the content of content$ to the file filename$.

If the file does not exist, it will be created.

The file can be read back using the function FILE.READ$(filename$)

File size is only limited by available disk space (internal FFAT or external SD card)

FILE.SAVE filename$, content$
 

Save the content of content$ to the file filename$.

The file can be read back using the function FILE.READ$(filename$)

File size is only limited by available disk space (internal FFAT or external SD card)

FILE.WRITE filename$, content$

Same functionalities as the previous command.

Implemented for homogeneity with other commands

FILE.FROMBASE64 source$, dest$

Convert the file defined ‘source$’ into the file defined in ‘dest$’.

The source file can be in any format but must be encoded in base64 format. Useful for wokwi to store any file in text format

FILE.TOBASE64 source$, dest$

Convert the file defined ‘source$’ into the file defined in ‘dest$’.

The source file can be in any format and will be encoded in base64 format.

FILE.SAVE_IOBUFF

See the chapter I/O buffer for more details

FILE.WRITE_IOBUFF

See the chapter I/O buffer for more details

FILE.APPEND_IOBUFF

See the chapter I/O buffer for more details

FILE.READ_IOBUFF

See the chapter I/O buffer for more details

 

Examples:

 

List all the files in the directory /html

d$ = FILE.DIR$("/html")

While D$ <> ""

  wlog d$

  d$ = FILE.DIR$

Wend

 

File operations

file.save "/test.bas", "The quick brown fox "

wlog "exists", file.exists("/test.bas")

wlog "size", file.size("/test.bas")

file.append "/test.bas", "jumps over the lazy dog"

wlog "size", file.size("/test.bas")

wlog "copy", file.copy("/test.bas", "/AAA.bas")

wlog "size", file.size("/AAA.bas")

wlog "rename", file.rename("/AAA.bas", "/BBB.bas")

wlog "size", file.size("/BBB.bas")

wlog "size", file.size("/AAA.bas")

wlog "read", file.read$("/test.bas")

wlog "delete", file.delete("/BBB.bas")

 

Download files from another module or WEB server

 

The command:         FILE.DOWNLOAD url$, file_path$

retrieves a file from a specified URL (url$) and saves it to the local file path (file_path$). This can be used both as a standalone command or as a function that returns a status code, indicating the success or failure of the download operation.

     url$: A string specifying the URL of the file to download. This should be a valid HTTP or HTTPS URL.

     file_path$: A string specifying the local path where the downloaded file should be saved.

When used as a function,FILE.DOWNLOAD returns an integer value that indicates the status of the download:

     1: Download completed successfully.

     -1: Not enough space available to download the file.

     -2: Failed to open the file for writing.

     -3: Failed to create an HTTP client.

     Other HTTP error codes: Various HTTP error codes that may be returned by the server (e.g., 404 for "Not Found", 500 for "Internal Server Error").

This command is also useful for downloading (copying) a file from another Annex RDS module. By providing the appropriate URL, you can easily transfer files between modules, which is especially useful for distributing updates or configurations across multiple devices.

Notes:

     The function handles both HTTP and HTTPS URLs, using a secure client

     The function checks for available space before attempting the download and will abort if there is insufficient space.

     All operations are logged to the serial output for debugging purposes.

Example 1: download from the WEB

FILE.DOWNLOAD "https://updates.cicciocb.com/annex-logo.png", "/logo.png"

or

Wlog FILE.DOWNLOAD("http://updates.cicciocb.com/annex_bee_new.png", "/logo2.png")

 

Example 1: download from another Annex RDS Module with IP: 192.168.1.181

FILE.DOWNLOAD "http://192.168.1.181/program1.bas", "/program1.bas"

or

Wlog FILE.DOWNLOAD("http://192.168.1.181/program1.bas", "/program1.bas")

 

 

print file.download ("https://updates.cicciocb.com/annex-logo.png", "/logo.png")

I/O BUFFERS

The I/O BUFFER is a functionality that gives the capability to hold and manage binary data. In short, the I/O buffer is a block of RAM memory that can be exchanged as a block or read and written byte per byte.  It overcomes the limitation of strings, which are unable to include the character ASCII 0 (NUL).

It has a defined length and can be freely dimensioned and cleared.

 

It can be used in the code using the IOBUFF keyword, and Annex exposes 5 I/O buffers numbered from 0 to 4.

The I/O buffers can have any size within the limits of the free RAM memory available. The main goal of this functionality is to interface with all the functions that require exchanges using binary data.

In the current implementation it can be used with :

-       Files

-       Serial Ports

-       SPI

-       I2C

-       UDP

 

Define the Size of an I/O Buffer

IOBUFF.DIM(buff_num,size)

This command allocates memory for an I/O buffer by defining its size.

     Parameters:

     buff_num: Specifies the buffer ID, ranging from 0 (first buffer) to 4 (last buffer).

     size: Specifies the size of the buffer in bytes. The value can range from 0 to the maximum available RAM.

     Return Value:

     The size of the allocated memory or 0 in case of error

     Behaviour:

     Allocates the specified amount of memory to the selected buffer.

     The buffer retains its size until it is manually destroyed or the program ends.

Example:

IOBUFF.DIM(0, 1000) 'dimension the I/O buffer 0 with 1000 bytes

Print IOBUFF.DIM(1, 25) 'dimension the I/O buffer 1 with 25 bytes (prints 25)

 

Fill a Buffer with Predefined Data

IOBUFF.DIM(buff_num,size) = data_list

The IOBUFF.DIM command can also initialise a buffer with a sequence of values during its creation.

     Parameters:

     buff_num: Specifies the buffer ID, ranging from 0 (first buffer) to 4 (last buffer).

     size: Specifies the size of the buffer in bytes. The value can range from 0 to the maximum available RAM.

     data_list: A list of values (e.g., integers, hexadecimal, binary) to store in the buffer.

     Return Value:

     The size of the allocated memory or 0 in case of error

     Behaviour:

     Reserves memory for the buffer and populates it with the specified values.

Example:

 

' Fills buffer 0 with 10 values

Print IOBUFF.DIM(0, 10) = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10  ' prints 10

' Fills buffer 1 with 5 values

IOBUFF.DIM(1, 5) = &h12, &hAA, &h50, &O377, &B10101010 

 

 

Release a Buffer

IOBUFF.DESTROY(buff_num,size)

Releases the memory allocated to a specific buffer.

     Parameters:

     buff_num: Specifies the buffer ID to be destroyed (0–4).

     Return Value:

     Always 0

     Behaviour:

     Frees the memory allocated for the specified buffer.

     After destruction, the buffer is no longer accessible until reallocated.

Example:

IOBUFF.DESTROY(0) ' Destroys buffer 0, releasing its allocated memory

 

Note: All buffers are automatically destroyed when the program ends.

 

Get the Size of a Buffer

IOBUFF.LEN(buff_num)

Returns the current size (in bytes) of the specified buffer.

     Parameters:

     buff_num: The ID of the buffer to query (0–4).

     Return Value:

     The size of the buffer in bytes.

Example:

Print IOBUFF.LEN(0) ' Prints the size of buffer 0

 

Read Data from a Buffer

IOBUFF.READ(buff_num,position)

Reads a single byte from a specified position in a buffer.

     Parameters:

     buff_num: The ID of the buffer to read from (0–4).

     position: The byte position to read (0 to buffer length - 1).

     Return Value:

     The value of the byte at the specified position (0–255).

Example:

Print IOBUFF.READ(0, 4) ' Prints the byte at position 4 from buffer 0

A = IOBUFF.READ(0, 7) ' Stores the byte at position 7 in variable A

 

Write Data to a Buffer

IOBUFF.WRITE(buff_num,position, value)

Writes a single byte to a specified position in a buffer.

     Parameters:

     buff_num: Specifies the buffer ID to be destroyed (0–4).

     position: The byte position to read (0 to buffer length - 1).

     value: The byte value to write (0–255).

     Return Value:

     Always 0

     Behaviour:

     Updates the specified position in the buffer with the given value.

Example:

IOBUFF.WRITE(0, 5, 123) ' Writes the value 123 at position 5 of buffer 0

 

 

The I/O buffers communicate with the other modules using the following syntax:

-   xxxx.READ_IOBUFF(buff_num)

Receive data in the buffer buff_num

 

-   xxxx.WRITE_IOBUFF(buff_num, start, size)

Transmit (send) data from the buffer buff_num starting from the position ‘start’ for ‘size’ bytes

 

-   xxxx.REPLY_IOBUFF(buff_num, start, size)

Reply to the sender data from the buffer buff_num starting from the position ‘start’ for ‘size’ bytes

 

Where xxxx can be :

UDP

SERIAL

SERIAL2

FILE

I2C

SPI

 

Detailed syntax :

UDP.READ_IOBUFF(buff_num)

SERIAL.READ_IOBUFF(buff_num)

SERIAL2.READ_IOBUFF(buff_num)

FILE.READ_IOBUFF(buff_num), filename$ [, position, nb_of_bytes_to_read]

I2C.READ_IOBUFF(buff_num), address, register, nb_of_bytes_to_read

SPI.READ_IOBUFF(buff_num), nb_of_bytes_to_read

 

UDP.WRITE_IOBUFF(buff_num [, start [, size]]), IP$, port

SERIAL.WRITE_IOBUFF(buff_num [, start [, size]])

SERIAL2.WRITE_IOBUFF(buff_num [, start [, size]])

 

FILE.SAVE_IOBUFF(buff_num [, start [, size]]), filename$

FILE.WRITE_IOBUFF(buff_num [, start [, size]]), filename$

FILE.APPEND_IOBUFF(buff_num [, start [, size]]), filename$

 

I2C.WRITE_IOBUFF(buff_num [, start [, size]]), address, register

SPI.WRITE_IOBUFF(buff_num [, start [, size]])

 

UDP.REPLY_IOBUFF(buff_num [, start [, size]]) [,port]

SPI.REPLY_IOBUFF(buff_num [, start [, size]]), (buff_num_reception)

 

The IOBUFFER can be used for sending or receiving data.

Read Operations

When used for receiving data, the syntax is always.READ_IOBUFF(buff_num).

 

When receiving data, it is not necessary to dimension the buffer before as it will be automatically dimensioned depending on the size of the data received. If the buffer was already containing some data, these will be flushed and replaced by the new data.

 

For example, the following command receives all the data available from the serial port 2 in the buffer 3 :

SERIAL2.READ_IOBUFF(3)

 

This command receives the data coming from an UDP connection in the buffer 1:

UDP.READ_IOBUFF(1)

 

Additionally some other arguments may be required.

This command reads 512 bytes from the file data.bin starting from the file position 123 in the buffer 0:

FILE.READ_IOBUFF(0), “/data.bin”, 123, 512

 

This command reads 8 bytes from an I2C device with address 63 from the register 19 in the buffer 4 :

I2C.READ_IOBUFF(4), 63, 19, 8

 

This command reads 32 bytes from the SPI bus in the buffer 2 :

SPI.READ_IOBUFF(2), 32

 

Write Operations

When used for sending data, the syntax is always .WRITE_IOBUFF(buff_num [, start [, size]])

 

When sending data, it is possible to send the entire buffer or only a part of it. Specifying the optional arguments start and size it is possible to define the part of the buffer to be sent; otherwise, if omitted, the entire buffer will be transferred.

 

For example, the following command sends 10 bytes from the buffer 1 starting from the position 45 to the serial port :

SERIAL.WRITE_IOBUFF(1, 45, 10)

 

This command sends the complete buffer 1 to the serial port 2

SERIAL2.WRITE_IOBUFF(1)

 

This command sends 8 bytes from the buffer 2 starting from the position 128 to the SPI bus

SPI.WRITE_IOBUFF(2, 128, 8)

 

Additionally some other arguments may be required.

 

This command sends 12 bytes from the buffer 1 starting from the position 64 to the UDP on the address 192.168.1.89 and port 8080 :

UDP.WRITE_IOBUFF(2, 128, 8), “192.168.1.89”, 8080

 

This command sends the entire buffer 2 on the same UDP device :

UDP.WRITE_IOBUFF(2), “192.168.1.89”, 8080

 

This command writes the buffer 1 to the file data.bin

FILE.WRITE_IOBUFF(1), “data.bin”

 

This command has the same result and is provided for compatibility with the existing syntax

FILE.SAVE_IOBUFF(1), “data.bin”

 

This command appends 36 bytes from the buffer 0 starting from the position 25 to data.bin

FILE.APPEND_IOBUFF(0, 25, 36), “data.bin”

 

This command sends the buffer 2 to the I2C device with address 63 and register 19 :

I2C.WRITE_IOBUFF(2), 63, 19

 

The same operation but sending only 4 bytes starting from position 0:

I2C.WRITE_IOBUFF(2, 0, 4), 63, 19

 

Special operations

The syntax .REPLY_IOBUFF(buff_num [, start [, size]]) defines some kind of special operations.

 

For example, this command sends the buffer 0 back to the UDP message sender:

UDP.REPLY_IOBUFF(0)

This is the equivalent of UDP.REPLY message$ but with the IOBUFFER

 

Optionally it is also possible specify part of the buffer and the destination port (eg: 5001) as below:

UDP.REPLY_IOBUFF(0, 2, 6), 5001

 

When used with the SPI bus, it transmits and receives at the same time.

As this operation requires 2 buffers, both must be specified.

For example, this command sends the buffer 0 and receive into the buffer 2:

SPI.REPLY_IOBUFF(0), (2)

This command sends 4 bytes from the buffer 0 starting from the position 89 and receive 4 bytes in the buffer 3:

SPI.REPLY_IOBUFF(0, 89, 4), (3)

 

Advanced operations

Several other functions / commands are available for advanced users.

These enable bit, string and hex operations

 

Convert a String into Buffer Content

IOBUFF.FROMSTRING(buff_num, var$ [, pos])

     Parameters:

     buff_num:  The ID of the buffer (0–4) where the string will be written.

     var$: The input string containing the text to be converted, e.g., "This is a text string".

     pos: (Optional) The starting position in the buffer where the string will be written.
Default: 0 (write from the beginning of the buffer).

     Return Value:

     The number of characters successfully written into the buffer.

     If used as a command, the return value is ignored.

     Behaviour:

     Converts the input string (var$) into its binary representation and writes it to the specified buffer (buff_num).

     If pos is specified, the string starts at the given byte position in the buffer.

     If the buffer does not have enough space, it is automatically resized to fit the string.

 

Example:

IOBUFF.FROMSTRING(0, "Hello")    ' Writes "Hello" into buffer 0 starting at position 0.

IOBUFF.FROMSTRING(0, "World", 10) ' Writes "World" into buffer 0 starting at position 10.

print IOBUFF.FROMSTRING(0, "World") ' Outputs "5" (the size of the string)

 

 

Convert Buffer Content to a String

IOBUFF.TOSTRING$(buff_num, [, start [, size]])

     Parameters:

     buff_num: The ID of the buffer (0–4) to read data from.

     start : (Optional) The starting position in the buffer for reading data.
Default: 0 (start from the first byte).

     size: (Optional) The number of bytes to read from the buffer.
Default: Reads from the starting position to the end of the buffer.

     Return Value:

     The text string generated from the specified portion of the buffer content.

     Behaviour:

     Converts binary data in the specified buffer (buff_num) into a string representation.

     If start and size are not provided, the entire buffer content is converted to a string.

     If the specified range (start + size) exceeds the buffer length, only the available data within the range is converted.

     Non-printable or invalid text characters may result in an incomplete or unexpected string.

     Note:

     start and size work like MID$ but the 1st byte is 0

Example:

IOBUFF.FROMSTRING(0, "Hello, World!")  ' Write "Hello, World!" into buffer 0.

 

text$ = IOBUFF.TOSTRING$(0)      ' Convert entire buffer content to a string.

PRINT text$                      ' Outputs: "Hello, World!"

 

partial$ = IOBUFF.TOSTRING$(0, 7, 5)  ' Read 5 bytes starting from position 7.

PRINT partial$                   ' Outputs: "World"

 

 

 

 

Convert Hexadecimal String to Buffer Content

IOBUFF.FROMHEX(buff_num, var$ [, pos])

     Parameters:

     buff_num:  The ID of the buffer (0–4) to store the converted data.

     var$:  The hexadecimal string to convert.
Must contain only valid hexadecimal characters (0–9 and A–F/a–f) with an even length.
Example: "aabbcc1235".

     pos: (Optional) The starting position in the buffer where the converted data will be stored.
Default: 0 (start writing at the beginning of the buffer).

     Return Value:

     The number of bytes successfully converted and written to the buffer.

     If used as a command, this return value is ignored.

     Behaviour:

     Converts the specified hexadecimal string (var$) into its binary representation and writes it into the buffer (buff_num).

     If pos is specified, the conversion starts from the given position in the buffer.

     If the string contains invalid characters an error is raised.

     If the buffer does not have enough space, it is automatically resized.

 

Example:

bytes_written = IOBUFF.FROMHEX(0, "aabbcc1235") 

PRINT bytes_written                  ' Outputs: 5 (bytes converted and stored).

PRINT IOBUFF.TOHEX$(0)               ' Outputs: "AABBCC1235"

 

IOBUFF.FROMHEX(0, "ff", 10)          ' Write single byte (FF) at position 10.

PRINT IOBUFF.READ(0, 10)             ' Outputs: 255 (decimal value of FF).

 

' Advanced example

IOBUFF.FROMHEX(1, "01020304050607080910")    

IOBUFF.FROMHEX(1, MID$("abcdef123456", 3, 4), 5)  ' Convert "cdef" and write at position 5.

PRINT IOBUFF.TOHEX$(1)               ' Outputs: "0102030405CDEF080910"

 

 

 

Convert Buffer Content to Hexadecimal String

IOBUFF.TOHEX$(buff_num, [, start [, size]])

     Parameters:

     buff_num:  The ID of the buffer (0–4) containing the data to convert.

     start: (Optional) The starting position in the buffer for the conversion.
Default: 0 (start from the beginning of the buffer).

     size: (Optional) The number of bytes to convert from the starting position.
Default: Converts all bytes from start to the end of the buffer.

     Return Value:

      A hexadecimal string representing the converted binary data from the buffer.

     Each byte in the buffer is converted to a two-character hexadecimal value (e.g., 255 → "FF").

     Behaviour:

     Reads the specified range of bytes from the buffer (buff_num) and converts them into a continuous hexadecimal string.

     If start and size are omitted, the entire buffer is converted.

     The conversion does not modify the content of the buffer.

     Note:

     start and size work like MID$ but the 1st byte is 0

 

Example:

IOBUFF.DIM(0, 10)                    ' Allocate buffer 0 with 10 bytes.

IOBUFF.WRITE(0, 0, &hFF)             ' Write byte 255 (hex FF) at position 0.

IOBUFF.WRITE(0, 1, &hAA)             ' Write byte 170 (hex AA) at position 1.

PRINT IOBUFF.TOHEX$(0)               ' Outputs: "FFAA0000000000000000"

 

PRINT IOBUFF.TOHEX$(0, 0, 2)         ' Outputs: "FFAA" (first two bytes).

PRINT IOBUFF.TOHEX$(0, 1, 1)         ' Outputs: "AA" (second byte only).

 

' Advanced example

IOBUFF.DIM(1, 20)                    ' Allocate buffer 1 with 20 bytes.

IOBUFF.WRITE(1, 5, &h12)             ' Write byte 18 (hex 12) at position 5.

IOBUFF.WRITE(1, 6, &h34)             ' Write byte 52 (hex 34) at position 6.

hex_str$ = IOBUFF.TOHEX$(1, 5, 2)    ' Convert bytes at position 5–6 to hex.

PRINT hex_str$                         ' Outputs: "1234"

 

 

Base64 conversion

Encode Buffer Content to Base64

IOBUFF.TOBASE64(buff_num)

Encodes the content of the specified buffer into a Base64-encoded string.

     Parameters:

     buff_num: The ID of the buffer (0–4) containing the data to encode.

     Return Value:

     The size of the Base64-encoded string (in bytes).

     If used as a command, this return value is ignored.

     Behaviour:

     Converts the binary data in the buffer into a Base64 string.

     The original data in the buffer is replaced by the Base64 string

     Automatically resizes the buffer to fit the decoded data.

 

Example:

' Encodes buffer 0 into Base64 and returns the size

Base64Size = IOBUFF.TOBASE64(0)

Print Base64Size ' Displays the size of the Base64 string

 

Decode Base64 String into Buffer Content

IOBUFF.FROMBASE64(buff_num, Base64String$)

Decodes a Base64 string and writes the resulting binary data into the specified buffer.

     Parameters:

     buff_num: The ID of the buffer (0–4) containing the data to decode.

     Base64String$: The Base64-encoded string to decode.

     Return Value:

     The size of the decoded buffer (in bytes).

     If used as a command, this return value is ignored.

     Behaviour:

     Decodes the Base64 string into binary data.

     The original data in the buffer is replaced by the decoded data.

     Automatically resizes the buffer to fit the decoded data.

 

Example:

' Decodes buffer 0 from Base64 format and returns the size

DecodedSize = IOBUFF.FROMBASE64(0)

Print DecodedSize ' Displays the size of the Decoded buffers

 

 

Cryptography

Encrypts the data in the buffer using the AES-128 algorithm with PKCS7 padding

IOBUFF.ENCRYPT(buff_num, key$)

     Parameters:

     buff_num: ID of the buffer (0–4).

     key$: A 16-character string representing the encryption key (128 bits).

     Return Value:

     The size of the encrypted buffer (in bytes).

     If used as a command, this return value is ignored.

     Behaviour:

     Encrypts the content of the specified buffer in place using the AES-128 algorithm.

     The original data in the buffer is replaced by its encrypted form.

     The key must be exactly 16 characters long.

     The encrypted buffer can only be decrypted using the same key.

     The buffer content is padded according to the PKCS7 method to ensure alignment with AES-128 block size (16 bytes).

 

 

Decrypts data in the buffer using the AES-128 algorithm

IOBUFF.DECRYPT(buff_num, key$)

     Parameters:

     buff_num: ID of the buffer (0–4).

     key$: The 16-character encryption key used during encryption.

     Return Value:

     The size of the decrypted buffer (in bytes).

     If used as a command, this return value is ignored.

     Behaviour:

     Decrypts the content of the specified buffer in place using the AES-128 algorithm.

     The original encrypted data in the buffer is replaced by its decrypted form.

     The key must match the one used for encryption.

     The buffer is unpadded to its original content according to the PKCS7 method.

 

Example:

key$ = "my_Personal_key1"             ' Sets the crypting key

IObuff.FromString(0, "Hello, World!") ' Converts a string into IO Buffer

print IObuff.Encrypt(0, key$)         ' Encrypts using a 16 characters key

wlog IObuff.ToHex$(0)                 ' Shows the result in Hex format

 

wlog IObuff.Decrypt(0, key$)  ' Decrypts using the same key

wlog IObuff.ToString$(0)   ' shows the decrypted string (same as the original)

 

 

CRC Function:

Calculates a Cyclic Redundancy Check (CRC) value for a given input buffer.

IOBUFF.CRC(buff_num, nb_bits, polynom, initial_value, ref_in, ref_out, xor_out)

     Parameters:

     buff_num: ID of the buffer (0–4) containing the data for which the CRC needs to be calculated.

     nb_bits: Bit order for the CRC calculation. It can be set from 8 to 32 (i.e. 16 for a 16-bit CRC).

     polynom: CRC polynomial used in the calculation .

     initial_value: Initial CRC value. This value is used to initialise the CRC calculation.

     ref_in: Input reflection flag (1 for true, 0 for false). If set to 1, the input data is processed in reverse bit order.

     ref_out: Output reflection flag (1 for true, 0 for false). If set to 1, the CRC output is reflected (i.e., processed in reverse bit order).

     xor_out: Final XOR value. This value is applied to the final CRC value before returning it.

     Return Value:

     The calculated CRC value, or 0 if the input buffer is empty.

     Behaviour:

     This function computes the CRC value for the data in the specified I/O buffer. It supports customizable CRC parameters to accommodate different CRC algorithms. You can define the polynomial, initial value, and final XOR value, and also specify whether to reflect the input data and/or output CRC.

     Nb_bits  specifies the bit size of the CRC (e.g., 16-bit, 32-bit).

     polynom defines the polynomial used for the calculation (e.g., 0x4c11db7 for CRC-32).

     initial_value is the initial CRC value, commonly 0xffffffff for CRC-32.

     ref_in and ref_out allow for reflection of input and output bits.

     xor_out applies an XOR operation to the final CRC value before returning.

     Note:

     Ensure that the I/O buffer contains the data you want to calculate the CRC for before calling this function. If the buffer is empty, the function returns 0.

 

CRC Demo Code

This demo code demonstrates how to calculate various CRC (Cyclic Redundancy Check) values for the string "123456789". It uses a variety of CRC algorithms, from CRC-8 to CRC-32, with different settings for each. The results are compared with expected CRC values, which can be verified using online tools like crc-calculator.

 

'CRC demo code

'references to https://crccalc.com/

a$ = "123456789"

wlog IObuff.fromstring(0, a$)

 

wlog "Algo CRC ", "Expected", "Result"

wlog "CRC-8/AUTOSAR", hex$(0xDF), hex$(IObuff.CRC(0, 8, 0x2F, 0xFF, 0, 0, 0xFF))

wlog "CRC-8/BLUETOOTH", hex$(0x26), hex$(IObuff.CRC(0, 8, 0xA7, 0x00, 1, 1, 0x00))

wlog "CRC-8/CDMA2000", hex$(0xDA), hex$(IObuff.CRC(0, 8, 0x9B, 0xFF, 0, 0, 0x00))

wlog "CRC-8/DARC", hex$(0x15), hex$(IObuff.CRC(0, 8, 0x39, 0x00, 1, 1, 0x00))

wlog "CRC-8/DVB-S2", hex$(0xBC), hex$(IObuff.CRC(0, 8, 0xD5, 0x00, 0, 0, 0x00))

wlog "CRC-8/GSM-A", hex$(0x37), hex$(IObuff.CRC(0, 8, 0x1D, 0x00, 0, 0, 0x00))

wlog "CRC-8/GSM-B", hex$(0x94), hex$(IObuff.CRC(0, 8, 0x49, 0x00, 0, 0, 0xFF))

wlog "CRC-8/HITAG", hex$(0xB4), hex$(IObuff.CRC(0, 8, 0x1D, 0xFF, 0, 0, 0x00))

wlog "CRC-8/I-432-1", hex$(0xA1), hex$(IObuff.CRC(0, 8, 0x07, 0x00, 0, 0, 0x55))

wlog "CRC-8/I-CODE", hex$(0x7E), hex$(IObuff.CRC(0, 8, 0x1D, 0xFD, 0, 0, 0x00))

wlog "CRC-8/LTE", hex$(0xEA), hex$(IObuff.CRC(0, 8, 0x9B, 0x00, 0, 0, 0x00))

wlog "CRC-8/MAXIM-DOW", hex$(0xA1), hex$(IObuff.CRC(0, 8, 0x31, 0x00, 1, 1, 0x00))

wlog "CRC-8/MIFARE-MAD", hex$(0x99), hex$(IObuff.CRC(0, 8, 0x1D, 0xC7, 0, 0, 0x00))

wlog "CRC-8/NRSC-5", hex$(0xF7), hex$(IObuff.CRC(0, 8, 0x31, 0xFF, 0, 0, 0x00))

wlog "CRC-8/OPENSAFETY", hex$(0x3E), hex$(IObuff.CRC(0, 8, 0x2F, 0x00, 0, 0, 0x00))

wlog "CRC-8/ROHC", hex$(0xD0), hex$(IObuff.CRC(0, 8, 0x07, 0xFF, 1, 1, 0x00))

wlog "CRC-8/SAE-J1850", hex$(0x4B), hex$(IObuff.CRC(0, 8, 0x1D, 0xFF, 0, 0, 0xFF))

wlog "CRC-8/SMBUS", hex$(0xF4), hex$(IObuff.CRC(0, 8, 0x07, 0x00, 0, 0, 0x00))

wlog "CRC-8/TECH-3250", hex$(0x97), hex$(IObuff.CRC(0, 8, 0x1D, 0xFF, 1, 1, 0x00))

wlog "CRC-8/WCDMA", hex$(0x25), hex$(IObuff.CRC(0, 8, 0x9B, 0x00, 1, 1, 0x00))

wlog "CRC-16/ARC", hex$(0xBB3D), hex$(IObuff.CRC(0, 16, 0x8005, 0x0000, 1, 1, 0x0000))

wlog "CRC-16/CDMA2000", hex$(0x4C06), hex$(IObuff.CRC(0, 16, 0xC867, 0xFFFF, 0, 0, 0x0000))

wlog "CRC-16/CMS", hex$(0xAEE7), hex$(IObuff.CRC(0, 16, 0x8005, 0xFFFF, 0, 0, 0x0000))

wlog "CRC-16/DDS-110", hex$(0x9ECF), hex$(IObuff.CRC(0, 16, 0x8005, 0x800D, 0, 0, 0x0000))

wlog "CRC-16/DECT-R", hex$(0x007E), hex$(IObuff.CRC(0, 16, 0x0589, 0x0000, 0, 0, 0x0001))

wlog "CRC-16/DECT-X", hex$(0x007F), hex$(IObuff.CRC(0, 16, 0x0589, 0x0000, 0, 0, 0x0000))

wlog "CRC-16/DNP", hex$(0xEA82), hex$(IObuff.CRC(0, 16, 0x3D65, 0x0000, 1, 1, 0xFFFF))

wlog "CRC-16/EN-13757", hex$(0xC2B7), hex$(IObuff.CRC(0, 16, 0x3D65, 0x0000, 0, 0, 0xFFFF))

wlog "CRC-16/GENIBUS", hex$(0xD64E), hex$(IObuff.CRC(0, 16, 0x1021, 0xFFFF, 0, 0, 0xFFFF))

wlog "CRC-16/GSM", hex$(0xCE3C), hex$(IObuff.CRC(0, 16, 0x1021, 0x0000, 0, 0, 0xFFFF))

wlog "CRC-16/IBM-3740", hex$(0x29B1), hex$(IObuff.CRC(0, 16, 0x1021, 0xFFFF, 0, 0, 0x0000))

wlog "CRC-16/IBM-SDLC", hex$(0x906E), hex$(IObuff.CRC(0, 16, 0x1021, 0xFFFF, 1, 1, 0xFFFF))

wlog "CRC-16/ISO-IEC-14443-3-A", hex$(0xBF05), hex$(IObuff.CRC(0, 16, 0x1021, 0xC6C6, 1, 1, 0x0000))

wlog "CRC-16/KERMIT", hex$(0x2189), hex$(IObuff.CRC(0, 16, 0x1021, 0x0000, 1, 1, 0x0000))

wlog "CRC-16/LJ1200", hex$(0xBDF4), hex$(IObuff.CRC(0, 16, 0x6F63, 0x0000, 0, 0, 0x0000))

wlog "CRC-16/M17", hex$(0x772B), hex$(IObuff.CRC(0, 16, 0x5935, 0xFFFF, 0, 0, 0x0000))

wlog "CRC-16/MAXIM-DOW", hex$(0x44C2), hex$(IObuff.CRC(0, 16, 0x8005, 0x0000, 1, 1, 0xFFFF))

wlog "CRC-16/MCRF4XX", hex$(0x6F91), hex$(IObuff.CRC(0, 16, 0x1021, 0xFFFF, 1, 1, 0x0000))

wlog "CRC-16/MODBUS", hex$(0x4B37), hex$(IObuff.CRC(0, 16, 0x8005, 0xFFFF, 1, 1, 0x0000))

wlog "CRC-16/NRSC-5", hex$(0xA066), hex$(IObuff.CRC(0, 16, 0x080B, 0xFFFF, 1, 1, 0x0000))

wlog "CRC-16/OPENSAFETY-A", hex$(0x5D38), hex$(IObuff.CRC(0, 16, 0x5935, 0x0000, 0, 0, 0x0000))

wlog "CRC-16/OPENSAFETY-B", hex$(0x20FE), hex$(IObuff.CRC(0, 16, 0x755B, 0x0000, 0, 0, 0x0000))

wlog "CRC-16/PROFIBUS", hex$(0xA819), hex$(IObuff.CRC(0, 16, 0x1DCF, 0xFFFF, 0, 0, 0xFFFF))

wlog "CRC-16/RIELLO", hex$(0x63D0), hex$(IObuff.CRC(0, 16, 0x1021, 0xB2AA, 1, 1, 0x0000))

wlog "CRC-16/SPI-FUJITSU", hex$(0xE5CC), hex$(IObuff.CRC(0, 16, 0x1021, 0x1D0F, 0, 0, 0x0000))

wlog "CRC-16/T10-DIF", hex$(0xD0DB), hex$(IObuff.CRC(0, 16, 0x8BB7, 0x0000, 0, 0, 0x0000))

wlog "CRC-16/TELEDISK", hex$(0x0FB3), hex$(IObuff.CRC(0, 16, 0xA097, 0x0000, 0, 0, 0x0000))

wlog "CRC-16/TMS37157", hex$(0x26B1), hex$(IObuff.CRC(0, 16, 0x1021, 0x89EC, 1, 1, 0x0000))

wlog "CRC-16/UMTS", hex$(0xFEE8), hex$(IObuff.CRC(0, 16, 0x8005, 0x0000, 0, 0, 0x0000))

wlog "CRC-16/USB", hex$(0xB4C8), hex$(IObuff.CRC(0, 16, 0x8005, 0xFFFF, 1, 1, 0xFFFF))

wlog "CRC-16/XMODEM", hex$(0x31C3), hex$(IObuff.CRC(0, 16, 0x1021, 0x0000, 0, 0, 0x0000))

wlog "CRC-32/AIXM", hex$(0x3010BF7F), hex$(IObuff.CRC(0, 32, 0x814141AB, 0x00000000, 0, 0, 0x00000000))

wlog "CRC-32/AUTOSAR", hex$(0x1697D06A), hex$(IObuff.CRC(0, 32, 0xF4ACFB13, 0xFFFFFFFF, 1, 1, 0xFFFFFFFF))

wlog "CRC-32/BASE91-D", hex$(0x87315576), hex$(IObuff.CRC(0, 32, 0xA833982B, 0xFFFFFFFF, 1, 1, 0xFFFFFFFF))

wlog "CRC-32/BZIP2", hex$(0xFC891918), hex$(IObuff.CRC(0, 32, 0x04C11DB7, 0xFFFFFFFF, 0, 0, 0xFFFFFFFF))

wlog "CRC-32/CD-ROM-EDC", hex$(0x6EC2EDC4), hex$(IObuff.CRC(0, 32, 0x8001801B, 0x00000000, 1, 1, 0x00000000))

wlog "CRC-32/CKSUM", hex$(0x765E7680), hex$(IObuff.CRC(0, 32, 0x04C11DB7, 0x00000000, 0, 0, 0xFFFFFFFF))

wlog "CRC-32/ISCSI", hex$(0xE3069283), hex$(IObuff.CRC(0, 32, 0x1EDC6F41, 0xFFFFFFFF, 1, 1, 0xFFFFFFFF))

wlog "CRC-32/ISO-HDLC", hex$(0xCBF43926), hex$(IObuff.CRC(0, 32, 0x04C11DB7, 0xFFFFFFFF, 1, 1, 0xFFFFFFFF))

wlog "CRC-32/JAMCRC", hex$(0x340BC6D9), hex$(IObuff.CRC(0, 32, 0x04C11DB7, 0xFFFFFFFF, 1, 1, 0x00000000))

wlog "CRC-32/MEF", hex$(0xD2C22F51), hex$(IObuff.CRC(0, 32, 0x741B8CD7, 0xFFFFFFFF, 1, 1, 0x00000000))

wlog "CRC-32/MPEG-2", hex$(0x0376E6E7), hex$(IObuff.CRC(0, 32, 0x04C11DB7, 0xFFFFFFFF, 0, 0, 0x00000000))

wlog "CRC-32/XFER", hex$(0xBD0BE338), hex$(IObuff.CRC(0, 32, 0x000000AF, 0x00000000, 0, 0, 0x00000000))

 

 

Bit Operations on Buffer Data

These bit operations provide low-level control over the buffer's contents, enabling manipulation of individual bits in each byte.

 

Get the Value of a Specific Bit in a Byte

IObuff.bit(buff_num, position, bit)

     Parameters:

     buff_num: The ID of the buffer (0–4).

     position: The byte position in the buffer to examine.

     bit: The bit position within the byte (0–7).

     0 is the least significant bit (rightmost bit).

     7 is the most significant bit (leftmost bit).

     Return Value:

     The value of the specified bit within the byte.

     Returns 0 if the bit is clear (0).

     Returns 1 if the bit is set (1).

     Behaviour:

     Extracts the bit value from the specified byte in the buffer.

     Does not modify the buffer content.

 

Example:

IOBUFF.DIM(0, 2)                 ' Allocate buffer 0 with 2 bytes.

IOBUFF.WRITE(0, 0, &hF0)         ' Write byte 240 (hex F0) at position 0.

PRINT IOBUFF.BIT(0, 0, 7)        ' Outputs: 1 (bit 7 of 0th byte is set).

PRINT IOBUFF.BIT(0, 0, 3)        ' Outputs: 0 (bit 3 of 0th byte is clear).

 

 

 

Set a Specific Bit in a Byte

IObuff.setbit(buff_num, position, bit)

     Parameters:

     buff_num: The ID of the buffer (0–4).

     position: The byte position in the buffer where the bit will be set.

     bit: The bit position (0–7) to be set to 1.

     0 is the least significant bit (rightmost bit).

     7 is the most significant bit (leftmost bit).

     Return Value:

     The value of the bit after setting (should always return 1).

     The return value is ignored if used as a command.

     Behaviour:

     Sets the specified bit in the specified byte of the buffer to 1.

     Does not affect other bits in the byte.

     The function returns 1 but this is typically ignored when used as a command.

 

Example:

IOBUFF.DIM(0, 1)                 ' Allocate buffer 0 with 1 byte.

IOBUFF.WRITE(0, 0, &h01)         ' Write byte 1 (hex 01) at position 0.

PRINT IOBUFF.SETBIT(0, 0, 7)     ' Set bit 7 in byte 0. Returns: 1.

PRINT IOBUFF.BIT(0, 0, 7)        ' Outputs: 1 (bit 7 is now set).

 

 

Clear a Specific Bit in a Byte

IObuff.clearbit(buff_num, position, bit)

     Parameters:

     buff_num: The ID of the buffer (0–4).

     position: The byte position in the buffer where the bit will be cleared.

     bit: The bit position (0–7) to be cleared to 0.

     0 is the least significant bit (rightmost bit).

     7 is the most significant bit (leftmost bit).

     Return Value:

     The value of the bit after clearing (should always return 0).

     The return value is ignored if used as a command.

     Behaviour:

     Clears the specified bit in the specified byte of the buffer, setting it to 0.

     Does not affect other bits in the byte.

     The function returns 0 but this is typically ignored when used as a command.

 

Example:

IOBUFF.DIM(0, 1)                 ' Allocate buffer 0 with 1 byte.

IOBUFF.WRITE(0, 0, &hFF)         ' Write byte 255 (hex FF) at position 0.

PRINT IOBUFF.CLEARBIT(0, 0, 7)   ' Clear bit 7 in byte 0. Returns: 0 (ignored).

PRINT IOBUFF.BIT(0, 0, 7)        ' Outputs: 0 (bit 7 is now cleared).

 

 

Toggle a Specific Bit in a Byte

IObuff.togglebit(buff_num, position, bit)

     Parameters:

     buff_num: The ID of the buffer (0–4).

     position: The byte position in the buffer where the bit will be toggled.

     bit: The bit position (0–7) to toggle

     0 is the least significant bit (rightmost bit).

     7 is the most significant bit (leftmost bit).

     Return Value:

     The new value of the toggled bit (0 or 1).

     The return value is ignored if used as a command.

     Behaviour:

     Toggles the specified bit in the specified byte of the buffer:

     If the bit is 0, it becomes 1.

     If the bit is 1, it becomes 0.

     Does not affect other bits in the byte.

     The function returns the new value of the bit but this is typically ignored when used as a command.

 

Example:

IOBUFF.DIM(0, 1)                 ' Allocate buffer 0 with 1 byte.

IOBUFF.WRITE(0, 0, &h0F)         ' Write byte 15 (hex 0F) at position 0.

PRINT IOBUFF.TOGGLEBIT(0, 0, 3)  ' Toggle bit 3 in byte 0. Returns: 0.

PRINT IOBUFF.BIT(0, 0, 3)        ' Outputs: 0 (bit 3 is now toggled).

 

Buffer copy

Copy Data from One Buffer to Another

IObuff.copy(dest_buff_num [,pos]) , (source_buff_num, [, start [, size]])

     Parameters:

     dest_buff_num: The ID of the destination buffer (0–4) where the data will be copied to.

     pos: (optional) The position within the destination buffer where the copy will begin.
Defaults to 0 if not specified.

     source_buff_num: The ID of the source buffer (0–4) from which the data will be copied.

     start: (optional) The starting byte in the source buffer from where copying will begin.
Defaults to 0 if not specified.

     size: (optional) The number of bytes to copy from the source buffer.
If omitted, it will copy from the start position to the end of the source buffer.

     Return Value:

     The number of bytes successfully copied to the destination buffer.

     If used as a command, the return value is ignored.

     Behaviour:

     Copies data from a source buffer to a destination buffer.

     If start and size are specified, only the selected portion of the source buffer will be copied.

     If pos is specified, it determines where in the destination buffer the data will be copied to.

     The content of the destination buffer is replaced or modified by the copied data, depending on the pos value.

     The copy operation automatically resizes the destination buffer if the size exceeds its capacity.

 

 

Example:

IOBUFF.DIM(1, 10)             ' Allocate 10 bytes for buffer 1 (source).

IOBUFF.WRITE(1, 0, &h01)      ' Write byte 1 at position 0 in buffer 1.

IOBUFF.WRITE(1, 1, &h02)      ' Write byte 2 at position 1 in buffer 1.

IOBUFF.COPY(0, 0), (1, 0, 2)  ' Copy 2 bytes from buffer 1 (starting from position 0) to buffer 0 (starting at position 0).

PRINT IOBUFF.TOHEX$(0)        ' Outputs: "0102" (2 bytes copied to buffer 0).

 

Code examples :

 

UDP - use the remote controller APP for IOS devices (iphone and Ipad)

 

image

 

 

' I/O buffers example using the RCWController

' available in the IOS app store.

' It uses by default the port 10000

' The APP sends a block of 10 bytes that

' will be printed in the console on the same line

udp.begin 10000

 

' define the place where jump on message reception

onudp received

wait

 

received:

' read the incoming data in the buffer 0

udp.read_iobuff(0)

size = iobuff.len(0)

print "received "; size; " bytes"

for z = 0 to 9

  ' read and print 1 byte at the time on the same line

  print iobuff.read(0, z),

next z

Print ' print an empty line

return

 

 

File read and transfer to the serial port by blocks

 

' I/O BUFFERS example using files

' read a file in blocks of 512 characters

' and send them to the serial port (print)

fileName$ = "/data8.txt"

block_size = 512 ' size of the block to be read

file_size = file.size(fileName$)

print "File size "; file_size

print file_size

for z = 0 to file_size - 1 step block_size

  file.read_iobuff(0), fileName$, z, block_size

  ' send the block on the serial port (print)

  serial.write_iobuff(0)

next 

 

Serial port data logger

 

' I/O BUFFERS example to create a serial data logger

' receive bytes from the serial port and

' write them into the file /mylog.txt

' all the characters will be recorded

' including the ASCII 0 (NUL)

filename$ = "/mylog.txt"

 

' define the place where jump on message reception

onserial received

wait

 

received:

' waits for 10 millisec giving time to receive all the data

pause 10

' read the incoming data in the buffer 0

serial.read_iobuff(0)

size = iobuff.len(0)

print "received "; size; " bytes"

' appends the received data to the file

file.append_iobuff(0), filename$

return

 

 

WIRING

image

 

This diagram shows pin mapping for the popular ESP32 DEV Board module.

(*) pins GPIO6 to GPIO11 are not available.

 

 

Annex 32, as it supports by default the M5stack wiring, assumes the following pins already allocated/dedicated

 

PIN

FUNCTION

DESCRIPTION

32

PWM BL TFT

Backlight TFT display

33

RST TFT

RST pin TFT

27

D/C TFT

D/C pin TFT

14

CS TFT

CS pin TFT

23

SPI MOSI

SPI MOSI pin (shared with SD and TFT)

19

SPI MISO

SPI MISO pin (shared with SD and TFT)

18

SPI SCK

SPI CLOCK pin (shared with SD and TFT)

4

CS SDCARD

CS pin SDCARD

0

CS TFT TOUCH

CS pin Touchscreen (from the TFT)

 

 

 

3

RX0

Serial Port RX pin

1

TX0

Serial Port TX pin

 

 

 

25

SPEAKER

Speaker or mono audio output

21

SDA I2C

I2C SDA pin

22

SCL I2C

I2C SCL pin

 

 

 

2

I2S DATA

Audio DAC I2S DATA pin

5

I2S BCLK

Audio DAC I2S BCLK pin

26

I2S LRCK

Audio DAC I2S LRCK pin

16

PSRAM

Optional PSRAM

17

PSRAM

Optional PSRAM

 

 

image

 

DIGITAL I/O

 

Pin numbers correspond directly to the ESP32 GPIO pin numbering.

The function of the pin (input / output) must be defined before using the function PIN.MODE as below :

 

To define the pin 5 as input :

PIN.MODE 15, INPUT

 

To define the pin 4 as input with a pullup:

PIN.MODE 4, INPUT, PULLUP

 

To define the pin 4 as input with a pulldown:

PIN.MODE 4, INPUT, PULLDOWN

 

To define the pin 2 as output

PIN.MODE 2, OUTPUT

 

To define the pin 2 as output open collector

PIN.MODE 2, OUTPUT, 1

 

Pins may also serve other functions, like Serial, I2C, SPI.

These functions are normally activated by the corresponding library.

 

The value from a pîn can be read as shown below :

A = PIN(5) read from GPIO5 pin

 

The pin value can be set as below

PIN(2)= 0 set 0 on the GPIO2 pin

 

The pin value (0 or 1) can also be easily toggled by subtracting it from 1 (because 1-0=1 and 1-1=0), eg:

PIN(2)= 1 - PIN(2) toggles the value of GPIO2 pin

 

This part is applicable only to the “classic” ESP32 as the other members of the family have different H/W characteristics and

Although pin numbers can be from 0 to 39, gpio pins 6 to 11 should not be used because they are connected to flash memory chips on most modules. Trying to use these pins as IOs will likely cause the program to crash.

 

Pins 34 to 39 are INPUT only and cannot be configured as PULLUP or PULLDOWN.

Pins 0 to 33 can be INPUT, OUTPUT INPUT, PULLUP or INPUT, PULLDOWN.

Note:

If the module is equipped with PSRAM, the gpio pins 16 and 17 are reserved and must not be used.

 

The command PIN.STRENGTH can be used to define the drive capability of the output pins from a scale from 0 to 3.

For example, the following command set the pin 15 with a drive capability of 2.

PIN.STRENGTH 15, 2

The ESP32 provides four drive strength levels for its GPIO pins:

         0: Weakest drive strength, approximately 5 mA.

         1: Low drive strength, approximately 10 mA.

         2: Medium drive strength, approximately 20 mA.

         3: Maximum drive strength, approximately 40 mA.

PIN SERIAL SHIFTING

Annex  supports two commands for serially shifting data:

-       PIN.SHIFTOUT for sending data

-       PIN.SHIFTIN for receiving data.

 Both commands allow control over bit order, bit count, and timing delays.

These commands are in particular useful to control external shift registers or simple SPI bus devices.

The PIN.SHIFTOUT command is used to send data out serially through a specified data pin. It shifts out data bits one at a time, synchronised with a clock signal. The command allows you to specify the order in which bits are shifted (least significant bit first or most significant bit first), the number of bits to shift, and the timing delay between each bit. This command drives the data pin high or low according to the current bit in the data, and toggles the clock pin to indicate when each bit should be read by the receiving device.

Syntax:

PIN.SHIFTOUT pin_data, pin_clk, data [, bit_order] [, nb_bits] [, delay_us]

Parameters:

     pin_data:

     Description: GPIO pin number used for the data line.

     pin_clk:

     Description: GPIO pin number used for the clock line that synchronises the data transfer.

     data :

     Description: Data to be shifted out.

     Bit_order (optional):

     Description: Specifies the bit order for shifting data. Possible values:

     0 (default) : LSBFIRST Least Significant Bit first.

     1           : MSBFIRST Most Significant Bit first.

     Nb_bits (optional):

     Description: Number of bits to shift out from the data. Default is 8 bits.

     Delay_us (optional):

     Description: Delay in microseconds between each bit shift. Default is 1 microsecond.

Details:

     This command uses critical section management to ensure atomic operations during the data shift process. However, because it relies on software delays, the timing may not be very precise, particularly  for delays shorter than 10 microseconds

     Bit Order: The bit order determines whether the least significant bit (LSBFIRST) or the most significant bit (MSBFIRST) is shifted out first.

     Number of Bits: Specifies how many bits from the data value will be shifted out. If not specified, the default is 8 bits.

     Delay: Introduces a delay between the setting of the data pin and toggling of the clock pin to control the timing of the data shift.

Example:

 

PIN.SHIFTOUT 13, 14, 0xFF   ' Shift out 8 bits from data 0xFF

PIN.SHIFTOUT 13, 14, 0xFF, 1' Shift out 8 bits from data 0xFF with MSBFIRST

PIN.SHIFTOUT 13, 14, 0xFFFF, 1, 16, 2  ' Shift out 16 bits from data 0xFFFF with MSBFIRST, 2 µs delay

 

 

The PIN.SHIFTIN function is used to receive data serially through a specified data pin. It shifts in data bits one at a time, using a clock signal to determine when to sample the data pin. Similar to PIN.SHIFTOUT, it allows you to specify the bit order, the number of bits to shift, and the timing delay between each bit. This  function reads the state of the data pin in sync with the clock signal, capturing each bit as it arrives and storing it in a variable.

Syntax:

PIN.SHIFTIN( pin_data, pin_clk [, bit_order] [, nb_bits] [, delay_us] )

Parameters:

     pin_data:

     Description: GPIO pin number used for the data line.

     pin_clk :

     Description: GPIO pin number used for the clock line that synchronises the data reading.

     Bit_order (optional):

     Description: Specifies the bit order for shifting data. Possible values:

     0 (default) : LSBFIRST Least Significant Bit first.

     1           : MSBFIRST Most Significant Bit first.

     Nb_bits (optional):

     Description: Number of bits to read from the data line. Default is 8 bits.

     Delay_us (optional):

     Description: Delay in microseconds between each bit read. Default is 1 microsecond.

Details:

     This command uses critical section management to ensure atomic operations during the data shift process. However, because it relies on software delays, the timing may not be very precise, particularly  for delays shorter than 10 microseconds

     Bit Order: Determines whether the least significant bit (LSBFIRST) or the most significant bit (MSBFIRST) is read first.

     Number of Bits: Specifies how many bits will be read from the data line. If not specified, the default is 8 bits.

     Delay: Introduces a delay between each bit read, allowing for control over timing and synchronisation.

Example:

 

A = PIN.SHIFTIN(21, 22) ' Shift in 8 bits from data pin 21 with clock pin 22

B = PIN.SHIFTIN(13, 14, 1) ' Shift in 8 bits from data pin 13 with clock pin 14, reading MSBFIRST

C = PIN.SHIFTIN(13, 14, 1, 16, 2)  ' Shift in 16 bits from data pin 13 with clock pin 14, reading MSBFIRST, 2 µs delay

 

PIN INTERRUPTS

The INTERRUPT command permits to trigger an event when the signal on an input pin changes.

The interrupt is triggered BOTH when the signal goes from LOW to HIGH and HIGH to LOW.

Therefore a momentary pulse actually generates 2 interrupts which need testing for Hi or Lo as appropriate.

Example:

 

pin.mode 12, input   ' set pin 12 as input
interrupt 12, change_input  ' set interrupt on pin 12

wait

change_input:
if pin(12) = 0 then return   ' if the pin is low, returns back
print "The pin changed to HIGH"
Return

 

It is possible to add an optional parameter, mode, that specify if the interrupt must be generated on the rising edge, the falling edge or on change:

Syntax:

INTERRUPT pin_no, {OFF | label} [, mode]

 

Parameters:

- pin_no: The input pin number for which the interrupt is being defined. It must be an integer value ranging from 0 to the maximum pin number supported by the specific variant of the ESP32 (-s2, -c3, -s3).

- label: The branch label to which the program will jump when the designated input pin signal changes. It must be a valid label in the program's context.

- OFF: Use this keyword to remove the interrupt associated with the specified input pin.

- mode (optional): An integer parameter or keyword specifying the trigger condition for the interrupt. It can take one of the following values:

  - 1, RISING: Rising edge trigger

  - 2, FALLING: Falling edge trigger

  - 3, CHANGE: Any change in signal trigger (default if 'mode' parameter is omitted)

 

Examples:

-       To set up an interrupt that jumps to the 'PIN5_CHANGE' label when a rising edge is detected on pin 5:

 

INTERRUPT 5, PIN5_CHANGE, RISING

 

-        To remove the interrupt associated with pin 5:

INTERRUPT 5, OFF

 

-       To set up an interrupt that jumps to the 'PIN13_TRANSITION' label when any change is detected on pin 13:

INTERRUPT 13, PIN13_TRANSITION , CHANGE

 

-       To set up an interrupt without specifying the trigger mode (defaulting to any change in signal) that jumps to the 'PIN7_UPDATE' label when pin 7 signal changes:

INTERRUPT 7, PIN7_UPDATE

 

Note:

-       Interrupts can provide a way to respond to external events asynchronously.

-       The optional 'mode' parameter allows you to customize the trigger condition for the interrupt to match your specific application requirements.

The input pin (pin_no) must be previously configured as an input before setting up the interrupt.

Ensure that the specified 'pin_no' and 'label' are valid within the scope of your program.

The maximum pin number supported by the ESP32 variant should be considered based on the specific model (-s2, -c3, -s3).

Analog inputs

Annex32  has 8 ADC pins with 12 bits resolution which are available to users.

The function ADC(pin) can be used to read voltage on the pins defined in the table below.

 

GPIO Pins Available as Analog Input

32

33

34

35

36

37

38

39

 

To read the voltage applied at the pin, the function ADC can be used as below :

 

print ADC(39)' read voltage from the pin 39

 

The voltage range is  0 ... 3.3V and the corresponding range returned by the function is 0 … 4095.

 

NOTE: When using the function ADC,the pin is automatically configured as an Analog Input

TOUCH inputs

Annex32 supports an additional ESP32 feature, the capacitive touch.

With this feature, it is possible to activate inputs with your fingers with just one wire attached to the pin.

The function PIN.TOUCH(pin) can be used to read the touch value on the pins defined in the table below.

 

GPIO Pins Available as Touch Input

0

2

4

12

13

14

15

27

32

33

 

The function PIN.TOUCH(pin) returns a value that drops as soon as the pin is touched.

Normal values are around 70 when not touched and lower than 20 when touched.

 

'Pin Touch example

'Place a wire on pin 13 and look how the value changes when touching it

while 1

  print pin.touch(13)

  pause 100

wend

end

 

Analog outputs

Annex32  has 2 DAC output pins with 8 bits resolution which are available to users.

This function is available only on  the pin GPIO25 and GPIO26

The function PIN.DAC pin, value can be used to set the output voltage on the pin.

 

The output voltage is approximately 0V @ value=0 and 3.3V @ value=255

 

'DAC output example

PIN.DAC 25, 128 'Set the pin 25 at ~1.65V

PIN.DAC 26, 64  'Set the pin 26 at ~0.82V

 

NOTE: When using the command PIN.DAC,the pin is automatically configured as an Analog Output

Hardware interfaces:

The ESP32 contains several H/W interfaces that can be controlled by Annex32 WI-Fi using specific commands and functions.

PWM

This functionality permits to control the output duty cycle of any pin, acting like an analog output.

There are 16 channels available where each channel can be connected to any output pin.

 

To use it, the function must first be configured using the command PWM.SETUP and then the value can be set using the command PWM.OUT.

 

The frequency and the resolution can be defined individually for each channel.

The resolution can be from 1 to 15 bits.

The maximal frequency is 80000000 / 2^resolution

 

This table resumes the maximal frequency available in function of the resolutions and the associated range:

 

RESOLUTION (BITS)

MAX FREQUENCY

VALUE RANGE

1

40000000

0 ... 1

2

20000000

0 ... 3

3

10000000

0 ... 7

4

5000000

0 .. 15

5

2500000

0 .. 31

6

1250000

 0 … 63

7

625000

0 … 127

8

312500

0 … 255

9

156250

0 … 511

10

78125

0 … 1023

11

39063

0 … 2047

12

19531

0 … 4095

13

9766

0 … 8191

14

4883

0 … 16383

15

2441

0 … 32767

 

All the output pins can be used for the PWM (the pins from GPIO0 to GPIO33).

As there are 16 channels, up to 16 individual output pins can be used.

If using the M5Stack, the channels 0 and 7 are already reserved and attached to the pins 25 and 32.

In this case the channels 0 and 7 must be avoided.

 

To setup an output pin as a PWM output the following command must be used :

PWM.SETUP pin, channel, default_value,  [,frequency] [,resolution]

 

For example, to define a PWM output at 5KHz with 12 bits of resolution on the pin GPIO5 the command is :

PWM.SETUP 5, 1, 2048, 5000, 12 ‘ pin 5, channel 1, output value at 2048 (50%), 5KHz, 12 bits

As the resolution is set at 12 bits, the range will be from 0 to 4095 (hence 2048 is 50%).

 

To define a PWM output at 10KHz with 8 bits on the pin GPIO22, the command is :

PWM.SETUP 22, 2, 128  ‘ pin 22, channel 2, value 128 ( 50%) , freq 10 KHz (default), resolution 8 bits (default)

 

As soon as the command PWM.SETUP is done, the PWM output can simply be changed with the command :

 

PWM.OUT channel, value

 

For example, the command

PWM.OUT 1, 1000

Set the channel 1 (associated with the pin 5 in the previous command) at 1000.

 

And the command

PWM.OUT 2, 10

Set the channel 2 (associated with the pin 22 in the previous command) at 10

 

To disconnect the pin from the PWM output the command is :

PWM.SETUP pin, OFF.

 

For example the command

PWM.SETUP 5, OFF

Disconnect the pin 5 fro the PWM

 

NOTE for the M5stack:

The channel 0 is dedicated to the internal speaker (pin 25)

The channel 7 is dedicated to the TFT backlight (pin 32)

 

 

SERVO

This functionality exposes the ability to control RC (hobby) servo motors.

There are no special commands dedicated as the servo can simply be used by setting a PWM pin with a 50Hz frequency.

For example, the following command :

PWM.SETUP 17, 1, 150, 50, 12

Defines the pin 17 with the pwm channel 1 with a default value of 150 (frequency at 50 Hz and resolution at 12 bits).

 

The output can then be set with the command

PWM.OUT 1, 307‘ channel 1 set at 90°

 

 

A typical servo motor expects to be updated every 20 ms with a pulse between 1 ms and 2 ms, or in other words, between a 5 and 10% duty cycle on a 50 Hz waveform. With a 1.5 ms pulse, the servo motor will be at the natural 90 degree position. With a 1 ms pulse, the servo will be at the 0 degree position, and with a 2 ms pulse, the servo will be at 180 degrees. You can obtain the full range of motion by updating the servo with any value in between.

image

Using a 12 bits resolution (max value = 4095 for 20 msec pulse (1/50 Hz)), the theoretical values should be :

  0° -> 1 msec -> 1/20 * 4096 = 205

90° -> 1.5 msec -> 1.5/20 * 4096 = 307

180° -> 2 msec -> 2/20 * 4096 = 409

 

Generating Tones

This section introduces the functionality of generating tones using the PWM.TONE command.

This command provides the means to create tones using the PWM.

 

Syntax

The PWM.TONE command follows a concise syntax:

 

PWM.TONE channel, frequency [, duration_ms]

 

-       channel: Selects a specific PWM channel for tone output.

-       frequency: Specifies the frequency of the generated tone in Hertz (Hz).

-       duration_ms: (Optional) Defines the duration of the tone in milliseconds (ms). If omitted, the tone will play indefinitely.

 

Practical Examples

 

Example 1: Single Tone

To generate a continuous tone at 1000 Hz on channel 1, use:

 

PWM.TONE 1, 1000

This command establishes a steady 1000 Hz tone on channel 1.

 

Example 2: Timed Tone

For a tone lasting 200 ms at 2000 Hz on channel 2, apply:

 

PWM.TONE 2, 2000, 200

Channel 2 will produce a tone at 2000 Hz for a duration of 200 milliseconds.

 

Example 3: Stopping a Tone

To halt an ongoing tone on channel 1, use the following command

 

PWM.TONE 1, 0  command

 

Prior to using PWM.TONE, ensure proper channel setup using the PWM.SETUP command, for example using PWM.SETUP 5, 1, 0. (pin 5, channel1, default output at 0)

 

Be mindful of the channel's frequency range and resolution limits.

I2S BUS

I²S (Inter-IC Sound), is an electrical serial bus interface standard used for connecting digital audio devices together. It is used to communicate PCM audio data between integrated circuits in an electronic device.

The I²S bus separates clock and serial data signals, resulting in a lower jitter than is typical of communications systems that recover the clock from the data stream.

Despite the name similarity, I²S is unrelated to the bidirectional I²C (I2C) bus.

 

The bus consists of three lines:

Bit clock line

-       Typically called "bit clock (BCLK)".  PIN GPIO5

Word clock line

-       Typically called "left-right clock (LRCLK)"  or “Word Select (WSEL)”. PIN GPIO26

Data line

-       Typically called "serial data (SD)". Can also be called (SDIN, SDOUT or DATA). PIN GPIO2

 

The typical use of the I2S is to connect an external DAC to provide a High Quality stereo sound output.

 

Using the PLAY.xxx commands, it will be possible to play MP3 and WAV files directly from the disk.

 

Any generic I2S DAC can be used.

Annex32 has been successfully tested with the PC5102A and the UDA1334A

 

imageUDA1334A I2S DAC

 

 

 

image

 

imagePCM5102A I2S DAC

 

NOTE:

This module requires the following setting (solder joints)

Component side:

Next to the sck connection

Back side:

1 set to L

2 set to L

3 set to H

4 set to L

 

image

 

It is now also possible to use the CODEC ES8388 using the command OPTION.ES8388

SPEAKER OUTPUT

The M5stack contains an internal speaker connected, via an audio amplifier, to the pin GPIO25.

This permits the generation of audio signals using the internal 8 bits DAC.

Using the PLAY.xxx commands, it will be possible to play MP3 and WAV files directly from the disk.

 

It is possible to connect an earphone directly on the output between the pin GPIO25 and the ground but the best is to connect a little audio amplifier.

 

NOTE: it is recommended to put a capacitor ( ~100nF) between the GPIO25 and the audio amplifier in order to remove the DC component from the audio signal.

SPDIF OUTPUT

It is also possible to generate the sound using a SPDIF output, in both cable or fiber optic format.

For that simple define the

PLAY.SETUP 3, [buff_size, mono]

The pin for the output is the one defined for the I2C_ Dout

 

 

I2C BUS

The I²C bus allows the module to connect to I²C devices.

 

I²C uses only two bidirectional open-drain lines, Serial Data Line (SDA) and Serial Clock Line (SCL), pulled up with resistors (typically 4.7K to 10K).

 

The I²C has a 7 bit address space permitting, theoretically, to connect up to 126 I/O devices.

 

The maximal number of nodes is limited by the address space and also by the total bus capacitance of 400 pF, which restricts practical communication distances to a few meters. The relatively high impedance and low noise immunity requires a common ground potential, which again restricts practical use to communication within the same PC board or small system of boards.

 

The current implementation is master mode @ 100Khz by default.

 

The SDA and SCL pins can be freely defined using the command I2C.SETUP sda_pin, scl_pin.

For example, to define pins 21(SDA) and 22(SCL) the command is :

I2C.SETUP 21, 22

 

It is important to provide correct pullup resistors on these lines; values between 4.7K to 10K should be appropriate.

 

The commands available are :

I2C.BEGIN, I2C.END, I2C.REQFROM, I2C.SETUP, I2C.WRITE

The functions available are :

I2C.LEN, I2C.READ, I2C.END

 

There are also other advanced functions / commands to simplify exchanges with the i2c bus.

The advanced commands available are :

I2C.READREGARRAY, I2C.WRITEREGBYTE,I2C.WRITEREGARRAY

 

The advanced functions available are :

I2C.READREGBYTE

 

The I2C bus can also be used with the IO Buffers ( look at the dedicated chapter)

 

As all the devices can have a "not well" determined address, please find here a little i2c scanner program which returns the address of all the devices found connected to the bus

'I2C Address Scanner

'print in the console the address of the devices found

I2C.SETUP 21, 22  ' set I2C port on pins 21 and 22

 

for i = 0 to 120

  i2c.begin i

  if i2c.end = 0 then

     print "found "; i , hex$(i)

     pause 10

  end if

next i

 

end

 

 

PCF8574 Module

This is an example of connection of a module with PCF8574 bought on Ebay at less than 2€ 

 

image

This drawing shows how this module must be connected to the ESP32.

It provides 8 digital inputs or outputs.

image

This is an example of code that "drives" this module:

I2C.SETUP 21, 22  ' set I2C port on pins 21 and 22

device_address = 32  'set to module i2c address

'Write from 0 to 255 on the module

'Each pin will blink at different frequency

For i = 0 to 255

PCF8574_write i

Next i

 

'Read all the inputs

'The result is printed into the serial console

' put all the inputs at pullup state

PCF8574_write 255

 

r = 0

For i = 0 to 1000

  PCF8574_read r

  Print r

Next i

End

 

sub PCF8574_write(x)

  i2c.begin device_address

  i2c.write x

  i2c.end

end sub

 

sub PCF8574_read(x)

  i2c.reqfrom device_address, 1

  x = i2c.read

  i2c.end

end sub

 
ADS1115 Module

This is another example of connection of a module with ADS1115 bought on Ebay at less than 2€.

This is a 16 Bit ADC 4 channel Module with Programmable Gain Amplifier.

imageimage

 

Because the module already contains two 10K I2C pullups, no external resistors are required

 

image

 

As this device is quite simple to interface, it can be directly driven using a “driver” written in basic.

' ADS1115 Driver for Annex

' datasheet http://www.ti.com/lit/ds/symlink/ads1115.pdf

' ADS1115 Registers

ADS1115_ADDRESS = &h48

ADS1115_CONV_REG = 0 : ADS1115_CONF_REG = 1

ADS1115_HI_T_REG = 2 : ADS1115_LO_T_REG = 3

 

i2c.setup 21, 22 ' set I2C bus

 

' Set the ADS1115 with :

'    AINp = AIN0 and AINn = AIN1

'    FSR = ±4.096 V

'    16 SPS

ADS1115_setup 0, 1, 1

 

' scale in volt

scale = 4.096 / 32768

 

v = 0

for i = 0 to 100000

 ADS1115_read v  ' read from the module

 print v * scale

next i

 

end

 

'---------------------------------------------------------

' INPUT MULTIPLEX :

' AINp is the input positive

' AINn is the input negative

'0 : AINp = AIN0 and AINn = AIN1

'1 : AINp = AIN0 and AINn = AIN3

'2 : AINp = AIN1 and AINn = AIN3

'3 : AINp = AIN2 and AINn = AIN3

'4 : AINp = AIN0 and AINn = GND

'5 : AINp = AIN1 and AINn = GND

'6 : AINp = AIN2 and AINn = GND

'7 : AINp = AIN3 and AINn = GND

 

'GAIN

'0 : FSR = ±6.144 V

'1 : FSR = ±4.096 V

'2 : FSR = ±2.048 V

'3 : FSR = ±1.024 V

'4 : FSR = ±0.512 V

'5 : FSR = ±0.256 V

'6 : FSR = ±0.256 V

'7 : FSR = ±0.256 V

 

'DATA RATE

'0 : 8 SPS

'1 : 16 SPS

'2 : 32 SPS

'3 : 64 SPS

'4 : 128 SPS

'5 : 250 SPS

'6 : 475 SPS

'7 : 860 SPS

sub ADS1115_setup(inp_mux, gain, rate)

 local conf

 conf = (inp_mux << 12) or (gain << 9) or (rate << 5) or 3 ' + disable comp

 'use the IO Buffer 0 for writing

 iobuff.dim(0,2) =  (conf and &hff00) >> 8 , conf and &hff

 i2c.write_iobuff(0), ADS1115_ADDRESS, ADS1115_CONF_REG

end sub

 

sub ADS1115_read(ret)

 'use the IO Buffer 0 for reading

 i2c.read_iobuff(0), ADS1115_ADDRESS, ADS1115_CONV_REG, 2

 if iobuff.len(0) = 0 then

   print "No communication"

   ret = 0

 else

   ret = iobuff.read(0, 0) << 8 + iobuff.read(0, 1)

 end if

 if ret > 32768 then ret = ret - 65536

end sub

 

 

MCP23017 Module

This is another example for connecting an I2C module, an MCP20S17 bought on Ebay at less than 2€.

This module provides 16 GPIO pins that can be used as digital inputs or outputs.

image

 

Because the module already contains two 10K I2C pullups, no external resistors are required

 

image

 

As this device is quite simple to interface, it can be directly driven using a “driver” written in basic.

' MCP23017 Driver for Annex

' datasheet http://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf

I2C.SETUP 21, 22  ' set I2C port on pins 21 and 22

device_address = 32  'set to module i2c address

 

'MCP23017 internal registers

IODIRA   = 0  : IODIRB   = 1 : IPOLA   = 2  : IPOLB   = 3

GPINTENA = 4  : GPINTENB = 5 : DEFVALA = 6  : DEFVALB = 7

INTCONA  = 8  : INTCONB  = 9 : IOCONA  = 10 : IOCONB  = 11

GPPUA    = 12 : GPPUB   = 13 : INTFA   = 14 : INTFB   = 15

INTCAPA  = 16 : INTCAPB = 17 : GPIOA   = 18 : GPIOB   = 19

OLATA    = 20 : OLATB   = 21

 

i2C.WriteRegByte device_address, IOCONA, &h08 ' init MCP23S17 with bit HAEN

i2C.WriteRegByte device_address, IODIRA, &hFF ' all PORT A pins as input

i2C.WriteRegByte device_address, GPPUA,  &hff ' set PORT A pullup on all pins

i2C.WriteRegByte device_address, IODIRB, &h00 ' all PORT B pins as output

 

r = 0

for z = 0 to 255

  I2C.WriteRegByte device_address, GPIOB, z  ' pulse all GPIOB pins

  r = i2C.ReadRegByte(device_address, GPIOA) ' read  all GPIOA pins

  print r

  pause 100

next z

 

 

SPI BUS

The SPI bus allows the module to connect to SPI devices.

 

The Serial Peripheral Interface bus (SPI) is a synchronous serial communication interface used for short distance communication between devices.

SPI devices communicate in full duplex mode using a master-slave architecture where the ESP32 is the master. The ESP32 generates the frame for reading and writing.

Multiple slave devices are supported through selection with individual chip select (CS) lines.

The SPI bus utilise four logic signals:

 

SIGNAL

DESCRIPTION

I/O PIN

SCLK

Serial Clock (output from the ESP32)

GPIO18

MISO

Master Input Slave Output (data input to the ESP32)

GPIO19

MOSI

Master Output Slave Input (data output from the ESP32)

GPIO23

CS

Chip Select (often active low, output from the ESP32)

Any output pin, controlled automatically

 

Because these pins are allocated by default, they may not not be available, by default, to be used as generic GPIO pins.

For that the command SPI.STOP enable to recover the control on these I/O pins

 

CS pin

As many devices can be connected in parallel, sharing the same SCLK, MISO and MOSI signals, each device is controlled individually using an individual CS signal.

As Annex32 implements multitasking, in order to guarantee that the CS signal is generated in phase with the data to be transferred, the CS pin is managed automatically.

The command SPI.CSPIN pin [, polarity] permits the pin associated with the device to be controlled. Additionally, it permits to define the polarity  as 0 = active low (default) and 1 = active high.

 

SPI Mode: Polarity and Clock Phase

The SPI interface defines no protocol for data exchange, limiting overhead and allowing for high speed data streaming. Clock polarity (CPOL) and clock phase (CPHA) can be specified as ‘0’ or ‘1’ to form four unique modes to provide flexibility in communication between master and slave as shown below :

 

image

If CPOL and CPHA are both ‘0’ (defined as Mode 0) data is sampled at the leading rising edge of the clock. Mode 0 is by far the most common mode for SPI bus slave communication.

If CPOL is ‘1’ and CPHA is ‘0’ (Mode 2), data is sampled at the leading falling edge of the clock. Likewise, CPOL = ‘0’ and CPHA = ‘1’ (Mode 1) results in data sampled on the trailing falling edge and CPOL = ‘1’ with CPHA = ‘1’ (Mode 3) results in data sampled on the trailing rising edge.

The table below summarizes the available modes.

 

Mode

CPOL

CPHA

0

0

0

1

0

1

2

1

0

3

1

1

 

The data can also be sent MSB first or LSB first.

This is defined as bit order and is MSB first by default

 

Even if the chip is able to achieve 80Mhz, the maximum realistic SPI speed is 40Mhz.

 

The commands available are :

SPI.SETUP speed [,data_mode [, bit_order]]

SPI.CSPIN pin [, polarity]

The functions available are :

ret = SPI.BYTE(byte)

a$ = SPI.STRING$(data$, len)

a$ = SPI.HEX$(datahex$, len)

As said previously,  because the ESP32 uses multitasking, it is impossible to warrant the exclusive use of the SPI bus during the execution of the script (it could be used by the SD card or the TFT, for example).

For this reason, the CS pin is managed internally by Annex directly by the SPI functions.

This is defined with the command SPI.CSPIN pin [, polarity]

The optional parameter  polarity  defines if the CS signal must be active low (0 = default) or active high (1).

This command will set the pin automatically as output.

 

The SPI bus can also be used with the IO Buffers ( look at the dedicated chapter)

 

Look at the examples below for more details:

74HC595 Module

This is an example of connection of a module with 74HC595 bought on Ebay at less than 2€ 

image

 

This drawing shows how this module must be connected to the ESP8266.

It provides 8 digital outputs.

image

This is an example of code that "drives" this module:

 

'Write from 0 to 255 on the module

'Each pin will blink at different frequency

 

spi.setup 100000  ' set the SPI port at 100KHz

SPI.CSPIN 15, 1 ' defines the pin 15 as CS active high

for i = 0 to 255

  r = spi.byte(i)

next i

 

end

 

 

MCP23S17 Module

This is another example for connecting an SPI module, an MCP23S17 bought on Ebay at less than 2€.

This module provides 16 GPIO pins that can be used as digital inputs or outputs. 

imageimage

 

image

 

As this device is quite simple to interface, it can be directly driven using a “driver” written in basic.

This is an example using the SPI pins and the GPIO15 as CS signal

 

' MCP23S17 Driver for Annex

' datasheet http://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf

 

spi.setup 1000000

 

'MCP23S17 SPI address

MCP23S17_ADDR = &h40  ' assumes A2, A1, A0 to GND

'MCP23S17 internal registers

IODIRA   = 0  : IODIRB   = 1 : IPOLA   = 2  : IPOLB   = 3

GPINTENA = 4  : GPINTENB = 5 : DEFVALA = 6  : DEFVALB = 7

INTCONA  = 8  : INTCONB  = 9 : IOCONA  = 10 : IOCONB  = 11

GPPUA    = 12 : GPPUB   = 13 : INTFA   = 14 : INTFB   = 15

INTCAPA  = 16 : INTCAPB = 17 : GPIOA   = 18 : GPIOB   = 19

OLATA    = 20 : OLATB   = 21

 

MCP23S17_WRITE IOCONA, &h08 ' init MCP23S17 with bit HAEN

MCP23S17_WRITE IODIRA, &h00 ' all PORT A pins as output

MCP23S17_WRITE IODIRB, &hff ' all PORT B pins as input

MCP23S17_WRITE GPPUB , &hff ' all PORT B pins as pullup

 

v = 0

for i = 0 to 255

 for z = 0 to 255

   MCP23S17_WRITE GPIOA, z ' pulse all GPIOA pins

   MCP23S17_READ  GPIOB, v ' read  all GPIOB pins

   print v

 next z

next i

End

 

' function for read / write the MCP23S17

sub MCP23S17_WRITE(register, value)

 SPI.CSPIN 15

 a = SPI.byte(MCP23S17_ADDR)

 a = SPI.byte(register)

 a = SPI.byte(value)

end sub

 

sub MCP23S17_READ(register, value)

 local a

 SPI.CSPIN 15

 a = SPI.byte(MCP23S17_ADDR or 1)

 a = SPI.byte(register)

 value = SPI.byte(0)

end sub

CAN BUS

A Controller Area Network (CAN bus) is a robust vehicle bus standard designed to allow microcontrollers and devices to communicate with each other's applications without a host computer. It is a message-based protocol, designed originally for multiplex electrical wiring within automobiles to save on copper, but can also be used in many other contexts.

 

The Annex32 implements the support for standard CAN 2.0A (11-bit identifier) and CAN 2.0B (29-bit identifier).

 

To interface with an external CAN BUS, the ESP32  requires the use of a CAN  transceiver like the TJA1050, the MCP2551 or the SN65HVD230.

 

For example this module is based on the chip TJA1050 and can be bought for around 1€ on the internet.

image

 

Annex32 supports the transmission and reception of CAN BUS frames.

The bus can be initialised in NORMAL mode, NO ACK mode and LISTEN ONLY mode

The following BUS speeds are supported 25, 50, 100, 125, 250, 500, 800, 1000 (Kbits / sec).

CAN.SETUP

To use the CAN BUS, it must be initialised before using the function CAN.SETUP :

ret = CAN.SETUP(speed, pin_tx, pin_rx, [can_mode [, filter_code, filter_mask]])

where :

speed        is the bus speed in Kbit/sec and can be 25, 50, 100, 125, 250, 800, 1000

pin_tx               is the pin of the ESP32 used for the TX signal (connected to the transceiver)

pin_rx               is the pin of the ESP32 used for the RX signal (connected to the transceiver)

can_mode     can be 0 (NORMAL), 1 (NO ACK) or 2 (LISTEN ONLY). Optional, defaults to 0 (NORMAL)

filter_code  is the reception filter code. Optional, defaults to &h00000000 (32 bits)

filter_mask  is the reception filter mask. Optional, defaults to &hFFFFFFFF (32 bits)

 

The function returns 0 if OK or another value in case of error

 

can_mode represents how the ESP32 interfaces with the BUS

 

can_mode

DESCRIPTION

NORMAL

Normal operating mode where CAN controller can send/receive/acknowledge messages

NO ACK

Transmission does not require acknowledgment. Use this mode for self testing

LISTEN ONLY

The CAN controller will not influence the bus (No transmissions or acknowledgments) but can receive messages

 

filter_code and filter_mask can be used to filter messages of a particular ID.

 

Example:

ret = CAN.SETUP(500, 4, 5, 1) 'Set the bus at 500Kb/sec in NO ACK mode using the pins 4 and 5

CAN.INIT

Alternatively, the CAN BUS can be initialised using the function CAN.INIT; this function has the same functionality such as the CAN.SETUP but gives more control on the BUS timing (for advanced users) :

ret = CAN.INIT(pin_tx, pin_rx, can_mode, brp, tset_1, tseg_2, sjw, triple_sampling, [filter_code, filter_mask])

where :

pin_tx               is the pin of the ESP32 used for the TX signal (connected to the transceiver)

pin_rx               is the pin of the ESP32 used for the RX signal (connected to the transceiver)

can_mode     can be 0 (NORMAL), 1 (NO ACK) or 2 (LISTEN ONLY)

brp          is the Baudrate prescaler (i.e., APB clock divider) can be any even number from 2 to 128

tset_1       is the Timing segment 1 (Number of time quanta, between 1 to 16)

tset_2       is the Timing segment 2 (Number of time quanta, 1 to 8)

sjw          is the Synchronization Jump Width (Max time quanta jump for synchronize from 1 to 4)

triple_samp  can be 1 to enable the triple sampling when the CAN controller samples a bit

filter_code  is the reception filter code. Optional, defaults to &h00000000 (32 bits)

filter_mask  is the reception filter mask. Optional, defaults to &hFFFFFFFF (32 bits)

 

The function returns 0 if OK or another value in case of error

 

Example:

PRINT CAN.INIT(4, 5, 2, 8, 15, 4, 3, 0) 'Set the bus at 500Kb/sec in LISTEN ONLY mode using the pins 4 and 5

CAN.STOP

The function CAN.STOP permits to stop the driver disconnecting it from the BUS :

ret = CAN.STOP

The function returns 0 if OK or another value in case of error

CAN.WRITE

The function CAN.WRITE permits to write a message on the BUS; the message can be composed from 0 to 8 bytes.

ret = CAN.WRITE( id, can_flags [,b0 [,b1 [,b2 [,b3 [,b4 [,b5 [,b6 [,b7 ]]]]]]]])

where :

id                        is the ID of the message to be sent; must be 11 bits or 29 bits for extended messages

can_flags       is used to indicate the type of message transmitted/received.

b0 ... b7        message bytes. Any combination from 0 to 8 bytes can be specified

 

The function  returns 0 if OK or 1 of message not sent correctly

 

can_flags represents the type of message transmitted/received.

 

can_flags

DESCRIPTION

0

No message flags (Standard Frame Format)

1

Extended Frame Format (29bit ID)

2

Message is a Remote Transmit Request

4

Transmit as a Single Shot Transmission

8

Transmit as a Self Reception Request

16

 Message's Data length code is larger than 8. This will break compliance with CAN2.0B

 

 

Example:

PRINT CAN.WRITE( &h12345678, 1, 10, 20, 30) 'Send an extended message with ID &h12345678 composed of 3 bytes (10, 20, 30)

CAN.WRITE_IOBUFF

The message can also be sent using the IOBUFFERS with the function CAN.WRITE_IOBUFF :

ret = CAN.WRITE_IOBUFF(bufnum)

 

The function  returns 0 if OK or 1 of message not sent correctly

 

The iobuffer must be set before and must contains from 5 to 13 bytes structured as below :

 

IOBUFFER BYTE

DESCRIPTION

0

Message ID Byte 0 (Most significant byte)

1

Message ID Byte 1

2

Message ID Byte 2

3

Message ID Byte 3 (Least significant byte)

4

Can_flags defined as the previous table

5 to 12

Message bytes ( can span from 5 to 12 for message bytes 0 to 8)

 

ONCANBUS

Another event, ONCANBUS , has been included to determine when a CAN message has been received.

ONCANBUS  canbus_received

 

Inside this event, it is possible to read and analyse the content of the message received.

When this event occurs, the following functions are available :

 

CAN.IDENT

The function CAN.IDENT that returns the ID of the message received

Example:

id = CAN.IDENT

 

CAN.FLAGS

The function CAN.FLAGS that returns the flags of the message received

Example:

flags = CAN.FLAGS

 

CAN.LEN

The function CAN.LEN that returns the length of the message received (the content bytes)

Example:

ret = CAN.LEN

 

CAN.BYTE

The content of the message can then be read byte per byte using the function CAN.BYTE :

ret = CAN.BYTE(num)   

Returns the content of the byte num from the message received (the content bytes from 0 to 7)

 

CAN.READ_IOBUFF

The message can also be received using the IOBUFFERS with the function CAN.READ_IOBUFF :

ret = CAN.READ_IOBUFF(bufnum) 

Returns the number of bytes received (the content)

 

This function “copies” the content of the received buffer into the buffer bufnum without any impact on the function CAN.BYTE.

 

Example:

'CANBUS example

'init the canbus

'print can.setup(500, 26, 5, 1) ' speed, pin_tx, pin_rx

' speed can be 25, 50, 100, 125, 250, 500 or 800 Kbits/sec

 

'can.setup can also have other optional arguments

'print can.setup(500, 4, 5, 0, &h00000000, &hffffffff) ' speed, pin_tx, pin_rx, mode, filter_code, filter_mask

' the mode can be 0:normal, 1:no_ack_tx, 2:listen_only

 

print can.init(26, 5, 1,  8, 15, 4, 3, 1, &h0, &hffffffff) ' pin_tx, pin_rx, mode, brp, tset_1, tseg_2, sjw, triple_sampling, filter_code, filter_mask

 

'prepare an iobuffer containing an iobuffer to be sent

iobuff.dim(0, 13)  = &h12, &h34, &h56, &h78, 0    , &h33, &h44, &h55, &h66, &h77, &h88, &h99, &haa

'                     id    id     id   id   flag   b0    b1    b2    b3    b4    b5    b6    b7

 

'defines the place where jumps when receiving CAN messages

ONCANBUS canbussi

 

for z = 0 to 1000

  ' the message can be sent using iobuffers

  'print can.write_iobuff(0)

 

  'or directly using the command write

  print "tx "; can.write( z,  0,     0, 1,2,3,4,5,6,7,8)

  '                       id  flag   bytes 0 - 7

  pause 1000

next z

 

print "end sending"

 

wait

 

'can message reception routine

canbussi:

'the message can be extracted using these functions

print "canbussi "; hex$(can.ident); " "; can.flags; " "; can.len; " bytes ";

 

'the content can be read byte per byte

for k = 0 to 7

  print can.byte(k),

next k

print

 

'or the message can be routed into an iobuffer and extracted byte per byte

'print can.read_iobuff(1)

'print iobuff.len(1)

'print iobuff.read(1, 0),  iobuff.read(1, 1),  iobuff.read(1, 2),  iobuff.read(1, 3), iobuff.read(1, 4)

return

 

 CANBUS BUFFERS

In addition to the previous functions,Annex implements the support for up-to 32 (from 0 to 31) dedicated reception buffers that can be read at any pace individually.

Each buffer has its own filter and mask and it can be polled without requiring the use of the interrupt.

The filter / mask defined in the CAN.SETUP function will act as a global filter and will be applicable to all the buffers.

When a new data arrives, it will be filtered and stored in the corresponding buffer.

If an existing data is already present, it will not be overridden (the new one will be discarded), the reason is to avoid any change of data during the processing phase.

To accept to receive new data, the buffer must be released with the command CAN.BUF_CLEAR(buf_num)

 

These are several additional functions :

 

CAN..BUF_FILTER

ret =CAN.BUF_FILTER(buf_no, code [,mask]) 'set the filter

 

example

ret =CAN.BUF_FILTER(0, &h1234)  'defines the ID &h1234 for the buffer 0

 

ret =  CAN.BUF_FILTER(0, &h1234, &hf)  'defines the ID &h1234 for the buffer 0  with a mask of &hf .In this case the addresses accepted will be from &h1230 to &h123f (last 4 bits at 1)

 

CAN.BUF_IDENT

ret = CAN.BUF_IDENT(buf_no)  'returns the ident 

 

CAN.BUF_LEN

ret =CAN.BUF_LEN(buf_no) 'returns the length of the data received in the buffer

 

CAN.BUF_FLAGS

ret = CAN.BUF_FLAGS(buf_no)  'returns the flags 

 

CAN.BUF_BYTE

ret = CAN.BUF_BYTE(buf_no, byte_pos)  'returns the byte 

 

CAN.BUF_CLEAR

ret = CAN.BUF_CLEAR(buf_no)  'clear the buffer and returns 0

 

The CAN.BUF_LEN can be used to determine if new data has arrived and, when the processing of the data is terminated, the buffer can be released using CAN.BUF_CLEAR

 

 

Example:

'init the canbus

 

'can.setup can also have other optional arguments

print can.setup(500, 26, 5, 0, &h00000000, &hffffffff) ' speed, pin_tx, pin_rx, mode, filter_code, filter_mask

' the mode can be 0:normal, 1:no_ack_tx, 2:listen_only

 

print can.BUF_FILTER(0, &h123)

print can.BUF_FILTER(1, &h456)

print can.BUF_FILTER(2, &h789)

 

for z = 0 to 10000000

  if (can.BUF_LEN(0)) then

    print hex$(can.BUF_IDENT(0)), can.BUF_FLAGS(0), can.BUF_LEN(0), can.BUF_BYTE(0, 0), can.BUF_clear(0)

  end if

  if (can.BUF_LEN(1)) then 

    print hex$(can.BUF_IDENT(1)), can.BUF_FLAGS(1), can.BUF_LEN(1), can.BUF_BYTE(1, 0), can.BUF_clear(1)

  end if

  if (can.BUF_LEN(2)) then 

    print hex$(can.BUF_IDENT(2)), can.BUF_FLAGS(2), can.BUF_LEN(2), can.BUF_BYTE(2, 0), can.BUF_clear(2)

  end if

next z

 

wait

 

RMT Module

The Remote Control Peripheral (RMT) module on the ESP32 is a versatile and powerful feature designed to handle protocols that require precise timing, such as infrared remote control transmissions, LED strip control, and other time-sensitive communication protocols. Unlike typical digital I/O operations, the RMT module can generate and decode signals with highly accurate timing, allowing it to handle various transmission standards with minimal CPU involvement.

Key Features

     Precise timing control for generating and receiving signals

     Flexible channel configuration

     Support for continuous transmission using circular buffer mode

     Carrier modulation and demodulation capabilities

 

The number of RMT channels, their configuration for transmission (TX) and reception (RX), and the available buffer sizes depend on the specific ESP32 chip variant:

ESP32 Variant

Total RMT Channels

Buffer Size per Channel

Total RMT RAM

Memory Management

Channel Sync Capability

RX demodulation Capability

ESP32

8

64 x 32-bit memory blocks

512 x 32-bit

Each channel can use up to 64 memory blocks. Channels can share memory blocks if required. Memory blocks are dynamically allocated to channels.

NO

NO

ESP32-S2

4

48 x 32-bit memory blocks

192 x 32-bit

Each channel can use up to 48 memory blocks. Memory is dynamically allocated, and multiple blocks can be assigned to a single channel.

YES

YES

ESP32-S3

8


 

4 TX Channels (0-3)

 

4 RX Channels (4-7)

48 x 32-bit memory blocks

384 x 32-bit

Channels 0-3 are TX only, and Channels 4-7 are RX only. Each channel can use up to 48 memory blocks.

Memory allocation is dynamic, and blocks can be shared among channels to optimise usage.

YES

YES

ESP32-C3

4


 

2 TX Channels (0-1)

 

2 RX Channels (2-3)

48 x 32-bit memory blocks

192 x 32-bit

Channels 0-1 are TX only, and Channels 2-3 are RX only.

Each channel can use up to 48 memory blocks. Memory allocation is dynamic, and blocks can be shared among channels to optimise usage.

YES

YES

Memory Management and Synchronisation of RMT Channels

The RMT module on each ESP32 chip variant uses a flexible memory management system that allows memory blocks to be dynamically assigned to individual channels based on the application's needs:

  1. Memory Blocks: Each channel is assigned a specific number of memory items, which store 32-bit wide data per item. Depending on the variant, each channel can use up to a maximum number of  48 or 64 items (a block). By default each channel is associated with a single block.
  2. Dynamic Allocation: The allocation of memory blocks to channels is dynamic, allowing a channel to be configured to use multiple memory blocks based on the protocol requirements. For example, a channel may need more memory blocks to handle longer data sequences or more complex communication protocols.
  3. Channel Synchronisation: Some ESP32 variants support the synchronisation between different RMT channels. This feature enables precise coordination of signal generation across multiple channels, which is especially useful for controlling multiple devices simultaneously or handling complex communication protocols that require synchronised timing.
Clock Divider

The RMT module operates with a clock divider that scales the main system clock down to a lower frequency suitable for precise timing operations. The default clock source for the RMT module is derived from the system clock running at 80 MHz. The clock divider adjusts this frequency to meet the specific timing requirements of the application.

     The clock divider value determines how many system clock cycles are used to produce one RMT clock cycle. The divider starts at 80, meaning the RMT clock is derived by dividing the 80 MHz system clock by the divider value. This scaling allows for various timing configurations, enabling the RMT module to handle different pulse widths and frequencies.

For example, with a clock divider of 80, the RMT clock frequency is imageproviding a time resolution of 1 microsecond per tick. Adjusting the divider allows for finer control over timing and signal generation.

RMT RAM Composition

The RMT module utilises dedicated RAM to store and process signal data.

Each entry in the RMT RAM is a 32-bit word divided into four fields, structured as follows:

Field

Description

Bits

level0

Level of the first pulse (high/low)

1 bit

duration0

Duration of the first pulse in ticks

15 bits

level1

Level of the second pulse (high/low)

1 bit

duration1

Duration of the second pulse in ticks

15 bits

 

image

Each memory block consists of these four fields, totaling 32 bits (4 bytes) per item. This structure allows the RMT module to precisely control pulse lengths and signal states, enabling accurate signal generation and decoding. Each RMT item represents a single pulse, with the following fields:

     Level0: The state of the signal for the first half of the pulse.

     Duration0: The length of time the signal remains at Level0. The value is set in ticks, where each tick is determined by the clock divider.

     Level1: The state of the signal for the second half of the pulse.

     Duration1: The length of time the signal remains at Level1. Similar to Duration0, this is set in ticks.

The number of items used depends on the number of pulses that need to be sent or received. Each channel can store multiple items, up to the limit specified in the table above.

The minimum value for the duration is zero (0) and is interpreted as a transmission end-marker.

The ‘duration’ fields represent the length of the pulse in terms of clock ticks. By specifying the duration, you determine how long the signal should be held at a particular level before transitioning to the next state. This allows for the precise timing and modulation of signals, crucial for tasks such as generating complex waveforms or encoding data.

For example, using a clock divider of 80, each tick corresponds to 1 microsecond.

Therefore, the Duration0 and Duration1 fields directly represent pulse lengths in microseconds.

Memory Block Extension

     All ESP32 variants allow for extending the memory blocks allocated to certain RMT channels by reducing the total number of available channels. This feature enables users to configure longer, more complex signal patterns by increasing the buffer size for specific channels. For example, on the ESP32, you can configure:

     8 channels with 64 items each

     4 channels with 128 items each

     2 channels with 256 items each

     This flexibility allows users to balance between the number of channels and the complexity of signals they can generate or receive. By reallocating memory, it is possible to tailor the RMT peripheral to meet the specific needs of the application, whether it involves fewer channels with longer signal patterns or more channels with shorter patterns.

 

 

RMT Transmit Synchronisation

Transmit synchronisation in the context of RMT (Remote Control Transceiver) refers to the ability to start multiple transmit channels simultaneously with precise timing. This feature is crucial for applications that require coordinated output across multiple channels, such as:

     Controlling complex LED matrices or strips

     Generating multi-channel waveforms

     Implementing protocols that require precise timing across multiple signal lines

The goal of transmit synchronisation is to ensure that multiple RMT channels begin their transmission at exactly the same moment, eliminating any timing discrepancies between channels.

Different ESP32 variants have varying levels of support for transmit synchronisation:

  1. ESP32:
    This earlier variant does not have built-in hardware support for TX synchronisation.
  2. ESP32-S2, ESP32-S3 and ESP32-C3:
    These newer variants include hardware support for TX synchronisation. They feature a synchronisation manager that can coordinate the start of transmission across multiple TX channels with high precision. This hardware-based approach allows for more accurate and reliable synchronised transmissions.

 

TX Transmitter Mode

In the transmitter mode, the RMT module of the ESP32 provides versatile capabilities for transmitting data. Key features include:

     Idle Level (idle_level): Set the signal level (high or low) on the RMT output when it is idle. This ensures a consistent signal state between transmissions.

     Loop Enable (loop_en): Enable or disable continuous looping of the data transmission.

     Carrier Signal: The RMT module supports the use of a carrier signal to modulate the output. This carrier signal can be customised with the following parameters:

     Enable Carrier Signal (carrier_en): Activate the carrier signal to modulate the output as required.

     Carrier Frequency (carrier_freq_hz): Set a specific frequency (e.g., 38 kHz), which is commonly used in IR communication.

     Duty Cycle Percentage (carrier_duty_percent): Adjust the duty cycle of the carrier signal to define the proportion of time the signal is high within each period. This can be set to values such as 33% or any other percentage based on application needs.

     Carrier Level (carrier_level): Specify the level (high or low) of the RMT output when the carrier is active, determining whether the carrier signal starts with a high or low output.

 

RX Reception Mode

In the reception mode, the RMT module provides several configurable parameters to optimise signal reception and processing:

     Enable Filter (filter_en): Activates a filter on the input of the RMT receiver to remove noise and unwanted signals.

     Filter Threshold (filter_ticks_thresh): Sets the threshold for the filter in terms of the number of ticks. Pulses shorter than this value will be filtered out. The acceptable range for this value is from 0 to 255 ticks.

     Idle Threshold (idle_threshold): Defines a pulse length threshold in ticks that will cause the RMT receiver to enter an idle state. Pulses longer than this threshold will be ignored, helping to manage longer, non-relevant signals.

Additionally, the RMT module can optionally demodulate the input signal using the following parameters:

     Enable Carrier Demodulation (rm_carrier): Activates the carrier demodulation feature to process modulated signals.

     Carrier Frequency (carrier_freq_hz): Specifies the frequency of the carrier signal in Hz, used for demodulation. This allows the receiver to correctly interpret signals modulated at specific frequencies.

     Carrier Duty Cycle (carrier_duty_percent): Sets the duty cycle of the carrier signal in percentage, which helps in accurately decoding the modulated signal.

     Carrier Level (carrier_level): Defines the level of the RMT input where the carrier is modulated, indicating whether the carrier signal affects the input when active.

RX Reception Event

The RMT uses the OnInfrared event for the reception of RX data. This event is triggered immediately when the RMT module receives incoming data.

RMT Command Functions
RMT.SETUP_TX channel, pin [, clk_div] [, mem_block_num] [, idle_level] [, loop_en] [, carrier_en] [, carrier_freq_hz] [, carrier_duty_percent] [, carrier_level]

     Purpose: Configures an RMT channel for transmission.

     Arguments:

     channel: RMT channel number (integer)

     pin: GPIO pin number (integer)

     clk_div: Clock divider (optional integer, default is 80)

     mem_block_num: Number of memory blocks (optional integer, default is 1)

     idle_level: Idle level for the channel (optional integer, default is RMT_IDLE_LEVEL_LOW)

     loop_en: Enable looping (optional boolean, default is false (0))

     carrier_en: Enable carrier signal (optional boolean, default is false (0))

     carrier_freq_hz: Carrier frequency in Hz (optional integer, default is 38000)

     carrier_duty_percent: Carrier duty cycle percentage (optional integer, default is 33)

     carrier_level: Carrier level (optional integer, default is RMT_CARRIER_LEVEL_HIGH)

     Description: Sets up the RMT channel for transmission with specified parameters. Uninstalls and reconfigures the RMT driver.

RMT.WRITE channel, num_items, name [, wait]

     Purpose: Sends data items on an RMT channel.

     Arguments:

     channel: RMT channel number (integer)

     num_items: Number of items to write (integer)

     name: Integer array containing the data items, where each element is a 32-bit word that encodes levels and periods.

     wait: Wait for transmission to complete (optional boolean, default is true)

     Description: Writes an array of RMT items to the specified channel. The name parameter represents an integer array where each element is a 32-bit word combining both the levels (1-bit) and periods (15-bits each for high and low durations) required for transmission. Optionally waits for the transmission to complete.

RMT.ENCODE channel, num_items, array() [, wait]

     Purpose: Encodes data items for transmission on an RMT channel.

     Arguments:

     channel: RMT channel number (integer)

     num_items: Number of items to encode (integer)

     array: A two-dimensional array containing the data to encode:

     array[x][0]: Level 0

     array[x][1]: Duration 0

     array[x][2]: Level 1

     array[x][3]: Duration 1

     wait: Wait for transmission to complete (optional boolean, default is true)

     Description: Encodes data for transmission from a two-dimensional array where each row represents a data item to be transmitted. The array must be defined beforehand with levels and durations structured as shown. The encoded data is then written to the specified channel, and it optionally waits for transmission to complete.

RMT.SETUP_RX channel, pin [, clk_div] [, mem_block_num] [, invert] [, filter_en] [, filter_ticks_thresh] [, idle_threshold] [, rm_carrier] [, carrier_freq_hz] [, carrier_duty_percent] [, carrier_level]

     Purpose: Configures an RMT channel for reception.

     Arguments:

     channel: RMT channel number (integer)

     pin: GPIO pin number (integer)

     clk_div: Clock divider (optional integer, default is 80)

     mem_block_num: Number of memory blocks (optional integer, default is 1)

     invert: Inverts the polarity of the signal (optional integer, default is false (0))

     filter_en: Enable filter (optional boolean, default is true (1))

     filter_ticks_thresh: Filter ticks threshold (optional integer, default is 100)

     idle_threshold: Idle threshold (optional integer, default is 65535)

     rm_carrier: Remove carrier signal (optional boolean, default is true)

     carrier_freq_hz: Carrier frequency in Hz (optional integer, default is 38000)

     carrier_duty_percent: Carrier duty cycle percentage (optional integer, default is 33)

     carrier_level: Carrier level (optional integer, default is RMT_CARRIER_LEVEL_HIGH)

     Description: Configures the RMT channel for reception with specified parameters. Uninstalls and reconfigures the RMT driver, sets up a ring buffer for received data, and starts the reception.

RMT.READ array()

     Purpose: Reads data items from an RMT channel.

     Arguments:

     array: Integer array where the received data will be stored, with each element being a 32-bit word that encodes levels and periods.

     Description: Reads data from the RMT ring buffer and stores it in an integer array (array). The array will contain 32-bit words, with each word representing the levels (1-bit) and periods (15-bits each for high and low durations) that were received. The array must be pre-defined before use.

RMT.DECODE array()

     Purpose: Decodes received data from an RMT channel.

     Arguments:

     array: A two-dimensional array to store the decoded data:

     array[x][0]: Level 0

     array[x][1]: Duration 0

     array[x][2]: Level 1

     array[x][3]: Duration 1

     Description: Decodes data from the RMT ring buffer into a two-dimensional array format where each row corresponds to a decoded item with levels and durations structured as shown. The array must be pre-defined before use.

RMT.ADD_GROUP channel

     Purpose: Adds an RMT channel to a group for synchronised transmission.

     Arguments:

     channel: RMT channel number (integer)

     Description: Adds the specified RMT channel to a group. This is used to define a set of channels that should transmit signals simultaneously. The transmission is synchronised, starting only when all channels in the group are ready.

RMT.DEL_GROUP channel

     Purpose: Removes an RMT channel from a group.

     Arguments:

     channel: RMT channel number (integer)

     Description: Removes the specified RMT channel from a group. This action stops the channel from being part of a synchronised transmission group.

RMT.END channel

     Purpose: Terminates (unistall) an RMT channel.

     Arguments:

     channel: RMT channel number (integer)

     Description: Uninstall the specified RMT channel. This action stops the channel from being active and frees the corresponding GPIO pin.

 

Synchronisation in Groups

The RMT.ADD_GROUP andRMT.DEL_GROUP commands manage the synchronisation of multiple RMT channels for transmission. By adding channels to a group, the user specifies which channels should start transmitting at the same time. The transmission begins only when all channels in the group are ready, ensuring synchronised signal output across multiple channels. When a writing command is given on the last channel of the group, the synchronised transmission can commence, providing coordinated timing for applications that require multiple simultaneous signals.

 

Example 1: RMT Transmission of a Pulse Sequence

This example demonstrates how to use the RMT (Remote Control) module on an ESP32 to transmit a sequence of pulses using the RMT.ENCODE command. Let's break down the example to understand what each part does and how it works.

 

' RMT example: set a sequence of 3 pulses of 1ms, 2ms, 3ms with 20msec between

dim a(10,5)

a(0,0) = 1 : a(0,1) = 1000: a(0,2) = 0 : a(0,3) = 20000

a(1,0) = 1 : a(1,1) = 2000: a(1,2) = 0 : a(1,3) = 20000

a(2,0) = 1 : a(2,1) = 3000: a(2,2) = 0 : a(2,3) = 20000

a(3,0) = 0 : a(3,1) = 0   : a(3,2) = 0 : a(3,3) = 0

 

 

' channel, pin, clk_div, num_blocks, idle_level, loop_en, carrier_en, carrier_freq, carrier_duty_percent, carrier_level

RMT.Setup_TX 0, 47, 80, 1, 0, 1, 1, 38000, 33, 1

RMT.ENCODE 0, 3, a()

end

 

Pulse Sequence Setup

The sequence of pulses is defined using a 2-dimensional array named a in the example, where each row represents one RMT item containing pulse levels and durations.

dim a(10,5)

a(0,0) = 1 : a(0,1) = 1000: a(0,2) = 0 : a(0,3) = 20000

a(1,0) = 1 : a(1,1) = 2000: a(1,2) = 0 : a(1,3) = 20000

a(2,0) = 1 : a(2,1) = 3000: a(2,2) = 0 : a(2,3) = 20000

a(3,0) = 0 : a(3,1) = 0   : a(3,2) = 0 : a(3,3) = 0

     a(n, m): Represents a 2-dimensional array where:

     a(0,0) to a(3,3) define the pulse sequence.

     Column Definitions:

     a(x,0): Level0 - The logic level of the pulse for the first phase.

     a(x,1): Duration0 - Duration (in ticks) for Level0.

     a(x,2): Level1 - The logic level of the pulse for the second phase.

     a(x,3): Duration1 - Duration (in ticks) for Level1.

Explanation of the Sequence

     a(0,0) to a(0,3): First pulse:

     Level0 = 1 (High)

     Duration0 = 1000 ticks (1ms)

     Level1 = 0 (Low)

     Duration1 = 20000 ticks (20ms gap)

     a(1,0) to a(1,3): Second pulse:

     Level0 = 1 (High)

     Duration0 = 2000 ticks (2ms)

     Level1 = 0 (Low)

     Duration1 = 20000 ticks (20ms gap)

     a(2,0) to a(2,3): Third pulse:

     Level0 = 1 (High)

     Duration0 = 3000 ticks (3ms)

     Level1 = 0 (Low)

     Duration1 = 20000 ticks (20ms gap)

     a(3,0) to a(3,3): Terminates the sequence:

     All fields set to 0, indicating the end of transmission.

RMT Setup for Transmission

RMT.Setup_TX 0, 47, 80, 1, 0, 1, 1, 38000, 33, 1

The RMT.Setup_TX command configures the transmitter with specific parameters:

     0: Channel number (0).

     47: GPIO pin number (47).

     80: Clock divider, resulting in a 1 MHz RMT clock.

     1: Number of memory blocks.

     0: Idle level set to low.

     1: Loop enable, which allows the transmission to repeat indefinitely.

     1: Carrier signal enabled.

     38000: Carrier frequency in Hz (38 kHz).

     33: Carrier duty cycle (33%).

     1: Carrier level set to high when the carrier is active.

Encoding and Transmitting the Pulse Sequence

RMT.ENCODE 0, 3, a()

The RMT.ENCODEcommand encodes the pulse sequence for transmission with the following parameters:

     0: Channel number.

     3: Number of items to encode (3 pulses).

     a(): The name of the array containing the pulse sequence.

Explanation of the Functionality

This example sets up the RMT module to send a series of three pulses, each with increasing duration, followed by a 20 ms gap. The RMT transmitter is configured to loop this sequence indefinitely.

By using the RMT.ENCODE command, the user specifies the pulse sequence data, which the ESP32 will transmit on GPIO pin 47. The transmission repeats in a loop until explicitly stopped.

Key Points

     Customizable Pulse Sequences: The example shows how to define complex sequences of pulses with varying durations and levels.

     Loop Transmission: By setting the loop enable parameter to 1, the transmission repeats indefinitely, which is useful for applications that require a constant signal output.

     Carrier and Idle Control: The carrier is enabled with a frequency of 38 kHz and a 33% duty cycle, suitable for applications like IR communication.

 

Example 2: RMT Transmission of a Sinusoidal Pattern

This example configures the ESP32's RMT module to transmit a sinusoidal signal pattern using 256 data items. The waveform is generated using the sin() function to create a sequence of pulses that simulate a sine wave, which is useful for applications like signal generation, testing, or remote control emulation.

' RMT demo for generating a sinusoidal signal pattern using 256 data items

dim s(256, 4)

for z = 0 to 256

  s(z,0) = 1

  s(z,1) = sin(z/256*PI*2) * 500 + 501

  s(z,2) = 0

  s(z,3) = 5000

next z

' channel, pin, clk_div, num_blocks, idle_level, loop_en, carrier_en, carrier_freq, carrier_duty_percent, carrier_level

RMT.Setup_TX 0, 47, 80, 6, 0, 1

rmt.ENCODE 0, 256, s(), 0

end

 

Explanation of the Example

  1. Define the Data Array:

     A 2-dimensional array s(256, 4) is defined to store 256 items, where each item represents a part of the sinusoidal waveform.

     Each item contains four fields:

     s(z,0): Level of the RMT output (1 or 0).

     s(z,1): Duration of the high or low level in clock ticks (calculated using a sine function).

     s(z,2): Level of the RMT output after the initial duration (0 in this case).

     s(z,3): Duration of the low level after the initial pulse (fixed at 5000 ticks).

  1. Populate the Array with Sinusoidal Data:

     The for loop iterates from 0 to 256 to generate a sinusoidal pattern.

     The duration s(z,1) is calculated using the sin() function to create a value that oscillates between 1 and 1001, simulating a sine wave. This is done by multiplying the sine function's result by 500 and adding 501 to ensure a minimum duration.

  1. RMT Setup for Transmission:

     RMT.Setup_TX initialises the RMT transmitter on channel 0, using GPIO pin 47, a clock divider (clk_div) of 80, and allocates 6 memory blocks (num_blocks = 6).

     Idle_level is set to 0

     Loop mode (loop_en) is enabled to continuously transmit the configured data.

  1. Encode and Transmit the Data:

     rmt.ENCODE encodes the data array s() with 256 items and sends it on channel 0.

     The function prepares the RMT module to transmit the sinusoidal pattern.

Memory Block Usage

The example uses 6 memory blocks to store at least 256 items:

     Memory Block Capacity: Each block can store either 64 items or 48 items, depending on the ESP32 variant.

     With 64 items per block, the 6 blocks can store a total of 384 items (6 × 64).

     With 48 items per block, the 6 blocks can accommodate 288 items (6 × 48).

This ensures that the RMT module has enough capacity to handle the entire sequence of 256 items required for the sinusoidal pattern transmission.

Key Features of This Example

     Continuous Sinusoidal Waveform Generation: The example demonstrates how to use the RMT module to generate a continuous sinusoidal waveform.

     Flexible Configuration: The setup uses 6 memory blocks to ensure sufficient storage for the waveform, regardless of whether the block size is 64 or 48 items.

 

Example 3: Synchronized RMT Transmission of Sinusoidal Patterns

This example demonstrates how to use the ESP32's RMT module to transmit synchronised sinusoidal signal patterns using two different channels (0 and 2). Both channels are set up to transmit the same sinusoidal waveform, but the transmissions are synchronised to start simultaneously. This is useful in applications where multiple signals must be generated in sync, such as in lighting systems.

' RMT demo for generating a sinusoidal signal pattern using 256 data items

K = 95 ' 95 points

dim s(K, 4)

for z = 0 to K

  s(z,0) = 1

  s(z,1) = sin(z/K*PI*2 - PI/2) * 500 + 501

  s(z,2) = 0

  s(z,3) = 5000

next z

 

' channel, pin, clk_div, num_blocks, idle_level, loop_en, carrier_en, carrier_freq, carrier_duty_percent, carrier_level

RMT.Setup_TX 0, 47, 80, 2, 0, 1

RMT.Setup_TX 2, 21, 80, 2, 0, 1

rmt.add_group 0

rmt.add_group 2

 

rmt.ENCODE 0, K-1, s(), 0

pause 500

rmt.ENCODE 2, K-1, s(), 0

end

Explanation of the Example

  1. Define the Data Array:

     The array s(K, 4) is defined to store K items (where K = 95), representing a sinusoidal waveform.

     Each item in the array has four fields:

     s(z,0): Level of the RMT output (1 or 0).

     s(z,1): Duration of the high or low level in clock ticks, calculated using the sin() function to generate a sinusoidal pattern.

     s(z,2): Level of the RMT output after the initial duration (0 in this case).

     s(z,3): Duration of the low level after the initial pulse (fixed at 5000 ticks).

  1. Populate the Array with Sinusoidal Data:

     The for loop iterates from 0 to K to generate the sinusoidal pattern.

     The duration s(z,1) is calculated using sin(z/K*PI*2 - PI/2) * 500 + 501, which creates a shifted sine wave oscillating between 1 and 1001.

  1. Setup for RMT Transmission:

     First Channel Setup (Channel 0):

     RMT.Setup_TX initialises the RMT transmitter on channel 0, using GPIO pin 47, a clock divider (clk_div) of 80, and allocates 2 memory blocks (num_blocks = 2).

     Loop mode (loop_en) is enabled to continuously transmit the configured data.

     Second Channel Setup (Channel 2):

     Similarly, RMT.Setup_TX initialises another RMT transmitter on channel 2, using GPIO pin 21, the same clock divider (clk_div) of 80, and 2 memory blocks.

     Loop mode (loop_en) is also enabled for this channel.

  1. Add Channels to the Group for Synchronized Transmission:

     rmt.add_group adds both channels (0 and 2) to a synchronisation group. This allows the signals from both channels to be transmitted simultaneously.

     The transmission for both channels will start only when all channels in the group are ready.

  1. Encode and Transmit the Data:

     rmt.ENCODE 0, K, s(), 0 encodes the data array s() with K items and sends it on channel 0.

     After a pause of 500 milliseconds, rmt.ENCODE 2, K, s(), 0 encodes the data array s() with the same K items and sends it on channel 2.

     The transmission will start simultaneously on both channels

Memory Block Usage

     Each channel is configured to use 2 memory blocks.

     Each memory block can store 64 or 48 items, depending on the configuration.

     With 2 memory blocks, each channel can store a maximum of:

     128 items (2 × 64) if the block size is 64 items.

     96 items (2 × 48) if the block size is 48 items.

     This configuration is sufficient to store the 95 items generated for the sinusoidal pattern.

Key Features of This Example

     Synchronised Sinusoidal Waveform Transmission: This example demonstrates how to use two RMT channels to transmit synchronised waveforms, which is useful in applications requiring precise timing across multiple outputs.

     Configurable Waveform: The sinusoidal pattern is generated dynamically using the sin() function, and its duration can be easily adjusted by modifying the parameters.

     Flexible Grouping: Adding channels to a group (rmt.add_group) enables simultaneous transmission, which is critical in applications like synchronised lighting

 

Example 4: Infrared Signal Reception and Decoding with RMT on ESP32

This example demonstrates how to configure an RMT channel on the ESP32 to receive an infrared signal  from a specified GPIO pin and decode it into a usable format. The example showcases how to set up the RMT receiver, handle the incoming signal, and convert it into a binary value that represents the transmitted IR code.

 

'RMT example on IR signal decoding

pin.mode 42, input

rmt.Setup_RX 4,42,80

dim rx(64)

onInfrared doRMT

wait

 

doRMT:

t = millis

rmt.decode rx()

print "RMT", ubound(rx()), millis-t

res=0

for z=0 to ubound(rx())

  'print z, rx(z,0), rx(z,1), rx(z,2), rx(z,3)

  t1 =  rx(z,3)

  res = (res << 1) + (t1>1000)

next z

print "code final", hex$(res), millis-t

return

 

Explanation of the Example

  1. Configure the GPIO Pin for Input:

     pin.mode 42, input sets GPIO pin 42 as an input pin. This pin will receive the infrared signal from the IR sensor or receiver module.

  1. Setup RMT Receiver:

     rmt.Setup_RX 4,42,80 configures the RMT channel 4 for receiving mode on GPIO pin 42 with a clock divider (clk_div) of 80. This sets up the RMT module to capture incoming pulses on the specified pin.

  1. Define an Array for Storing Received Data:

     dim rx(64) declares an array rx with a size of 64 to store the received data items. Each entry in this array will hold information about the pulse width and levels captured by the RMT receiver.

  1. Set Up an Event Handler for Infrared Signals:

     onInfrared doRMT sets up an event handler named doRMT to be triggered when an IR signal is detected.

  1. Wait for IR Signal:

     The wait command puts the system in a waiting state until the IR signal is received, and the doRMT handler is triggered.

  1. Handle the IR Signal (doRMT Function):

     Capture Start Time: t = millis records the current time in milliseconds to measure the duration of the decoding process.

     Decode Received Data: rmt.decode rx() decodes the captured data items and stores them in the rx array.

     Print Decoding Results: print "RMT", ubound(rx()), millis-t prints the number of items in the rx array and the time taken to decode the signal.

     Extract Data Bits from the Received Signal:

     Initialise a result variable res to 0.

     Loop through each item in the rx array:

     t1 = rx(z,3) retrieves the duration of the low level for each pulse.

     res = (res << 1) + (t1>1000) shifts the result by one bit and adds 1 if the duration t1 is greater than 1000 ticks, or adds 0 otherwise.

     Print Final Decoded Code: print "code final", hex$(res), millis-t displays the final decoded value in hexadecimal format and the total decoding time.

Key Features of This Example

     IR Signal Reception and Decoding: The example demonstrates the use of the ESP32's RMT module to receive an infrared signal, store it in an array, and decode it into a binary code.

     Timing Analysis: By measuring the time taken to decode the signal, the example provides insights into the efficiency of the decoding process.

     Bitwise Operations for Decoding: The example uses bitwise operations to efficiently extract data bits from the received signal based on pulse durations.

Memory Block Usage

     This example uses a single RMT channel (4) for receiving the IR signal. Since the rx array is defined with 64 items, it fits within the default memory block size allocated for a single RMT channel.

Key Configuration Parameters for Reception

     Filter Enable and Threshold:

     The RMT receiver can filter out noise or unwanted short pulses by setting the filter_en parameter.

     The filter threshold filter_ticks_thresh determines the minimum duration a pulse must have to be considered valid. Pulses shorter than this will be ignored.

     Idle Threshold:

     The idle_threshold is used to detect when the signal becomes idle. Pulses longer than this threshold are considered idle, which helps in recognizing the end of a transmission.

     Carrier Demodulation (Optional):

     If the input signal is modulated with a carrier frequency, the RMT receiver can demodulate it using settings such as carrier_rm, carrier_freq_hz, carrier_duty_percent, and carrier_level.

Applications

This example is useful for:

     Infrared Remote Control Systems: Decoding commands sent from an IR remote control.

     Sensor Data Reception: Receiving data from sensors that use infrared communication.

     Wireless Communication Protocols: Implementing custom communication protocols using IR signals.

By leveraging the ESP32's RMT module, this example shows how to efficiently receive and process IR signals for a wide range of applications.

 

COUNTERS

This functionality exposes two counters that permit to count pulses from any input pin.

Additionally, each counter can also return the time occurred between consecutive pulses (period); this is useful as this will permit to determine the frequency of low frequency signals simply taking its reciprocal 

(f = 1 / period).

These counters are not based on H/W but are managed using processor interrupts, so the input frequency should be limited to around 10 Khz.

It is possible to define when the pulse is counted (on Rising Edge, on Falling Edge, on Change).

The “on Change” is particularly interesting when associated with low frequency measurement as it will permit to double the number of pulses.

Before using the counters, the input pin must be set as INPUT using the command PIN.MODE.

To start to use the counters, the following command is available:

COUNTER.SETUP cnt, pin [,mode]

where:

‘cnt’ defines which counter (1 or 2)

‘pin’ defines the input pin (can be any valid pin except GPIO16)

‘mode’ can be 1 (rising edge), 2 (falling edge) or 3 (change). If not specified, the mode change is enabled.

 

Example:

PIN.MODE 12,INPUT   ‘defines the pin GPIO12 as INPUT

COUNTER.SETUP 1, 12, 1  ‘ Counter 1 using pin GPIO12, count on Rising Edge

 

The pulses counted can be read using the function COUNTER.COUNT(cnt).

The period between 2 consecutive pulses can be read using the function COUNTER.PERIOD(cnt).

 

Example:

print COUNTER.COUNT(1)  ‘print the pulses counted from the counter 1

print COUNTER.PERIOD(1) ‘print the period from the counter 1

 

FInally the counters can be reset with the command COUNTER.RESET cnt

 

Example:

COUNTER.RESET 1  ‘ reset the counter 1

 

PID controllers

A proportional–integral–derivative controller (PID controller. or three-term controller) is a control loop feedback mechanism widely used in industrial control systems and a variety of other applications requiring continuously modulated control. (ref wikipedia)

A PID controller continuously calculates an error value e(t) as the difference between a desired setpoint (SP) and a measured process variable (PV) and applies a correction based on proportional, integral, and derivative terms (denoted P, I, and D respectively), hence the name.

In practical terms it automatically applies accurate and responsive correction to a control function.

An everyday example is the cruise control on a car, where ascending a hill would lower speed if only constant engine power is applied. The controller's PID algorithm restores the measured speed to the desired speed with minimal delay and overshoot, by increasing the power output of the engine.

Annex implements 4 PID controllers that can be used simultaneously for any application.

 

The commands are :

PIDx.INIT Kp, Ki, Kd

PIDx.SETMODE mode

PIDx.LIMITS min, max

PIDx.PERIOD msec

PIDx.PARAMS Kp, Ki, Kd

 

The main function is:

Pid_Out = PIDx.COMPUTE(CURR_VALUE, TARGET_VALUE)

 

PIDx can bePID1, PID2, PID3 or PID4.

 

The first step is to initialise the PID controller.

This can be done with the command PIDx.INIT Kp, Ki, Kd :

Example:

PID1.INIT 50, 80, 1 'initialise the controller with Kp = 50, Ki = 80 and Kd = 1

 

Optionally the output limits can be set using the command PIDx.LIMITS min, max.

If not defined the output is limited between 0 and 255

Example:

PID1.LIMITS 0, 1023 ' limits the output between 0 and 1023

 

Then the sampling period can be defined using the command PIDx.PERIOD msec

If not defined the period is set at 100 msec

Example:

PIDx.PERIOD 50 ' define the period at 50 msec

 

Finally the main function  output = PIDx.COMPUTE(input, setpoint)

Example:

Pid_Out = PID1.COMPUTE(CURR_VALUE, TARGET_VALUE)

 

This function must be called regularly in a loop; the best is to call it using a timer.

 

The command PIDx.SETMODE mode can be used to put the loop in manual mode with PIDx.SETMODE 0.

In this case the PID loop will be stopped and the output value will be frozen.

To restore the auto mode (default), the command is PIDx.SETMODE 1.

 

At any moment the PID parameters can be changed using the command PIDx.PARAMS Kp, Ki, Kd :

Example:

PID1.PARAMS 30, 80, 10 ' modify the PID parameters with Kp = 30, Ki = 80 and Kd = 10

 

The following example shows how to control the speed of a 3-wire 12V PC fan.

The PID utilises the counter to determine the fans speed controlling it using the PWM.

A little circuit is required to drive the positive side of the FAN.image

 

 

CODE: pid1.bas


' PID Test program

' cicciocb 2019

' this example controls the speed of a 3-wire PC fan

' using the internal counter as input and the PWM as output

 

PID1.INIT 1, 5, 0   'init the PID paramters

PID1.LIMITS 0, 1023  'the PWM goes up to 1023

 

pin.mode 12, input, pullup   'GPIO12 is the tach input. Pullup is ON

counter.setup 1, 12, 3  ' count changes so the output is doubled

cnt_p = 0 ' previous value of the counter

target = 50 'the default target speed (hz)

 

timer0 100, do_pid 'the PID is updated each 100msec

onHtmlReload create_web_page

gosub create_web_page

wait

 

create_web_page:

cls

a$ = "PID DEMO PROGRAM<br>"

a$ = a$ + "SPEED (Hz) " + textbox$(target)

html a$

return

 

do_pid:

' The frequency is computed at each cycle counting the pulses occurred

' As the cycle is executed each 100msec, the frequency computed

' is 1/10 of the real one 

cnt = counter.count(1)

freq = cnt - cnt_p ' the frequency

cnt_p = cnt

 

'the frequency is doubled and divided by 10

'so the real target is target *2 /10

out = pid1.compute(freq, target *2 /10) 'compute the PID

print "pulses ";freq, "freq "; freq *10/2, "pwm out ";out

pwm(13) = out

return

 

 

SOUND PLAYER

Annex provides the functionality to play WAV and MP3 sound directly from disk (FATFS or SD card).

The mp3 streaming from the web is also supported permitting to play Web Radios.

As the ESP-32 is equipped with a dual core CPU, this activity is done in parallel and does not impact the overall performance of Annex-32.

The sound output can be sent to the internal speaker (in particular for the m5stack) or to an external I2S DAC.

Look at the previous chapters for more details on the sound output.

 

To play sounds, the command available is PLAY.xxx

 

Before using this command, the sound output must be set as below :

PLAY.SETUP dest [,buffer], [mono]

If ‘dest’ is 0 is the output will be sent to the GPIO25 and 26 ( and the internal speaker for the M5stack)

If ‘dest’ is 1 is the output will be sent to the external DAC

If ‘dest’ is 2 is the output will be sent to the GPIO25 and 26 ( and the internal speaker for the M5stack) but using the PDM mode

The optional argument ’buffer’ defines the size of the memory block allocated as an output buffer.

Its value is 8 by default and can be increased up to 64.

Increasing the size of the buffer will permit to reduce some glitches that may occur in case of strong WiFi activity.

The optional argument ‘mono’, if set to 1, set the output in mono mode (useful for single channel speaker)

If the command PLAY.SETUP is run without arguments, the sound is sent by default to the internal speaker.

 

To play mp3 files, the command is :

PLAY.MP3 mp3file$

Example

PLAY.MP3 "/mp3/MyMusic.mp3"

 

To play wav files, the command is:

PLAY.WAV wavfile$

Example

PLAY.WAV "/wav/MySound.wav"

 

The position (the time) of the sound played can be controlled using the command PLAY.SEEK using a value from 0 (beginning) to 100 (end).

Example

PLAY.SEEK 50 position the sound at the middle of its length (50%)

PLAY.SEEK 0  rewind the sound

 

The function PLAY.POS returns the current position of the file from 0 (beginning) to 100 (end)

Example:

print PLAY.POS

 

It is also possible to play mp3 streaming web radios with the command

PLAY.STREAM streaming_url$ [,buffer] [,disable_id3] [,use_http10] [,show_buffer] [,preload_time] 

Example:

PLAY.STREAM"http://91.121.159.124:8000/eko-des-garrigues-128k.mp3"

 

To avoid glitches, the stream is buffered locally using a buffer of 20 Kbytes.

This can eventually be increased to improve the performance of the streaming, in particular with ESP32 modules that include the PSRAM.

Example:

PLAY.STREAM "http://audio4.nemostream.tv:8011/autodj", 50000

 

To avoid glitches, the stream is preloaded in the buffer for 4 seconds or until it reaches the 80% of the allocated size; the optional argument ‘preload_time’ can be used to modify this time.

It is important to note that streams using https:, require more memory and more CPU power to process the encrypted data. In this case, it is recommended to use modules with PSRAM and set a big buffer size ( at least 150000, for example).

 

The optional argument ‘disable_id3’ disables the parsing of the metadata included in the stream. This is particularly useful for high rate streams that uses massively the cpu (generating a lot of glitches)

 

The optional argument ‘use_http10’ is useful for streams that still uses the HTTP 1.0 protocol

Example:

PLAY.STREAM "http://icecast.radiofrance.fr/franceinter-lofi.mp3", 50000,,1

 

The optional argument ‘show_buffer’ will show how the buffer is managed and can be useful for debug

 

The sound is always played in the background, even if the program is stopped, until the end of the file (or forever for the web radios).

 

As the sound is played in the background, the functionPLAY.ISPLAYING returns the following values :

 

VALUE

DESCRIPTION

0

The sound is stopped

1

The mp3 file is playing

2

The wav file is playing

 

 

To stop playing, the command is :

PLAY.STOP

 

The volume can be changed with the command:

PLAY.VOLUME vol

‘vol’ is by default 100 and represents the full volume (100%).

In case of sound files recorded with low volume, it is also possible to specify a value greater than 100.

Take into account that the output audio will saturate if the value is too high.

 

Example

PLAY.VOLUME 50  ‘set the sound at 50% of normal volume.

 

A new feature has been included that enables the creation of a VU meter for the left and right channels.

The functions PLAY.VU_L and PLAY_VU_R return the average value of the sound currently playing for the left and right channel.

These functions return a value between 0 and 32767.

This value is computed with the average of the last 1024 samples of the sound currently playing.

This can be eventually changed using the function PLAY.VU_AVERAGE value

It must be noted that this value must be converted in logarithmic scale before being used as a vu meter.

 

Metadata Decoding from Mp3 and streaming

Annex includes another functionality that automatically extracts the metadata information from the media playing.

The metadatas are information that are included inside the stream of data and contain useful information such as the title of the song, the artist, the name of the radio station, etc.

These are usually named ICY for the web radios and ID3 for the mp3 files.

As this information is “async” because it can arrive at any time during the listening, another event has been included for this purpose.

The name of this event is  ONPLAY label and it simply jumps at the label specified as soon as a play event occurs.

Is then possible to read the information received using the function play.message$

This function returns a message in the form of metaname=value

Example Artist=Police and Title=Roxanne

 

The following “metadata” information are implemented

 

Name

DESCRIPTION

Group

Title

The title of the song currently played

mp3

Artist

The mp3 file is playing

mp3

SiteName

Name of the web radio

Web radio

Genre

Genre of the web radio

Web radio

StreamTitle

The title of the song currently played

Web radio

Bitrate

Bitrate (in Kbs) of the web radio

Web radio

 

Another “special” metadata is also included that is raised when the mp3 song is over.

In this case play.message$ returns Status=end

This is useful to indicate to switch to the next song when using Annex as an mp3 file player.

SPEECH SYNTHESIS with vintage C64 SAM speaker

Annex integrates SAM, a port of the reverse-engineered speech synthesizer Software Automatic Mouth (SAM)

Sam is a very small Text-To-Speech (TTS) program written in C, that runs on most popular platforms. It is an adaptation to C of the speech software SAM (Software Automatic Mouth) for the Commodore C64 published in the year 1982 by Don't Ask Software (now SoftVoice, Inc.). It includes a Text-To-Phoneme converter called reciter and a Phoneme-To-Speech routine for the final output. It is so small that it also works on embedded computers.

The sound output and the volume follow the same rules defined in the previous chapter

 

To use it, the command is:

PLAY.SPEAK“message” [, phonetic]

Example

PLAY.SPEAK “The quick brown fox jumps over the lazy dog”

 

Using an optional parameter “phonetic” to 1, it is possible to use the synthesys in phonetic mode

 

This table lists the phonemes available:

 

VOWELS                            VOICED CONSONANTS

IY           f(ee)t                    R        red

IH           p(i)n                     L        allow

EH           beg                       W        away

AE           Sam                       W        whale

AA           pot                       Y        you

AH           b(u)dget                  M        Sam

AO           t(al)k                    N        man

OH           cone                      NX       so(ng)

UH           book                      B        bad

UX           l(oo)t                    D        dog

ER           bird                      G        again

AX           gall(o)n                  J        judge

IX           dig(i)t                   Z        zoo

                                       ZH       plea(s)ure

DIPHTHONGS                             V        seven

EY           m(a)de                    DH       (th)en

AY           h(igh)

OY           boy

AW           h(ow)                     UNVOICED CONSONANTS

OW           slow                      S         Sam

UW           crew                      Sh        fish

                                       F         fish

                                       TH        thin

SPECIAL PHONEMES                       P         poke

UL           sett(le) (=AXL)           T         talk

UM           astron(omy) (=AXM)        K         cake

UN           functi(on) (=AXN)         CH        speech

Q            kitt-en (glottal stop)    /H        a(h)ead

 

 

The complete documentation of the original SAM can be found here :

http://www.retrobits.net/atari/sam.shtml

 

SPEECH SYNTHESIS using google translate

Annex32 implements a feature permitting speech texts using the voice synthesis available in google translate.

Obviously this feature requires the module to be connected to the internet.

The command is PLAY.VOICE"message", "language" [, "filename"] [, action]

Example:

PLAY.VOICE"Hello World with Annex 32", "en" 'speech this text in english

 

The voice sound (in mp3 format) is first downloaded locally to the local disk then is played using the internal MP3 player.  By default the sound is saved as  /_voice.mp3 but the name can be changed using the optional parameter "filename".

This permits to “reuse” these saved “speech” files at a later time, simply playing them like regular mp3 files.

This is particularly useful because the voice download process is not immediate (it takes a few seconds).

 

 

The last optional parameter (action) can be used to modify the default behaviour as defined below :

 

VALUE

DESCRIPTION

0

Stop a sound in progress and speech

1 (default)

Waits for the end of the sound in progress and then speech

2

Simply save the sound as file on the disk

 

The message should be limited to less than 200 characters.

The language should be any valid google language code:

PLAY.VOICE"Hello World with Annex 32", "en" 'standard English British

PLAY.VOICE"Hello World with Annex 32", "en-US" ' US (American) English

PLAY.VOICE"Benvenuti in Annex 32", "it" ' Italian

PLAY.VOICE"Bonjour avec Annex 32", "fr" ' French

PLAY.VOICE"Bonjour avec Annex 32", "fr-CA" ' French Canadian

 

The complete list of google “language codes” can be found here :

https://cloud.google.com/text-to-speech/docs/voices

 

SPEECH SYNTHESIS using voiceRSS free service

Annex32 implements a feature permitting speech texts using the voice synthesis using the free service provided by voiceRSS (http://www.voicerss.org).

Before using this service it is necessary to register and get your API key.

The command is PLAY.voiceRSS"message", "language", "key" [, "filename"] [, action]

Example:

key$ = "7c39b2b5d21b4bd4bd23782a15384512"

PLAY.voiceRSS"Hello World with Annex 32","en-gb", key$ 'standard English British

 

The voice sound (in mp3 format) is first downloaded locally to the local disk then is played using the internal MP3 player.  By default the sound is saved as  /_voice.mp3 but the name can be changed using the optional parameter "filename".

This permits to “reuse” these saved “speech” files at a later time, simply playing them like regular mp3 files.

This is particularly useful because the voice download process is not immediate (it takes a few seconds).

 

The last optional parameter (action) can be used to modify the default behaviour as defined below :

 

VALUE

DESCRIPTION

0

Stop a sound in progress and speech

1 (default)

Waits for the end of the sound in progress and then speech

2

Simply save the sound as file on the disk

 

The language should be any valid language code defined in the API here http://www.voicerss.org/api/

key$ = "7c39b2b5d21b4bd4bd23782a15384512"

PLAY.voiceRSS"Hello World with Annex 32", "en-gb", key$'standard English British

PLAY.voiceRSS"Hello World with Annex 32", "en-us", key$  ' US (American) English

PLAY.voiceRSS"Benvenuti in Annex 32", "it-it", key$  ' Italian

PLAY.voiceRSS"Bonjour avec Annex 32", "fr-fr", key$  ' French

PLAY.voiceRSS"Bonjour avec Annex 32", "fr-ca", key$  ' French Canadian

 

Other parameters (such as the voice, the sample rate, the speed, ..) can be passed inside the language field (see below for the sample rate).

PLAY.voiceRSS"Hello World with Annex 8", "en-gb&f=8khz_16bit_mono", key$

 

By default the mp3 file is requested with 22khz_16bit_mono resolution.

 

check this page for more information about all the other optional parameters

http://www.voicerss.org/api/

 

VS1053B Audio Decoder

The VS1053B is a highly versatile audio codec chip known for its ability to decode a wide range of audio formats, including MP3, AAC, WMA, MIDI, Ogg Vorbis, and FLAC. When utilised together with Annex32, it enables users to seamlessly integrate advanced audio decoding capabilities into their projects. This combination facilitates the creation of multimedia applications with support for diverse audio formats, ensuring high-fidelity playback and enhancing the overall user experience.

Using this module, it is possible to play sound files directly from the disk (FATFS or SD card) as well as stream Web Radio. This is where the module provides significant added value, as it allows listening to nearly all available Web radio streams by decoding virtually all audio formats.

The VS1003B is also supported but with much less functionalities (for example the aac audio is not supported)

You can find easily several audio modules based on this chip as, for example, the ones shown below :

 

Module with VS1053B and SDCARD that can be used at the same timeimageimage

 

This module can be wired as shown below (including the SDCARD)

image

 

Module with VS1053B chip, (but take care that it's often sold with the cheaper VS1003B chip.)

 

 

 

 

 

 

 

imageimage

 

 

This module can be wired as shown below

image

Commands :

The usage of the module is very similar to that of sound player commands, with nearly identical syntax.

 

The first command to use is

VS1053.SETUP XCS_pin, XDCS_pin, DREQ_pin [,info_enabled] [,SPIfreq] [SCI_CLOCKF]

Where XCS_pin, XDCS_pin, DREQ_pin represent the pin used for the connection and the optional argument info_enabled if is 1, enable a more detailed report on what is happening in the background.

The other optional arguments are for advanced mode and will probably be removed in the future.

 

In the schematic examples above, the command should be:

VS1053.SETUP 12, 13, 15

Executing this command, the following message should be shown in the console:

The version is 4 (VS1053)

If the message is different, check the wiring or check if the module is a VS1053B and not a VS1003B!

 

To play any music file, the command is simply

VS1053.PLAY file$

Where file$ can be any valid music file identified by the extension of the file as per the table below :

 

FILE FORMAT

FILE EXTENSION

MP3

.mp3

AAC

.aac

WAV

.wav

MPEG 4 Audio

.m4a

FLAC

.flac

OGG

.ogg

MIDI (format 0 only)

.mid

 

Example

VS1053.PLAY "/mp3/MyMusic.mp3"

or

VS1053.PLAY "/wav/MySound.wav"

or

VS1053.PLAY "/midi/MyMidi.mid"

 

To play web radios streaming the command is

VS1053.STREAM streaming_url$

Example

VS1053.STREAM"http://audio4.nemostream.tv:8011/autodj"

or

VS1053.STREAM"https://radioitaliasmi.akamaized.net/hls/live/2093120/RISMI/stream01/streamPlaylist.m3u8"

 

Annex32 implements a feature permitting speech texts using the voice synthesis available in google translate.

Obviously this feature requires the module to be connected to the internet.

The command is

VS1053.VOICE "message", "language"

Example:

PLAY.VOICE"Hello World with Annex 32", "en" 'speech this text in english

 

The voice sound (in mp3 format) is first downloaded locally to the local disk as  /_voice.mp3 and then is played using the internal MP3 player.

 

To stop playing, the command is

VS1053.STOP

 

The volume can be changed with the command:

VS1053.VOLUME vol

Vol is by default 21 and represents the full volume (100%). It can vary from 0 (mute) to 21 (loudest)

Example

VS1053.VOLUME 10

 

In case of problem, the module can be reset using the command

VS1053.RESET

 

Advanced functionalities

The VS1053B is a powerful DSP chip that can also be "reprogrammed" via software "patches" loaded at runtime. These "patches" can range from simple bug corrections to the implementation of new audio codecs (such as FLAC) or new functionalities (such as audio equaliser, spectrum analyser, MIDI mode, etc.).

 

Annex implements a specific function that enables the loading of these "patches" into the chip. The patches are simply text files (usually with the .cmd extension) containing a list of commands to be sent to the VS1053B. After this loading phase, the new functionality/mode becomes available.

 

These “patches” can be downloaded directly from the VLSI website

 

The command to upload the patch is :

VS1053.INIT patchFile$ 

The example below upload a patch that implements the FLAC decoder

VS1053.INIT "/patches/vs1053b-patches-flac.cmd"

 

Some patches / functionalities require reading / writing inside the internal DSP registers.

For these reasons the following command / function have been implemented :

VS1053.WRITE register, value

 

VS1053.READ register

 

MIDI special mode

Loading a special “patch” it is possible to put the module in real-time MIDI mode.

This permits to send MIDI commands and play MIDI notes directly using the following commands :

 

VS1053.MIDI_CMD cmd, data1, data2

VS1053.NOTE_ON channel, note, velocity

VS1053.NOTE_OFF channel, note, velocity

 

This example plays a note for 1 second :

vs1053.setup 12, 13, 15

vs1053.volume 21

vs1053.init "/patches/rtmidistart.cmd" 'upload the start midi patch

vs1053.midi_cmd &hC0, &h40, 0

vs1053.note_on 0, 60, 127

pause 1000

vs1053.note_off 0, 60, 127

 

LCD DISPLAY USING I2C

An LCD display can be connected to the module using I2C interface.

These displays are very cheap and available on Ebay at less than 4€.

This picture shows an LCD with 4 lines at 20 characters per line.

image

In general these displays are based on the chip HD44780 and work with a parallel interface.

Because the number of pins available on the ESP module is very limited, there is an additional module (usually supplied with the display) which allows connection using the 2-wire I2C bus.

 

This picture shows the module (generally soldered in the back of the display) enabling the I2C connection.

image

These modules are based on the chip PCF8574 and have the following relationship between the display pins and the bits of the PCF8574:

 

PCF8574 BIT

LCD SIGNAL

 

PCF8574 BIT

LCD SIGNAL

BIT 0

RS

 

BIT 4

D4

BIT 1

RW

 

BIT 5

D5

BIT 2

E

 

BIT 6

D6

BIT 3

BACKLIGHT

 

BIT 7

D7

 

However, this mapping is managed directly into the ESP module so you don’t need to worry about it.

The only important information is the I2C address of the display which may change depending on the card.

The connection is very simple, just 2 pins for the I2C  and the power supply are required.

image

An important point is that the display must be powered with 5V because it will not work at 3.3 V.

 

In order to use the LCD, there are 2 steps :

-       Initialise the I2C bus

-       Init the display

This can be done with the following commands :

 

I2C.SETUP 21, 22  ' set I2C port on pins 21 and 22

LCD.INIT 63, 20, 4  ‘ init an LCD at address 63 (3F in hex) with 20 characters per line and 4 lines

 

After these 2 lines, there are 2 additional commands available :

LCD.CLS  ‘ clear the screen of the LCD

LCD.PRINT x, y, text$  ‘ print a text on the LCD at the position (x, y)

 

Example:

I2C.SETUP 21, 22  ' set I2C port on pins 21 and 22

'init an LCD at address 63 (3F in hex) with 20 characters per line and 4 lines

LCD.INIT 63, 20, 4

LCD.CLS  ' clear the screen of the LCD

'print a message on the LCD at the first char of the first line

LCD.PRINT 1, 1, "HELLO WORLD"

 

In addition it is possible to control the backlight of the display using the functions

LCD.OFF  ' turns OFF the backlight of the LCD

LCD.ON   ' turns ON  the backlight of the LCD                  

 

The LCD has the capability to hold 8 custom characters identified as the ASCII chars from 0 to 7.

The command LCD.CUSTOM char, array() enables to define these custom characters.

 

For example, to define the custom char 2 :

dim a(8) = 0, 0, 10, 21, 17, 10, 4, 0 'these are 8 bytes defining the 8 rows

LCD.CUSTOM 2, a() 'set the character 2

LCD.PRINT 1,1, CHR$(2) ' print the char

 

Finally the command LCD.WRITE char enables to print a single char;

It enables, in particular, to print the character 0 (that is ignored in LCD.PRINT).

 

For example, this program :

I2C.SETUP 4, 5  'set I2C port on pins 4 and 5

'init an LCD at address 63 (3F in hex) with 20 characters per line and 4 lines

LCD.INIT 63, 20, 4

LCD.CLS  ' clear the screen of the LCD

'print a message on the LCD at the first char of the first line

LCD.PRINT 1, 1, "HELLO WORLD"

'Create 8 custom chars

dim a(8) = 0, 0, 10, 21, 17, 10, 4, 0 'Heart

LCD.CUSTOM 0, a()

dim a(8) = 0, 0, 10, 31, 31, 14, 4, 0 'Heart filled

LCD.CUSTOM 1, a()

dim a(8) = 0, 10, 0, 0, 17, 14, 0, 0 'smile

LCD.CUSTOM 2, a()

dim a(8) = 0, 10, 0, 0, 14, 17, 0, 0 'sad

LCD.CUSTOM 3, a()

dim a(8) = 0, 14, 17, 17, 17, 10, 10, 27 'omega

LCD.CUSTOM 4, a()

dim a(8) = 4, 14, 31, 4, 4, 4, 4, 4 'arrow up

LCD.CUSTOM 5, a()

dim a(8) = 4, 4, 4, 4, 4, 31, 14, 4 'arrow down

LCD.CUSTOM 6, a()

dim a(8) = 0, 4, 10, 17, 10, 4, 0, 0 'diamond

LCD.CUSTOM 7, a()

 

LCD.print 1 ,2, ""  'set the cursor on the 2nd line

'Print the 8 custom chars

for z = 0 to 7

  LCD.WRITE z

next z

 

Will give this result on the LCD:

image

 

The custom characters can be created online using this website  https://maxpromer.github.io/LCD-Character-Creator/

image

For example, the char defined in the image, can be defined in annex as below :

 

dim a(8) = &h04, &h0E, &h1F, &h04, &h04, &h1F &h0E, &h04

LCD.CUSTOM 3, a()

 

 

OLED DISPLAY

An OLED display can be connected to the module using I2C interface.

These displays are very cheap and available on Ebay at less than 3€.

This picture shows an OLED with 128 x 64 pixels monochrome but the size is only 0.96".

 

image

 

This display is based on the chipset SSD1306

 

It is also possible to use a display based on the chipset SH1106.

The connection is very simple, just 2 pins for the I2C  and the power supply are required.

image

 

In order to use the OLED, there are 2 steps :

-       Initialise the I2C bus

-       Init the display

This can be done with the following commands :

 

I2C.SETUP 21, 22  ' set I2C port on pins 21 and 22

OLED.INIT orientation 'init with a given orientation (0 = normal, 1 = upside-down)

In case of the display SH1106, the command is

OLED.INIT orientation, 1 'init with a given orientation (0 = normal, 1 = upside-down)

 

After these 2 lines, there are several commands available :

OLED.CLS, OLED.COLOR, OLED.FONT, OLED.PIXEL, OLED.LINE, OLED.RECT, OLED.CIRCLE, OLED.PRINT, OLED.IMAGE, OLED.BMP, OLED.REFRESH

 

The current implementation of the OLED is based on a double buffering; this permits drawing in background on the screen while the current image is still shown. This technique permits to avoid flickering while drawing objects on the screen. The command OLED.REFRESH fmt  allows users to choose between an automatic refresh (OLED.REFRESH 1) or a manual refresh (OLED.REFRESH 0). By default the refresh is automatic.

 

When an automatic refresh is set, the image is immediately updated after each drawing command, whereas with the manual refresh, the image is refreshed only when an OLED.REFRESH command is executed.

 

The OLED.COLOR col defines the color to be used by the different drawing commands. As the display is monochrome, only the color 0 (black) and 1(white) can be defined; an additional color 2 (reverse) permits to draw objects in reverse to the existing color already present on the screen; useful to draw and clear the same object. By default the color is 1 (white).

 

The OLED.IMAGE x, y, image$ permits  to draw an image on the screen from a file. The file format must be XBM, a kind of ‘C’ source code. This format is not really popular but it is supported by the free tool Gimp.

 

The OLED.BMP x, y, image$  permits to draw an image on the screen from a file. The file format must be BMP b&w (2 colors).

 

The command OLED.FONT font_num permits to define the font to be used by the command OLED.PRINT.

There are 3 fonts available, ARIAL MT10,  ARIAL MT16,  ARIAL MT24.

 

Example:

I2C.SETUP 21, 22  ' set I2C port on pins 21 and 22

OLED.INIT 1 ' init the OLED upside-down

OLED.CLS ' clear the screen

OLED.FONT 2

OLED.COLOR 1

OLED.PRINT 10,10, "HELLO WORLD"

 

ST7920 LCD DISPLAY

An ST7920 LCD display can be connected to the module using SPI interface.

These displays are very cheap and available on Ebay at less than 5€.

This picture shows an ST7920 with 128 x 64 pixel monochrome.

 

Some cheap boards will have PSB connected to VDD (5v) This forces the parallel interface to be used. Before you connect your display check that pin 2 (VDD ,5v) and pin 15  (PSB) are not connected.  If they are you may need to cut a jumper. Otherwise you will short out your power supply, and the display will not work.

imageimage

 

This display is provided with a parallel interface BUT it can be used with a SPI interface, so only 3 pins are required.

image

In order to use the display, it must be initialised.

This can be done with the following command:

ST7920.INIT CS_pin

As per the wiring above, the command is

ST7920.INIT 15

 

After these 2 lines, there are several commands available :

ST7920.CLS, ST7920.COLOR, ST7920.FONT, ST7920.PIXEL, ST7920.LINE, ST7920.RECT, ST7920.CIRCLE, ST7920.PRINT, ST7920.IMAGE, ST7920.BMP,ST7920.REFRESH

 

The current implementation of the ST7920 is based on a double buffering; this permits drawing in background on the screen while the current image is still shown. This technique permits to avoid flickering while drawing objects on the screen. The command ST7920.REFRESH fmt allows users to choose between an automatic refresh (ST7920.REFRESH 1) or a manual refresh (ST7920.REFRESH 0). By default the refresh is automatic.

 

When an automatic refresh is set, the image is immediately updated after each drawing command whereas, with the manual refresh, the image is refreshed only when an ST7920.REFRESH command is executed.

 

The ST7920.COLOR col defines the color to be used by the different drawing commands. As the display is monochrome, only the color 0 (black) and 1(white) can be defined; an additional color 2 (reverse) permits to draw objects that reverse the existing color already present on the screen; useful to draw and clear the same object. By default the color is 1 (white).

 

The ST7920.IMAGE x, y, image$ permit to draw an image on the screen from a file. The file format must be XBM, a kind of ‘C’ source code. This format is not really popular but it is supported by the free tool Gimp.

 

The ST7920.BMP x, y, image$  permits to draw an image on the screen from a file. The file format must be BMP b&w (2 colors).

 

The command ST7920.FONT font_num permits to define the font to be used by the command ST7920.PRINT.

There are 3 fonts available, ARIAL MT10,  ARIAL MT16,  ARIAL MT24.

 

Example:

ST7920.INIT 15 ' init the ST7920 with the CS at the pin 15

ST7920.CLS ' clear the screen

ST7920.FONT 2

ST7920.COLOR 1

ST7920.PRINT 10,10, "HELLO WORLD"

 

RTC module

A module based on chipset DS1307 or DS3231 can be connected to the module using the I2C interface.

These modules are very cheap and available on Ebay at less than 2€ (check if battery is included).

This picture shows a DS3231 module which is very compact and already contains two 4.7K I2C pullups :

               image                                image

The connection is very simple, just 2 pins for the I2C  and the power supply are required.

image

 

Available Instructions:

RTC.DATE$[(format)]

RTC.TIME$

RTC.SETTIME Year, Month, Day, Hours, Minutes, Seconds

 

The use of the RTC module is very simple.

First the I2C must be initialised with the command I2C.SETUP.

Then the date and the time can be read with the string functions RTC.TIME$ and RTC.DATE$.

 

This time and date can be manually set using the command RTC.SETTIME.

The Syntax is :

RTC.SETTIME Year, Month, Day, Hours, Minutes, Seconds

 

Example

Set the date to 02 September 2017 at 13:58:12

 

RTC.SETTIME 17, 9, 2, 13, 58, 12

 

Example

I2C.SETUP 21, 22  ' set I2C port on pins 21 and 22

Print "The date is " + RTC.DATE$

Print "The time is " + RTC.TIME$

 

PCA9685 (PWM / Servo) Module

A PWM / Servo module based on chipset PCA9685  can be connected to the module using the I2C interface.

These modules are very cheap and available on Ebay at less than 2€.

This picture shows a PCA9685 module that makes available up to 16 PWM / Servo outputs.

The PCA9685 is an I²C-bus controlled 16-channel controller optimized for Red/Green/Blue/Amber (RGBA) color backlighting applications. It operates at a programmable frequency from a typical of 24 Hz to 1526 Hz. All outputs share the same PWM frequency.

The duty cycle for each output is adjustable from 0 % to 100 % with 12-bit resolution (4096 steps).

It can also be used to control servo actuators, simply specifying the PWM frequency at 50 Hz.

imageimage

This module must be connected using I2C and, because it already contains two 10K I2C pullups, no external resistors are required.

image

Available Instructions:

PCA9685.SETUP address

PCA9685.SETFREQ freq

PCA9685.PWM pin, value

 

In order to use the module, it must be first set with the command PCA9685.SETUP address

Then the PWM frequency can be set with the command PCA9685.SETFREQ freq

FInally, the outputs can be driven with the command PCA9685.PWM pin, value

 

This is an example that drives 2 servos connected on outputs 0 and 1.

PCA9685.SETUP &H40, 55

PCA9685.SETFREQ 50

PCA9685.PWM 0, 150

PCA9685.PWM 1, 100

 

DX = 1

DY = 1

MINX = 100 : MAXX = 500

MINY = 150 : MAXY = 300

X = MINX : Y = MINY

 

WHILE 1

  PCA9685.PWM 0, Y

  PCA9685.PWM 1, X

  PAUSE 30

  PRINT Y, DY, MAXY

  X = X + DX

  Y = Y + DY

  IF (X < MINX) OR (X > MAXX) THEN DX = - DX

  IF (Y < MINY) OR (Y > MAXY) THEN DY = - DY

WEND

END

TM1637 display module

A display module based on the chipset TM1637 with 4 7-segments display can be connected to the module.

These modules are very cheap and available on Ebay at around 1€.

This picture shows a module with 4 digits at 0.36”.

 

image       image

The following picture shows another module with 4 digits at 0.56”.

image

The following picture shows another module with 6 digits at 0.56”.

image

Notice that some modules have the “colon” points in the middle, some have the decimal points and some other have 6 digits including the decimal points

 

The connection is very simple, just 2 pins and the power supply are required.

 

Even if the protocol is very similar to the I2C, it is quite different, so the I2C pins used for other I2C devices cannot be shared as this will conflict.

image

 

Available Instructions are:

TM1637.SETUP data_pin, clock_pin [, bit_delay] [, display_type]

TM1637.PRINT msg$ [, brightness]

 

To use it, is very simple.

First initialise the display with the command TM1637.SETUP

With the wiring above, the command must be :

TM1637.SETUP 15, 16

Note that some modules may already include i2c pullup resistors on board (so simply try first without).

It is important to highlight that some display modules may have a capacitor on the input pins.

In that case it will require an extra parameter (bit_delay) at the end of the setup command.

This value can be experimentally found, but a value of 100 should be appropriate for all the modules.

Example :  TM1637.SETUP 15 16, 100

If a “6 digits display” must be connected, another extra parameter  (display_type) is required.

Example :  TM1637.SETUP 15 16, 100, 1

The display can be used with the command TM1637.PRINT msg$ [, brightness]

Where

msg$ is a text string that contains the message to show

brightness defines the luminosity of the display from 0 (OFF) to 7 (MAX); if omitted the value is 7

 

All ASCII characters can be used but will be shown within the limitation of the 7 segments of the display.

The decimal point and the colon (:) are automatically managed so, to print 12:34 on the display, simply use

TM1637.PRINT "12:34" or  TM1637.PRINT "1.234"

 

Example

TM1637.SETUP 15, 16, 100

For i = 0 to 9999

  TM1637.PRINT str$(i), 4

Next i

 

 

TM1638 display module

A display module based on the chipset TM1638 with 8 7-segments display can be connected to the module.

These modules provide 8 LEDs, 8 Digits and 8 Keypad Interface.

These modules are very cheap and available on Ebay at around 2€.

This picture shows a module with 8 digits at 0.36”, 8 leds and 8 buttons

 

image

The connection requires 3 pins plus the power supply.

image

 

 

Available Instructions are:

TM1638.BUTTONS

TM1638.PRINT msg$ [, brightness ]

TM1638.SETUP data_pin, clock_pin, strobe_pin

TM1638.LEDS val

 

To use it is very simple.

First initialise the display with the command TM1638.SETUP data_pin, clock_pin, strobe_pin

With the wiring above, the command must be :

TM1638.SETUP 21, 22, 15

The display can then be used with the command TM1638.PRINT msg$ [, brightness ]

Where

msg$ is a text string that can contain up to 8 chars ,

brightness defines the luminosity of the display from 0 (OFF) to 15 (MAX); if omitted the value is 15

All ASCII characters can be used but will be shown within the limitation of the 7 segments of the display.

 

Example

TM1638.SETUP 21, 22, 15

For i = 0 to 9999

  TM1638.PRINT str$(i)

Next i

 

As the module also contains 8 leds, it is possible to control them using the command TM1638.LEDS val.

val is a 8 bit number where each bit is associated to a led.

Example

TM1638.SETUP 21, 22, 15

For i = 0 to 255

  TM1638.LEDS i

Next i

 

It is also possible to get the status of the buttons with the function TM1638.BUTTONS

Example

TM1638.SETUP 21, 22, 15

For i = 0 to 5000

  Print TM1638.BUTTONS

Next i

 

MAX7219 8-Digits 7-segment display

A display module based on the chipset MAX7219 with 8 7-segments display can be connected to the module.

These modules provides  8 Digits 7-segments display including dot points.

These modules are very cheap and available on Ebay at around 2€.

This picture shows a module with 8 digits at 0.36”.

image

image

The wiring is done using the SPI bus plus a dedicated CS pin.

image

Available Instructions are:

MAXDISPLAY.SETUP CS_pin

MAXDISPLAY.PRINT msg$ [,brightness]

 

To use it is very simple.

First initialise the display with the command MAXDISPLAY.SETUP CS_pin

With the wiring above, the command must be :

MAXDISPLAY.SETUP 15

The display can then be used with the command MAXDISPLAY.PRINT msg$ [,brightness]

Where

msg$ is a text string that can contains up to 8 chars ,

brightness defines the luminosity of the display from 0 (OFF) to 15 (MAX); if omitted the value is 15

All ASCII characters can be used but will be shown within the limitation of the 7 segments of the display.

 

Example

MAXDISPLAY.SETUP 15

For i = 0 to 9999

  MAXDISPLAY.PRINT str$(i)

Next i

 

MAX7219 Dot Matrix Display

It is also possible to connect dot matrix modules based on the chipset MAX7219.

These modules contain 4 8x8 dot matrix displays each one with a dedicated MAX7219 chip.

These modules can be chained in order to compose a larger display.

The picture shows a module available on Ebay at around 5€.

image

image

 

The wiring is done using the SPI bus plus a dedicated CS pin.

image

 

Available Instructions are:

MAXSCROLL.SETUP nb_devices, CS_pin

MAXSCROLL.PRINT msg$

MAXSCROLL.NEXT msg$

MAXSCROLL.TEXT msg$

MAXSCROLL.SHOW position [, brightness]

MAXSCROLL.SCROLL [brightness]

MAXSCROLL.OSCILLATE [brightness]

 

To use it, the first command required is the setup of the display.

This can be done with the command MAXSCROLL.SETUP nb_devices, CS_pin.

The first argument defines the number of 8x8 displays connected; using the module shown above, the number is 4. 

The 2nd argument defines the pin used for the CS signal; using the schematic shown above the pin is 15 (GPIO15). In our case the command must be :

 MAXSCROLL.SETUP 4, 15

 

The text can then be set on the display with 3 different commands :

1.    MAXSCROLL.PRINT msg$

2.    MAXSCROLL.NEXT msg$

3.    MAXSCROLL.TEXT msg$

The first will set the text that will be shown at the beginning, the 2nd will set the text that will be shown when the first one will be scrolled out of the display and the 3rd will permit to modify immediately the text shown.

 

For example, 

MAXSCROLL.PRINT "Hello"

MAXSCROLL.NEXT "Friend"

 

Will permit to show “Hello” at the beginning; then as soon as “Hello” is scrolled out of the screen, the text “Friend” will be shown and it will scroll on the display forever until the next execution of the command MAXSCROLL.NEXT msg$

 

The command MAXSCROLL.TEXT msg$ will permit to modify the text during the scrolling sequence, useful for “dynamic” messages (i.e time/date information).

 

The command MAXSCROLL.SHOW position [, brightness] will permit to move the text in a given position.

The position 1 is the rightmost line of the display, and increasing this value will move the text more to the left.

Optionally it is possible to define the brightness of the display.

 

The last set of commands is composed of

1.    MAXSCROLL.SCROLL [brightness]

2.    MAXSCROLL.OSCILLATE [brightness]

 

The first will permit to scroll the text from the right to the left and, when the text will be completely scrolled out, it will restart again with the same text or, if defined, with the text set with the command MAXSCROLL.NEXT.

 

The 2nd will permit to scroll the text from the right to the left and, when the text will be completely scrolled out, it will be scrolled back in the opposite direction until it will reach the initial position, then the process will restart again.

 

These 2 commands have an optional parameter permitting to define the luminosity of the display in a range from 0 (min) to 15 (max); the default value is 0.

 

As the message requires a continuous scrolling, these commands must be called on a timed interval (using a timer).

 

Let us show an example using the SCROLL command

'Set 4 8x8 displays with GPIO15 as CS pin

MAXSCROLL.SETUP 4, 15

'Set the first message as the current time

MAXSCROLL.PRINT TIME$

'Set the second message as the current date

MAXSCROLL.NEXT DATE$

'Set the refresh rate of the display (50 msec) - lower values -> scroll faster

TIMER0 50, SCROLLME

WAIT

 

SCROLLME:

 'Scroll the display with an intensity of 5

 MAXSCROLL.SCROLL 5

RETURN

 

This is another example using the OSCILLATE command:

'Set 4 8x8 displays with GPIO15 as CS pin

MAXSCROLL.SETUP 4, 15

'Set the message

MAXSCROLL.PRINT "Hello World"

'Set the refresh rate of the display (50 msec) - lower values -> scroll faster

TIMER0 50, SCROLLME

WAIT

 

SCROLLME:

 'Oscillate the display with an intensity of 5

 MAXSCROLL.OSCILLATE 5

RETURN

 

NeoPixel WS2812B led strips

It is possible to connect NeoPixel led strips based on WS2812B Leds.

These strips are generally available in a linear form but also as a circular array.

imageimage

 

The wiring is very simple as only one output pin is required for the ESP32.

 

The strips must be supplied at 5V with a dedicated power-supply.

As each led could require up-to 60mA, the power supply must be sized in consequence.

 

The strip is considered as a sequence of leds where each one has a position and can have a different color.

From a logical point of view, even the circular array is seen as a linear strip with a start and end position.

Then the following commands are available :

 

 

FUNCTIONS / COMMANDS

DESCRIPTION

NEO.SETUP pin, [nb_led]

Setup the led strip.

The first argument defines the GPIO pin used and the 2nd argument defines the number of leds of the strip

NEO.STRIP led_start_pos, led_end_pos, R, G, B [, disable]

Set the leds from the position led_start_pos to the position led_end_pos with the color defined by R, G and B. The optional argument [, disable] if set to 1, permits to write new led values into memory without refreshing the strip.

NEO.STRIP led_start_pos, led_end_pos, COLOR [, disable]

Set the leds from the position led_start_pos to the position led_end_pos with the color defined by COLOR. The optional argument [, disable] if set to 1, permits to write new led values into memory without refreshing the strip.

NEO.PIXEL led_pos, R, G, B [, disable]

Set the led at the position led_pos with the  color defined by R, G and B. The optional argument [, disable] if set to 1, permits to write new led values into memory without refreshing the strip.

NEO.PIXEL led_pos, COLOR [, disable]

Set the led at the position led_pos with the color defined by COLOR. The optional argument [, disable] if set to 1, permits to write new led values into memory without refreshing the strip.

NEO.RGB(R, G, B)

Returns a combined color containing the R, G and B components

NEO.GETPIXEL(led_pos)

Returns the combined color of the pixel at the position led_pos

NEO.ROTATELEFT num_steps, [led_end_pos, led_end_pos, disable]

Rotate left the leds of num_steps from the position led_start_pos to the position led_end_pos. The optional argument [, disable] if set to 1, permits to write new led values into memory without refreshing the strip.

NEO.ROTATERIGHT num_steps, [led_end_pos, led_end_pos, disable]

Rotate right the leds of num_steps from the position led_start_pos to the position led_end_pos. The optional argument [, disable] if set to 1, permits to write new led values into memory without refreshing the strip.

NEO.SHIFTLEFT num_steps, [led_end_pos, led_end_pos, disable]

Shift left the leds of num_steps from the position led_start_pos to the position led_end_pos. The optional argument [, disable] if set to 1, permits to write new led values into memory without refreshing the strip.

NEO.SHIFTRIGHT num_steps, [led_end_pos, led_end_pos, disable]

Shift right the leds of num_steps from the position led_start_pos to the position led_end_pos. The optional argument [, disable] if set to 1, permits to write new led values into memory without refreshing the strip.

NEO.REFRESH

Refresh the strip from the internal buffer memory

NEO.DIM(COLOR , Gain)

Returns a color with a given gain.

If gain is 1, returns the original color

If gain is below 1, returns a darker color

If gain is greater than 1, returns a brighter color

NEO.LIGHTEN(COLOR , Gain)

Returns a color blended toward white

Gain can go from 0 (original COLOR) to 1 (white)

NEO.DARKEN(COLOR , Gain)

Returns a color blended toward black

Gain can go from 0 (original COLOR) to 1 (black)

NEO.LINEARBLEND(COLOR1, COLOR2, progress)

Returns a color blended toward COLOR1 and COLOR2,

Gain can go from 0 (COLOR1) to 1 (COLOR2)

NEO.BILINEARBLEND(
Upper_Left_COLOR, Upper_Right_COLOR, Lower_Left_COLOR, Lower_Right_COLOR, x, y)

Returns a color blended toward 4 colors by the amount defined by 2 variables, x and y.

With x=0 and y=0 returns Upper_Left_COLOR

With x=1 and y=0 returns Lower_Left_COLOR

With x=0 and y=1 returns Upper_Right_COLOR

With x=1 and y=1 returns Lower_Right_COLOR

 

 

 

 

 

 

 

 

 

 

 

The first command, NEO.SETUP pin, [nb_led], defines the pin to be used as output and the size (in pîxels) of the led strip.

For example  NEO.SETUP 2, 60  defines a strip containing 60 leds (or a ring with 60 leds) connected on the pin GPIO02.

This creates a local memory buffer of the strip line permitting the manipulation of the colors in the background.

 

Then, the leds of the strips can be addressed taking into account that the first led has the position 0 and the last has the position (nb_led - 1).

For example, using the declaration  NEO.SETUP 2, 60, the last led has the position 59.

 

The leds can then be addressed individually using the command NEO.PIXEL or as a block using the commandNEO.STRIP.

 

For example, NEO.PIXEL 10, 255, 0, 0  sets the led at the position 10 with the color RED and the command NEO.STRIP 20, 30, 0, 0, 255  sets the leds at positions 20 through 30 with the color BLUE

 

The colors can be specified as a sequence of 3 numbers from 0 to 255 representing the intensity for the Red, Green and Blue components, or as a single 24bit number where the 3 colors are merged together as one.

 

The function NEO.RGB(R, G, B) permits to generate this merged color.

 

For example, these 3 commands produce the same effect :

 NEO.STRIP 0, 10, 0, 255, 0

 NEO.STRIP 0, 10, NEO.RGB(0, 255, 0)

 NEO.STRIP 0, 10, 65280

 

The optional argument [, disable] if set to 1, permits to write new led values into memory without refreshing the strip. This is useful to manipulate several leds, refreshing the complete line only when required.

 

For example, with the following program, all the leds will be refreshed one by one at 100ms interval :

NEO.SETUP 2, 60

FOR z = 0 TO 59

  NEO.PIXEL z, 128

  PAUSE 100

NEXT z

 

But, with the following program, all the leds will be updated in a single shot at the end (after 6 seconds) :

NEO.SETUP 2, 60

FOR z = 0 TO 59

  NEO.PIXEL z, 128, 1

  PAUSE 100

NEXT z

NEO.REFRESH

NeoPixel based WS2812b Dot Matrix DIsplay

It is also possible to connect Dot Matrix modules based on WS2812B Leds.

These modules contain 64 WS2812B leds organised in an 8x8 matrix.

Several modules can be chained in order to compose a large display.

imageimage

They can also be spanned in several chained lines to compose taller displays.

The wiring is very simple as only one output pin is required for the ESP32.

The modules must be supplied at 5V with a dedicated power-supply.

image

It must be taken into account that these 8x8 modules can require a lot of current, in particular if all the leds are at max intensity.

As each led could require up-to 60mA, the power supply must be sized accordingly.

From a practical point of view, the displays will probably never show all the pixels at the same time, so we can consider at least 2 amps per display (so 20 amps for 10 displays).

 

The displays available on the market can be arranged differently using a “normal” or a “serpentine” layout.

Several configurations are supported; use the LAYOUT number below each image below in the NEOSCROLL.SETUP command

 

LAYOUT 0 and 1

image

 

LAYOUT 2 and 3

image


 

 

LAYOUT 4 and 5

image

 

The actual implementation is based on a “canvas” where it is possible to draw any content using pixels, texts, images and then scroll it horizontally or vertically as desired.

This gives a great flexibility as the message can be composed of any combination of elements (Text + images, for example) and changed dynamically during the scrolling process.

This could be considered as a kind of TFT display with the resolution determined by the number of leds present.

For the same reason, the colors (65K) and the fonts are managed in the same way as for the TFT (more details inside the TFT chapter).

 

All the actions on the display (write text, drawing bmp, …) are done internally into a memory space reserved for that scope. The result will be transferred on the display itself only when using the command NEOSCROLL.SHOW or the commands NEOSCROLL.SCROLL / NEOSCROLL.OSCILLATE.

The advantage of this approach is that an image containing several elements can be prepared in the background and transferred to the display only when it has been completed.

Available Instructions are:

 

FUNCTIONS / COMMANDS

DESCRIPTION

NEOSCROLL.SETUP nb_devices, nb_lines, pin [,layout] [,width, height, orientation]

Setup the Neoscroll display.

The first argument defines the number of devices connected eventually spanned on several lines; for the layouts 2 and 3, this represents the number of leds for each line

The 2nd argument defines the number of lines composed by the modules; for the layouts 2 and 3 this represents the number of lines of pixels (and not modules)  using the schematic shown above, the number is 1.

The 3rd argument defines the pin used for the input signal; using the schematic shown above the pin is 2 (GPIO2).

The 4th argument defines the layout of the display itself arranged following the layout shown in the pictures above.

The optional 5th and 6th arguments define the size of the ‘canvas’ that will be created.

If not specified, the canvas will have the same size as the display (in pixels).

The optional 7th argument, if set to 1, will reverse the image upside-down.

NEOSCROLL.DELETE

Remove the driver from the memory in the eventuality that is not required anymore.

NEOSCROLL.FILL color, [x, y, width, height]

Fill the display with a given color; by default the complete canvas is filled with this color but only a specific area can be defined giving the other parameters.

NEOSCROLL.TEXT.POS x, y

Set the position where the text will be drawn. By default the position is set at the bottom left of the display to comply with the Adafruit GFX font format that use the lower position of the font as reference.

NEOSCROLL.TEXT.FONT font

Set the font that must be used; by default there is a font #1 that is 5x7 proportional. The font 10 to 13 can be used loading them with the TFT.LOADFONT command

NEOSCROLL.SHOW x, y

Transfer the content of the internal memory space to the display itself so that the image will be refreshed.

‘x’ and ‘y’ represent the offset of the initial position to be shown.

NEOSCROLL.TEXT.BRIGHTNESS brightness

Set the brightness of the text to draw; can be different for each text drawn.

Its value can be from 0 to 255 and defaults to 255

NEOSCROLL.BRIGHTNESS brightness

Set the brightness of the entire image; the effect will be visible only at the next screen redraw.

Its value can be from 0 to 255 and defaults to 128

NEOSCROLL.PRINT text$, color$

Print a text on the canvas at the current cursor position using the current font..

The ‘text$’ itself is coupled to the ‘color$’ information where each character defines the color of each character of the text. The logic is based on a one-to-one correspondence between the text string and the color string.

If the color string is shorter than the text or is missing the color will be the last color used.

 

B

TFT_BLUE

b

TFT_NAVY

C

TFT_CYA;

c

TFT_DARKCYAN

G

TFT_GREEN

g

TFT_DARKGREEN

K

TFT_BLACK

k

TFT_DARKGREY

M

TFT_MAGENTA

m

TFT_MAROON

R

TFT_RED

r

TFT_DARKRED

Y

TFT_YELLOW

y

TFT_GREENYELLOW

O

TFT_ORANGE

o

TFT_OLIVE

P

TFT_PURPLE

p

TFT_PINK

W

TFT_WHITE

w

TFT_LIGHTGREY

S

TFT_SILVER

NEOSCROLL.SPRITESHEET image$

Load a BMP color image in memory. Portions of this image can be extracted and copied into the canvas afterwards

NEOSCROLL.SPRITE x, y, width, height, x_in_bmp, y_in_bmp
Copy a portion of the SPRITESHEET image into the canvas using the parameters given
NEOSCROLL.LIMITS [x1,] [x2], [y1], [y2]

Defines the limits of the scrolling area. By defaults these are automatically set at the size of the canvas but can be modified dynamically to scroll only a given portion of the canvas.

NEOSCROLL.SYNC

Can be used to sync the LIMITS after a printing / drawing command.

NEOSCROLL.MODE mode

Set the scrolling mode as below

 

0

Horizontal from right to left

1

Vertical from bottom to top

2

Horizontal from left to right

3

Vertical from top to bottom

NEOSCROLL.SCROLL
NEOSCROLL.SCROLL 
Scroll the image using the current MODE and within the current LIMITS.c

If used as a function, it returns a value of 1 when the animation is over (limit reached); this is useful to determine when the message must be changed

NEOSCROLL.OSCILLATE
NEOSCROLL.OSCILLATE
Oscillate the image using the current MODE and within the current LIMITS.c

If used as a function, it returns a value of 1 when the animation is over (limit reached); this is useful to determine when the message must be changed

NEOSCROLL.X

Returns the current X position

NEOSCROLL.Y

Returns the current Y position

 

To use it, the first command required is the setup of the display.

This can be done with the command

NEOSCROLL.SETUP nb_devices, nb_lines, pin [,serpentine] [,width, height]

The first argument defines the number of 8x8 modules connected; using the schematic shown above, the number is 4. 

The 2nd argument defines the number of lines composed by the 8x8 modules; using the schematic shown above, the number is 1.

The 3rd argument defines the pin used for the input signal; using the schematic shown above the pin is 2 (GPIO2).

The 4th argument defines if the display itself is arranged in a linear way or as a serpentine.

If it is 0 (default) the normal layout is selected, if it is 1, the serpentine layout is chosen.

The optional 5th and 6th arguments define the size of the ‘canvas’ that will be created.

If not specified, the canvas will have the same size of the display (in pixels).

 

 

In our case the command must be :

 NEOSCROLL.SETUP 4, 1, 2, 0 '4 displays, 1 row, pin 2, no serpentine

 

The text can then be set on the display with the following command

NEOSCROLL.PRINT text$, color$

 

This command will print a text at the actual cursor position (the left lower corner of the display, by default).

The cursor will be automatically moved at the end of this text so, a successive print, will be attached at the end

 

For example, 

NEOSCROLL.PRINT "Hello" , "RGBYM" 'will print Hello with different colors

NEOSCROLL.PRINT "Friend", "B" 'will print Friend in Blue after Hello

 

 

 

The command NEOSCROLL.SHOW x, y  will permit displaying the text in a given position.

Negative and positive values are possible

The position 0,0 corresponds to the left lower corner.

Specifying, for example 1,0 the the text shown will be shifted of 1 pixel at the left

 

 

The last set of commands is composed of

NEOSCROLL.SCROLL

NEOSCROLL.OSCILLATE

The first will permit to scroll the text from the right to the left and, when the text will be completely scrolled out, it will restart again with the same text

 

The 2nd will permit to scroll the text from the right to the left and, when the text will be completely scrolled out, it will be scrolled back in the opposite direction until it will reach the initial position, then the process will restart again.

 

These 2 commands can optionally be used as functions; in this case the returned value will be always 0 except when the animation is terminated (one of the limits reached); this can be used to determine the right moment for changing the scrolling message.

 

As the message requires a continuous scrolling, these commands must be called on a timed interval (using a timer).

 

Let us show a basic example

'Set 4 WS2812B displays with GPIO2 as input

neoscroll.setup 16, 2, 5, 0

neoscroll.fill 0

neoscroll.show 0, 0

neoscroll.print "Hello World", "R"

neoscroll.show 0,0

 

This is another example using the OSCILLATE command and vertical scroll:

'Set 8 WS2812B displays with GPIO2 as input

data "Hello World!", "rgbyMrgbyMrgbyM", 1

data "How are you?", "gyMrgbyM", 10

data "Annex&Neopixels", "byMvkwbrgbyM", 11

data "Feel so good!", "yMrgbyMrgbyM", 1

 

dim msg$(10)

dim col$(10)

dim myfont(10)

for z = 0 to 3

  read msg$(z), col$(z), myfont(z)

next z

seq = 0

nb_messages = z

wlog ramfree

neoscroll.setup 8, 1, 5, 0, 128, 128

 

for z = 0 to nb_messages -1

neoscroll.text.pos 0, z * 10 + 7

neoscroll.print msg$(z) + chr$(10), col$(z)

next z

 

neoscroll.mode 1'vertical

neoscroll.sync

neoscroll.limits 0,0, -7, 39

pause 100

 

timer0 100, scrolla

timer1 900, mytime

wait

 

scrolla:

a = neoscroll.oscillate

Return

 

mytime:

neoscroll.text.pos 0, 47

neoscroll.fill 0, 0, 40, 63, 47

neoscroll.print TIME$, "b"

return

 

This is another example with horizontal scroll and several fonts

'Set 16 WS2812B displays on 2 rows with GPIO2 as input

data "Good Morning", "rgbyMrgbyMrgbyM", 1

data "How are you?", "rgbyMrgbyM", 10

data "ANNEX AND NEOPIXELS", "rgbyMvkwbrgbyM", 11

data "WORKS VERY WELL TOGETHER", "rgbyMrgbyMrgMrgMrgMrgbyM", 1

 

dim msg$(10)

dim col$(10)

dim myfont(10)

for z = 0 to 3

  read msg$(z), col$(z), myfont(z)

next z

seq = 0

nb_messages = z

wlog ramfree

neoscroll.setup 16, 2, 2, 0, 512, 32

neoscroll.show 0, 0

tft.loadfont "/fonts/T3_16_Bold10pt7b.bin", 1

tft.loadfont "/fonts/FreeSerifBold12pt7b.bin", 2

neoscroll.spritesheet "/bmp16x16/danger.bmp"

set_message

neoscroll.sprite neoscroll.x, 0, 16, 16, 0, 0

neoscroll.sync

 

neoscroll.mode 0'horizontal

 

timer0 30, scrolla

wait

 

sub set_message

  neoscroll.fill 0 

  neoscroll.text.pos 0, 15

  neoscroll.text.font myfont(seq)

  neoscroll.print msg$(seq), col$(seq)

  wlog "dim", neoscroll.x, neoscroll.y

  neoscroll.sprite neoscroll.x, 0, 16, 16, 0, 0

  neoscroll.sync

  seq = seq + 1

  if seq >= nb_messages then seq = 0

end sub

 

scrolla:

a = neoscroll.oscillate

if (a = 1) then set_message

return

 

 

HUB75 Matrix Displays - DMAMATRIX

DMAMATRIX

 

-       Only the 64x64 panels are actually supported

-       The parameters specified with .INIT and .SETUP cannot be changed without resetting the module (this is a driver limitation limitation)

-       Only ESP32-S3 has been tested and supported actually

imageimage

 

image

 

FUNCTIONS / COMMANDS

DESCRIPTION

DMAMATRIX.INIT R1, G1, B1, R2, G2, B2, A, B, C, D, E, LAT, OE, CLK [,freq_DMA] [,resolution]

Defines the pin to be used for the display.

The optional ‘freq_DMA’ can be defined (by default is 20000000 -> 20Mhz)

The optional ‘resolution’ from 2 to 8 bits can be defined (by default is 8); lower value consumes less RAM memory 

DMAMATRIX.SETUP nb_devices, nb_lines [,layout] [,width, height, orientation]

Setup the Neoscroll display.

The first argument defines the number of devices connected eventually spanned on several lines; for the layouts 2 and 3, this represents the number of leds for each line

The 2nd argument defines the number of lines composed by the modules; for the layouts 2 and 3 this represents the number of lines of pixels (and not modules)  using the schematic shown above, the number is 1.

The 3th argument defines the layout of the display (not fully implemented; actually if this is an odd number, it enables a double buffer for the display itself; this speeds up the update operation as only the modified pixels are transferred to the DMA buffer memory).

The optional 4th and 5th arguments define the size of the ‘canvas’ that will be created.

If not specified, the canvas will have the same size as the display (in pixels).

The optional 6th argument, if set to 1, will reverse the image upside-down (not yet implemented).

 

IMPORTANT:

This command can be used only once in the code.

Calling it again with other parameters will not have any effects if the module is not rebooted before

DMAMATRIX.DELETE

Remove the driver from the memory in the eventuality that is not required anymore.

Do not work properly : the memory is released but a reset of the module is required for restarting the image

DMAMATRIX.FILL color, [x, y, width, height]

Fill the display with a given color; by default the complete canvas is filled with this color but only a specific area can be defined giving the other parameters.

DMAMATRIX.TEXT.POS x, y

Set the position where the text will be drawn. By default the position is set at the bottom left of the display to comply with the Adafruit GFX font format that uses the lower position of the font as reference.

DMAMATRIX.TEXT.FONT font

Set the font that must be used; by default there is a font #1 that is 5x7 proportional. The font 10 to 13 can be used loading them with the TFT.LOADFONT command

DMAMATRIX.TEXT.COLOR color

Set the default text color to be used

DMAMATRIX.SHOW [x, y]

Transfer the content of the internal memory space to the display itself so that the image will be refreshed.

‘x’ and ‘y’ represent the offset of the initial position to be shown; if omitted both default to 0

DMAMATRIX.TEXT.BRIGHTNESS brightness

Set the brightness of the text to draw; can be different for each text drawn.

Its value can be from 0 to 255 and defaults to 255

DMAMATRIX.BRIGHTNESS brightness

Set the brightness of the entire image; the effect will be visible only at the next screen redraw.

Its value can be from 0 to 255 and defaults to 90

DMAMATRIX.PRINT text$ [, color$ | color]

Print a text on the canvas at the current cursor position using the current font..

The ‘text$’ itself is coupled to the ‘color$’ information where each character defines the color of each character of the text. The logic is based on a one-to-one correspondence between the text string and the color string.

If the color string is shorter than the text or is missing the color will be the last color used.

 

B

TFT_BLUE

b

TFT_NAVY

C

TFT_CYA;

c

TFT_DARKCYAN

G

TFT_GREEN

g

TFT_DARKGREEN

K

TFT_BLACK

k

TFT_DARKGREY

M

TFT_MAGENTA

m

TFT_MAROON

R

TFT_RED

r

TFT_DARKRED

Y

TFT_YELLOW

y

TFT_GREENYELLOW

O

TFT_ORANGE

o

TFT_OLIVE

P

TFT_PURPLE

p

TFT_PINK

W

TFT_WHITE

w

TFT_LIGHTGREY

S

TFT_SILVER

DMAMATRIX.SPRITESHEET image$

Load a BMP color image in memory. Portions of this image can be extracted and copied into the canvas afterwards

DMAMATRIX.SPRITE x, y, width, height, x_in_bmp, y_in_bmp
Copy a portion of the SPRITESHEET image into the canvas using the parameters given
DMAMATRIX.LIMITS [x1,] [x2], [y1], [y2]

Defines the limits of the scrolling area. By default these are automatically set at the size of the canvas but can be modified dynamically to scroll only a given portion of the canvas.

DMAMATRIX.SYNC

Can be used to sync the LIMITS after a printing / drawing command.

DMAMATRIX.MODE mode

Set the scrolling mode as below

 

0

Horizontal from right to left

1

Vertical from bottom to top

2

Horizontal from left to right

3

Vertical from top to bottom

DMAMATRIX.SCROLL
DMAMATRIX.SCROLL 
Scroll the image using the current MODE and within the current LIMITS.c

If used as a function, it returns a value of 1 when the animation is over (limit reached); this is useful to determine when the message must be changed

DMAMATRIX.OSCILLATE
DMAMATRIX.OSCILLATE
Oscillate the image using the current MODE and within the current LIMITS.c

If used as a function, it returns a value of 1 when the animation is over (limit reached); this is useful to determine when the message must be changed

DMAMATRIX.PIXEL x, y, color

Draws a pixel

DMAMATRIX.LINE x1, y1, x2, y1, color

Draws a line

DMAMATRIX.CIRCLE x, y, radius, color [,fill]

Draws a circle

If ‘fill’ = 1 the circle will be filled

DMAMATRIX.RECT x, y, w, h, color [,fill]

Draws a rectangle

If ‘fill’ = 1 the rectangle will be filled

DMAMATRIX.X

Returns the current X position

DMAMATRIX.Y

Returns the current Y position

DMAMATRIX.POSX

Returns the current X position in the animation sequence

DMAMATRIX.POSY

Returns the current Y position in the animation sequence

DMAMATRIX.PLAYGIF gif$ [,x , y]

Plays an animated GIF image from disk.

The frames of the GIF image are shown immediately on the screen at the position x, y (or, if not defined, from 0,0).

Important : This is a blocking function

DMAMATRIX.LOADGIF gif$ [,x , y]

Load an animated GIF image in memory from disk.

The frames of the GIF image can extracted and copied into the canvas afterwards starting from the position x, y (or, if not defined, from 0,0)

DMAMATRIX.FRAMEGIF [do_not_show [,loop]]

Shows a frame of the GIF image.

By default the frame is shown directly; if the parameter ‘do_not_show” is 1, the frame is only loaded in the buffer.

If the parameter ‘loop’ is 1, the gif will loop (will repeat from the beginning when the last frame is reached).

This function returns 0 if the last frame has been reached or the number of ms to wait before the next frame to respect the GIF framerate.

 

 

SD CARD ADAPTER

An SD CARD can be connected using a module wired as below:

 

image

 

 

The following SD CARD modules have been successfully tested with Annex32:

 

Module for MicroSD with active buffer on board.

As this module sports a voltage regulator that converts 5V to 3.3V, it is required to bypass it using the connection as shown in the picture below:

 

image

image

 

 

 

Module for full size SD-CARD with passive adapters:

image

TFT DISPLAY ILI9341

A TFT Display based on chipset ILI9341 can be connected to the module using the SPI interface.

These displays are available on Ebay at different sizes from 2.2” to 3.2” and are very cheap.

The resolution of the display is 320 x 240 pixels with 65K colors.

They can also include a touchscreen controller to receive positional feedback via the SPI interface.

The model shown below is a 2.8” and contains an interface for the Touch Screen.

As the interface is SPI, the display requires at least 5 pins when connected as a display only and 6 when the touch screen is enabled.

Additionally these displays also include a  reader that can be used to connect an SDCARD to the module.

 

The image below shows an 2.8” display provided with touch screen interface:

image

image

These displays have a little jumper zone (J1) that must be solder-bridged if powering the module from 3.3V else it will be configured to work at 5v.

 

 

Wiring with touch and SDCARD

 

image

                             

 

image

 

 

 

 

 

In order to use the TFT, the first step is to initialise the Display

This can be done with the following commands :

TFT.INIT Orientation

 

Orientation is a number between 0 and 3 specifying the TFT orientation:

 

0

Portrait

1

Landscape

2

Portrait reversed

3

Landscape reversed

 

The display is initialised, by default, at 40MHz (40 000 000) but many displays can also work at 80Mhz.

This can be changed with the command

TFT.SETFREQ 80000000

Increasing the speed at 80 Mhz improve the performances of the display but this does not work for all the displays (for example does not works for the M5Stack)

 

The display can then be cleared with the command

TFT.FILL color

 

The display is now ready to receive drawing commands.

 

The list of commands and functions available is described further below in the Chapter “Lovyan GFX”

 

The color is defined as a number between 0 and 65535; this corresponds to the color format named 565 where 5 bits are dedicated to Red, 6 to green and 5 to blue.

The function TFT.RGB permits to specify the R,G,B components as numbers from 0 to 255.

For example the function TFT.RGB(255,0,0) defines the color RED and TFT.RGB(0,255,0) defines the color green.

 

It is also possible to define a color giving directly its name.

The function is TFT.COLOR(colorname)

Colorname can be :

 

BLACK

NAVY

DARKGREEN

DARKCYAN

MAROON

PURPLE

OLIVE

LIGHTGREY

DARKGREY

BLUE

GREEN

CYAN

RED

MAGENTA

YELLOW

WHITE

ORANGE

GREENYELLOW

PINK

BROWN

GOLD

SILVER

SKYBLUE

VIOLET

 

Optionally it is also possible to define the color directly with its name even without using the TFT.COLOR syntax.

For sake of clarity this shows all the possible ways to define the same color :

TFT.FILL 0

Or

TFT.FILL TFT.RGB(0, 0, 0)

Or

TFT.FILL TFT.COLOR(black)

Or

TFT.FILL black

 

The same logic can be applied for any command requiring a color such as

TFT.TEXT.COLOR red

 

However, TFT.COLOR(colorname) can be used into regular expressions as it returns the numeric value of the color whilst the colorname itself can be used only as argument in the functions that require a color.

 

For example

Col = TFT.COLOR(red) + TFT.COLOR(blue)

Is a valid expression

but

Col = Red + blue

Is not a valid expression.

 

The backlight of the display is controlled using a PWM output on the pin defined in the configuration of the module. By default, for the classic ESP32,  it is assigned to GPIO32.

The command TFT.BRIGHTNESS value (from 0 to 255) can be used to control the luminosity.

 

Look at the documentation for the details of each command.

 

Example :

Tft.init 1

tft.fill 0

for r = 0 to 30000 step 0.02

 d=r/6

 s=sin(r)*sin(5*r+d)*140+160

 c=cos(r)*sin(5*r+d)*100+120

 tft.circle s,c,10,rnd(65535),1

next r

 

It is also possible to save (dump) the content of the screen into a file on the disk (LFS or SDCARD).

Note: This will not work for all modules/TFTs because some do not allow reading through the SPI input bus or simply because the SPI input is not wired to the TFT.

This is the case, in particular, for the M5Stack.

 

The command is

TFT.SAVE “/dumpfile.bmp”.

The file will be stored in .BMP format.

 

 

 

TFT DISPLAY ILI9163

A TFT Display based on chipset ILI9163 can be connected to the module using the SPI interface.

These displays are available on Ebay in different sizes and are very cheap.

The model shown below is a 1.8”  with a resolution of 160 x 128 pixels with 65K colors.

 

As the interface is SPI, the display requires at least 5 pins.

Additionally these displays also include a card reader that can be used to connect an SDCARD to the module.

 

image

 

image

These displays have a little jumper zone (J1) that must be solder-bridged if powering the module from 3.3V else it will be configured to work at 5v.

 

 

TFT DISPLAY ILI9486

A TFT Display based on chipset ILI9486 can be connected to the module using the SPI interface.

These displays are available on Ebay with a size of 3.5” and are quite cheap.

The resolution of the display is 480 x 320 pixels with 65K colors.

They can also include a touchscreen controller to receive positional feedback via the SPI interface.

As the interface is SPI, the display requires at least 5 pins when connected as a display only, and 6 when the touch screen is used.

This display is a great option compared to the ILI9341 as the higher resolution enables the creation of nicer GUI pages with a better touchscreen interaction.

These displays have a connector adapter for the Raspberry Pi but can easily be used with Annex.

They are built on the Waveshare design and use a 16 bit serial interface based on the 74HC04, 74HC4040 and 2 x 74HC4094 logic chips.

The SPI max speed for these displays is 20Mhz.

This display  is configured to be supplied with 5V so the Voltage regulator must be bypassed (solder- bridged) if it is supplied with 3.3V.

image

image

 

image

TFT DISPLAY ILI9481

A TFT Display based on chipset ILI9481 can be connected to the module using the SPI interface.

These displays are available on Ebay with a size of 3.5” and are quite cheap.

The resolution of the display is 480 x 320 pixels with 65K colors.

They can also include a touchscreen controller to receive positional feedback via the SPI interface.

As the interface is SPI, the display requires at least 5 pins when connected as a display only, and 6 when the touch screen is used.

This display is a great option compared to the ILI9341 as the higher resolution and the quite large size of the screen enables the creation of nicer GUI pages with a better touchscreen interaction.

In addition it shares the same connector pinout with the ILI9341 modules so can then be used on PCBs already designed for the ILI9341.

The SPI max speed for these displays is 10 Mhz so it is quite slow.

Additionally these displays also include a  reader that can be used to connect an SDCARD to the module.

 

image

TFT DISPLAY ILI9488

A TFT Display based on chipset ILI9488 can be connected to the module using the SPI interface.

These displays are available on Ebay with a size of 3.5” and are quite cheap.

The resolution of the display is 480 x 320 pixels with 65K colors.

They can also include a touchscreen controller to receive positional feedback via the SPI interface.

As the interface is SPI, the display requires at least 5 pins when connected as a display only, and 6 when the touch screen is used.

This display is a great option compared to the ILI9341 as the higher resolution and the quite large size of the screen enables the creation of nicer GUI pages with a better touchscreen interaction.

In addition it shares the same connector pinout with the ILI9341 modules so can then be used on PCBs already designed for the ILI9341.

The SPI max speed for these displays is 40 Mhz.

Additionally these displays also include a  reader that can be used to connect an SDCARD to the module.

 

image

TFT DISPLAY ST7735

A TFT Display based on chipset ST7735 can be connected to the module using the SPI interface.

These displays are available on Ebay in different sizes and resolutions and are very cheap.

Because there are many variants of this display, Annex32 supports 8 different ST7735 settings in the config menu. You should try all of them until you find the one that matches your display.

The model shown below is a 0.96”  with a resolution of 160 x 80 pixels with 65K colors.

 

As the interface is SPI, the display requires at least 5 pins.

The backlight signal is not mandatory (the LED pin can be put to +3.3V for max intensity).

 

 

image

image

TFT DISPLAY ST7796

A TFT Display based on chipset ST7796 can be connected to the module using the SPI interface.

These displays are available on Ebay with a size of 4.0” and are quite cheap.

The resolution of the display is 480 x 320 pixels with 65K colors.

They can also include a touchscreen controller to receive positional feedback via the SPI interface.

As the interface is SPI, the display requires at least 5 pins when connected as a display only, and 6 when the touch screen is used.

This display is a great option compared to the ILI9341 as the higher resolution and the quite large size of the screen enables the creation of nicer GUI pages with a better touchscreen interaction.

In addition it shares the same connector pinout with the ILI9341 modules so can then be used on PCBs already designed for the ILI9341 and is very fast as it can be used at 80Mhz.

Additionally these displays also include a  reader that can be used to connect an SDCARD to the module.

 

image

 

image

These displays have a little jumper zone (J1) that must be solder-bridged if powering the module from 3.3V else it will be configured to work at 5v.

 

These displays have a design fault, a diode is fitted inline with the TFT_CS line, this allows the CS line to be pulled low but only parasitic currents pull it high (aided slightly by diode capacitance on a rising edge). Since CS tends to stick low the SDO line never tristates and the touch controller driver is too weak to overcome the TFT drive output. This diode must be removed and replaced with a  link and so it can tristates the SDO output as it should (see image below)

image

 


 

TFT DISPLAY ST7789

A TFT Display based on chipset ST7789 can be connected to the module using the SPI interface.

These displays are available on Ebay in different sizes and resolutions and are very cheap.

Because there are many variants of this display, Annex32 supports 5 different ST7789 settings in the config menu. You should try all of them until you find the one that matches your display.

The supported resolutions are :

240 x 240, 135 x 240, 240 x 280, 172 x 320 and 170 x 320.

 

As the interface is SPI, the display requires at least 5 pins.

The backlight signal is not mandatory (the LED pin can be put to +3.3V or left open for max intensity).

 

The model shown below is a 1.3”  with a resolution of 240x 240 pixels with 65K colors.

The particularity of this display is that it does not have the CS signal so it is always active.

This means that it cannot share the SPI bus with other devices (such as the SD Card).

For motivated people, there is an instructable that explains how add the CS signal

https://www.instructables.com/Adding-CS-Pin-to-13-LCD/

imageimage

 

TBD - schematics


 

 

OLED DISPLAY SSD1351 RGB

A OLED Color Display based on chipset SSD1351 can be connected to the module using the SPI interface.

These modules have a very sharp image and high brightness but are not very cheap.

 

As the interface is SPI, the display requires at least 5 pins.

The backlight signal is not present and is not required.

 

The model shown below is a 1.5”  with a resolution of 128 x 128 pixels with 65K colors.

 

 

image

 

TBD - schematics

TFT DISPLAY GC9A01

A TFT Display based on chipset GC9A01 can be connected to the module using the SPI interface.

These are easily available as a 1.28” round displays with a resolution of 240 x 240.

 

As the interface is SPI, the display requires at least 5 pins.

The backlight signal is not mandatory (the LED pin can be put to +3.3V or left open for max intensity).

 

image

TBD - schematics

 

 

 

TouchScreen

The touchscreen functionality allows detecting the position of the point pressed on the screen.

Both resistive and capacitive controllers are supported.

 

Support is included for the following touchscreen controllers:

-       XPT2046 (using the SPI bus)

-       GT911 (using the I2C bus)

-       FT5X06 (using the I2C bus)

 

The touchscreen controller can be selected via the web configuration page.

 

For the XPT2046 controller using the SPI bus, its pins are shared with those of the TFT display.

Therefore, only the chip select (named TOUCH in the config page) pin for the touch controller needs to be defined (with some exceptions for specific modules that are handled differently).

For controllers using the I2C bus, the corresponding I2C pins must be specified in the configuration page.

 

TouchScreen - Resistive

The touchscreen functionality permits to get the position of the point pressed on the screen.

The support is based on the chip XPT2416 that is connected using the bus SPI.

It is associated with the event OnTouch and the functions TOUCH.X , TOUCH.Y and TOUCH.Z.

The touchscreen must be calibrated before first use, and also if TFT.init orientation is changed.

This can be done with the command  TOUCH.CALIB

The user will be asked to click on the 4 crosses for the calibration.

The calibration result will be stored permanently inside the module and will not be required to do anymore.

 

There are 2 commands to read the touchscreen :

TOUCH.READ -> read the touchscreen position calibrated

TOUCH.RAW -> read the touchscreen without calibration

 

There are 4 additional commands to setup / customise the touchscreen :

TOUCH.RESET -> reset the specific H/W setup for the module ESP32-2432S

TOUCH.THRESHOLD value -> set the threshold sensitivity value (default 350)

TOUCH.AVERAGE value -> set the average value (default 50)

TOUCH.DELAY value -> set the delay value (default 30)

Note: these values are stored permanently inside the module and will not be required to do anymore

 

There are 3 functions :

TOUCH.X -> returns the X position

TOUCH.Y -> returns the Y position

TOUCH.Z -> returns the touched status (if 1 means touched)

 

Example:

OnTouch touchme

wait

 

touchme:

  touch.read 'Read the calibrated position

  print "touched", touch.x, touch.y, touch.z

return

 

TouchScreen - Capacitive

The touchscreen functionality permits to get the position of the point pressed on the screen.

The support is based on the chip GT911 that is connected using the bus I2C.

It is associated with the event OnTouch and the functions TOUCH.X , TOUCH.Y and TOUCH.Z.

 

Before use the touchscreen, the following commands are required:

 

OPTION.TOUCH 'Select the capacitive controller

I2C.SETUP 19, 20 'Set the pins for the I2C bus

'initialise the capacitive touch; the optional rotation can be from 0 to 3

TOUCH.INIT [rotation]

The commands to read the touchscreen is:

TOUCH.READ -> read the touchscreen position calibrated

 

There are 3 functions :

TOUCH.X -> returns the X position

TOUCH.Y -> returns the Y position

TOUCH.Z -> returns the touched status (if 1 means touched)

 

Example:

OPTION.TOUCH 'Select the capacitive controller

I2C.SETUP 19, 20 'Set the pins for the I2C bus

touch.init 'initialise the capacitive touch

OnTouch touchme

wait

 

touchme:

  touch.read 'Read the calibrated position

  print "touched", touch.x, touch.y, touch.z

return

 

 

TFT FONTS

Several text fonts are available to be used for the TFT.

 

The commands are :

TFT.TEXT.FONT font_number

TFT.TEXT.SIZE font_size

TFT.LOADFONT"filename" [, 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13]

TFT.PRINT expression [[,; ]expression] ...

TFT.TEXT.DRAW "text", x, y [font]

TFT.TEXT.ALIGN alignment

TFT.TEXT.PADDING width

 

 

There are actually 8 fonts installed as shown in the pictures below as shown on the TFT at 320x240.

imageimage

imageimage

imageimage

imageimage

 

The fonts 6 to 8 have only a limited set of characters as shown in the pictures.

The font 3 and 5 are the same as the font1 but just increased in size.

 

The size of the characters can be controlled for any font using the command TFT.TEXT.SIZE font_size.

This  is essentially a multiplying coefficient that is applied to the font.

 

For example the font 7 with TFT.TEXT.SIZE 2 will be drawn as below

image

 

It is important to note that, except for the font 1, the  3 and 5, the character spacing is not fixed as the fonts are not monospace but proportional.

 

In addition to these fonts available by default, it is possible to load dynamically up to 4 new fonts from file.

These will be loaded into the RAM and available as font 10,11, 12 and 13.

 

The fonts available are essentially all the freefonts available in the Adafruit_GFX library format simply converted in binary ready to be loaded into Annex.

The list is very long (~50) and many others can be also included after conversion.

A dedicated web site is available for the conversion directly in the right format:

https://www.cicciocb.com/FontConverter/

 

To load a new font the command is :

TFT.LOADFONT “filename” [,slot]

Where ‘slot ‘ can be 1 (default), 2, 3 or 4 (they can also be from 10 to 13 for the same result)

For example, to load the font “Orbitron_Light_32” and the font “Yellowtail_32” :

TFT.LOADFONT “/fonts/Orbitron_Light_32.bin”, 1

TFT.LOADFONT “/fonts/Yellowtail_32.bin”, 1

 

The result will be :

image

 

The text can be printed with or without a background (in transparent mode), useful to superimpose the text over an image.

image

 

This is controlled using the command TFT.TEXT.COLOR text_color [, background_color]

If the background_color is not specified, the text will be printed without background.

NOTE : the freefonts loaded from file will always be “transparent” independently of the text color setting.

 

The text can be printed using 2 commands :

TFT.PRINT expression [[,; ]expression] …

and

TFT.TEXT.DRAW "text", x, y [font]

 

TFT.PRINT works in the same way as the serial print command, including all the options, and prints the text at the position previously defined by the command TFT.TEXT.POS x, y

As soon as the text is printed, the position is automatically advanced on the next line or held on the same line if the ; is attached at the end of the command.

It also has the advantage to wrap the text automatically on the next line as soon as it goes out of the screen.

 

However, this command is not very flexible and is not adapted for text that changes dynamically.

 

On the other hand, the command TFT.TEXT.DRAW  is much more flexible as it enables a strict control on the text to be drawn.

It rely on 2 other commands :

TFT.TEXT.ALIGN alignment

This command defines the alignment of the text to be drawn, in relationship with the coordinates of the point defined in the command TFT.TEXT.DRAW

The table below shows all the possible alignments

 

VALUE

KEYWORD

ALIGNMENT

0

ALIGN_TOP_LEFT

Top left

1

ALIGN_TOP_MID

Middle of top

2

ALIGN_TOP_RIGHT

Top right

3

ALIGN_MID_LEFT

Middle of left side

4

ALIGN_MID_MID

Center

5

ALIGN_MID_RIGHT

Middle of the right side

6

ALIGN_BOT_LEFT

Bottom left

7

ALIGN_BOT_MID

Middle of bottom

8

ALIGN_BOT_RIGHT

Bottom right

 

TFT.TEXT.PADDING width

This command defines the minimal width of the text to be drawn, useful to overprint and erase old text or numbers.

 

TFT.TEXT.DRAW "text", x, y [,font]

This command draws a text at the position defined by x and y using the optional font defined or the font defined with the command TFT.TEXT.FONT.

The text is drawn using the alignment defined with the command TFT.TEXT.ALIGN

QR CODES

TFT.QRCODE "message", x, y, width [,version]

This command draws a text message on the TFT as QR CODE that can be read using a mobile phone simply taking a picture of the image shown on the display.

 

image

GRAPHIC GUI for TFT

A full set of graphical objects has been included in Annex32.

 

There are several objects that can be defined using a specific GUI.xxxx function.

When defining the object, each function returns a handler that must be stored into a variable to gain access to this object later in the code.

 

All these graphical objects are strongly associated with the touchscreen that must be calibrated before with the command TOUCH.CALIB.

 

At the beginning, the command GUI.INIT Nb_objects, back_color is required to define how many objects will be declared and the initial background color.

Nb_objects defines the max number of objects present on the screen at the same time but the program can contain more objects.

 

The objects created using the functions defined below, will not be drawn directly on the screen but will be held in memory until the command GUI.REFRESH is executed.

This permits us to update all the objects at the same time.

 

Here is a simple example that will create two GUI items, a textline and a button. When the button is clicked , or the left button on M5stack is pressed, the textline changes.

'simple GUI example

gui.init 20, black  'reserve memory for 20 GUI objects. clears screen to black

 

txt = GUI.Textline(10,50,190,20, "Text Line Here", 2)  'x,y,w,h,text,fontsize

but = GUI.Button(20, 200, 100, 20, "BUTTON!",2 ) 'x,y,w,h,text,fontsize

 

gui.setevent but, TOUCH, buttonclick  'set touched event, jump to buttonclick

interrupt 39, buttonclick 'if using M5stack can't click screen- so use left button

gui.autorefresh 30, 1 'display gui items automatically each 30ms including touch

wait

 

buttonclick:

gui.settext txt,"Button Pressed" 'change text line.

return

 

 

 

For example, defining a textline with:

TXT1 = GUI.Textline(10, 10, 100, 20, "Hello World!")

The variable txt1 will contain a handler permitting to modify the properties of the textline; for example the following line :

GUI.SetText TXT1, "Text changed!"

Will change the text of the object previously defined.

 

If it is not required to hold the handler of the object into the code (for example if it never changes), it is possible to ignore the handler and define the object using a command syntax without parentheses:

GUI.Textline 10, 10, 100, 20, "Hello World!"

 

GUI Objects

gui.TextLine

Txt1 =GUI.Textline(x, y, width, height, "text" [,font] [,color_text] [,color_back] [,color_frame] [,alignment] [,margin] )

Font is the number of the font.

image

gui.Button

But1 = GUI.Button(x, y, width, height, "text" [,font] [,radius] [,toggle] [,group] [,color_text] [,color_pressed] [,color_released] [,color_frame] )

Font is the number of the font.

Radius is the radius of the rounded part of the button (0 by default is not rounded).

Toggle is 0 for momentary (default) or 1 for toggle.

Toggle can also be expressed directly using the keywords MOMENTARY or TOGGLE.

Group is a number that permits to associate interactive buttons together; this permits to deactivate a toggle button when selecting another in the group (like a group of radio buttons).

image

gui.Image

Img1 = GUI.Image(x, y, width, height, fname$ [,background] [,background_on] [,toggle] [,group] )

The width and the height are just used to define the touch area, because the size of the image will be defined by the image file content.

The file can be BMP or JPG format.

The BMP can be also with 32bits permitting to define a color background that can be eventually changed with the command gui.setcolor.

Toggle is 0 for momentary (default) or 1 for toggle.

Toggle can also be expressed directly using the keywords MOMENTARY or TOGGLE.

Background defines the normal background color of the image and background_on defines the background color when the image is set to 1.

Defining 2 different colors, it is possible to use the image as a kind of “buttonImage” where the background color changes as a function of the button state.

Optionally the background color can be controlled from the code using the function Gui.SetColor.

NEW: if the background is -1, the background around the image will be transparent

image

gui.ButtonImage

A combination of a button with 2 images

Img2 = GUI.ButtonImage(x, y, width, height, image1$, image2$ [,toggle], [group] , [background] )

 

The width and the height are just used to define the touch area, because the size of the image will be defined by the image file content.

The files can be BMP or JPG format.

The BMP can also be 32bits permitting to define a color background with the command gui.setcolor.

Toggle is 0 for temporary (default) or 1 for toggle.

Toggle can also be expressed directly using the keywords MOMENTARY or TOGGLE.

Group is a number that permits to associate interactive buttons together; this permits to deactivate a toggle button when selecting another in the group (like a group of radio buttons).

Background is the background color (for transparent images)

NEW: if the background is -1, the background around the image will be transparent

imageimage

gui.CheckBox

Chk1 = GUI.CheckBox(x, y, width, height, value [, style] [,group] [,color_set] [,color_back] [,color_frame] )

Font is the size of the font.

Value is the initial value of the checkbox (0 or 1.)

Style is : 0 for squared checkbox, 1 for crossed checkbox, 2 for circular checkbox (radio button).

Style can also be expressed directly using the keywords SQUARED , CROSSED or RADIO.

By default the style is SQUARED.

Group is a number that permits to associate interactive checkboxes together; this permits to deactivate a checkbox when selecting another in the group (like a group of radio buttons).

image

gui.Slider

Sld1 = GUI.Slider(x, y, width, height, value [,orientation] [,color_cursor] [,color_back] )

The slider has by default a range from 0 to 100.

Value permits to define the default value.

Orientation can be 0 (default) for horizontal and 1 for vertical.

Orientation can also be expressed directly using the keywords HORIZONTAL or VERTICAL.

image

gui.ProgressBar

Prg1 = GUI.ProgressBar(x, y, width, height, value [,orientation]   [,color_set] [,color_back] [,color_frame] )

 

The progressBar has by default a range from 0 to 100.

Value permits to define the default value.

Orientation can be 0 (default) for horizontal and 1 for vertical.

Orientation can also be expressed directly using the keywords HORIZONTAL or VERTICAL.

image

gui.Ramp

Rmp1 = GUI.Ramp(x, y, width, height, value)

The ramp has by default a range from 0 to 100.

image

gui.Gauge

Gau1 = GUI.Gauge(x, y, width, height, value [,color_needle] [,color_back] [,color_frame] [,color_ticks] )

The gauge has by default a range from 0 to 100.

imageimage

gui.Box

Box1 = GUI.Box(x, y, width, height, color1 [,frame_color [,color2]])

The box has by default a unique color with a white frame around.

The optional parameter ‘frame_color’ defines the color of the frame.

The optional parameter ‘color2’ allows the color of the box to be swapped between the 2 colors using the command gui.setvalue (example for a squared led).

By default color2 is black

image

 

gui.Circle

Cir1 = GUI.Circle(x, y, radius, color1 [,frame_color [,color2]])

The circle has by default a unique color with a white frame around.

The optional parameter ‘frame_color” defines the color of the frame.

The optional parameter ‘color2’ allows the color of the circle to be swapped between the 2 colors using the command gui.setvalue (example for a circular led).

By default color2 is black.

image

gui.Rect

Rect1 = GUI.Rect(x, y, width, height, color,[,color2])

The optional parameter ‘color2’ allows the color of the circle to be swapped between the 2 colors using the command gui.setvalue (example for a squared led).

By default color2 is black.

This draws a simple rectangle.

image

gui.Line

Line1 = GUI.Line (x1, y1 x2, y2, color)

This draws a simple line.

image

 

 

GUI.TEXTAREA(x, y, width, height, "text", [,font] [,alignment] [,color_text] [,color_back] [,color_frame] [,margin] )

Creates a text area on a graphical user interface within the TFTdisplay. This function facilitates the display of text, automatically formatting it into multiple lines. The string can be split either by the newline character `chr$(10)` or automatically wrapped by word.

 

Parameters

     x: The x-coordinate position of the text area on the TFT display.

     y: The y-coordinate position of the text area on the TFT display.

     width: The width of the text area in pixels.

     height: The height of the text area in pixels.

     "text": The text string to be displayed within the text area.

     font (Optional): An optional parameter specifying the font to be used for the text. Default font may be used if not specified.

     alignment (Optional): An optional parameter specifying the alignment of the text within the text area.

     color_text (Optional): An optional parameter specifying the color of the text. Default color may be used if not specified.

     color_back (Optional): An optional parameter specifying the background color of the text area. Default color may be used if not specified.

     color_frame (Optional): An optional parameter specifying the color of the text area's frame. Default color may be used if not specified.

     margin (Optional): An optional parameter specifying the margin around the text within the text area.

 

Return Value

     A variable representing the created text area. This variable can be used to manipulate the text area in subsequent commands.

 

 

GUI.GETTEXT obj, var$

Parameters

     obj: The object from which to retrieve the text.

     var$: The variable to store the retrieved text.

GUI.VISIBLE obj, visible

Parameters

     obj: The object from which to retrieve the text.

     visible: 0=hidden, 1=visible.

 

GUI Functions

gui.GetValue

Value = GUI.GetValue(obj)

 

Returns the current value from any object.

Works for button, Imagebutton, checkbox, slider, ….

 

gui.Target

Id = GUI.Target

Returns the ID of the object that generated the event.

Useful for having a common event handler routine for several objects.

GUI Commands

gui.INIT

Gui.Init nb_elements [, back_color]

Initialise the graphical GUI interface.

Nb_elements define how many graphical elements can be defined.

This is just for memory reasons, if more objects are defined, they will be ignored.

Back_color defines the background color (by default is black).

gui.REDRAW

Gui.Redraw

Redraw all the content of the GUI.

All the objects will be redrawn, even those that have not changed since the last refresh.

gui.REFRESH           

Gui.Refresh [touch]

Refresh the content of the GUI.

If ‘touch’ is 1, the touchscreen will also be refreshed. This is useful if the module doesn’t have a touchscreen (like the m5stack).

 

gui.AUTOREFRESH

Gui.AutoRefresh interval [, touch]

Refresh the content of the GUI at regular intervals.

‘Interval’ defines the time interval in milliseconds.

If ‘touch’ is 1, the touchscreen will also be refreshed. This is useful if the module doesn’t have a touchscreen (like the m5stack).

 

gui.SETVALUE        

Gui.SetValue object, value [, no_event]

Set the value for any valid object.

If no_event is 1, the event associated with the object will not be raised

 

gui.SETTEXT           

Gui.SetText object, text$

Set the text for textline and for buttons.

 

gui.SETIMAGE         

Gui.SetImage object, image1$ [,image2$]

Defines the image(s) for the IMAGE object and the ImageButton Object.

 

gui.SETCOLOR       

Gui.SetColor object, col1 [,col2 [,col3 [,col4]]]

Set the colors for all the objects.

This command is valid for all the objects, but the syntax is different for each object.

The detail is :

 

Object

Format

TextLine

Gui.SetColor object, color_text [,color_back [,color_frame]]

Button

Gui.SetColor object, color_text [,color_pressed [,color_released [,color_frame]]]

Checkbox

Gui.SetColor object, color_set [, color_back [, color_frame]]

ProgressBar

Gui.SetColor object, color_set [, color_back [, color_frame]]

Slider

Gui.SetColor object, color_cursor [, color_back [, color_frame [, color_ticks]]]

Gauge

Gui.SetColor object, color_needle [, color_back [, color_frame [, color_ticks]]]

Box

Gui.SetColor object, color_set [, color_back [, color_frame [, color_released]]]

Circle

Gui.SetColor object, color_set [, color_back [, color_frame [, color_released]]]

Rectangle

Gui.SetColor object, color

Line

Gui.SetColor object, color

Image

Gui.SetColor object, color_back  ( this works only with bmp with transparency)

ButtonImage

Gui.SetColor object, color_back1, color_back2

 

 

 

gui.SETRANGE       

Gui.SetRange object, value_mini, value_maxi

Define the range for the slider, the progressbar, the ramp and the gauge.

 

gui.SETEVENT 

Gui.SetEvent object, event_type [, label]

Define an event for any object.

 

Event

Value

Meaning

NONE

0

Disable the event

TOUCH

1

Triggered when touching on the object

LEAVE

2

Triggered when leaving the touch from the object

CHANGE

3

Triggered when the value of the object changes

 

Label is the place where it will jump; it is not required if the event is NONE.

The events can be defined for button, checkbox, slider, image and imagebutton.

 

ID = Gui.Target 

Returns the ID of the object that generated the event.

Useful for having a common event handler routine for several objects

 

gui.SETSTYLE         

Set the style for all the objects.

This command is valid for all the objects, but the syntax is different for each object.

The detail is :

 

Object

Format

Slider

Gui.SetStyle object, size_cursor [, number_of_ticks [, tick_length]]

Gauge

Gui.SetStyle object, needle_length [, needle_width  [, number_of_ticks [, tick_length]]]

TextLine

Gui.SetStyle object, alignment [, text_margin]

 

alignment can be :

 

Keyword

Value

Alignement

ALIGN_TOP_LEFT

0

Top left

ALIGN_TOP_MID

1

Middle of top

ALIGN_TOP_RIGHT

2

Top right

ALIGN_MID_LEFT

3

Middle of left side

ALIGN_MID_MID

4

Center

ALIGN_MID_RIGHT

5

Middle of the right side

ALIGN_BOT_LEFT

6

Bottom left

ALIGN_BOT_MID

7

Middle of bottom

ALIGN_BOT_RIGHT

8

Bottom right

 

 

Text_margin defines the margin in pixels.

 


LovyanGFX Graphics Library

LovyanGFX is a powerful and flexible graphics library integrated into Annex 32 RDS starting from Release 2+. This library significantly enhances graphical capabilities for ESP32-based projects, replacing the previous TFT_eSPI library. It provides advanced features and optimizations to support complex graphical operations while maintaining efficiency and compatibility with the previous implementation.

Key Features:

Font Management

-       Custom Fonts: Supports loading fonts in Adafruit GFX format, converted using the Annex Font Converter.

-       Flexible Text Rendering: Allows customization of font size, alignment, padding, and colors.

Image Handling

-       Supported Formats: Displays BMP, JPG, and PNG images directly on the TFT display or sprites.

-       Advanced Manipulation: Includes options for scaling, cropping, rotation, and transparency.

Sprite Support

-       Off-Screen Buffers: Enables creation and manipulation of sprites for smooth animations and advanced graphical effects.

-       Dynamic Drawing: Allows text and image rendering directly onto sprites.

-       Advanced Sprite Management: Up to 10 sprites can be used simultaneously, numbered from 0 to 9. Sprites can be resized, superposed, merged, rotated between them to create complex graphic effects and animations easily.

-       Important Note: Sprites consume RAM memory, so it is essential to use them cautiously, especially if the ESP32 device lacks PSRAM. Excessive use of sprites can lead to out-of-memory issues, affecting the stability and performance of your application.

Geometric Drawing

-       Shapes: Provides drawing functions for lines, rectangles (including rounded corners), circles, ellipses, arcs, triangles, and wedge lines.

-       Customization: Supports smoothing, thickness adjustments, and filled shapes.

Hardware Integration

-       Efficient SPI Usage: Optimized for high-performance rendering with adjustable SPI frequencies.

-       Brightness Control: Allows adjustment of TFT display brightness.

QR Code Generation

-       Integrated Functionality: Includes support for generating QR codes directly on the display.

 

Implementation Notes

LovyanGFX commands are mapped to Annex 32 RDS functions, making it easy to leverage its capabilities within the firmware. You can use dedicated commands for text rendering, image handling, sprite management, geometric drawing, and more.

 

This integration not only ensures compatibility with the previous TFT_eSPI library but also significantly expands the range of functions available for graphical applications.

For each command/function, the corresponding LovyanGFX reference has been included so that you can consult the official LovyanGFX documentation for further details.

 

Color Management

Colors in LovyanGFX are managed at 16 bits in RGB565 format. This encoding uses 5 bits for red, 6 bits for green, and 5 bits for blue, resulting in efficient color representation. Colors can be expressed either as a 16-bit number or as a predefined color from a table provided in the documentation. This approach ensures compatibility with various graphical operations while maintaining high performance across supported devices.

 

GFX Functions


 

TFT.RGB(r, g, b)

Description: Converts RGB color values to a 16-bit color format.

Arguments:

     r: Red component (from 0 to 255).

     g: Green component (from 0 to 255).

     b: Blue component (from 0 to 255).

Return: 16-bit color value.

TFT Command: tft3->color565()

LovyanGFX Command: color565()


TFT.COLOR colorName

Description: Retrieves a predefined color based on its name.

Arguments:

     colorName: Name of the color.

Return: Color value.

TFT Command: get_TFT_Color()

LovyanGFX Command: N/A (Custom function)

The list of the colors and their corresponding RGB565 values (in hex format) is shown below :

Color Name

RGB565 Value

BLACK

0x0000

NAVY

0x000F

DARKGREEN

0x03E0

DARKCYAN

0x03EF

MAROON

0x7800

PURPLE

0x780F

OLIVE

0x7BE0

LIGHTGREY

0xD69A

DARKGREY

0x7BEF

BLUE

0x001F

GREEN

0x07E0

CYAN

0x07FF

RED

0xF800

MAGENTA

0xF81F

YELLOW

0xFFE0

WHITE

0xFFFF

ORANGE

0xFDA0

GREENYELLOW

0xB7E0

PINK

0xFE19

BROWN

0x9A60

GOLD

0xFEA0

SILVER

0xC618

SKYBLUE

0x867D

VIOLET

0x915C

 


 

TFT.WIDTH

Description: Gets the width of the TFT display.

Arguments: None

Return: Width of the display.

TFT Command: dest->width()

LovyanGFX Command: width()


TFT.SPRITE.WIDTH spriteNum

Description: Gets the width of the specified sprite.

Arguments:

     spriteNum: Sprite number.

Return: Width of the sprite.

TFT Command: dest->width()

LovyanGFX Command: width()


TFT.HEIGHT

Description: Gets the height of the TFT display.

Arguments: None

Return: Height of the display.

TFT Command: dest->height()

LovyanGFX Command: height()


TFT.SPRITE.HEIGHT spriteNum

Description: Gets the height of the specified sprite.

Arguments:

     spriteNum: Sprite number.

Return: Height of the sprite.

TFT Command: dest->height()

LovyanGFX Command: height()


TFT.GETPIXEL x, y

Description: Gets the color of a pixel at specified coordinates on the TFT display.

Arguments:

     x: X-coordinate of the pixel.

     y: Y-coordinate of the pixel.

Return: Color of the pixel.

TFT Command: dest->readPixel()

LovyanGFX Command: readPixel()


TFT.SPRITE.GETPIXEL spriteNum, x, y

Description: Gets the color of a pixel at specified coordinates on the specified sprite.

Arguments:

     spriteNum: Sprite number.

     x: X-coordinate of the pixel.

     y: Y-coordinate of the pixel.

Return: Color of the pixel.

TFT Command: dest->readPixel()

LovyanGFX Command: readPixel()


TFT.SIZE filename$

Description: Gets the size of an image file.

Arguments:

     filename$: Path to the image file.

Return: Image size.

TFT Command: getImageSize()

LovyanGFX Command: N/A (Custom function)


TFT.FRAMEGIF [loop = 0]

Description: Plays the next frame of a GIF animation.

Arguments:

     loop (optional): Loop the GIF if set to 1.

Return: Pause duration until the next frame or 0 if the end of the animation is reached.

TFT Command: gif->playFrame()

LovyanGFX Command: playFrame()


 

GFX Commands


 

TFT.LOADFONT path$, font_num

Description: Loads a font from a file for use in text rendering.

Arguments:

     path$: Path for the file .bin containing the font.

     font_num: font number (from 1 to 4 or 10 to 13);

Return: None

TFT Command: loadFont_generic()

LovyanGFX Command: lgfx::GFXfont, setFont()

Notes: The font must be in Adafruit GFX format converted with the  Annex Font Converter


TFT.INIT [rot]

Description: Initializes the TFT display with a specified rotation.

Arguments:

     rot (optional): Rotation value (default is 1).

Return: None

TFT Command: doTftInit()

LovyanGFX Command: init(), setRotation(), fillScreen(), setTextFont()


TFT.SETFREQ freq [, read_freq]

Description: Sets the TFT SPI frequency.

Arguments:

     freq: Frequency value.

     read_freq (optional): If provided, sets the read clock frequency.

Return: None

TFT Command: tft3->getPanel()->getBus()->setClock(TFT_SPI_frequency)

LovyanGFX Command: getPanel(), getBus(), setClock()


TFT.TEXT.POS x, y

Description: Sets the cursor position for text drawing on the TFT display or a specified sprite.

Arguments:

     x: X-coordinate for the cursor position.

     y: Y-coordinate for the cursor position.

Return: None

TFT Command: doTftTextPos()

LovyanGFX Command: setCursor()


TFT.SPRITE.TEXT_POS spriteNum, x, y

Description: Sets the cursor position for text drawing on the specified sprite.

Arguments:

     spriteNum: Sprite number.

     x: X-coordinate for the cursor position.

     y: Y-coordinate for the cursor position.

Return: None

TFT Command: doTftTextPos()

LovyanGFX Command: setCursor()


TFT.TEXT.COLOR col [, back]

Description: Sets the text color and optionally the background color for the TFT display.

Arguments:

     col: Text color.

     back (optional): Background color.

Return: None

TFT Command: doTftTextCol()

LovyanGFX Command: setTextColor()


TFT.SPRITE.TEXT.COLOR spriteNum, col [, back]

Description: Sets the text color and optionally the background color for the specified sprite.

Arguments:

     spriteNum: Sprite number.

     col: Text color.

     back (optional): Background color.

Return: None

TFT Command: doTftTextCol()

LovyanGFX Command: setTextColor()


TFT.TEXT.SIZE size [, font]

Description: Sets the text size and optionally the font for the TFT display.

Arguments:

     size: Text size.

     font (optional): Font number.

Return: None

TFT Command: doTftTextSize()

LovyanGFX Command: setTextSize(), setTextFont()


TFT.SPRITE.TEXT.SIZE spriteNum, size [, font]

Description: Sets the text size and optionally the font for the specified sprite.

Arguments:

     spriteNum: Sprite number.

     size: Text size.

     font (optional): Font number.

Return: None

TFT Command: doTftTextSize()

LovyanGFX Command: setTextSize(), setTextFont()


TFT.PRINT str$ [, x] [, y] [, fontnum]

Description: Prints text or data to the TFT display.

Arguments:

     str$: String to print.

     x (optional): X-coordinate for printing.

     y (optional): Y-coordinate for printing.

     fontnum (optional): Font number.

Return: None

TFT Command: doTftPrint(dest)

LovyanGFX Command: print()


TFT.SPRITE.PRINT spriteNum, str$ [, x] [, y] [, fontnum]

Description: Prints text or data to the specified sprite.

Arguments:

     spriteNum: Sprite number.

     str$: String to print.

     x (optional): X-coordinate for printing.

     y (optional): Y-coordinate for printing.

     fontnum (optional): Font number.

Return: None

TFT Command: doTftPrint(dest)

LovyanGFX Command: print()


TFT.BMP filename$ [, x] [, y] [, scale]

Description: Draws a BMP image on the TFT display.

Arguments:

     filename$: Path to the BMP file.

     x (optional): X-coordinate for the image.

     y (optional): Y-coordinate for the image.

     scale (optional): Scale factor.

Return: None

TFT Command: dotftbmp()

LovyanGFX Command: drawBmpFile()


TFT.JPG filename$ [, x] [, y] [, scale]

Description: Draws a JPG image on the TFT display.

Arguments:

     filename$: Path to the JPG file.

     x (optional): X-coordinate for the image.

     y (optional): Y-coordinate for the image.

     scale (optional): Scale factor.

Return: None

TFT Command: dotftjpg()

LovyanGFX Command: drawJpgFile()


TFT.IMAGE filename$ [, x] [, y] [, zoom] [, x1] [, y1] [, w] [, h]

Description: Draws an image (BMP, JPG, or PNG) on the TFT display.

Arguments:

     filename$: Path to the image file.

     x (optional): X-coordinate for the image.

     y (optional): Y-coordinate for the image.

     zoom (optional): Zoom factor.

     x1, y1 (optional): Cropping coordinates.

     w, h (optional): Width and height for cropping.

Return: None

TFT Command: doTftImage()

LovyanGFX Command: drawBmpFile(), drawJpgFile(), drawPngFile()


TFT.SPRITE.IMAGE spriteNum, filename$ [,x] [,y] [,zoom] [,x1] [,y1] [,w] [,h]

Description: Draws an image (BMP, JPG, or PNG) on the TFT display or a specified sprite.

Arguments:

     spriteNum: Sprite number.

     filename$: Path to the image file.

     x (optional): X-coordinate for the image.

     y (optional): Y-coordinate for the image.

     zoom (optional): Zoom factor.

     x1, y1 (optional): Cropping coordinates.

     w, h (optional): Width and height for cropping.

Return: None

TFT Command: doTftImage()

LovyanGFX Command: drawBmpFile(), drawJpgFile(), drawPngFile()


TFT.BRIGHTNESS brt

Description: Sets the brightness of the TFT display.

Arguments:

     brt: Brightness intensity (0-255).

Return: None

TFT Command: dotftbrightness()

LovyanGFX Command: setBrightness()


TFT.TEXT.FONT fontnum

Description: Sets the font for text rendering on the TFT display.

Arguments:

     fontnum: Font number.

Return: None

TFT Command: setTextFontandSize()

LovyanGFX Command: setTextFont()


TFT.SPRITE.TEXT.FONT spriteNum, fontnum

Description: Sets the font for text rendering on the specified sprite.

Arguments:

     spriteNum: Sprite number.

     fontnum: Font number.

Return: None

TFT Command: setTextFontandSize()

LovyanGFX Command: setTextFont()


TFT.TEXT.DRAW str$, x, y [, fontnum]

Description: Draws a string at specified coordinates on the TFT display .

Arguments:

     str$: String to draw.

     x: X-coordinate for the text.

     y: Y-coordinate for the text.

     fontnum (optional): Font number.

Return: None

TFT Command: doTftPrint(dest)

LovyanGFX Command: drawString()


TFT.SPRITE.TEXT.DRAW spriteNum, str$, x, y [, fontnum]

Description: Draws a string at specified coordinates on the TFT display or a specified sprite.

Arguments:

     spriteNum: Sprite number.

     str$: String to draw.

     x: X-coordinate for the text.

     y: Y-coordinate for the text.

     fontnum (optional): Font number.

Return: None

TFT Command: doTftPrint(dest)

LovyanGFX Command: drawString()


TFT.TEXT.ALIGN datum

Description: Sets the text alignment (datum) for rendering on the TFT display.

Arguments:

     datum: Alignment value.

Return: None

TFT Command: doTftTextAlign()

LovyanGFX Command: setTextDatum()


TFT.SPRITE.TEXT.ALIGN spriteNum, datum

Description: Sets the text alignment (datum) for rendering on the specified sprite.

Arguments:

     spriteNum: Sprite number.

     datum: Alignment value.

Return: None

TFT Command: doTftTextAlign()

LovyanGFX Command: setTextDatum()


TFT.TEXT.PADDING padding

Description: Sets the text padding for rendering on the TFT display.

Arguments:

     padding: Padding value.

Return: None

TFT Command: doTftTextPadding()

LovyanGFX Command: setTextPadding()


TFT.SPRITE.TEXT.PADDING spriteNum, padding

Description: Sets the text padding for rendering on the TFT display or a specified sprite.

Arguments:

     spriteNum: Sprite number.

     padding: Padding value.

Return: None

TFT Command: doTftTextPadding()

LovyanGFX Command: setTextPadding()


TFT.QRCODE str$, x, y, w [, version]

Description: Draws a QR code on the TFT display.

Arguments:

     str$: QR code content.

     x: X-coordinate for the QR code.

     y: Y-coordinate for the QR code.

     w: Width of the QR code.

     version (optional): QR code version.

Return: None

TFT Command: tft3->qrcode()

LovyanGFX Command: qrcode()


TFT.CREATESPRITE spriteNum, w, h

Description: Creates a sprite with specified dimensions.

Arguments:

     spriteNum: Sprite number.

     w: Width of the sprite.

     h: Height of the sprite.

Return: None

TFT Command: LovyanSprite[spriteNum].createSprite(w, h)

LovyanGFX Command: createSprite()


TFT.DELETESPRITE spriteNum

Description: Deletes a specified sprite.

Arguments:

     spriteNum: Sprite number to delete.

Return: None

TFT Command: LovyanSprite[spriteNum].deleteSprite()

LovyanGFX Command: deleteSprite()


TFT.SPRITE.FROMBMP spriteNum, filename$

Description: Creates a sprite from a BMP file.

Arguments:

     spriteNum: Sprite number.

     filename$: Path to the BMP file.

Return: None

TFT Command: LovyanSprite[spriteNum].createFromBmpFile()

LovyanGFX Command: createFromBmpFile()


TFT.SPRITE.FROMIMG spriteNum, filename$

Description: Creates a sprite from an image file (BMP, JPG, or PNG).

Arguments:

     spriteNum: Sprite number.

     filename$: Path to the image file.

Return: None

TFT Command: doTftImage()

LovyanGFX Command: createFromBmpFile(), drawBmpFile(), drawJpgFile(), drawPngFile()


TFT.LINE x1, y1, x2, y2, col [, radius]

Description: Draws a line on the TFT display.

Arguments:

     x1: Starting X-coordinate.

     y1: Starting Y-coordinate.

     x2: Ending X-coordinate.

     y2: Ending Y-coordinate.

     col: Line color.

     radius (optional): Radius for line width or smoothness. (-1 = aliased, >1 thickness)

Return: None

TFT Command: doTftLine()

LovyanGFX Command: drawLine(), drawSmoothLine(), drawWideLine()


TFT.SPRITE.LINE spriteNum, x1, y1, x2, y2, col [, radius]

Description: Draws a line on the TFT display or a specified sprite.

Arguments:

     spriteNum: Sprite number.

     x1: Starting X-coordinate.

     y1: Starting Y-coordinate.

     x2: Ending X-coordinate.

     y2: Ending Y-coordinate.

     col: Line color.

     radius (optional): Radius for line width or smoothness. (-1 = aliased, >1 thickness)

Return: None

TFT Command: doTftLine()

LovyanGFX Command: drawLine(), drawSmoothLine(), drawWideLine()


TFT.WEDGELINE x1, y1, x2, y2, col, radius1, radius2

Description: Draws a wedge line on the TFT display.

Arguments:

     x1: Starting X-coordinate.

     y1: Starting Y-coordinate.

     x2: Ending X-coordinate.

     y2: Ending Y-coordinate.

     col: Line color.

     radius1: Starting radius. (thickness)

     radius2: Ending radius. (thickness)

Return: None

TFT Command: doTftWedgeLine()

LovyanGFX Command: drawWedgeLine()


TFT.SPRITE.WEDGELINE spriteNum, x1, y1, x2, y2, col, radius1, radius2

Description: Draws a wedge line on the specified sprite.

Arguments:

     spriteNum: Sprite number.

     x1: Starting X-coordinate.

     y1: Starting Y-coordinate.

     x2: Ending X-coordinate.

     y2: Ending Y-coordinate.

     col: Line color.

     radius1: Starting radius. (thickness)

     radius2: Ending radius. (thickness)

Return: None

TFT Command: doTftWedgeLine()

LovyanGFX Command: drawWedgeLine()


TFT.RECT x, y, w, h, col [, fill] [, radius]

Description: Draws a rectangle on the TFT display.

Arguments:

     x: X-coordinate for the rectangle.

     y: Y-coordinate for the rectangle.

     w: Width of the rectangle.

     h: Height of the rectangle.

     col: Rectangle color.

     fill (optional): Fill option (1 for filled, 2 for smooth filled).

     radius (optional): Corner radius for rounded rectangles.

Return: None

TFT Command: doTftRect()

LovyanGFX Command: drawRect(), fillRect(), drawRoundRect(), fillRoundRect(), fillSmoothRoundRect()


TFT.SPRITE.RECT spriteNum, x, y, w, h, col [, fill] [, radius]

Description: Draws a rectangle on the specified sprite.

Arguments:

     spriteNum: Sprite number.

     x: X-coordinate for the rectangle.

     y: Y-coordinate for the rectangle.

     w: Width of the rectangle.

     h: Height of the rectangle.

     col: Rectangle color.

     fill (optional): Fill option (1 for filled, 2 for smooth filled).

     radius (optional): Corner radius for rounded rectangles.

Return: None

TFT Command: doTftRect()

LovyanGFX Command: drawRect(), fillRect(), drawRoundRect(), fillRoundRect(), fillSmoothRoundRect()


TFT.CIRCLE x, y, radius, col [, fill]

Description: Draws a circle on the TFT display.

Arguments:

     x: X-coordinate for the circle center.

     y: Y-coordinate for the circle center.

     radius: Radius of the circle.

     col: Circle color.

     fill (optional): Fill option (1 for filled, 2 for smooth filled).

Return: None

TFT Command: doTftCircle()

LovyanGFX Command: drawCircle(), fillCircle(), fillSmoothCircle()


TFT.SPRITE.CIRCLE spriteNum, x, y, radius, col [, fill]

Description: Draws a circle on the specified sprite.

Arguments:

     spriteNum: Sprite number.

     x: X-coordinate for the circle center.

     y: Y-coordinate for the circle center.

     radius: Radius of the circle.

     col: Circle color.

     fill (optional): Fill option (1 for filled, 2 for smooth filled).

Return: None

TFT Command: doTftCircle()

LovyanGFX Command: drawCircle(), fillCircle(), fillSmoothCircle()


TFT.ELLIPSE x, y, radius1, radius2, col [, fill]

Description: Draws an ellipse on the TFT display.

Arguments:

     x: X-coordinate for the ellipse center.

     y: Y-coordinate for the ellipse center.

     radius1: Horizontal radius of the ellipse.

     radius2: Vertical radius of the ellipse.

     col: Ellipse color.

     fill (optional): Fill option (1 for filled).

Return: None

TFT Command: doTftEllipse()

LovyanGFX Command: drawEllipse(), fillEllipse()


TFT.SPRITE.ELLIPSE spriteNum, x, y, radius1, radius2, col [, fill]

Description: Draws an ellipse on the specified sprite.

Arguments:

     spriteNum: Sprite number.

     x: X-coordinate for the ellipse center.

     y: Y-coordinate for the ellipse center.

     radius1: Horizontal radius of the ellipse.

     radius2: Vertical radius of the ellipse.

     col: Ellipse color.

     fill (optional): Fill option (1 for filled).

Return: None

TFT Command: doTftEllipse()

LovyanGFX Command: drawEllipse(), fillEllipse()


TFT.ARC x, y, radius1, radius2, angle1, angle2, col [, fill]

Description: Draws an arc on the TFT display or a specified sprite.

Arguments:

     x: X-coordinate for the arc center.

     y: Y-coordinate for the arc center.

     radius1: Horizontal radius of the arc.

     radius2: Vertical radius of the arc.

     angle1: Starting angle of the arc.

     angle2: Ending angle of the arc.

     col: Arc color.

     fill (optional): Fill option (1 for filled).

Return: None

TFT Command: doTftArc()

LovyanGFX Command: drawArc(), fillArc()


TFT.SPRITE.ARC spriteNum, x, y, radius1, radius2, angle1, angle2, col [, fill]

Description: Draws an arc on the specified sprite.

Arguments:

     spriteNum: Sprite number.

     x: X-coordinate for the arc center.

     y: Y-coordinate for the arc center.

     radius1: Horizontal radius of the arc.

     radius2: Vertical radius of the arc.

     angle1: Starting angle of the arc.

     angle2: Ending angle of the arc.

     col: Arc color.

     fill (optional): Fill option (1 for filled).

Return: None

TFT Command: doTftArc()

LovyanGFX Command: drawArc(), fillArc()


TFT.TRIANGLE x1, y1, x2, y2, x3, y3, col [, fill]

Description: Draws a triangle on the TFT display.

Arguments:

     x1: X-coordinate of the first vertex.

     y1: Y-coordinate of the first vertex.

     x2: X-coordinate of the second vertex.

     y2: Y-coordinate of the second vertex.

     x3: X-coordinate of the third vertex.

     y3: Y-coordinate of the third vertex.

     col: Triangle color.

     fill (optional): Fill option (1 for filled).

Return: None

TFT Command: doTftTriangle()

LovyanGFX Command: drawTriangle(), fillTriangle()


TFT.SPRITE.TRIANGLE spriteNum, x1, y1, x2, y2, x3, y3, col [, fill]

Description: Draws a triangle on the specified sprite.

Arguments:

     spriteNum: Sprite number.

     x1: X-coordinate of the first vertex.

     y1: Y-coordinate of the first vertex.

     x2: X-coordinate of the second vertex.

     y2: Y-coordinate of the second vertex.

     x3: X-coordinate of the third vertex.

     y3: Y-coordinate of the third vertex.

     col: Triangle color.

     fill (optional): Fill option (1 for filled).

Return: None

TFT Command: doTftTriangle()

LovyanGFX Command: drawTriangle(), fillTriangle()


TFT.PIXEL x, y, col

Description: Draws a pixel on the TFT display.

Arguments:

     x: X-coordinate for the pixel.

     y: Y-coordinate for the pixel.

     col: Pixel color.

Return: None

TFT Command: doTftPixel()

LovyanGFX Command: drawPixel()


TFT.SPRITE.PIXEL spriteNum, x, y, col

Description: Draws a pixel on the specified sprite.

Arguments:

     spriteNum: Sprite number.

     x: X-coordinate for the pixel.

     y: Y-coordinate for the pixel.

     col: Pixel color.

Return: None

TFT Command: doTftPixel()

LovyanGFX Command: drawPixel()


TFT.FILL col

Description: Fills the entire TFT screen with a specified color.

Arguments:

     col: Fill color.

Return: None

TFT Command: doTftFill()

LovyanGFX Command: fillScreen()


TFT.SPRITE.FILL spriteNum, col

Description: Fills a specified sprite with a specified color.

Arguments:

     spriteNum: Sprite number to fill.

     col: Fill color.

Return: None

TFT Command: LovyanSprite[spriteNum].fillSprite()

LovyanGFX Command: fillSprite()


TFT.AAC

Description: Prints the pivot coordinates of the TFT display.

Arguments: None

Return: None

TFT Command: Serial.printf()

LovyanGFX Command: getPivotX(), getPivotY()


TFT.SAVE filename$ [, spriteDest]

Description: Saves the content of the TFT display or a specified sprite to a BMP file.

Arguments:

     filename$: Path to save the BMP file.

     spriteDest (optional): Sprite number to save.

Return: None

TFT Command: saveToBMP()

LovyanGFX Command: readRectRGB()


TFT.PIVOT xf, yf

Description: Sets the pivot point for rotation and scaling on the TFT display .

Arguments:

     xf: X-coordinate for the pivot.

     yf: Y-coordinate for the pivot.

Return: None

TFT Command: doTftPivot()

LovyanGFX Command: setPivot()


TFT.SPRITE.PIVOT spriteNum, xf, yf

Description: Sets the pivot point for rotation and scaling on the specified sprite.

Arguments:

     spriteNum: Sprite number to fill.

     xf: X-coordinate for the pivot.

     yf: Y-coordinate for the pivot.

Return: None

TFT Command: doTftPivot()

LovyanGFX Command: setPivot()

 

 


TFT.SPRITE.COPY spriteNum, spriteDest, x, y, w, h, x1, y1 [,col] [,angle] [,zoom]

Description: Copies a portion of one sprite to another with optional rotation and scaling.

Arguments:

     spriteNum: Source sprite number.

     spriteDest: Destination sprite number.

     x, y: Source coordinates.

     w, h: Width and height of the area to copy.

     x1, y1: Destination coordinates.

     col (optional): Color key for transparency.

     angle (optional): Rotation angle.

     zoom (optional): Zoom factor.

Return: None

TFT Command: doTftSpriteCopy()

LovyanGFX Command: readRect(), pushImageRotateZoom()


TFT.PUSH spriteNum, xf, yf [, col] [, angle] [, zoom]

Description: Pushes a sprite to the TFT display at specified coordinates with optional rotation and scaling.

Arguments:

     spriteNum: Sprite number to push.

     xf, yf: Coordinates to push the sprite.

     col (optional): Color key for transparency.

     angle (optional): Rotation angle.

     zoom (optional): Zoom factor.

Return: None

TFT Command: LovyanSprite[spriteNum].pushSprite()

LovyanGFX Command: pushSprite()


TFT.SPRITE.PUSH spriteNum [, spriteDest] [, xf] [, yf] [, col] [, angle] [, zoom]

Description: Pushes a sprite to the TFT display or another sprite with optional parameters.

Arguments:

     spriteNum: Sprite number to push.

     spriteDest (optional): Destination sprite number.

     xf, yf (optional): Coordinates to push the sprite.

     col (optional): Color key for transparency.

     angle (optional): Rotation angle.

     zoom (optional): Zoom factor.

Return: None

TFT Command: LovyanSprite[spriteNum].pushRotateZoom()

LovyanGFX Command: pushRotateZoom()


TFT.SPRITE.PUSHAA spriteNum [, spriteDest] [, xf] [, yf] [, col] [, angle] [, zoom]

Description: Pushes a sprite to the TFT display or another sprite with anti-aliasing and optional parameters.

Arguments:

     spriteNum: Sprite number to push.

     spriteDest (optional): Destination sprite number.

     xf, yf (optional): Coordinates to push the sprite.

     col (optional): Color key for transparency.

     angle (optional): Rotation angle.

     zoom (optional): Zoom factor.

Return: None

TFT Command: LovyanSprite[spriteNum].pushRotateZoomWithAA()

LovyanGFX Command: pushRotateZoomWithAA()


TFT.LOADGIF path$ [, x] [, y]

Description: Loads a GIF file. It must be animated using the function TFT.FRAMEGIF

Arguments:

     path$: Path for the file .gif containing the animation.

     x, y (optional): Coordinates for the position of the animation; by default 0,0

Return: None

TFT Command: gif->open()

LovyanGFX Command: N/A


TFT.PLAYGIF path$ [, x] [, y]

Description: Loads a GIF file. The animation will be played until the end (blocking function)

Arguments:

     path$: Path for the file .gif containing the animation.

     x, y (optional): Coordinates for the position of the animation; by default 0,0

Return: None

TFT Command: gif->open(), gif->playFrame()

LovyanGFX Command: N/A

 

 


 

 

LVGL - Light and Versatile Graphics Library

 

LVGL (Light and Versatile Graphics Library) is a powerful tool for creating embedded graphical user interfaces (GUIs), and it's an integral part of the Annex development environment. It allows developers to design visually appealing and interactive user interfaces with a minimal memory footprint, making it well-suited for resource-constrained ESP32 projects.

Core Concepts in Annex32 LVGL

Base Object

The foundation of every UI element in LVGL is the base object. Think of it as a basic rectangular building block upon which all other widgets are constructed. It manages fundamental aspects like position, size, and parent-child relations

Parts

Widgets are often composed of multiple parts that make up their appearance and functionality. For example, a slider might have a background, an indicator, and a knob. These parts allow for fine-grained customization of each widget

States

Widgets can exist in different states, such as "default," "pressed," "focussed," or "disabled." The state of a widget can influence its appearance and how it responds to user interactions.

Flags

Flags are used to enable or disable specific features or behaviours of an object. For instance, a flag can make an object clickable, scrollable, or hidden.

Object Relationships, Attributes, Styles, and Events Object

Hierarchy

LVGL objects within Annex are structured in a parent-child hierarchy. This hierarchy provides a way to group related UI elements and manage their layout and visibility.

Attributes and Properties

Objects have various attributes and properties that define their characteristics, such as their position, size, visibility, and opacity.

Styles

Styles define the visual appearance of objects, including colors, fonts, borders, and padding. Applying styles helps maintain a consistent look and feel across the user interface.

Events in LVGL (Annex)

LVGL is event-driven, meaning objects can respond to various events such as clicks, touches, value changes, and more. Event handlers can be attached to objects to define what happens when a particular event occurs.

By grasping these core concepts, developers working with Annex can effectively leverage LVGL to create engaging and functional user interfaces for their ESP32-based applications.

Colors in LVGL (Annex)

LVGL provides flexible ways to manage colors. Colors are typically defined using a structure that represents Red, Green, and Blue components. Within Annex, you can set colors for various aspects of a widget:

● Background Color: The color of the main background of the widget.

● Text Color: The color of the text displayed on the widget.

● Border Color: The color of the widget's border.

● Image Color: Colors can be applied to images, allowing effects like tinting.

LVGL supports various color formats, and Annex likely leverages these to allow easy color definition using hexadecimal color codes (e.g., &hRRGGBB) or predefined color constants.

In this implementation, the colors will be always specified as 24 bits RGB, even if the final display (the TFT) only supports 16 bits colors.

As an example, the number &hFF0000 represents the RED color, &h00FF00 the GREEN color and &h0000FF the BLUE color.

Opacity in LVGL (Annex)

Opacity determines the level of transparency of an object, ranging from fully transparent to fully opaque. In LVGL, opacity is typically controlled using an 8-bit value, where:

● 0 means fully transparent (invisible).

● 255 means fully opaque (completely visible).

Opacity can be applied to the following elements:

● Background: Controls the transparency of the widget's background.

● Text: Adjusts the transparency of the text displayed on the widget.

● Images: Controls the transparency of images.

● Borders: Adjusts the transparency of the border.

Opacity settings are often combined with colors to create various visual effects, such as semi-transparent backgrounds, faded text, or subtle image overlays.

Usage in Annex

Within Annex, you would typically use specific commands or functions to set colors and opacity for LVGL objects. For example:

' Set background color to red with 50% opacity
LVGL.SET_BG_COLOR obj, &hff0000
LVGL.SET_BG_OPA obj, 128 ' 128 = 50% of 255


The specifics will depend on the actual API provided by Annex for interacting with LVGL. Colors and opacity are essential tools for creating visually appealing and informative user interfaces within the Annex environment.

 Widgets in LVGL (and Annex): The Building Blocks of User Interfaces

In LVGL, widgets are pre-built UI components that provide ready-to-use functionality and visual elements for creating user interfaces. They encapsulate both the appearance and behavior of common UI elements, simplifying the development process. Widgets are built upon the core concepts of LVGL, such as objects, styles, events, and flags, allowing for customization and interaction.

Annex provides a specific set of LVGL widgets tailored for ESP32 projects. Let's explore these widgets, grouped by their general function:

Basic Display Elements:

Base (the base object): This is the fundamental building block; a simple rectangle that serves as the foundation for all other widgets. It manages basic properties like position, size, and style. In Annex, it's likely used as a container or as a basis for custom widgets.

Label: Used to display text. Labels can be customized with different fonts, colors, and alignments. Annex includes the option relevant for controlling how labels handle long texts.

Image: Used to display images. This allows you to incorporate graphical elements into your UI. Annex likely supports various image formats like BMP, JPG and PNG.

Buttons and Input:

Button: A standard clickable button used to trigger actions. In Annex, you can customize the appearance and behavior of buttons using styles and event handlers.

ImageButton: A button that uses one or two images as its visual representation. The documentation's LV_IMAGEBUTTON_STATE_* enums are specific to these buttons, allowing you to define different images for different button states (released, pressed, disabled, etc.).

ImageToggle: A button toggle (2 alternating states) that uses one or two images as its visual representation. The documentation's LV_IMAGEBUTTON_STATE_* enums are specific to these buttons, allowing you to define different images for different button states (released, pressed, disabled, etc.).

Switch: A toggle switch used to turn something on or off. Annex likely uses styles to customize its appearance.

Slider: Allows the user to select a value along a continuous range. Annex uses styles to modify indicator and background

Keyboard: Provides a virtual keyboard for text input, particularly useful on touchscreens. The LV_KEYBOARD_MODE_* enums in the documentation define the different keyboard layouts (text, number, special characters) available in Annex.

Text Area: A multi-line text input field where users can enter and edit text. Often used in conjunction with the Keyboard widget.

Selectors and Indicators:

Roller: A spinning wheel selector, allowing users to choose from a list of options. ● List: Displays a scrollable list of items, allowing users to select an option from the list.

Dropdown : A compact widget that displays a single selected value and expands to show a list of options when activated.

Tabview: Creates a tabbed interface, allowing users to switch between different panels of content.

Checkboxes and Radio Buttons:

Checkbox: A standard checkbox for toggling a boolean value.

Radio (a customized checkbox): A checkbox that is usually grouped into multiple others, where only one of them is selected

Indicators and Visualizations:

LED: Simulates a light-emitting diode, typically used to indicate status.

Bar: Visually represents a value within a range, often used for progress indicators or level meters.

Arc: Displays values on an arc.

Canvas: A blank rectangular area that is manipulated by LVGL draw APIs.

Scale: Used to draw a scale or a ruler with tick marks and labels.

Data Display:

Line: Draws a line used to create the needle for a Scale widget.

Message Box (MsgBox): Creates a pop-up window to display a message with buttons for user interaction.

GIF: Used to display GIF animated images.

Groups:

Association of objects around a common objective (i.e. receive events from a keyboard)

By combining these widgets and leveraging LVGL's customization options, Annex allows developers to create a wide range of user interfaces for ESP32 projects, from simple status displays to complex interactive applications.

 

Getting Started with Annex

Initializing LVGL and Understanding Memory Allocation

When starting an Annex project with LVGL for graphical user interfaces, understanding memory allocation is paramount. LVGL requires memory for the screen buffer and for storing the objects (widgets) themselves.

LVGL.INIT: Configuring Memory and Display

The LVGL.INIT command in Annex sets up LVGL and allocates memory. The syntax is:

LVGL.INIT col_fg, col_bg [, buff_size]

Arguments:

     col_fg: The foreground color.

     col_bg: The background color.

     buff_size (Optional): Size of the screen buffer in bytes.

Memory Allocation Breakdown:

 Screen Buffer, if not explicitly specified will be :

● With PSRAM: If PSRAM is available, the screen buffer is allocated in PSRAM and sized at SCREEN_WIDTH * SCREEN_HEIGHT * 2 bytes.

● Without PSRAM: If PSRAM is not available, the screen buffer is allocated in internal RAM, and sized at SCREEN_WIDTH * SCREEN_HEIGHT *2 / 10 bytes.

Object RAM: This memory is used to store the widgets (buttons, labels, etc.) and their associated data.

● ESP32 and ESP32-S3: 1MB of RAM is allocated for objects. (TBC)

● ESP32-S2: 256KB of RAM is allocated for objects.

● If PSRAM is NOT Available: In all cases, if PSRAM is not available, the object RAM is allocated, and in this case, the RAM allocated will be 16K for all the devices.

Important Notes on Memory Management.

● PSRAM Impact: The presence of PSRAM significantly impacts the available memory for the screen buffer, enabling larger and more complex displays.

● Object RAM Limits: The amount of object RAM dictates the complexity of your UI. Exceeding the available object RAM can lead to crashes or unexpected behavior. The Documentation states what you can configure using the object RAM

Understanding col_fg and col_bg in LVGL.INIT

In the Annex environment, the LVGL.INIT command initializes the LVGL library and sets up the memory buffers. Among its arguments, col_fg and col_bg play a fundamental role in defining the initial color scheme of the display.

Purpose of col_fg and col_bg:

● col_fg (Foreground Color): This parameter specifies the primary color that will be used for elements like text, borders, and other prominent visual features in your UI. It essentially sets the "accent" color.

● col_bg (Background Color): This parameter defines the base color for the background of your display and most widgets.

Why are they important?

These two color settings establish the initial visual foundation for your entire application. They determine the overall tone and contrast of the UI. Choosing appropriate col_fg and col_bg values is crucial for:

● Readability: Ensuring sufficient contrast between text and background for easy reading.

● Visual Appeal: Creating an aesthetically pleasing color scheme.

● Branding: Aligning the UI colors with your brand identity.

Color Representation.

The specific format for specifying col_fg and col_bg will depend on the Annex implementation and the capabilities of the underlying LVGL library. Common methods include:

● Hexadecimal Color Codes: Using a representation of the color in hexadecimal format (e.g., &hFF0000 for red).

● Predefined Color Constants:

List of predefined colors with the corresponding RGB888 values (in hexadecimal format)

Color Name

RGB88 Value

BLACK

0x000000

NAVY

0x000080

DARKGREEN

0x006400

DARKCYAN

0x008B8B

MAROON

0x800000

PURPLE

0x800080

OLIVE

0x808000

LIGHTGREY

0xD3D3D3

DARKGREY

0xA9A9A9

BLUE

0x0000FF

GREEN

0x008000

CYAN

0x00FFFF

RED

0xFF0000

MAGENTA

0xFF00FF

YELLOW

0xFFFF00

WHITE

0xFFFFFF

ORANGE

0xFFA500

GREENYELLOW

0xADFF2F

PINK

0xFFC0CB

BROWN

0xA52A2A

GOLD

0xFFD700

SILVER

0xC0C0C0

SKYBLUE

0x87CEEB

VIOLET

0x8A2BE2

 

Example:

Here's an example of using LVGL.INIT with col_fg and col_bg in Annex:

' Initialize LVGL with a red foreground and a black background
LVGL.INIT RED, BLACK

LVGL.INIT &h0000FF, &hFFFFFF ' Using hexadecimal color codes



LVGL.SET_THEME : Setting the default Theme

This command sets the theme for LVGL. The theme defines the overall look and feel of the user interface, including colors, fonts, and other visual attributes. The syntax is:

LVGL.SET_THEME col_primary, col_secondary, fontnum, dark [, theme_type]

Arguments:

     col_primary: Primary color used for prominent UI elements like buttons and active states.

     col_secondary: Secondary color used for less prominent UI elements and inactive states.

     fontnum: Font number to be used for text elements.

     dark: Dark mode flag (1 for dark mode, 0 for light mode).

     theme_type (Optional) : theme type:

     1: Simple theme.

     2: Mono theme.

     0: Default theme (default).

- Primary Color (col_primary): This color is used for the main interactive elements such as buttons in their active or pressed state. It should contrast well with the background color to ensure visibility and usability.

- Secondary Color (col_secondary): This color is used for secondary elements and inactive states. It complements the primary color and helps to create a harmonious color scheme.

- Font Number (fontnum): Specifies the font to be used for text elements within the UI. Different fonts can be loaded and used to customize the appearance of text.

- Dark Mode (dark): Enables or disables dark mode, which uses a darker color palette that is easier on the eyes in low-light environments.

- Theme Type (theme_type): Allows you to choose between different predefined themes or create a custom theme. The simple and mono themes provide quick ways to apply a consistent look, while the default theme allows for full customization.

Examples:

 1. Set a custom theme with a blue primary color, green secondary color, font number 1, and dark mode enabled

LVGL.SET_THEME &h0000FF, &h00FF00, 1, 1

2. Set a simple theme with a red primary color, black secondary color, font number 2, and light mode enabled

LVGL.SET_THEME &hFF0000, &h000000, 2, 0, 1

3. Set a mono theme with a white primary color, gray secondary color, font number 3, and dark mode enabled

LVGL.SET_THEME &hFFFFFF, &h808080, 3, 1, 2

By setting the theme, you can quickly apply a consistent look and feel across your entire application, ensuring that all UI elements are visually cohesive and aesthetically pleasing.

 

Understanding lv_style_selector_t

lv_style_selector_t is a key feature in LVGL that enables the combination of two values to target a specific part of an object in a particular state. This allows developers to apply styles dynamically and precisely to objects.

Components of lv_style_selector_t

         Part (lv_part_t): Specifies which part of the object to target.
Common parts include LV_PART_MAIN, LV_PART_SCROLLBAR, etc.

         State (lv_state_t): Defines the state of the object, such as LV_STATE_PRESSED, LV_STATE_HOVERED, etc.

It is possible, for example, to change the color of a part of an object in a particular state.

The example below shows how change the color of a button when pressed:

' Defines the constants (taken from the tables below)

LV_PART_MAIN = 0x0

LV_STATE_PRESSED = 0x0020

' Create a button
But = LVGL.BUTTON "Button"

' Set the background color for the button when pressed

LVGL.SET_BG_COLOR But, RED, LV_PART_MAIN or LV_STATE_PRESSED


This argument is often optional and, in this case, it defaults to 0 =  LV_PART_MAIN or LV_STATE_DEFAULT     that means the main part of the object in its default state.

Functions and Commands in LVGL Implementation

The current implementation provides a comprehensive set of functions designed to facilitate various operations within the library. These functions are versatile and can be utilized in two distinct ways:

  1. As Functions: When used in this manner, they return a value as specified in the documentation. This return value can be meaningful and is often used for further processing or decision-making within your application.
    For instance, in the case of objects such as labels, buttons, etc., the returned value typically represents a reference or ID for the created object. This ID is essential for interacting with the object later in your code. By using this reference, you can

     Modify Properties: Change attributes such as colors, sizes, fonts, or alignment dynamically.

     Update Content: Adjust the text of a label, the image of an icon, or the state of a button.

     Add Events: Attach event handlers to respond to user interactions like clicks, drags, or gestures.

     Perform Advanced Operations: Use the ID to group objects, animate them, or manage their visibility.

  1. As Commands: Alternatively, these functions can be invoked solely to perform an action without considering their return value. This approach is particularly useful when the result is either meaningless or not required for the specific use case.

The example below shows this :

' Creates a label and get its ID into the variable Lab1

Lab = LVGL.LABEL "Label" ' used as Function

' Change the text of the label
LVGL.SET_TEXT Lab, "Change Text"

' Creates a label with no use of its ID

LVGL.LABEL "Label2" ' Used as Command

 


LVGL Functions


LVGL.INIT col_fg, col_bg [, buff_size [, buff_count = 1]

Description: Initializes LVGL with specified colors and optional buffer size and buffer count.

Arguments:

     col_fg: Foreground color.

     col_bg: Background color.

     buff_size: Optional buffer size. Default is:

     If PSRAM is available:

     Screen_width * screen_height * 2

     If PSRAM is NOT available:

     Screen_width * screen_height * 2 / 10

     buff_count = 1: Optional buffer count. Default is 1.

Return: None

LVGL Commands: lv_init(), lv_display_create(), lv_display_set_flush_cb(), lv_display_set_buffers()


LVGL.SET_THEME col_primary, col_secondary, fontnum, dark [, theme_type = 0]

Description: Sets the theme for LVGL.

Arguments:

     col_primary: Primary color.

     col_secondary: Secondary color.

     fontnum: Font number.

     dark: Dark mode flag.

     theme_type = 0: Optional theme type (1 for simple, 2 for mono, 0 for default). Default is 0.

Return: None

LVGL Commands: lv_theme_simple_init(), lv_theme_mono_init(), lv_theme_default_init()


LVGL.REFRESH

Description: Refreshes the LVGL display. Must be called regularly in a loop or with a timer for the update of the screen.

Arguments: None

Return: None

LVGL Command: lv_timer_handler()


LVGL.START [memory = 8192] [, priority = 0] [, core = 0]

Description: Starts the LVGL task with customizable memory allocation, priority, and core assignment.

Arguments:

     memory = 8192: Memory size for the task. Default is 8192.

     priority = 0: Optional task priority. Default is 0 (lowest priority).

     core = 0: Optional core to run the task on. Default is 0.

Return: None

RTOS Command: xTaskCreatePinnedToCore()

Notes: This command utilizes a FreeRTOS function to create a separate task for LVGL operations. The created task runs the LVGL.REFRESH function, which internally calls lv_timer_handler(). This approach offers an alternative to manually calling LVGL.REFRESH at regular intervals. This command is available only on modules with dual core and should be used only if a PSRAM chip is present.


LVGL.STOP

Description: Stops the LVGL task.

Arguments: None

Return: None

LVGL Command: Sets lvgl_task_run to false and waits for the task to stop.


LVGL.RESET

Description: Resets the LVGL environment by stopping the task and deinitializing LVGL.

Arguments: None

Return: None

LVGL Commands: lv_deinit()


LVGL.CLEAN [obj]

Description: Cleans the content of active screen or the content of the optional object.

Arguments:

     obj: Optional object to be cleaned; If not specified, the active screen will be cleaned..

Return: None

LVGL Command: lv_obj_clean()


LVGL.DELETE obj

Description: Deletes a specified LVGL object.

Arguments:

     obj: Object to delete.

Return: None

LVGL Command: lv_obj_delete()


LVGL.SCREEN

Description: Returns the active screen object. The active screen represents the device where the image is shown (the display). By default it is the “father” of all the objects.

Arguments: None

Return: Active screen object.

LVGL Command: lv_screen_active()

Link to LVGL Official DOC


LVGL.CURSOR

Description: Returns the screen cursor object. Can be used to hide / show or modify the default cursor pointer.

Arguments: None

Return: Screen cursor object.

LVGL Command: N/A


LVGL.DEF_FATHER obj

Description: Sets the default parent object. If 0 is provided, the default parent will be the active screen object (LVGL.SCREEN). Each object created after this command will be a child of it.

Arguments:

     obj: Object to set as the default parent.

Return: None

LVGL Command: Sets lv_father to the specified object.


LVGL.ARC [x [, y [, w [, h]]]]

Description: Creates an arc object with optional dimensions.

Arguments:

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created arc object.

LVGL Command: lv_arc_create()

Link to LVGL Official DOC


LVGL.ARC_ROTATE_OBJ_TO_ANGLE arc_obj, obj_to_rotate, radius_offset

Description: Rotates an object to the current value of an ARC object.

Arguments:

     arc_obj: Arc object.

     obj_to_rotate: Object to rotate.

     radius_offset: Offset on the radius to be applied at the rotated object.

Return: None

LVGL Command: lv_arc_rotate_obj_to_angle()

Notes: This command enables drawing a text along the cursor of an ARC object.


LVGL.BASE [x [, y [, w [, h]]]]

Description: Creates a base object with optional dimensions. The “base” object can be used as a container for other objects acting like a “father” object.

Arguments:

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created base object.

LVGL Command: lv_obj_create()

Link to LVGL Official DOC


LVGL.BAR [x [, y [, w [, h]]]]

Description: Creates a bar object with optional dimensions.

Arguments:

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created bar object.

LVGL Command: lv_bar_create()

Link to LVGL Official DOC


LVGL.BUTTON text$ [, x[, y [, w [, h]]]]

Description: Creates a button with text.

Arguments:

     text$: Button text.

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created button object.

LVGL Commands: lv_button_create(), lv_label_create(), lv_label_set_text()

Link to LVGL Official DOC


LVGL.BUTTONMATRIX but_map$ [, x [, y[, w [, h]]]]

Description: Creates a button matrix with a specified map and optional dimensions.

Arguments:

     but_map$: String defining the button names.

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created button matrix object.

LVGL Commands: lv_buttonmatrix_create(), lv_buttonmatrix_set_map()

Button Map Composition

The but_map$ string defines the layout and labels of the buttons in the matrix. Here’s how to structure it:

  1. Button Separation: Button labels are separated by commas (,). Each comma indicates a new button within the same row.
  2. Line Breaks: To create multiple rows, use the newline character (\n). This places buttons on separate lines within the matrix.

Example

Bm1 = LVGL.BUTTONMATRIX "UP,DOWN,\n,LEFT,RIGHT"

Link to LVGL Official DOC


LVGL.CANVAS [x [, y [, w [, h [, col_bg]]]]]

Description: Creates a canvas object with a given dimensions. The canvas object acts as a container for sprites drawn in the TFT library.

Arguments:

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width. Default is 50 px.

     [h]: Optional height. Default is 50 px.

     [bg_col]: Optional background color . Default is black.

Return: Created canvas object.

LVGL Command: lv_canvas_create(),lv_canvas_set_buffer(),lv_canvas_fill_bg()

Notes: The CANVAS requires at least 2 × image width × image height bytes of RAM, so it should be used only with small images and modules with PSRAM.

Link to LVGL Official DOC


LVGL.CHECKBOX text$ [, x[, y [, w [, h]]]]

Description: Creates a checkbox with text.

Arguments:

     text$: Checkbox text.

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created checkbox object.

LVGL Commands: lv_checkbox_create(), lv_checkbox_set_text()

Link to LVGL Official DOC


LVGL.RADIO text$ [, x[, y [, w [, h]]]]

Description: Creates a radio button with text.

Arguments:

     text$: Radio button text.

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created radio button object.

LVGL Commands: lv_checkbox_create(), lv_checkbox_set_text(), lv_obj_set_style_radius(), lv_obj_set_style_bg_image_src()

Link to LVGL Official DOC


LVGL.DROPDOWN options$ [, x [, y[, w [, h]]]]

Description: Creates a dropdown with options.

Arguments:

     options$: Dropdown options — a string containing a list of options separated by “\n”, e.g.[1] , “First\nSecond\nLong\nShort”.

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created dropdown object.

LVGL Commands: lv_dropdown_create(), lv_dropdown_set_options()

Link to LVGL Official DOC


LVGL.GIF path$ [, x[, y [, w [, h]]]]

Description: Creates a GIF object from a file path.

Arguments:

     path$: File path of the GIF.

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created GIF object.

LVGL Commands: lv_gif_create(), lv_gif_set_src()

Notes: The GIF requires at least 4 × image width × image height bytes of RAM, so it should be used only with small animations and modules with PSRAM.

Link to LVGL Official DOC


LVGL.GIF_PLAY obj, play_control

Description: Controls the playback of a GIF.

Arguments:

     obj: GIF object.

     play_control: Playback control (0 to pause, 1 to resume, 2 to restart).

Return: None

LVGL Commands: lv_gif_pause(), lv_gif_resume(), lv_gif_restart()


LVGL.IMAGE path$

Description: Creates an image object from a file path (supports BMP, JPEG, PNG).

Arguments:

     path$: File path of the image.

Return: Created image object.

LVGL Commands: lv_readBmpFile(), lv_readJpgFile(), lv_readPngFile()

Notes: This command loads the images in RAM, so it should be used sparingly, especially with modules without PSRAM.

Link to LVGL Official DOC


LVGL.IMAGEBUTTON img1 [, img2]

Description: Creates an image button with optional images for different states. This command works like a temporary button, where the image changes when the button is pressed and reverts back when released.

Arguments:

     img1: Image for the pressed state.

     [img2]: Optional image for the released state. If not specified, img1 will be used with a lower level of luminosity for the released state.

Return: Created image button object.

LVGL Commands: lv_imagebutton_create(), lv_imagebutton_set_src()

Notes: This command loads the images in RAM, so it should be used sparingly, especially with modules without PSRAM.

Link to LVGL Official DOC


LVGL.IMAGETOGGLE img1 [, img2]

Description: Creates an image button with optional images for different states. This command works like a toggle button, where the image changes when the button is checked or unchecked.

Arguments:

     img1: Image for the checked state.

     [img2]: Optional image for the unchecked state. If not specified, img1 will be used with a lower level of luminosity for the unchecked state.

Return: Created image button object.

LVGL Commands: lv_imagebutton_create(), lv_imagebutton_set_src()

Notes: This command loads the images in RAM, so it should be used sparingly, especially with modules without PSRAM.

Link to LVGL Official DOC


LVGL.KEYBOARD mode

Description: Creates a keyboard with an optional mode map.

Arguments:

     mode: Mode value. (lv_keyboard_mode_t)

Return: Created keyboard object.

LVGL Commands: lv_keyboard_create(), lv_keyboard_set_mode()

Link to LVGL Official DOC


LVGL.KBD_SET_TEXTAREA kbd_obj, txt_obj

Description: Sets the text area for a keyboard object. To clarify, it designates the textarea that will receive the keys coming from the keyboard object.

Arguments:

     kbd_obj: Keyboard object.

     txt_obj: Text area object.

Return: None

LVGL Command: lv_keyboard_set_textarea()


LVGL.LABEL text$ [, x[, y [, w [, h]]]]

Description: Creates a label with text.

Arguments:

     text$: Label text.

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created label object.

LVGL Commands: lv_label_create(), lv_label_set_text()

Link to LVGL Official DOC


LVGL.LED [color [, x [, y [, w [, h]]]]]

Description: Creates an LED with optional color and position.

Arguments:

     [color]: Optional LED color.

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created LED object.

LVGL Commands: lv_led_create(), lv_led_set_color()

Link to LVGL Official DOC


LVGL.LIST [x [, y [, w [, h]]]]

Description: Creates a list object.

Arguments:

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created list object.

LVGL Command: lv_list_create()

Link to LVGL Official DOC


LVGL.ADD_BUTTON list_obj, icon, text$

Description: Adds a button to a list.

Arguments:

     list_obj: List object.

     icon: Icon for the button (check table with the icon codes).

     text$: Text for the button; it can contain an icon code too.

Return: Created button object.

LVGL Command: lv_list_add_button()


LVGL.ADD_TEXT list_obj, text$

Description: Adds text to a list.

Arguments:

     list_obj: List object.

     text$: Text to add.

Return: Created text object.

LVGL Command: lv_list_add_text()


LVGL.MSGBOX title$, msg$

Description: Creates a message box with a title and text.

Arguments:

     title$: Title text.

     msg$: Message text.

Return: Created message box object.

LVGL Commands: lv_msgbox_create(), lv_msgbox_add_title(), lv_msgbox_add_text(), lv_msgbox_add_close_button(), lv_msgbox_add_footer_button()

Link to LVGL Official DOC


LVGL.MSGBOX_CLOSE msgbox_obj

Description: Closes a message box.

Arguments:

     msgbox_obj: Message box object to close.

Return: None

LVGL Command: lv_msgbox_close()


LVGL.ROLLER options$ [, x [, y [, w [, h]]]]

Description: Creates a roller with options.

Arguments:

     options$: Roller options — a string containing a list of options separated by “\n”[2] , e.g., “First\nSecond\nLong\nShort”.

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created roller object.

LVGL Commands: lv_roller_create(), lv_roller_set_options()

Link to LVGL Official DOC


LVGL.SCALE [x [, y [, w [, h]]]]

Description: Creates a scale object with optional dimensions. By default, the scale is LV_SCALE_MODE_HORIZONTAL_BOTTOM with a range from 0 to 100, 21 ticks with major ticks every 2. The mode can be changed with the command LVGL.SET_MODE.

Arguments:

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created scale object.

LVGL Commands: lv_scale_create(), lv_scale_set_text_src(), lv_scale_set_mode(), lv_scale_set_label_show(), lv_scale_set_total_tick_count(), lv_scale_set_major_tick_every(), lv_obj_set_style_length(), lv_scale_set_range()

Link to LVGL Official DOC


LVGL.SET_ANGLE_RANGE obj, val

Description: Sets the angle range for a scale object.

Arguments:

     obj: Scale object.

     val: Angle range value.

Return: Object type.

LVGL Command: lv_scale_set_angle_range()


LVGL.SET_TICKS obj, total, interval

Description: Sets the total tick count and major tick interval for a scale object.

Arguments:

     obj: Scale object.

     total: Total tick count.

     interval: Major tick interval.

Return: None.

LVGL Commands: lv_scale_set_total_tick_count(), lv_scale_set_major_tick_every()


LVGL.SET_LABEL_SHOW obj, val

Description: Sets whether to show labels on a scale object.

Arguments:

     obj: Scale object.

     val: Show labels flag (1 for true, 0 for false).

Return: None.

LVGL Command: lv_scale_set_label_show()


LVGL.LINE

Description: Creates a line object.

Arguments: None.

Return: Created line object.

LVGL Command: lv_line_create()

Note: The line is actually used only as a needle for the Scale Object.


LVGL.SET_LINE_NEEDLE_VALUE scale_obj, line_obj, length, val

Description: Sets the line needle value for a scale object.

Arguments:

     scale_obj: Scale object.

     line_obj: Needle object.

     length: Needle length.

     val: Needle value.

Return: None.

LVGL Command: lv_scale_set_line_needle_value()


LVGL.SET_IMAGE_NEEDLE_VALUE scale_obj, image_obj, val

Description: Sets the image needle value for a scale object. This allows an image to be used as the needle for the scale object. The image must be loaded beforehand and aligned with the scale object. The functions LVGL.SET_IMAGE_PIVOT or LVGL.SET_IMAGE_PIVOT_PCT can be used to perfectly align the rotation point (the pivot) of the needle.

Arguments:

     scale_obj: Scale object.

     line_obj: Needle object.

     val: Needle value.

Return: None.

LVGL Command: lv_scale_set_image_needle_value()

Notes: The image must point to the right. E.g. -O------>


LVGL.SLIDER [x [, y [, w [, h]]]]

Description: Creates a slider object with optional dimensions.

Arguments:

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created slider object.

LVGL Command: lv_slider_create()

Link to LVGL Official DOC


LVGL.SPINNER anim, angle [, x [, y [, w [, h]]]]

Description: Creates a spinner with animation parameters.

Arguments:

     anim: Animation time.

     angle: Angle increment.

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created spinner object.

LVGL Commands: lv_spinner_create(), lv_spinner_set_anim_params()

Link to LVGL Official DOC


LVGL.SWITCH [x [, y [, w [, h]]]]

Description: Creates a switch object with optional dimensions.

Arguments:

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created switch object.

LVGL Command: lv_switch_create()

Link to LVGL Official DOC


LVGL.TABVIEW [x [, y [, w [, h]]]]

Description: Creates a tab view object.

Arguments:

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created tab view object.

LVGL Command: lv_tabview_create()

Link to LVGL Official DOC


LVGL.ADD_TAB tab_view_obj, tab_name$

Description: Adds a tab to a tab view.

Arguments:

     tab_view_obj: Tab view object.

     tab_name$: Tab name.

Return: Created tab object.

LVGL Command: lv_tabview_add_tab()


LVGL.SET_TAB_BAR_POS tab_view_obj, tab_pos

Description: Sets the tab bar position for a tab view.

Arguments:

     tab_view_obj: Tab view object.

     tab_pos: Position value (lv_dir_t).

Return: None.

LVGL Command: lv_tabview_set_tab_bar_position()


LVGL.SET_ACTIVE obj, idx,[anim]

Description: Sets the active tab for a tab view object.

Arguments:

     obj: Tab view object.

     idx: Index of the tab to set as active.

     [anim]: Optional animation flag (1 for animated, 0 for immediate).

Return: Object type.

LVGL Command: lv_tabview_set_active()


LVGL.TEXTAREA text$ [, x [, y [, w [, h]]]]

Description: Creates a text area with text.

Arguments:

     text$: Text area text.

     [x]: Optional X position.

     [y]: Optional Y position.

     [w]: Optional width.

     [h]: Optional height.

Return: Created text area object.

LVGL Commands: lv_textarea_create(), lv_textarea_set_one_line(), lv_textarea_set_text()

Notes: By default, the textarea is a single line but can be changed using the command LVGL.SET_MODE.

Link to LVGL Official DOC


LVGL.ADD_EVENT obj, event, gotoline

Description: Adds an event to an object.

Arguments:

     obj: Object to add the event to.

     event: Event code. (lv_event_code_t)

     gotoline: Line number to go to when the event is triggered.

Return: None.

LVGL Command: lv_obj_add_event_cb()

Notes: This command adds an event to an object. The event code and the line number to go to when the event is triggered are specified.

Link to LVGL Official DOC


LVGL.REMOVE_EVENT obj, event

Description: Removes an event from an object.

Arguments:

     obj: Object to remove the event from.

     event: Event code. (lv_event_code_t)

Return: None.

LVGL Command: lv_obj_remove_event()


LVGL.ADD_FLAG obj, flag

Description: Adds one or more flags to an LVGL object.

Arguments:

     obj: The LVGL object to add the flag(s) to.

     flag: The flag or combination of flags to add (can use bitwise OR for multiple flags). (lv_obj_flag_t)

Return: Object type.

LVGL Command: lv_obj_add_flag()

Link to LVGL Official DOC


LVGL.REMOVE_FLAG obj, flag

Description: Removes one or more flags from an LVGL object.

Arguments:

     obj: The LVGL object to remove the flag(s) from.

     flag: The flag or combination of flags to remove (can use bitwise OR for multiple flags). (lv_obj_flag_t)

Return: Object type.

LVGL Command: lv_obj_remove_flag()


LVGL.UPDATE_FLAG obj, val, [flag = 1]

Description: Updates a flag for an object.

Arguments:

     obj: Object to update flag for.

     val: Value for the flag (can be 0 or 1).

     [flag]: Optional Flag to update (default = 1). (lv_obj_flag_t)

Return: Object type.

LVGL Command: lv_obj_update_flag()


LVGL.GET_FLAG obj

Description: Returns the flags of an object. (lv_obj_flag_t)

Arguments:

     obj: Object to get flags for.

Return: Flags of the object.

LVGL Command: Returns obj->flags.


LVGL.ADD_STATE obj, state

Description: Adds one or more states to an LVGL object.

Arguments:

     obj: The LVGL object to add the state(s) to.

     state: The state or combination of states to add (can use bitwise OR for multiple states). (lv_state_t)

Return: Object type.

LVGL Commands: lv_obj_add_state()

Link to LVGL Official DOC


LVGL.REMOVE_STATE obj, state

Description: Removes one or more states from an LVGL object.

Arguments:

     obj: The LVGL object to remove the state(s) from.

     state: The state or combination of states to remove (can use bitwise OR for multiple states). (lv_state_t)

Return: Object type.

LVGL Commands: lv_obj_remove_state()


LVGL.SET_STATE obj, val, [state = 1]

Description: Sets the state of an LVGL object.

Arguments:

     obj: The LVGL object to set the state for.

     val: Boolean value (1 to set the state, 0 to clear it).

     [state]: Optional. The specific state to set or clear. (default = 1). (lv_state_t)

Return: Object type.

LVGL Commands: lv_obj_set_state()

Link to LVGL Official DOC


LVGL.GET_STATE obj

Description: Returns the state of an object. (lv_state_t)

Arguments:

     obj: Object to get state for.

Return: State of the object.

LVGL Command: lv_obj_get_state()


LVGL.ALIGN_TO obj, obj_base, align [, x [, y]]

Description: Aligns an object to another object.

Arguments:

     obj: Object to align.

     obj_base: The reference object to align obj to.

     align: The alignment type, defined as (lv_align_t).
This determines how the objects are positioned relative to each other.

     [x]: Optional horizontal offset in pixels, applied after alignment.

     [y]: Optional vertical offset in pixels, applied after alignment.

Return: None.

LVGL Command: lv_obj_align_to()

Notes: This command enables you to position an object (obj) relative to another object (obj_base) using predefined alignment types. The alignment types are numeric values defined in the  (lv_align_t)  table (refer to the image below for details).
image

The optional x and y arguments allow you to fine-tune the position by shifting the aligned object horizontally and vertically by a specified number of pixels.

Link to LVGL Official DOC


LVGL.GET_CHILD obj, idx

Description: Returns the child object at a specific index.

Arguments:

     obj: Parent object.

     idx: Index of the child object.

Return: Child object at the specified index.

LVGL Command: lv_obj_get_child()


LVGL.GET_CHILD_COUNT obj

Description: Returns the number of child objects.

Arguments:

     obj: Parent object.

Return: Number of child objects.

LVGL Command: lv_obj_get_child_count()


LVGL.GET_PARENT obj

Description: Returns the parent object.

Arguments:

     obj: Child object.

Return: Parent object.

LVGL Command: lv_obj_get_parent()


LVGL.SET_PARENT obj, obj_parent

Description: Sets the parent of an object.

Arguments:

     obj: Child object.

     obj_parent: New parent object.

Return: None.

LVGL Command: lv_obj_set_parent()


LVGL.GET_CLASS_ID obj

Description: Returns the class ID of an object.[3] 

Arguments:

     obj: Object to get the class ID for.

Return: Class ID of the object.

LVGL Command: get_obj_type()


LVGL.GROUP

Description: Creates a new group.

Arguments:: None.

Return:: Created group.

LVGL Command:: : lv_group_create()


LVGL.GROUP_ADD group, obj

Description: Adds an object to a group.

Arguments:

     group: Group to add the object to.

     obj: Object to add to the group.

Return:: Group.

LVGL Command:: : lv_group_add_obj()


LVGL.GROUP_REMOVE obj

Description:: Removes an object from its group.

Arguments:

     obj: Object to remove from the group.

Return: None.

LVGL Command: lv_group_remove_obj()


LVGL.GROUP_DELETE group

Description: Deletes a group.

Arguments:

     group: Group to delete.

Return: None.

LVGL Command: lv_group_delete()


LVGL.GET_GROUP obj

Description: Gets the group of an object.

Arguments:

     obj: Object to get the group for.

Return: Group of the object.

LVGL Command: lv_obj_get_group()


LVGL.GET_TARGET

Description: Returns the target object who triggered the event.

Arguments: None.

Return: Target object.

LVGL Command: lv_obj_target


LVGL.GET_GESTURE

Description: Returns the gesture that triggered the event.

Arguments: None.

Return: Gesture enum (lv_dir_t).

LVGL Command: lv_obj_gesture_dir


LVGL.GET_VALUE obj

Description: Returns the value of an object. The value can vary depending on the type of the object.

Arguments:

     obj: Object to get value for.

     For Slider: Get the value.

     For Arc: Get the value.

     For Bar: Get the value.

     For Led: Get the brightness.

     For Roller: Get the index of the selected option.

     For Dropdown: Get the index of the selected option.

     For ImageButton: Get the state.

     For Keyboard: Get the index of the last "activated" key by the user (pressed, released, focused, etc.).

     For ButtonMatrix: Get the index of the last "activated" button by the user (pressed, released, focused, etc.).

Return: Value of the object.

LVGL Commands: lv_slider_get_value(), lv_arc_get_value(), lv_bar_get_value(), lv_led_get_brightness(), lv_roller_get_selected(), lv_dropdown_get_selected(), lv_obj_get_state()


LVGL.LOAD_FONT path$, fontnum

Description: Loads a font from a file.

Arguments:

     path$: File path of the font.

     fontnum: Font index (from 100 to 103).

Return: None.

LVGL Command: lv_binfont_create()

Notes: The fonts are loaded from file and must be in .bin format converted using the LVGL Online Font Converter


LVGL.SET_FONT obj, fontnum [,style_selector]

Description: Sets the font of an object.

Arguments:

     obj: Object to set font for.

     fontnum: Font number.

     style_selector: Optional state to set font for. (lv_state_t)  and (lv_part_t)

Font Numbers:

     1 : unascii 8px

     2 : unascii 16px

     8 : montserrat 8

     10 : montserrat 10

     12 : montserrat 12

     14 : montserrat 14

     16 : montserrat 16

     18 : montserrat 18

     20 : montserrat 20

     30 : montserrat 30

     100 : loaded font 100

     101 : loaded font 101

     102 : loaded font 102

     103 : loaded font 103

Return: None.

LVGL Command: lv_obj_set_style_text_font()


LVGL.SET_BG_ANGLES obj, start, end

Description: Sets the background angles of an arc object.

Arguments:

     obj: Arc object.

     start: Start angle.

     end: End angle.

Return: Object type.

LVGL Command: lv_arc_set_bg_angles()


LVGL.SET_BG_COLOR obj, col_bg [, style_selector]

Description: Sets the background color of an object.

Arguments:

     obj: Object to set background color for.

     col_bg: Background color.

     style_selector: Optional state to set background color for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Command: lv_obj_set_style_bg_color()


LVGL.SET_BG_OPA obj, val [, style_selector]

Description: Sets the background opacity of an object.

Arguments:

     obj: Object to set background opacity for.

     val: Background opacity value (from 0=transparent to 255=cover).

     style_selector: Optional state to set background opacity for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Command: lv_obj_set_style_bg_opa()


LVGL.SET_BORDER_COLOR obj, color [, style_selector]

Description: Sets the border color of an object.

Arguments:

     obj: Object to set border color for.

     color: Border color.

     style_selector: Optional state to set border color for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Command: lv_obj_set_style_border_color()


LVGL.SET_BORDER_SIDE obj, side [, style_selector]

Description: Sets the border side for an object.

Arguments:

     obj: Object to set border side for.

     side: Border side value (lv_border_side_t).

     style_selector: Optional state to set border side for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Command: lv_obj_set_style_border_side()


LVGL.SET_BORDER_WIDTH obj, width [, style_selector]

Description: Sets the border width for an object.

Arguments:

     obj: Object to set border width for.

     width: Border width value.

     style_selector: Optional state to set border width for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Command: lv_obj_set_style_border_width()


LVGL.SET_CLIP_CORNER obj, val [, style_selector]

Description: Sets the clip corner for an object.

Arguments:

     obj: Object to set clip corner for.

     val: Clip corner flag (1 for true, 0 for false).

     style_selector: Optional state to set clip corner for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Command: lv_obj_set_style_clip_corner()

Note: Enable to clip the overflowed content on the rounded corner. Can be true (1) or false (0).


LVGL.SET_ARC_COLOR obj, color [, style_selector]

Description: Sets the color of an ARC object. This command is oriented for ARC, SPINNER, and SCALE objects.

Arguments:

     obj: Object to set arc color for.

     color: Arc color.

     style_selector: Optional state to set arc color for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Command: lv_obj_set_style_arc_color()


LVGL.SET_ARC_OPA obj, val [, style_selector]

Description: Sets the opacity of an ARC object. This command is oriented for ARC, SPINNER, and SCALE objects.

Arguments:

     obj: Object to set arc opacity for.

     val: Opacity value (from 0=transparent to 255=cover).

     style_selector: Optional state to set arc opacity for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Command: lv_obj_set_style_arc_opa()


LVGL.SET_LINE_COLOR obj, color [, style_selector]

Description: Sets the color of an object. This command tries to be generic and should cover all objects, including LED.

Arguments:

     obj: Object to set color for.

     color: Color value. The effect depends on the object type:

     For LED: Sets the color of the LED (lv_led_set_color()).

     For other objects: Sets the lv_obj_set_style_line_color property.

     style_selector: Optional state to set color for. (lv_state_t)  and (lv_part_t)

Return: Object type.

LVGL Commands: lv_obj_set_style_arc_color(), lv_obj_set_style_line_color(), lv_led_set_color()


LVGL.SET_LINE_OPA obj, val [, style_selector]

Description: Sets the opacity of an object. This command tries to be generic and should cover all objects.

Arguments:

     obj: Object to set opacity for.

     val: Opacity value (from 0=transparent to 255=cover).

     style_selector: Optional state to set opacity for. (lv_state_t)  and (lv_part_t)

Return: Object type.

LVGL Commands: lv_obj_set_style_line_opa()


LVGL.SET_FLEX_ALIGN obj, main, cross, track_cross

Description: Sets the flex alignment for an object.

Arguments:

     obj: Object to set flex alignment for.

     main: Alignment for the main axis (lv_flex_align_t).

     cross: Alignment for the cross axis (lv_flex_align_t).

     track_cross: Alignment for the track cross (lv_flex_align_t).

Return: None.

LVGL Command: lv_obj_set_flex_align()

Link to LVGL Official DOC


LVGL.SET_FLEX_FLOW obj, flex_flow

Description: Sets the flex flow for an object.

Arguments:

     obj: Object to set flex flow for.

     flex_flow: Flex flow value (lv_flex_flow_t).

Return: None.

LVGL Command: lv_obj_set_flex_flow()

Link to LVGL Official DOC


LVGL.SET_HEIGHT obj, h

Description: Sets the height of an object.

Arguments:

     obj: Object to set height for.

     h: Height.

Return: None.

LVGL Command: lv_obj_set_height()


LVGL.SET_IMAGE_RECOLOR obj, color [, style_selector]

Description: Sets the image recolor of an object.

Arguments:

     obj: Object to set image recolor for.

     color: Recolor value.

     style_selector: Optional state to set image recolor for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Command: lv_obj_set_style_image_recolor()


LVGL.SET_IMAGE_RECOLOR_OPA obj, val [, style_selector]

Description: Sets the image recolor opacity of an object.

Arguments:

     obj: Object to set image recolor opacity for.

     val: Recolor opacity value (from 0=transparent to 255=cover).

     style_selector: Optional state to set image recolor opacity for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Command: lv_obj_set_style_image_recolor_opa()


LVGL.SET_LAYER obj, layer

Description: Moves an object to a specified layer.

Arguments:

     obj: Object to move.

     layer: Layer index or special value:

     1000 for foreground

     -1000 for background

     -9999 bottom layer

     9999 top layer

     10000 sys layer

Return: None.

LVGL Commands: lv_obj_move_foreground(), lv_obj_move_background(), lv_obj_move_to_index(), lv_obj_set_parent()


LVGL.SET_LENGTH obj, val [, style_selector]

Description: Sets the length for an object.

Arguments:

     obj: Object to set length for.

     val: Length value.

     style_selector: Optional state to set length for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Command: lv_obj_set_style_length()


LVGL.SET_LINE_ROUNDED obj, val [, style_selector]

Description: Sets whether the line is rounded for an object.

Arguments:

     obj: Object to set line rounded for.

     val: Line rounded flag (1 for true, 0 for false).

     style_selector: Optional state to set line rounded for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Command: lv_obj_set_style_line_rounded()


LVGL.SET_LINE_WIDTH obj, val [, style_selector]

Description: Sets the line width for an object.

Arguments:

     obj: Object to set line width for.

     val: Line width value.

     style_selector: Optional state to set line width for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Command: lv_obj_set_style_line_width()


LVGL.SET_MARGIN obj, top, [,bottom [,left [,right [,vert [,horiz [, style_selector]]]]]]

Description: Sets the margin for an object.

Arguments:

     obj: Object to set margin for.

     top: Top margin value.

     bottom: Optional bottom margin value.

     left: Optional left margin value.

     right: Optional right margin value.

     vert: Optional vertical margin value.

     horiz: Optional horizontal margin value.

     style_selector: Optional state to set margin for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Commands: lv_obj_set_style_margin_top(), lv_obj_set_style_margin_bottom(), lv_obj_set_style_margin_left(), lv_obj_set_style_margin_right(), lv_obj_set_style_margin_ver(), lv_obj_set_style_margin_hor()

Link to LVGL Official DOC


LVGL.SET_MODE obj, val

Description: Sets the mode for an object. The mode can vary depending on the type of the object.

Arguments:

     obj: Object to set mode for.

     val: Mode value. The acceptable values depend on the object type:

     For Scale: Set how the scale is shown (lv_scale_mode_t):

     0x00: The scale will be horizontal and the labels text aligned to the top.

     0x01: The scale will be horizontal and the labels text aligned to the bottom.

     0x02: The scale will be vertical and the labels text aligned to the left.

     0x04: The scale will be vertical and the labels text aligned to the right.

     0x08: The scale will be round and the labels text aligned to the inner side.

     0x10: The scale will be round and the labels text aligned to the outer side.

     For Keyboard: Set how the keyboard is shown (lv_keyboard_mode_t):

     0: Lowercase text input mode.

     1: Uppercase text input mode.

     2: Special characters input mode.

     3: Numeric input mode.

     For Label: Set the long mode (lv_label_long_mode_t):

     0: Wrap lines longer than the object width and expand the object height.

     1: Write dots at the end if the text is too long.

     2: Roll the text back and forth.

     3: Roll the text circularly.

     4: Clip the text out of the object's size.

     For Text Area: Set the line mode:

     0: Multi-line text input mode.

     1: Single-line text input mode.

Return: Object type.

LVGL Commands: lv_scale_set_mode(), lv_keyboard_set_mode()


LVGL.SET_PAD obj, top, [,bottom [,left [,right [,vert [,horiz [,row [,column [, style_selector]]]]]]]]

Description: Sets the padding for an object.

Arguments:

     obj: Object to set padding for.

     top: Top padding value.

     bottom: Optional bottom padding value.

     left: Optional left padding value.

     right: Optional right padding value.

     vert: Optional vertical padding value.

     horiz: Optional horizontal padding value.

     row: Optional row padding value.

     column: Optional column padding value.

     style_selector: Optional state to set padding for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Commands: lv_obj_set_style_pad_top(), lv_obj_set_style_pad_bottom(), lv_obj_set_style_pad_left(), lv_obj_set_style_pad_right(), lv_obj_set_style_pad_ver(), lv_obj_set_style_pad_hor(), lv_obj_set_style_pad_row(), lv_obj_set_style_pad_column()

Link to LVGL Official DOC


LVGL.SET_PAD_GAP obj, val [, style_selector]

Description: Sets the padding gap for an object.

Arguments:

     obj: Object to set padding gap for.

     val: Padding gap value.

     style_selector: Optional state to set padding gap for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Command: lv_obj_set_style_pad_gap()


LVGL.SET_POS obj, x, y

Description: Sets the position of an object.

Arguments:

     obj: Object to set position for.

     x: X position.

     y: Y position.

Return: None.

LVGL Command: lv_obj_set_pos()

Link to LVGL Official DOC


LVGL.SET_RANGE obj, start, end

Description: Sets the range of an object. This command covers the following objects: Arc, Slider, Bar, Scale.

Arguments:

     obj: Object to set range for.

     start: Start value.

     end: End value.

Return: Object type.

LVGL Commands: lv_arc_set_range(), lv_slider_set_range(), lv_bar_set_range(), lv_scale_set_range()


LVGL.SET_RADIUS obj, val [, style_selector]

Description: Sets the radius for an object.

Arguments:

     obj: Object to set radius for.

     val: Radius value.

     style_selector: Optional state to set radius for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Command: lv_obj_set_style_radius()


LVGL.SET_ROTATION obj, angle

Description: Sets the offset rotation of an ARC or SCALE object.

Arguments:

     obj: Object to set rotation for.

     angle: Rotation value (°). The angular offset from the 3 o'clock position (clockwise).

Return: Object type.

LVGL Commands: lv_arc_set_rotation(), lv_scale_set_rotation()


LVGL.SET_SCROLL_DIR obj, scroll_dir

Description: Sets the scroll direction for an object.

Arguments:

     obj: Object to set scroll direction for.

     scroll_dir: Scroll direction (1 for vertical, 2 for horizontal, 3 for all, 0 for none).

Return: None.

LVGL Command: lv_obj_set_scroll_dir()


LVGL.SET_SIZE obj, w, h

Description: Sets the size of an object.

Arguments:

     obj: Object to set size for.

     w: Width.

     h: Height.

Return: None.

LVGL Command: lv_obj_set_size()

Link to LVGL Official DOC


LVGL.SET_SIZE_PCT obj, w_pct, h_pct

Description: Sets the size of an object as a percentage.

Arguments:

     obj: Object to set size for.

     w_pct: Width percentage.

     h_pct: Height percentage.

Return: None.

LVGL Command: lv_obj_set_size()

Link to LVGL Official DOC


LVGL.SET_TEXT obj, str$

Description: Sets the text of an object. It works for the following objects:

-       Button (including the buttons in the LIST)

-       Checkbox / Radio

-       Label (including the text in the LIST

-       Textarea

-       Scale : set the text of the scale labels (texts separated by ‘,’ )

Arguments:

     obj: Object to set text for.

     str$: Text to set.

Return: Object type.

LVGL Commands: lv_label_set_text(), lv_checkbox_set_text(), lv_textarea_set_text(), lv_scale_set_text_src()


LVGL.SET_TEXT_ALIGN obj, align

Description: Sets the text alignment of an object.

Arguments:

     obj: Object to set text alignment for.

     align: Text alignment value (lv_text_align).

Return: None.

LVGL Command: lv_obj_set_style_text_align()


LVGL.SET_TEXT_COLOR obj, color [, style_selector]

Description: Sets the text color of an object.

Arguments:

     obj: Object to set text color for.

     color: Text color.

     style_selector: Optional state to set text color for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Command: lv_obj_set_style_text_color()


LVGL.SET_TRANSFORM_PIVOT obj, x, y [, style_selector]

Description: Sets the transformation pivot of an object.

Arguments:

     obj: Object to set transformation pivot for.

     x: X pivot value.

     y: Y pivot value.

     style_selector: Optional state to set transformation pivot for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Commands: lv_obj_set_style_transform_pivot_x(), lv_obj_set_style_transform_pivot_y()


LVGL.SET_TRANSFORM_PIVOT_PCT obj, x_pct, y_pct [, style_selector]

Description: Sets the transformation pivot as a percentage for an object.

Arguments:

     obj: Object to set transformation pivot for.

     x_pct: X pivot percentage.

     y_pct: Y pivot percentage.

     style_selector: Optional state to set transformation pivot for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Commands: lv_obj_set_style_transform_pivot_x(), lv_obj_set_style_transform_pivot_y()


LVGL.SET_IMAGE_PIVOT obj, x, y

Description: Set the rotation center of the image.

Arguments:

     obj: Image object to set the rotation center for.

     x: X pivot value.

     y: Y pivot value.

Return: None.

LVGL Commands: lv_image_set_pivot()


LVGL.SET_IMAGE_PIVOT_PCT obj, x_pct, y_pct [

Description: Set the rotation center in percentage of the image.

Arguments:

     obj: Object to set transformation pivot for.

     x_pct: X pivot percentage.

     y_pct: Y pivot percentage.

Return: None.

LVGL Commands: lv_image_set_pivot()


LVGL.SET_TRANSFORM_ROTATION obj, angle [, style_selector]

Description: Sets the transformation angle of an object.

Arguments:

     obj: Object to set transformation angle for.

     angle: Angle value (resolution 0.1°).

     style_selector: Optional state to set transformation angle for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Command: lv_obj_set_style_transform_rotation()


LVGL.SET_TRANSFORM_SCALE obj, x, y [, style_selector]

Description: Sets the transformation scale of an object.

Arguments:

     obj: Object to set transformation scale for.

     x: X scale value.

     y: Y scale value.

     style_selector: Optional state to set transformation scale for. (lv_state_t)  and (lv_part_t)

Return: None.

LVGL Commands: lv_obj_set_style_transform_scale_x(), lv_obj_set_style_transform_scale_y()

Notes: The value 256 (or LV_SCALE_NONE) means normal size, 128 half size, 512 double size, and so on.


LVGL.SET_VALUE obj, val [, anim = 1]

Description: Sets the value of an object. The value can vary depending on the type of the object.

Arguments:

     obj: Object to set value for.

     val: Value to set.

     anim: Optional animation flag (1 for animated, 0 for immediate); defaults to 1

For specific objects:

     Slider: Set the value with the optional animation flag.

     Arc: Set the value.

     Bar: Set the value with the optional animation flag.

     LED:

     0: LED off.

     1: LED on.

     2: LED toggle.

     Other values: Set luminosity (from 3 to 255).

     Roller: Set the selected option with the optional animation flag.

     Dropdown: Set the selected option.

     ImageButton: Set the state.

Return: Object type.

LVGL Commands: lv_slider_set_value(), lv_arc_set_value(), lv_bar_set_value(), lv_led_on(), lv_led_off(), lv_led_toggle(), lv_led_set_brightness(), lv_roller_set_selected(), lv_dropdown_set_selected(), lv_imagebutton_set_state()


LVGL.SET_WIDTH obj, w

Description: Sets the width of an object.

Arguments:

     obj: Object to set width for.

     w: Width.

Return: None.

LVGL Command: lv_obj_set_width()


LVGL.SPRITE.PUSH canvas_obj, sprite_num [, x [, y]]

Description: Push (copy) a sprite object, defined in the TFT library, into a canvas object. If the dimensions of the canvas and the sprite differ, only the overlapping portion (relative size) will be copied. By default, the sprite is copied starting from the top-left corner of the canvas. However, this behavior can be modified using the optional x and y arguments to specify the starting position.
This command allows you to draw graphics (such as lines, circles, etc.) using TFT.xxx functions within sprites and then transfer the resulting image into LVGL.

Arguments:

     canvas_obj: Canvas object where the sprite will be copied

     sprite_num : Sprite object number (from 0 to 9) as defined in the TFT library.

     [x]: Optional X position.

     [y]: Optional Y position.

Return: None.

LVGL Commands: lv_canvas_get_image(),lv_obj_invalidate()


LVGL.SWAP obj, obj_base

Description: Swaps the positions of two objects.

Arguments:

     obj: First object.

     obj_base: Second object.

Return: None.

LVGL Command: lv_obj_swap()


LVGL.VISIBLE obj, vis

Description: Sets the visibility of an object.

Arguments:

     obj: Object to set visibility for.

     vis: Visibility flag (1 for visible, 0 for hidden).

Return: None.

LVGL Command: lv_obj_update_flag()


LVGL.RGB(red, green, blue)

Description: Combines the RGB components into a single value.

Arguments:

     red: Red color component (from 0 to 255).

     green: Green color component (from 0 to 255).

     blue: Blue color component (from 0 to 255).

Return: Combined RGB888 color.

LVGL Command: N/A


LVGL.MOUSE_ENABLE

Description: Creates a mouse pointer object. The mouse pointer is actually a purple arrow. The “mouse” position and status can then be set using the commands LVGL.MOUSEMOVE

Arguments: None.

Return: None.

LVGL Commands: lv_indev_create(), lv_indev_set_type(), lv_indev_set_cursor(), lv_indev_set_read_cb()


LVGL.MOUSEMOVE mouse_x, mouse_y, mouse_z

Description: Sets the position of the “mouse”.

Arguments: None.

     mouse_x: X position of the mouse.

     mouse_y: Y position of the mouse.

     mouse_z: button of the mouse (0 = released, 1 = pressed)

Return: None.

LVGL Command: None.


LVGL.MOUSE_CURSOR

Description: Returns the mouse cursor object. Can be used to hide / show or modify the default mouse pointer.

Arguments: None

Return: Mouse cursor object.

LVGL Command: N/A


LVGL.KEYBOARD_ENABLE

Description: Initializes a keyboard functionality permitting to send keystrokes from an external hardware keyboard to LVGL objects. The keystrokes can be sent using the command LVGL.SET_KEYBOARD_KEY.

Arguments: None.

Return: None.

LVGL Commands: lv_indev_create(), lv_indev_set_type(), lv_indev_set_cursor(), lv_indev_set_read_cb()


LVGL.SET_KEYBOARD_KEY key

Description: Sends a keystroke to the active object.

Arguments:

     key: ASCII code of the key to be sent; 0 means no key pressed.

Return: None.

LVGL Command: None.


LVGL.SET_KEYBOARD_GROUP group

Description: Sets the group of objects that will receive keystrokes sent using the command LVGL.SET_KEYBOARD_KEY. The active object in the group will receive the keystrokes.

Arguments: None.

Return: None.

LVGL Command: lv_indev_set_group()


LVGL.SET_IMAGE_SRC obj, src$

Or

LVGL.SET_IMAGE_SRC obj, ref

Description: Sets the source of an image object (obj) to display either an icon or an image.

Arguments:

     obj: Object to set icon for.

     Src: The source of the image

     If src is a string, it sets

     An icon code (e.g., LV_SYMBOL_OK) or

     A file path to load an external image (e.g., "/:image.bmp").

     P.S. : image loaded in this way are very slow because are loaded dynamically

     If src is a reference (memory address), it sets:

     A pointer to an image descriptor (lv_img_dsc_t) stored in memory, generally shared with another image already loaded and get with LVGL.GET_IMAGE_SRC

Return: None.

LVGL Command: lv_image_set_src()


LVGL.GET_IMAGE_SRC obj

Description: Gets the reference of the  image source (memory address)

Arguments:

     obj: Object to get image source for.

Return: The image source .

LVGL Command: lv_image_get_src()


LVGL.GET_CLASS_NAME$ obj

Description: Returns the class name of an object.

Arguments:

     obj: Object to get class name for.

Return: Class name of the object (string).

LVGL Command: lv_obj_get_class()

Notes: Useful to determine the type of object (same as GET_CLASS_ID but with a text output).


LVGL.GET_TEXT$ obj

Description: Returns the text of an object. Covers the following objects: Button, Checkbox / Radio, Label, Textarea, Keyboard (the key pressed), Roller, Dropdown, ButtonMatrix (the button pressed), and the buttons/text in the LIST.

Arguments:

     obj: Object to get text for (string).

Return: Text of the object.

LVGL Commands: lv_label_get_text(), lv_checkbox_get_text(), lv_textarea_get_text(), lv_roller_get_selected_str(), lv_dropdown_get_selected_str(), lv_keyboard_get_button_text()


 

LVGL Tables

The LVGL library provides a rich and versatile set of predefined enums, states, flags, and modes to manage and customize graphical user interface (GUI) elements. These tables serve as a comprehensive reference for developers, enabling them to understand and utilize the framework's capabilities effectively. Below, all the tables available in LVGL are listed with a brief explanation or introduction for each:

  1. Widget States
    This table summarizes the possible states of a widget, such as LV_STATE_CHECKED or LV_STATE_PRESSED. Each state is represented by a hexadecimal value and can be combined using bitwise operations to represent multiple states simultaneously.
  2. Widget Parts
    Describes the internal components of widgets, such as scrollbars, indicators, knobs, and custom parts. These parts contribute to the widget's appearance and functionality.
  3. Object Flags
    Lists on/off features that control object behavior in the GUI. Flags like LV_OBJ_FLAG_CLICKABLE or LV_OBJ_FLAG_SCROLLABLE determine how objects respond to user interactions and layout management.
  4. Image Button States
    Defines the visual and interactive states of image buttons, such as pressed, released, disabled, or checked.
  5. Alignment Enums
    Specifies alignment options for objects relative to their parent containers or other objects (e.g., LV_ALIGN_CENTER, LV_ALIGN_TOP_LEFT).
  6. Text Alignment Enums
    Defines how text is aligned within its container, offering options like left-aligned (LV_TEXT_ALIGN_LEFT) or center-aligned (LV_TEXT_ALIGN_CENTER).
  7. Direction Enums
    Enumerates possible directions for scrolling or other operations, such as horizontal (LV_DIR_HOR) or vertical (LV_DIR_VER).
  8. Border Side Enums
    Specifies which sides of an object should have borders (e.g., LV_BORDER_SIDE_FULL, LV_BORDER_SIDE_BOTTOM).
  9. Flexbox Layout Options and Enumerations
    Includes flexbox layout options (e.g., LV_FLEX_FLOW_ROW, LV_FLEX_ALIGN_CENTER) for arranging items in flexible and responsive layouts.
  10. Scale Modes
    Describes how scales are displayed in objects like sliders or arcs (e.g., horizontal top-aligned or round outer-aligned).
  11. Label Long Mode Options
    Specifies how labels handle text that exceeds their width, such as wrapping (LV_LABEL_LONG_WRAP) or scrolling circularly (LV_LABEL_LONG_SCROLL_CIRCULAR).
  12. Keyboard Modes and Keys
    Provides modes for keyboard input (e.g., numeric mode: LV_KEYBOARD_MODE_NUMBER) and key enums for navigation (e.g., arrow keys: LV_KEY_UP, LV_KEY_DOWN).
  13. Event Codes
    Lists event codes representing interactions like clicks (LV_EVENT_CLICKED) or presses (LV_EVENT_PRESSED)
  14. Symbol Definitions (unicode from FontAwesome)
    This table lists LVGL's built-in symbols derived from FontAwesome icons, represented as UTF-8 encoded strings for consistent UI elements:

These tables provide developers with structured information to configure widgets, manage object behavior, and implement advanced GUI features in LVGL applications efficiently.


Widget States (lv_state_t)

This table summarizes the possible states of a widget, with each state represented by a hexadecimal value. The states can be combined using bitwise OR operations to represent multiple states simultaneously.

State

Value (Hex)

Description

LV_STATE_DEFAULT

0x0000

Default state.

LV_STATE_CHECKED

0x0001

Widget is checked.

LV_STATE_FOCUSED

0x0002

Widget is focused.

LV_STATE_FOCUS_KEY

0x0004

Widget is focused via keyboard.

LV_STATE_EDITED

0x0008

Widget is being edited.

LV_STATE_HOVERED

0x0010

Widget is hovered over.

LV_STATE_PRESSED

0x0020

Widget is pressed.

LV_STATE_SCROLLED

0x0040

Widget is scrolled.

LV_STATE_DISABLED

0x0080

Widget is disabled.

LV_STATE_USER_1

0x1000

Custom user state 1.

LV_STATE_USER_2

0x2000

Custom user state 2.

LV_STATE_USER_3

0x4000

Custom user state 3.

LV_STATE_USER_4

0x8000

Custom user state 4.

LV_STATE_ANY

0xFFFF

Special value to target all states in some functions.


Widget Parts (lv_part_t)

The following table describes the possible parts of widgets in a graphical user interface (GUI) framework. These parts are the internal building blocks of widgets, such as sliders, buttons, and checkboxes. Each part serves a specific function within the widget, contributing to its overall appearance and behavior.

Part

Value (Hex)

Description

LV_PART_MAIN

0x000000

A background-like rectangle.

LV_PART_SCROLLBAR

0x010000

The scrollbar(s).

LV_PART_INDICATOR

0x020000

Indicator, e.g., for slider, bar, switch, or the tick box of the checkbox.

LV_PART_KNOB

0x030000

Like handle to grab to adjust the value.

LV_PART_SELECTED

0x040000

Indicate the currently selected option or section.

LV_PART_ITEMS

0x050000

Used if the widget has multiple similar elements (e.g., table cells).

LV_PART_CURSOR

0x060000

Mark a specific place, e.g., for text area's cursor or on a chart.

LV_PART_CUSTOM_FIRST

0x080000

Extension point for custom widgets.

LV_PART_ANY

0x0F0000

Special value to target all parts in some functions.

 


 

Object Flags (lv_obj_flag_t)

The following table lists the on/off features that control an object's behavior in a GUI framework. These flags can be combined using bitwise OR operations to enable multiple behaviors simultaneously. They determine how an object responds to user interactions and how it is managed within the layout.

Flag

Value (Hex)

Description

LV_OBJ_FLAG_HIDDEN

0x000001

Make the object hidden.

LV_OBJ_FLAG_CLICKABLE

0x000002

Make the object clickable by the input devices.

LV_OBJ_FLAG_CLICK_FOCUSABLE

0x000004

Add focused state to the object when clicked.

LV_OBJ_FLAG_CHECKABLE

0x000008

Toggle checked state when the object is clicked.

LV_OBJ_FLAG_SCROLLABLE

0x000010

Make the object scrollable.

LV_OBJ_FLAG_SCROLL_ELASTIC

0x000020

Allow scrolling inside but with slower speed.

LV_OBJ_FLAG_SCROLL_MOMENTUM

0x000040

Make the object scroll further when "thrown".

LV_OBJ_FLAG_SCROLL_ONE

0x000080

Allow scrolling only one snappable children.

LV_OBJ_FLAG_SCROLL_CHAIN_HOR

0x000100

Allow propagating the horizontal scroll to a parent.

LV_OBJ_FLAG_SCROLL_CHAIN_VER

0x000200

Allow propagating the vertical scroll to a parent.

LV_OBJ_FLAG_SCROLL_CHAIN

0x000300

Combination of horizontal and vertical scroll chain.

LV_OBJ_FLAG_SCROLL_ON_FOCUS

0x000400

Automatically scroll object to make it visible when focused.

LV_OBJ_FLAG_SCROLL_WITH_ARROW

0x000800

Allow scrolling the focused object with arrow keys.

LV_OBJ_FLAG_SNAPPABLE

0x001000

If scroll snap is enabled on the parent it can snap to this object.

LV_OBJ_FLAG_PRESS_LOCK

0x002000

Keep the object pressed even if the press slid from the object.

LV_OBJ_FLAG_EVENT_BUBBLE

0x004000

Propagate the events to the parent too.

LV_OBJ_FLAG_GESTURE_BUBBLE

0x008000

Propagate the gestures to the parent.

LV_OBJ_FLAG_ADV_HITTEST

0x010000

Allow performing more accurate hit (click) test.

LV_OBJ_FLAG_IGNORE_LAYOUT

0x020000

Make the object not positioned by the layouts.

LV_OBJ_FLAG_FLOATING

0x040000

Do not scroll the object when the parent scrolls and ignore layout.

LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS

0x080000

Send LV_EVENT_DRAW_TASK_ADDED events.

LV_OBJ_FLAG_OVERFLOW_VISIBLE

0x100000

Do not clip the children to the parent's ext draw size.

LV_OBJ_FLAG_FLEX_IN_NEW_TRACK

0x200000

Start a new flex track on this item.

LV_OBJ_FLAG_LAYOUT_1

0x800000

Custom flag, free to use by layouts.

LV_OBJ_FLAG_LAYOUT_2

0x1000000

Custom flag, free to use by layouts.

LV_OBJ_FLAG_WIDGET_1

0x2000000

Custom flag, free to use by widget.

LV_OBJ_FLAG_WIDGET_2

0x4000000

Custom flag, free to use by widget.

LV_OBJ_FLAG_USER_1

0x8000000

Custom flag, free to use by user.

LV_OBJ_FLAG_USER_2

0x10000000

Custom flag, free to use by user.

LV_OBJ_FLAG_USER_3

0x20000000

Custom flag, free to use by user.

LV_OBJ_FLAG_USER_4

0x40000000

Custom flag, free to use by user.

 


Image Button States (lv_imagebutton_state_t)

The following table describes the possible states of an image button in a graphical user interface (GUI) framework. These states define the visual and interactive behavior of the image button, such as whether it is pressed, released, disabled, or checked. Each state can be used to customize the appearance and functionality of the button in different scenarios.

 

State

Value (Hex)

Description

LV_IMAGEBUTTON_STATE_RELEASED

0x00

The button is in its default, unpressed state.

LV_IMAGEBUTTON_STATE_PRESSED

0x01

The button is currently being pressed by the user.

LV_IMAGEBUTTON_STATE_DISABLED

0x02

The button is disabled and does not respond to user interactions.

LV_IMAGEBUTTON_STATE_CHECKED_RELEASED

0x03

The button is checked (toggled on) and in its default, unpressed state.

LV_IMAGEBUTTON_STATE_CHECKED_PRESSED

0x04

The button is checked and currently being pressed by the user.

LV_IMAGEBUTTON_STATE_CHECKED_DISABLED

0x05

The button is checked but disabled, not responding to interactions.

LV_IMAGEBUTTON_STATE_NUM

0x06

Represents the total number of states available for the image button.


LVGL Alignment Enums (lv_align_t)

The following table describes the alignment options available in the LVGL framework. These enums define how objects can be aligned relative to each other or to their parent containers. Each alignment option specifies a particular position or orientation for an object within its layout.

Alignment Option

Value

Description

LV_ALIGN_DEFAULT

0

Default alignment

LV_ALIGN_TOP_LEFT

1

Align to the top-left corner

LV_ALIGN_TOP_MID

2

Align to the top-middle

LV_ALIGN_TOP_RIGHT

3

Align to the top-right corner

LV_ALIGN_BOTTOM_LEFT

4

Align to the bottom-left corner

LV_ALIGN_BOTTOM_MID

5

Align to the bottom-middle

LV_ALIGN_BOTTOM_RIGHT

6

Align to the bottom-right corner

LV_ALIGN_LEFT_MID

7

Align to the middle of the left side

LV_ALIGN_RIGHT_MID

8

Align to the middle of the right side

LV_ALIGN_CENTER

9

Align to the center

LV_ALIGN_OUT_TOP_LEFT

10

Align outside the top-left corner

LV_ALIGN_OUT_TOP_MID

11

Align outside the top-middle

LV_ALIGN_OUT_TOP_RIGHT

12

Align outside the top-right corner

LV_ALIGN_OUT_BOTTOM_LEFT

13

Align outside the bottom-left corner

LV_ALIGN_OUT_BOTTOM_MID

14

Align outside the bottom-middle

LV_ALIGN_OUT_BOTTOM_RIGHT

15

Align outside the bottom-right corner

LV_ALIGN_OUT_LEFT_TOP

16

Align outside the top of the left side

LV_ALIGN_OUT_LEFT_MID

17

Align outside the middle of the left side

LV_ALIGN_OUT_LEFT_BOTTOM

18

Align outside the bottom of the left side

LV_ALIGN_OUT_RIGHT_TOP

19

Align outside the top of the right side

LV_ALIGN_OUT_RIGHT_MID

20

Align outside the middle of the right side

LV_ALIGN_OUT_RIGHT_BOTTOM

21

Align outside the bottom of the right side

 

 


LVGL Text Alignment Enums (lv_text_align_t)

The following table describes the text alignment options available in the LVGL framework. These enums define how text is aligned within its container, allowing for precise control over the text layout and appearance.

Text Alignment Option

Value

Description

LV_TEXT_ALIGN_AUTO

0

Align text automatically

LV_TEXT_ALIGN_LEFT

1

Align text to the left

LV_TEXT_ALIGN_CENTER

2

Align text to the center

LV_TEXT_ALIGN_RIGHT

3

Align text to the right

 

 


 

 

LVGL Direction Enums (lv_dir_t)

The following table describes the direction enums available in the LVGL framework. These enums define the possible directions for scrolling or other directional operations within a graphical user interface.

Enum

Value (Hex)

Description

LV_DIR_NONE

0x00

No direction specified.

LV_DIR_LEFT

0x01

Direction is left.

LV_DIR_RIGHT

0x02

Direction is right.

LV_DIR_TOP

0x04

Direction is top.

LV_DIR_BOTTOM

0x08

Direction is bottom.

LV_DIR_HOR

0x03

Horizontal direction (left or right).

LV_DIR_VER

0x0C

Vertical direction (top or bottom).

LV_DIR_ALL

0x0F

All directions (horizontal and vertical).

 


LVGL Border Side Enums (lv_border_side_t)

The following table describes the border side enums available in the LVGL framework.
These enums define which sides a border should be drawn on. Values can be combined using bitwise OR.

 

Enum

Value (Hex)

Description

LV_BORDER_SIDE_NONE

0x00

No border.

LV_BORDER_SIDE_BOTTOM

0x01

Border on the bottom side.

LV_BORDER_SIDE_TOP

0x02

Border on the top side.

LV_BORDER_SIDE_LEFT

0x04

Border on the left side.

LV_BORDER_SIDE_RIGHT

0x08

Border on the right side.

LV_BORDER_SIDE_FULL

0x0F

Borders on all sides (top, bottom, left, right).

LV_BORDER_SIDE_INTERNAL

0x10

Used for matrix-like objects (e.g., Button matrix).

 


 

Flexbox Layout Options and Enumerations

The following tables describe various flexbox layout options and enumerations in a graphical user interface (GUI) framework. These options and enumerations control the arrangement, alignment, and behavior of elements within a flex container, allowing for flexible and responsive layouts.

Flexbox Layout Options

The following table describes the flexbox layout options available in the LVGL framework. These options define how flex items are arranged within a flex container, providing control over the layout direction, wrapping behavior, and alignment.

Option

Value (Hex)

Description

LV_FLEX_COLUMN

0x01

Arrange the flex items in a column, stacking them vertically.

LV_FLEX_WRAP

0x04

Allow the flex items to wrap onto multiple lines if there isn't enough space.

LV_FLEX_REVERSE

0x08

Reverse the direction of the flex items within the container.

Flex Alignment Options (lv_flex_align_t)

The following table describes the flex alignment options available in the LVGL framework. These options define how flex items are aligned within their container, providing control over the distribution and spacing of items.

Alignment

Value (Hex)

Description

LV_FLEX_ALIGN_START

0x00

Align items to the start of the container.

LV_FLEX_ALIGN_END

0x01

Align items to the end of the container.

LV_FLEX_ALIGN_CENTER

0x02

Center items within the container.

LV_FLEX_ALIGN_SPACE_EVENLY

0x03

Distribute items evenly with equal space around them.

LV_FLEX_ALIGN_SPACE_AROUND

0x04

Distribute items evenly with equal space around the outer edges.

LV_FLEX_ALIGN_SPACE_BETWEEN

0x05

Distribute items evenly with space only between them.

Flex Flow Options (lv_flex_flow_t)

The following table describes the flex flow options available in the LVGL framework. These options define the direction in which flex items are arranged within a flex container, including row and column layouts, as well as wrapping and reversing behaviors.

Flow

Value (Hex)

Description

LV_FLEX_FLOW_ROW

0x00

Arrange items in a row.

LV_FLEX_FLOW_COLUMN

0x01

Arrange items in a column.

LV_FLEX_FLOW_ROW_WRAP

0x04

Arrange items in a row with wrapping.

LV_FLEX_FLOW_ROW_REVERSE

0x08

Arrange items in a reversed row.

LV_FLEX_FLOW_ROW_WRAP_REVERSE

0x0C

Arrange items in a reversed row with wrapping.

LV_FLEX_FLOW_COLUMN_WRAP

0x05

Arrange items in a column with wrapping.

LV_FLEX_FLOW_COLUMN_REVERSE

0x09

Arrange items in a reversed column.

LV_FLEX_FLOW_COLUMN_WRAP_REVERSE

0x0D

Arrange items in a reversed column with wrapping.

 


Scale modes (lv_scale_mode_t)

The following table describes the mode options available for Scale objects in LVGL.

Mode

Value (Hex)

Description

LV_SCALE_MODE_HORIZONTAL_TOP 

0x00

The scale will be horizontal and the labels text aligned to the top.

LV_SCALE_MODE_HORIZONTAL_BOTTOM

 

0x01

The scale will be horizontal and the labels text aligned to the bottom.

LV_SCALE_MODE_VERTICAL_LEFT    

0x02

The scale will be vertical and the labels text aligned to the left.

LV_SCALE_MODE_VERTICAL_RIGHT  

0x04

The scale will be vertical and the labels text aligned to the right.

LV_SCALE_MODE_ROUND_INNER   

0x08

The scale will be round and the labels text aligned to the inner side.

LV_SCALE_MODE_ROUND_OUTER

0x10

The scale will be round and the labels text aligned to the outer side.


Label Long Mode Options (lv_label_long_mode_t)

The following table describes the long mode options available for labels in the LVGL framework. These options define how text that exceeds the label's width is handled, providing various ways to manage and display long text content.

Mode

Value (Hex)

Description

LV_LABEL_LONG_WRAP

0x00

Wrap lines longer than the object width and expand the object height.

LV_LABEL_LONG_DOT

0x01

Write dots at the end if the text is too long.

LV_LABEL_LONG_SCROLL

0x02

Roll the text back and forth.

LV_LABEL_LONG_SCROLL_CIRCULAR

0x03

Roll the text circularly.

LV_LABEL_LONG_CLIP

0x04

Clip the text out of the object's size.


Keyboard Mode Enums (lv_keyboard_mode_t)

The following table describes the keyboard mode enums available in the LVGL framework. These enums define the different modes that a keyboard object can operate in, such as text input, special characters, numeric input, and user-defined modes.

Keyboard Mode

Value

Description

LV_KEYBOARD_MODE_TEXT_LOWER

0

Standard text input mode with lowercase letters.

LV_KEYBOARD_MODE_TEXT_UPPER

1

Text input mode with uppercase letters.

LV_KEYBOARD_MODE_SPECIAL

2

Mode for inputting special characters.

LV_KEYBOARD_MODE_NUMBER

3

Numeric input mode.

LV_KEYBOARD_MODE_USER_1

4

User-defined mode 1.

LV_KEYBOARD_MODE_USER_2

5

User-defined mode 2.

LV_KEYBOARD_MODE_USER_3

6

User-defined mode 3.

LV_KEYBOARD_MODE_USER_4

7

User-defined mode 4.


Keyboard Key Enums (lv_key_t)

The following table describes the keyboard key enums available in the LVGL framework. These enums represent various keys that can be used to control a focused object via the lv_group_send function. Each enum corresponds to a specific key, such as arrow keys, escape, delete, and other functional keys, allowing for navigation and interaction within the graphical user interface.

Enum Value

Value

Description

LV_KEY_UP

17

Up arrow key

LV_KEY_DOWN

18

Down arrow key

LV_KEY_RIGHT

19

Right arrow key

LV_KEY_LEFT

20

Left arrow key

LV_KEY_ESC

27

Escape key

LV_KEY_DEL

127

Delete key

LV_KEY_BACKSPACE

8

Backspace key

LV_KEY_ENTER

10

Enter key

LV_KEY_NEXT

9

Next key (Tab)

LV_KEY_PREV

11

Previous key

LV_KEY_HOME

2

Home key

LV_KEY_END

3

End key


Event Codes (lv_event_code_t)

The following table describes the event codes available in the LVGL framework. These codes represent various events that can occur within the graphical user interface, such as clicks, presses, releases, and other interactions.

Event

Value (Hex)

Description

LV_EVENT_ALL

0x00

Represents all events.

LV_EVENT_PRESSED

0x01

The object has been pressed.

LV_EVENT_PRESSING

0x02

The object is being pressed continuously.

LV_EVENT_PRESS_LOST

0x03

The object is still pressed but the cursor/finger slid off.

LV_EVENT_SHORT_CLICKED

0x04

The object was pressed for a short period and released.

LV_EVENT_LONG_PRESSED

0x05

The object has been pressed for at least long_press_time.

LV_EVENT_LONG_PRESSED_REPEAT

0x06

Called repeatedly after long_press_time.

LV_EVENT_CLICKED

0x07

Called on release if not scrolled.

LV_EVENT_RELEASED

0x08

Called when the object has been released.

LV_EVENT_SCROLL_BEGIN

0x09

Scrolling begins.

LV_EVENT_SCROLL_THROW_BEGIN

0x0A

Scroll throw begins.

LV_EVENT_SCROLL_END

0x0B

Scrolling ends.

LV_EVENT_SCROLL

0x0C

Scrolling is in progress.

LV_EVENT_GESTURE

0x0D

A gesture is detected.

LV_EVENT_KEY

0x0E

A key is sent to the object.

LV_EVENT_ROTARY

0x0F

An encoder or wheel was rotated.

LV_EVENT_FOCUSED

0x10

The object is focused.

LV_EVENT_DEFOCUSED

0x11

The object is defocused.

LV_EVENT_LEAVE

0x12

The object is defocused but still selected.

LV_EVENT_HIT_TEST

0x13

Perform advanced hit-testing.

LV_EVENT_INDEV_RESET

0x14

Input device has been reset.

LV_EVENT_HOVER_OVER

0x15

Input device hover over object.

LV_EVENT_HOVER_LEAVE

0x16

Input device hover leave object.

LV_EVENT_COVER_CHECK

0x17

Check if the object fully covers an area.

LV_EVENT_REFR_EXT_DRAW_SIZE

0x18

Get the required extra draw area around the object.

LV_EVENT_DRAW_MAIN_BEGIN

0x19

Starting the main drawing phase.

LV_EVENT_DRAW_MAIN

0x1A

Perform the main drawing.

LV_EVENT_DRAW_MAIN_END

0x1B

Finishing the main drawing phase.

LV_EVENT_DRAW_POST_BEGIN

0x1C

Starting the post draw phase.

LV_EVENT_DRAW_POST

0x1D

Perform the post draw phase.

LV_EVENT_DRAW_POST_END

0x1E

Finishing the post draw phase.

LV_EVENT_DRAW_TASK_ADDED

0x1F

Adding a draw task.

LV_EVENT_VALUE_CHANGED

0x20

The object's value has changed.

LV_EVENT_INSERT

0x21

A text is inserted to the object.

LV_EVENT_REFRESH

0x22

Notify the object to refresh something.

LV_EVENT_READY

0x23

A process has finished.

LV_EVENT_CANCEL

0x24

A process has been cancelled.

LV_EVENT_CREATE

0x25

Object is being created.

LV_EVENT_DELETE

0x26

Object is being deleted.

LV_EVENT_CHILD_CHANGED

0x27

Child was removed, added, or its size/position changed.

LV_EVENT_CHILD_CREATED

0x28

Child was created.

LV_EVENT_CHILD_DELETED

0x29

Child was deleted.

LV_EVENT_SCREEN_UNLOAD_START

0x2A

A screen unload started.

LV_EVENT_SCREEN_LOAD_START

0x2B

A screen load started.

LV_EVENT_SCREEN_LOADED

0x2C

A screen was loaded.

LV_EVENT_SCREEN_UNLOADED

0x2D

A screen was unloaded.

LV_EVENT_SIZE_CHANGED

0x2E

Object coordinates/size have changed.

LV_EVENT_STYLE_CHANGED

0x2F

Object's style has changed.

LV_EVENT_LAYOUT_CHANGED

0x30

The children position has changed due to a layout recalculation.

LV_EVENT_GET_SELF_SIZE

0x31

Get the internal size of a widget.

LV_EVENT_INVALIDATE_AREA

0x32

Invalidate an area.

LV_EVENT_RESOLUTION_CHANGED

0x33

Resolution has changed.

LV_EVENT_COLOR_FORMAT_CHANGED

0x34

Color format has changed.

LV_EVENT_REFR_REQUEST

0x35

Refresh request.

LV_EVENT_REFR_START

0x36

Refresh start.

LV_EVENT_REFR_READY

0x37

Refresh ready.

LV_EVENT_RENDER_START

0x38

Render start.

LV_EVENT_RENDER_READY

0x39

Render ready.

LV_EVENT_FLUSH_START

0x3A

Flush start.

LV_EVENT_FLUSH_FINISH

0x3B

Flush finish.

LV_EVENT_FLUSH_WAIT_START

0x3C

Flush wait start.

LV_EVENT_FLUSH_WAIT_FINISH

0x3D

Flush wait finish.

LV_EVENT_VSYNC

0x3E

Vertical sync event.

LV_EVENT_LAST

0x3F

Number of default events.

LV_EVENT_PREPROCESS

0x8000

Process event before the class default event processing.

 


Symbol Definitions (unicode from FontAwesome)

This table lists LVGL's built-in symbols derived from FontAwesome icons, represented as UTF-8 encoded strings for consistent UI elements:

Symbol

Unicode Sequence

Icon

LV_SYMBOL_AUDIO

"\xEF\x80\x81"

music

LV_SYMBOL_VIDEO

"\xEF\x80\x88"

film

LV_SYMBOL_LIST

"\xEF\x80\x8B"

list-alt

LV_SYMBOL_OK

"\xEF\x80\x8C"

check

LV_SYMBOL_CLOSE

"\xEF\x80\x8D"

times

LV_SYMBOL_POWER

"\xEF\x80\x91"

power-off

LV_SYMBOL_SETTINGS

"\xEF\x80\x93"

cog

LV_SYMBOL_HOME

"\xEF\x80\x95"

home

LV_SYMBOL_DOWNLOAD

"\xEF\x80\x99"

download

LV_SYMBOL_DRIVE

"\xEF\x80\x9C"

inbox

LV_SYMBOL_REFRESH

"\xEF\x80\xA1"

sync

LV_SYMBOL_MUTE

"\xEF\x80\xA6"

volume-off

LV_SYMBOL_VOLUME_MID

"\xEF\x80\xA7"

volume-down

LV_SYMBOL_VOLUME_MAX

"\xEF\x80\xA8"

volume-up

LV_SYMBOL_IMAGE

"\xEF\x80\xBE"

image

LV_SYMBOL_TINT

"\xEF\x81\x83"

tint

LV_SYMBOL_PREV

"\xEF\x81\x88"

step-backward

LV_SYMBOL_PLAY

"\xEF\x81\x8B"

play

LV_SYMBOL_PAUSE

"\xEF\x81\x8C"

pause

LV_SYMBOL_STOP

"\xEF\x81\x8D"

stop

LV_SYMBOL_NEXT

"\xEF\x81\x91"

step-forward

LV_SYMBOL_EJECT

"\xEF\x81\x92"

eject

LV_SYMBOL_LEFT

"\xEF\x81\x93"

angle-left

LV_SYMBOL_RIGHT

"\xEF\x81\x94"

angle-right

LV_SYMBOL_PLUS

"\xEF\x81\xA7"

plus

LV_SYMBOL_MINUS

"\xEF\x81\xA8"

minus

LV_SYMBOL_EYE_OPEN

"\xEF\x81\xAE"

eye

LV_SYMBOL_EYE_CLOSE

"\xEF\x81\xB0"

eye-slash

LV_SYMBOL_WARNING

"\xEF\x81\xB1"

exclamation-triangle

LV_SYMBOL_SHUFFLE

"\xEF\x81\xB4"

random

LV_SYMBOL_UP

"\xEF\x81\xB7"

angle-up

LV_SYMBOL_DOWN

"\xEF\x81\xB8"

angle-down

LV_SYMBOL_LOOP

"\xEF\x81\xB9"

retweet

LV_SYMBOL_DIRECTORY

"\xEF\x81\xBB"

folder

LV_SYMBOL_UPLOAD

"\xEF\x82\x93"

upload

LV_SYMBOL_CALL

"\xEF\x82\x95"

phone-alt

LV_SYMBOL_CUT

"\xEF\x83\x84"

cut

LV_SYMBOL_COPY

"\xEF\x83\x85"

copy

LV_SYMBOL_SAVE

"\xEF\x83\x87"

save

LV_SYMBOL_BARS

"\xEF\x83\x89"

bars

LV_SYMBOL_ENVELOPE

"\xEF\x83\xA0"

envelope

LV_SYMBOL_CHARGE

"\xEF\x83\xA7"

bolt

LV_SYMBOL_PASTE

"\xEF\x83\xAA"

copy

LV_SYMBOL_BELL

"\xEF\x83\xB3"

bell

LV_SYMBOL_KEYBOARD

"\xEF\x84\x9C"

keyboard

LV_SYMBOL_GPS

"\xEF\x84\xA4"

location-arrow

LV_SYMBOL_FILE

"\xEF\x85\x9B"

file

LV_SYMBOL_WIFI

"\xEF\x87\xAB"

wifi

LV_SYMBOL_BATTERY_FULL

"\xEF\x89\x80"

battery-full

LV_SYMBOL_BATTERY_3

"\xEF\x89\x81"

battery-three-quarters

LV_SYMBOL_BATTERY_2

"\xEF\x89\x82"

battery-half

LV_SYMBOL_BATTERY_1

"\xEF\x89\x83"

battery-quarter

LV_SYMBOL_BATTERY_EMPTY

"\xEF\x89\x84"

battery-empty

LV_SYMBOL_USB

"\xEF\x8A\x87"

usb

LV_SYMBOL_BLUETOOTH

"\xEF\x8A\x93"

bluetooth

LV_SYMBOL_TRASH

"\xEF\x8B\xAD"

trash-alt

LV_SYMBOL_EDIT

"\xEF\x8C\x84"

pencil-alt

LV_SYMBOL_BACKSPACE

"\xEF\x95\x9A"

backspace

LV_SYMBOL_SD_CARD

"\xEF\x9F\x82"

sd-card

LV_SYMBOL_NEW_LINE

"\xEF\xA2\xA2"

level-down-alt

LV_SYMBOL_DUMMY

"\xEF\xA3\xBF"

 

 

 

 

 

 

 

 

 

 

 

USB HID INTERFACE (Mouse, Keyboard, Gamepad) - ESP32-S3 only

 

It is possible to connect USB devices, the ESP32-S3 acting as an HOST controller.

The USB device must be connected using the default USB pins (GPIO19 D- , GPIO20 D+).

Only one device can be connected on the port (the USB hubs don’t work) but is possible to use combined devices such as mixed mouse / keyboard remote controller using a wireless dongle, such as the devices shown below::

image

 

image

image

 

It is possible to connect directly the USB device to the module, using an USB type C adapter and shorting the jumpers IN-OUT and USB-OTG on the ESP32-S3 modules like shown in the images below:

 

image

 

image

 

How use the USB devices

USB.SETUP Command

The primary command for using USB devices is USB.SETUP WIDTH, HEIGHT

This command defines the screen size, establishing the position limits for the mouse.

For instance, to set up for a VGA display with a resolution of 640x480, the command would be:

 

USB.SETUP 640, 480

 

This setup enables the use of various USB input devices such as a mouse, keyboard, or gamepad.

 

Mouse Input

When a mouse is connected, the system automatically generates and activates the following variables:

     mouseX: Current X-coordinate of the mouse cursor.

     mouseY: Current Y-coordinate of the mouse cursor.

     mouseZ: Represents mouse buttons.

     mouseW: Represents the mouse wheel.

 

Keyboard Input

For a connected keyboard, the following variable is automatically generated and active:

     Kbdcode: Contains the code of the last key pressed.

 

Gamepad Input

When a gamepad is connected, the system generates and activates the following array of variables:

     gamepadcodes(8): An array of 8 elements containing the codes of the gamepad.

 

Associated Events

There are four events associated with these USB devices:

 

1.    onMouseMove : Triggered when the mouse moves.
2.    onMouseClick: Triggered when a mouse button is clicked.
3.    onKeyboard: Triggered when a key is pressed on the keyboard.
4.    onGamePad: Triggered when there is a change in the gamepad state.

 

Handling Events

Inside these events, it is possible to access the content of the variables when changes occur.

The example below demonstrates all the events available:

 

USB.Setup 640, 480

onMouseMove Mouse_Move

onMouseClick Mouse_Click

onKeyboard Keyboard_Press

onGamePad Gamepad_Change

wait

 

Mouse_Move:

print "mouse move", mouseX, mouseY, mouseZ

return

 

Mouse_Click:

print "mouse click", mouseX, mouseY, mouseZ

return

 

Keyboard_Press:

print "keyboard", kbdcode

return

 

Gamepad_Change:

print "Gamepad", gamepadcodes(1), gamepadcodes(2), gamepadcodes(3), gamepadcodes(4), gamepadcodes(5), gamepadcodes(6)

return

 

 

USB HID Mouse / Keyboard Emulation - ESP32-S3 only

Introduction

Annex implements support for commands to emulate a USB mouse or keyboard using an ESP32-S3.

This functionality allows controlling a PC by simulating a user interacting with the mouse and keyboard, either through scripts written in Annex or via WiFi.

The USB device must be connected using the default USB pins (GPIO19 D-, GPIO20 D+), which are generally accessible through the USB connector labeled 'USB'—not the 'COM' connector, as that is typically linked to a USB-to-serial converter chip.

Commands

USB.START [keymap$]

         Description: Initializes the USB system and keyboard emulation. Optionally sets a custom key mapping.

         Arguments:

         keymap$: A string containing hex values for custom key mappings.
If omitted, the default EN_US keyboard mapping is used.

         Note:

         This command must be executed before using other commands.
It can be reused to change keyboard mappings.

         By running this command, you should hear the classic sound in Windows when USB devices are recognized. This sound indicates that the system has successfully detected the connected devices.


USB.TYPETEXT text$

         Description: Simulates typing a string of text.

         Arguments:

         text$: The string to be typed.

         Note:

         If the text “typed” is not correct, this likely means that you need to set up the keymap for your specific keyboard language. In this case, run the command USB.START with the keymap corresponding to your local keyboard layout.


USB.KEYPRESS keycode

         Description: Simulates pressing and holding a specific key.

         Arguments:

         keycode: The numerical value representing the key code.

         Note:

         Take care that you can easily lose control of the PC with this command as the key will remain pressed until the command USB.KEYRELEASE is executed. This can result in your screen being filled with repeated characters from the key that is pressed.


USB.KEYRELEASE keycode

         Description: Simulates releasing a specific key.

         Arguments:

         keycode: The numerical value representing the key code.


USB.KEYRELEASEALL

         Description: Simulates releasing all currently pressed keys.

         Arguments: None.


USB.MOUSEMOVE width, height, [wheel [, pan]]

         Description: Simulates moving the mouse cursor by specified distances with optional scrolling and panning.

         Arguments:

         width: Horizontal movement (-127 to 127).

         height: Vertical movement (-127 to 127).

         wheel (optional): Wheel movement (scrolling). Defaults to zero if not provided.

         pan (optional): Panning movement. Defaults to zero if not provided.


USB.MOUSECLICK button

         Description: Simulates clicking a mouse button.

         Arguments:

         button: The numerical value representing the mouse button.


USB.MOUSEPRESS button

         Description: Simulates pressing and holding a mouse button.

         Arguments:

         button: The numerical value representing the mouse button.


USB.MOUSERELEASE button

         Description: Simulates releasing a mouse button.

         Arguments:

         button: The numerical value representing the mouse button.


Example of Mouse / Keyboard actions:

USB.START

pause 1000

px = 200 : py = 0

for z = 0 to 2*pi+0.001 step pi/360

  x = cos(z) * 200

  y = sin(z) * 200

  USB.MOUSEMOVE x-px, y-py

  px = x : py = y

  pause 1

next z

 

for z = 1 to 16

  USB.TYPETEXT chr$(&hB3) ' TAB

  pause 100

next z

pause 500

 

USB.TYPETEXT chr$(&hB0) ' ENTER

 

USB.TYPETEXT "This is a Text typed directly by Annex into another TAB " + str$(rnd())

 

By default, the keyboard is set to EN-US. It can be changed by specifying the keymap in the USB.START function.

For example, to set the keyboard to Italian

IT_IT$ = "00000000000000002A2B280000000000000000000000000000000000000000002C9E9F74A1A2A32DA5A6B030363837A4271E1F20212223242526B7B632A7B2AD738485868788898A8B8C8D8E8F909192939495969798999A9B9C9D6F3570AEB8000405060708090A0B0C0D0E0F101112131415161718191A1B1C1D00B5000000"

USB.START IT_IT$

 

Mouse Button Definitions

Button

Description

Value

MOUSE_LEFT

Left mouse button

1

MOUSE_RIGHT

Right mouse button

2

MOUSE_MIDDLE

Middle mouse button (scroll wheel)

4

MOUSE_BACKWARD

Backward navigation button

8

MOUSE_FORWARD

Forward navigation button

16

MOUSE_ALL

All mouse buttons pressed simultaneously

31

 

Keycode Definitions

Key

Description

Value

KEY_LEFT_CTRL

Left control key

&h80

KEY_LEFT_SHIFT

Left shift key

&h81

KEY_LEFT_ALT

Left alt key

&h82

KEY_LEFT_GUI

Left GUI key (Windows/Command)

&h83

KEY_RIGHT_CTRL

Right control key

&h84

KEY_RIGHT_SHIFT

Right shift key

&h85

KEY_RIGHT_ALT

Right alt key

&h86

KEY_RIGHT_GUI

Right GUI key (Windows/Command)

&h87

KEY_UP_ARROW

Up arrow key

&hDA

KEY_DOWN_ARROW

Down arrow key

&hD9

KEY_LEFT_ARROW

Left arrow key

&hD8

KEY_RIGHT_ARROW

Right arrow key

&hD7

KEY_BACKSPACE

Backspace key

&hB2

KEY_TAB

Tab key

&hB3

KEY_RETURN

Return key

&hB0

KEY_ESC

Escape key

&hB1

KEY_INSERT

Insert key

&hD1

KEY_DELETE

Delete key

&hD4

KEY_PAGE_UP

Page up key

&hD3

KEY_PAGE_DOWN

Page down key

&hD6

KEY_HOME

Home key

&hD2

KEY_END

End key

&hD5

KEY_CAPS_LOCK

Caps lock key

&hC1

KEY_F1

F1 key

&hC2

KEY_F2

F2 key

&hC3

KEY_F3

F3 key

&hC4

KEY_F4

F4 key

&hC5

KEY_F5

F5 key

&hC6

KEY_F6

F6 key

&hC7

KEY_F7

F7 key

&hC8

KEY_F8

F8 key

&hC9

KEY_F9

F9 key

&hCA

KEY_F10

F10 key

&hCB

KEY_F11

F11 key

&hCC

KEY_F12

F12 key

&hCD

 

Keymaps for regional keyboards

 

EN_US$ = "00000000000000002A2B280000000000000000000000000000000000000000002C9EB4A0A1A2A434A6A7A5AE362D3738271E1F20212223242526B333B62EB7B89F8485868788898A8B8C8D8E8F909192939495969798999A9B9C9D2F3130A3AD350405060708090A0B0C0D0E0F101112131415161718191A1B1C1DAFB1B0B500"

FR_FR$ = "00000000000000002A2B280000000000000000000000000000000000000000002C38206030B41E21222D31AE1023B6B7A79E9FA0A1A2A3A4A5A63736322EB290679485868788898A8B8C8D8E8FB39192938495969798999D9B9C9A62656D6625641405060708090A0B0C0D0E0F331112130415161718191D1B1C1A61636E5F00"

IT_IT$ = "00000000000000002A2B280000000000000000000000000000000000000000002C9E9F74A1A2A32DA5A6B030363837A4271E1F20212223242526B7B632A7B2AD738485868788898A8B8C8D8E8F909192939495969798999A9B9C9D6F3570AEB8000405060708090A0B0C0D0E0F101112131415161718191A1B1C1D00B5000000"

DE_DE$ = "00000000000000002A2B280000000000000000000000000000000000000000002C9E9F31A1A2A3B1A5A6B030363837A4271E1F20212223242526B7B632A7B2AD548485868788898A8B8C8D8E8F909192939495969798999A9B9D9C656D6600B8000405060708090A0B0C0D0E0F101112131415161718191A1B1D1C6472677000"

ES_ES$ = "00000000000000002A2B280000000000000000000000000000000000000000002C9E9F74A1A2A32DA5A6B030363837A4271E1F20212223242526B7B632A7B2AD738485868788898A8B8C8D8E8F909192939495969798999A9B9C9D6F3570AEB8000405060708090A0B0C0D0E0F101112131415161718191A1B1C1D00B5000000"

PT_BR$ = "00000000000000002A2B280000000000000000000000000000000000000000002C9E9F20A1A2A3B1A5A6B030363837A4271E1F20212223242526B7B632A7B2AD548485868788898A8B8C8D8E8F909192939495969798999A9B9D9C656D6600B8000405060708090A0B0C0D0E0F101112131415161718191A1B1D1C6472677000"

PT_PT$ = "00000000000000002A2B280000000000000000000000000000000000000000002C9E9FA0A1A2A32DA5A6AF2F363837A4271E1F20212223242526B7B632A7B2AD5F8485868788898A8B8C8D8E8F909192939495969798999A9B9C9D65356600B8000405060708090A0B0C0D0E0F101112131415161718191A1B1C1D64B5670000"

SV_SE$ = "00000000000000002A2B280000000000000000000000000000000000000000002C9E9FA061A2A331A5A6B12D363837A4271E1F20212223242526B7B632A7B2AD5F8485868788898A8B8C8D8E8F909192939495969798999A9B9C9D656D6600B8000405060708090A0B0C0D0E0F101112131415161718191A1B1C1D6472670000"

DA_DK$ = "00000000000000002A2B280000000000000000000000000000000000000000002C9E9FA061A2A331A5A6B12D363837A4271E1F20212223242526B7B632A7B2AD5F8485868788898A8B8C8D8E8F909192939495969798999A9B9C9D65726600B8000405060708090A0B0C0D0E0F101112131415161718191A1B1C1D646E670000"

HU_HU$ = "00000000000000002A2B280000000000000000000000000000000000000000002CA19F5B73A2469EA5A678A0363837A3351E1F20212223242526B77672A45DB6598485868788898A8B8C8D8E8F909192939495969798999A9B9D9C49544A60B8640405060708090A0B0C0D0E0F101112131415161718191A1B1D1C455A515E00"

 

 

 

INFRARED INTERFACE

An infrared receiver can be connected to the module permitting to decode messages received from RC remote controllers.

It is also possible to connect an IR led permitting to generate RC codes from the module.

 

This picture shows a kit containing an IR receiver, an IR LED and a controller available on ebay at around 1€.

image

 

 

The following drawing shows an example of connection using the pins GPIO12 and GPIO13:

 

 

image

image

Details of wiring for the VS1838B

 

 

There are several commands associated with the IR functions :

IR.INIT, IR.GET$, IR.SEND and ONINFRARED.

 

In order to use the Infrared functions, the first command to use is IR.INIT.

This command defines the pins to be used for the IR receiver and the IR transmitter.

As per the wiring given above, the command must be:

IR.INIT 13, 12

 

The command ONINFRARED defines the label where the program will jump when a code is received by the Infrared receiver. Then, using the function IR.GET$ it will be possible to retrieve the code of the message received:

 Example

IR.INIT 13, 12

ONINFRARED irReceived

Wait

 

irReceived:

PRINT IR.GET$

RETURN

 

The transmission can be done using the command IR.SEND:

The format is IR.SEND format, code$, bits

 

Example for a NEC code:

IR.SEND 3, "20DF40BF", 32

 

The following formats are supported for the reception and the transmission :

VALUE

FORMAT

-1

UNKNOWN

0

UNUSED

1

RC5

2

RC6

3

NEC

4

SONY

5

PANASONIC

6

JVC

7

SAMSUNG

 

This is an example working with the RC controller shown in the picture above.

It shows the status of the button 1 to 8 pressed on the web page and can control 8 leds wired to a PCF8574 using the I2C bus :

 

oninfrared irReceived

onHtmlReload mypage

l1 = 0: l2 = 0: l3=0: l4=0: l5=0: l6=0: l7=0: l8=0

ir.init 13

i2c.setup 21, 22

l = 0

PCF8574_write l

 

gosub mypage

wait

 

irReceived:

print ir.get$, ir.get$(1), ir.get$(2), val("&h" + ir.get$(3)), ir.get$(4), ir.get$(5)

code_type = val(ir.get$(1))

address = val(ir.get$(2))

cmd = val("&h" + ir.get$(3))

' if NEC CODE

if code_type = 3 then

  ' if RC address is 0

  if address = 0 then

     if cmd = 22 then l = l xor 1

     if cmd = 25 then l = l xor 2

     if cmd = 13 then l = l xor 4

     if cmd = 12 then l = l xor 8

     if cmd = 24 then l = l xor 16

     if cmd = 94 then l = l xor 32

     if cmd =then l = l xor 64

     if cmd = 28 then l = l xor 128   

     PCF8574_write l

     setleds l

  end if

end if

return

 

mypage:

cls

a$ = ""

a$ = a$ + |<h1> TEST OF IR REMOTE CONTROLLER COUPLED<br>|

a$ = a$ + | WITH AN I2C PCF8574 AND 8 LEDS</h1>|

a$ = a$ + led$(l1) + led$(l2) + led$(l3) + led$(l4) + led$(l5) + led$(l6) + led$(l7) + led$(l8)

html a$

return

 

sub setleds(x)

  ' set the status for the leds

  l1 = (x and 1)

  l2 = (x and 2)

  l3 = (x and 4)

  l4 = (x and 8)

  l5 = (x and 16)

  l6 = (x and 32)

  l7 = (x and 64)

  l8 = (x and 128)    

  refresh

end sub

 

sub PCF8574_write(x)

  i2c.begin 32 'PCF8574

  i2c.write x

     i2c.end

end sub

 

ULTRASONIC DISTANCE SENSOR HC-SR04

An Ultrasonic distance sensor HC-SR04 can be connected to the module.

This sensor permits to measure the distance from a target positioned in front in a range going from a minimum of 3 cm to a maximum of 3 meters.

image

For the connection, it requires 2 pins plus the power supply. (5 Volts).

 

image

 

The only function is DISTANCE(pin_trig, pin_echo) which returns the distance from the target in cm.

 

Example:

' Measure the distance from the target 2 times / second

print "DISTANCE MEASUREMENT"

for i = 0 to 1000

  print str$(DISTANCE(15,12), "%4f") + "cm"

  pause 500

next i

end

 

 

DHT xx Temperature / Humidity Sensors

A Temperature / Humidity sensor of the DHTxx family can be connected.

The picture below shows the ones that are currently supported.

image

 

These sensors requires a single wire connection like shown below:

 

image

 

To use them is very simple.

First initialise the sensor with the command DHT.SETUP pin, model

The pin can be any available pin of the device, and model can be 11, 21 or 22 (for DHT11, DHT21 or DHT22).

Assuming that we are using the DHT22 on the pin GPIO2,  the command must be :

 

DHT.SETUP 2, 22

 

Then 3 functions are available :

DHT.TEMP

DHT.HUM

DHT.HEATINDEX

 

The first returns the value of the temperature in °C

The 2nd returns the value of the Humidity in %

The 3rd returns the value of the heat index in °C

.

Example

DHT.SETUP 2 ,22

Print "The Temperature is "; DHT.TEMP ; "°C"

Print "The Humidity is "; DHT.HUM ; "%"

Print "The Heat Index is "; DHT.HEATINDEX ; "°C"

 

 

 

 

DS18B20 Temperature Sensors

One or several  DS18B20 Temperature sensors can be connected.

The picture below shows the ones that are currently supported.

image

These Dallas 1-wire sensors use a single wire connection as shown below, allowing multiple sensors to be connected in parallel on the same 1-wire bus from a single gpio pin.

 

image

 

There is just one function available :

TEMPR$(pin_number, [ID], [resolution])

 

This function will return the temperature or the ID of the device depending on the parameter ‘ID’ specified.

In the schematic above, to read the 3 temperatures, the example code is :

Print "The Temperature 1 is ";TEMPR$(2, 1) ; "°C"

Print "The Temperature 2 is ";TEMPR$(2, 2) ; "°C"

Print "The Temperature 3 is ";TEMPR$(2, 3) ; "°C"

 

The ‘pin number’ is any available pin of the device; it can change between calls permitting to use several pins at the same time.

The ID can be a number, a String, or not specified:

- If is a number (say 'n'), the result will be the temperature (in °C) of the nth device connected on that pin

- If is a string, it must contains the Hex address of the device requested; this address can be recovered using the command without this argument

- If not specified, the result will be the address list of the devices connected on the pin (blocks of 8 bytes separated by ',')

 

Example using 2 DS18B20 connected on the pin 12 :

Print TEMPR$(12, 1) ' will print 20.5

Print TEMPR$(12, 2) ' will print 22.3

Print TEMPR$(12) ' will print 28ff5bdb701604f0,28ff5bdb7016045

Print TEMPR$("28ff5bdb701604f0") ' will print 20.5

 

Additionally, the parameter ‘resolution’ can be provided (from 9 to 12 bits).

The resolution determine the minimal increment of temperature and also the conversion time (see table below)

BITS

Resolution °C

Conversion Time (msec)

9

0.5

94

10

0.25

188

11

0.125

375

12

0.0625

750

If the resolution is not specified, it defaults to 12 as before.

The sensors can also be read in async mode:

 

Giving 0 as ID, starts the conversion on all the DS18B20 sensors connected without waiting for the answer

 

For example

ret$ = TEMPR$(2, 0) ' starts an async read on the pin 2

 

The result will be the string "START"

 

Then, it will be possible to read the devices as below

 

ret1$ = TEMPR$(2, 1) 'read the 1st sensor on the pin 2

ret2$ = TEMPR$(2, 2) 'read the 2nd sensor on the pin 2

 

In this case, if the value is not yet available (during the conversion time) the result will be "WAIT' that will be replaced by the good value at the end of the conversion.

 

To restart another conversion, the same command must be executed

ret$ = TEMPR$(2, 0) ' starts an async read on the pin 2

 

BNO055 Absolute Orientation Sensor

A BNO055 Absolute Orientation Sensor can be connected to the module using I2C interface.

This sensor contains 3 accelerometers, 3 gyros and 3 magnetometers BUT also contains an integrated 32 bits controller running Bosch Sensortec sensor fusion software.

This permits unloading the module from all the calculations related to the implementation of a Fusion algorithm.

 

image

This component is quite expensive ( ~10 €) compared to the classic MPU6050, MPU9250, ... but the quality of the internal fusion algo permits to use it without any effort.

Before connecting it, the links S0 and S1 must be soldered with the ‘-’ position as shown in the picture, to enable I2C.

 

The connection is very simple, just 2 pins for the I2C bus and the power supply are required.

The module is already provided with on-board pull-up resistors, so external pull-up resistors are not required.

 

 

 

image

Available instructions are :

BNO055.SETUP(address)
BNO055.HEADING
BNO055.PITCH
BNO055.ROLL
BNO055.VECTOR ( param )
BNO055.CALIB [(param)]

 

The use of the BNO055 module is very simple.

First the I2C must be initialised with the command I2C.SETUP.

Then the module must be initialised with the function BNO055.SETUP(address).

‘address’ must be &h28 if the pin ‘I2C’ is connected to GND or &h29 if connected to VCC.

This function returns 1 if the module has been initialised properly otherwise it returns 0.

After the initialisation, the euler angles can be simply read using the corresponding functions BNO055.HEADING, BNO055.PITCH and BNO055.ROLL

Another useful function is BNO055.CALIB [(param)] which returns the calibration status of the BNO055 internal sensors.

If used without any parameters it returns 1 when all the internal sensors are calibrated, otherwise it returns 0.

The BNO055 is put in auto calibration mode so it will calibrate by itself in the background.

Refer to the following link for more information : BNO055 Calibration

 

Example

I2C.SETUP 21, 22  ' set I2C port on pins 21 and 22
if bno055.setup(&h28) = 0 then
  print "BNO module not found"
  end
end if

for z = 1 to 1000
  print "Pitch:", bno055.pitch
  print "Roll:", bno055.roll

  print "Heading:", bno055.heading

  print "Calibrated:", bno055.calib

  pause 100
next z

end

 

BME280 Combined humidity and pressure sensor

A BME280 Sensor can be connected to the module using the I2C interface.

The BME280 combines individual high linearity, high accuracy sensors for pressure, humidity and temperature.

The cheaper BMP280 could be used instead, but it doesn’t contain a humidity sensor.

 

imageimage

 

The connection is very simple, just 2 pins for the I2C bus and the power supply are required.

The module is already provided with on-board pull-up resistors, so external pull-up resistors are not required.

 

 

 

 

 

 

 

 

image

Available instructions are :

BME280.SETUP(address)
BME280.ALT(qnh)
BME280.HUM
BME280.QFE
BME280.QNH(altitude)
BME280.TEMP


The use of the BME280 module is very simple.

First the I2C must be initialised with the command I2C.SETUP.

Then the module must be initialised with the function BME280.SETUP(address).

‘address’ must be &h76 if the pin ‘SDO’ is connected to GND or &h77 if connected to VCC.

This function returns 1 if the module has been initialised properly, otherwise it returns 0.

After the initialisation, the temperature, pressure and humidity can be simply read using the corresponding functions BME280.TEMP, BME280.QFE and BME280.HUM.

The function BME280.ALT(qnh) returns the altitude information but requires, as a parameter, the pressure at sea level.

At the opposite, the function BME280.QNH(altitude) returns the sea level pressure but requires, as a parameter, the current altitude.

Example

I2C.SETUP 21, 22  ' set I2C port on pins 21 and 22

if bme280.setup(&h76) = 0 then print "BME280 not found" : end

for z = 1 to 1000
  print "Temperature", bme280.temp
  print "Humidity", bme280.hum
  print "Pressure", bme280.qfe
  qnh = bme280.qnh(150) ' assume the altitude at 150 meters
  print "Qnh     ", qnh
  print "Altitude", bme280.alt(1019) ' assume a sea level pressure at 1019 Hpa
  pause 100
next z

 

 

BME680 Combined gas, pressure, temperature & humidity sensor

The BME680 is an integrated environmental sensor that combines gas, humidity, pressure, and temperature measurements. This sensor can be connected to the module using the I2C interface and now utilises the BSEC (Bosch Sensortec Environmental Cluster) library for advanced features and improved accuracy.

 

image        image

The connection is very simple, just 2 pins for the I2C bus and the power supply are required.

The module is already provided with on-board pull-up resistors, so external pull-up resistors are not required.

 

image

 

The use of the BME680 module with the BSEC library is straightforward:

  1. Initialise the I2C bus using the I2C.SETUP command.
  2. Initialise the BME680 sensor with BME680.BEGIN(address):

         Use &h76 if SDO is connected to GND

         Use &h77 if SDO is connected to VCC or left floating

         This function returns 0 if successful, otherwise it returns an error code

  1. Configure the sensor using BME680.SETUP(rate, filename):

         Set the sampling rate and optionally load a BSEC configuration file

  1. After initialization, you can read various parameters:

         Temperature: BME680.TEMP

         Pressure: BME680.PRESS

         Humidity: BME680.HUM

         Gas resistance: BME680.GAS_RES

         Indoor Air Quality (IAQ): BME680.IAQ

         CO2 equivalent: BME680.CO2

         Breath VOC equivalent: BME680.BREATH_VOC

  1. Use BME680.RUN() to update the sensor readings. It returns 1 if new data is available.

Additional functions like BME680.SAVE_STATE() and BME680.LOAD_STATE() are available for managing the sensor's state, and BME680.SET_OFFSET() for temperature calibration.

BSEC Configuration Files
These are files that contain pre-configured settings for the BSEC algorithm, optimised for different use cases. They are typically provided by Bosch Sensortec as text files containing CSV data.

 

Common configurations include:

         Generic_18v_3s_4d

         Generic_18v_300s_4d

         Generic_18v_300s_28d

         Generic_33v_3s_4d

         Generic_33v_300s_4d

         Generic_33v_300s_28d

 

The naming convention typically indicates:

         Voltage (1.8V or 3.3V)

         Sampling period (3s or 300s)

         Run-in time (4 days or 28 days)

These configuration files are usually distributed with the BSEC library and can be downloaded from Bosch Sensortec's official resources. https://github.com/boschsensortec/BSEC-Arduino-library/tree/master/src/config

 

FUNCTIONS / COMMANDS

DESCRIPTION

BME680.BEGIN(address)

Initialise the sensor connected using I2C. 'address' must be &h76 if the pin 'SDO' is connected to GND or &h77 if connected to VCC. Returns 0 if the BME680 sensor has been found, otherwise returns an error code

BME680.SETUP(rate, filename)

Configure the sensor and load BSEC configuration if provided. 'rate' is the sampling rate in seconds, 'filename' is the path to a CSV file containing a BSEC configuration.

Typical rates are

0.0033333 for ULP

0.3333333 for LP (recommended)

1 for CONTINUOUS

BME680.SAVE_STATE(filename)

Save the current BSEC state to a file. 'filename' is the path to save the state CSV file

BME680.LOAD_STATE(filename)

Load a previously saved BSEC state from a file. 'filename' is the path to the state CSV file to load

BME680.SET_OFFSET(offset)

Sets the temperature offset for more accurate readings. 'offset' is the temperature offset in °C

BME680.RUN

Run the BSEC algorithm to update sensor readings. Returns 1 if new data is available, 0 otherwise

BME680.TEMP

Returns the Temperature parameter from the sensor in °C

BME680.RAW_TEMP

Returns the raw temperature reading

BME680.HUM

Returns the Humidity parameter from the sensor in %

BME680.RAW_HUM

Returns the raw humidity reading

BME680.PRESS

Returns the Barometric Pressure parameter from the sensor in hPa

BME680.IAQ

Returns the Indoor Air Quality index

BME680.STATIC_IAQ

Returns the static Indoor Air Quality index

BME680.IAQ_ACCURACY

Returns the IAQ accuracy (0-3)

BME680.CO2

Returns the CO2 equivalent estimate in ppm

BME680.BREATH_VOC

Returns the breath VOC equivalent estimate in ppm

BME680.GAS

Returns the gas percentage

BME680.GAS_RES

Returns the gas resistance in Ohms

BME680.BME_STATUS

Returns the BME680 sensor status

BME680.BSEC_STATUS

Returns the BSEC library status

BME680.STAB_STATUS

Returns the sensor stabilisation status

BME680.RUN_STATUS

Returns the sensor run-in status

 

 

Example

I2C.SETUP 21, 22 ' set I2C port on pins 21 and 22

if BME680.Begin(&h77) <> 0 then print "BME680 not found" : end

r = BME680.Setup(0.333333, "/config/generic_33v_3s_4d/bsec_iaq.txt")

r = BME680.Set_Offset(4)   ' 4°C of offset for the Temperature

r = BME680.Load_State("/bsec_state.csv")  ' load the saved state

 

z = 1

while 1

  if BME680.RUN = 1 then

    print "Temperature", BME680.TEMP

    print "Humidity", BME680.HUM

    print "Pressure", BME680.PRESS

    print "IAQ", BME680.IAQ

    print "CO2 Equivalent", BME680.CO2

    print "Breath VOC", BME680.BREATH_VOC

    print "Gas Resistance", BME680.GAS_RES

    ' Save state every 100 iterations

    if z mod 100 = 0 then

      ret = BME680.SAVE_STATE("/bsec_state.csv")

    endif

    z = z + 1

  endif

  pause 1000

wend

 

HDC1080 High Accuracy Digital Humidity Sensor with Temperature Sensor

The HDC1080 is a digital humidity sensor with integrated temperature sensor that provides excellent measurement accuracy at very low power. The HDC1080 operates over a wide supply range, and is a low cost, low power alternative to competitive solutions in a wide range of common applications. The humidity and temperature sensors are factory calibrated.

 

The device can be connected to the ESP32 using the I2C interface.

image

 

The following functions are available :

 

HDC1080.SETUP(address 'the address is always &h40
Start the device using the given I2C address.

Returns 0 if OK or 1 in case of error

 

HDC1080.TEMP

Returns the temperature in °C

 

HDC1080.HUM

Returns the humidity in %

 

HDC1080.HEATUP(time)

Heat up the sensor for ‘time’ seconds

The heater helps in reducing the accumulated offset after long exposure at high humidity conditions.

 

Example

'HDC1080 simple demo
i2c.setup 21, 22

if hdc1080.Setup(&h40) = 1 then print "HDC1080 not found" : end

While 1

  print "Temperature "; hdc1080.temp, "Humidity "; hdc1080.hum

  pause 1000

wend

 

CCS811 Air Quality Sensor

The CCS811 is an ultra-low power digital gas sensor solution which integrates a metal oxide (MOX) gas sensor to detect a wide range of Volatile Organic Compounds (VOCs) for indoor air quality monitoring with a microcontroller unit (MCU), which includes an Analog-to-Digital converter (ADC), and an I²C interface.

 

Annex32 includes the support for this device using the full implementation of the Sparkfun Library.

The device can be connected to the ESP32 using the I2C interface.

 

Generic CCS811 module    

Module that combines a CCS811 with an HDC1080

image

image

 

 

Return Status codes:

Most of the functions returns 0 is the result is OK otherwise a number following this error table :

Return Value

MEANING

0

OK

1

ID Error

2

I2C Error

3

INTERNAL ERROR

4

UNKNOWN ERROR

5

GENERIC ERROR

 

The following functions are available :

 

CCS811.SETUP(address) 'the address can be &h5A or &h5B

Start the device using the given I2C address.

Returns 0 if OK or a value following the status codes table

 

CCS811.READ

Updates the total volatile organic compounds (TVOC) in parts per billion (PPB) and the CO2 value.

Returns 0 if OK or a value following the status codes table

 

CCS811.CHECKSTATERROR

Checks to see if the error bit is set.

Returns 1 if an error is set otherwise 0

 

CCS811.AVAIL

Checks to see if data is available ( DATA_READY flag is set in the status register).

Return 1 if data is available otherwise 0

 

CCS811.APPVALID

Checks to see if a valid application firmware is loaded (APP_VALID flag is set in the status register).

Return 1 if application is valid otherwise 0

 

CCS811.GETERRORREG

Returns the status of the error register

 

CCS811.GETBASELINE

Returns the baseline value.

Used for telling the sensor what 'clean' air is.

You must put the sensor in clean air and record this value.

 

CCS811.SETBASELINE(baseline)

Set the baseline value taken from the function CCS811.GETBASELINE

Returns 0 if OK or a value following the status codes table

 

CCS811.INT_ENABLE

Enable the nINT signal

Returns 0 if OK or a value following the status codes table

 

CCS811.INT_DISABLE

Disable the nINT signal

Returns 0 if OK or a value following the status codes table

 

CCS811.SETDRIVEMODE(mode)

Set the operation mode of the device following the table below:

MODE

MEANING

EXPLANATION

0

Idle

Measurements are disabled in this mode

1

Read every 1 sec

Constant power mode, IAQ measurement every second

2

Read every 10 sec

Pulse heating mode IAQ measurement every 10 seconds

3

Read every 60 sec

Low power pulse heating mode IAQ measurement every 60 seconds

4

Raw mode

Constant power mode, sensor measurement every 250ms.

In this mode the internal chip algo is not updated and the processing must be done on the host system.

 

After each measurement interval, a new sample is processed by the internal chip algo and the function CCS811.AVAIL will return 1 indicating that the data is ready.

If the nINT signal is enabled, the CCS811 nINT pin will be set to 0 until the data will be read with CCS811.READ

 

SETENVDATA(humidity, temperature) 'humidity in %, temperature in °C

Given a temp and humidity, write this data to the CSS811 for better compensation

Returns 0 if OK or a value following the status codes table

 

CCS811.TVOC

Returns the TVOC computed value

 

CCS811.CO2

Returns the CO2 computed value

 

Example 1

'CCS811 simple demo
i2c.setup 21, 22

if ccs811.Setup(&h5a) <> 0 then print "CCS811 not found" : end

print ccs811.setdrivemode(1 'update every second

While 1

  if ccs811.avail = 1 then

    a = ccs811.read

    print "CO2 "; ccs811.CO2, "TVOC "; ccs811.TVOC

  end if

Wend

 

Example 2

'CCS811 combined with a HDC1080 module demo

i2c.setup 21, 22

if ccs811.Setup(&h5a) <> 0 then print "CCS811 not found" : end

if hdc1080.Setup(&h40) <> 0 then print "HDC1080 not found" : end

print ccs811.setdrivemode(2 'update every 10 seconds

 

While 1

  a = ccs811.setenvdata(hdc1080.hum, hdc1080.temp)

  print "Temperature "; hdc1080.temp, "Humidity "; hdc1080.hum

  if ccs811.avail = 1 then

    a = ccs811.read

    print "CO2 "; ccs811.CO2, "TVOC "; ccs811.TVOC

  end if

  pause 1000

wend

 

 

 

APDS9960 Digital Proximity, Ambient Light, RGB and Gesture Sensor

An APDS9960 Sensor can be connected to the module using the I2C interface.

 

The APDS-9960 device features advanced Gesture detection, Proximity detection, Digital Ambient Light Sense (ALS) and Color Sense (RGBC).

Gesture detection utilises four directional photodiodes to sense reflected IR energy (sourced by the integrated LED) to convert physical motion information (i.e. direction and distance) into digital information.

image

 

The connection is very simple, just 2 pins for the I2C bus and the power supply are required.

The module is already provided with on-board pull-up resistors, so external pull-up resistors are not required.

 

 

 

image

Available functions are :

APDS9960.SETUP(mode)
APDS9960.READGESTURE
APDS9960.AMBIENT
APDS9960.RED
APDS9960.GREEN
APDS9960.BLUE
APDS9960.PROXIMITY
APDS9960.GESTUREGAIN
APDS9960.GESTURELED

 

There is also an associated ONGESTURE event.

The use of the APDS9960 module is quite simple.

 

First the I2C must be initialised with the command I2C.SETUP.

Then the module must be initialised with the function APDS9960.SETUP(mode).

mode” must be 1 for “GESTURE” mode.

As soon as a gesture is recognised, the event ONGESTURE is triggered, so it is then possible to get the recognised gesture with the function APDS9960.READGESTURE

 

Example

'APDS9960 GESTURE SENSOR DEMO
i2c.setup 21,22
'set the sensor in GESTURE mode
if apds9960.Setup(1) = 0 then print "APDS9960 not found" : end
'define the Gesture event
ongesture gesture
'Wait for the event
wait

gesture:
r = apds9960.ReadGesture
select case r
  case 1
    print "LEFT"
  case 2
    print "RIGHT"
  case 3
    print "UP"
  case 4
    print "DOWN"
  case 5
    print "NEAR"
  case 6
    print "FAR"
  case else
    print "none"
end select
return

 

The module can also be configured as an Ambient & RGB light sensor.

In this case “mode” must be 2 for “Ambient Light and RGB Color” mode.

Example

'APDS9960 LIGHT SENSOR DEMO
i2c.setup 21,22
'set the sensor in Ambient light and RGB Color mode
if apds9960.Setup(2) = 0 then print "APDS9960 not found" : end

for z
= 1 to 10000
 
print "Light:", apds9960.ambient, apds9960.red, apds9960.green, apds9960.blue
 
pause 100
next z
end

 

The module can, finally, be configured also as a Proximity sensor.

In this case “mode” must be 3 for “Proximity” mode.

Example

'APDS9960 PROXIMITY SENSOR DEMO
i2c.setup 21,22
'set the sensor in Proximity mode
if apds9960.Setup(3) = 0 then print "APDS9960 not found" : end

for z
= 1 to 10000
 
print "Distance:", apds9960.proximity
 
pause 100
next z
end

 

RFID MFRC522 RFID cards reader

A RFID card/key reader module based on the chipset MFRC522 can be connected to the module using the SPI Interface. These modules are very cheap and available on Ebay at less than 2€.

 

image

 

These modules enable to read/write these kind of devices, also easily available and very cheap

imageimage

 

 

 

These devices are based on a chip manufactured by NXP (MIFARE 1K) that contains 1KBytes of memory.

Each device has a 4 bytes identifier (NUID) that is unique and cannot be modified.

For this reason this NUID is normally used as a simple way to identify the device.

For more secured applications, personal data can be written on the device and secured using passwords.

For more information, there is a nice article on that subject here and the datasheet of the card here

Annex implements all the functions permitting reading and writing these devices.

 

The module must be connected using the SPI bus as below:

 

image

 

The pin RST can be eventually left unconnected or put to +3.3V.

 

To start using the module, it must be setup using the function RFID.SETUP(CS_pin, RST_pin)

Example:

ret = RFID.SETUP(15, 0)

Note: if the RST pin is left unconnected, it can be replaced by -1 in the function

 

This function returns a value following the table below :

 

VALUE

REASON

0

Failed

18

Counterfeit chip

136

Clone

144

Version 0.0

145

Version 1.0

146

Version 2.0

255

Failed

 

 

Then it is possible to set the gain (sensitivity) of the module with the function RFID.SETGAIN(gain)

By default the gain is 4 and can range from 0 (minimum) to 7 (maximum)

Example:

ret = RFID.SETGAIN(7)

This function returns the value set or another value in case of error.

 

Another event, ONRFID , has been included to determine when a device is detected.

All the actions related to the card (read / write), must be done inside this event

Example

ONRFID  card_detected

 

When this event occurs, the following functions are available :

RFID.NUID$ that returns the NUID of the card detected (ex. CD788821)

Example:

nuid$ =  RFID.NUID$

 

RFID.TYPE$ that returns the type (model) of the card detected (typically MIFARE 1KB )

 

Example:

type$ =  RFID.TYPE$

 

It can return any of the following values:

TYPE

PICC compliant with ISO/IEC 14443-4

PICC compliant with ISO/IEC 18092 (NFC)

MIFARE Mini, 320 bytes

MIFARE 1KB

MIFARE 4KB

MIFARE Ultralight or Ultralight C

MIFARE Plus

MIFARE DESFire

MIFARE TNP3XXX

SAK indicates UID is not complete.

Unknown type

 

Example:

'MRFC522 RFID CARD READER DEMO

print "Setup", hex$(rfid.setup(15, 0))

print "SetGain", rfid.setgain(7)

'define the RFID event

ONRFID card_detected

wait

 

card_detected:

print "card detected"

print "Type", rfid.type$

print "NUID", rfid.nuid$

return

 

In addition to the function described above, there are also other “advanced” functions.

These enable you to read and write blocks on the card.

Each block is 16 bytes long and the card (MIFARE 1K) contains 64 blocks.

The memory is organised into 16 sectors of 4 blocks each.

 

To note that :

-       The sector 0 is read only as it contains the NUID that cannot be changed

-       The sector 3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63 have a special function and should not be written; in particular they contain the passwords.

-       Writing and reading to the card requires a password (6 bytes) that, by default, is set to FFFFFFFFFFFF; this must be known and cannot be extracted from the card.

-        

So the first “advanced” function is RFID.SETKEY that permit to define another password if the card doesn’t use the default FFFFFFFFFFFF

Example:

ret = RFID.SETKEY("A1B2C3D4E5F6")

The function returns 1 if OK or 0 in case of non valid password

Important : this function set the key that is valid for all the blocks of the same sector (i.e. the blocks 4 to 7).

 

Then, the function RFID.READ$(block [,key_b]) can be used to read a block of 16 bytes.

The result will be a string like “010102030405060708090A0B0C0D0E0F” or a message indicating that an error is occurred :

 

MESSAGE

REASON

Auth Failed

Error during the authorisation phase.

Probably the password is not valid

Read Failed

Error during the reading phase.

Probably the card has been moved too far from the reader

 

Important: The KEY A is selected by default but the KEY B can be selected putting a ,1 extra argument in the function  RFID.READ$ (example RFID.READ$(block, 1)

 

If the card stops responding or answers with an error, it is required to remove the card from the reader and then bring it closer.

To avoid this action, use the function  RFID.RESET or the function RFID.AWAKE to reset the reader.

This is particularly useful when reading using a wrong KEY as these functions reset the module and enable it to retry again with another KEY.

 

Last function is RFID.WRITE(block, data$) that can be used to write a block of 16 bytes.

block must be a number from 0 to 63 and data$ a string like “010102030405060708090A0B0C0D0E0F”

The function returns the following error values:

 

MESSAGE

REASON

0

No error

1

Error during the authorisation phase.

Probably the password is not valid

2

Error during the writing phase.

Probably trying to write into a read only block or the content to be written is not valid

 

Writing NUID for UID changeable card (4 byte UID version)

In general, the standard MIFARE RFID modules have a unique NUID identifier that cannot be changed.

However, there exist some special “chinese” modules that enable the feature to set an arbitrary NUID.

For that, the special function RFID.SETNUID(NUID$) can be used for this purpose where NUID$ represents an 4 bytes hex code

Example:

ret = RFID.SETNUID("AABBCCDD")

The function returns 1 if OK or 0 in case of error

 

Important : this function works only for UID changeable cards

VL53L0X TOF (Time Of Flight) Distance Sensor 

The VL53L0X is a new generation Time-of-Flight (ToF) laser-ranging module providing accurate distance measurement whatever the target reflectances unlike conventional technologies. It can measure absolute distances up to 2m, setting a new benchmark in ranging performance levels, opening the door to various new applications.

It must connected using I2C using the wiring as shown below :

imageimage

 

To start to use, it must be initialised using the

VL53L0X.INIT function.  

The syntax is:

 

Ret = VL53L0X.INIT

 

It returns 1 if the initialisation was successful or 0 if not OK.

 

Then, the following commands are available :

 

VL53L0X.SETRANGE range

Set the distance range (sensitivity); by default the value is 0 for a max range of 600 mm

 

VL53L0X.SETRANGE

Range (mm)

0 ( default)

~ 600

1

~ 2000

 

VL53L0X.SETACCURACY accuracy

Set the accuracy of the readout modifying the time required for the measurement.

By default the value is 0 for a Measurement time of 33 msec.

 

VL53L0X.SETACCURACY

Measurement time (msec)

0 ( default)

33

1

 200

2

400

 

Finally it is possible to read the distance using the function

VL53L0X.DISTANCE

The value returned is the distance measured in millimeters.

If the measurement is not valid, for example if the distance is out of range, this function returns 8190.

This is a “blocking” function meaning that the program will stop during the time required for the measurement, i.e. 400 ms when using the accuracy at 2.

 

For this reason the alternative function

VL53L0X.DISTANCE_N

returns the same information but without blocking the execution of the code.

Obviously, the distance measured will be “refreshed” only at the rate defined with the function VL53L0X.SETACCURACY

 

Example:

' VL53L0X example program

print VL53L0X.init  ' will print 1 if the device has been found

VL53L0X.SetAccuracy 2 ' set the refresh rate at 400 msec (max accuracy)

VL53L0X.SetRange 1 ' set the range at 2000 mm ( 2 meters )

for z = 1 to 100000

  print VL53L0X.Distance ' get the distance 

next z

 

An additional “custom” function is also available for experienced users:

VL53L0X.CUSTOM signal_rate_limit, VcselPeriodPreRange, VcselPeriodFinalRange, MeasurementTimingBudget

Check the documentation of the driver for more information.

HX711 - Weight Measurement Module 

The HX711 is a high-precision analog-to-digital converter (ADC) chip designed for weighing scale and industrial control applications. It is commonly used in load cells, which are transducers that convert physical force into an electrical signal, and is capable of amplifying and digitising the low-level signals produced by these sensors.

The HX711 chip contains two differential analog inputs for the load cell signal, and provides a 24-bit digital output that can be read by a microcontroller or other digital device. It has programmable gain amplifiers with a selectable gain of 128 or 64, allowing for greater sensitivity and resolution of the load cell readings.

 

You can buy for very cheap a kit composed of a “Load Cell” and an HX711 module as shown below:

image

 

The connection require only 2 wires for the Data and the Clock signal as below:

image

 

The current implementation use a single -very simple -  function :

 

ret = HX711(data_pin, clk_pin [,resolution])

 

the optional parameter resolution can be:

0 -> Input A GAIN 128 (default)

1 -> Input A Gain 64

2 -> Input B Gain 32

 

Example:

' HX711 example program

' The offset and scale must be adapted in function of the load cell;

' You can start setting offset to 0 and the scale to 1 and then find

' your numbers using an object with "known" weight as reference

dat = 32

clk = 26

dim sample(30)

weight = 0

offset = 100671 ' must be adapted to the specific load cell

scale = 0.009663 ' must be adapter to the specific load cell

samples = 5 ' The average is done on 5 samples

gosub webpage

onHtmlReload webpage

while 1

  media = 0

  for r = 1 to samples

    sample(r)= HX711(dat,clk) ' input A GAIN 128 (default)

  next r

  'computes the average removing the lowest and the highest value

  max=sample(1)

  min=sample(1)

  sum=0

  for i= 1 to samples

    sum = sum + sample(i)

    if sample(i) > max then max=sample(i)

    if sample(i) < min then min=sample(i)

  next i

  avg = (sum - max - min) / (samples-2)

  w = avg - offset

  weight = fix(w * scale)

  wlog weight, avg

 

  'pause 500

wend

end

 

tare:

offset = avg

return

 

webpage:

cls

a$ = ""

a$ = a$ + CSSID$("wgt", "width:300px; font-size:150px; border:none; pointer-events:none;")

a$ = a$ + CSSID$("bt", "width:300px; height:50px")

a$ = a$ + "weight (g): " + textbox$(weight, "wgt") + "<br>"

a$ = a$ + button$("Tare", tare, "bt") + "<br><br>"

a$ = a$ + "scale: " + textbox$(scale)

 

html a$

autorefresh 200

return

 

SI5351 Clock Generator Module

The Si5351 clock generator is an I2C controller clock generator. It uses the onboard precision clock to drive multiple PLL's and clock dividers using I2C instructions. By setting up the PLL and dividers you can create precise and arbitrary frequencies.

There are three independent outputs, and each one can have a different frequency. Outputs are 3Vpp, either through a breadboard-friendly header or, for RF work, an optional SMA connector.

The outputs can go from 8Khz to 160Mhz and the output drive strength can go from 2 to 8 mA.

The chip contains 2 PLL:

-       PLL 0 → Shared with the outputs 0 and 1

-       PLL 1 → Dedicated to the output 2.

image

The connection is very simple, just 2 pins for the I2C bus and the power supply are required.

The module is already provided with on-board pull-up resistors, so external pull-up resistors are not required.

image

 

 

FUNCTIONS / COMMANDS

DESCRIPTION

SI5351.INIT [capacitor [,crystal]]

Initialise the module.

The optional parameter ‘capacitor’ can be as below

DESCRIPTION

VALUE

CAPACITOR 0 pF

0

CAPACITOR 6 pF

1

CAPACITOR 8 pF

2

CAPACITOR 10 pF

3

 

The optional parameter ‘crystal’ can be 25000000 or 27000000.

 

The default values are 8pF and 25MHz

SI5351.CALIB correction

Set the correction for the frequency calibration

SI5351.SETFREQ out_nb, frequency

Set the frequency for the output ‘out_nb’

‘frequency’ can go from 8000 to 160000000

SI5351.SETFREQ_MAN out_nb, frequency, pll

Set the frequency manually for the output ‘out_nb’

‘frequency’ is the output frequency and

‘pll’ is the PLL frequency

SI5351.STRENGTH out_nb, strength

Set the strength for the output ‘output’

The parameter strength can be as below

DESCRIPTION

VALUE

DRIVE 2MA

0

DRIVE 4MA

1

DRIVE 6MA

2

DRIVE 8MA

3

SI5351.PHASE out_nb, phase

Set the phase for the output ‘out_nb’

SI5351.RESET_PLL pll_nb

Reset the PLL  ‘pll_nb’

 ‘pll_nb’ can be 0 or 1

SI5351.ENABLE out_nb, enable

Enable / disable the output ‘out_nb’

If ‘enable’ = 1, the output is enabled

If ‘enable’ = 0, the output is disabled

SI5351.INVERT out_nb, invert

Enable / disable the output ‘out_nb’

If ‘invert’ = 1, the output is inverted

If ‘invert’ = 0, the output is normal

SI5351.LOAD filename$

Load a file containing the parameters generated by the software “ClockBuilder Pro”

 

Example:

' SI5351 example program

SDA = 21

SCL = 22

I2C.SETUP SDA, SCL   'Pins as shown

 

si5351.init '3, 25000000

si5351.calib 212000 'set the correction to calibrate the frequency error

 

si5351.setfreq 0, 5000000 'set 5MHz on output 0

si5351.setfreq 2, 30000000 'set 30MHz on output 2

 

si5351.phase 0, 0

si5351.phase 1, 0

si5351.phase 2, 127

si5351.reset_pll 0

si5351.reset_pll 1

 

si5351.invert 0, 0 'do not invert out 0

si5351.invert 2, 0 'do not invert out 1

 

si5351.enable 0, 1 'enable out 0

si5351.enable 1, 0 'disable out 1

si5351.enable 2, 1 'enable out 2

 

si5351.strength 0, 1 'set 4mA on out 0

si5351.strength 2, 3 'set 8mA on out 2

 

counter.init 17 'set the internal H/W frequency counter on pin 17

while 1

  wlog counter.cpufreq 'read the frequency (up to ~40MHz max)

  pause 1000

wend

 

STEP MOTOR

-       Based on the library https://github.com/gin66/FastAccelStepper

-       Controls up to 3 motors

-       allows up to 200000 generated steps per second

-       Works in background (the pulses are automatically generated even if the program is stopped)

-       ESP32 only

 

 

FUNCTIONS / COMMANDS

DESCRIPTION

STEPPER.SETUP stepper_id, pin_step, pin_dir

Setup the driver to use the step motor

stepper_id can be from 1 to 3 (0 to 2 ?)

pin_step and pin_dir can be any output capable pin

Default speed is 100Hz and default acceleration is 10 step/sec^2

STEPPER.SETPARAM stepper_id, speed, acceleration

Set the step motor speed and acceleration parameters

stepper_id can be from 1 to 3 (0 to 2 ?)

speed is in pulses/sec (Hz)

acceleration is in step/sec^2

STEPPER.SETPOSITION stepper_id, position

Set the current position of the motor (like a reset but at a given position)

stepper_id can be from 1 to 3 (0 to 2 ?)

position is the desired position (in steps), and can be positive or negative (is a 32 bits number)

STEPPER.MOVE stepper_id, position

Move the motor relatively to the current position (can be positive / negative)

stepper_id can be from 1 to 3 (0 to 2 ?)

position is the desired position (in steps), and can be positive or negative (is a 32 bits number)

STEPPER.MOVETO stepper_id, position

Move the motor to the absolute position (can be positive / negative)

stepper_id can be from 1 to 3 (0 to 2 ?)

position is the desired position (in steps), and can be positive or negative (is a 32 bits number)

STEPPER.STOP stepper_id

stops the motor using the current deceleration

stepper_id can be from 1 to 3 (0 to 2 ?)

STEPPER.FORCESTOP stepper_id

stops the motor immediately (kind of abort)

stepper_id can be from 1 to 3 (0 to 2 ?)

STEPPER.RUNFWD stepper_id

Run the motor in the Forward direction and continue until STEPPER.STOP is executed.

The motor accelerate and reach the speed defined with the parameters defined with STEPPER.SETPARAM

 

stepper_id can be from 1 to 3 (0 to 2 ?)

STEPPER.RUNBKD stepper_id

Run the motor in the Backward direction and continue until STEPPER.STOP is executed.

The motor accelerate and reach the speed defined with the parameters defined with STEPPER.SETPARAM

 

stepper_id can be from 1 to 3 (0 to 2 ?)

STEPPER.GETPOSITION(stepper_id)

Returns he current position (change during the movement)

stepper_id can be from 1 to 3 (0 to 2 ?)

STEPPER.GETTARGET(stepper_id)

Returns the final target position (the one reached at the process)

stepper_id can be from 1 to 3 (0 to 2 ?)

 

MPU9250 

The MPU-9250 is a 9-DOF System in Package (SiP) that combines two chips: the MPU-6500, which contains a 3-axis gyroscope as well as a 3-axis accelerometer, and the AK8963, which features a 3-axis magnetometer.

It also contains a temperature sensor.

 

imageimage

 

It must be connected using I2C wiring.

For that the I2C must be initialised before using the command

I2C.Setup 21,22, 400000 '400000 set the I2C to max speed

 

To start to use, it must be initialised using theMPU9250.SETUP function.

The syntax is:

 

Ret =MPU9250.SETUP(address)

‘Address’ can be &h68 or &h69 depending on the wiring of the MPU9250.

The address depends on the voltage applied to the pin AD0 :

 

LEVEL ON PIN AD0

ADDRESS (HEXADECIMAL)

GND or open

68

VCC

69

 

It returns 1 if the initialisation was successful, or 0 if not OK.

 

The chip temperature can then be read using the function

Ret = MPU9250.TEMP

Example:

Print  MPU9250.TEMP

 

Then all the chip values can then be read using the function

Ret = MPU9250.VECTOR(array())

Using an array guarantees that all the data received will be synchronised with each other as read at the same time.

The function returns 1 if the action was successful; otherwise 0.

NOTE: The array must be defined before with the command DIM with a minimum size of 10

The variables are read in a one-shoot operation, as per the table below:

 

INDEX

PARAMETER

UNITS

0

Accelerometer X axis

m/sec2

1

Accelerometer Y axis

2

Accelerometer Z axis

3

Gyroscope X axis

deg / sec

4

Gyroscope Y axis

5

Gyroscope Z axis

6

Magnetometer X axis

micro tesla

7

Magnetometer Y axis

8

Magnetometer Z axis

 

Example:

I2C.Setup 21,22, 400000 '400000 set the I2C to max speed

if MPU9250.Setup(&h68) = 0 then print "MPU9250 not found" : end

Print "Temperature", MPU9250.TEMP ; "°C"

Dim vect(10) 'dimension the array

'read the values for all the axis

Ret =  MPU9250.VECTOR(vect())

'Print all the values

Print "ax "; vect(0), "ay "; vect(1), "az "; vect(2)

Print "gx "; vect(3), "gy "; vect(4), "az "; vect(5)

Print "mx "; vect(6), "my "; vect(7), "mz "; vect(8)

 

It must be noted that, because of the different internal orientation of the MPU6500 part and the AK8963, the axis of the magnetometers are not aligned with the accelerometers and the gyros.

However, this has been taken into account so this function will always return the correct values.

 

The MPU9250 can be straightly connected with the IMU Fusion functions (see below) enabling it to compute, in a single operation, all the orientation angles (pitch, roll and yaw).

 

The Madgwick algorithm can be run using the following functions :

Ret =  MPU9250.MADGWICK

This function reads all the values from the MPU9250 and processes them using the Madgwick algorithm.

The result can then be read using FUSION.PITCH,FUSION.ROLL  and FUSION.YAW.

 

In the same way, the Mahony algorithm can be run using the following functions :

Ret =  MPU9250.MAHONY

This function reads all the values from the MPU9250 and processes them using the Mahony algorithm.

The result can then be read using FUSION.PITCH,FUSION.ROLL  and FUSION.YAW.

 

Note: The FUSION must be initialised before using the command FUSION.INIT

Example:

I2C.Setup 21,22, 400000 '400000 set the I2C to max speed

 

if MPU9250.Setup(&h68) = 0 then print "MPU9250 not found" : end

Print "Temperature", MPU9250.TEMP ; "°C"

 

FUSION.Init ' initialise the fusion algorithms

while 1 ' infinite loop

  a = MPU9250.Madgwick 'runs the Madgwick algo

  Print FUSION.Pitch, FUSION.Roll, FUSION.Yaw 'prints the result

wend

 

MPU6500  / MPU6050

The MPU-6500 is a 6-DOF MotionTracking device that combines a 3-axis gyroscope and a 3-axis accelerometer in a small package. It also contains a temperature sensor.

imageimage

 

It must be connected using I2C wiring.

For that the I2C must be initialised before using the command

I2C.Setup 21,22, 400000 '400000 set the I2C to max speed

 

To start to use, it must be initialised using theMPU6500.SETUP function.

The syntax is:

 

Ret =MPU6500.SETUP(address)

‘Address’ can be &h68 or &h69 depending on the wiring of the MPU6500.

The address depends on the voltage applied to the pin AD0 :

 

LEVEL ON PIN AD0

ADDRESS (HEXADECIMAL)

GND or open

68

VCC

69

 

It returns 1 if the initialisation was successful or 0 if not OK.

 

The chip temperature can then be read using the function

Ret = MPU6500.TEMP

Example:

Print  MPU6500.TEMP

 

Then all the chip values can then be read using the function

Ret = MPU6500.VECTOR(array())

Using an array guarantees that all the data received will be synchronised with each other as read at the same time.

The function returns 1 if the action was successful; otherwise 0.

NOTE: The array must be defined before with the command DIM with a minimum size of 10

The variables are read in a one-shoot operation, as per the table below:

 

INDEX

PARAMETER

UNITS

0

Accelerometer X axis

m/sec2

1

Accelerometer Y axis

2

Accelerometer Z axis

3

Gyroscope X axis

deg / sec

4

Gyroscope Y axis

5

Gyroscope Z axis

 

Example:

I2C.Setup 21,22, 400000 '400000 set the I2C to max speed

if MPU6500.Setup(&h68) = 0 then print "MPU6500 not found" : end

Print "Temperature", MPU6500.TEMP ; "°C"

Dim vect(10) 'dimension the array

'read the values for all the axis

Ret =  MPU6500.VECTOR(vect())

'Print all the values

Print "ax "; vect(0), "ay "; vect(1), "az "; vect(2)

Print "gx "; vect(3), "gy "; vect(4), "az "; vect(5)

 

The MPU6886 can be straightly connected with the IMU Fusion functions (see below) enabling it to compute, in a single operation, all the orientation angles (pitch, roll and yaw).

 

The Madgwick algorithm can be run using the following functions :

Ret =  MPU6500.MADGWICK

This function reads all the values from the MPU6500 and processes them using the Madgwick algorithm.

The result can then be read using FUSION.PITCH,FUSION.ROLL  and FUSION.YAW.

 

In the same way, the Mahony algorithm can be run using the following functions :

Ret =  MPU6500.MAHONY

This function reads all the values from the MPU6500 and processes them using the Mahony algorithm.

The result can then be read using FUSION.PITCH,FUSION.ROLL  and FUSION.YAW.

 

 

Note: The FUSION must be initialised before using the command FUSION.INIT

Example:

I2C.Setup 21,22, 400000 '400000 set the I2C to max speed

if MPU6500.Setup(&h68) = 0 then print "MPU6500 not found" : end

Print "Temperature", MPU6500.TEMP ; "°C"

 

FUSION.Init ' initialise the fusion algorithms

while 1 ' infinite loop

  a = MPU6500.Madgwick 'runs the Madgwick algo

  Print FUSION.Pitch, FUSION.Roll, FUSION.Yaw 'prints the result

wend

 

Note: As this IMU does not contain a magnetometer, you will experience yaw drift over an extended period of time. This is unavoidable and a limitation of the technology.

MPU6886 (For M5 Atom) 

The MPU-6886 is a 6-DOF MotionTracking device that combines a 3-axis gyroscope and a 3-axis accelerometer in a small package. It also contains a temperature sensor.

This is in particular installed inside the M5Stack Atom Matrix using an internal I2C bus (pin 21 and 25).

image

 

For this reason it is not required to initialise the I2C bus as it will be done automatically.

 

To start to use, it must be initialised using theMPU6886.SETUP function.

The syntax is:

 

Ret =MPU6886.SETUP

The address is set automatically to HEX 68 so it is not required

It returns 1 if the initialisation was successful or 0 if not OK.

 

The chip temperature can then be read using the function

Ret = MPU6886.TEMP

Example:

Print  MPU6886.TEMP

 

Then all the chip values can be read using the function

Ret = MPU6886.VECTOR(array())

Using an array guarantees that all the data received will be synchronised with each other as read at the same time.

The function returns 1 if the action was successful; otherwise 0.

NOTE: The array must be defined before with the command DIM with a minimum size of 10

The variables are read in a one-shoot operation, as per the table below:

 

INDEX

PARAMETER

UNITS

0

Accelerometer X axis

m/sec2

1

Accelerometer Y axis

2

Accelerometer Z axis

3

Gyroscope X axis

deg / sec

4

Gyroscope Y axis

5

Gyroscope Z axis

 

Example:

if MPU6886.Setup = 0 then print "MPU6686 not found" : end

Print "Temperature", MPU6886.TEMP ; "°C"

Dim vect(10) 'dimension the array

'read the values for all the axis

Ret =  MPU6886.VECTOR(vect())

'Print all the values

Print "ax "; vect(0), "ay "; vect(1), "az "; vect(2)

Print "gx "; vect(3), "gy "; vect(4), "az "; vect(5)

 

The MPU6886 can be straightly connected with the IMU Fusion functions (see below) enabling it to compute, in a single operation, all the orientation angles (pitch, roll and yaw).

 

The Madgwick algorithm can be run using the following function :

Ret =  MPU6886.MADGWICK

This function reads all the values from the MPU6886 and processes them using the Madgwick algorithm.

The result can then be read using FUSION.PITCH,FUSION.ROLL  and FUSION.YAW.

 

In the same way, the Mahony algorithm can be run using the following functions :

Ret =  MPU6886.MAHONY

This function reads all the values from the MPU6886 and processes them using the Mahony algorithm.

The result can then be read using FUSION.PITCH,FUSION.ROLL  and FUSION.YAW.

 

Note: The FUSION must be initialised before using the command FUSION.INIT

Example:

if MPU6886.Setup = 0 then print "MPU6686 not found" : end

Print "Temperature", MPU6886.TEMP ; "°C"

 

FUSION.Init ' initialise the fusion algorithms

while 1 ' infinite loop

  a = MPU6886.Madgwick 'runs the Madgwick algo

  Print FUSION.Pitch, FUSION.Roll, FUSION.Yaw 'prints the result

wend

 

Note: As this IMU does not contain a magnetometer, you will experience yaw drift over an extended period of time. This is unavoidable and a limitation of the technology.

IMU FUSION FUNCTIONS

Annex includes 2 fusion algorithms designed to provide pitch, roll and yaw orientation from data coming from IMUs like the MPU9250.

The 2 algorithms are Madgwick and Mahony.

 

Both are provided in 2 forms, with 6-DOF and 9-DOF..

 

To start, the algos must be initialised with the command

FUSION.INIT

 

Then the different algos can be called as below :

 

For the 6-DOF Madgwick:

FUSION.MADGWICK ax, ay, az, gx, gy, gz

 

For the 9-DOF Madgwick:

FUSION.MADGWICK ax, ay, az, gx, gy, gz, mx, my, mz

 

For the 6-DOF Mahony:

FUSION.MAHONY ax, ay, az, gx, gy, gz

 

For the 9-DOF Mahony:

FUSION.MAHONY ax, ay, az, gx, gy, gz, mx, my, mz

 

The angles can be read using the function FUSION.ANGLE(axis) following the table below:

 

AXIS

RETURNED INFORMATION

UNIT

1

PITCH

°

2

ROLL

°

3

YAW

°

 

In a simpler way, it is also possible to read the values using the functions :

Pitch = FUSION.PITCH

Roll  = FUSION.ROLL

Yaw   = FUSION.YAW

 

The 2 algos can be tuned using the following coefficients :

For Madgwick :

FUSION.BETA = 0.6   ' default value 0.6

FUSION.ZETA = 0.6   ' default value 0.6  - only for 6-DOF algo

 

For Mahony:

FUSION.Kp = 2 ' proportional feedback default value 2

FUSION.Ki = 0  ' integral feedback default value 0

 

Example with the MPU9250 and a Madgwick algo:

 

I2C.Setup 21,22, 400000 '400000 set the I2C to max speed

'initialise the MPU9250 with address hex 68

if MPU9250.Setup(&h68) = 0 then print "MPU9250 not found" : end

FUSION.Init ' initialise the fusion algorithms

FUSION.Beta = 0.6 'set beta parameter to 0.6

Dim p(10) 'dimension the array

while 1 ' infinite loop

   i = MPU9250.vector(p()) 'read the values for all the axis

   'note: the syros must be converted to RAD/sec

   FUSION.Madgwick p(0), p(1), p(2), (p(3) * PI/180), (p(4)* Pi/180), (p(5) * Pi/180), p(6), p(7), p(8)

   Print FUSION.Pitch, FUSION.Roll, FUSION.Yaw 'prints the result

wend

 

 

 

ETHERNET Module W5500

 

An Ethernet module based on the chipset WIZnet W5500 can be connected to the module using SPI interface.

These modules are very cheap and available on Ebay at less than 5€.

 

This picture shows 2 modules based on this chipset which have been successfully tested with Annex32.

imageimage

imageimage

 

This schematic shows how to connect the W5500 module to the ESP32 module.

image

 

This module permits to connect the ESP32 to the network using a wired connection.

Annex32 implements the functionalities to send and receive TCP and UDP packets.

It can be used in ADDITION to the existing WI-FI functionalities, as it exposes all the functionalities permitting to communicate with other modules / web services.

However, Annex32 cannot be administered through this connection, administration must continue to be done using Wi-Fi.

The actual implementation introduces a new keyword, ETHERNET, which is used as the prefix for all the commands / functions related to it.

For simplicity, all the commands / functions replicate the same existing Wi-Fi functionality.

For example Ethernet.wget$ is the equivalent of wget$, Ethernet.IP$ is the equivalent of IP$, etc.

 

 

a = ETHERNET.init( cs_pin [, ip$, mask$, gateway$ ] )     Initialise the interface, variable a holds the status result.

If ip, mask, gateway are not defined, the module will request a DHCP address from a DHCP server.

DHCP status returns  =0 if failed to receive a DHCP IP,  =1 if DHCP IP received successfully,  =2 if using a manually configured fixed IP address,  =-1 if ethernet module not found, =-2 if UTP cable is not connected

 

a$ = ETHERNET.IP$   returns the IP address of the module (same format as IP$)

 

 

a$ = ETHERNET.WGET$( url$, [port] )  same as WGET$ but the syntax has been modified also for the WGET$

make a GET request on a remote server. The arguments http_server [, port ]

the format of the url is [protocol]://web_address:port/path

Example for the same website (all are valid):

print ethernet.wget$(“jsonplaceholder.typicode.com/posts”)  ‘ use by default the port 80

print ethernet.wget$(“http://jsonplaceholder.typicode.com/posts”)  ‘ use by default the port 80

print ethernet.wget$(“jsonplaceholder.typicode.com:80/posts”)  ‘ define the the port 80

print ethernet.wget$(“jsonplaceholder.typicode.com/posts”, 80)  ‘ define the the port 80

 

Another example

print ethernet.wget$("http://portquiz.net:8080/") ‘ define the port 8080

print ethernet.wget$("http://portquiz.net/", 8080) ‘ define the port 8080

 

a$ = ETHERNET.WPOST$( url$, [ [, port | payload$] [,port] ] )

make a POST request on a remote server

the arguments http_server [ [, port | payload$] [,port] ]

the format of the url is [protocol]://web_address:port

 

These functions :

 

ETHERNET.UDP.BEGIN      ETHERNET.UDP.STOP        ETHERNET.UDP.WRITE            ETHERNET.UDP.REPLY      ETHERNET.UDP.READ$     ETHERNET.UDP.REMOTE$

 

Have the same function and format as the corresponding wifi versions but are for the ethernet network

 

 

WEB SERVER:

 

ETHERNET.SERVER.BEGIN [port]  ‘ start the ethernet web server on the defined port (by default 80)

ETHERNET.SERVER.STOP  ‘ stop the ethernet web server

 

ETHERNET.SERVER.GETURL$ ‘ returns the url of the request done on the server

ETHERNET.SERVER.GETARG$ ‘ returns the arg from the request (same as

URLMSGGET$)

 

ETHERNET.SERVER.RETURN  ret$  [, content_type$]

‘ permit to return a content to the caller page

 

 

EVENTS:

ONETHERNETUDP  label

same event as ONUDP but for the ETHERNET

 

ONETHERNETURL label

Is triggered when a request is done with any url

The url can be read with the function ethernet.server.geturl$ and:

The arguments can be read with the function ethernet.server.getarg$

FTP

The File Transfer Protocol (FTP) is a standard network protocol used for the transfer of computer files between a client and server on a computer network.

Annex implements a function permitting to send  files stored locally to the remote server.

 

The function is :

BAS.FTP$

The FTP port is defined by default at the standard value 21.

 

To send a file the command is

 

res$ =  BAS.FTP$(host$, login$, password$, file$, folder$)

Where :

     host$ is the address of the FTP server

     login$ is the login of the account on the FTP server

     password$ is the password of the account on the FTP server

     file$ is the file that will be sent

     folder$ is the folder where the file will be sent

 

Note :

     If the remote folder does not exist, it will be created automatically.

   in this case make sure you have the right to create the directories on the FTP server

 

If the transmission was successful, the function returns a message like this:

-       226 Transfer complete (153.536 KB/s).

 

In case of problems, the function returns a self explaining messages like this :

-       550 Can't change directory to "/newfolder".   

-       530 Permission denied

-       -2 File not found

-       …...

 

Example :

res$ =  BAS.FTP$("192.168.1.57", "myLogin", "myPass", "/test.bas", "/")

 

This is a useful example that permit to backup the module sending all the local files to the FTP server

 

' FTP function example revised

' cicciocb 2019

' send all the local files to the remote server

' in the folder /

' The directory structure will be also copied

 

'starts from the root

d$ = FILE.DIR$("/")

'Then lists all the files

While D$ <> ""

  print "I'm sending ", d$

  path$ = left$(d$, instr(-1, d$, "/")) ' extract the path

  print bas.ftp$( "192.168.1.57", "robin", "hood", d$, path$)

  d$ = FILE.DIR$

Wend

end

 

 

Server data requests  (GET, POST and PUT)

Annex includes the functionality to request/send data from/to the server using HTTP GET, POST and PUT requests.

The GET is the most common HTTP method, generally used to request (GET) data from a server but can also be used to send data to the server.

This is what your web browser does when typing a url in the address bar.

This method uses the url to include all the data to be transferred to the server and returns the answer from the server.

As support, there is a nice site https://jsonplaceholder.typicode.com/ that permits you to exercise into issuing GET requests.

For example, http://jsonplaceholder.typicode.com/comments/1  is composed of :

 

 

http:// => protocol. By default uses the port 80.

jsonplaceholder.typicode.com => base url

/comments/1 => url used to transfer arguments (comments = 1)

 

Another way to transfer arguments is using them after a ? as below:

http://jsonplaceholder.typicode.com/comments?id=1 

In this case we transfer the request for comments with id=1

 

Another example : http://jsonplaceholder.typicode.com/comments?id=1&id=4

In this case we transfer the request for comments with id=1 and id=4.

To note that the arguments are composed of couples arg=value separated by &

 

The same requests can be done using an encrypted protocol, the https:// that uses the port 443 :

https://jsonplaceholder.typicode.com/comments?id=1&id=4  (to note the https://)

 

The POST method is less used than the GET but it is the most appropriate to send data to the server.

In contrast to the GET method where the data is transferred inside the url of the request, the POST method transfers the data in the body of the message.

The PUT method is very similar to POST but is generally used to modify a resource.

 

Annex implements 4 methods to make HTTP requests :

-       WGET$(server$, port, [,rx_header] [,header$])

-       WGET$(url$ [,rx_header] [,header$])

-       WPOST$(server$, body$, port [,rx_header] [,header$] )

-       WPOST$(url$, body$ [,rx_header] [,header$])

-       WPUT$(server$, body$, port [,rx_header] [,header$] )

-       WPUT$(url$, body$ [,rx_header] [,header$])

-       WGETASYNC[(] server$, port, [,rx_header] [)]

-       WGETASYNC[(] url$,[,rx_header] [)]

 

Basically WGET$ and WGETASYNC both do the same operation but WGET$ waits until the server answers whilst WGETASYNC continues the normal execution of the program and triggers (asynchronously) an event when the answer arrives .

 

Example with WGET$ :

' do an HTTP GET request

a$ = WGET$("jsonplaceholder.typicode.com/comments?id=1&id=4", 80)

' do an HTTPS GET request

a$ = WGET$("jsonplaceholder.typicode.com/comments?id=1&id=4", 443)

 

' or with the alternative syntax

 

' do an HTTP GET request

a$ = WGET$("http://jsonplaceholder.typicode.com/comments?id=1&id=4")

' do an HTTPS GET request

a$ = WGET$("https://jsonplaceholder.typicode.com/comments?id=1&id=4")

' do an HTTPS GET request

a$ = WGET$("https://httpbin.org/get?Annex=10&GET=20&text=30&Data=40")

 

To note :

The leading HTTP:// or HTTPS:// must be removed if the port is specified

The protocol is specified using the port number; by default is HTTP but will be HTTPS if the port is 443.

 

Example with WPOST$ :

' do an HTTP POST request

a$ = WPOST$("ptsv2.com/t/annextest/post", "name=Annex&version=1.39", 80)

' check at https://ptsv2.com/t/annextest for the result

 

' or with the alternative syntax

a$ = WPOST$("http://ptsv2.com/t/annextest/post", "name=Annex&version=1.39")

'

a$ = WPOST$("http://httpbin.org/post?a=10", "Annex POST text Data")

 

To note :

The leading HTTP:// or HTTPS:// must be removed if the port is specified

The protocol is specified using the port number; by default is HTTP but will be HTTPS if the port is 443.

 

Example with WPUT$ :

' do an HTTP POST request

a$ = WPOST$("ptsv2.com/t/annextest/put", "name=Annex&version=1.39", 80)

' check at https://ptsv2.com/t/annextest for the result

 

' or with the alternative syntax

a$ = WPOST$("http://ptsv2.com/t/annextest/put", "name=Annex&version=1.39")

'

a$ = WPOST$("http://httpbin.org/put?a=10", "Annex POST text Data")

 

 

To note :

The leading HTTP:// or HTTPS:// must be removed if the port is specified

The protocol is specified using the port number; by default is HTTP but will be HTTPS if the port is 443.

 

 

 

Example with WGETASYNC:

ONWGETASYNC answer_done

' do an HTTPS GET request

WGETASYNC "jsonplaceholder.typicode.com/comments?id=1&id=4", 443

' or with the alternative syntax

'WGETASYNC "https://jsonplaceholder.typicode.com/comments?id=1&id=4"

Wait

answer_done:

Print WGETRESULT$

Return

 

To note :

The leading HTTP:// or HTTPS:// must be removed if the port is specified

The protocol is specified using the port number; by default is HTTP but will be HTTPS if the port is 443.

The brackets around WGETASYNC are optional.

 

Optionally it is possible to specify an extra parameter rx_header for WGET$, WPOST$, WPUT$ and WGETASYNC.

If this parameter is 1, the header of the received message will be included in the answer.

This will be helpful for debugging.

Note: if you don’t know what the header is, just ignore this option.

 

Another optional argument is header$ that enables you to include a specific header inside the content requested from the remote server.

It can be "Content-Type: application/json"  or "Content-Type: text/html",  for example.

Multiple information can be included simply separating each “key:value” couplet with chr$(10).

MQTT Client

MQTT stands for MQ Telemetry Transport. It is a publish/subscribe, extremely simple and lightweight messaging protocol, designed for constrained devices and low-bandwidth, high-latency or unreliable networks. The design principles are to minimise network bandwidth and device resource requirements whilst also attempting to ensure reliability and some degree of assurance of delivery. These principles also turn out to make the protocol ideal of the emerging “machine-to-machine” (M2M) or “Internet of Things” world of connected devices, and for mobile applications where bandwidth and battery power are at a premium.

 

The current implementation supports the unencrypted (port 1883) or encrypted SSL connections (port 8883).

The url must specify the protocol and optionally the port.

Example:

 "mqtt://test.mosquitto.org" or "mqtt://test.mosquitto.org:1883" for unencrypted

 

 "mqtts://test.mosquitto.org" or "mqtts://test.mosquitto.org:8883" for encrypted

 

Annex implements the protocol with the following characteristics :

-       It can publish QoS 0, QoS 1 or QoS 2 messages.

-       It can subscribe at QoS 0, QoS 1 or QoS 2.

-       The maximum message size is 1024 characters

-       The keepalive interval is set to 120 seconds

-       The network timeout is set to 10 seconds

-       The client uses MQTT 3.1.1

If the MQTT connection with the remote server is lost, the module will retry to reconnect automatically.

 

When using SSL connections, it might be required to use certificates / private keys.

 

In general a CERTIFICATE is a text block like this :

-----BEGIN CERTIFICATE-----

MIIB9TCCAWACAQAwgbgxGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxHDAaBgNV

BAsME0RvY3VtZW50IERlcGFydG1lbnQxOTA3BgNVBAMMMFdoeSBhcmUgeW91IGRl

Awel8LzGx5uMOshezF/KfP67wJ93UW+N7zXY6AwPgoLj4Kjw+WtU684JL8Dtr9FX

ozakE+8p06BpxegR4BR3FMHf6p+0jQxUEAkAyb/mVgm66TyghDGC6/YkiKoZptXQ

98TwDIK/39WEB/V607As+KoYazQG8drorw==

-----END CERTIFICATE-----

 

 

And a PRIVATE KEY is a text block like this

-----BEGIN RSA PRIVATE KEY-----

MIIEpQIBAAKCAQEAz2ZbLZ45k/G0O+dKxshu3WaN+pfSZov6Q1tZ/Vsbjt7bS0Qk

LSTXrMP4OdiLBtC7ynqhkGL39ktFnFqRTx67XuyL0YmjyPX5e4DbveY/riGwK4MZ

JwQV3escd6MlQEAxvKFPH5+csDnDxXlJ9Mz+4DY7ElVJyhGiwyPrmigZ9Ph1FPc1

h8xSYmkCgYEAkbvPyMR/q5XQ4Cg2J8BPci3lw38Hhfb1Mr5mpDpRhocPRqWL2Vb0

4CxYKMT65wl1voa5wmsDukbUlrqBq6LPaIeCF2MqKLAahrSOI9O5U3r29wRYhxcD

49FDJGTr/0eTMl+/d8f08W/XmJC1YtF9edVIfpJejelQCElB4zSEgFU=

-----END RSA PRIVATE KEY-----

 

These certificates / Private keys can be stored into a string variable and given as arguments to the MQTT.certif function. The best is to store them into text files and get into a string variable using FILE.READ$

 

 

The following table describes the functions available.

 

FUNCTIONS / COMMANDS

DESCRIPTION

MQTT.Setup(server$ [,debug])

Setup the MQTT communications.

Server$ is the MQTT server url

‘debug’, if set to 1, enable some useful debug messages

This function clears all the existing certificates and PSK

Returns 258 at the first initialisation and then 0

MQTT.Certif(cert_pem$ [,client_cert_pem$] [,client_key_pem$])

Set the SSL certificates.

‘cert_pem$’ is used for the main server authorisation

‘client_cert_pem’ and ‘client_key_pem$’ are used for a more complex authorisation scheme (for advanced users)

When setting the certificates, the PSK will be removed

MQTT.PSK(psk_hint_key$)

Set the PSK as an alternative to certificate verification.

When setting this PSK all the certificates will be removed

MQTT.LWT(topic$, message$ [,Qos] [,retain])

Set the last will and testament (LWT) message in the specified topic

Qos can be 0, 1 or 2; if not defined defaults to 0

‘retain’, if set to 1, the message is retained

Returns 0 if OK

MQTT.Connect(login$, pass$ [,id$])

Connect to the server using the provided login and password.

Optionally id$ permit to define an arbitrary ID

Returns 0 if OK

MQTT.Connect("", "" [,id$])

Connect to the server without identification

Optionally id$ permit to define an arbitrary ID

Returns 0 if OK

MQTT.Disconnect[()]

Disconnects from the MQTT server

Returns 0 if OK

MQTT.Publish(topic$, message$ [,Qos] [,retain])

Publish a string message in the specified topic

Qos can be 0, 1 or 2; if not defined defaults to 0

‘retain’, if set to 1, the message is retained

Returns the msg_id of the message sent

MQTT.Subscribe(topic$ [,Qos])

Subscribes to messages published to the specified topic.

Qos can be 0, 1 or 2; if not defined defaults to 0

Returns 0 if OK

MQTT.UnSubscribe(topic$)

Unsubscribes from the specified topic

Returns 0 if OK

MQTT.Connected[()]

Returns the current connection status.

Returns 1 if connected or 0 if disconnected

MQTT.Status[()]

Returns the current status. It can be:

    MQTT_STATE_INIT = 0

    MQTT_STATE_DISCONNECTED = 1

    MQTT_STATE_CONNECTED = 2

    MQTT_STATE_WAIT_RECONNECT = 3

OnMQTT label

Define a label where the program will jump when an MQTT message is received

MQTT.Message$

Returns the MQTT message received

MQTT.Topic$

Returns the MQTT topic received or the event name.

The event can be:

 

Value

Event

_BEFORE_CONNECT_

Raised before the connection is done. Useful to determine if the module is trying to (re)connect

_CONNECTED_

Raised when the connection is done

_DISCONNECTED_

Raised when the connection is lost

_ERROR_

Raised in case of error

 

This is an example based on the free MQTT test server “test.mosquitto.org”.

The program subscribes and sends messages to the same “/AnnexTest” topic.

It should print the same messages that are sent to the server.

 

' MQTT SSL test program

' Using mosquitto test server

onmqtt mqtt_msg

print mqtt.setup("mqtts://test.mosquitto.org", 1)

print mqtt.connect("", "") ' No login / pass required

print mqtt.subscribe("/AnnexTest") ' subscribe to the topic /AnnexTest

 

for z = 1 to 10

  ' send messages to the topic /AnnexTest

  print mqtt.publish("/AnnexTest", "Annex"+str$(z))

  pause 100

next z

print ramfree

wait

' receive messages from the server

mqtt_msg:

print "TOPIC  : "; mqtt.topic$

print "MESSAGE: "; mqtt.message$

return

 

This is another example based on the free MQTT test server “test.mosquitto.org” or “mqtt.eclipseprojects.io”

It uses a certificate stored into an external file; it can be omitted removing the function mqtt.Certif

The program subscribes and sends several messages to several topics and receives them back.

This also shows how to use the event "_CONNECTED_" for starting the process.

' MQTT SSL test program

' Using mosquitto or eclipseprojects.io test server

' MQTT SSL DEMO

a$ = file.read$("/mosquitto.pem") ' reads the certificate from file

'a$ = file.read$("/eclipseprojects.pem") ' reads the certificate from file

onmqtt mqtt_event

print mqtt.setup("mqtts://test.mosquitto.org", 1) ' set debug

'print mqtt.setup("mqtts://mqtt.eclipseprojects.io:8883")

print mqtt.Certif(a$) ' set the certificate

print mqtt.connect("", "")

prev = ramfree

wait

 

mqtt_event:

print "event mqtt", MQTT.Topic$, MQTT.Message$

if (MQTT.Topic$ = "_CONNECTED_") then

   print "subscribe 0" , mqtt.subscribe("/AnnexTest/QOS0", 0)

   print "subscribe 1" , mqtt.subscribe("/AnnexTest/QOS1", 1)

   print "subscribe 2" , mqtt.subscribe("/AnnexTest/QOS2", 2)

   timer0 2000, publisher

end if

return

 

publisher:

  r$ = str$(rnd(10000))

  print mqtt.publish("/AnnexTest/QOS0", "Test 0 " + r$, 0)

  print mqtt.publish("/AnnexTest/QOS1", "Test 1 " + r$, 1)

  print mqtt.publish("/AnnexTest/QOS2", "Test 2 " + r$, 2)

  rf = ramfree

  print "ramfree ", rf, rf - prev

  prev = rf

return

 

 

This program is the same of the previous one but it uses a full authorisation using CA certificate, client certificate and client key stored into  external files

' MQTT SSL test program

' Using mosquitto test server

' MQTT SSL DEMO using full certificates

ca$ = file.read$("/mosquitto.org.crt") ' reads the certificate from file

cert$ = file.read$("/client.crt") ' read the client certificate from file

key$ = file.read$("/client.key") ' reads the key from file

onmqtt mqtt_event

print mqtt.setup("mqtts://test.mosquitto.org:8884", 1) ' set debug

print mqtt.Certif(ca$, cert$, key$) ' set the certificates

ca$ = "" : cert$ = "" : key$ = "" ' free these variables

print mqtt.connect("", "")

prev = ramfree(1)

wait

 

mqtt_event:

print "event mqtt", MQTT.Topic$, MQTT.Message$

if (MQTT.Topic$ = "_CONNECTED_") then

   print "subscribe 0" , mqtt.subscribe("/AnnexTest/QOS0", 0)

   print "subscribe 1" , mqtt.subscribe("/AnnexTest/QOS1", 1)

   print "subscribe 2" , mqtt.subscribe("/AnnexTest/QOS2", 2)

   timer0 2000, publisher

end if

return

 

publisher:

  r$ = str$(rnd(10000))

  print mqtt.publish("/AnnexTest/QOS0", "Test 0 " + r$, 0)

  print mqtt.publish("/AnnexTest/QOS1", "Test 1 " + r$, 1)

  print mqtt.publish("/AnnexTest/QOS2", "Test 2 " + r$, 2)

  rf = ramfree(1)

  print "ramfree ", rf, rf - prev

  prev = rf

return

 

MQTT Broker

An MQTT broker is a central component in MQTT-based communication systems, acting as an intermediary between devices that publish messages and those that subscribe to receive them. In the context of Annex RDS for ESP32, the MQTT broker is a simplified, lightweight implementation designed to run directly on the microcontroller.

This embedded MQTT broker provides core MQTT functionalities within the constraints of the microcontroller's resources. It can handle up to 12 connected devices simultaneously, making it suitable for small to medium-scale IoT applications. The broker manages client connections, handles message routing based on topics, and facilitates the publish/subscribe model of communication. Importantly, this broker supports Quality of Service (QoS) levels 0 and 1, allowing for flexible message delivery guarantees depending on the application's needs.

A unique feature of this implementation is that the broker itself can participate in the communication as if it were a pre-connected client. This means the broker can both subscribe to topics and publish messages, allowing it to listen for specific messages and respond or act upon them directly. This capability enables the ESP32 to not only mediate communication between other devices but also to be an active participant in the IoT ecosystem it manages.

Key features of this lightweight broker include:

     Managing up to 12 simultaneous client connections

     Processing basic MQTT commands (CONNECT, PUBLISH, SUBSCRIBE, etc.)

     Routing messages between publishers and subscribers

     Maintaining a list of topics and subscriptions

     Implementing basic authentication

     Acting as a client to subscribe and publish messages

     Supporting QoS levels 0 and 1 for message delivery

     Supports the Last Will Testament messages

     Supports messages up to :

     Client ID : 50 characters

     Topic : 100 characters

     Payload : 1024 characters

This lightweight broker enables ESP32 devices to act as central hubs in small-scale IoT networks, allowing for efficient, event-driven communication between multiple devices without the need for an external broker. It's particularly useful in scenarios where low latency, local processing, or offline operation is required, with the added benefit of the broker being able to actively participate in the communication flow. The support for QoS 0 and 1 ensures that users can choose between best-effort delivery and at-least-once delivery, depending on their specific application requirements.

MqttBroker.Setup(port, login$, password$ [, debug])

Set up the MQTT broker.

     port: Integer. The port number for the MQTT broker (default is 1883).

     login$: String. The login username for broker authentication. If it is an empty string (""), it will be ignored.

     password$: String. The password for broker authentication. If it is an empty string (""), it will be ignored.

         debug: Optional Boolean. Enable debug mode if set to 1.
Returns: 0 on success, -1 on failure.

Example

result = MqttBroker.Setup(1883, "user", "pass", 1)

 

MqttBroker.Start(ramsize)

Starts the MQTT broker task.

     ramsize: Integer. The stack size in bytes for the MQTT broker task.
Returns: 0 on success, -1 if the task is already running.

Example

result = MqttBroker.Start(20000)

 

 

MqttBroker.Stop

Stops the MQTT broker task.

Returns: 0 (always successful).

 

Example

result = MqttBroker.Stop

 

MqttBroker.Restart

Restarts the MQTT broker.

Returns: 0 (always successful).

 

Example

result = MqttBroker.Restart

 

MqttBroker.Publish(topic, payload[, qos[, retain]])

Publishes a message to a specified topic.

     topic$: String. The topic to publish to.

     payload$: String. The message content.

     qos: Optional Integer. Quality of Service level (0 or 1). Default is 0.

         retain: Optional Boolean. Whether to retain the message. Default is 0.
Returns: 0 (always successful).

Example

result = MqttBroker.Publish("sensors/temperature", "25.5", 1, 1)

 
MqttBroker.Subscribe(topic$)

Subscribes to a specified topic.

     topic$: String. The topic to subscribe to.

     The broker can manage up to 20 different topics.

Returns:

     0: Subscription successful.

     1: Topic already exists (already subscribed).

         -1: Cannot add more topics (maximum limit of 20 topics reached).

Example

 

result = MqttBroker.Subscribe("sensors/temperature")

IF result = 0 THEN

  PRINT "Successfully subscribed to topic"

ELSEIF result = 1 THEN

  PRINT "Already subscribed to this topic"

ELSEIF result = -1 THEN

  PRINT "Cannot subscribe: maximum number of topics reached"

ENDIF

 

 

Special Characters in Topics:

     '/': Used as a topic level separator.

     '#': Multi-level wildcard. Must be the last character in the topic string.

     '+': Single-level wildcard. Can be used at any level in the topic string.

Examples of topic patterns:

     "sensors/#": Subscribes to all topics under "sensors"

     "sensors/+/temperature": Subscribes to temperature topics for all sensors

     "home/+/room1/#": Subscribes to all messages for room1 in any house

 
MqttBroker.UnSubscribe(topic$)

Unsubscribes from a specified topic.

     topic: String. The topic to unsubscribe from.
Returns: 0 on success, -1 on failure.

Example

result = MqttBroker.UnSubscribe("sensors/temperature")

 
MqttBroker.ListTopics[(list$)]

 

Lists all subscribed topics by the server.

The list does not include the topics subscribed by the clients.

If the optional variable List$ is specified, it will contain the list of topics, separated by newlines (CHR$(10)).

Returns: Number of subscribed topics.

 

Example

topicCount = MqttBroker.ListTopics

Print topicCount

'or

topicCount = MqttBroker.ListTopics(topicList$)

Print topicList$

 

 
MqttBroker.ClearTopics

Clears all subscribed topics.

Returns: 0 (always successful).

 

Example

result = MqttBroker.ClearTopics

 

MqttBroker.ListClients[(list$)]

Lists all connected clients, including their IP address.

If the optional variable List$ is specified, it will contain the list of “client,ip” separated by newlines (CHR$(10)).

Returns: Number of connected clients.

 

Example

clientCount = MqttBroker.ListClients

Print clientCount

'or

clientCount = MqttBroker.ListClients(clientsList$)

Print clientsList$

 

OnMQTT Event Handler

The ONMQTT event handler allows you to respond to MQTT events, including incoming messages and connection status changes.

Syntax:

OnMQTT label

         label: The label where the program will jump when an MQTT event occurs.

Returns: Does not return a value.

 

Example

OnMQTT label

 

 

Event Information Variables

When an MQTT event occurs, you can access these special variables:

     MQTT.Topic$: Contains the topic of the received message or the name of the event.

     MQTT.Message$: Contains the payload of the received message or, for special events, the IP address of the client.

     MQTT.Client$: Contains the ID of the client connected to the broker.

Special Event Topics

MQTT.Topic$ can contain these special values for non-message events:

     "_CONNECTED_": Triggered when a connection is established

     "_DISCONNECTED_": Triggered when the connection is lost

     "_WRONG_LOGIN_": Triggered when the login credentials are incorrect

For these special events, MQTT.Message$ contains the IP address of the client.

 

Example Usage:

MyMqttHandler:

  PRINT "Client ID: "; MQTT.Client$

  IF MQTT.Topic$ = "sensors/temperature" THEN

    PRINT "Received temperature: "; MQTT.Message$

  ELSEIF MQTT.Topic$ = "_CONNECTED_" THEN

    PRINT "MQTT connection established for IP: "; MQTT.Message$

  ELSEIF MQTT.Topic$ = "_DISCONNECTED_" THEN

    PRINT "MQTT connection lost for IP: "; MQTT.Message$

  ELSEIF MQTT.Topic$ = "_WRONG_LOGIN_" THEN

    PRINT "Login failed for client IP: "; MQTT.Message$

  ENDIF

RETURN                                         

 

 

Disabling ONMQTT

To disable the ONMQTT event handler:

Example

OnMQTT OFF

 

Notes:

     All string arguments should be enclosed in quotes.

     Optional arguments are shown in square brackets [  ].

     The MQTT broker must be set up and started before using other functions.

     Error handling: If a function fails, it may return a negative value or set an error state. Check the return value or system error state after calling these functions.

     Always end your OnMQTT handler with a RETURN statement.

     Use special characters carefully to efficiently manage your subscriptions and avoid unnecessary message traffic.

 

Minimalist example of mini MQTT server

' Setup broker on port 1883 with login/password and debug mode enabled

print MqttBroker.Setup 1883, "mylogin", "mypass", 1 

 

' Start the MQTT broker with a stack size of 20000 bytes

print MqttBroker.Start 20000                        

                                          

 

 

Example of mini MQTT server tracking connection / disconnections

' Setup broker on port 1883 with login/password and debug mode enabled

print MqttBroker.Setup 1883, "mylogin", "mypass", 1 

 

' Start the MQTT broker with a stack size of 20000 bytes

print MqttBroker.Start 20000                        

 

' Set up the MQTT event handler to jump to 'doMQTT' when an event occurs

onMQTT doMQTT                                      

 

' Keep the program running indefinitely

wait                                                

 

' MQTT event handler for processing incoming messages

doMQTT:                                            

  ' Print the topic of the received message

  print "TOPIC === "; MQTT.Topic$                   

 

  ' Print the content of the received message

  print "MESSAGE = "; MQTT.Message$                  

 

  ' Print the ID of the client that sent the message

  print "CLIENT == "; mqtt.Client$                   

 

  ' Return from the event handler

return                                             

 

 

Complete example of mini MQTT server

' Setup broker on port 1883 with login/password and debug mode enabled

print MqttBroker.Setup 1883, "mylogin", "mypass", 1 

 

' Start the MQTT broker with a stack size of 20000 bytes

print MqttBroker.Start 20000                        

 

' Clear any existing topic subscriptions

print Mqttbroker.ClearTopics                        

 

' Subscribe to a simple topic

print Mqttbroker.Subscribe("/AnnexTest")            

 

' Subscribe using a single-level wildcard for temperature topics from Tasmota devices

print Mqttbroker.Subscribe("/tasmota/+/temperature")

 

' Subscribe using a multi-level wildcard for all messages in room1 of any home

print Mqttbroker.Subscribe("/home/+/room1/#")       

 

' List all currently subscribed topics

print mqttbroker.ListTopics                         

 

' Set up the MQTT event handler to jump to 'doMQTT' when an event occurs

onMQTT doMQTT                                      

 

' Keep the program running indefinitely

wait                                                

 

' MQTT event handler for processing incoming messages

doMQTT:                                            

  ' Print the topic of the received message

  print "TOPIC === "; MQTT.Topic$                   

 

  ' Print the content of the received message

  print "MESSAGE = "; MQTT.Message$                  

 

  ' Print the ID of the client that sent the message

  print "CLIENT == "; mqtt.Client$                   

 

  ' Return from the event handler

return                                             

 

 

 

ESP-NOW

ESP-NOW is a fast, connectionless communication technology featuring short packet transmission.

ESP-NOW is ideal for smart lights, remote control devices, sensors and other applications.

 

This is a special protocol developed by Espressif that enables the ESP8266 / ESP32  modules to communicate between themselves easily without any specific network connection (i.e. no router).

 

The modules (peers) can inter-communicate even if they are not connected on a common network, the unique requirement is to share the same Wifi radio channel.

 

Practically, each peer of the ESP-NOW network can send a message to any other peer(s) directly and very fast without establishing a network link before. After sending, it will be able to know if the message has been received

In the same way, it can also receive a message from any other peer.

 

The ESP-NOW is very fast and simple to put in place but there are the following limitations :

-       The max number of peers is 20

-       The transmitted message size can be max 250 characters

-       For the ESP32 it does not work in STA mode (only in AP+STA mode) when used in combination with the ESP8266 (works OK between ESP32 only)

 

The ESP-NOW network does not use TCP/IP, so uses the peers MAC addresses to communicate instead of IP addresses.

 

As Annex is very versatile, a network module can use its wifi interface for ESP-NOW and for standard routed IP WiFi networking, so it can communicate with both types of network modules, allowing it to function as a kind of “Gateway” between ESP-NOW and routed WiFi.

Each module (peer) holds a list of ‘receivers” containing the MAC addresses of all the peers that will receive a message when using the command EspNow.Write(msg$)

 

Functions and commands available :

 

FUNCTIONS / COMMANDS

DESCRIPTION

EspNow.Begin

starts the ESP-NOW communications

EspNow.Stop

stops the ESP-NOW communications

EspNow.Add_Peer(MAC_add$ [,interface] [,channel])

add a peer (module) to the ‘receiver’ list

where interface is 0 = AUTO (default), 1=STA, 2=AP

and channel is any valid channel numbers or 0 = current channel (default)

EspNow.Del_Peer

delete a peer (module) from the ‘receiver’ list

EspNow.Write(msg$)

write a message to the peers defined in the list

EspNow.Write(msg$, MAC_add$)

write a message to a specific peer defined by its MAC address

All these functions return a value; a non-zero value indicates that an error has occurred.

If the returned value is not required, the functions can be used as commands without reading into a variable.

Example :

Ret = EspNow.Write(msg$)                 used as function

EspNow.Write msg$               used as command (without brackets)

 

 

STRING FUNCTIONS

DESCRIPTION

EspNow.READ$

Read the message received

ESPNow.REMOTE$

Read the MAC address of the emitter of the message received

ESPNow.ERROR$

Read the MAC address of the device(s) that didn’t received the message

All these functions return a string value

 

 

EVENTS

DESCRIPTION

OnEspNowMsg label

Trigger an event each time a message is received

OnEspNowError label    

Trigger an event each time that a transmission error occurs.

This happen, in particular, when the receiver device has not received the message

 

 

These pictures shows some 3 typical ESP-NOW communication models:

image

 

image

 

image

 

 

Let’s see an example with 3 modules with 2 acting like sensors and the 3rd as receiver.

The sensor modules will send a message each second to the receiver.

The receiver will print these messages in the console.

image

Code for the SENSOR1 module

'ESP-NOW sensor1 example

RECEIVER_MAC$ = "60:01:94:51:D0:7D" ' MAC address of the receiver

print "init " ; espnow.begin  ' should print 0 if all OK

espnow.add_peer RECEIVER_MAC$    ' set the address of the receiver

onEspNowError status ' set the place where jump in case of TX error

timer0 1000, sendMessage ' trigger a message at each second

wait

 

sendMessage:

espnow.write "Sensor 1 : " + str$(rnd(1000)) ' send the message

return

 

status:

print "TX error on "; espnow.error$  ' print the error

return

 

 

Code for the SENSOR2 module

'ESP-NOW sensor2 example

RECEIVER_MAC$ = "60:01:94:51:D0:7D" ' MAC address of the receiver

print "init " ; espnow.begin  ' should print 0 if all OK

espnow.add_peer RECEIVER_MAC$    ' set the address of the receiver

onEspNowError status ' set the place where jump in case of TX error

timer0 1000, sendMessage ' trigger a message at each second

wait

 

sendMessage:

espnow.write "Sensor 2 : " + str$(rnd(1000)) ' send the message

return

 

status:

print "TX error on "; espnow.error$  ' print the error

return

 

 

Code for the RECEIVER module

'ESP-NOW receiver example

print "init " ; espnow.begin  ' should print 0 if all OK

onEspNowMsg message ' set the place where jump in case of message reception

wait

 

message:

print "RX:"; espnow.read$; " from "; espnow.remote$ ' print the message

return

 

Let’s see another example always with 2 sensors and one receiver.

In this case the receiver will retransmit back to the sensor 1 the message received.

This means that the sensor 1 will receive the message coming from the sensor 2 and also its own message.

The sensor 1 and the receiver will print the messages received in the console

image

Code for the SENSOR1 module

'ESP-NOW sensor example

RECEIVER_MAC$ = "60:01:94:51:D0:7D"

print "init " ; espnow.begin  ' should print 0 if all OK

espnow.add_peer RECEIVER_MAC$    ' set the address of the receiver

onEspNowMsg message ' set the place where jump in case of message reception

onEspNowError status ' set the place where jump in case of TX error

timer0 1000, sendMessage ' trigger a message at each second

wait

 

sendMessage:

espnow.write "Sensor 1 : " + str$(rnd(1000)) ' send the message

return

 

message:

print "RX:"; espnow.read$; " from "; espnow.remote$ ' print message

return

 

status:

print "TX error on "; espnow.error$  ' print the error

return

 

 

Code for the SENSOR2 module

'ESP-NOW sensor2 example

RECEIVER_MAC$ = "60:01:94:51:D0:7D" ' MAC address of the receiver

print "init " ; espnow.begin  ' should print 0 if all OK

espnow.add_peer RECEIVER_MAC$    ' set the address of the receiver

onEspNowError status ' set the place where jump in case of TX error

timer0 1000, sendMessage ' trigger a message at each second

wait

 

sendMessage:

espnow.write "Sensor 2 : " + str$(rnd(1000)) ' send the message

return

 

status:

print "TX error on "; espnow.error$  ' print the error

return

 

 

Code for the RECEIVER module

'ESP-NOW receiver example #2

SENSOR1_MAC$ = "68:C6:3A:C3:06:DB"

print "init " ; espnow.begin  ' should print 0 if all OK

espnow.add_peer SENSOR1_MAC$    ' set the address of the sensor 1

onEspNowMsg message ' set the place where jump in case of message reception

wait

 

message:

msg$ = espnow.read$

rem$ = espnow.remote$

print "RX:"; msg$; " from "; rem$

ret = espnow.write( msg$ + " Transferred from " + rem$ ) ' transfer the message received

return

 

status:

print "TX error on "; espnow.error$ ' print the message

return

 

Let’s see now another example where a sensor will send a message to 2 receivers :

 image

Code for the SENSOR module

'ESP-NOW sensor example

RECEIVER1_MAC$ = "60:01:94:51:D0:7D"

RECEIVER2_MAC$ = "68:C6:3A:C3:06:DB"

print "init " ; espnow.begin  ' should print 0 if all OK

espnow.add_peer RECEIVER1_MAC$    ' set the address of the receiver 1

espnow.add_peer RECEIVER2_MAC$    ' set the address of the receiver 2

onEspNowError status ' set the place where jump in case of TX error

timer0 1000, sendMessage ' trigger a message at each second

wait

 

sendMessage:

espnow.write "Sensor : " + str$(rnd(1000)) ' send the message

return

 

status:

print "TX error on "; espnow.error$  'print the error

return

 

 

Code for the RECEIVER 1 module

'ESP-NOW receiver example

print "init " ; espnow.begin  ' should print 0 if all OK

onEspNowMsg message ' set the place where jump in case of message reception

wait

 

message:

print "RX:"; espnow.read$; " from "; espnow.remote$ ' print the message

return

 

 

Code for the RECEIVER 2 module

'ESP-NOW receiver example

print "init " ; espnow.begin  ' should print 0 if all OK

onEspNowMsg message ' set the place where jump in case of message reception

wait

 

message:

print "RX:"; espnow.read$; " from "; espnow.remote$ ' print the message

return

 

—--------------

BLUETOOTH Low Energy (BLE)[4] 

Overview

The ESP32 supports Bluetooth Low Energy (BLE), operating alongside WiFi, allowing mobile devices such as smartphones, tablets, and computers to connect. Both free (open) and secure (password-protected) connections are supported.

Operating Modes

     Server Mode:
In this mode, other devices can connect to the ESP32. This is a primary mode for BLE on the ESP32.

     Client Mode:
In client mode, the ESP32 can connect to other BLE server devices, such as BLE keyboards, sensors, or other peripherals, enabling versatile two-way communication.

     Scan:
The ESP32 can scan for all nearby BLE devices, identifying those within range for potential connections.

Server Mode

UUIDs and Characteristics

The ESP32 is recognized as a Nordic UART device with the following UUIDs:

     Service UUID: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
Identifies the BLE service on the ESP32 as a Nordic UART service.

     Characteristic UUIDs:

     RX Characteristic UUID: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E
Purpose: Used to receive messages from the connected BLE client. Messages can be up to 512 characters long.
Note: When defined as part of the BLE service, this UUID allows message reception through the ONBLUETOOTH event.

     TX Characteristic UUID: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E
Purpose: Used to send notifications (messages) from the ESP32 to the connected BLE client. The maximum message length is 20 characters. This is the faster and preferred method of communication.

Communication Details

     Service UUID:
Used to identify the ESP32 as a Nordic UART device. Devices can discover this service and interact with the associated characteristics.

     RX Characteristic:
Used to receive data from the connected BLE client. The maximum message length is 512 characters.

     TX Characteristic:
Used for sending notifications from the ESP32 to the connected BLE client, with a maximum message length of 20 characters. This method is fast and efficient for real-time communication.

BLE Commands / Functions

The following commands are available for setting up and managing the BLE functionality:

BLUETOOTH.SETUP "devicename" [, code]

Sets the name of the BLE device as visible to other devices. An optional pin code can be set for secure connections. The pin must be a 6-digit number; if a shorter number (e.g., 1) is set, it will be interpreted as 000001.
Example Usage:

'Sets the BLE device name to "ESP32_Device" with no pin code.

BLUETOOTH.SETUP "ESP32_Device"

' Sets the BLE device name to "ESP32_Device" with the pin code 123456.

BLUETOOTH.SETUP "ESP32_Device", 123456

 

BLUETOOTH.CLEAR

Clears the BLE configuration, freeing up approximately 20KB of RAM. An error message might appear in the console, but this is normal and can be ignored.

BLUETOOTH.DELETE

Deletes the BLE configuration, freeing up approximately 40KB of RAM. After executing this command, the BLE cannot be used again without restarting the ESP32 module. This is applicable only to the “classic ESP32.”

BLUETOOTH.POWER pow

Sets the output power level from 0 to 7, corresponding to -12dBm to +9dBm.

BLUETOOTH.WRITE "text"

Writes a text message to the connected device using the notification channel.

BLUETOOTH.READ$

Returns a text message from the connected device.

BLUETOOTH.LEN

Returns the length of the message received from the connected device.

BLUETOOTH.CONNECTED

Returns 1 if a device is connected, or 0 if not.

BLUETOOTH.STATUS

Returns the status of the BLE connection, useful in event handling.

Possible return values:

 

0: None

1: Device connected

2: Device disconnected

3: Message received in server mode

4: Scan terminated

5: Message received in client mode

BLUETOOTH.WRITE_IOBUFF(buff_num [, start [, size]])

Writes data from an IO BUFFER to the connected device using the notification channel.

BLUETOOTH.READ_IOBUFF(buff_num)

Reads data into an IO BUFFER from the connected device.

BLUETOOTH.SCAN time

Initiates a BLE scan for time seconds.

BLUETOOTH.SCANRESULT$

Returns the list of devices found during the scan in JSON format.

Client Mode Functions

The following commands support BLE client mode functionality, enabling the ESP32 to connect to external BLE server devices:

BLUETOOTH.CLIENT mac, service_UUID, characteristic_UUID

Connects the ESP32 to a BLE server device with the specified MAC address, service UUID, and characteristic UUID. This command is essential for establishing direct communication with specific BLE peripherals, such as sensors or keyboards.
Note: The mac address for this command can be obtained by performing a BLUETOOTH.SCAN, which lists nearby BLE devices along with their MAC addresses. Additionally, when the characteristic UUID is defined in BLUETOOTH.CLIENT, it enables message reception via the ONBLUETOOTH event, similar to the RX Characteristic UUID.

BLUETOOTH.CLWRITE characteristic_UUID, "text"

Writes a text string to the specified characteristic UUID on the connected BLE server.

BLUETOOTH.CLWRITE_IOBUFF characteristic_UUID, (buff_num [, start [, size]])

Writes data from an IO BUFFER to a characteristic on the connected BLE server, useful for managing binary data transfers.

Event Handling

The ESP32 provides an event mechanism to handle BLE-related events asynchronously:

ONBLUETOOTH label

Defines the event routine for Bluetooth (BLE) operations. The BLUETOOTH.STATUS function is useful within this event handler to determine the specific type of event that occurred.

Examples for the Server Mode:

print ramfree(1) 'ramfree before

onbluetooth ble_receive

bluetooth.setup "bleServer", 1

print ramfree(1) 'ramfree after

 

IOBUFF.DIM(1, 10) = 65, 66, 67, 68, 69, 70, 71, 72, 73, 74

 

timer0 500, send_msg

wait

 

Send_msg:

  'bluetooth.write_iobuff(1, 5, 2)

  bluetooth.write "_" + str$(rnd(1000)) + chr$(10)

return

 

ble_receive:

  print bluetooth.len, bluetooth.status

  if bluetooth.status = 3 then

    bluetooth.read_iobuff(0)

    for z = 1 to iobuff.len(0)

      print iobuff.read(0, z-1),

    next z

    print

  end if

return

 

 

Receiving parameters from Xiaomi Mijia “Hacked” temperature sensors where the information are included into the Advertising message

wlog ramfree(1)

onbluetooth ble_receive

bluetooth.scan 10

 

z = 1

while 1

  while (bluetooth.status <> 4)

    print z

    pause 100

    z = z + 1

  wend

  gosub ble_receive

  bluetooth.scan 10

wend

wait

 

ble_receive:

  'print bluetooth.len, bluetooth.status

  select case bluetooth.status

  case 1: print "BLE Device Connected"

  case 2: print "BLE Device Disconnected"

  case 3:

      bluetooth.read_iobuff(0)

      for z = 1 to iobuff.len(0)

        print iobuff.read(0, z-1),

      next z

      print

  case 4:

      print "scan terminated"

      a$ = bluetooth.scanresult$

     ' wlog a$

      sens1$ = json$(a$, "ATC_941E4C.Data")

      extract_params sens1$, "Bedroom"

      sens2$ = json$(a$, "ATC_C5C5B9.Data")

      extract_params sens2$, "Kitchen"

      bluetooth.scan 10 ' restart the scan

end select

return

 

sub extract_params (sens$, id$)

  if (sens$ <> "not found") then

    a = iobuff.fromhex(0, sens$)

    temp = iobuff.read(0, 6) * 256 + iobuff.read(0, 7)

    if (temp > 32767) then temp =  temp - 65536

    hum =  iobuff.read(0, 8)

    batt = iobuff.read(0, 9)

    cnt =  iobuff.read(0, 12)

    wlog "sensor: "; id$, "humidity "; hum, "Temperature "; temp/10, "Battery "; batt, "counter ";cnt

  endif

end sub

 

Example for the client mode

bluetooth.clear

onbluetooth ble_receive

bluetooth.scan 5

pause 6000

' this is the mac address of an HLK LD2450

bluetooth.client "13:BC:0F:4E:67:E8", "FFF0", "FFF1"

wait

 

ble_receive:

print bluetooth.len, bluetooth.status, ramfree(1)

select case bluetooth.status

  case 1

    print "------>Device Connected"

  case 2

    print "======<Device Disconnected"   

  case 4

    a$ = bluetooth.scanresult$

    wlog a$

   

  case 5

    bluetooth.READ_IOBUFF(0)

    print iobuff.tohex$(0)

 

end select

 

return

 

Example with the extraction of parameters using IoBuffers

bluetooth.clear

onbluetooth ble_receive

bluetooth.scan 5

pause 6000

' this is the mac address of an HLK LD2450

bluetooth.client "13:BC:0F:4E:67:E8", "FFF0", "FFF1"

wait

 

ble_receive:

print bluetooth.len, bluetooth.status, ramfree(1)

select case bluetooth.status

  case 1

    print "------>Device Connected"

  case 2

    print "======<Device Disconnected"

  case 4

    a$ = bluetooth.scanresult$

    wlog a$

   

  case 5

    bluetooth.READ_IOBUFF(0)

    print iobuff.tohex$(0)

    if iobuff.len(0) = 30 then

      buff$ = iobuff.tohex$(0)

      k = iobuff.read(0,4) + iobuff.read(0,5) * 256

      if (k > 32767) k = -k+32768

      x = k

      k = iobuff.read(0,6) + iobuff.read(0,7) * 256

      if (k > 32767) k = -k+32768

      y = k

      k = iobuff.read(0,8) + iobuff.read(0,9) * 256

      if (k > 32767) k = -k+32768

      speed = k

      dist = sqr(x^2 + y^2)

      k = iobuff.read(0,10) + iobuff.read(0,11) * 256

      if (k > 32767) k = -k+32768     

      r = k

      print x, y, speed, dist, r

    end if

end select

return

 

TELEGRAM (messenger) support

Annex implements the direct support for the TELEGRAM messenger

 

Using these commands/functions it is possible to:

 

-       Send full text messages

-       Send html styled text messages

-       Get user Ident

-       Get text messages

-       Get text messages async

-       Send Images

 

For more information please refer to the official telegram API

https://core.telegram.org/bots/api

 

The commands are :

Set the Telegram Token ID

TELEGRAM.SetToken "token"

 

Set the operating mode

TELEGRAM.SetMode 0  'set the basic https communications (this is the default)

TELEGRAM.SetMode 1  'set the https communication using a certificate (internal)

 

Set the max time that the commands will wait for an answer from the telegram server

TELEGRAM.SetWait 10 ‘ set the max time at 10 seconds (the default is 10 seconds)

 

Receive incoming messages update in json format but in async mode.

It uses the same event ONWGETASYNCused by the command WGETASYNC

TELEGRAM.getUpdatesAsync

 

The functions are :

 

A simple method for testing your bot's auth token. Returns basic information about the bot in form of a User object.

ret$ = TELEGRAM.getMe$

 

Send a text message. If the optional html is 1, the text can be formatted using some html tags

ret$ = TELEGRAM.sendMessage$( chat_id, "message" [, html] )

More informations here https://core.telegram.org/bots/api#html-style

 

Receive incoming messages update in json format

ret$ = TELEGRAM.getUpdates$

 

Send an image; the image can be in jpeg, bmp, gif or png format

ret$ = TELEGRAM.sendImage$( chat_id, image_path$)

 

Example of basic commands

telegram.settoken "1234567890:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"

telegram.setwait 10

telegram.setmode 0

 

wlog telegram.getMe$ 'get the user’s informations

wlog telegram.getUpdates$ 'get the new messages

 

'Send a message to the chat_id 1234567890

wlog telegram.sendmessage$(1234567890, "Hello, world! " + str$(rnd(1000)))

 

'Send pictures from the disk to the chat_id 1234567890

wlog telegram.sendimage$(1234567890, "/images/sam.png")

wlog telegram.sendimage$(1234567890, "/images/poisson.bmp")

 

'Prepare an HTML formatted message

nl$ = chr$(10)

b$ = ||

b$ = b$ + |<b>bold</b>, <strong>bold</strong>| + nl$

b$ = b$ + |<i>italic</i>, <em>italic</em>| + nl$

b$ = b$ + |<u>underline</u>, <ins>underline</ins>| + nl$

b$ = b$ + |<s>strikethrough</s>, <strike>strikethrough</strike>, <del>strikethrough</del>| + nl$

b$ = b$ + |<b>bold <i>italic bold <s>italic bold strikethrough</s> <u>underline italic bold</u></i> bold</b>| + nl$

b$ = b$ + |<a href='http://www.example.com/'>inline URL</a>| + nl$

b$ = b$ + |<a href='tg://user?id=123456789'>inline mention of a user</a>| + nl$

b$ = b$ + |<code>inline fixed-width code</code>| + nl$

b$ = b$ + |<pre>pre-formatted fixed-width code block</pre>| + nl$

b$ = b$ + |<pre><code class='language-python'>pre-formatted fixed-width code block written in the Python programming language</code></pre>|

 

'Send the message in HTML format

wlog telegram.sendmessage$(1234567890, b$, 1)

 

end

 

 

Example of echo bot (reply the command received)

telegram.settoken "1234567890:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"

telegram.setwait 10

telegram.setmode 0

 

onwgetasync asynco

'Get the update each 5 seconds

timer0 5000, getmessages

wait

 

getmessages:

telegram.GetUpdatesAsync

return

 

'Receive the messages

asynco:

r$ = WGETRESULT$

wlog r$

text$ = json$(r$, "text")

if (text$ <> "not found") then

  c$ = json$(r$, "chat.id")   'get the chat_id

  wlog telegram.sendmessage$(val(c$), "echo : " + text$)

end if

return

 

LORA

LoRa is a wireless modulation technique derived from Chirp Spread Spectrum (CSS) technology. It encodes information on radio waves using chirp pulses - similar to the way dolphins and bats communicate!

LoRa modulated transmission is robust against disturbances and can be received across great distances.

LoRa is ideal for applications that transmit small chunks of data with low bit rates. Data can be transmitted at a longer range compared to technologies like WiFi, Bluetooth or ZigBee.

These features make LoRa well suited for sensors and actuators that operate in low power mode.

LoRa can be operated on the license free sub-gigahertz bands, for example, 915 MHz, 868 MHz, and 433 MHz.

A detailed description on LoRa can be found here

 

The WiFi LoRa 32 module is supported, which includes the SX127x Heltec Module.

This module includes the SX127x LoRa modules

 

image

 

As it has a specific configuration for the SPI bus, the Config Menu includes a dedicated choice

image

An SDCard can be connected on the module using the following pinout :

image

 

The OLED display present on the module is supported with the OLED.xxx functions already implemented.

As this OLED has an additional RST pin, the corresponding GPIO16 must be put to 1 before use.

 

FUNCTIONS / COMMANDS

DESCRIPTION

LoRa.Setup ss, reset, dio0

Defines the pins to be used for the module SX127x.

The SPI pins are the default pins defined for the module

LoRa.Begin(freq)

Initialise the driver with the specified frequency.

The frequency must be specified in Hz.

Returns 1 if OK or 0 in case of error.

Example

Print LoRa.Begin(886e6) ‘for 886 Mhz

LoRa.End

Terminates the operations

LoRa.BeginPacket

Start the sequence of sending a packet.

Returns 1 if OK or 0 in case of error.

LoRa.Print

Write a message into the lora packet

Returns the number of character written

LoRa.EndPacket

Terminate the packet and send it

LoRa.Receive

Puts the radio in continuous receive mode

LoRa.RSSI

Returns the RSSI of the received packet

LoRa.SNR

Returns the estimated SNR of the received packet in dB

LoRa.Idle

Put the radio in idle (standby) mode.

LoRa.Sleep

Put the radio in sleep mode.

LoRa.TXpower pow

Change the TX power of the radio.

Can be from 0 to 20 dBm

The default value is`14`

LoRa.SpreadFactor factor

Change the spreading factor of the radio.

Supported values are between `6` and `12`

The default value is`11`

LoRa.SignalBandwidth band

Change the signal bandwidth of the radio (in Hz)

Supported values are `7.8E3`, `10.4E3`, `15.6E3`, `20.8E3`, `31.25E3`, `41.7E3`, `62.5E3`, `125E3`, and `250E3`.

The default value is`125E3`

LoRa.CodingRate rate

Change the coding rate of the radio.

Supported values are between `5` and `8`, these correspond to coding rates of `4/5` and `4/8`. The coding rate numerator is fixed at `4`.

The default value is ‘5’

LoRa.PreambleLen len

Change the preamble length of the radio.

Supported values are between `6` and `65535`.

The default value is ‘8’

LoRa.SyncWord word

Change the sync word of the radio.

‘Word’ is a byte value to use as the sync word

The default value is `&h34`

LoRa.EnableCRC enable

Enable or disable CRC usage

‘enable’ can be 1 or 0 (enable / disable)

By default a CRC is not used.

OnLora

Define a label where the program will jump when an LoRa message is received

The script branch must be terminated with ‘RETURN’. 

To disable OnLora OFF

LoRa.Message$

Returns the LoRa message received

 

 

Examples

 

Simple transmitter program

' LoRa test program

' Using the WIFI LoRa 32 module

' Send a simple message to the receiver

' use the default values

LoRa.Setup 18, 14, 26  ' SS, RESET, DIO0

print LoRa.Begin(886e6) ' 886 MHz

for pkt = 1 to 10000

  LoRa.BeginPacket

  LoRa.Print "SEND:" + str$(pkt)

  LoRa.EndPacket

  pause 1000

next pkt

 

Simple receiver program

' LoRa test program

' Using the WIFI LoRa 32 module

' Receive a simple message from the sender

' and prints in the wlog console

' use the default values

LoRa.Setup 18, 14, 26  ' SS, RESET, DIO0

print LoRa.Begin(886e6) ' 886 MHz

onLoRa receive

LoRa.Receive

wait

 

receive:

r$ = LoRa.Message$

wlog r$, ramfree, LoRa.RSSI, LoRa.SNR

return

 

More complex example using OLED with transmission and receptions

' LoRa test program

' Using the WIFI LoRa 32 module

' Send and receive messages to another module

' running the same code

'''''''''''''''''''''''''

' set the RST pin of the OLED to 1

pin.mode 16, output

pin(16) = 1

I2C.SETUP 4, 15 ' set I2C port on pins 4 and 15

Oled.Init 2, 1 ' initialise the OLED

Oled.Cls ' clear the screen

Oled.Font 2

Oled.Color 1

Oled.Print 0, 10, "LORA XMT/RCV"

 

pin.mode 25, output ' enable the internal white led

 

LoRa.Setup 18, 14, 26  ' SS, RESET, DIO0

print LoRa.Begin(886e6) ' 886 MHz

LoRa.SpreadFactor 7

LoRa.SignalBandwidth 125e3

LoRa.SyncWord &h88 'default if &h34

LoRa.TXpower 020

onLoRa receive

LoRa.Receive

pkt = 0

timer0 1000, send 'send a message each second

wait

 

receive:

r$ = LoRa.Message$

print r$, ramfree, LoRa.RSSI, LoRa.SNR

Oled.Cls

Oled.Font 2

Oled.Print 0, 10, "LORA XMT/RCV"

Oled.Font 1

Oled.Print 0, 30, r$

 

Oled.Print 0, 40, "RSSI: " + str$(LoRa.RSSI)

Oled.Print 0, 50, "SNR:  " + str$(LoRa.SNR)

pin(25) = 1 ' blinks the internal white led

Oled.Refresh 0

pause 100

pin(25) = 0

return

 

send:

  LoRa.BeginPacket

  LoRa.Print "SEND:" + str$(pkt) + " " + str$(LoRa.RSSI)

  LoRa.EndPacket

  pkt = pkt + 1

return

 

Modbus

Annex implements support for MODBUS TCP in client mode. The underlying library (eModbus) is built on an asynchronous model where all communication occurs in separate tasks, enabling Modbus requests and responses to be non-blocking. Answer reception is handled asynchronously via an event (the WGETASYNC event). To maintain simplicity, only a select few commands have been implemented, each with a simple syntax.

 

The command MODBUS.CONNECT is used to establish a connection to a Modbus device or server. It requires specifying the IP address of the device.

Optionally, you can also specify the port number to connect to. Additionally, you can configure timeout and idle timeout parameters to control how long the system waits for responses and when it considers a connection idle. These settings help manage communication and resource usage efficiently.

 

The complete syntax is :

MODBUS.CONNECTIP$, [port] [,timeout] [,idleTimeout]

Where:

         IP$: This parameter specifies the IP address of the device or server to which the Modbus connection will be established. It's a required parameter, as it defines the target for the connection.

         port: This optional parameter specifies the port number to connect to on the target device. If not provided, it defaults to the standard Modbus TCP port (port 502). It allows for connecting to a specific port if the Modbus server is configured to listen on a non-standard port.

         timeout: This optional parameter defines the maximum time the library will wait for a response after sending a request. If not provided, it uses a default timeout value of 2000ms (2sec). It ensures that the communication doesn't hang indefinitely waiting for a response from the server.

         idleTimeout: This optional parameter sets the duration of inactivity allowed before considering the connection idle and potentially closing it. If not provided, the library uses a default idle timeout value of 60000ms (60sec). It helps in managing resources by closing connections that are inactive for a specified period.

To disconnect from the device or server, the command is

MODBUS.DISCONNECT

To note that the disconnection will happen automatically after an idleTimeout period of inactivity (by default 60 seconds)

 

The token concept

The token concept involves assigning a user-defined token value to each request. This token is associated with the request and is subsequently returned in the callback. The token remains unchanged throughout the process, allowing users to easily correlate requests with their corresponding responses.

 

Consider an application with multiple ModbusClients, each interacting with different types of Modbus servers or with several async requests enqueued. If you wish to handle all responses with a single event function, irrespective of the server origin, distinguishing between responses becomes essential.

 

By utilising the token assigned during request initiation, you can precisely identify and match responses to their respective requests, regardless of the server they originate from.

 

Requests

Annex implements a common MODBUS.REQUEST command to set up and enqueue a request.

 

MODBUS.REQUEST token, serverID, functionCode [,p1] [,p2] [,p3]

This command enables the sending of various kinds of requests depending on the number of arguments specified. The request is added to a queue of a maximum of 100 elements, and control is returned to the program without blocking the execution. In async mode, the library will send the elements present in the queue depending on the capacity of the device or server.

The token argument is a 32-bit number provided at request time, which will be returned exactly as it is in the response.

The argument serverID must be an 8-bit number, while the argument functionCode must contain a value as defined in the table below :

FUNCTION CODE

VALUE

ANY_FUNCTION_CODE     

&h00

READ_COIL             

&h01

READ_DISCR_INPUT      

&h02

READ_HOLD_REGISTER    

&h03

READ_INPUT_REGISTER   

&h04

WRITE_COIL            

&h05

WRITE_HOLD_REGISTER   

&h06

READ_EXCEPTION_SERIAL 

&h07

DIAGNOSTICS_SERIAL    

&h08

READ_COMM_CNT_SERIAL  

&h0B

READ_COMM_LOG_SERIAL  

&h0C

WRITE_MULT_COILS      

&h0F

WRITE_MULT_REGISTERS  

&h10

REPORT_SERVER_ID_SERIAL

&h11

READ_FILE_RECORD      

&h14

WRITE_FILE_RECORD     

&h15

MASK_WRITE_REGISTER   

&h16

R_W_MULT_REGISTERS    

&h17

READ_FIFO_QUEUE       

&h18

ENCAPSULATED_INTERFACE

&h2B

USER_DEFINED_41       

&h41

USER_DEFINED_42       

&h42

USER_DEFINED_43       

&h43

USER_DEFINED_44       

&h44

USER_DEFINED_45       

&h45

USER_DEFINED_46       

&h46

USER_DEFINED_47       

&h47

USER_DEFINED_48       

&h48

USER_DEFINED_64       

&h64

USER_DEFINED_65       

&h65

USER_DEFINED_66       

&h66

USER_DEFINED_67       

&h67

USER_DEFINED_68       

&h68

USER_DEFINED_69       

&h69

USER_DEFINED_6A       

&h6A

USER_DEFINED_6B       

&h6B

USER_DEFINED_6C       

&h6C

USER_DEFINED_6D       

&h6D

USER_DEFINED_6E       

&h6E

 

If you specify an invalid server ID or a Modbus standard function code taking a different number of parameters, an error message is sent to Serial and the message is not generated.

Parameters to known standard Modbus messages are checked for conformity.

Message with no parameter

MODBUS.REQUEST token, serverID, functionCode

This is usable to set up Modbus standard messages for the Modbus function codes requiring no additional parameter, as 0x07, 0x0B, 0x0C and 0x11.

 

Message with 1 parameter

MODBUS.REQUEST token, serverID, functionCode, p1

There is one standard Modbus message requiring exactly one 16 bit parameter: &h18, READ_FIFO_QUEUE. This format will help set it up correctly, but of course may be used for any other proprietary function code with the same signature. Please note that in this case the p1 parameter will not be range-checked.

 

Message with 2 parameters

MODBUS.REQUEST token, serverID, functionCode, p1, p2

This format will be one of the most used throughout, as the most relevant Modbus messages have this signature (taking two 16 bit parameters).

These are the Function Codes &h01, &h02, &h03, &h04, &h05 and &h06.

 

Message with 3 parameters

MODBUS.REQUEST token, serverID, functionCode, p1, p2, p3

Modbus standard function code &h16 (MASK_WRITE_REGISTER) does take three 16 bit arguments.

 

Sending Custom Messages

In addition to the standard Modbus commands, there's also a provision for sending custom messages.

This is facilitated by another variant of this command, which allows for the transmission of raw messages in the form of a sequence of hex bytes directly onto the Modbus bus.

 

The exact syntax for sending a raw message is:

MODBUS.REQUEST token, raw_message$

Where

     token is the token used for the request

     raw_message$ is a string composed of a sequence of hex bytes, such as "01 03 00 FD 00 01". The spaces are optional and can be removed (i.e. “01 03 00 FD 00 01” or “010300FD0001” are equivalent). The CRC (Cyclic Redundancy Check) is automatically calculated.

 

This feature provides flexibility for implementing custom communication protocols or executing advanced operations that may not be covered by the standard Modbus commands.

 

Modbus RTU Support

Additionally, support is extended to Modbus RTU, a widely used variant of the Modbus protocol. Modbus RTU operates over serial communication, making it suitable for applications where wired connections are preferred or where long-distance communication is required. It offers robustness and reliability, especially in industrial environments.

The command modbus.setupRTU is used to configure the RTU interface connection.

The syntax is as follows:

 

MODBUS.SetupRTURX_pin, TX_pin, RE_DE_pin, ["BBBB,P,D,S"]

Where:

 

         RX_pin: The pin used for receiving data.

         TX_pin: The pin used for transmitting data.

         RE_DE_pin: The pin where the RE/DE wire of the attached RS485 adapter is connected

         BBBB: Defines the baud rate, which can be any valid serial speed (e.g., 9600, 19200, ..., 115200).

         P: Specifies the parity, which can be N (None), E (Even), or O (Odd).

         D: Indicates the number of data bits, which can be 7 or 8.

         S: Denotes the number of stop bits, which can be 1 or 2.

By default, the configuration is set to "9600,N,8,1".

 

Modbus RTU utilises RS485 for serial communication. While microcontrollers typically use UART for serial communication, an external RS485 adapter is necessary for Modbus RTU. These adapters convert UART signals to the electrical specifications of RS485, enabling communication over extended distances and with multiple devices on the bus due to its differential signalling.  RS485 adapters are readily available and cost-effective.

 

Similar to Modbus TCP, Modbus RTU operates asynchronously. Reception of data also occurs asynchronously using the same event mechanism, ensuring a consistent approach to communication handling across both protocols. Modbus RTU also leverages the same concept of tokens, where communication tasks are executed independently, promoting efficiency and reliability.

 

To send messages, the same logic of MODBUS.REQUEST is applied, except that the command is named

MODBUS.requestRTU ….. (see the details in the chapter above)

This ensures uniformity in the command structure while facilitating communication over Modbus RTU.

 

Reception of the data

The reception of the data happens inside a WGETASYNC event and the message can be retrieved inside the variable WGETRESULT$

The received message is composed of a sequence of hexadecimal bytes (2 hex chars) separated by spaces.

This is an example of received message, correspondent to the request MODBUS.REQUEST 1234, 1, 3, 5:

1234 01 03 02 00 01

Each message starts with the token used in the corresponding request (1234) followed by the message content (01 03 02 00 01).

The content always starts with the serverID (01), the functionCode (03) and the data (02 00 01).

 

Here's a received message corresponding to the request MODBUS.REQUEST 4567, 1, 6, 3, 1:

4567 01 06 00 03 00 01

As in the previous example, the message starts with the token used in the corresponding request (4567) followed by the serverID (01), the functionCode (06) and the data (00 03 00 01).

 

In case of error, the message content will be replaced with a detailed error message.

Here's a received error message

1234 Error response: E0 - Timeout

 

TCP Example:

'MODBUS TCP example - write and read in the HOLD_REGISTER 0

READ_HOLD_REGISTER = 3

WRITE_HOLD_REGISTER = 6

SERVER_ID = 1

onWgetAsync modbus_received 'set the event handler function

modbus.connect "192.168.1.130" 'address of the remote server

for z = 0 to 1000

  'write to the address 0

  modbus.request 1234, SERVER_ID, WRITE_HOLD_REGISTER, 0, z

  'read from the address 0

  modbus.request 4567, SERVER_ID, READ_HOLD_REGISTER, 0, 1 

  pause 1000

next z

end

 

modbus_received:

r$ = WGETRESULT$

print r$

token$ = word$(r$, 1) 'extract the token (first word)

if (token$ ="4567") then  ' if the token correspond to the read request

  if (word$(r$, 2) <> "Error") then  'if is not an error

     'assemble the 2 bytes in one 16 bits word

     value$ = "&h"+ word$(r$, 5) + word$(r$, 6) 

     wlog val(value$) 'converts from hex to integer

  end if

endif

return

 

MODBUS RTU wiring

The pictures below show a typical RS485 adapter that can be used with the ESP32

imageimage

 

 

The following schematic illustrates how to connect this adapter to the ESP32:

 

image

 

The picture below shows a typical device (AHT20 temperature / humidity sensor) that can be connected using the MODBUS RTU

image

 

This example shows how to read temperature and humidity data from the device shown above

'Example of MODBUS RTU with the sensor N434E01 AHT20

READ_INPUT_REGISTER = 4

SERVER_ID = 1

onWgetAsync modbus_received 'set the event handler function

modbus.setupRTU 2,5,26 ' by default is 9600,N,8,1

do

  modbus.requestRTU 1234, SERVER_ID, READ_INPUT_REGISTER, 0, 2

  pause 1000

loop

end

 

modbus_received:

r$ = WGETRESULT$

'wlog r$,ramfree(1)

token$ = word$(r$, 1) 'extract the token (first word)

if (token$ ="1234") then  ' if the token correspond to the read request

  if (word$(r$, 2) <> "Error") then  'if is not an error

    'assemble the 2 bytes in one 16 bits word

    temp$ = "&h"+ word$(r$, 5) + word$(r$, 6) 

    'assemble the 2 bytes in one 16 bits word

    hum$ = "&h"+ word$(r$, 7) + word$(r$, 8)

    wlog "Temp:"; val(temp$)/10 , "Hum:"; val(hum$)/10

  end if

endif

return

 


Regular Expressions (RegEx)

Regular expressions (regex) are sequences of characters that form a search pattern, used to match and manipulate text strings based on certain rules. They provide a powerful way to search, replace, and validate strings using patterns that define sets of strings, characters, or character classes. Regular expressions are widely used in text processing tasks, such as pattern matching, data validation, and text manipulation, across various programming languages and software applications.

The current implementation processes regular expressions identical in syntax to Lua's string.match, string.find, and similar functions. This adaptation allows seamless integration with Lua code, facilitating familiar usage patterns for users accustomed to Lua's regular expression syntax.

 

The regex functions available are :

 

ret = regex.find(string$, pattern$, [start], [result$])

This function retrieves the position of the substring within the string$ that matches the specified pattern$, starting from the specified start position. If a capture is designated in the pattern$ (further elaborated below) the function returns the position of the captured substring and if the result$ string variable is specified, the captured substring will be copied into it.

 

ret = regex.match(string$, pattern$, [result_array$()])

This function returns the number of captures designated in the pattern$ (further elaborated below) that match in the string$. If the array variable result_array$() is specified, all captures are copied into the array.

Patterns

The standard patterns (character classes) you can search for are:

 

 . --- (a dot) represents all characters.

%a --- all letters.

%c --- all control characters.

%d --- all digits.

%l --- all lowercase letters.

%p --- all punctuation characters.

%s --- all space characters.

%u --- all uppercase letters.

%w --- all alphanumeric characters.

%x --- all hexadecimal digits.

%z --- the character with hex representation 0x00 (null).

%% --- a single '%' character.

%1 --- captured pattern 1.

%2 --- captured pattern 2 (and so on).

%f[s]  transition from not in set 's' to in set 's'.

%b()   balanced nested pair ( ... ( ... ) ... )

 

Important! - the uppercase versions of the above represent the complement of the class. eg. %U represents everything except uppercase letters, %D represents everything except digits.


 

Magic characters

 

There are some "magic characters" (such as %) that have special meanings. These are:

 

^ $ ( ) % . [ ] * + - ?

 

 

If you want to use those in a pattern (as themselves) you must precede them by a % symbol.

 

eg. %% would match a single % .

 

In practice, it is safe to put % in front of any non-alphanumeric character. If in doubt, put a % in front of a special character.


 

Sets

 

You can build your own pattern classes (sets) by using square brackets, eg.

 

[abc] ---> matches a, b or c

[a-z] ---> matches lowercase letters (same as %l)

[^abc] ---> matches anything except a, b or c

[%a%d] ---> matches all letters and digits

[%a%d_] ---> matches all letters, digits and underscore

[%[%]] ---> matches square brackets (had to escape them with %)

 

You can use pattern classes in the form %x in the set. If you use other characters (like periods and brackets, etc.) they are simply themselves.

 

You can specify a range of characters inside a set by using simple characters (not pattern classes like %a) separated by a hyphen. For example, [A-Z] or [0-9]. These can be combined with other things. For example [A-Z0-9] or [A-Z,.].

 

The end-points of a range must be given in ascending order. That is, [A-Z] would match upper-case letters, but [Z-A] would not match anything.

 

A hyphen at the start or end of a set is itself (matches a hyphen).

 

You can negate a set by starting it with a "^" symbol, thus [^0-9] is everything except the digits 0 to 9. The negation applies to the whole set, so [^%a%d] would match anything except letters or digits. In anywhere except the first position of a set, the "^" symbol is simply itself.

 

Inside a set (that is a sequence delimited by square brackets) the only "magic" characters are:

 

 

] ---> to end the set, unless preceded by %

% ---> to introduce a character class (like %a), or magic character (like "]")

^ ---> in the first position only, to negate the set (eg. [^A-Z)

- ---> between two characters, to specify a range (eg. [A-F])

 

Thus, inside a set, characters like "." and "?" are just themselves.


 

Repetition

 

The repetition characters, which can follow a character, class or set, are:

 

 

+  ---> 1 or more repetitions (greedy)

*  ---> 0 or more repetitions (greedy)

-  ---> 0 or more repetitions (non greedy)

?  ---> 0 or 1 repetition only

 

 

A "greedy" match will match on as many characters as possible, a non-greedy one will match on as few as possible.


 

Anchor to start and/or end of string

 

The standard "anchor" characters apply:

 

 

^  ---> anchor to start of subject string (must be the very first character)

$  ---> anchor to end of subject string   (must be the very last character)

 

For example:

 

^You see     ---> string must start with "You see"

experience$  ---> string must end with "experience"

^Tick$       ---> string must be exactly "Tick" with no other characters


 

Captures

 

You can also use round brackets to specify "captures":

 

You see (.*) here

 

Here, whatever matches (.*) becomes the first capture.

 

You can also refer to matched substrings (captures) later on in an expression:

wlog regex.find("You see dogs and dogs", "You see (.*) and %1", , z$)'print 9 (pos of dogs)

wlog z$'print dogs

 

wlog regex.find("You see dogs and cats", "You see (.*) and %1", , z$)'print 0 (not found)

wlog z$'empty string

 

This example shows how you can look for a repetition of a word matched earlier, whatever that word was ("dogs" in this case).

 

As a special case, an empty capture string returns as the captured pattern, the position of itself in the string. eg.

wlog regex.find("You see dogs and cats", "You .* ()dogs .*") 'print 9 (pos of dogs)

 

 

What this is saying is that the word "dogs" starts at column 9.

 

There is a limit of 32 captures that can be returned.


 

Balanced sequences

 

Finally you can look for nested "balanced" things (such as parentheses) by using %b, like this:

 

print (string.find ("I see a (big fish (swimming) in the pond) here",

       "%b()"))  --> 9 41

 

 

After %b you put 2 characters, which indicate the start and end of the balanced pair. If it finds a nested version it keeps processing until we are back at the top level. In this case the matching string was "(big fish (swimming) in the pond)".


 

Frontier patterns

 

A "frontier" (or boundary) pattern is used to assert a transition from one set of characters to another (eg. non-letters to letters, or non-digits to digits). This can be useful to detect words, such as "log" but omit "blog" or "logging".

 

A frontier is specified as %f[set] and matches on a transition from not-in-set to in-set. For example, to match "log" on its own:

 

wlog regex.find ("There is a log here", "%f[%a]log%f[%A]") 'print 12 (pos of log)

wlog regex.find ("There is a blog here", "%f[%a]log%f[%A]") 'print 0 (not found)

wlog regex.find ("There is a logging here", "%f[%a]log%f[%A]") 'print 0 (not found)

 

The first frontier ("%f[%a]") matches on the transition from not-letters to letters. The second frontier ("%f[%A]") matches on letters to not-letters. Effectively this gives you a word boundary match.


 

Multiple matches

 

Using the function regex.match is possible to see if a string matches captures inside a given pattern.

Example :

wlog regex.match ("You see dogs and cats" , "(dogs)") 'print 1 (1 capture)

wlog regex.match ("You see dogs and cats" , "(dogs).*(cats)") 'print 2 (2 captures)

wlog regex.match ("You see dogs and cats" , "(dos)") 'print 0 (no capture)

 

But this function has also a more powerful functionality enabling it to extract multiple captures from a given string.

Example:

str$ = "date:1/11/2022 time:12:10:55 lat:N43.6047 long:E1.4442 elev:151"

pat$ = "date:(%d+/%d+/%d+) time:(%d+:%d+:%d+) lat:([NS][%d%.]+) long:([EW][%d%.]+) elev:(%d+)"

wlog regex.match(str$ , pat$, a$()) 'print 5 (5 captures)

for z = lbound(a$()) to ubound(a$())

  wlog a$(z) 'print 1/11/2022 12:10:55 N43.6047 E1.4442 151

next z

 

This function creates a new array (a$, in this example) that contains all the captures.

Is the array is already existing, its content will be replaced (and automatically redimensioned)

 

 


 

M5 Tough

image

The M5Stack Tough is a Waterproof ESP32 Module that includes a combination of 8M PSRAM + 16M FLASH memory, a rich set of peripherals and an expansion interface.

M5 TOUGH has full-coverage support dustproof and waterproof`, which can ensure the stability of circuit operation even in complex industrial applications. The M5 TOUGH is ideal for industrial control, smart buildings, outdoor node data acquisition, and other applications.

The peripherals included are :

     2 inches LCD capacitive Multi-touch screen

     NS4168 16 bits I2S power amplifier + 1W speaker

     TFCard slot

     AXP192 power management chip

     BM8563-RTC clock

     RS485 interface

 

More detailed information can be found on the official page

This module is fully supported by Annex32, including the power management functions through a set of dedicated commands / functions starting with the prefix M5Tough.

 

The Config Menu includes a dedicated choice for this module, including the selection of the right TFT driver

 

image

 

     The touch screen is supported and operational with all the GUI functions and requires no calibration

     The SDcard is supported and can be enabled

     The I2S audio chip is automatically configured for using the internal speaker.

     The RTC is supported using the same RTC.xxx functions already implemented

     The power and battery management, including the sleep functionalities, are fully supported

 

 

FUNCTIONS / COMMANDS

DESCRIPTION

M5Tough.BatLevel

Returns the charge status of the battery in %

M5Tough.BatVoltage

Returns the battery voltage in Volts

M5Tough.BatCurrent

Returns the battery current in mA.

A positive value means that the battery is charging

A negative value means that the battery is discharging

M5Tough.VinVoltage

Returns the input voltage in Volts

M5Tough.VinCurrent

Returns the input current in mA

M5Tough.VBusVoltage

Returns the VBUS voltage in Volts

M5Tough.VBusCurrent

Returns the VBUS current in mA

M5Tough.BatChgCurrent

Returns the battery charge current in mA.

M5Tough.BatPower

Returns the battery power in mW

M5Tough.AxpTemp

Returns the AXP192 internal temperature in °C

M5Tough.ApsVoltage

Returns the APS voltage in Volts ????

M5Tough.AxpState

Returns the Axp192 state

 

Bit Value

Description

128

isACIN()

32

isVBUS()

4

isCharging()

M5Tough.TftPower power

Select the power for the TFT (1 = on, 0 = off)

M5Tough.SpeakerPower power

Select the power for the internal speaker (1 = on, 0 = off)

M5Tough.SetBusPowerMode mode

Select the input power mode :

0 - From USB or Battery

1 - From external input

M5Tough.PowerOff sec

Turn off the power from the module and power on it again after sec seconds.

The max time is 15300 seconds (approx 4.25 Hours)

During the power off time, it can be restarted using the power button.

This mode remove completely the power from the module (minimal power consumption) as it rely on the external RTC for restarting the power (and not using the deep sleep mode of the ESP32)

M5Tough.LightSleep sec

Puts the module in light sleep for sec seconds

M5Tough.DeepSleep sec

Puts the module in deep sleep for sec seconds

 

Example

' Example for the M5 Tough

' The RTC must be set before running this

' program to show the correct time

wlog rtc.time$

wlog rtc.date$

 

wlog "BATLEVEL  ", M5Tough.BATLEVEL

wlog "BATVOLTAGE  ", M5Tough.BATVOLTAGE 

wlog "BATCURRENT  ", M5Tough.BATCURRENT 

wlog "VINVOLTAGE  ", M5Tough.VINVOLTAGE 

wlog "VINCURRENT  ", M5Tough.VINCURRENT 

wlog "VBUSVOLTAGE ", M5Tough.VBUSVOLTAGE

wlog "VBUSCURRENT ", M5Tough.VBUSCURRENT

wlog "AXPTEMP ", M5Tough.AXPTEMP

wlog "BATPOWER  ", M5Tough.BATPOWER 

wlog "BATCHGCURRENT ", M5Tough.BATCHGCURRENT

wlog "APSVOLTAGE  ", M5Tough.APSVOLTAGE 

wlog "AXPSTATE", M5Tough.AXPSTATE

 

ANNEXCAM

The AnnexCam is a special version of Annex32 specially developed for camera support.

It is  essentially the same firmware as the Annex32 except that many drivers have been removed to gain space and memory.

The main reason is because the camera itself uses practically all the ESP32 pins available leaving very few pins for the I/O.

The ESP32-CAM module and the M5Camera model B are supported.

These modules include an OV2640 camera and an additional PSRAM for big size pictures.

 

The actual implementation allows you to use this module to take snapshots or use it as a web camera while running basic scripts in parallel.

image

 

 

For the ESP32-CAM, AnnexCam follows the pinout of the SDCARD that is wired differently compared to the M5stack..

 

image

 

AnnexCAM supports the SDCARD for the ESP32-CAM using the SPI mode wiring.

This permits to free 2 pins, the GPIO4 and the GPIO12 that can be used as general I/O.

As the pin GPIO4 is already connected to the “Flash” led, the unique I/O pin available is the GPIO12.

In addition, the GPIO1 and GPIO3 (serial TX and RX) can also be used as general I/O pins.

 

The M5CAMERA do not supports the SDCARD and exposes only 2 pins (GPIO4 and GPIO13) via the GROVE connector. Only the model B is actually supported.

 

image

 

Functionalities enabled in the ANNEXCAM version

 

FUNCTIONALITY

ENABLED

TFT display

QRCODE

ESPNOW

PID

ETHERNET

CONVERT

MQTT

OLED

APDS9960

BME280

INFRARED

PLAY (WAV, MP3, VOICE)

NEOPIXEL

VL53L0X

RFID

FREQUENCY METER

IOBUFFER

WDT

MPU9250

MPU6886

MPU6050

FUSION ALGO

BNO055

PCA9685

TM1637 AND TM1638

MAXDISPLAY

BLUETOOTH

CCS811

HDC1080

TELEGRAM

 

Camera Functions / commands

The AnnexCam version introduce the following functions:

 

Ret = CAMERA.SETUP(framesize)

Initialise and set the initial resolution of the camera.

The parameter can be a number from 0 to 10 as described in the table below.

Returns 0 in case of error otherwise 1

Example :

Print CAMERA.SETUP(7) ' init the camera at 800 x 600

Note:

This command is not required anymore as the camera initialises automatically at the reboot.

 

Ret = CAMERA.PICTURE(filename$)

Get a picture from the camera and save it locally using the filename provided.

It works on both SDcard and internal FFAT space within the limits of the free space available.

Returns 0 in case of error otherwise 1

Example :

Print CAMERA.PICTURE("/image.jpg") ' save the picture in the file image.jpg

 

Ret = CAMERA.STOP()

Stops the camera driver

Returns 0 in case of error otherwise 1

 

Ret = CAMERA.GETVALUE(param$)

Returns the value of the parameter as defined in the table below:

Example :

Print CAMERA.GETVALUE("hmirror") ' get the hmirror parameter

 

Ret = CAMERA.PARAMS(param$, value)

Set the parameter as defined in the table below :

Returns 1 in case of error otherwise 0

Example :

Print CAMERA.PARAMS("vflip", 1) ' set the vflip parameter to 1

 

The parameter param$ can be :

 

PARAMETER

DESCRIPTION

framesize

Resolution of the image as per table below

 

0

96 x 96

1

160 x 120

2

176 x 144

3

240 x 176

4

240 x 240

5

320 x 240

6

400 x 296

7

480 x 320

8

640 x 480

9

800 x 600

10

1024 x 768

11

1280 x 720

12

1280 x 1024

13

1600 x 1200

quality

Quality of the image from 10 to 63 (0 = max quality) (default 10)

brightness

Brightness of the image from -2 to 2 (default 0)

contrast

Contrast of the image from -2 to 2 (default 0)

saturation

Saturation (color) of the image from -2 to 2 (default 0)

vflip

Flip vertically the image is 1 (default 0)

hmirror

Mirror horizontally the image if 1 (default 0)

flash

Turns on/off the bright white led connected on the module (default 0)

detection

Enables the face detection algo (0=disable, 1=enable)

recognition

Enables the face recognition algo  (0=disable, 1=enable)

enroll

Enroll the face detected by the camera and store it in the RAM (0=disable, 1=enable)

savefaces

Save the faces enrolled from the RAM to the disk (FFAT or SDCARD) (must be 1 to save)

readfaces

Read the faces enrolled from the disk (FFAT or SDCARD) to the RAM (must be 1 to read)

special_effect

//0 - 6

colorbar

1= enabled / 0= disabled

wb_mode

//0 - 4

awb

TBD

awb_gain

TBD

aec

TBD

aec2

TBD

ae_level

//-2 - 2

aec_value

//0 - 1200

agc

TBD

agc_gain

//0 - 30

gaincancelling

//0 - 6

bpc

TBD

wpc

TBD

raw_gma

TBD

lenc

TBD

dcw

TBD

 

Using AnnexCam in output page

 

Using the url http://module_ip/picture will show directly the image in the browser.

Refreshing the web page (using F5, for example) will refresh the image.

 

To use the camera in the output page, the following html line is required :

HTML |<img id='camera'>|

 

Alternatively, the following line can be used to have an image that resize automatically

HTML |<img id='camera' src="picture" style=width:100%;height:auto;">|

 

Then a javascript command is required to start the video

JSCALL |set_pictimer(30);|  ' try to refresh each 30 msec

 

Example:

 

' set the resolution at 640 x 480

if camera.setup(7) = 0 then "Camera Error" : end

 

cls

html |<img id='camera' src="picture" style=width:100%;height:auto;">|

jscall |set_pictimer(30);|

 

 

 

A slightly more complete example :

rate = 30 ' rate between each picture sample (msec)

 

pause 100

' set the max resolution in terms of memory

if camera.setup(10) = 0 then end

 

print camera.params("vflip", 1)

print camera.params("hmirror", 1)

 

'set at 800x600

print camera.params("framesize", 7)

 

pause 100

 

onHtmlReload setpage

gosub setpage

wait

 

setpage:

cls

a$ = ""

a$ = a$ + |<h2>AnnexCAM Demo mini</h2> |

a$ = a$ + |<img id='camera' src="picture" style=width:100%;height:auto;">|

html a$

 

jscall "set_pictimer(" + str$(rate) + ");"

return

 

 

To save a picture on the disk :

' set the resolution at 800 x 600

if camera.setup(7) = 0 then "Camera Error" : end

 

Print CAMERA.PICTURE("/image.jpg")

 

The image can then be downloaded / seen using the file manager page.

 

Control of the camera using URL

The camera parameters can be modified using the following URL:

http://module_ip/cam_setpar?param=value

 

Where param can be any parameter from the table below

 

Example:

http://192.168.1.66/cam_setpar?brightness=2

The value returned can be -1 if the parameter is unknown, 1 in case of error or 0 if all was OK

 

The parameters can be read using the following url:

http://module_ip/cam_status

The value returned will be a string like this

framesize=4 quality=10 brightness=0 contrast=0 saturation=0 vflip=1 hmirror=1 colorbar=0 special_effect=0 flash=0

Where all the parameters are separated by the newline character

 

PARAMETER

DESCRIPTION

framesize

Resolution of the image as per table below

 

0

96 x 96

1

160 x 120

2

176 x 144

3

240 x 176

4

240 x 240

5

320 x 240

6

400 x 296

7

480 x 320

8

640 x 480

9

800 x 600

10

1024 x 768

11

1280 x 720

12

1280 x 1024

13

1600 x 1200

quality

Quality of the image from 10 to 63 (10 = max quality)

brightness

Brightness of the image from -2 to 2 (default 0)

contrast

Contrast of the image from -2 to 2 (default 0)

saturation

Saturation (color) of the image from -2 to 2 (default 0)

vflip

Flip vertically the image is 1 (default 0)

hmirror

Mirror horizontally the image if 1 (default 0)

flash

Turns on/off the bright white led connected on the module

special_effect

TBD

colorbar

TBD

 

 

Face Recognition

AnnexCAM includes the support for face recognition.

This is basically based on 2 parts :

1)    Face detection

2)    Face recognition

 

The face detection enables the detection of faces whilst the face recognition compares the face detected against a list of previously stored faces.

This is very CPU time and resources consuming so it works only with resolutions of 320x240 and below.

 

 

The detection / recognition can be controlled using the following URL:

http://module_ip/cam_setpar?param=value

 

PARAMETER

DESCRIPTION

detection

Enables the face detection algo (0=disable, 1=enable)

recognition

Enables the face recognition algo  (0=disable, 1=enable)

enroll

Enroll the face detected by the camera and store it in the RAM (0=disable, 1=enable)

savafaces

Save the faces enrolled from the RAM to the disk (FFAT or SDCARD) (must be 1 to save)

readfaces

Read the faces enrolled from the disk (FFAT or SDCARD) to the RAM (must be 1 to read)

 

The faces enrolled are stored in the file named “/face.fh”.

This file can then be backuped and transferred to another module.

 

If the face detection is enabled, as soon as the camera detect a face, AnnexCAM will include a special parameters in the header of the image transferred :

Detected:x1, y1, x2, y2

Where (x1, y1) and (x2, y2)  are the coordinates (in pixels) that describe the corners of the box surrounding the face detected

 

If the face recognition is enabled, as soon as the camera recognise a face, AnnexCAM will include a special parameters in the header of the image transferred :

Recognition:Match ID:xx

Where xx is a number that identify the subject identified

Or

Recognition:No Match

If the face has not been recognised

 

This information can be extracted from the browser side using javascript.

 

Image / video reception from Annex

Annex includes the feature to receive the image from another module with AnnexCAM and show them on the TFT display.

This can be done using the function

Ret$ = TFT.CAMERA(url$ [,x ,y] [,scale])

where

url$ is the address of the camera

x and y represent the position where the image will be shown on the display

scale is a number that enable to scale down the image, useful to display an image with higher resolution than the display

 

‘scale’(optional) enable to scale the image (see next table)

 

scale

Scaling effect

0

1:1

1

1:2

2

1:4

3

1:8

 

For example, to receive a simple stream of images ( a video) from the camera with IP 192.168.1.13:

while 1

  a$ = tft.camera$("http://192.168.1.13/picture")

wend

 

This function returns a string value that represents the header of the answer coming from the camera.

The header contains very interesting information such as the detection or the recognition of a face.

 

This is a typical content

HTTP/1.1 200 OK

Content-Length: 7229

Content-Type: image/jpeg

Access-Control-Allow-Origin: *

Access-Control-Allow-Headers: Content-Type,Authorization

Access-Control-Expose-Headers: Detected, Recognition, Resolution

Resolution: 320x240

Detected: 57.469482,0.000000,190.526123,186.304199

Recognition: No Match

Connection: close

Accept-Ranges: none

 

The highlighted part contains the coordinates of the detected face and eventually if the face has been detected compared to a list of stored profiles

 

This more complete example shows how to manage the value returned by TFT.CAMERA$.

It also shows how include the login and password for camera with restricted access

timer0 1000, count

tft.init 1

tft.fill tft.color(red)

tft.brightness 255

a$= ""

c = 0 : z = 0

while 1

  'Read from the camera using the given login:password

  a$ = tft.camera$("http://mylogin:mypassword@192.168.1.13/picture")

  'Check inside the answer is a face has been detected / recognised

  p = instr(a$, "Detected:")

  if  p <> 0 then

    d$ = mid$(a$, p + 9)

    x1 = val(word$(d$, 1, ",")) : y1 = val(word$(d$, 2, ","))

    x2 = val(word$(d$, 3, ",")) : y2 = val(word$(d$, 4, ","))

    r = instr(a$, "Recognition:")

    if r = 0 then

      tft.rect x1, y1, x2-x1, y2-y1, 65504 '(yellow)

    else

      if instr(d$, "No Match") <> 0 then

        tft.rect x1, y1, x2-x1, y2-y1, 63488 '(red)

      else

        tft.rect x1, y1, x2-x1, y2-y1, 2016 '(green)

      end if

    end if

  end if

wend

end

 

count:

print "frames / sec ", z-c, ramfree

c = z

return

 

ANNEXEPAPER for LILYGO T5 4.7” E-paper module

The AnnexEpaper is a special version of Annex32 specially developed for this module.

It is  essentially the same firmware as the Annex32 except that this version fully supports the e-paper display including the optional touchscreen and many drivers have been removed to gain space and memory.

The main reason is because the e-paper display itself uses practically all the ESP32 pins available leaving very few pins for the I/O.

This module includes an EPD4.7” e-paper display, a 16Mbytes Flash chip and an additional PSRAM for big size pictures.

 

image

EPAPER.SETUP rotation ' rotation from 0 to 3

Setup the display with the correct orientation

The orientation cannot be changed without restarting the device (will be fixed)

 

EPAPER.ON

Turns the display ON

 

EPAPER.OFF

Turns the display OFF

 

EPAPER.CLS

Clear the display and the buffer memory

 

EPAPER.CLEAR

Clear the the buffer memory but not the display itself

Useful to refresh the image on the display

 

EPAPER.REFRESH mode [,temperature] 'temperature by default it 25°C

Refreshes the image on the display; the mode must be defined

 

EPAPER.PIXEL x, y, color

 

EPAPER.LINE x1, y1, x2, y2, color

 

EPAPER.RECT x, y, w, h, color [,fill]

 

EPAPER.CIRCLE x, y, r, color [,fill]

 

EPAPER.TEXT.ALIGN align

 

Defines the text alignment

1

EPD_DRAW_BACKGROUND

2

EPD_DRAW_ALIGN_LEFT

4

EPD_DRAW_ALIGN_RIGHT

8

EPD_DRAW_ALIGN_CENTER

 

EPAPER.TEXT.COLOR color

Defines the text color from 0 (black) to 15 (white)

 

EPAPER.TEXT.FONT font

Set the font to be displayed

0

FiraSans 12

1

Verdana 20

10

Loaded Font 1

11

Loaded Font 2

12

Loaded Font 3

 

 

EPAPER.TEXT.DRAW "string", x, y

 

EPAPER.LOADFONT "/fontfile.fnt" [, fontnum]

Loads a font from file; the fontnum can be 1(default),  2 or 3

 

EPAPER.BMP "/bmpfile.bmp", x, y [, reverse]

Draws a bmp file on the display; it must be in B/W 8 bits format

If reverse=1 the color will be reversed (negative image)

 

EPAPER.QRCODE "message", x, y, width [,version]

This command draws a text message on the display as QR CODE that can be read using a mobile phone simply taking a picture of the image shown on the display.

By default the version is 6

image

 

EPAPER.SAVE "/bmpfile.bmp", x, y [, reverse]

Save the image shown on the display in a bmp 8 bits format.

 

If the adapted touchscreen is available, the following functions are available as in the normal ESP32 version

TOUCH.READ, TOUCH.X, TOUCH.Y, TOUCH.Z

 

Additionally, the command TOUCH.SLEEP sleeps the touch screen controller to reduce power

 

 

GRAPHIC GUI for E-PAPER

The AnnexEpaper version includes all the GUI objects as defined in the GRAPHIC GUI for TFT chapter (except for the RAMP object) using the same syntax but with the colors adapted to the monochromatic display.

The following images show some screenshots taken directly from the display itself (using the command EPAPER.SAVE) with some demo programs.

 

Example 1

Bluetooth.delete ' free the RAM used by the bluetooth

epaper.setup 0

epaper.cls

print touch.setup

gui.init 50

gui.textline(200, 10, 550, 60, "Touch E-Paper 4.7 Demo", 1)

 

t1 = gui.textline( 20, 100, 200, 50, "Top Left", 0, 0, 15, 0, ALIGN_TOP_LEFT)

t2 = gui.textline(380, 100, 200, 50, "Top Mid", 0, 0, 15, 0, ALIGN_TOP_MID)

t3 = gui.textline(740, 100, 200, 50, "Top Right", 0, 0, 15, 0, ALIGN_TOP_RIGHT)

 

t4 = gui.textline( 20, 180, 200, 50, "Mid Left", 0, 0, 15, 0, ALIGN_MID_LEFT)

t5 = gui.textline(380, 180, 200, 50, "Mid Mid", 0, 0, 15, 0, ALIGN_MID_MID)

t6 = gui.textline(740, 180, 200, 50, "Mid Right", 0, 0, 15, 0, ALIGN_MID_RIGHT)

 

t7 = gui.textline( 20, 260, 200, 50, "Bot Left", 0, 0, 15, 0, ALIGN_BOT_LEFT)

t8 = gui.textline(380, 260, 200, 50, "Bot Mid", 0, 0, 15, 0, ALIGN_BOT_MID)

t9 = gui.textline(740, 260, 200, 50, "Bot Right", 0, 0, 15, 0, ALIGN_BOT_RIGHT)

 

ta = gui.textline( 20, 340, 300, 60, "Mid Left", 1, 0, 15, 0, ALIGN_MID_LEFT)

tb = gui.textline(330, 340, 300, 60, "Mid Mid", 1, 0, 15, 0, ALIGN_MID_MID)

tc = gui.textline(640, 340, 300, 60, "Mid Right", 1, 0, 15, 0, ALIGN_MID_RIGHT)

 

td = gui.textline( 20, 420, 300, 60, "Top Left", 1, 15, 0, 0, ALIGN_TOP_LEFT)

te = gui.textline(330, 420, 300, 60, "Mid Mid", 1, 15, 0, 0, ALIGN_MID_MID)

tf = gui.textline(640, 420, 300, 60, "Top Right", 1, 15, 0, 0, ALIGN_TOP_RIGHT)

 

gui.textline(150, 500, 700, 35, "Demo of text alignements")

 

gui.autorefresh 100, 1

wait

 

image

 

Example 2

Bluetooth.delete ' free the RAM used by the bluetooth

 

epaper.setup 0

epapercls

print touch.setup

gui.init 50

 

gui.textline(200, 10, 550, 60, "Touch E-Paper 4.7 Demo", 1)

 

gui.textline(20, 120, 200, 50, "Squared", 1 )

gui.textline(320, 90, 1, 30, "Option 1", 0, 0, 15, 15)

gui.textline(520, 90, 1, 30, "Option 2", 0, 0, 15, 15)

gui.textline(720, 90, 1, 30, "Option 3", 0, 0, 15, 15)

c1 = gui.checkbox(300, 120, 50, 50, 0, squared)

c2 = gui.checkbox(500, 120, 50, 50, 0, squared)

c3 = gui.checkbox(700, 120, 50, 50, 0, squared)

 

gui.textline(20, 220, 200, 50, "Crossed", 1 )

gui.textline(320, 220, 1, 30, "Option 4", 0, 0, 15, 15)

gui.textline(520, 220, 1, 30, "Option 5", 0, 0, 15, 15)

gui.textline(720, 220, 1, 30, "Option 6", 0, 0, 15, 15)

c4 = gui.checkbox(300, 250, 50, 50, 0, crossed)

c5 = gui.checkbox(500, 250, 50, 50, 0, crossed)

c6 = gui.checkbox(700, 250, 50, 50, 0, crossed)

 

gui.textline(20, 350, 200, 50, "Radio", 1 )

gui.textline(320, 350, 1, 30, "Option 7", 0, 0, 15, 15)

gui.textline(520, 350, 1, 30, "Option 8", 0, 0, 15, 15)

gui.textline(720, 350, 1, 30, "Option 9", 0, 0, 15, 15)

c7 = gui.checkbox(300, 380, 50, 50, 1, radio, 1)

c8 = gui.checkbox(500, 380, 50, 50, 0, radio, 1)

c9 = gui.checkbox(700, 380, 50, 50, 0, radio, 1)

 

gui.textline(150, 500, 700, 35, "Demo of Button Image Groups")

 

gui.autorefresh 100, 1

 

wait

 

 

image

 

image

 

 

image

 

 

 

image

image

 

image

 

image

image

 

image

 

image

 

Functionalities enabled in the E-PAPER version

 

FUNCTIONALITY

ENABLED

TFT display

QRCODE

ESPNOW

PID

ETHERNET

CONVERT

MQTT

OLED

APDS9960

BME280

INFRARED

PLAY (WAV, MP3, VOICE)

NEOPIXEL

VL53L0X

RFID

FREQUENCY METER

IOBUFFER

WDT

MPU9250

MPU6886

MPU6050

FUSION ALGO

BNO055

PCA9685

TM1637 AND TM1638

MAXDISPLAY

BLUETOOTH

CCS811

HDC1080

TELEGRAM

PEEK and POKE FUNCTIONS

The functions PEEK and POKE are commands used for accessing the contents of a specific memory cell referenced by its memory address.

PEEK gets the byte located at the specified memory address.

POKE sets the memory byte at the specified address.

The memory can be accessed by byte (uint8_t), by word (uint8_16) or by double word (uint32_t).

Generally the internal CPU registers are 32 bits so this should be the “normal” access mode

The following functions / commands are available

 

FUNCTION

DESCRIPTION

BAS.PEEK(addr)

Read a double word (32 bits) from ‘addr’ memory address

BAS.PEEK16(addr)

Read a word (16 bits) from ‘addr’ memory address

BAS.PEEK8(addr)

Read a byte(8 bits) from ‘addr’ memory address

BAS.POKE addr, data

Write a double word (32 bits) ‘data’ into ‘addr’ memory address

BAS.POKE16 addr, data

Write a word (16 bits) ‘data’ into ‘addr’ memory address

BAS.POKE8 addr, data

Write a byte (8 bits) ‘data’ into ‘addr’ memory address

 

Example

'EXAMPLE SHOWING THE USE OF PEEK AND POKE FOR BLINKING LEDS

'-------------------------------------------------------------

'Name Description Address Access

'GPIO_OUT_REG GPIO 0-31 output register 0x3FF44004 R/W

'GPIO_OUT_W1TS_REG GPIO 0-31 output register_W1TS 0x3FF44008 WO

'GPIO_OUT_W1TC_REG GPIO 0-31 output register_W1TC 0x3FF4400C WO

'GPIO_OUT1_REG GPIO 32-39 output register 0x3FF44010 R/W

'GPIO_OUT1_W1TS_REG GPIO 32-39 output bit set register 0x3FF44014 WO

'GPIO_OUT1_W1TC_REG GPIO 32-39 output bit clear register 0x3FF44018 WO

'GPIO_ENABLE_REG GPIO 0-31 output enable register 0x3FF44020 R/W

'GPIO_ENABLE_W1TS_REG GPIO 0-31 output enable register_W1TS 0x3FF44024 WO

'GPIO_ENABLE_W1TC_REG GPIO 0-31 output enable register_W1TC 0x3FF44028 WO

'GPIO_ENABLE1_REG GPIO 32-39 output enable register 0x3FF4402C R/W

'GPIO_ENABLE1_W1TS_REG GPIO 32-39 output enable bit set register 0x3FF44030 WO

'GPIO_ENABLE1_W1TC_REG GPIO 32-39 output enable bit clear register 0x3FF44034 WO

'-------------------------------------------------------------

pin.mode 4, output

pin.mode 5, output

do

  pin(4) = 0

  pin(5) = 0

  print bin$(bas.peek(&h3FF44004))

  pause 1000

  pin(4) = 1

  pin(5) = 1

  print bin$(bas.peek(&h3FF44004))

  pause 1000

  bas.poke &h3FF4400C, &b110000

  print bin$(bas.peek(&h3FF44004))

  pause 1000

  bas.poke &h3FF44008, &b110000

  print bin$(bas.peek(&h3FF44004))

  pause 1000

loop

 

 

 

CONVERSION FUNCTIONS

A set of conversion functions have been implemented.

These permit conversion from different units / formats in a simple way.

All these functions share the same prefix CONVERT. followed by the specific conversion name.

 

The functions implemented are :

 

FUNCTION

DESCRIPTION

CONVERT.DEGC_TO_F(degC)

Converts from °C to °F

CONVERT.F_TO_DEGC(degF)

Converts from °F to °C

CONVERT.TO_IEEE754(num)

Converts from float number to IEEE754 binary format

CONVERT.FROM_IEEE754(iee754_bin)

Converts from IEEE754 binary format to float number

CONVERT.MAP(number, fromLow, fromHigh, toLow, toHigh)

Re-maps a number from one range to another. That is, a value of fromLow would get mapped to toLow, a value of fromHigh to toHigh, values in-between to values in-between, etc.

CONVERT.TO_BCD(number)

Converts a byte to BCD format

CONVERT.FROM_BCD(number)

Convert to a byte from BCD format

CONVERT.LIMITS(number, min, max)

Restricts a number within a specified range.

 `number` is the value to be limited.

 `min` is the minimum allowed value for the number.

 `max` is the maximum allowed value for the number.

 

BAS CONSTANTS

Several constants are available in the interpreter using the BAS.xxx format.

All these constants share the same prefix BAS. followed by the specific option.

Some of them (i.e. BAS.RTCMEM$) can also be written using it as a destination..

 

CONSTANT

DESCRIPTION

BAS.VER

Returns the version of the Basic in numerical format

Example:

Print BAS.VER

1.37

BAS.VER$

Returns the version of the Basic in string format

Example:

Print BAS.VER$

Annex32 WI-Fi 1.37

BAS.ERRLINE

Returns the line number where the error happened. Value of 0 means no error.

It is reset to 0 with the command ONERROR CLEAR or  running the program or with the command ONERROR IGNORE or ONERROR SKIP.

BAS.ERRNUM

Returns a number where non zero means that there was an error.

It is reset to 0 with the command ONERROR CLEAR or  running the program or with the command ONERROR IGNORE or ONERROR SKIP.

BAS.ERRMSG$

Return a string representing the error message that would have normally been displayed on the console. It is reset to “No Error” running the program or with the command ONERROR CLEAR or ONERROR IGNORE or ONERROR SKIP.

BAS.FILENAME$

Returns the name of the current basic file

BAS.RTCMEM$

Returns the content of the CPU RTC internal memory.

This memory maintains the content between reset so it is useful in association with the SLEEP command when the module goes in low power mode.

This memory is limited at 7680 bytes and can be set with the corresponding command  BAS.RCTMEM$ = “xxx”.

The content of this memory is lost in case of power OFF.

BAS.SSID$

Returns the login used for the STATION wifi connection.

BAS.PASSWORD$

Returns the password used for the STATION wifi connection.

 

BAS.LOAD

Loads another .bas program and runs it immediately.

Returns 0 if successful or -1 if the file was not found

Example:

Print BAS.LOAD "/test.bas"

BAS.RESETREASON

Returns the reason for the last reset.

The reason is defined in the table below

VALUE

REASON

0

Unknown

1

Power on reset

2

Unknown

3

Software reset digital core

4

Legacy watch dog reset digital core

5

Deep Sleep reset digital core

6

Reset by SLC module, reset digital core

7

Timer Group0 Watch dog reset digital core

8

Timer Group1 Watch dog reset digital core

9

RTC Watch dog reset digital core

10

 Intrusion tested to reset CPU

11

Time Group reset CPU

12

Software reset CPU

13

RTC Watch dog reset CPU

14

for APP CPU, reset by PRO CPU

15

Reset when the vdd voltage is not stable

16

RTC Watch dog reset digital core and rtc module

BAS.WAKEUPREASON

Returns the reason for the wake up if the module was in deep sleep

The reason is defined in the table below

VALUE

REASON

0

Unknown

1

N/A

2

EXT0 - Input Pin

3

EXT1

4

Timer

5

Touch - Touch pin

6

ULP

7

GPIO  (in light sleep only)

8

UART (in light sleep only)

9

WIFI  (in light sleep only)

10

COCPU interrupt

11

COCPU crash

12

BT (in light sleep only)

BAS.DEVICE

Returns a number representing the current module connected

 

VALUE

MODULE

0

Generic ESP32

1

Custom

100

M5 Stack

101

M5 ATOM

102

M5 ATOM ECHO

103

M5 ATOM MATRIX

104

M5 Tough

120

WIFI loRa 32

150

ODROID GO

151

ESP32-2432S028

152

ESP32-3248S035R

153

ESP32-3248S035C

160

ESP32-4848S040

161

ESP32-8048S070C

201

ESP32-CAM

202

M5 CAMERA

BAS.TFT

Returns a number representing the TFT display connected

 

VALUE

DISPLAY

0 to 7

ST7735

11

GC9A01

51

SSD1351

81

ILI9481

86

ILI9486

88

ILI9488

89

ST7789 #0

91

ILI9163

93

ILI9341

94

M5stack

95

M5stack with different TFT

96

ST7796

101 to 106

ST7789 #1 to ST7789 #6

255

NO TFT

 

 

OPTION COMMANDS

It is possible to define some options in the interpreter using the OPTION.xxx commands.

All these commands share the same prefix OPTION. followed by the specific option.

 

The options available are :

 

COMMAND

DESCRIPTION

OPTION.BASE 0 | 1

Defines the lower limit for array subscripts.

Can be 0 (default) or 1.

This command must be executed before the declaration of any array (best in the first lines of the program)

OPTION.CPUFREQ 80|160|240

Define CPU speed in Mhz of the module.

The value can be 80, 160 or 240. 

The default value is 240Mhz.

Setting the speed at 80Mhz, will divide by 3 the speed of the module but lower the power requirement of the module to around 5mA

OPTION.ES8388

Enable the ES8388 Codec for the AI-Thinker Audio Kit

It uses the following pins:

I2C SDA -> pin 33

I2C SCL -> pin 32

I2S_MCLK  -> pin 0

PA_ENABLE -> pin 21

The other pins must be defined in the advanced config page

OPTION.MAC mac$

Define an arbitrary MAC address for the module.

‘mac$’ must be a valid MAC address.

Example :

OPTION.MAC "AA:BB:CC:DD:EE:FF"

OPTION.LOWRAM value

Define the RAM available lower limit. If during the execution of the program this limit is reached, the program automatically stops with an OUT OF MEMORY error message. By default the value is defined at 10000.

As it introduces a little overhead, it can be disabled setting this option at 0 (however this is not recommended).

OPTION.NTPSYNC

Sync the local time with the remote NTP servers

OPTION.WDT time

Define the time for the Watchdog timer.

If the WDT is not reset regularly with the command OPTION.WDTRESET within the defined time, the module will reset automatically.

Setting time at 0, will disable the watchdog.

OPTION.WDTRESET

Reset the Watchdog timer

OPTION.WLOG value

Define how the log will be printed in the Editor page

 

value

Description

0

WLOG will be ignored

1

WLOG will be printed (default)

2

All will be logged, including the command HTML, CSS, JSCALL, ....

OPTION.TOUCH value

Define the kind of touchscreen controller to use

 

value

Description

0

Resistive based on XPT2046 (default)

1

Capacitive based on GT911

 

 

OPTION.I2S BCLK_pin, WSEL_pin, DOUT_pin

Set / override the default pins allocated for the I2S output

OPTION.PSRAM limit

When external memory is in use, the allocation strategy is to initially try to satisfy smaller allocation requests with internal memory and larger requests with external memory.

The limit parameter helps balance the use of internal and external memory. Adjusting this value can optimise memory allocation based on the specific needs and constraints of your application.

By default the limit is 8192.

When changed the value is stored internally and will be automatically loaded at the next restart.

 

HALL Sensor (Internal):

The ESP32 contains an internal sensor that can be read using the following function:

BAS.HALL

 

Example

PRINT BAS.HALL

However, this functionality is very marginal as the sensor is not sensitive at all.

 

 

FUNCTIONS:

The functions are divided into 2 groups :

-       Numerical functions (Double precision / integer)

-       String functions

The string functions are always terminated by a ‘$’ (dollar) sign.

 

NUMERICAL FUNCTIONS

 

ABS(number)

Returns the absolute value of the argument 'number'

ACOS(number)

Returns the arccosine value of the argument 'number' in radians

ADC(pin)

Returns the external voltage applied to the ADC pin defined as a digital value ranging from 0 (0v) to 4095.

Input voltage range is 0 ... 3.3V.

APDS9960.SETUP (mode)

Initialise a APDS9960 sensor connected using I2C to the module.

‘mode’ determine the sensing modality as per the table below :

 

MODE

SENSING MODALITY

1

Gesture Detection

2

Ambient Light and RGB Color Sensing

3

Proximity Sensing

 

Before using it, the I2C bus must be initialised with the command I2C.SETUP

This function returns 1 if the APDS9960 sensor is found, otherwise it returns 0

APDS9960.READGESTURE

Returns the last gesture detected by the APDS9960 sensor.

The APDS9960 sensor must be set in “Gesture Detection” mode before using this function ( APDS9960.SETUP(1) )

The returned value is :

VALUE

GESTURE

0

NONE

1

LEFT

2

RIGHT

3

UP

4

DOWN

5

NEAR

6

FAR

APDS9960.AMBIENT

Returns the ambient luminosity detected by the APDS9960 sensor.

The APDS9960 sensor must be set in “Ambient Light and RGB Color Sensing” mode before using this function ( APDS9960.SETUP(2) )

The range of the returned value is from 0 to 65535

APDS9960.RED

Returns the red light intensity detected by the APDS9960 sensor.

The APDS9960 sensor must be set in “Ambient Light and RGB Color Sensing” mode before using this function ( APDS9960.SETUP(2) )

The range of the returned value is from 0 to 65535

APDS9960.GREEN

Returns the green light intensity detected by the APDS9960 sensor.

The APDS9960 sensor must be set in “Ambient Light and RGB Color Sensing” mode before using this function ( APDS9960.SETUP(2) )

The range of the returned  value is from 0 to 65535

APDS9960.BLUE

Returns the blue light intensity detected by the APDS9960 sensor.

The APDS9960 sensor must be set in “Ambient Light and RGB Color Sensing” mode before using this function ( APDS9960.SETUP(2) )

The range of the returned value is from 0 to 65535

APDS9960.PROXIMITY

Returns the distance information detected by the APDS9960 sensor.

The APDS9960 sensor must be set in “Proximity Sensing” mode before using this function ( APDS9960.SETUP(3) )

The range of the returned value is from 0 to 255

APDS9960.GESTUREGAIN (gain)

Set the gain of the gesture sensing provided by the APDS9960 sensor.

‘gain’ can be one of the following values:

 

GAIN

MEANING

0

1x

1

2x

2

4x

3

8x

 

This function returns 1 if the function was successful, otherwise it returns 0

APDS9960.GESTURELED (intensity)

Set the inensity of the LED used during the gesture sensing provided by the APDS9960 sensor.

‘intensity’ can be one of the following values:

 

INTENSITY

MEANING

0

100 mA

1

50 mA

2

25 mA

3

12.5 mA

 

This function returns 1 if the function was successful, otherwise it returns 0

ASC(string$)

Returns the ASCII code of the first char in ‘string$’

ASIN(number)

Returns the arcsine value of the argument 'number' in radians

ATAN(number)

Returns the arctangent of the argument 'number' in radians

ATAN2(x, y)

Returns the angle whose tangent is the quotient of two specified numbers.

BAS.VER

Returns the version of the Basic in numerical format

Example:

Print BAS.VER

1.25

BAS.ERRLINE

Returns the line number where the error happened. Value of 0 means no error.

It is reset to 0 with the command ONERROR CLEAR, or by running the program, or with the command ONERROR IGNORE, or ONERROR SKIP.

BAS.ERRNUM

Returns a number where non zero means that there was an error.

It is reset to 0 with the command ONERROR CLEAR, or by running the program, or with the command ONERROR IGNORE, or ONERROR SKIP.

BME280.SETUP(address)

Initialise a BME280 sensor connected using I2C to the module.

‘address’ defines the I2C address of the sensor. The value can be &h76 or &h77.

Before using it, the I2C bus must be initialised with the command I2C.SETUP

Returns 1 if the BME280 sensor has been found, otherwise returns 0

BME280.ALT(qnh)

Returns the current altitude using the baro pressure from the sensor BME280.

The sea level pressure (in HectoPascal) must be given as a reference argument.

The unit of the value returned is Meters (m)

BME280.HUM

Returns the Humidity parameter from the sensor BME280.

The unit of the value returned is ‘%’

If the value returned is always 0, the sensor is probably a BMP280.

BME280.QFE

Returns the Barometric Pressure parameter from the sensor BME280.

The unit of the value returned is HectoPascal ‘Hpa’

BME280.QNH(altitude)

Returns the sea level pressure using the baro pressure from the sensor BME280.

The current altitude (in meters) must be given as a reference argument.

The unit of the value returned is HectoPascal ‘Hpa’

BME280.TEMP

Returns the Temperature parameter from the sensor BME280.

The unit of the value returned is ‘%’

BNO055.SETUP( address)

Initialise a BNO055 connected using I2C to the module.

‘address’ defines the I2C address of the sensor. The value can be &h28 or &h29.

Before using it, the I2C bus must be initialised with the command I2C.SETUP

Returns 1 if the BNO055 sensor has been found, otherwise returns 0

BNO055.HEADING

Returns the Heading angle information from the sensor BNO055.

The unit of the value returned is ‘degrees’

BNO055.PITCH

Returns the Pitch angle information from the sensor BNO055.

The unit of the value returned is ‘degrees’

BNO055.ROLL

Returns the Roll angle information from the sensor BNO055.

The unit of the value returned is ‘degrees’

BNO055.VECTOR ( param, axis)

Returns different type of information from the sensor BNO055.

Refer to the table below for the details of the information returned.

 

Example:

Print “Gyro infos x,y “, BNO055.VECTOR(3,1), BNO055.VECTOR(3,2)

 

PARAM

AXIS

PARAMETER

UNITS

1

1

Accelerometer X axis

m/sec2

2

Accelerometer Y axis

3

Accelerometer Z axis

2

1

Magnetometer X axis

micro tesla

2

Magnetometer Y axis

3

Magnetometer Z axis

3

1

Gyroscope X axis

deg / sec

2

Gyroscope Y axis

3

Gyroscope Z axis

4

1

Linear Accelerometer X axis

m/sec2

2

Linear Accelerometer Y axis

3

Linear Accelerometer Z axis

5

1

Gravity Data X axis

m/sec2

2

Gravity Data Y axis

3

Gravity Data Z axis

6 or any other value

1

Euler Angle Heading

deg

2

Euler Angle Roll

3

Euler Angle Pitch

BNO055.CALIB [(param)]

Returns the calibration status of the BNO055 sensor.

Used without any argument, it will return the global calibration status ( 1 = calibrated, 0 = not calibrated).

Refer to the table below when the function is called with an argument

 

PARAM

PARAMETER

1

System Status

2

Gyroscopes Status

3

Accelerometers Status

4

Magnetometers Status

none

Global Status (returns 1 if all are OK)

Example:

Print “Is Calibrated“, BNO055.CALIB

CINT(number)

Round numbers with fractional portions up or down to the next whole number or integer.

For example :

     15.46 will round to 15

     15.57 will round to 16

     -83.45 will round to -83

     -83.55 will round to -84

See also INT() and FIX().

CONVERT.DEGC_TO_F(degC)

Converts from °C to °F

CONVERT.F_TO_DEGC(degF)

Converts from °F to °C

CONVERT.TO_IEEE754(num)

Converts from float number to IEEE754 binary format

CONVERT.FROM_IEEE754(ieee754_bin)

Converts from IEEE754 binary format to float number

CONVERT.MAP(number, fromLow, fromHigh, toLow, toHigh)

Re-maps a number from one range to another. That is, a value of fromLow would get mapped to toLow, a value of fromHigh to toHigh, values in-between to values in-between, etc.

CONVERT.TO_BCD(number)

Converts a byte to BCD format

CONVERT.FROM_BCD(number)

Convert to a byte from BCD format

COS(number)

Returns the cosine of the argument 'number' in radians.

COUNTER.COUNT (cnt)

Returns the number of pulses recorded by the counter.

‘cnt’ identifies the counter, which can be 1 or 2

It is associated with the commands COUNTER.SETUP, COUNTER.RESET

COUNTER.PERIOD (cnt)

Returns the period of time between 2 successive pulses recorded by the counter.

The value returned is expressed in uS (micro seconds).

‘cnt’ identifies the counter, which can be 1 or 2

It is associated with the commands COUNTER.SETUP, COUNTER.RESET

DATEUNIX(date$)

Converts a date in format dd/mm/yy into UNIX FORMAT.

See also TIMEUNIX, and the complementary UNIXDATE$ and UNIXTIME$

DHT.TEMP

Returns the temperature of the DHT sensor set with "DHT.SETUP"

The syntax is temp = DHT.TEMP

Returns the temperature in °C

DHT.HUM

Returns the humidity of the DHT sensor set with "DHT.SETUP"

The syntax is hum = DHT.HUM

Returns the humidity in %

DHT.HEATINDEX

Returns the heat index of the DHT sensor set with "DHT.SETUP"

The syntax is heat = DHT.HEATINDEX

Returns the heatindex in °C

DISTANCE(pin_trig, pin_echo)

Using a HC-SR04 ultrasonic sensor, this function returns the distance in cm to a target. The range is approximately from 3 cm to 3 meters.

‘pin_trig’ and ‘pin_echo’ define the pins where the HC-SR04 module is connected.

EMAIL from$, to$, subject$, message$

Send an e-mail and return the status of the sending.

The program will stop the execution until the message is sent or an error occurs.

The result will be 1 if OK or 0 if a problem happend.

‘from$’ is the email address of the sender (ex: from_me@yahoo.com)

‘to$’’ is the email address of the receiver  (ex: to_you@yahoo.com)

‘subject$’ is the subject of the message

‘message$’ is the content of the message

The sender and receiver must both be valid email addresses.

Example :

r = EMAIL ("from_me@yahoo.com", "to_you@gmail.com", "Important message " + date$,  "The memory available is " + str$(ramfree) )

ESPNOW.ADD_PEER(MAC_add$ [,interface] [,channel])

Add a peer (module)  to the ‘receiver’ list.

The peer is specified by its MAC address

‘interface’ can be 0 = AUTO (default), 1=STA, 2=AP

‘channel’ can be any valid channel numbers or 0 = current channel (default)

Returns 0 if OK or another number in case of error

ESPNOW.BEGIN

Starts the ESP-NOW communications.

Returns 0 if OK or another number in case of error

ESPNOW.DEL_PEER(MAC_add$)

Delete a peer (module)  from the ‘receiver’ list.

The peer is specified by its MAC address (MAC_add$)

Returns 0 if OK or another number in case of error

ESPNOW.STOP

Stops the ESP-NOW communications.

Returns 0 if OK or another number in case of error

ESPNOW.WRITE( msg$)

write a message to the peers defined in the list

The message ‘msg$’ must be less than 250 characters.

Returns 0 if OK or another number in case of error

ESPNOW.WRITE( msg$,MAC_add$)

write a message to a specific peer defined by its MAC address (MAC_add$)

The message ‘msg$’ must be less than 250 characters.

Returns 0 if OK or another number in case of error

EXP(number)

Returns the exponential value of 'number'.

FIX(number)

Truncate a number to a whole number by eliminating the decimal point and all characters to the right of the decimal point.

For example :

     7.11 will return 7

     7.85 will return 7

      -2.11 will return -2

     -2.75 will return -2

The major difference between FIX and INT is that FIX provides a true integer function (ie, does not return the next lower number for negative numbers as INT() does).

See also INT() and CINT() .

FILE.DELETE(filename$)

Delete the file specified by ‘filename$’.

Returns 1 if the delete was successful, otherwise returns 0

FILE.EXISTS(filename$)

Returns 1 if the file ‘filename$’ exists, otherwise returns 0

FILE.SIZE(filename$)

Returns the size of the file (in bytes) if the file exist, otherwise returns -1

FLASHFREE

Returns the free disk memory available (number of bytes)

FUSION.ANGLE(axis)

Returns the angles (in degrees) calculated by the FUSION algorithm.

The returned value is :

AXIS

RETURNED INFORMATION

1

PITCH

2

ROLL

3

YAW

INSTR([start], string$, pattern$)

Returns the position at which 'pattern$’ is located into ‘string$’, starting from (optional) start.

‘start’ can also be a negative number. In this case the pattern will be searched from the end of the string.

The function returns 0 if pattern$ is not found

I2C.LEN

Returns the number of bytes available for retrieval with I2C.READ. This should be called on a master device after a call to I2C.REQFROM.

Example:

Len = I2C.LEN

I2C.READ

Reads a byte that was transmitted from a slave device to a master after a call to I2C.REQFROM.

Example:

b = I2C.READ

I2C.READREGBYTE (i2c_address, register)

Read a byte from a slave device using a given device register address.

‘i2c_address’ define the I2C slave address

‘register’ defines the device register

 

Example:

i2c_addr = &h60 : register = 33

value = I2C.ReadRegByte i2c_addr , register

Will read the value of the register address 33 on the device with i2c address &h60.

 

For clarification, this command is equivalent to the following program:

  i2c.begin i2c_addr

  I2c.write register

  i2c.end 

  i2c.reqfrom i2c_addr, 1

  value = i2c.read

  I2c.end

 

TBD : the syntax must be conformed to the other functions (using parentheses)

I2C.END

Ends a transmission to a slave device that was begun by I2C.BEGIN and transmits the bytes that were queued by I2C.WRITE.

It  returns a value indicating the status of the transmission:

0:success

1:data too long to fit in transmit buffer

2:received NACK on transmit of address

3:received NACK on transmit of data

4:other error

 

Example:

stat = I2C.END

INT(number)

Truncate an expression to the next whole number less than or equal to the argument.

For example :

     7.11 will return 7

     7.85 will return 7

      -2.11 will return -3

     -2.75 will return -3

The FIX() function provides a true integer function.

See also FIX() and CINT() .

LEN(string$)

Returns the length of the string ‘string$’

LOG(number)

Returns the natural logarithm of the argument 'number'

MILLIS

Returns the number of milliseconds elapsed since the start-up of the module

MQTT.Setup(server$ [,debug])

Setup the MQTT communications.

Server$ is the MQTT server url

‘debug’, if set to 1, enable some useful debug messages

Returns 258 at the first initialisation and then 0

MQTT.Certif(cert_pem$ [,client_cert_pem$] [,client_key_pem$])

Set the SSL certificates.

‘cert_pem$’ is used for the main server authorisation

‘client_cert_pem’ and ‘client_key_pem$’ are used for a more complex authorisation scheme (for advanced users)

When setting the certificates, the PSK will be removed

MQTT.PSK(psk_hint_key$)

Set the PSK as an alternative to certificate verification.

When setting this PSK all the certificates will be removed

MQTT.LWT(topic$, message$ [,Qos, [,retain])

Set the last will and testament (LWT) message in the specified topic

Qos can be 0, 1 or 2; if not defined defaults to 0

‘retain’, if set to 1, the message is retained

Returns 0 if OK

MQTT.Connect(login$, pass$ [,id$])

Connect to the server using the provided login and password.

Optionally ID$ permits to define an arbitrary ID

Returns 0 if OK

MQTT.Connect("", "" [,id$])

Connect to the server without identification

Optionally ID$ permits to define an arbitrary ID

Returns 0 if OK

MQTT.Disconnect[()]

Disconnects from the MQTT server

Returns 0 if OK

MQTT.Publish(topic$, message$ [,Qos] [,retain])

Publish a string message in the specified topic

Qos can be 0, 1 or 2; if not defined defaults to 0

‘retain’, if set to 1, the message is retained

Returns the msg_id of the message sent

MQTT.Subscribe(topic$ [,Qos])

Subscribes to messages published to the specified topic.

Qos can be 0, 1 or 2; if not defined defaults to 0

Returns 0 if OK

MQTT.UnSubscribe(topic$)

Unsubscribes from the specified topic

Returns 0 if OK

MQTT.Connected[()]

Returns the current connection status.

Returns 1 if connected or 0 if disconnected

MQTT.Status[()]

Returns the current status. It can be:

    MQTT_STATE_INIT = 0

    MQTT_STATE_DISCONNECTED = 1

    MQTT_STATE_CONNECTED = 2

    MQTT_STATE_WAIT_RECONNECT = 3

NEO.GETPIXEL(pos)

Gets, in a stripline, the 32bit merged color value of the led at position 'led_pos'

 

NEO.RGB(R, G, B)

Returns the 3 supplied R,G,B colours merged into a single 32bit RGB color value, useful for the NEO.PIXEL function and web page colors

PI

Returns the value 3.1415925….

PID1.COMPUTE( current_value, target_value)

Returns the computed value of the given PID controller.

The ‘target_value’ is desired output value while ‘current_value’ is the value coming from the sensor.

This function must be called regularly in a loop

As there are 4 PID controllers, the prefix can be PID1, PID2, PID3 or PID4.

PIN(pin_number)

Returns the value of any external I/O pin.

The pin_number refers to GPIO and can be from 0 ... 5 or 12 ...15

The value returned is 0 if the pin is LOW and 1 if the pin is HIGH

PIN.TOUCH(pin_number)

Returns the touch value for the pin ‘pin_number’.

‘Pin_number’ can be 0, 2, 4, 12, 13, 14, 15, 27 32, 33.

The value returned is around 70 when not touched and around 15 when touched.

PING(host$)

The ping function can be used to test the ability of the ESP32 to reach a specified destination computer. The ping command is usually used as a simple way to verify that a computer can communicate over the network with another computer or network device.

‘host$’ is the remote address to ping. Can be also an IP address.

Returns 1 if the remote host is reachable, otherwise returns 0 if unreachable

Example:

Print PING("www.google.com")

Print PING("192.168.1.1")

Important:

This is a script-only function which doesn’t work in ‘immediate’ mode.

POW(x, y)

Return the number x raised to the power of y

RAMFREE

Returns the free ram available (number of bytes)

RFID.SETUP(CS_pin, RST_pin)

Setup the RFID module.

The module must be connected using the SPI BUS (see wiring in the RFID chapter)

‘CS_pin’ is the pin where the CS signal is connected

‘RST_pin’ is the pin where the RST signal is connected.

The RST signal can be left unconnected; in this case the value of -1 must be set.

This function returns a value following the table below :

 

VALUE

REASON

0

Failed

18

Counterfeit chip

136

Clone

144

Version 0.0

145

Version 1.0

146

Version 2.0

255

Failed

RFID.SETGAIN(gain)

Set the gain (sensitivity) of the RFID module .

By default the gain is 4 and can range from 0 (minimum) to 7 (maximum)

RFID.SETKEY(key$)

Define another password if the card doesn’t use the default FFFFFFFFFFFF

RFID.RESET

Reset the RFID reader.

This is particularly useful when reading using a wrong KEY as this function reset the module and enables it to retry again with another KEY.

RFID.AWAKE

Awake the reader.

This is particularly useful when reading using a wrong KEY as this function awake the module and enables it to retry again with another KEY.

RFID.SETNUID(NUID$)

Write the NUID for “UID changeable card”

See the RFID chapter for more details

RFID.WRITE(block, data$)

Write a block of 16 bytes to the RFID card

‘block’ is the number of the block (from 0 to 63 for MIFARE 1K)

Data is a string like “010102030405060708090A0B”

The function returns the following error values:

MESSAGE

REASON

0

No error

1

Error during the authorisation phase.

Probably the password is not valid

2

Error during the writing phase.

Probably trying to write into a read only block or the content to be written is not valid

RND(number)

Returns a random number in the range from 0 to ‘number' -1

If ‘number’ is equal to 1, the result will be a value less than 1 but greater than or equal to zero.

If ‘number’ is a negative number, it will be used as seed by the pseudo-random number generator algorithm. This will force a deterministic sequence.

If used without arguments (i.e. RND() ), it will return a value from the true random generator with a random number in the range from 0 to 1.

SERIAL.LEN

Returns the number of chars available in the receive buffer of the serial port

SERIAL2.LEN

Returns the number of chars available in the receive buffer of the serial port #2

SGN(number)

Returns the sign of the argument 'number', +1 for positive numbers, 0 for 0, and -1 for negative numbers.

SIN(number)

Returns the sine of the argument 'number' in radians.

SPI.BYTE(byte)

Write and receive a byte on the SPI bus.

Send the content of ‘byte’ and returns the byte received

Example:

r = SPI.BYTE(&haa)

SQR(number)

Return the square root of the argument ‘number’

TAN(number)

Returns the tangent of the argument 'number' in radians.

TFT.RGB(r,g,b)

Returns a 16 bit number representing the RGB565 conversion of a color specified with 8 bit resolution.

‘r’  is the red component; must be in the range 0 to 255

‘g’  is the green component; must be in the range 0 to 255

‘b’  is the blue component; must be in the range 0 to 255

 

Example :

TFT.FILL TFT.RGB(0,255,0)  ‘ fill the screen with a full green color

TIMEUNIX(time$)

Converts a time in format hh:mm:ss into UNIX FORMAT.

See also DATEUNIX, and the complementary UNIXTIME$ and UNIXDATE$

TM1638.BUTTONS

Returns the state of the 8 buttons installed on the module TM1638.

It returns an 8-bit value where each bit is associated with a button

Example :

Print TM1638.BUTTONS  ‘print 1 if the button 1 is pressed

TOUCH.X

Returns the X position of the touched position on the TFT screen.

Useful in combination with the function TOUCH.Y and the command ONTOUCH

TOUCH.Y

Returns the X position of the touched position on the TFT screen.

Useful in combination with the function TOUCH.X and the command ONTOUCH

VAL(string$)

Returns the supplied string converted into a numeric value.

Example :

a$ = “12.34”

b = val(a$)

The same function can also be used to convert from HEX :

a$ = "&hFF01"

b = val(a$)

WIFI.CHANNEL

Returns the current radio channel used for the WIFI communication.

Can be a number from 1 to 13

WIFI.MODE

Return the current mode of the WIFI connection.

The returned value is:

 

VALUE

MEANING

0

The WIFI is in sleep mode

1

The WIFI is in STATION mode

2

The WIFI is in AP mode

3

The WIFI in AP+STA mode

WIFI.NETWORKS  ( network$ )

Returns the number of networks found after the command WIFI.SCAN.

The returned value is :

            -2 if the scan is not started

            -1 if the scan is not terminated

            or the number of networks found (can be 0 if none)

The variable ‘network$’ will contain the list of any networks found.

‘network$’ will contain a line for each network with the SSID, the BSSID and the RSSI separated by comma (,).

 

Example :

WIFI.SCAN

While WIFI.NETWORKS(A$) = -1

Wend

Print a$

 

The result will be (for example) :

Vodaphone, 00:50:56:C0:00:08, -50

Orange, 00:50:56:C0:32:07, -70

Xxxx,  00:50:56:C0:86:CA,-78

WIFI.RSSI

Returns the intensity of the WIFI signal received when connected in STA mode.

The unit of the value received is in db from 0 (zero) to -120 (minus 120). The closer the value to 0 (zero), the stronger the signal will be. An RSSI of -55 (minus 55) is a stronger signal than -70 (minus 70).

WIFI.STATUS

Returns the status of the WIFI connection.

The returned value is :

VALUE

MEANING

0

IDLE

1

NO SSID AVAILABLE

2

SCAN COMPLETED

3

CONNECTED

4

CONNECTION FAILED

5

CONNECTION LOST

6

DISCONNECTED

255

OFF

WORD.COUNT( string$ [,delimiter$])

This function returns the number of words in the specified string.

The string delimiter is optional; when it is not used, the space character is the delimiter.

Example :

a$ = "abc def ghi ijk"

Print WORD.COUNT(a$)  ‘ will print 4

b$ = "the-!-quick-!-brown-!-fox-!-jumps-!-over"

Print WORD.COUNT(b$ "-!-")will print 6

See also WORD$, WORD.DELETE$ and WORD.FIND.

WORD.FIND( string$, find$ [,delimiter$])

This function returns the word position in the string.

The string delimiter is optional; when it is not used, the space character is the delimiter.

If the word is not found, the result is 0.

Example :

a$ = "abc def ghi ijk"

Print WORD.FIND(a$, "ghi")  ‘ will print 3

b$ = "the-!-quick-!-brown-!-fox-!-jumps-!-over"

Print WORD.FIND(b$, "fox", "-!-") ‘ will print 4

See also WORD$, WORD.DELETE$ and WORD.COUNT.

 

STRING FUNCTIONS

BAS.ERRMSG$

Return a string representing the error message that would have normally been displayed on the console. It is reset to “No Error” by: running the program, or with the command ONERROR CLEAR, or ONERROR IGNORE, or ONERROR SKIP.

BAS.FILENAME$

Returns the name of the current basic file

BAS.FTP$( host$, login$, password$, file$, folder$)

Transfer a file stored locally on an FTP server.

Returns an explicit text message as the result of the operation.

host$ is the address of the FTP server

login$ is the login of the account on the FTP server

password$ is the password of the account on the FTP server

file$ is the file that will be sent

folder$ is the folder where the file will be sent

BAS.PASSWORD$

Returns the password used for the STATION wifi connection.

 

BAS.RTCMEM$

Returns the content of the CPU RTC internal memory.

This memory maintains the contents between resets, so it is useful in association with the SLEEP command when the module goes in low power mode.

This memory is limited at 7680 bytes and can be set with the corresponding command  BAS.RCTMEM$ = “xxx”.

The content of this memory is lost in case of power OFF.

BAS.SSID$

Returns the login used for the STATION wifi connection.

BAS.VER$

Returns the version of the Basic in string format

Example:

Print BAS.VER$

Annex WI-Fi Basic 1.36 beta

BIN$(number)

Returns the Binary representation of the argument ‘number’.

The number is converted to integer before the conversion.

BUTTON$(name$, label [, id] )

Returns a string containing the html representation of a button.

‘name$’ represent the text shown in the button,

‘label’ is the GOSUB label where it will branch to when clicked,

‘id’ is an optional argument that can be used to define the ID of the object (useful to style it with CSS).

The function called when clicking on the button must always terminate with the RETURN command

Check the chapter about html objects for more details

CHECKBOX$( variable [,id])

Returns a string containing the html representation of a checkbox.

‘variable’ is the variable associated with the checkbox; changing the value of the variable in the basic code will change also the value in the html and vice-versa (0 = unchecked, 1 = checked).

The variable must be Numerical.

‘id’ is an optional argument and can be used to define the ID of the object (useful to style it with CSS).

When the value is changed by the user, the event ‘onHtmlChange’ is triggered.

Check the chapter about html objects for more details

CHR$(number)

Returns a string containing the ASCII character with the code ‘number’

Example: z$ = CHR$(64)

now z$ contains the "@" character

number must be between 0-255

CSSID$(object_id, object_style)

Returns a string containing the css representation of style defined for a given object.

‘object_id’ represents the ID of the object to be styled.

‘object _style’ represents the property to be given to the object.

Check the chapter about html objects for more details

DATE$[(format)]

Returns the actual date with the format dd/mm/yy

The time takes into account the Time Zone parameter defined into the "Config" page.

If ‘format’ is specified, the format can be :

format = 1  => American format  M/D/Y

format = 2 => Canadian format Y/M/D

ESPNOW.ERROR$

Returns the MAC address of the device(s) that didn’t received the message

ESPNOW.READ$

Returns the message received from the ESP-NOW peer

ESPNOW.REMOTE$

Returns the MAC address of the emitter of the message received

FILE.DIR$[(path$)]

Will search for files and return the names of entries found.

 'path$' represents the directory name.

 'path$' can include wildcards characters as ‘*’, ‘.’ and ‘?’

The function will return the first entry found.

To retrieve subsequent entries use the function with no arguments. ie, DIR$.

The return of an empty string indicates that there are no more entries to retrieve.

Example, to get all the files present in the directory /html :

d$ = FILE.DIR$("/html")

While D$ <> ""

  Print d$

  d$ = FILE.DIR$

Wend

Valid wildcard expressions are :

d$ = FILE.DIR$(“/html/ex*.html”)  ‘ returns all the files starting with the “ex”

d$ = FILE.DIR$(“/html/list.*”)  ‘ returns all the files named list.xxx

FILE.READ$(filename$,[line_num] | [start, length])

Returns the content of the file ‘filename$’.

Specifying 'line_num', only the corresponding line is read from the file.

If start and length options are specified, the file is read from the ‘start’ position for ‘length’ characters, otherwise the complete file is read in one go.

The line number starts from 1.

If the line is not existing (reached the end of file), the function will return “_EOF_” to indicate the end of the file.

HEX$(number)

Returns the Hexadecimal representation of the argument ‘number’

The number is converted to integer before the conversion.

HtmlEventButton$

returns the name of the button that generates the jump.

Useful to manage several buttons in the same function

HtmlEventVar$

Returns the name of the variable changed during the event onHtmlChange.

Useful to determine the object that changed its value

IMAGE$(path [,id])

Returns a string containing the html representation of an image.

‘Path’ represents the url of the image; it can be local or from the internet.

‘id’ is an optional argument and can be used to define the ID of the object (useful to style it with CSS)

Check the chapter about html objects for more details

IMAGEBUTTON$(path, label [,id])

Returns a string containing the html representation of an image that can be clicked as a button.

‘Path’ represents the url of the image; it can be local or from the internet.

‘label’ is the GOSUB label where it will branch to when clicked,

‘id’ is an optional argument and can be used to define the ID of the object (useful to style it with CSS)

The function called when clicking on the image must always terminate with the RETURN command

Check the chapter about html objects for more details

IP$

Returns the local IP address, the Subnet mask and the Gateway address separated by space.

Example:

Print IP$ ‘print the complete address separated by single space

192.168.1.45 255.255.255.0 192.168.1.1

Print WORD$(IP$,1) ‘ will print only the IP

192.168.1.45

IR.GET$[ (param) ]

Returns the code received by the IR receiver.

In function of the param value, the function returns :

 

PARAM

RETURNED VALUE

0 or missing

Hexadecimal code

1

Decode type

2

Address

3

Command

4

Bits

5

Repeat

 

Must be used in association with the command IR.INIT and ONINFRARED

Example

IR.GET$ ‘ will print the HEX code received

JSON$(string$, field$)

Will parse a json string for a named data element within it.

If the element is found, its value is returned in String format, else the text "not found".

The key can have the following syntax :

"Key.subkey.innerkey….." .

 Array can also be included such as "weather[5].description"

LCASE$(string$)

Returns ‘string$’ converted to lowercase characters

LED$(variable [,id])

Returns a string containing the html representation of a led.

‘variable’ represents the variable associated with the led; changing the value of the variable in the basic code will change the led from red (0) to green ( any value not equal to 0).

The variable must be Numerical.

‘id’ is an optional argument and can be used to define the ID of the object (useful to style it with CSS)

Check the chapter about html objects for more details

LEFT$(string$, num)

Returns the leftmost ‘num’ characters of ‘string$’

LISTBOX$(variable$, "option1, option2, option3, ..." [, height]  [,id])

Returns a string containing the html representation of a listbox / combobox.

‘variable$’ represent the variable associated with the listbox;

changing the value of the variable in the basic code will change also the value in the html and vice-versa. The variable must be type String.

‘option1’, ‘option2’, …. represent the content of the listbox.

‘height’ is an optional parameter and defines the height of the listbox; if not specified, the object will be a combobox

‘id’ is an optional argument used to define the ID of the object (useful to style it with CSS).

When the value is changed by the user, the event ‘onHtmlChange’ is triggered.

Check the chapter about html objects for more details

MAC$[ (id) ]

Returns the active MAC address. It consists of 6 hex bytes separated by colons.

It must be noted that the MAC address can be different if the module is connected in Station mode or in AP mode.

Example:

Print MAC$

62:01:94:5E:37:8D

 

Optionally it is possible to select the address to be shown using the argument ‘id’

Example :

Print MAC$(0)  ‘ print the Station mode address

60:01:94:5E:37:8D

Print MAC$(1) ‘ print the AP mode address

62:01:94:5E:37:8D

METER$(variable, min, max [,id])

Returns a string containing the html representation of a meter.

‘variable’ represents the variable associated with the slider; changing the value of the variable in the basic code will change the value in the html.

The variable must be Numerical.

‘min’ and max represent the minimum and maximum value of the meter.

‘id’ is an optional argument which can be used to define the ID of the object (useful to style it with CSS)

Check the chapter about html objects for more details

MID$(string$, start [,num])

Returns a substring of ‘string$’ starting from ‘start’ with a length of ‘num’ characters. If ‘num’ is not defined, the result will continue until the end of the line

Start must be integer starting at 1

example:

z$="Hello World"

wlog mid$(z$,4,5) ‘will print "lo Wo"

MQTT.Message$

Returns the MQTT message received

MQTT.Topic$

Returns the MQTT topic received or the event name.

The event can be:

 

Value

Event

_BEFORE_CONNECT_

Raised before the connection is done. Useful to determine if the module is trying to (re)connect

_CONNECTED_

Raised when the connection is done

_DISCONNECTED_

Raised when the connection is lost

_ERROR_

Raised in case of error

OCT$(number)

Returns the Octal representation of the argument ‘number’

The number is converted to integer before the conversion.

PASSWORD$(variable [, id] )

Returns a string containing the html representation of a password textbox..

‘variable’ represents the variable associated with the textbox; changing the value of the variable in the basic code will change also the value in the html and vice-versa. The variable can be Numerical or String.

‘id’ is an optional argument which can be used to define the ID of the object (useful to style it with CSS)

Check the chapter about html objects for more details

REPLACE$(expression$, find$, replacewith$)

Returns a substring of ‘expression$’ where any instances of the text inside ‘find$’ is replaced with ‘replacewith$’

RFID.NUID$

Returns the NUID of the RFID card detected

RFID.TYPE$

Returns the type (model) of the RFID card detected

It can return any of the following values:

TYPE

PICC compliant with ISO/IEC 14443-4

PICC compliant with ISO/IEC 18092 (NFC)

MIFARE Mini, 320 bytes

MIFARE 1KB

MIFARE 4KB

MIFARE Ultralight or Ultralight C

MIFARE Plus

MIFARE DESFire

MIFARE TNP3XXX

SAK indicates UID is not complete.

Unknown type

 RFID.READ$(block [,key_b])

Reads a block of 16 bytes from the RFID card.

‘block’ is the number of the block (from 0 to 63 for MIFARE 1K)

‘key_b’ if not present or 0 the card will be read using the KEY A

If ‘key_b” is equal to 1, the card will be read using the KEY B

The result will be a string like “010102030405060708090A0B0C0D0E0F”

or a message indicating that an error is occurred :

 

MESSAGE

REASON

Auth Failed

Error during the authorisation phase.

Probably the password is not valid

Read Failed

Error during the reading phase.

Probably the card has been moved too far from the reader

RIGHT$(string$, num)

Returns the rightmost ‘num’ characters of ‘string$’

RTC.DATE$[(format)]

Returns the RTC module date with the format dd/mm/yy

The module can be DS1307 or DS3231

If ‘format’ is specified, the format can be :

format = 1  => American format  M/D/Y

format = 2 => Canadian format Y/M/D

See also the RTC.SETTIME and RTC.TIME$

NOTE : If no RTC is connected, (or is not connected correctly) then will return "165/165/165"

RTC.TIME$

Returns the RTC module time with the format hh:mm:ss.

The module can be DS1307 or DS3231

See also the RTC.SETTIME and RTC.DATE$

NOTE : If no RTC is connected, (or is not connected correctly) then will return "45:165:165"

SERIAL.CHR$

Returns the first character present in the input buffer of the serial port

Useful in association with the command ONSERIAL

SERIAL.INPUT$

Returns all the characters present in the input buffer of the serial port.

Useful in association with the command ONSERIAL

SERIAL2.CHR$

Returns the first character present in the input buffer of the serial port #2

Useful in association with the command ONSERIAL

SERIAL2.INPUT$

Returns all the characters present in the input buffer of the serial port #2

Useful in association with the command ONSERIAL2

SLIDER$(variable, min, max [,step] [,id])
 

Returns a string containing the html representation of a slider.

‘variable’ represents the variable associated with the slider; changing the value of the variable in the basic code will change also the value in the html and vice-versa. The variable must be Numerical.

‘Min’ and max represent the minimum and maximum value of the slider.

The optional argument ‘step’ represents the minimal increment (by default the value is 1).

‘id’ is an optional argument which can be used to define the ID of the object (useful to style it with CSS).

When the value is changed by the user, the event ‘onHtmlChange’ is triggered.

Check the chapter about html objects for more details

SPACE$(number)

Returns a string consisting of the specified number of spaces.

SPI.STRING$(data$, len)

Write and receive a string on the SPI bus.

Write the content of ‘len’ characters of the string ‘data$’

Example:

a$ = SPI.STRING("hello", 5)

SPI.HEX$(datahex$, len)

Write and receive an HEX string on the SPI bus.

The string is a sequence of hex characters (2 for each byte)

Write the content of ‘len’ characters of the string ‘data$’

Example:

a$ = SPI.HEX("A0B1C2D3E4F5", 6) ‘ send 6 bytes (sequence of A0, B1, C2, D3, E4, F5) and receive the result in a$

STR$ (number [,format$ [,toint]])

Returns the argument ‘‘number’ converted to string format.

 

The optional ‘format$’ permits to define how the number is printed.

The format is based on ‘C’ printf command.

The additional ",1" is required for the number types marked “Integer” in the table below.

Example :

a = 12.34567890

Print STR$(a, "%7.4f")  ‘ will print 12.3456

Print STR$(a, "%8.5f")  ‘ will print  12.34567

 

a = 255

Print STR$(a, "%04x", 1)  ‘ will print 00FF  ‘HEX

Print STR$(a, "%04o", 1)  ‘ will print 0377  ‘OCT

 

The formats available are :

 

FORMAT

DESCRIPTION

TYPE

c

Char

Integer

d

Signed Integer

Integer

e

Exponential

Float

f

Floating Point

Float

g

Use shorter of the two formats

f or e

Float

o

Octal

Integer

p

Pointer (8 digits hex)

Integer

P

Pointer without 0x

Integer

u

Unsigned Integer

Integer

x

Hexadecimal (lower case letters)

Integer

X

Hexadecimal (upper case letters)

Integer

 

The format must observe the following rule :

 

%[integer_with][.][precision][format]

 

For example to specify a floating number composed of 4 digits before the decimal point and 3 digit after the point you must write : %4.3f

 

Example for several formats

 

Format

Number

Result

 

%2.1f

14.33

14.3

28.128

28.1

 

%4.3f

15

  15.000

4152.3751

4152.375

 

%1.4e

128

1.2800e+02

12852

1.2852e+02

%04f

12

0012

%4x

255

  ff

%04X

255

00FF

STRING$(num, char$)

Returns a string ‘num’ chars long composed of the char ‘char$’ - char$ can also be a string of chars, eg: "<BR>" or "&nbsp;"

TEMPR$(pin_number [,ID])

Returns information from the DS18B20 temperature sensor

 

The syntax is a$ = TEMPR$(pin_number [, ID])

 

The ‘pin number’ is any available pin of the device; it can change between calls permitting to use several pins at the same time.

The ID can be a number, a String, or not specified:

- If is a number (say 'n'), the result will be the temperature (in °C) of the nth device connected on that pin

- If is a string, it must contains the Hex address of the device requested; this address can be recovered using the command without this argument

- If not specified, the result will be the address list of the devices connected on the pin (blocks of 8 bytes separated by ',')

Example using 2 DS18B20 are connected on the pin 12 :

Print TEMPR$(12,1) ‘ will print 20.5

Print TEMPR$(12,2) ‘ will print 22.3

 

Print TEMPR(12) ‘will print 28ff5bdb701604f0,28ff5bdb7016045

 

Print TEMPR(12,"28ff5bdb701604f0") ‘will print 20.5

 

The sensors can also be read in async mode:

 

Giving 0 as ID, starts the conversion on all the DS18B20 sensors connected without waiting for the answer

 

For example

ret$ = TEMPR$(2, 0) ' starts an async read on the pin 2

 

The result will be the string "START"

 

Then, it will be possible to read the devices as below

 

ret1$ = TEMPR$(2, 1) 'read the 1st sensor on the pin 2

ret2$ = TEMPR$(2, 2) 'read the 2nd sensor on the pin 2

 

In this case, if the value is not yet available (during the conversion time) the result will be "WAIT' that will be replaced by the good value at the end of the conversion.

 

To restart another conversion, the same command must be executed

ret$ = TEMPR$(2, 0) ' starts an async read on the pin 2

TEXTAREA$(variable [, id] )

Returns a string containing the html representation of a textarea.

‘variable’ represent the variable associated with the textarea;

changing the value of the variable in the basic code will change also the value in the html and vice-versa. The variable can be Numerical or String.

‘id’ is an optional argument and can be used to define the ID of the object (useful to style it with CSS).

‘Variable’ can have several lines separated by the character chr$(13).

When the value is changed by the user, the event ‘onHtmlChange’ is not triggered automatically but only when the focus is lost (for example when another html element is selected).

Check the chapter about html objects for more details

TEXTBOX$(variable [, id] )

Returns a string containing the html representation of a textbox.

‘variable’ represent the variable associated with the textbox;

changing the value of the variable in the basic code will change also the value in the html and vice-versa. The variable can be Numerical or String.

‘id’ is an optional argument which can be used to define the ID of the object (useful to style it with CSS).

When the value is changed by the user, the event ‘onHtmlChange’ is triggered.

Check the chapter about html objects for more details

TRIM$(string$)

Returns ‘string$’ with the leading and trailing spaces removed

TIME$

Returns the actual time with the format hh:mm:ss.

The time takes into account the Time Zone parameter defined into the "Config" page.

UCASE$(string$)

Returns ‘string$’ converted to uppercase characters

UDP.READ$

Returns the UDP message received, or an empty string if no message received.

Useful in association with the command ONUDP

UDP.REMOTE$

Returns the IP address and the port of the sender of the message received.  The format is IP:port  (example 192.168.1.88:5541).

Useful in association with the command ONUDP

UNIXDATE$(value [,format])

Returns a date with the format dd/mm/yy extract from ‘value’ given in UNIX format. The value can be Numerical or String.

This is useful to extract the date from the JSON string given by OpenWeatherApi

if ‘format’ is specified, the format can be :

format = 1  => American format  M/D/Y

format = 2 => Canadian format Y/M/D

See also the complementary DATEUNIX()

UNIXTIME$(value)

Returns a time with the format hh:mm:ss extract from ‘value’ given in UNIX format. The value can be Numerical or String.

This is useful to extract the time from the JSON string given by OpenWeatherApi

See also the complementary TIMEUNIX()

URLMSGGET$ ([arg$])

Get the message received from the URL AJAX GET request.

Returns the value of the url argument defined in arg$.

If arg$ is missing, all the arguments are returned (useful for debugging).

Useful in combination with ONURLMESSAGE and URLMSGRETURN

Example : if a remote client makes the following url request :

http://esp_local_ip/msg?red=10&green=20&blue=30

Print URLMSGGET$("red")     ‘ will return 10

Print URLMSGGET$("green")   ‘ will return 20

Print URLMSGGET$("blue")    ‘ will return 30

Print URLMSGGET$() ‘ will return  red=10&green=20&blue=30

More information here

WGET$( http_server$, port [,header] )

Returns the result of a GET server request.

‘http_server$’ is the server url request

‘port’ is the port number; if port=443, the connection will be done using SSL (secure).

‘Header’, if =1, will include the header in the answer (useful for debug)

The program will stop waiting for the answer.

Example :

print WGET$("www.fakeresponse.com/api/?sleep=5", 80)

In this case the program will stop 5 seconds waiting for the answer of the server.

See the command WGETASYNC to avoid this limitation.

WGET$( url$, [,header] )

Returns the result of a GET server request.

url$’ is the web server url request

if ‘url$’ starts with https:// , the connection will be done using SSL (secure).

‘Header’, if =1, will include the header in the answer (useful for debug)

The program will stop waiting for the answer.

Example :

print WGET$("https://jsonplaceholder.typicode.com/comments?id=1&id=4")

In this case the program will stop waiting for the answer of the server.

See the command WGETASYNC to avoid this limitation.

WGETRESULT$

Return the message received asynchronously from the command WGETASYNC

WORD$(string$, position [,delimiter$])

This function returns the nth word in the string, where n=1 or greater.

The string delimiter is optional; when it is not used, the space character is the delimiter.

Example :

a$ = "abc def ghi ijk"

Print WORD$(a$, 3)  ‘ will print ghi

b$ = "the-!-quick-!-brown-!-fox"

Print WORD$(b$, 2, "-!-") ‘ will print quick

See also WORD.COUNT, WORD.FIND and WORD.DELETE$

WORD.DELETE$(string$, position [delimiter$])

This function returns a string where the nth word has been deleted.

The string delimiter is optional; when it is not used, the space character is the delimiter.

Example :

a$ = "abc def ghi ijk"

Print WORD.DELETE$(a$, 3)  ‘ will print abc def ijlk

b$ = "the-!-quick-!-brown-!-fox"

Print WORD.DELETE$(b$, 2, "-!-") ‘ will print the-!-brown-!-fox

See also WORD, WORD.COUNT and WORD.FIND.

WORD.EXTRACT$(string$, lead$, trail$)

Returns the substring included between lead$ and trail$.

Example

a$ = “https://www.google.com/test

Print WORD.EXTRACT$(a$, “https://”, “/test”) ‘ will print www.google.com

WORD.GETPARAM$( setting$, parameter$  [,separator$])

Get a parameter from a string containing a series of parameters stored as below:

param1=value1

param2=value2

…….

paramx=valuex

‘setting$’ defines the string containing the set of parameters

‘parameter$’ defines the parameters to be got.

‘separator$’ is an optional parameter specifying a different separator character.

Example, assuming that setting$ contains the parameters :

print WORD.GETPARAM$(setting$, "param2")‘will print value2

 

By default the separator is the character ‘=’.

Useful in combination with WORD.SETPARAM and FILE.READ$

WPOST$(server$, body$, port [,header])

Returns the result of a POST server request.

‘http_server$’ is the server url request

‘body$’ is the field that will be sent in the request

‘port’ is the port number; if port=443, the connection will be done using SSL (secure).

‘Header’, if =1, will include the header in the answer (useful for debug)

The program will stop while waiting for the answer.

Example :

print  WPOST$("ptsv2.com/t/annextest/post", "name=Annex&version=1.39", 80)

WPOST$(url$, body$,  [,header])

Returns the result of a POST server request.

‘url$’ is the web server url request

‘body$’ is the field that will be sent in the request

If ‘url$’ starts with https:// the connection will be done using SSL (secure).

‘Header’, if =1, will include the header in the answer (useful for debug)

The program will stop while waiting for the answer.

Example :

print  WPOST$("https://ptsv2.com/t/annextest/post", "name=Annex&version=1.39")

 

 

COMMANDS:

 

AUTOREFRESH interval

Same function of the command REFRESH but with an automatic interval.

Define the variables refresh interval in milliseconds.

This should never be lower than 300ms due to performance reasons.

NOTE: It must be run after the command CLS as it is managed into the javascript.

BAS.LOAD filename$

Loads another .bas program and runs it immediately.

Returns 0 if the successful or -1 if the file was not found

Example:

Print BAS.LOAD "/test.bas"

BAS.RTCMEM$ = val$

Set the content of the CPU RTC internal memory.

This memory maintains the content between reset, so it is useful in association with the SLEEP command when the module goes in low power mode.

The content of this memory is lost in case of power OFF.

This memory is limited at 7680 bytes, and can be read with the corresponding command  val$ = BAS.RCTMEM$

CLS

Clear the html content of the page to all the clients connected by Websockets.

 

Check the chapter about html objects for more details

See also the commands HTML, JSCALL, JSCRIPT, JSEXTERNAL, CSS and WLOG

CSS style_code$

Send a CSS style code to the page to all the clients connected by Websockets.

 

Check the chapter about html objects for more details

See also the commands HTML, JSCALL, JSCRIPT, JSEXTERNAL, CLS and WLOG

COMMAND cmd$

Permit to execute any basic command defined into ‘cmd$’.

It acts as a macro command like the immediate window

Example :

COMMAND ("print sin(PI/2)")  ‘will print 1

COUNTER.RESET cnt

Reset the counter to 0 (count and period).

‘cnt” defines the counter and can be 1 or 2

COUNTER.SETUP cnt, pin [,mode]

Setup a counter in association with a pin.

There are 2 counters that can count the number of pulses or the period between pulses.

‘cnt” defines the counter and can be 1 or 2

‘pin’ defines the pin and can be any valid pin number

‘mode’ defines the when the pulses are taken into account :

 

MODE

EDGE

1

On the RISING edge

2

On the FALLING edge

3

On CHANGE

 

 If not specified, the mode is 3 (on change)

CSSEXTERNAL file$

Define an external css file to be used in the page of all the clients connected by Websockets.

 

Check the chapter about html objects for more details

See also the commands CLS, HTML, JSCALL, JSCRIPT, CSS and WLOG

DATA const1 [,const2] ...

Stores numerical and string constants to be accessed by READ.

String constant must be between double quotes "

Expressions can be used for the numerical constants (ex. PI * 2)

DECR var [, decrement]

Decrements the variable "var" by 1 or, if specified, by the value in "decrement".

This functionally is equivalent to var = var - decrement but executes more efficiently.

DHT.SETUP pin, model

Set the parameters for Temperature / Humidity sensor DHT11, DHT21 or DHT22

The syntax is DHT.SETUP pin, model

The pin number is any available pin of the device;

The model can be 11, 21 or 22 (for DHT11, DHT21 or DHT22)

See also the functions DHT.TEMP, DHT.HUM and DHT.HEATINDEX

EMAIL.SETUP server$, port, user_name$, password$ [, debug]
 

Setup the parameters for an SMTP server to be used to send e-mails.

This command must be executed before using the command EMAIL or EMAILASYNC.

An SMTP account like <mail.smtp2go.com> is required.

NEW : The command uses an SSL connection, so it should work with any SMTP service provider; the port should be 465

‘server$’ is the url of the service provider (ex. mail.smtp2go.com)

‘Port’ is the port required (ex. 465)

‘user_name$’ is the login name of the SMTP account

‘password$’ is the password of the SMTP account

All the parameters are required.

The last optional parameter ‘debug’ if set to 1, enables a debug mode useful to catch connection problems.

Example :

EMAIL.SETUP "mail.smtp2go.com", 465, "my_login", "my_pass"

EMAILASYNC from$, to$, subject$, message$

Send an e-mail in async mode; this means that the request is managed in the background and the program will continue to run without interruptions.

‘from$’ is the email address of the sender (ex: from_me@yahoo.com)

‘to$’’ is the email address of the receiver  (ex: to_you@yahoo.com)

‘subject$’ is the subject of the message

‘message$’ is the content of the message

The sender and receiver must be a valid email addresses.

Example :

EMAILASYNC ("from_me@yahoo.com", "to_you@gmail.com", "Important message " + date$,  "The memory available is " + str$(ramfree) )

FILE.FROMBASE64 source$, dest$

Convert the file defined ‘source$’ into the file defined in ‘dest$’.

The source file can be in any format but must be encoded in base64 format.

Useful for wokwi to store any file in text format

FILE.SAVE filename$, content$

Save the content of ‘content$’ in the file ‘filename$’.

The file can be read back using the function FILE.READ$(filename$).

File size is only limited by available disk space (FFAT or external SD card)

FILE.TOBASE64 source$, dest$

Convert the file defined ‘source$’ into the file defined in ‘dest$’.

The source file can be in any format and will be encoded in base64 format.

FUSION.INIT

Initialise the FUSION IMU / AHRS algorithm

FUSION.MADGWICK ax, ay, az, gx, gy, gz

Execute the MADGWICK 6 DOF algo

The input parameters are the following :

 

PARAM

MEANING

UNITY

ax

Acceleration on x axis

g *

ay

Acceleration on y axis

g *

az

Acceleration on z axis

g *

gx

Gyro on x axis

°/sec

gy

Gyro on y axis

°/sec

gz

Gyro on z axis

°/sec

(*) the unit is not really important but must be consistent between the group

This algo utilise the variables FUSION.BETA and FUSION.ZETA

FUSION.MADGWICK ax, ay, az, gx, gy, gz, mx, my, mz

Execute the MADGWICK 9 DOF algo

The input parameters are the following :

 

PARAM

MEANING

UNITY

ax

Acceleration on x axis

g *

ay

Acceleration on y axis

g *

az

Acceleration on z axis

g *

gx

Gyro on x axis

°/sec

gy

Gyro on y axis

°/sec

gz

Gyro on z axis

°/sec

mx

Magnetometer on x axis

milligauss *

my

Magnetometer on y axis

milligauss *

mz

Magnetometer on z axis

milligauss *

(*) the unit is not really important but must be consistent between the group

This algo utilise the variable FUSION.BETA

FUSION.MAHONY ax, ay, az, gx, gy, gz, mx, my, mz

Execute the MAHONY 9 DOF algo

The input parameters are the following :

 

PARAM

MEANING

UNITY

ax

Acceleration on x axis

g *

ay

Acceleration on y axis

g *

az

Acceleration on z axis

g *

gx

Gyro on x axis

°/sec

gy

Gyro on y axis

°/sec

gz

Gyro on z axis

°/sec

mx

Magnetometer on x axis

milligauss *

my

Magnetometer on y axis

milligauss *

mz

Magnetometer on z axis

milligauss *

 

(*) the unit is not really important but must be consistent between the group

This algo utilise the variables FUSION.KP and FUSION.KI

FUSION.BETA =

Set the BETA parameter. This is used for the MADGWICK algo 6 DOF and 9 DOF.

FUSION.ZETA =

Set the ZETA parameter. This is used for the MADGWICK algo 6 DOF.

FUSION.KI =

Set the KI parameter. This is used for the MAHONY algo 9 DOF.

FUSION.KP =

Set the KP parameter. This is used for the MAHONY algo 9 DOF.

HTML code$

Send html content to the page of all the clients connected by Websockets.

 

Check the chapter about html objects for more details

See also the commands CLS, JSCALL, JSCRIPT, JSEXTERNAL, CSS and WLOG

I2C.SETUP sda_pin, scl_pin [,freq ]

Initiate the Wire library and join the I2C bus as a master. The ‘sda_pin’ and ‘scl_pin’ define the pins to be used as SDA and SCL signals.

The frequency (up-to 4 Mhz) can be defined using the parameters ‘freq’ in hertz

Example:

I2C.SETUP 21, 22 ‘ define the pin 21 as SDA and the pin 22 as SCL

I2C.BEGIN address

Begin a transmission to the I2C slave device with the given address. Subsequently, queue bytes for transmission with the I2C.WRITE command and transmit them by calling I2C.END command.

‘address’ defines the 7-bit address of the device to transmit to

Example:

I2C.BEGIN &h57 ‘ begins the transmission on the address hex 57

I2C.END

Ends a transmission to a slave device that was begun by I2C.BEGIN and transmits the bytes that were queued by I2C.WRITE.

Example:

I2C.END

 

It can also returns a value indicating the status of the transmission:

0:success

1:data too long to fit in transmit buffer

2:received NACK on transmit of address

3:received NACK on transmit of data

4:other error

 

Example:

stat = I2C.END

I2C.REQFROM address, length

Used by the master to request bytes from a slave device. The bytes may then be retrieved with the I2C.LEN and I2C.READ functions.

 

‘address’ defines the 7-bit address of the device to request bytes from

‘Length’ defines the number of bytes to request

Example:

I2C.REQFROM &h57, 8 ‘ requests for 8 bytes from the address hex 57

 

I2C.READREGARRAY i2c_address, register, nb_of_bytes, Array()

Read a series of bytes from a slave device using a given device register address.

The result is copied into an array given as argument.

Each received byte will be placed into an element of the array (starting from 0).

The array must be defined before the command with enough space to receive the bytes.

Example :

Dim MyArray(10) : i2c_addr = &h60 : register = 33 : length = 7

I2C.ReadRegArray i2c_addr , register, length , MyArray()

Will read 7 bytes from the register address 33 on the device with i2c address &h60.

The result will be placed into MyArray where MyArray(0) will contain the 1st received byte, MyArray(1) the 2nd, …..

 

For clarification, this command is equivalent to the following program:

 

  i2c.begin i2c_addr

  i2c.write register

  i2c.end 

  i2c.reqfrom i2c_addr, length

  for i = 0 to length - 1

    MyArray(i) = i2c.read

  next i

  i2c.end

I2C.WRITE value

Writes queues bytes for transmission from a master to slave device (in-between calls to I2C.BEGIN and I2C.END).

 

‘value’ represents a value to send as a single byte

Example:

I2X.WRITE &h55

I2C.WRITEREGBYTE i2c_address,register, value

Write a byte to a slave device using a given device register address.

‘i2c_address’ define the I2C slave address

‘register’ defines the device register

‘value’ defines the value to be written into the device

Example:

i2c_addr = &h60 : register = 33 : value = 55

I2C.WriteRegByte i2c_addr , register, value

Will write 55 in the register address 33 on the device with i2c address &h60.

 

For clarification, this command is equivalent to the following program:

 

  i2c.begin i2c_addr

  I2c.write register

  i2c.write value

  i2c.end 

I2C.WRITEREGARRAY i2c_address, register, nb_of_bytes, Array()
 

Write a series of bytes to a slave device using a given device register address.

The values to be written are taken from an array given as argument.

Each byte must be placed into an element of the array (starting from 0).

The array must be defined before the command and set with the desired byte sequence to be sent

Example :

Dim MyArray(10) : MyArray(0) = 12 : MyArray(1) = 34 : MyArray(2) = 56

i2c_addr = &h60 : register = 33 : length = 3

I2C.WriteRegArray i2c_addr , register, length , MyArray()

Will write 3 bytes to the register address 33 on the device with i2c address &h60.

The sequence 12, 34, 56 will be written to the device

 

For clarification, this command is equivalent to the following program:

 

  i2c.begin i2c_addr

  i2c.write register

  for i = 0 to length - 1

    i2c.write MyArray(i)

  next i

  i2c.end

INCR var [, increment]

Increments the variable "var" by 1 or, if specified, by the value in "increment".

This functionally is equivalent to var = var + increment but executes more efficiently.

 

INPUT.TIMEOUT timeout

Define the time (in milliseconds) that the INPUT command will wait for an input from the serial port (console). After this time the INPUT will return an empty value.

INPUT.TIMEOUT 0 removes the timeout

INPUT["prompt$";] variable
 

Allows input from the console to a variable.

The input command will prompt with a question mark (?).

If the "prompt string$" is specified it will be printed before the question mark.

During the input command the execution of the program will be stopped waiting for an input from the serial port. This can be an issue as the program can get stuck.

The command INPUT.TIMEOUT will permit to interrupt the command after a given timeout duration to prevent it waiting for input indefinitely.

INTERRUPT pin_no, {OFF | label} [, mode]

Specifies a branch label for the interrupt to jump to when the designated input pin signal changes. The optional 'mode' parameter allows you to specify the trigger condition for the interrupt: rising edge, falling edge, or any change in signal. The 'OFF' keyword can be used to remove the interrupt associated with the specified input pin.

Parameters:

- pin_no: The input pin number for which the interrupt is being defined. It must be an integer value ranging from 0 to 39.

- label: The branch label to which the program will jump when the designated input pin signal changes. It must be a valid label in the program's context.

- OFF: Use this keyword to remove the interrupt associated with the specified input pin.

- mode (optional): An integer parameter specifying the trigger condition for the interrupt. It can take one of the following values:

  - 1, RISING: Rising edge trigger

  - 2, FALLING: Falling edge trigger

  - 3, CHANGE: Any change in signal trigger (default if 'mode' parameter is omitted)

IR.INIT pin_rx | OFF [, pin_tx]

Initialise the IR receiver and the IR transmitter

‘pin_rx’ is the pin where the IR receiver is connected

‘pin_tx’ is the pin where the IR led is connected

 

If ‘pin_rx’ is OFF, the receiver is disabled

If ‘pin_tx’ is not defined, the transmitter is disabled

Example :

IR.INIT 14, 12 ‘define the pin 14 for the receiver and the pin 12 for the transmitter

IR.SEND type, code$, bits

Send a code via the IR transmitter

‘type’ is the type of RC (3 = NEC, ...)

‘code$’ is the code in hexadecimal format

‘bits’ is the number of bits (32, ...)

JSCALL javaCode$

Send javascript content to the page of all the clients connected by Websockets.

 

Check the chapter about html objects for more details

See also the commands CLS, HTML, JSCRIPT, JSEXTERNAL, CSS and WLOG

JSCRIPT script$

Execute a javascript content in the page of all the clients connected by Websockets.

 

Check the chapter about html objects for more details

See also the commands CLS, HTML, JSCALL, JSEXTERNAL, CSS and WLOG

JSEXTERNAL file$

Define an external javascript file to be used in the page of all the clients connected by Websockets.

 

Check the chapter about html objects for more details

See also the commands CLS, HTML, JSCALL, JSCRIPT, CSS and WLOG

LCD.INIT address, cols, rows

Initialize a LCD display connected using I2C to the module.

‘address’ is the I2C slave address of the LCD display

‘cols’ is the number of columns of the LCD display

‘rows’ is the number of rows of the LCD display

 

Before using it, the I2C bus must be initialised with the command I2C.SETUP

 

Example:

I2C.SETUP 21, 22 ‘init the I2C on pins 21 and 22

LCD.INIT 63, 20, 4  ‘init the LCD at I2C address 63 with 20 columns and 4 rows

LCD.PRINT 1,1 "HELLO WORLD"

LCD.CLS

Clear the content of the LCD display connected using I2C to the module

LCD.PRINT x, y, text$

Print a text on the LCD.

‘x’ and ‘y’ define the position where ‘text$’ will be printed

LOCAL var1 [,var2], ...

Defines local variables inside user named subroutines.

Using this command inside the subroutines, permits to create variables that exist only during the routine; they will vanish at the end of the routine. This will permit also to avoid to unintentionally modify variables that have the same name which were already used elsewhere in the code.

See the paragraph "Scope of the variables" for more details.

Example:

  LOCAL I, A$

MAXDISPLAY.SETUP CS_pin

Setup a 8 digit 7-segments display based on the chip MAX7219.

The display must be connected using the SPI bus plus a CS_pin.

‘CS_pin’ defines the pin used for the CS signal

Example:

MAXDISPLAY.SETUP 15

MAXDISPLAY.PRINT msg$ [,‘brightness]

Print a message on the 8 digit 7-segments MAX7219 display.

All ASCII characters can be used but will be shown within the limitation of the 7 segments of the display.

‘msg$’ defines the message to be printed

‘brightness” defines the luminosity of the display from 0 (blank) to 15 (max)

By default the luminosity is at 15

MAXSCROLL.SETUP nb_devices, CS_pin

Set Up a DotMatrix chain display based on the chip MAX7219.

The chain can be composed by one or more modules in daisy chain.

The display must be connected using the SPI bus plus a CS_pin.

‘Nb_devices’ defines how many modules are connected

‘CS_pin’ defines the pin used for the CS signal

Example for a 4 digit module available on ebay :

MAXSCROLL.SETUP 4, 15  ‘ 4 digits, CS on pin 15

MAXSCROLL.PRINT msg$

Print a message on the DotMatrix Display.

The message will be shown using the command MAXSCROLL.SCROLL

‘msg$’ defines the message to be shown

MAXSCROLL.NEXT msg$

Define the message that will be shown on the DotMatrix Display as soon as the message set with the command MAXSCROLL.PRINT is terminated.

Permit to maintain a continuity on the message shown.

‘msg$’ defines the message that will be printed

MAXSCROLL.TEXT msg$

Set a new message without resetting the message at the initial position.

Useful to modify the message while it’s already scrolling.

‘msg$’ defines the new message to be shown

MAXSCROLL.SHOW pos [, brightness]

Show in a given position the message defined with the command MAXSCROLL.PRINT or the command MAXSCROLL.NEXT

‘Pos’ define the position of the message (in pixels)

‘brightness” defines the luminosity of the display from 0 (blank) to 15 (max)

The position 1 if the rightmost line of the display and increasing this value will move the text more on the left. Decrementing (negative numbers) this value will move the text more on the right.

MAXSCROLL.SCROLL [brightness]

Execute a single pixel scroll from the right to left of the message set on the DotMatrix display. In order to maintain a continuity of the scrolling, this command must be called on a timed interval (using a timer)

‘brightness” defines the luminosity of the display from 0 (blank) to 15 (max)

MAXSCROLL.OSCILLATE [brightness]

Execute a single pixel scroll oscillating the message set on the DotMatrix display. In order to maintain a continuity of the scrolling, this command must be called on a timed interval (using a timer)

‘brightness” defines the luminosity of the display from 0 (blank) to 15 (max)

NEO.PIXEL led_pos, R, G, B [, disable]

Set, in a stripline, the led at position 'led_pos' with the color R,G,B.

The optional argument 'disable' (if = 1) is useful for updating several pixels together; it will write the new value into memory, but it will not be displayed until the next non-‘disable’ write causes all ‘disabled’ pixels to display their updated values at the same time.

NEO.PIXEL led_pos, COLOR [, disable]

Set, in a stripline, the led at position 'led_pos' with the color ‘COLOR’.

The content of ‘COLOR’ is a merged color value; it can be generated using the function NEO.RGB().

The optional argument 'disable' (if = 1) will permit to write in the memory without refreshing the strip; this is useful to show several leds at the same time

NEO.SETUP pin [,nb_led]

The NEOPIXEL are led strips based on the WS2812 Leds

define the pin to be used for the NEO PIXEL commands

‘Pin’ define the pin number to be used

Optionally it is possible to define the number of leds presents in the string.

By default the strip contains 512 leds.

NOTE: it is recommended to define the number of leds to have a faster refresh, in particular for small strips.

NEO.STRIP led_start_pos, led_end_pos, R, G, B [, disable]

Set, in a stripline, the leds from the position 'led_start_pos' to 'led_end_pos' with the color R,G,B.

The optional argument 'disable' (if = 1) will permit to write in the memory without refreshing the strip; this is useful to show several leds at the same time

NEO.STRIP led_start_pos, led_end_pos, COLOR [, disable]

Set, in a stripline, the leds from the position 'led_start_pos' to 'led_end_pos' with the color ‘COLOR’

The content of ‘COLOR’ is a merged color value; it can be generated using the function NEO.RGB().

The optional argument 'disable' (if = 1) will permit to write in the memory without refreshing the strip; this is useful to show several leds at the same time

NEOSCROLL.SETUP nb_devices, pin [,serpentine]

Set Up a NeoMatrix chain display based on WS2812 dot matrix led modules.

The chain can be composed by one or more modules in daisy chain.

The display must be connected using a single pin

‘Nb_devices’ defines how many modules are connected

‘pin’ defines the pin used for the signal

‘Serpentine’ defines if the display is arranged as a serpentine; can be 0 (normal) or 1 (serpentine). By default is 0. 

Example for a 4 digit module available on ebay :

NEOSCROLL.SETUP 4, 15  ‘ 4 digits, using the pin 15

NEOSCROLL.PRINT msg$

Print a message on the NeoMatrix Display.

The message will be shown using the command NEOSCROLL.SCROLL

‘msg$’ defines the message to be shown

NEOSCROLL.NEXT msg$

Define the message that will be shown on the NeoMatrix Display as soon as the message set with the command NEOSCROLL.PRINT is terminated.

Permit to maintains a continuity on the message shown.

‘msg$’ defines the message that will be printed

NEOSCROLL.COLORS col$

Defines the colors associated with the character to be shown on the NeoMatrix display. The logic of the colors is described in the specific NeoMatrix chapter

NEOSCROLL. NEXTCOLORS col$

Defines the colors of the message defined with the command NEOSCROLL.NEXT

NEOSCROLL.SHOW pos [, brightness]

Show in a given position the message defined with the command NEOSCROLL.PRINT or the command NEOSCROLL.NEXT

‘Pos’ define the position of the message (in pixels)

‘brightness” defines the luminosity of the display from 0 (blank) to 255 (max)

The position 1 if the rightmost line of the display and increasing this value will move the text more on the left. Decrementing (negative numbers) this value will move the text more on the right.

NEOSCROLL.TEXT msg$

Set a new message without resetting the message at the initial position.

Useful to modify the message while it’s already scrolling.

‘msg$’ defines the new message to be shown

NEOSCROLL.SCROLL [‘brightness]

Execute a single pixel scroll from the right to left of the message set on the DotMatrix display. In order to maintain a continuity of the scrolling, this command must be called on a timed interval (using a timer)

‘brightness” defines the luminosity of the display from 0 (blank) to 255 (max)

NEOSCROLL.OSCILLATE [‘brightness]

Execute a single pixel scroll oscillating the message set on the DotMatrix display. In order to maintain a continuity of the scrolling, this command must be called on a timed interval (using a timer)

‘brightness” defines the luminosity of the display from 0 (blank) to 255 (max)

OLED.CLS

Clear the content of the OLED display connected using I2C to the module

OLED.INIT orientation [,model]

Initialise an OLED display connected using I2C to the module.

‘orientation’ is a number that can be 0 or 1 specifying the orientation:

0

Landscape

1

Landscape reversed

 

By default the OLED SSD1306 is enabled but specifying ‘model’ as 1 the display SSH1106 will be enabled.

 

The OLED predefined I2C address is 60 (3c in hex).

Before using it, the I2C bus must be initialised with the command I2C.SETUP

 

Example :

I2C.SETUP 21, 22  ' set I2C port on pins 21 and 22

OLED.INIT 1 ‘ init OLED at landscape reversed

 

In case of the display SH1106, the command is

OLED.INIT 1, 1 'init OLED at landscape reversed, SSH1106

OLED.REFRESH fmt

Defines how the image is sent on the OLED after each drawing command.

If ‘fmt’ = 1, the image is automatically refreshed after each drawing command.

If ‘fmt’ = 0, the image must be manually refreshed with OLED.REFRESH 0

This method provides a double buffer permitting to draw several objects on the screen avoiding flickering.

OLED.COLOR color

Set the color used by the OLED drawing commands.

The color is defined as above:

 

0

Black

1

White

2

Reverse

OLED.PIXEL x, y

Draw a pixel at the position x, y on the OLED display

OLED.LINE x1, y1, x2, y2

Draw a line between the point (x1,y1) and  the point (x2,y2) on the OLED display

OLED.RECT x,y, width, height [,fill]

Draw a rectangle at the point (x,y) with the specified width, height on the OLED.

Specifying 1 for the argument fill, the rectangle will be filled.

OLED.CIRCLE x, y, radius [, fill]

Draw a circle at the point (x,y) with the specified radius on the OLED display.

Specifying 1 for the argument fill, the circle will be filled.

OLED.FONT font_num

Set the font used by the OLED.PRINT command.

The font_num is defined as above (by default the font 1 is selected)

 

1

Arial MT 10

Width : 10px

Height:13px

2

Arial MT 16

Width : 16px

Height:19px

3

Arial MT 24

Width : 24px

Height:28px

OLED.PRINT x, y, text$ [background]

Print a text on the OLED display.

‘x’ and ‘y’ define the position where ‘text$’ will be printed.

An optional ‘background’ parameter permit to specify the background color.

OLED.IMAGE x, y, image$

Shows an image in XBM format from the internal disk on the OLED display.

‘X’ and ‘y’ define the position where the image will be shown

‘image$’ is the name of the file containing the image

OLED.BMP x, y, image$

Shows an image in BMP format from the internal disk on the OLED display.

‘X’ and ‘y’ define the position where the image will be shown

‘image$’ is the name of the file containing the image

ONERROR ABORT or ONERROR IGNORE or ONERROR SKIP [nn] or ONERROR CLEAR or ONERROR GOTO label

This controls the action taken if an error occurs while running a program and applies to all errors including syntax errors.

ONERROR ABORT will display the error message and abort the program. This is the normal behaviour and is the default when a program starts running.

ONERROR IGNORE will cause any error to be ignored.

ONERROR SKIP will ignore an error in a number of commands (specified by the number 'nn') executed following this command. 'nn' is optional, the default if not specified is one.

After the number of commands has completed (with an error or not) the behaviour will revert to ONERROR ABORT.

If an error occurs and is ignored/skipped the read only variable BAS.ERRNUM will be set to non zero and BAS.ERRMSG$ will be set to the error message that would normally be generated. These are reset to zero and an empty string by ONERROR CLEAR. They are also cleared when the program is run and when ONERROR IGNORE and ONERROR SKIP are used. ONERROR IGNORE can make it very difficult to debug a program so it is strongly recommended that only ONERROR SKIP be used.

In addition the command ONERROR GOTO label permits to define a routine that can manage the error; issuing RETURN inside this routine, will return to the line following the error.

ONESPNOWERROR [label | OFF]

Define the label where the program will jump when an error occurs during the transmission  of an ESP-NOW  message.

This happen, in particular, when the receiver device has not received the message

ONESPNOWMSG [label | OFF]

Define the label where the program will jump when an ESP-NOW message is received

ONGESTURE [label | OFF]

Define a label where the program will jump when the APDS9960 sensor detects a gesture.  To disable ONGESTURE OFF

ONHTMLCHANGE [label | OFF]

Define a label where the program will jump when an html object present in the output html page changes its value. The code must be terminated with ‘RETURN’. 

To disable ONHTMLCHANGE OFF

ONHTMLRELOAD [label | OFF]

Define a label where the program will jump when a reload of the output html page is requested or a new client connects to this page. The code must be terminated with ‘RETURN’.  To disable ONHTMLRELOAD OFF

ONINFRARED label

Define a label where the program will jump when an IR code is received by the Infrared receiver. The script branch must be terminated with ‘RETURN’. 

To disable ONINFRARED OFF

ONMQTT label

Define a label where the program will jump when an MQTT message is received

The script branch must be terminated with ‘RETURN’. 

To disable ONMQTT OFF

ONRFID label

Define a label where the program will jump when an RFID device is detected

The script branch must be terminated with ‘RETURN’. 

To disable ONRFID OFF

ONSERIAL [label | OFF]

Define a label where the program will jump when a message is received on the serial port (console). The code must be terminated with ‘RETURN’.

To disable ONSERIAL OFF

ONSERIAL2 [label | OFF]

Define a label where the program will jump when a message is received on the serial port #2. The code must be terminated with ‘RETURN’

To disable ONSERIAL2 OFF

ONTOUCH [label | OFF]

Define a label where the program will jump when the TFT screen is touched. The code must be terminated with ‘RETURN’

To disable ONTOUCH OFF.

Useful in combination with the functions TOUCH.X and TOUCH.Y

ONUDP [label | OFF]

Define a label where the program will jump when a UDP message is received. The code must be terminated with ‘RETURN’.

To disable ONUDP OFF

ONURLMESSAGE [label | OFF]

Define a label where the program will jump when a URL AJAX GET request is received. This is typically when the url http://local_ip/msg?param=value is accessed. For more detail refers to the dedicated paragraph..

To disable ONURLMESSAGE OFF.

Useful in combination with URLMSGRETURN and URLMSGGET$

More information here

ONWGETASYNC [label | OFF]

Define a label where the program will jump when a WGETASYNC message is received. The code must be terminated with ‘RETURN’.

To disable ONWGETASYNC OFF

OPTION.CPUFREQ 80|160|240

Define CPU speed in Mhz of the module.

The value can be 80, 160 or 240.  The default value is 240Mhz.

Setting the speed at 80Mhz, will divide by 3 the speed of the module but lower the power requirement of the module by around 5mA

OPTION.LOWRAM value

Define the RAM available lower limit. If during the execution of the program this limit is reached, the program automatically stops with an OUT OF MEMORY error message. By default the value is defined at 10000.

As it introduces a little overhead, it can be disabled setting this option at 0 (however this is not recommended).

PAUSE delay

Pause the module for ‘delay’ milliseconds.

During the pause, all the activities are not suspended (it is non-blocking).

This means that all interrupts will continue to be managed.

PCA9685.SETUP addr

Setup a PWM / SERVO drive module based on the chip PCA 9685.

This module must be connected using the bus I2C.

‘Add’ defines the I2C address of the chip (normally 64)

Example:

PCA9685.SETUP 64 ‘ set the module at the I2C address 64 (40 in hexadecimal)

PCA9685.SETFREQ freq

Set the PWM frequency of the PWM / Servo module PCA 9685

‘Freq’ defines the frequency of the PWM signal

The value can be from  24 Hz to 1526 Hz.

To drive servos, the frequency must be 50 Hz

Example:

PCA9685.SETFREQ 50 ‘ set the PWM frequency at 50 Hz

PCA9685.PWM pin, value

Set the PWM signal on one of the 16 outputs of the PCA9685 module.

‘Pin’ can be from 0 to 15

‘Value’ can be from 0 to 4095.

Example:

PCA9685.PWM 0, 2048 ‘ put the output 0 at 50% duty cycle

PID1.INIT Kp, Ki, Kd

Initialise the PID controller with the Kp, Ki, and Kd parameters.

As there are 4 PID controllers, the prefix can be PID1, PID2, PID3 or PID4.

PID1.LIMITS min, max

Set the output limits of the given PID controller.

If not defined the limits are defined as 0 to 255.

As there are 4 PID controllers, the prefix can be PID1, PID2, PID3 or PID4.

PID1.PERIOD msec

Set the sampling period for the given PID controller.

If not defined the default value is 100 msec.

As there are 4 PID controllers, the prefix can be PID1, PID2, PID3 or PID4.

PID1.PARAMS Kp, Ki, Kd

Modify the PID parameters for the given PID controller.

As there are 4 PID controllers, the prefix can be PID1, PID2, PID3 or PID4.

PID1.SETMODE mode

Set the working mode of the given PID controller.

If ‘mode’ is set to 0, the controller will be stopped and the output value will be frozen.

By default the ‘mode’ is set to 1.

As there are 4 PID controllers, the prefix can be PID1, PID2, PID3 or PID4.

PIN(pin_number) = val

Set the value of any external I/O pin.

The pin_number refers to GPIO and can be from 0 ... 5 or 12 ...33

The val can be 0 or 1 to set the pin to LOW or HIGH

Before being used, the pin must be set as OUTPUT with the command PIN.MODE

PIN.DAC pin_number, value

The function PIN.DAC pin, value can be used to set the output voltage on the pin 25 or 26 (only these pins are available for analog output)

The output voltage is approximately 0V @ value=0 and 3.3V @ value=255

PIN.MODE pin_number, mode [,PULLUP | PULLDOWN ]

Set any pin to digital mode as input or output.

The ‘pin_number’ can be from 0 to 39.

The ‘mode can’ be INPUT or OUTPUT or SPECIAL

The optional parameter PULLUP permits to add a weak pullup resistor on the pin.

The optional parameter PULLDOWN permits to add a weak pulldown resistor on the pin.

The mode SPECIAL can be used to restore the normal functionality to any pin.

For example, if the pin GPIO1 (normally assigned to the TX functionality) has been defined as input (with the command PIN.MODE 1, INPUT), its normal functionality can be restored with the command

PIN.MODE 1, SPECIAL

PLAY.MP3 mp3$

Play mp3 files stored in the internal disk or from the SD card.

The sound is played in the background, even if the program is stopped, until the end of the record or executing the command PLAY.STOP.

Example:

PLAY.MP3 “/mp3/music.mp3”

PLAY.STREAM stream$ [,buffer]

Play an mp3 streaming web radio.

The sound is played in the background, even if the program is stopped, until the execution of the command PLAY.STOP.

The optional argument ’buffer’ defines the size of the memory block allocated as an input buffer. Its value is 20000 by default and can be increased up to the free RAM available..

Example:

PLAY.STREAM "http://91.121.159.124:8000/eko-des-garrigues-128k.mp3"

PLAY.SETUP dest [,buffer] [,mono]

Set the destination output for the sound player commands.

If ‘dest’ is 0 is the output will be sent to the GPIO25 and 26 ( and the internal speaker for the M5stack)

If ‘dest’ is 1 is the output will be sent to the external DAC

If ‘dest’ is 2 is the output will be sent to the GPIO25 and 26 ( and the internal speaker for the M5stack) but using the PDM mode

The optional argument ’buffer’ defines the size of the memory block allocated as an output buffer.

Its value is 8 by default and can be increased up to 64.

Increasing the size of the buffer will permit to reduce some glitches that may occur in case of strong WiFi activity.

The optional argument ‘mono’, if set to 1, set the output in mono mode (useful for single channel speaker)

If the command PLAY.SETUP is run without arguments, the sound is sent by default to the internal speaker.

 

Example:

PLAY.SETUP 1 ‘ define the output to the external DAC

PLAY.SPEAK message$ [, phonetic]

Speaks a vocal message using the internal SAM speech synthesizer.

The message must be composed of english words and limited to 255 characters.

It can optionally talk using phonemes; in this case ‘phonetic’ must be 1.

Example :

PLAY.SPEAK “The quick brown fox jumps over the lazy dog”

PLAY.STOP

Stop the playing of sound

PLAY.VOICE "message", "language" [, "filename"] [, action]

Speaks a vocal message using the voice synthesis available in google translate.

PLAY.VOLUME volume

Defines the output volume.

It can be from 0 to 100 but greater than 100 values are accepted if the sound file was recorded with low volume

Example:

PLAY.VOLUME 50  ‘ set the sound at 50%

PLAY.WAV

Play wav files stored in the internal disk or from the SD card.

The sound is played in the background, even if the program is stopped, until the end of the record or executing the command PLAY.STOP.

Example:

PLAYWAV “/wav/music.wav”

PRINT expression[[,; ]expression] ...

Outputs text to the serial port (console)

Multiple expressions can be used and must be separated by either a:

-       Comma (,) which will output the tab character

-       Semicolon(;) which will not output anything (it is just used to separate expressions).

A semicolon (;) at the end of the expression list will suppress the automatic output of a carriage return/ newline at the end of a print statement.

Integers (whole numbers) are printed without a decimal point while fractions are printed with the decimal point and the significant decimal digits. Large floating point numbers are printed in scientific number format.

PRINT2 expression [[,; ]expression] ...

Outputs text to the serial port #2.

Multiple expressions can be used and must be separated by either a:

-       Comma (,) which will output the tab character

-       Semicolon(;) which will not output anything (it is just used to separate expressions).

A semicolon (;) at the end of the expression list will suppress the automatic output of a carriage return/ newline at the end of a print statement.

Integers (whole numbers) are printed without a decimal point while fractions are printed with the decimal point and the significant decimal digits. Large floating point numbers are printed in scientific number format.

PWM.SETUP pin, chan, default,  [,freq] [,resol]

Attach a PWM channel to a given output pin.

‘pin’ can be any output pin

‘chan’ can be from 0 to 15.

‘default is the initial pwm value set to the output

‘freq’ is the pwm frequency; by default is 10KHz

‘resol’ is the resolution; by default is 8bits

 

Frequency limits depend on resolution.

For duty resolution of 8 bits, the maximal frequency is 312.5 kHz.

The available duty levels are (2^bit_num)-1, where bit_num can be 1-15.

The maximal frequency is 80000000 / 2^bit_num

NOTE for the M5stack:

The channel 0 is dedicated to the internal speaker (pin 25)

The channel 7 is dedicated to the TFT backlight (pin 32)

See the PWM chapter for more details

PWM.SETUP pin, OFF

Detach the pin from the PWM output.

PWM.OUT chan, value

Set a given value to the PWM channel.

The channel is associated to a given pin with the command PWM.SETUP

‘chan’ can be from 0 to 15

‘value’ can be from 0 to the max defined by the resolution (by default 0 to 255)

READ var1 [,var2] ...

Reads values from DATA statements and assigns these values to the named variables. Variable types in a READ statement must match the data types in DATA statements as they are read.

See also DATA and RESTORE.

REBOOT

Reboots the module (software reset)

REFRESH

Refresh (sync) the variables in the basic code with the corresponding variables in the input html page (one shot)

RESTORE [label]

Resets the line and position counters for the READ statement at the beginning or a specific position defined by ‘label’

RTC.SETTIME Year, Month, Day, Hours, Minutes, Seconds

Set the RTC module (DS1307 or DS3231) with the supplied date / time

‘Year’ can be from 0 (for 2000) to 99 (for 2099)

‘Month’ can be from 1 (january) to 12 (december)

‘Day’ can be from 1 to 31

‘Hours’ can be from 0 to 23

‘Minutes’ can be from 0 to 59

‘Seconds’ can be from 0 to 59

See also RTC.DATE$ and RTC.TIME$

SERIAL.BYTE ch1 [,ch2] . . .

Send one or more bytes to the serial port (console).

The bytes can be one or more separated by a comma.

The values can be any value from 0 to 255.

Example :

SERIAL.BYTE &h10, &h00, &h12, &h09

SERIAL2.BYTE ch1 [,ch2] . . .

Send one or more byte to the serial port #2.

The bytes can be one or more separated by a comma.

The values can be any value from 0 to 255.

Example :

SERIAL2.BYTE &h10, &h00, &h12, &h09

SERIAL.MODE baudrate [, bits, parity, stop]

Set the speed for the Serial Port (console)

The format is fixed to 8 bits No parity 1 bit stop.

‘baudrate’ defines the speed (can be any allowed value)

‘bits’ can be from 5 to 8

‘parity’ {0 = none : 1 = odd, 2 = even)

‘stop’ can be 1 or 2

SERIAL2.MODE baudrate, pin_tx, pin rx  [, bits, parity, stop] [, TXbuffer, RXbuffer]

Set the speed and the pins for the serial port #2

It is possible to specify any pin for the TX and RX signals.

The format is fixed to 8 bits No parity 1 bit stop.

‘baudrate’ defines the speed (can be any allowed value)

‘pin_tx’ defines the pin for the TX signal

‘pin_rx’ defines the pin for the RX signal.

‘bits’ can be from 5 to 8

‘parity’ {0 = none : 1 = odd, 2 = even)

‘stop’ can be 1 or 2

‘TXbuffer’ defines the size of the TX buffer (default is 256)

‘RXbuffer’ defines the size of the RX buffer (default is 256)

SETTIME Year, Month, Day, Hours, Minutes, Seconds

Set the internal timekeeper with the supplied date / time

‘Year’ can be from 70 (for 1970) to 38 (for 2038); values >100 are accepted so 2017 can be specified as 17 or 117.

‘Month’ can be from 1 (january) to 12 (december)

‘Day’ can be from 1 to 31

‘Hours’ can be from 0 to 23

‘Minutes’ can be from 0 to 59

‘Seconds’ can be from 0 to 59

SLEEP value [,pin, level]

Put the ESP in deep sleep (low energy) for 'value' seconds.

At the end of the period, the unit will reboot and reload the default basic program.

Optionally, it is possible to wake up the module using an external signal sent on an input pin

In this case the pin and the level must be specified in addition to the time value.

Only RTC IO can be used as a source for external wake up.

They are pins: 0,2,4,12-15,25-27,32-39.

Level is 1 for wakeup on High and 0 for wakeup on Low

SOCKET client, msg$

Send a WebSocket message only to a specific client.

This command should not be used as It will probably be removed in the future

‘client’ is the number of the client

‘msg$’ is the message to be sent

SPI.CSPIN pin [, polarity]

Defines the ‘pin’ used as CS for the SPI functions.

Because the ESP32 uses multitasking, the CS pin is managed directly by Annex

The optional parameter  ‘polarity’  defines if the CS signal must be active low (0 = default) or active high (1).

This command will set the pin automatically as output.

SPI.SETUP speed [,data_mode [, bit_order]]

Initialise the SPI port with the speed (bits/sec)

The speed can be max 80000000 (80MHz for CPU running at 160MHz)

The optional parameters are:

data_mode : can be 0 (default) 1, 2 or 3.

bit_order : can be 0 (lsb_first) or 1 (msb_first - default)

SPI.STOP

Stops the SPI bus activity and restore the control on the SPI I/O pins (18 - 19 - 23).

After this command these pins can be used again as standard GPIO

ST7920.INIT CS_pin

Initialize an ST7920 display connected using SPI to the module.

‘CS_pin’ defines the pin used for the CS signal

This command initialise automatically the SPI bus at 1 Mhz (max frequency allowed by the display)

 

Example :

 

ST7920.INIT 15 ‘ init the ST7920 with the CS at pin 16

ST7920.CLS

Clear the content of the ST7920 display connected using SPI to the module

ST7920.REFRESH fmt

Defines how the image is sent on the ST7920 after each drawing command.

If ‘fmt’ = 1, the image is automatically refreshed after each drawing command.

If ‘fmt’ = 0, the image must be manually refreshed with ST7920.REFRESH 0

This method provides a double buffer permitting to draw several objects on the screen avoiding flickering.

ST7920.COLOR color

Set the color used by the ST7920 drawing commands.

The color is defined as above:

 

0

Black

1

White

2

Reverse

ST7920.PIXEL x, y

Draw a pixel at the position x, y on the ST7920 display

ST7920.LINE x1, y1, x2, y2

Draw a line between the point (x1,y1) and  the point (x2,y2) on the ST7920 display

ST7920.RECT x,y, width, height [,fill]

Draw a rectangle at the point (x,y) with the specified width, height on the ST7920.

Specifying 1 for the argument fill, the rectangle will be filled.

ST7920.CIRCLE x, y, radius [, fill]

Draw a circle at the point (x,y) with the specified radius on the ST7920 display.

Specifying 1 for the argument fill, the circle will be filled.

ST7920.FONT font_num

Set the font used by the ST7920.PRINT command.

The font_num is defined as above (by default the font 1 is selected)

 

1

Arial MT 10

Width : 10px

Height:13px

2

Arial MT 16

Width : 16px

Height:19px

3

Arial MT 24

Width : 24px

Height:28px

ST7920.PRINT x, y, text$ [background]

Print a text on the ST7920 display.

‘x’ and ‘y’ define the position where ‘text$’ will be printed.

An optional ‘background’ parameter permits to specify the background color.

ST7920.IMAGE x, y, image$

Shows an image in XBM format from the internal disk on the ST7920 display.

‘X’ and ‘y’ define the position where the image will be shown

‘image$’ is the name of the file containing the image

ST7920.BMP x, y, image$

Shows an image in BMP format from the internal disk on the ST7920 display.

‘X’ and ‘y’ define the position where the image will be shown

‘image$’ is the name of the file containing the image

TM1637.PRINT msg$ [, brightness ]

Print a message on the display TM1637.

All ASCII characters can be used but will be shown within the limitation of the 7 segments of the display. The decimal point and the colon (:) are automatically managed if the display support them.

‘msg$’ defines the message to be shown

‘brightness” defines the luminosity of the display from 0 (blank) to 7 (max)

By default the luminosity is at 7

TM1637.SETUP data_pin, clock_pin [, bit_delay] [, display_type]

Defines the pins to be used for the display TM1637.

‘data_pin’ defines the pin allocated for the signal DIO of the display

‘clock_pin” defines the pin allocated for the signal CLK of the display

‘bit_delay’ permit to add a delay when the display module is provided with capacitors on the input pin. Its value is 5 by default and should be defined at 100 in this case.

‘display_type’ must be 1 if a “6 digits” display is connected

TM1638.PRINT msg$ [, brightness ]]

Print a message on the display TM1638. The message can be up to 8 chars.

All ASCII characters can be used but will be shown within the limitation of the 7 segments of the display.

‘msg$’ defines the message to be printed

‘brightness” defines the luminosity of the display from 0 (blank) to 15 (max)

By default the luminosity is at 15

TM1638.SETUP data_pin, clock_pin, strobe_pin

Defines the pins to be used for the display TM1638.

‘data_pin’ defines the pin allocated for the signal DIO of the display

‘clock_pin” defines the pin allocated for the signal CLK of the display

‘strobe_pin” defines the pin allocated for the signal STB of the display

TM1638.LEDS val

Controls the 8 leds installed on the module TM1638.

‘Val’ is an 8-bits value where each bit is associated with a led.

Example :

TM1638.LEDS 1 ‘ illuminated the led 1

TFT.BMP filename$, [x, y [, back_color] ]

Display a bitmap file on the TFT display.

The file must be present on the local disk before use.

The file format must be ".bmp" with 24 or 32 bits.

The image can be of any size but is limited to 320 x 240 (resolution of the display).

The position (x, y) is optional; if specified, the image will be drawn from that point.

The back color is useful for 32bit images when a transparent color is defined; in this case the transparency will be replaced by the ‘back_color’.

Defining a back_color at -1, the transparency will be maintained, useful to put icons on the top of an image.

‘filename$’ is the name of the bmp file

‘x’ is the horizontal position of the image

‘y’ is the vertical position of the image

‘back_color’ (optional) is the background color (-1 by default)

Example

TFT.BMP "/icon1.bmp", 50, 50

TFT.BRIGHTNESS val

Set the TFT backlight intensity.

‘val’ can be from 0 (dark) to 255 (max)

Example:

TFT.BRIGHTNESS 128 ‘ set the luminosity at 50%

TFT.CIRCLE x, y, radius,color [, fill]

Trace a circle at the point (x,y) with the specified radius.

Specifying 1 for the argument fill, the circle will be filled.

Example

A filled circle at 20,20 radius 18, with a reddish color

TFT.CIRCLE 20,20,18,TFT.RGB(255,10,10),1

TFT.FILL color

Fill the whole screen with a given color.

‘color’ is the color; as it must be a 16 bit color (RGB565), its value can be from 0 to 65535.

The color can be obtained specifying the R,G,B components with the function TFT.RGB.

Example:

TFT.FILL 0  ‘ fill the screen with black (equivalent of CLS)

TFT.IMAGE filename$, [x, y [, back_color] ]

Display a BMP or JPG file on the TFT display.

The file must be present on the local disk before use.

The file format must be ".bmp" with 24 or 32 bits or “.jpg”

The image can be of any size but is limited to 320 x 240 (resolution of the display).

The position (x, y) is optional; if specified the image will be drawn from that point.

The back color is useful for 32bit images when a transparent color is defined; in this case the transparency will be replaced by the ‘back_color’.

Defining a back_color at -1, the transparency will be maintained, useful to put icons on the top of an image.

‘filename$’ is the name of the image file

‘x’ is the horizontal position of the image

‘y’ is the vertical position of the image

‘back_color’ (optional) is the background color (-1 by default)

Example

TFT.IMAGE "/icon1.bmp", 50, 50

TFT.IMAGE “/roses.jpg”, 64, 64

TFT.INIT orientation

Initialize a TFT ILI9431 display connected to the module.

‘orientation’ is a number between 0 and 3 specifying the orientation:

 

0

Portrait

1

Landscape

2

Portrait reversed

3

Landscape reversed

 

Example :

TFT.INIT 1           ‘ Landscape

Check the chapter about the TFT display  for more details

TFT.JPG filename$, [x, y [, scale] ]

Display a JPG file on the TFT display.

The file must be present on the local disk before use.

The file format must be “.jpg”

The image can be of any size but is limited to 320 x 240 (resolution of the display).

The position (x, y) is optional; if specified the image will be drawn from that point.

 

‘filename$’ is the name of the jpg file

‘x’ is the horizontal position of the image

‘y’ is the vertical position of the image

‘scale’(optional) enable to scale the image (see next table)

 

scale

Scaling effect

0

1:1

1

1:2

2

1:4

3

1:8

 

Example

TFT.JPG “/roses.jpg”, 64, 64

TFT.LINE x1, y1, x2, y2, col

Trace a line on the TFT between the point (x1,y1) and  the point (x2,y2) with the color ‘col’

Example:

TFT.LINE 50, 50, 150, 150, TFT.RGB(255, 0, 0)

TFT.PIXEL x, y, col

Draw a pixel at the position x, y with the color ‘col’

TFT.PIXEL 50, 50, red

TFT.PRINT expression [[,; ]expression] ...

Draw a text on the TFT display.

Multiple expressions can be used and must be separated by either a:

-       Comma (,) which will output the tab character

-       Semicolon(;) which will not output anything (it is just used to separate expressions).

A semicolon (;) at the end of the expression list will suppress the automatic output of a carriage return/newline at the end of a print statement.

Integers (whole numbers) are printed without a decimal point while fractions are printed with the decimal point and the significant decimal digits. Large floating point numbers are printed in scientific number format.

TFT.RECT x, y, width, height, color [ [,fill] ,[round_radius] ]

Trace a rectangle at the point (x,y) with the specified width, height and color.

Specifying 1 for the argument fill, the rectangle will be filled.

Specifying a value for ‘round_radius’, the rectangle will be rounded at the corners with the value specified.

Example:

TFT.RECT 100, 50, 50, 50, TFT.RGB(255, 128, 0)

TFT.SETFREQ freq

Sets the SPI frequency for the TFT. The default value is typically 40MHz (40,000,000), but it can vary depending on the specific TFT model being used.

Increasing the speed to 80MHz can enhance display performance, but this may not be compatible with all TFT displays. For instance, it may not work with the M5Stack.

TFT.TEXT.COLOR color [,backcolor]

Set the color and the background of the text that will be printed with the command TFT.PRINT

‘color’ define the color of the text

‘backcolor’ (optional) defines the background of the text

If ‘backcolor’ is not defined, the background will be black

TFT.TEXT.POS x, y

Position the text cursor at the point (x, y).

The text will be printed at that position with the command TFT.PRINT

TFT.TEXT.SIZE size

Set the size of the text that will be printed with the command TFT.PRINT

The ‘size’ can be from 1 to 8.

TIMER0 interval, label

Starts a timer causing the program to periodically jump to the defined label.

The RETURN at the end of the timer branch causes program control to return to where it was before being interrupted by TIMER0.

‘Interval’ defines the periodicity (milliseconds)

‘Label’ defines the place where the timer will jump regularly.

Setting the interval to 0 will disable it.

Note: The Timer0 has a higher priority than Timer1.

Example

TIMER0 1000, cycle  -> jumps to ‘cycle’ at each second

TIMER1 interval, label

Starts a timer causing the program to periodically jump to the defined label.

The RETURN at the end of the timer branch causes program control to return to where it was before being interrupted by TIMER1.

‘Interval’ defines the periodicity (milliseconds)

‘Label’ defines the place where the timer will jump regularly.

Setting the interval to 0 will disable it.

Example

TIMER1 1000, cycle  -> jumps to ‘cycle’ at each second

TOUCH.CALIB

Start the calibration of the touch screen. The user will be asked to click on 4 crosses.

The calibration values will be stored inside the module and stay in effect even after restarts.

UDP.BEGIN port

Start the UDP Server.

‘port’ is the udp port to be open (numerical).

All the messages received on this port can be read with the function UDP.READ$

UDP.REPLY msg$ [,port]

Send an UDP message back to the original transmitter.

Permits to answer directly without specifying the IP and port.

It is optionally possible to specify the remote port with the argument ’port’

UDP.STOP

Stop the UDP server.

UDP.WRITE ip, port, msg$

Send a UDP message to the client defined with the IP address ‘ip’ and the port ‘port". The message ‘msg$" must be a String.

UDP.Begin must be used to initialise the UDP port before using UDP.write

URLMSGRETURN msg$ [,content_type$]

Returns a message to the client that sent the URL AJAX GET request.

Is an async request, so it can work in parallel with other tasks.

When the program is not running, any request will receive the message "STOPPED".

The message can be optionally composed of an hex string in the format of 2 hex char per byte (ex: “3a552b23”) associated with a content type string (ex: "image/gif").

For more detail refers to the dedicated paragraph..

Useful in combination with ONURLMESSAGE and URLMSGGET$

More information here

WAIT

Stops the execution of the program while waiting for events.

Useful when using "event driven" code (timers, interrupts, triggered events, ..)

WGETASYNC server$, port [,header]

Start a GET server request in async mode

‘server$’ is the server url request

‘port’ is the port number; if port=443, the connection will be done using SSL (secure).

‘header’, if =1, will include the header in the answer (useful for debug)

The program will continue and the answer will be received in background.

As soon as the answer is completed, the program will jump to the label defined with the command ONWGETASYNC.

To get the result, use the function WGETRESULT$.

Example :

ONWGETASYNC answer_done

WGETASYNC("www.fakeresponse.com/api/?sleep=5", 80)

For i = 0 to 10000

‘ a kind of sleep just to demonstrate that the code continues to run

Print i

Next i

Wait

answer_done:

Print WGETRESULT$

Return

WGETASYNC url$, port [,header]

Start a GET server request in async mode

url$’ is the web server url request

If ‘url$’ starts with https://  the connection will be done using SSL (secure).

‘header’, if =1, will include the header in the answer (useful for debug)

The program will continue and the answer will be received in background.

As soon as the answer is completed, the program will jump to the label defined with the command ONWGETASYNC.

To get the result, use the function WGETRESULT$.

Example :

ONWGETASYNC answer_done

WGETASYNC("http://www.fakeresponse.com/api/?sleep=5")

For i = 0 to 10000

‘ a kind of sleep just to demonstrate that the code continues to run

Print i

Next i

Wait

answer_done:

Print WGETRESULT$

Return

WIFI.APMODE SSID$, password$ [, channel] [, IP$ , MASK$]

Put the module in AP-Mode using the given SSID and Password.

Optionally it is possible to define the Radio Channel, the IP and the MASK address

IMPORTANT : the password must be at least 9 characters

WIFI.AWAKE

Wake Up the WiFi from the sleep mode triggered with the command WIFI.SLEEP

WIFI.CONNECT SSID$, password$ [, BSSID$] [, IP$ , MASK$ [, GATEWAY$]]

 

Connect the module to a WiFi network using the given SSID and password.

Using the optional parameter BSSID$ will start the connection to a specific WiFi access point.

It is possible to gather the connection status using the function WIFI.STATUS

The IP address configuration set in the config page will be used for the new connection; this may cause the module to fall outside the WIFI network IP range.

This can be avoided leaving the IP address blank in the config page relying on DHCP to assign them.

Optionally it is possible to define the IP, the MASK and the GATEWAY using the optional string parameters.

WIFI.POWER pow

Set the output power of WiFi

‘pow’ defines the value in dBm

The range is between 0 and 20.5

WIFI.SCAN

Starts to scan WiFi networks available.

Must be used in association with WIFI.NETWORKS

WIFI.SLEEP

Put the WiFi in sleep mode.

The module will be placed in “modem-sleep” mode.

This mode turns the WiFi OFF but the module will continue to work.

In this mode the power requirement is lowered to around 25mA.

Important: this will work only if the module is in AP mode with static IP address or in STA mode

WLOG [text$ | num]

Send text content to the debug page.

 

Check the chapter about html objects for more details

See also the commands CLS, HTML, JSCRIPT, JSEXTERNAL, CSS and JSCALL

WORD.DELPARAM setting$, parameter$, [,separator$]

Delete a parameter from a string containing a series of parameters. If the parameter exists, it will be removed, otherwise the string will not be modified.

The parameters are stored as below :

param1=value1

param2=value2

…….

paramx=valuex

‘setting$’ defines the string containing the set of parameters

‘parameter$’ defines the parameters to be deleted.

‘separator$’ is an optional parameter specifying a different separator character.

Example, assuming that a$ is empty :

WORD.SETPARAM a$, "light", "on"

WORD.SETPARAM a$, "temp", "10"

WORD.SETPARAM a$, "pump", "off"

A$ will contain :

light=on

temp=10

pump=off

 

Using the following line:

WORD.DELPARAM a$, "temp"

A$ will contain :

light=on

pump=off

By default the separator is the character ‘=’.

Useful in combination with WORD.GETPARAM$, WORD.SETPARAM and FILE.SAVE

WORD.SETPARAM  setting$, parameter$, value$ [,separator$]

Put a parameter into a string containing a series of parameters. If the same parameter already exists, its value will be replaced with the new one.

The parameters are stored as below :

param1=value1

param2=value2

…….

paramx=valuex

‘setting$’ defines the string containing the set of parameters

‘parameter$’ defines the parameters to be set.

‘value$’ defines the value to be set.

‘separator$’ is an optional parameter specifying a different separator character.

Example, assuming that a$ is empty :

WORD.SETPARAM a$, "light", "on"

WORD.SETPARAM a$, "temp", "10"

WORD.SETPARAM a$, "pump", "off"

A$ will contain :

light=on

temp=10

pump=off

 

Using the following line:

WORD.SETPARAM a$, "temp", "20"

A$ will contain :

light=on

temp=20

pump=off

 

By default the separator is the character ‘=’.

Useful in combination with WORD.GETPARAM$, WORD.DELPARAM and FILE.SAVE

 

BASIC KEYWORDS

 

CASE

Keyword :  Used in combination with the SELECT command

DIM array(size) [, …]

Permits to define arrays.

The arrays can be floating point or string.

The number of dimensions (subscripts) is limited to 5.

Look at the chapter "Arrays" for more details

DO

The DO loop

ELSE

Keyword : Used in combination with the IF and SELECT commands

ELSEIF

Keyword : Used in combination with the IF command

END [IF | SELECT | SUB]

Used in several forms:

END alone terminate the execution of the program

END IF  to terminate the IF

END SELECT : to terminate a SELECT CASE

END SUB : to terminate a SUB

ENDIF

Used in combination with the IF command; can be also written as END IF

EXIT {DO | FOR | SUB}

Permit to exit from a DO LOOP (EXIT DO), a FOR LOOP (EXIT FOR) or a SUB (EXIT SUB)

FOR

FOR command;  Used in combination with the NEXT  command

GOSUB [label | lab$]

Jumps to a named label; the flow control will come back as soon as the command RETURN is reached.

The label must begin with a letter, not a number.

The contents of a string variable can be used instead of a static label name, allowing choice of destinations for creating dynamic function calls

GOTO [label | lab$]

Jumps to a named label; the label must begin with a letter, not a number.

The contents of a string variable can be used instead of a static label name, allowing choice of destinations for creating dynamic jumps

IF

IF command; used in combination with THEN, ELSE, ELSEIF,  ENDIF and END IF

LET var = expression

Optional for variable assignment

LOOP

Keyword : Used in combination with the DO command

NEXT

Keyword : Used in combination with the FOR  command

OFF

Keyword : used in combination with the INTERRUPT command

OUTPUT

Keyword : Used in combination with the PIN.MODE command

PULLUP

Keyword : Used in combination with the PIN.MODE command

PULLDOWN

Keyword : Used in combination with the PIN.MODE command

REM

Define a comment(remark); the symbol ‘ can be used instead

RETURN

Returns to the caller after a Gosub or an Event happened

SELECT

The SELECT CASE

SPECIAL

Keyword : Used in combination with the PIN.MODE command

STEP

Keyword : Used in combination with the FOR  command

SUB

Defines "user named" subroutines.

Refer to the paragraph "SUB" and "Scope of the variables" for more details.

THEN

Keyword : Used in combination with the IF command; this keyword is optional in the IF command

TO

Keyword : Used in combination with the FOR  command

UNTIL

Keyword :  Used in combination with the DO command

WEND

Keyword : Used in combination with the WHILE  command

WHILE

The WHILE LOOP; also used as condition for the DO LOOP

 

 


possibly change \n to ","

see to change \n with ","

to create the table

To include the support for external mouse / keyboards