ESP32forth Update
🙘
October 8, 2022
IMPROVEMENTS SINCE AUGUST
🙘
• CASE
• BTERM & RELINQUISH
• Shell Words
• Code Words & DUMP
• More ESP-CAM Bindings
• USER_VOCABULARIES
CASE
CASE
1 OF ." one" ENDOF
2 OF ." two" ENDOF
." other: " DUP .
ENDCASE
1 OVER = IF
s" one" type
ELSE
2 OVER = IF
s" two" type
ELSE
s" other:" type DUP .
THEN
THEN
DROP
CASE
🙘
• Terser branching on a value
• Forth syntax doesn't quite allow jump tables
- Worth exploring? Or un-Forthy?
BTERM &
RELINQUISH
BTERM
🙘
• Bluetooth serial can be handy
• Discovered that bterm wasn't working on regular ESP32!
• The issue is that bluetooth needs about 120KB free
• RELINQUISH ( n -- ) releases n bytes from the back of the heap
• Built into bterm lazy loading
Shell
Words
A Forth-y Shell
🙘
• Basic BASH-like words
• But ESP32 doesn't build in directory support
• A few extra words on Linux
cp ( "src" "dst" -- ) Copy "src" file to "dst".
mv ( "src" "dst" -- ) Rename "src" file to "dst".
rm ( "path" -- ) Remove "path" file.
touch ( "path" -- ) Create "path" file if it doesn't exist.
cat ( "path" -- ) Print contents of "path" file.
ls ( "path" -- ) List files or directories in "path".
cd ( "path" -- ) Change director to "path".
mkdir ( "path" -- ) Create directory "path".
rmdir ( "path" -- ) Remove directory "path".
pwd ( -- ) Print current directory.
DEMO Shell
& Editor
Code Words
& DUMP
Code Words
🙘
• Added CODE words, but assembler not yet ready
• Uses a C call signature for stable ABI
• Not all memory can be used for ESP32 code
• ESP32 and Linux support only at the moment
• Assembler coming soon
• Lazy loaded by ASM word
CODE ( "name" ) -- Define a code word
END-CODE -- End a code word
CHERE ( -- a ) -- Get code pointer
CALLOT ( n -- ) -- Allocate code memory
CODE1, ( n -- ) -- Compile 1 byte
CODE2, ( n -- ) -- Compile 2 byte
CODE3, ( n -- ) -- Compile 3 byte
CODE4, ( n -- ) -- Compile 4 byte
Forth to C Entry SIGNATURE:
cell_t *myfunc(cell_t *sp, float **fp);
-------
On x64:
%rdi - Data stack pointer in
%rax - Data stack pointer out
%rsi - Pointer to floating stack pointer
-------
On Xtensa (ESP32):
a2 - Data stack pointer in & out
a3 - Pointer to floating stack pointer
YV(internals, CALLCODE, float *t_fp = fp; DUP; \
sp = (cell_t *) (*(call_t*) (w + sizeof(cell_t)))(sp, &t_fp); \
fp = t_fp; DROP) \
ASM FORTH
CODE my2*
$48 CODE1, $89 CODE1, $f8 CODE1, ( mov %rdi, %rax )
$48 CODE1, $d1 CODE1, $27 CODE1, ( shlq [%rdi] )
$c3 CODE1, ( ret )
END-CODE
ASM FORTH
CODE my2*
$004136 CODE3, ( entry a1, 32 )
$0288 CODE2, ( l32i.n a8, a2, 0 )
$1188f0 CODE3, ( slli a8, a8, 1 )
$0289 CODE2, ( s32i.n a8, a2, 0 )
$f01d CODE2, ( retw.n )
END-CODE
' - 20 hex dump
416208 34 2A 40 00 00 00 00 00
416210 B2 3E 41 00 00 00 00 00 08 03 00 00 00 00 00 00
416220 16 2A 40 00 00 00 00 00
ESP-CAM
Bindings
esp_camera_init ( config -- f )
esp_camera_deinit ( -- f )
esp_camera_fb_get ( -- fb )
esp_camera_fb_return ( fb -- )
esp_camera_sensor_get ( -- sensor )
esp_camera_save_to_nvs ( key -- n )
esp_camera_load_from_nvs ( key -- n )
( formats )
PIXFORMAT_RGB565
PIXFORMAT_YUV422
PIXFORMAT_GRAYSCALE
PIXFORMAT_JPEG
PIXFORMAT_RGB888
PIXFORMAT_RAW
PIXFORMAT_RGB444
PIXFORMAT_RGB555
( frame sizes )
FRAMESIZE_96x96 ( 96x96)
FRAMESIZE_QQVGA ( 160x120 )
FRAMESIZE_QCIF ( 176x144 )
FRAMESIZE_HQVGA ( 240x176 )
FRAMESIZE_240x240 ( 176x144 )
FRAMESIZE_QVGA ( 320x240 )
FRAMESIZE_CIF ( 400x296 )
FRAMESIZE_HVGA ( 480x320 )
FRAMESIZE_VGA ( 640x480 )
FRAMESIZE_SVGA ( 800x600 )
FRAMESIZE_XGA ( 1024x768 )
FRAMESIZE_HD ( 1280x720 )
FRAMESIZE_SXGA ( 1280x1024 )
FRAMESIZE_UXGA ( 1600x1200 )
( access to config )
camera-fb-count ( -- a )
camera-jpeg-quality ( -- a )
camera-frame-size ( -- a )
camera-format ( -- a )
( Access a frame returned by esp_camera_fb_get )
fb->buf ( -- a )
fb->len ( -- n )
fb->width ( -- n )
fb->height ( -- n )
fb->format ( -- n )
fb->sec ( -- n )
fb->usec ( -- n )
( Access methods in struct returned by esp_camera_sensor_get )
s->xclk_freq_hz ( a )
s->init_status ( s )
s->reset ( s )
s->set_pixformat ( s pixformat )
s->set_framesize ( s framesize )
s->set_contrast ( s level )
s->set_brightness ( s level )
s->set_saturation ( s level )
s->set_sharpness ( s level )
s->set_denoise ( s level )
s->set_gainceiling ( s gainceil )
s->set_quality ( s quality )
s->set_colorbar ( s enable )
s->set_whitebal ( s enable )
s->set_gain_ctrl ( s enable )
s->set_exposure_ctrl ( s enable )
s->set_hmirror ( s enable )
s->set_vflip ( s enable )
( --- )
s->set_aec2 ( s enable )
s->set_awb_gain ( s enable )
s->set_agc_gain ( s gain )
s->set_aec_value ( s gain )
( --- )
s->set_special_effect ( s effect )
s->set_wb_mode ( s mode )
s->set_ae_level ( s level )
( --- )
s->set_raw_gma ( s enable )
s->set_lenc ( s enable )
( --- )
s->get_reg ( s reg mask )
s->set_reg ( s reg mask value )
s->set_res_raw ( s startX startY endX endY offsetX offsetY totalX totalY outputX outputY scale binning )
s->set_pll ( s bypass mul sys root pre seld5 pclken pclk )
s->set_xclk ( s time xclk )
USER_VOCABULARIES
Y(myword, n0 = myfunc(a1, n0); DROP) \
X("myword!", MYWORDBANG, n0 = myfunc(n0)) \
YV(myvocab, myword, n0 = myfunc(a1, n0); DROP) \
XV(myvocab, "myword!", MYWORDBANG, n0 = myfunc(n0)) \
Builtins add an extra chain of builtin words
e.g.
internals-builtins
Wire-builtins
userwords.h
-----------
#define USER_VOCABULARIES V(myvocab) V(myvocab2)
#define USER_WORDS \
XV(myvocab, "my+", MYPLUS, n1 = n1 + n0; DROP) \
YV(myvocab2, myword, n0 = n0 + 10) \
VOCABULARY myvocab myvocab DEFINITIONS
transfer myvocab-builtins
FORTH
VOCABULARY myvocab2 myvocab2 DEFINITIONS
transfer myvocab2-builtins
FORTH
QUESTIONS?
🏵
Thank you!