Getting Started - amir1387aht/MicroCS GitHub Wiki

Getting started

This guide takes you from a fresh clone to a C# script running inside your own firmware.

1. Build the host tools

git clone https://github.com/amir1387aht/MicroCS && cd MicroCS
make            # → ./mcs   (needs any C99 compiler; no other dependencies)
make test       # optional: full test suite

./mcs is the compiler, the VM, a REPL and the standalone runtime in one binary.

2. Run your first script

// hello.cs
using System;
using System.Linq;

var squares = Enumerable.Range(1, 5).Select(i => i * i).ToList();
Console.WriteLine($"squares: {string.Join(", ", squares)}");
var (min, max) = (squares.Min(), squares.Max());
Console.WriteLine($"range {min}..{max}, last = {squares[^1]}");
./mcs hello.cs
# squares: 1, 4, 9, 16, 25
# range 1..25, last = 25
./mcs --repl --sim # the device REPL, with a simulated board

3. Talk to (simulated) hardware

The --sim flag gives scripts a virtual board with every peripheral (GPIO with interrupts, UART, I²C sensors, SPI, ADC, DAC, PWM, timers, I²S, QSPI flash, CAN, watchdog, RTC), and --run-for lets the job scheduler run for a while:

./mcs --sim examples/hardware/01_blink.cs
./mcs --sim examples/hardware/05_i2c_temperature.cs
./mcs --sim --ramfs 16384 --run-for 1200 examples/hardware/16_data_logger.cs
./mcs --sim --sim-log tests/t08_hal.cs     # trace every peripheral access

All 16 hardware examples are listed in examples/README.md. The peripheral API is documented in HAL.md, the scheduler in SCHEDULER.md, files in FILESYSTEM.md.

4. Precompile for a device

On small parts, compile on the PC and ship only the VM:

./mcs -c app.cs -o app.mcsb                    # image file (copy to the device FS)
./mcs -C app.cs -n app_image -o app_image.h -s # const array to link into flash
./mcs -d app.mcsb                              # check what is inside
./mcs --xip app.mcsb                           # run it the way mcs_exec_image_xip() does on flash

A runtime-only build (-DMCS_ENABLE_COMPILER=0) saves ~44 KB of flash and the compiler's RAM. Images are portable between 32- and 64-bit hosts. Format: BYTECODE.md. For 32–64 KB RAM parts see LOW_RESOURCE.md.

5. Embed the VM in firmware (Option 1)

  1. Add MicroCS to your build — include microcs.mk, add_subdirectory(MicroCS), an ESP-IDF component, a Zephyr module, a PlatformIO/Arduino library, or just the .c files in your IDE. Every variant is in PORTING.md.
  2. Optional: configure it. Copy config/mcs_user_config.h into your project as mcs_user_config.h — it holds every option with its default value — and edit the values you change. For another profile's defaults generate it: python3 tools/gen_config.py --profile embedded -o mcs_user_config.h (auto, min, tiny, mcu, lowram, embedded, linux — see include/profiles/). -D… options work too and win over the header. Details: CONFIGURATION.md.
  3. Create a VM on a static pool and run a script (a runnable version is examples/quickstart_embed.c, make quickstart):
#include "mcs.h"
#include "app_image.h"     /* generated by: ./mcs -C app.cs -n app_image -o app_image.h */

static uint8_t heap[128 * 1024];
static mcs_pool_t pool;

void scripts_main(void) {
    mcs_config_t cfg; mcs_config_default(&cfg);
    mcs_pool_init(&pool, heap, sizeof heap);
    cfg.realloc_fn = mcs_pool_realloc; cfg.alloc_ud = &pool;
    cfg.heap_limit = sizeof heap - 2048;
    cfg.write_fn = my_uart_write;          /* Console.Write*            */
    cfg.ticks_fn = my_millis;              /* time, limits, scheduler   */
    mcs_vm_t* vm = mcs_new(&cfg);
    if (mcs_exec_image(vm, app_image, app_image_len) != MCS_OK)
        my_log("script failed: %s", mcs_last_error(vm));
    mcs_free(vm);
}

To let C# use the board's peripherals, add a port and one line: mcs_stm32_hal_init(&hal, &board); mcs_hal_open_lib(vm, &hal); (or mcs_esp32_…, mcs_rp2_…, mcs_zephyr_…, mcs_arduino_…). Full walkthrough with C bindings, calling script functions from C, limits and the GC contract: EMBEDDING.md.

6. A complete C# firmware with a REPL (Option 2)

mcs_runtime_run() turns the board into a C# device: REPL on the console, /boot.cs and /main.cs from the filesystem, jobs, interrupt callbacks and an upload protocol. Start from a ready-made project — Pico, ESP32, STM32 CubeMX, Zephyr, Arduino — then upload programs from the PC:

./mcs --shell --fs device_root      # try the protocol on the host first
python3 tools/mcs_remote.py --exec "./mcs --shell --fs device_root" put app.cs /main.cs + run /main.cs
python3 tools/mcs_remote.py --port /dev/ttyACM0 repl     # on a real board

Details: STANDALONE.md.

Where next?