MM-2350 is a mini-computer designed to implements the Minimacy vision of a system in which you can understand 100% of its operation. [](html) [](html) Technical specifications: - Micro-controller: Raspberry Pi RP2350, 150MHz, 512KB RAM, hardware random generator - PSRAM: 8MB - Flash: 16 MB - USB-C: power and RP2350 programming - 2 Ethernet ports with separate controllers (SPI). MAC addresses provided. - OLED display: 128x64 pixels (I2C) - 1 SD card reader (SPI) - 1 RTC (Real-time clock) with CR1220 battery support (I2C) - 4 switches: BOOT, RESET, LEFT, RIGHT - 1 blue LED (user) - 1 red LED (power) - 1 CONSOLE port (UART) - 1 debug port (Raspberry Pi Debug probe) - 1 expansion port: 5V, 3.3V, ground, UART, I2C, SPI, 4 GPIOs Documentation: - [MM-2350 schematic](https://minimacy.net/book/rsc/MM-2350/MM-2350-schematic.pdf) - [MCU: RP2350](https://minimacy.net/book/rsc/MM-2350/RP-008373-DS-2-rp2350-datasheet.pdf) - [PSRAM: APS6404L](https://minimacy.net/book/rsc/MM-2350/APS6404L-3SQR-SN.pdf) - [Flash: W25Q128JVSIQ](https://minimacy.net/book/rsc/MM-2350/W25Q128JVSIQ.pdf) - [Ethernet: ENC624j600](https://minimacy.net/book/rsc/MM-2350/encX24j600.pdf) - [Real-time clock: MCP7940N](https://minimacy.net/book/rsc/MM-2350/MCP7940N.pdf) - [Oled display: SSD1306](https://minimacy.net/book/rsc/MM-2350/SSD1306.pdf) #Getting Started Steps: - Assume prior familiarity with Minimacy on a host computer - Copy blink to the SD card - Connect the console, launch the romdisk.server.mcy program on the host - Understand how disks work in baremetal mode - Modify boot.mcy - Use the flash disk The first time, you should follow the order of the chapters. ##Minimacy Minimacy is a highly cross-platform technology: computers, mobile phones, and embedded baremetal. When working on embedded products, you will generally develop the components of your application on your computer, then transfer them to the embedded product. This implies that you are already familiar with Minimacy on a computer. This guide assumes you have already installed Minimacy, that you know how to run programs (*.mcy files), and that you have some basic knowledge of the Minimacy language. This guide covers the MM-2350 board, designed specifically for Minimacy. You should have: - An MM-2350 board - A computer (Windows, Linux, Mac) - A USB / USB-C cable to power the MM-2350 board - A USB / UART cable to connect the CONSOLE output of the MM-2350 board to the computer - A micro-SD card formatted in FAT32 - A micro-SD card reader for your computer ##Blink By default, Minimacy launches the boot.mcy program found: - On a computer: in the ./programs/ directory - On MM-2350: at the root of the SD card Insert the SD card into your computer. Verify that the card is formatted as FAT32. At the root of the card, create a file boot.mcy with the following content: fun blink(state)= led(state); onTimeout(500, lambda()= blink(!state));; fun main() = blink(true);; This program blinks the blue LED on the MM-2350 board, toggling its state every 500 milliseconds. Eject the SD card from your computer and insert it into the MM-2350 board. Connect the MM-2350 board to your computer using the USB/USB-C cable. The board powers on (steady red LED), and after a few seconds, the blue LED starts blinking. Congratulations! You have just run your first embedded program on MM-2350. Remove the SD card for the rest of the getting-started guide. ##Console To develop efficiently, you need to interact with the MM-2350 console. This is a text-mode interface accessible from your computer, based on a serial (UART) connection initialized at 115,200 bps (8 bits, no parity, 1 stop bit). To do this: - Connect the USB/UART cable: one end to your computer, the other to the port marked "CONSOLE" on the MM-2350 board. - On your computer, launch the program ./programs/romdisk/romdisk.server.mcy As a reminder: - On Windows: double-click the romdisk.server.mcy file, and associate *.mcy files with ./bin/minimacy.exe if not already done. - On Linux: from the minimacy directory, run: >./bin/minimacy ./programs/romdisk/romdisk.server.mcy - On macOS: from the minimacy directory, run: >./bin/minimacyMac ./programs/romdisk/romdisk.server.mcy In all cases, you will see the following output: >Bootdisk server & console - 2026 - Sylvain Huet >----------------------------------------------- >(edit the bootdisk content in file romdisk/romdisk.server.txt) This program tries to detect available serial connections. If it finds only one, it uses it automatically. If it finds several, it asks you to choose. For example: >Available serial ports: >1. COM6: USB Serial Port >2. COM5: Silicon Labs CP210x USB to UART Bridge >Enter number> Restart the MM-2350 board, either by unplugging/replugging the USB-C cable, or by pressing the RESET button on the board. The following messages appear: >> Minimacy - Sylvain Huet - 2020-26 - 2.0.1/MM2350 >> ---- >> 32 bits >> Memory strip 0: 481280 bytes (0x200070bc - 0x2007c8bc) >> Memory strip 1: 8388608 bytes (0x11000000 - 0x11800000) >> Memory length : 8869888 bytes (0x875800) > >File list: >Disk image size: 0 bytes >Sent time: Tue, 03 Feb 2026 15:49:44 UTC >++ >> Current working directory: [empty] >> Default user directory : [empty] >> BIOS compiled in 887 ms >> current time: Tue, 03 Feb 2026 15:49:46 UTC >> compiling 'baremetal.mm2350.boot' >> compiling 'core.storage.format' >> compiling 'core.storage.fat32' >> compiling 'core.util.cache' >> compiling 'core.storage.romdisk' >> compiling 'driver.generic.spi.sdcard.storage' >> compiling 'driver.generic.gpio' >> compiling 'driver.generic.spi' >> compiling 'driver.generic.spi.encX24j600.ethernet' >> compiling 'driver.generic.i2c.ssd1306.oled' >> compiling 'driver.generic.i2c' >> compiling 'driver.generic.i2c.mcp7940n.rtc' >> compiling 'driver.generic.display' >> compiling 'driver.generic.flash' >> compiled in 778 ms >> RTC: Tue, 03 Feb 2026 15:49:46 UTC >> Storage: check volume flash0 >> Storage: no mbr >> Storage: found fat32 partition (15.728.640 Bytes, cluster size: 4096): FLASH >> Building romdisk, depth 2 >> SD: sdInit >> compiling 'boot' >> compiled in 3 ms >] █ By default, on a new MM-2350 board, the boot goes to the top-level: you can enter commands. For example: >] 1+2 >-> Int: 3 (0x3) You can turn on the blue LED: >] led(true) >-> Bool: true ##Behind the Magic Let us break down the boot message: >> Minimacy - Sylvain Huet - 2020-26 - 2.0.1/MM2350 >> ---- >> 32 bits At board startup, you can verify the version of Minimacy. This is a 32-bit version since the MM-2350 board uses the Raspberry Pi RP2350 microcontroller. >> Memory strip 0: 481280 bytes (0x200070bc - 0x2007c8bc) >> Memory strip 1: 8388608 bytes (0x11000000 - 0x11800000) >> Memory length : 8869888 bytes (0x875800) On the MM-2350 board, the RAM usable by Minimacy is split into two parts: - Approximately 470 KB internal to the RP2350 - 8 MB external PSRAM > >File list: >Disk image size: 0 bytes >Sent time: Tue, 03 Feb 2026 15:49:44 UTC >++ At startup, the MM-2350 board interacts with the romdisk.server.mcy program running on the computer. This program is not just a simple terminal: when it receives the message, it understands that the MM-2350 board is requesting boot information. This information is of two types: - The current time on the computer, which allows the MM-2350 board to set its clock. - A "disk image" containing files whose use we will see shortly. Here the disk is empty (Disk image size: 0 bytes). If you have inserted a battery in the MM-2350 board slot, the time will be preserved even when the board is powered off. >> Current working directory: [empty] >> Default user directory : [empty] >> BIOS compiled in 887 ms >> current time: Tue, 03 Feb 2026 15:49:46 UTC These four lines are also present in the computer version of Minimacy. In baremetal mode, the working and user directories are always empty (root directory). The BIOS is compiled in under a second. It is exactly the same BIOS as on the computer version. On a computer, Minimacy finds these files in the ./rom/bios/ directory. In baremetal mode, a set of files are already "hard-coded" in the Minimacy firmware. These are primarily the files from the ./rom/bios, ./rom/core, ./rom/baremetal, ./rom/driver directories, as well as the boot.mcy file in the ./programs/ directory. We will see later how to modify this list and recompile the firmware. Once the BIOS is compiled, the MM-2350 version of Minimacy first executes the baremetal.mm2350.boot.mcy program: >> compiling 'baremetal.mm2350.boot' >> compiling 'core.storage.format' >> compiling 'core.storage.fat32' >> compiling 'core.util.cache' >> compiling 'core.storage.romdisk' >> compiling 'driver.generic.spi.sdcard.storage' >> compiling 'driver.generic.gpio' >> compiling 'driver.generic.spi' >> compiling 'driver.generic.spi.encX24j600.ethernet' >> compiling 'driver.generic.i2c.ssd1306.oled' >> compiling 'driver.generic.i2c' >> compiling 'driver.generic.i2c.mcp7940n.rtc' >> compiling 'driver.generic.display' >> compiling 'driver.generic.flash' >> compiled in 778 ms This hardware boot compiles the various drivers: SD card, Ethernet controller, OLED screen, RTC clock, flash memory. This takes less than a second. >> RTC: Tue, 03 Feb 2026 15:49:46 UTC >> Storage: check volume flash0 >> Storage: no mbr >> Storage: found fat32 partition (15.728.640 Bytes, cluster size: 4096): FLASH >> Building romdisk, depth 2 >> SD: sdInit >> compiling 'boot' >> compiled in 3 ms Then the hardware boot initializes all these components before launching the boot.mcy program, which by default starts the top-level with the "consoleStart" command. The default boot.mcy code is simply: fun main() = consoleStart(nil);; ##Disks in Baremetal Mode To go further, you need to understand the "disk" structure in Minimacy. There are three levels: - A "volume" corresponds to a physical storage medium. - A "partition" is a subdivision of a volume. It can be formatted in several ways, but Minimacy only recognizes FAT32 format. A volume can contain multiple partitions, though there is usually only one. - Finally, a "mount" defines the file path in Minimacy through which a partition is accessed. For example, if a partition contains a file /bar/test.txt, and it is mounted with: - Mount path: /foo/ - Partition path: /bar/ Then Minimacy can access the file via the path /foo/test.txt. The fs() command allows you to visualize this structure. On a new MM-2350 board without an SD card: >] fs() >Volumes: > Volume Access SectorSize NbSectors TotalSize > ------ ------ ---------- --------- --------- > flash0 writable 512 28.672 14M > romdisk1 readonly 562.998 1 549k > >Partitions: > Volume Access TotalSize Partition > ------ ------ ---------- --------- > flash0 writable 13M FLASH > romdisk1 readonly 549k NATIVE > >Mounts: > Id Volume Partition Access Mount Path Partition Path > -- ------ --------- ------ ---------- -------------- > 0 flash0 FLASH writable [empty] / > 1 romdisk1 NATIVE readonly [empty] [empty] There are two volumes: - romdisk1: a disk hard-coded in the firmware, discussed in the previous chapter. - flash0: a large portion of the flash memory is used as a hard disk with a single partition; it occupies 14 MB of the 16 MB on the board, as 2 MB are reserved for the firmware (which also contains romdisk1). Each volume provides one partition: - FLASH: the flash memory partition - NATIVE: the romdisk partition The last section "Mounts" shows how these partitions are mounted and in what order: flash first, then romdisk. This means that when Minimacy looks for a file, it searches first in the FLASH partition, then in the NATIVE partition (romdisk). You can view the contents of these disks: >] dir(nil) > DIRECTORY | Thu, 01 Jan 1970 00:00:00 UTC | 1: baremetal/ > DIRECTORY | Thu, 01 Jan 1970 00:00:00 UTC | 1: bios/ > DIRECTORY | Thu, 01 Jan 1970 00:00:00 UTC | 1: core/ > DIRECTORY | Thu, 01 Jan 1970 00:00:00 UTC | 1: demo/ > DIRECTORY | Thu, 01 Jan 1970 00:00:00 UTC | 1: driver/ > 68 | Thu, 01 Jan 1970 00:00:00 UTC | 1: boot.mcy When the MM-2350 board is new, the flash partition is empty; the only visible files are those from the romdisk. They have no real date since they are embedded in the firmware — their Unix timestamp is 0, dating them to 01/01/1970. You also notice on each line "1:" just before the file or directory name, meaning these files are on mount index 1. In the earlier fs() command, index 1 corresponded to the NATIVE partition of the romdisk1 volume. Now, insert the micro-SD card containing the following boot.mcy file back into the MM-2350 (one line has been added compared to the Blink chapter): fun blink(state)= led(state); onTimeout(500, lambda()= blink(!state));; fun main() = blink(true); consoleStart(nil);; Restart the MM-2350 board. This time the console shows: >> SD: sdInit >> SD: EMMC version 1, highCapacity true, 15.267.840 sectors (512 bytes per sector) >> Storage: check volume sd0 >> Storage: check partition sd0:0 >> Storage: found fat32 partition (38.797.312 Bytes, cluster size: 512): MINIMACY Minimacy found an SD card, which it names "volume sd0", with a FAT32 partition called MINIMACY. What is important to understand next is that the Minimacy firmware cannot read files from the SD card on its own. The firmware contains only the Minimacy compiler and runtime written in pure C. The SD driver and the FAT32 library are applications written in the Minimacy language; the compiler cannot call them since it can only compile programs already in RAM. Things are different on a computer, where Minimacy can access the disk via the OS and ANSI functions such as fopen(), fread(), etc. How then, in the baremetal version, can the compiler compile files located on the SD card? The solution is as follows: when a FAT32 partition is found, the hardware boot program (baremetal.mm2350.boot.mcy) loads all *.mcy files found up to depth 2 in the directory tree and turns them into a romdisk — a large character string that is then mounted as a disk: >> Building romdisk, depth 2 >> - boot.mcy: 124 bytes Then Minimacy launches the boot.mcy program: >> compiling 'boot' >> compiled in 5 ms >] █ The blue LED blinks, and you can enter commands. This time the fs() command returns more lines: >] fs() >Volumes: > Volume Access SectorSize NbSectors TotalSize > ------ ------ ---------- --------- --------- > romdisk2 readonly 145 1 145 > sd0 writable 512 15.267.840 7G > flash0 writable 512 28.672 14M > romdisk1 readonly 562.998 1 549k > >Partitions: > Volume Access TotalSize Partition > ------ ------ ---------- --------- > romdisk2 readonly 145 SDTEST:*.mcy > sd0 writable 33M SDTEST > flash0 writable 13M FLASH > romdisk1 readonly 549k NATIVE > >Mounts: > Id Volume Partition Access Mount Path Partition Path > -- ------ --------- ------ ---------- -------------- > 0 romdisk2 SDTEST:*.mcy readonly [empty] [empty] > 1 sd0 SDTEST writable [empty] / > 2 flash0 FLASH writable [empty] / > 3 romdisk1 NATIVE readonly [empty] [empty] You will notice new volumes sd0 and romdisk2, and new partitions: - SDTEST: the SD card partition (our SD card's partition is named SDTEST) - SDTEST:*.mcy: the partition containing the *.mcy files found on the SD card When Minimacy looks for a file, it searches in this order: romdisk2, sd0, flash0, romdisk1. ##Modifying boot.mcy At this point, to "work" and for example modify the boot.mcy program, the procedure seems cumbersome: - Remove the SD card - Reinsert it into the computer - Open, edit, save the boot.mcy file - Remove the SD card - Reinsert it into the MM-2350 board - Restart or press the RESET button on the board We need a faster solution, because in software development it is essential that the modify/test loop be as fluid as possible. What we want is the minimal workflow: - Modify the boot.mcy program on the computer - Restart the board As mentioned above, the romdisk.server.mcy program running on the computer is not just a terminal: when it receives the message, it can transmit a romdisk that will override the files present on the card. We simply need to define the list of files to include in this romdisk. To simplify things, remove the SD card from the MM-2350 and leave it aside. Edit the file ./programs/romdisk/romdisk.server.txt on the computer. List the files one per line, with no leading spaces or tabs (otherwise the line is ignored): >#to comment files, just insert a tab before the path >boot.mcy Now edit the file ./programs/boot.mcy on the computer as follows: fun main() = echoLn "Hello, world!"; consoleStart(nil);; Press the RESET button on the MM-2350 board. This time the console shows the following for the BOOTDISK block: > >File list: >+ boot.mcy >Disk image size: 84 bytes >Sent time: Tue, 03 Feb 2026 17:29:04 UTC >+= We can see that the computer sent a romdisk of 84 bytes, containing only the boot.mcy file. Then, at the end, our "Hello, world!" message: >> compiling 'boot' >> compiled in 3 ms >Hello, world! >] Compilation happens on the fly. On the computer, modify boot.mcy again, replacing the content with: fun main() = echoLn "Compilation is so fast!"; consoleStart(nil);; Save, restart the board, the console now ends with: >> compiling 'boot' >> compiled in 4 ms >Compilation is so fast! >] The development modify/test loop is optimal! You can visualize the disk structure: >] fs() >Volumes: > Volume Access SectorSize NbSectors TotalSize > ------ ------ ---------- --------- --------- > flash0 writable 512 28.672 14M > romdisk0 readonly 94 1 94 > romdisk1 readonly 562.998 1 549k > >Partitions: > Volume Access TotalSize Partition > ------ ------ ---------- --------- > flash0 writable 13M FLASH > romdisk0 readonly 94 BOOTDISK > romdisk1 readonly 549k NATIVE > >Mounts: > Id Volume Partition Access Mount Path Partition Path > -- ------ --------- ------ ---------- -------------- > 0 romdisk0 BOOTDISK readonly [empty] [empty] > 1 flash0 FLASH writable [empty] / > 2 romdisk1 NATIVE readonly [empty] [empty] We can see that there is now a romdisk0 volume, containing the BOOTDISK partition and mounted at index 0, meaning every file is searched first in this romdisk. In summary, for efficient development on the MM-2350 board: - Use the Bootdisk to load the files you are working on into the board: list them in ./programs/romdisk/romdisk.server.txt. - Edit these files on the computer and restart the board, which reloads them in the sequence. Once the application is ready, you can: - Copy these files to an SD card and insert it into the MM-2350 board. - Copy these files to the flash disk (covered later). - Embed these files in the NATIVE romdisk of the firmware and recompile it (covered later). Then remove the files from the Bootdisk (e.g., by commenting them out in ./programs/romdisk/romdisk.server.txt). The board is now autonomous and can operate without the computer. ##Using the Flash Disk Remember that the FLASH disk corresponds to a portion of the 16 MB of flash memory on the MM-2350 board. It is formatted in FAT32. In the absence of an SD card, it is the only writable disk available. >] fs() >Volumes: > Volume Access SectorSize NbSectors TotalSize > ------ ------ ---------- --------- --------- > flash0 writable 512 28.672 14M > romdisk1 readonly 564.923 1 551k > >Partitions: > Volume Access TotalSize Partition > ------ ------ ---------- --------- > flash0 writable 13M FLASH > romdisk1 readonly 551k NATIVE > >Mounts: > Id Volume Partition Access Mount Path Partition Path > -- ------ --------- ------ ---------- -------------- > 0 flash0 FLASH writable [empty] / > 1 romdisk1 NATIVE readonly [empty] [empty] You can write using the function: save(content, filename) >] save("Hello, world!","test.txt") >-> Bool: nil >] dir(nil) > DIRECTORY | Thu, 01 Jan 1970 00:00:00 UTC | 1: baremetal/ > DIRECTORY | Thu, 01 Jan 1970 00:00:00 UTC | 1: bios/ > DIRECTORY | Thu, 01 Jan 1970 00:00:00 UTC | 1: core/ > DIRECTORY | Thu, 01 Jan 1970 00:00:00 UTC | 1: demo/ > DIRECTORY | Thu, 01 Jan 1970 00:00:00 UTC | 1: driver/ > 37 | Thu, 01 Jan 1970 00:00:00 UTC | 1: boot.mcy > 13 | Thu, 05 Feb 2026 18:14:42 UTC | 0: test.txt >7 element(s) The test.txt file is created in mount index 0, confirming the flash disk is working. There is another use case for the FLASH disk. If the application you are developing is ready, runs from the SD card, and fits within 14 MB, you may want to operate without an SD card by copying everything to Flash. To do this, use the baremetal.mm2350.admin.mcy program already integrated in the firmware's NATIVE disk. Activate it by starting the MM-2350 board while holding the left button. After a few moments, an admin menu appears on the board's screen: [](html) And in the console: >Commands: >-------- >help > this message >setTime > set the current time >flash > list of all files on flash disk >sd > list of all files on sd card >format > format the flash disk >import path > copy a file from the sd card to the flash disk >import > copy all files from the sd card to the flash disk >export path > copy a file from the flash disk to the sd card >export > copy all files from the sd card to the flash disk >dir [path] > show the directory content >copy [src] [dst] > copy a file >delete [path] > delete a file >toplevel > start the toplevel >> █ The key commands are: - sd: lists all files on the SD card with total size - format: formats (completely erases) the flash disk - import: copies all files from the SD card to the flash disk - flash: lists all files on the flash disk Applying the first three commands in order copies all SD card files to the flash disk. You can then remove the SD card and restart the MM-2350 board. To revert, restart the board while holding the left button to launch baremetal.mm2350.admin.mcy, then use the "format" command to reset the flash disk. #Developing an Application Topics: - Using the screen - Using the network - Using the expansion port Due to Minimacy's highly cross-platform nature, applications developed for the MM-2350 board have almost no differences from those developed for the computer version of Minimacy: - All pure computation is identical. - File access is identical. - Use of the clock is identical. - The console works the same way. Three aspects however present differences: - User interface: screen and buttons - Network configuration - Use of the expansion port, which has no equivalent on a computer ##Graphical Interface The interface consists of two elements: - A monochrome 128x64 pixel screen - Two "left" and "right" buttons It is recommended to use the driver.generic.display package, as it emulates this interface on a computer, allowing you to work on the interface directly on the computer. The principle is as follows: - The screen is treated as a graphics window and a 128x64 pixel bitmap. Initialize the screen by calling uiStart() with dimensions 128x64. On a computer, an 8x zoom is applied to the window (otherwise it would be unreadable). - You can use all bitmap display functions, but limit yourself to two colors: white (0xFFFFFF) and black (0x000000). - As on a computer, use uiUpdate() to transfer the content of uiBuffer() to the screen. Anything that is not black will be displayed as white. - The buttons are treated as the left and right arrow keys on the computer. - For text on screen, a purely monochrome (black and white, no greyscale) small font is needed. The package includes a 6x8 pixel font and text display functions, avoiding the need to include core.2d.font and core.2d.png packages. A simple example: use driver.generic.display;; fun main()= uiStart(0, 0, 128, 64, nil, "Test"); bitmapErase(uiBuffer(), 0); bitmapCircle(uiBuffer(), 0, 0, 128, 64, 0xffffff, nil); drawStringCenter(64, 28, "MINIMACY", false); uiUpdate();; This program displays an ellipse with text in the center. It can be run on both a computer and the MM-2350 board. A second example showing button usage: use driver.generic.display;; fun drawScreen(text)= bitmapErase(uiBuffer(), 0); drawStringCenter(64, 28, text, false); uiUpdate();; fun main()= uiStart(0, 0, 128, 64, nil, "Test"); uiOnKeyDown( lambda(key)= if key==Key_Left then drawScreen("LEFT"); if key==Key_Right then drawScreen("RIGHT"); ); uiOnKeyUp( lambda(key)= drawScreen("READY")); drawScreen("READY");; This program displays the "READY" message at the center of the screen, replaced by "LEFT" or "RIGHT" when the corresponding button (or arrow key on the computer) is pressed. It can be run on both a computer and the MM-2350 board. ##Network Configuration On a computer, the operating system handles configuring and managing network connections: when your application starts, the network is already ready. On the MM-2350, the hardware boot (baremetal.mm2350.boot.mcy) only initializes the drivers for the two Ethernet ports, but cannot guess the configuration you need. For each port, three configuration types are possible: - Inactive - With a static IP address - With a dynamic IP address obtained via DHCP You can view the result of this initialization with the net() command: >] net() > Name MAC IP Mask Gateway DNS > ---- --- -- ---- ---- ---- > right 2c:fe:8b:fb:58:65 ... ... ... ... > left 2c:fe:8b:fb:58:6f ... ... ... ... > lo 127.0.0.1 255.0.0.0 ... ... The two ports are named 'left' and 'right' and have no IP address. It is therefore up to your application, generally in the main() function of boot.mcy, to define this configuration. The hardware boot defines two constants ETH_LEFT and ETH_RIGHT, equal to "left" and "right" respectively. Here is how to configure the two Ethernet ports: use core.net.ipOverEth;; use baremetal.mm2350.boot;; fun main ()= netDhcp(netUp(ETH_LEFT)); netStatic(netUp(ETH_RIGHT), "169.254.1.1", "255.255.0.0", nil, nil); ... ;; In this example, the left port is configured with DHCP, and the right port with a static IP. Note the use of core.net.ipOverEth, a readable but somewhat complex package that implements in the Minimacy language an IP layer with ARP, UDP, DHCP, and TCP. From there, you can use the network just as on a computer. You can also access the network at a lower level, without loading the IP layer (and without using core.net.ipOverEth). The hardware boot defines two functions giving access to the two Ethernet ports: ethLeft() and ethRight(). You can use the results of these functions to call: - encX24j600LinkStatus(): returns the status of the Ethernet connector (connected/disconnected) - encX24j600OnReceive(): defines a callback for receiving Ethernet frames - encX24j600Send(): sends an Ethernet frame - encX24j600SetPromiscuous(): enables or disables promiscuous mode ##Expansion Port The expansion port provides access to power (ground, 3.3V, 5V) and the following interfaces: - uart1 - spi1 - i2c1 - 4 GPIOs The numbers "1" correspond to the numbering used in the RP2350 microcontroller datasheet. The uart0, spi0, and i2c0 interfaces are already used by the board: - uart0: the console - spi0: the Ethernet controllers and SD card reader - i2c0: the clock and screen The uart1, spi1, and i2c1 interfaces are therefore completely free for use by the application. The UART port is named "uart1" and can be accessed using the serialOpen() function, just as on a computer. The spi1 port uses the SPI protocol, which has the characteristic of linking write and read operations: every time you write a byte, you receive a byte in exchange. If you only want to write, you ignore what is read but still read it. Similarly, if you only want to read, you must send dummy bytes. This is reflected in the available API. You call these functions with the constant "Spi1" designating the spi1 interface. It is possible to drive multiple peripherals with a single SPI port: each peripheral has a CS (chip select) input that normally stays at 1. When the application wants to communicate with a peripheral, it sets CS to 0 and returns it to 1 once the exchange is complete. The expansion port has a CS pin, but you can also use one of the 4 GPIOs as CS if you connect multiple SPI peripherals. The i2c1 port uses the I2C protocol, which allows communication with multiple peripherals distinguished by a one-byte address. To read or write, you must specify the i2c1 port via the constant "I2c1" and the peripheral address. When using multiple SPI or I2C peripherals, keep the following in mind: - Speed must be shared: there is one spi1 clock and one i2c1 clock. - Use locks (lockCreate(), lockSync() functions) to prevent your drivers from conflicting. The hardware boot (baremetal.mm2350.boot.mcy) defines two locks you are invited to use: - CommonI2c1Lock - CommonSpi1Lock #Going Further Steps: - Creating the NATIVE romdisk - Recompiling Minimacy - The hardware boot ##NATIVE Romdisk As we have seen previously, the Minimacy firmware includes the content of a number of *.mcy files that allow it to boot until it is able to read the flash or SD card in FAT32 format to find additional resources. These files are grouped in the NATIVE romdisk, defined by the file: >./baremetal/raspberry-2350/raspberry-2350-native-romdisk.h This file is not present in the git archive. To compile the Minimacy firmware, you must first generate it. To generate it, you first define the files to include. They are defined in the same way as the bootdisk, but in the following file: >./programs/romdisk/romdisk.native.rp2350.txt By default, this includes: the BIOS, the baremetal files, the drivers, and the libraries from the ./rom/core directory. It also includes the boot.mcy file that will be used for startup. You can add any files you want, including your own application files. Remember that you list one file per line, with no leading spaces or tabs (otherwise the line is ignored). The firmware of the Minimacy Virtual Machine is about 350KB, and the part of the flash dedicated to the full firmware (Minimacy + NATIVE romdisk) is 2MB, as 14MB are used as the flash0 volume. So you may put up to 1650KB (2MB-350KB) of data in the NATIVE romdisk. Beyond that, you'd have to redefine the flash memory allocation. Then launch the program: >./programs/romdisk/romdisk.native.rp2350.mcy As a reminder: - On Windows: double-click the romdisk.native.rp2350.mcy file, and associate *.mcy files with ./bin/minimacy.exe if not already done. - On Linux: from the minimacy directory, run: >./bin/minimacy ./programs/romdisk/romdisk.native.rp2350.mcy - On macOS: from the minimacy directory, run: >./bin/minimacyMac ./programs/romdisk/romdisk.native.rp2350.mcy The program displays the list of files included in the romdisk and the path of the resulting file: >../baremetal/raspberry-2350/raspberry-2350-native-romdisk.h It is now possible to recompile the Minimacy firmware. ##Firmware Compilation To compile the firmware, we use the official Raspberry Pi solution: the "Raspberry Pi Pico" extension for Visual Studio Code. [Download link](https://marketplace.visualstudio.com/items?itemName=raspberry-pi.raspberry-pi-pico) Once the extension is installed, in Visual Studio Code open the directory "./baremetal/raspberry-2350". Once Visual Studio Code is properly launched, you will see the "compile" and "run" icons appear at the bottom. Now restart the MM-2350 board, connected to the PC via the USB/USB-C cable, while holding down the "BOOT" button. On Windows, the board then appears as a USB drive named "RP2350". Go back to Visual Studio Code and click the "run" button. [](html) The firmware is then compiled and transmitted (flashed) to the board. Once flashing is complete, the board restarts with the new firmware. [](html) Your compiled firmware is also available as a *.uf2 file: >./baremetal/raspberry-2350/build/minimacy.uf2 In the binary release of Minimacy, this file is available in: >./bin/minimacyMM2350.uf2 This file allows you to flash an MM-2350 board without installing Visual Studio Code: start an MM-2350 board, connected to the PC via the USB/USB-C cable, while holding down the "BOOT" button. On Windows, the board then appears as a USB drive named "RP2350". Simply copy the uf2 file to this drive: the firmware is flashed and the board restarts. ##Hardware Boot When Minimacy starts, it always compiles the same BIOS files (located in ./rom/bios) and then launches the BIOS. Once the BIOS is launched, Minimacy starts the application. By default on a computer, this is the program ./programs/boot.mcy. On MM-2350, this is the program ./baremetal/baremetal.mm2350.boot.mcy. It is relatively short and you can read it. It simply: - Defines the pin constants for the various functions - Initializes the CS (chip select) for the board's SPIs (Ethernet controllers and SD card) - Initializes the time from the RTC component - Initializes the screen and displays the splash screen - Initializes the "left" and "right" buttons - Initializes the driver.generic.display library - Initializes the two Ethernet ports Then, if no button is pressed: - Mounts the FLASH memory partitions at the root - Searches for *.mcy files and optionally creates a romdisk - Mounts the SD card partitions at the root - Searches for *.mcy files and optionally creates a romdisk Finally: - Launches the "boot.mcy" program. #Case Use 3D Slash to modelize and 3d print your case. [](html) [Open model >>](https://www.3dslash.net/slash.php?alias=19081e4bb767c9eae4da743a1587be401a94f1a07c4667e350f1aff51cb75517)