Portenta H7: PicoC - C-code interpreter

I have "my" PicoC C-code-interpreter running on Portenta H7
(it uses and needs the SDRAM for C-code scripts, all 8MB used for C-code, as text, huge space for "C-code scripts").

What is PicoC?
It is a C-code-interpreter (not a compiler, it does not need any other tools).
It runs natively on target (here Portenta H7).
It interprets input on UART (USB-C with UART terminal), from SD Card as C-code statements (text lines and files, decoded and interpreted as C-code).

It executes the C-code statements:
no need to compile, interactive (see immediately if statement is wrong and why), not so fast
on execution (it is interpreted), but very fast on code writing and turnaround to modify C-code.
(not any compiler or external tool needed).
Very convenient to write new scripts like C-programs and let them run.

It is like writing C-code programs (including to load "scripts" from SD Card, use "#include ..." with files on SD Card etc.).
Enter C-code on command line, without a need to compile, no need to have a compiler involved, nothing to install: all comes with the MCU board and UART terminal.
It is "interpreted" (text parsing and execution if correct), not compiled.

Benefit: you can add your own C-functions as new "commands", all available as full source code, it runs on small MCUs (and could be ported to WIN32 as well - I have it also running in a Nokia Qt GUI App for Windows, MacOS).

Who does want to use?
Who wants to use "PicoC" on Portenta H7?

It is almost ready: I had to fix some issues with using gets(), reading files from SD Card (e.g. RunScript(executeScript), #include files).
And clean up the code plus more comments for integration on other targets.
Afterwards, I will release a project and BIN file to flash on Portenta H7.

Here a screenshot (UART) how it looks like to use PicoC:

BTW:
I know, there is also MicroPython. But:
it seems to come with a full binary installation. And I do not have any clue how to add my own functions to it. For instance: I need SPI commands, I2C read and write, user GPIO pins (set and read) etc. No idea how to extend a MicroPython system with my own code and stuff, at least
how to implement new user functions.

PicoC is full source code. It uses available BSP (system), e.g. for UART line in, print line on UART, SD Card.
And very easy to add a new function definition, e.g. doing a SPI transaction, available as a new
function which can be called on command line, in "C-code" scripts.

The good news (for me): the code is small enough to fit with all my BSP functions into Portenta H7 flash memory. Potentially, I can also enable the math functions (e.g. coming via math.h).

It behaves like a real C-code compiler, just: it executes immediately after entering a correct statement (interpreted immediately). No need to wait for compile, to flash code etc.
Just place it on SD card or transfer via UART (or network). And ready to execute C-code-programs/applications.

Sharing my latest status here (potentially before I say "good bye" to this forum).

CubeIDE project with Pico-C
My Pico-C (C-code interpreter) is now able to read C-code files, #include files ... from SD Card.
The link to full source code project at the end.

Give it a try
The BIN file to flash - with Arduino Bootloader (not killing it):
BIN file to flash with Arduino Bootloader

Flash it via CMD line, "dtf-util.exe", e.g. via command line:

dfu-util -a 0 -d 2341:035b --dfuse-address=0x08040000:leave -D PortentaH7_CubeIDE_CM7_bootloader.bin

When it boots...
Remark: often, my USB-C UART is not realized on host side. Do a power cycle of Portenta H7 board and find/open UART device (provided as VCP via USB-C).

UART via USB-C cable: baudrate: 1843200 (no flow control, no parity, 1 stop bit)

Use command "help" to see which commands are implemented.

Use SD-Card
If you want to use SD Card:
put a formatted SD card (FAT32) into slot (you need the breakout board!). Copy files you want to use before to it (see below)
Do a command via UART as:

sdinit 1

It initializes SD card - ready to use (mandatory to do once), list the content of root directory.
If you see SD Card root directory - all fine to use SD Card (e.g. also in Pico-C for C-code script files).

Launch Pico-C
Enter command

picoc

You should see a different welcome message, a different prompt ( : ). This is the Pico-C command line. Enter some C-statements and check what happens (errors or taken and executed as C-code).

You can call function:

CHelp();

in order to see which "commands" (C-code functions) are available to use in Pico-C.

Simple test of Pico-C:
Enter these commands:

int i;
i = 0;
while (1) {
printf("i=%d\n", i++);
}

It will print the incrementing variable i. You can stop the endless loop (here via while(1) ), with entering CTRL-C on UART terminal (command line).

Pico-C from SDCard
Place C-code scripts on SD card (copy before to SD card on host PC - or use TFTP (ETH network) - details on request how to transfer files via network to SD card).

Have two files on SD Card:
"test.h":

/*include file*/
#undef a
int a;
#define LED_LOOP_DELAY	200

"test.c":

#include "test.h"

int i;
i = 10;
printf("i = %d\n", i);

printf("toggle LED: press CTRL-C to abort\n");
while (1) {
	//2 : blue, 1 = on, 0 = off
	SetLED(2,1); mssleep(LED_LOOP_DELAY);
	SetLED(2,0); mssleep(LED_LOOP_DELAY);
}

When you have entered "picoc" (see prompt ':') - enter function call:

RunScript("test.c");

It should let blink the Blue LED (faster than the green "heartbeat" LED).
You can stop with CTRL-C.

If you are still on Pico-C command line (with prompt ':') - enter function call:

exit(0);

It will return to main command shell (prompt is '>').

Screenshot (after "sdinit 1" done on shell command line!):

CubeIDE project
Here, I provide the full source code (really any line of code, as full Open Source, including the Pico-C interpreter code).
It is an STM CubeIDE project (not an Arduino sketch project!).
But linker script is set to create a BIN which can be flashed via Portenta H7, Ardunino Bootloader (see above).

CubeIDE project as ZIP
CubeIDE project as "exported archive"
the BIN file to flash with Arduino Bootloader ("dft-util.exe")

Good Bye
I think, I have provided some help here for other people, I have shared something for the community.
Potentially, I will leave this forum and say "good bye" to everybody here:

  • I was expecting much more help/guidance on this forum, esp. help from Arduino team, expecting Arduino providing Full Source Code projects (as I did, committed to Open Source, why not Arduino? They do NOT do at the end).

  • OK, I understand: a user forum (without Arduino team commenting, not helping here - instead they send me just notifications about deleting my threads and contributions, maybe "disappointed with me"). I am fine, I do not really need help (from this forum, esp. if there is not any from Arduino). But I hope, I could contribute to and help other people a little bit here.

Have fun and good luck with the Portenta H7 board (and with Arduino). :smiley:

1 Like

Thanks for all your work! I have benefited from it, still working on the QSPI. I got your HAL based code working and getting to the point where I can use my CubeIDE generated code with one or two HAL calls, then let's check if the Mbed-OS code will work. Not sure if the 16 MB QSPI memory is useful enough but to use all board features, I'm interested enough to put in some effort.

The Portenta hardware is great but, in the end, you end up working with STM32CubeIDE and Mbed-OS to get important low-level features done, which kind of defeats the purpose of having a user-friendly Arduino environment. For instance, I have the ADCs working in dual mode with DMA fired by an external (non-timer) trigger. Arduino will never provide such detail - I had to use an STM32 example to get it working (CubeIDE is not complete), which was hard enough already. Once you get to the point where such things are working you are hardly using Arduino features anymore. If I can't get this QSPI working today for instance, I will be forced to build my debug Mbed-OS installation so then why even go back to the Arduino build. If Arduino provided a documented way to easily build a debug version of Mbed-OS, that would be helpful actually.

Good luck with your endeavors!

Few comments:
I want to get QSPI working as well, still. I think, I have it on Arduino system (with VisualStudio Micro as IDE, but as a sketch).
Just, I want to add also to my CubeIDE project, to have QSPI as storage (e.g. for web pages, APP code, system config ...).

Actually, it is not really worth it: what I have realized: this chip on Arduino Portenta H7 is a "strange" (old) one: it does not support MemoryMapped mode: not able to do code fetches (to run code execution directly from QSPI). It is usable as data storage, even code in it - but you had to copy from QSPI to other location for execution (so, it does not extend the code space).

Mbed-OS: on my "bare-metal" CubeIDE I do not use any Mbed or Arduino LIB and neither the API. The RTOS used is CMSIS OS (v2) and FreeRTOS.
The drawback: all the higher level features such as connecting to a cloud service (MQTT?) and using C++ coding style is not there.
OK, adding these "#ifdef "C" {" everywhere should make it possible to use C++. But on my project are not any class definitions (yet). It is still like direct STM HAL use (what works actually also in an Arduino sketch).

ADC: I want to add at least to read the die temperature sensor (ADC3, channel 18).

And the CM4 is not used, not running in my system (I do not have yet a use case where CM4 would help, I need the max. performance on CM7 for almost all stuff (SPI, I2C, network, SD card, file system, web server, network Python access).

I think you mean "CubeMX" - the code generator: it is helpful, esp. to get code how to initialize devices. But in terms of "how to use" (e.g. how to read via ADC the temperature sensor, how to use calibration data ...) it does not help. But several examples on Internet out there, even datasheet is very helpful. (I like to go anyway the "grass root path", knowing in all details which code, what it will do, how does it work, what and where done ...).

Debugger:
I totally agree: I want to use (only) a full open source system. I want to be able to see and debug any line of code, including a LIB involved. I have seen on native Arduino coding and API several flaws, e.g. SPI not able to configure LSB first, I2C with driving 3V3 totem pole pulses (even using 1V8 Open Drain) etc. And the QSPI chip on board - unfortunately, does not work as I need and even STM32CubeProgrammer with external loader cannot access QSPI (e.g. to flash or just read what is on this chip via debugger).

Yes, a nice piece of HW. But making use of all the features (I am a HW guy, testing other chips), fighting for the best performance ... is pretty tough with Arduino IDE and API (e.g. why not 480 MHz core clock? Why network is so slow and needs modification on FIFOs used in code ...?).

My biggest problem to divert from Arduino: the IDE, even VisualStudio Micro, are so slow. When I had to compile in office (there are several IT tools and checkers running in background) - it is so slow. No fun (it takes up to one day just to compile, where at home it works fine).
I need also a fast "turn-around" on IDE, modify, compile, download, test. But the Arduino IDE does support (the compile time even at home is sooooo slow, CubeIDE projects are 10 times faster to compile all after clean).
And the missing debugger - almost a "no go" for me.
Therefore, a native CubeIDE project, with full open source, full debug - was the driving force.

FWIW, today I was able to debug some mbed-os code. I can now tell where my QSPIFBlockDevice creation fails. My debug-setup approach is documented here and is crude but effective. I have a pretty decent makefile setup within STM32CubeIDE that lets me build and debug it. FYI.