PicoMite User Manual
PicoMite User Manual
User Manual
MMBasic Ver 5.07.07
Revision 2
Support
Support questions should be raised on the Back Shed forum ( http://www.thebackshed.com/forum/Microcontrollers )
where there are many enthusiastic MMBasic users who would be only too happy to help. The developers of the
PicoMite firmware are also regulars on this forum.
The compiled object code (the .uf2 file) for the PicoMite is free software: you can use or redistribute it as you
please. The source code is available from GitHub ( https://github.com/UKTailwind/PicoMite ) and can be
freely used subject to some conditions (see the header on the source files).
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
The author of this manual is Geoff Graham with input by Peter Mather, Harm de Leeuw, Mick Ames and
many others on The Back Shed forum. It is distributed under a Creative Commons Attribution-
NonCommercial-ShareAlike 3.0 Australia license (CC BY-NC-SA 3.0)
Introduction............................................................................................................................. 4
Getting Started ....................................................................................................................... 5
Quick Start Tutorial ................................................................................................................. 8
PicoMite Hardware ................................................................................................................. 9
Using MMBasic..................................................................................................................... 11
Full Screen Editor ................................................................................................................. 15
Program and Data Storage................................................................................................... 17
Variables and Expressions ................................................................................................... 24
Subroutines and Functions ................................................................................................... 29
Using the I/O pins ................................................................................................................. 32
Sound Output ....................................................................................................................... 36
Special Device Support ........................................................................................................ 39
Display Panels ...................................................................................................................... 46
Touch Support ...................................................................................................................... 53
Graphics Commands and Functions .................................................................................... 55
PicoMite Advanced Graphics ............................................................................................... 60
Advanced Graphics Programming Techniques .................................................................... 68
MMBasic Characteristics ...................................................................................................... 74
Predefined Read Only Variables .......................................................................................... 76
Options ................................................................................................................................. 79
Commands ........................................................................................................................... 85
Functions ............................................................................................................................ 131
Obsolete Commands and Functions .................................................................................. 145
Appendix A – Serial Communications ................................................................................ 146
Appendix B – I2C Communications .................................................................................... 148
Appendix C – 1-Wire Communications ............................................................................... 151
Appendix D – SPI Communications.................................................................................... 152
Appendix E – The PIO Programming Package .................................................................. 154
Appendix F – Programming in BASIC - A Tutorial .............................................................. 163
The emphasis with MMBasic is on ease of use and development. The development cycle is very fast with the
ability to instantly switch from edit to run. Errors are listed in plain English and when an error does occur a
single keystroke will invoke the built in editor with the cursor positioned on the line that caused the error. In
summary the features of the PicoMite are:
The BASIC interpreter is full featured with floating point, 64-bit integers and string variables, long
variable names, arrays of floats, integers or strings with multiple dimensions, extensive string handling
and user defined subroutines and functions. Typically it will execute a program up to 100,000 lines per
second. MMBasic allows the embedding of compiled C programs for high performance functions and
the running program can be protected from being listed or modified by a PIN number.
Support for all Raspberry Pi Pico input/output pins. These can be independently configured as
digital input or output, analog input, frequency or period measurement and counting. Within MMBasic
the I/O pins can be dynamically configured as inputs or outputs. MMBasic commands will generate
pulses and can be used to transfer data in parallel. Interrupts can be used to notify when an input pin has
changed state. PWM outputs can be used to create various sounds, control servos or generate computer
controlled voltages for driving equipment that uses an analogue input (e.g. motor controllers). In
addition, pins that are not exposed on the Raspberry Pi Pico can be accessed using MMBasic allowing it
to be used on other modules that use the RP2040 processor.
Support for TFT LCD display panels using parallel, SPI and I2C interfaces allowing the BASIC
program to display text and draw lines, circles, boxes, etc in up to 16 million colours. Resistive touch
controllers on these panels are also supported allowing them to be used as sophisticated input devices.
LCD panels can cost as little as US$7 and provide a low cost, high tech graphical user interface. For
higher speed and greater resolution SSD1963 based TFT screens are also supported.
Flexible program and data storage. Programs and data can be read/written from an internal file system
(size 688KB) or to an externally connected SD Card up to 32GB formatted as FAT16 or FAT32. This
includes opening files for reading, writing or random access and loading and saving programs. The SD
Card can also be read/written on personal computers running Windows, Linux or the Mac operating system.
Programming and control is done via the USB interface. All that is needed is a laptop/desktop
computer running a VT100 terminal emulator. Once the program has been written and debugged the
PicoMite can be instructed to automatically run the program on power up with no user intervention.
A full screen editor is built into the PicoMite and can edit the whole program in one session. It includes
advanced features such as colour coded syntax, search and copy, cut and paste to and from a clipboard.
Programs can be easily transferred from a desktop or laptop computer (Windows, Mac or Linux) using
the XModem protocol or by streaming the program over the serial console input.
A comprehensive range of communications protocols are implemented including I2C, asynchronous
serial, RS232, SPI and 1-Wire. These can be used to communicate with many sensors (temperature,
humidity, acceleration, etc) as well as for sending data to test equipment.
The PicoMite has built in commands to directly interface with infrared remote controls, the DS18B20
temperature sensor, LCD display modules, battery backed clock, numeric keypads and more.
Power requirements are 2.0 to 5.5 volts at 10 to 42 mA.
Terminal Emulator
You also need a terminal emulator program on your desktop computer. This program acts like an old fashioned
computer terminal where it will display text received from a remote computer and any key presses will be sent
to the remote computer over the serial link. The terminal emulator that you use should support VT100
emulation as that is what the editor built into the PicoMite expects.
For Windows users it is recommended that you use Tera Term as this has a good VT100 emulator and is known
to work with the XModem protocol which you can use to transfer
programs to and from the PicoMite (Tera Term can be downloaded from:
http://tera-term.en.lo4d.com ).
The screen shot on the right shows the setup for Tera Term. Note that the
"Port:" setting will vary depending on which USB port your Raspberry Pi
Pico was plugged into. The PicoMite ignores the baud rate setting so it can
be set to any speed (other than 1200 baud which puts the Pico into
firmware upgrade mode).
If you are using Tera Term do not set a delay between characters and if
you are using Putty set the backspace key to generate the backspace
character.
Some Tests
Here are a few things that you can try out to prove that you have a working PicoMite.
All of these commands should be typed at the command prompt (">"). What you type is shown in bold and the
PicoMite’s output is shown in normal text.
What is the current time? Note that the PicoMite's clock starts at midnight on power up.
> PRINT TIME$
00:04:01
Count to 20:
> FOR a = 1 to 20 : PRINT a; : NEXT a
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Apple Macintosh
The Apple Macintosh (OS X) is somewhat easier as it has the device driver and terminal emulator built in.
First start the application ‘Terminal’ and at the prompt list the connected serial devices by typing in:
ls /dev/tty.*.
The USB to serial converter will be listed as something like /dev/tty.usbmodem12345. While still at the
Terminal prompt you can run the terminal emulator at 38400 baud by using the command:
screen /dev/tty.usbmodem12345 38400
By default the function keys will not be correctly defined for use in the PicoMite's built in program editor so
you will have to use the control sequences as defined in the section Full Screen Editor of this manual. To avoid
this you can reconfigure the terminal emulator to generate these codes when the appropriate function keys are
pressed.
Documentation for the screen command is here: https://www.systutorials.com/docs/linux/man/1-screen/
Linux
For Linux see these posts:
https://www.thebackshed.com/forum/ViewTopic.php?TID=14157&PID=175474#175474#175466
A Simple Program
To enter a program, you can use the EDIT command which is described later in this manual. However, for the
moment, all that you need to know is that anything that you type will be inserted at the cursor, the arrow keys
will move the cursor and backspace will delete the character before the cursor.
To get a quick feel for how the PicoMite works, try this sequence (your terminal emulator must be VT100
compatible):
At the command prompt type EDIT followed by the ENTER key.
The editor should start up and you can enter this line: PRINT "Hello World"
Press the F1 key in your terminal emulator (or CTRL-Q which will do the same thing). This tells the
editor to save your program and exit to the command prompt.
At the command prompt type RUN followed by the ENTER key.
You should see the message: Hello World
Congratulations. You have just written and run your first program on the PicoMite. If you type EDIT again
you will be back in the editor where you can change or add to your program.
Flashing a LED
Connect a LED to pin GP21 (marked on the underside of the board)
and a ground pin as shown in the diagram on the right.
Then use the EDIT command to enter the following program:
SETPIN GP21, DOUT GP21
DO
PIN(GP21) = 1 470 ohms LED
PAUSE 300 GND
PIN(GP21) = 0
PAUSE 300
LOOP
When you have saved and run this program you should be greeted by the LED flashing on and off. It is not a
great program but it does illustrate how the PicoMite can interface to the physical world via your programming.
The program itself is simple. The first line sets pin GP21 as an output. Then the program enters a continuous
loop where the output of that pin is set high to turn on the LED followed by a short pause (300 milliseconds).
The output is then set to low followed by another pause. The program then repeats the loop.
If you leave it this way, the PicoMite will sit there forever with the LED flashing. If you want to change
something (for example, the speed of flashing) you can interrupt the program by typing CTRL-C on the console
and then edit it as needed. This is the great benefit of MMBasic, it is very easy to write and change a program.
If you want this program to automatically start running every time power is applied you can use the command:
OPTION AUTORUN ON
To test this you can remove the power and then re-apply it. The PicoMite should start up flashing the LED.
Power Supply
The Raspberry Pi Pico has a flexible power
VBUS VSYS 3V3EN 3V3
system.
The input voltage from either the USB or VBUS
inputs is connected through a Schottky diode to the 100K
buck-boost SMPS (Switch Mode Power Supply)
which has an output of 3.3V. The SMPS will
accommodate input voltages from 1.8V to 5.5V BUCK-BOOST RP2040
USB
allowing the PicoMite to run from a wide range of SMPS & Flash
Input
power sources including batteries.
External circuitry can be powered by VBUS
(normally 5V) or by the 3V3 (3.3V) output which
can source up to 300mA.
For embedded controller applications generally an external power source (other than USB) is required and this
can be connected to VSYS via a Schottky diode. This will allow the PicoMite to be powered by whichever
supply is producing the highest voltage (USB or VSYS). The diodes will prevent feedback into the lower
voltage supply.
To minimize power supply noise it is possible to ground 3V3EN to turn off the SMPS. When shutdown the
converter will stop switching, internal control circuitry will be turned off and the load disconnected. You can
then power the board via a 3.3V linear regulator feeding into the 3V3 pin.
Clock Speed
By default the clock speed for the PicoMite is 133MHz which is the recommended maximum for the Raspberry
Pi Pico. However, by using the OPTION CPUSPEED command, the CPU can be overclocked up to 378MHz
or run slower to a minimum of 48MHz. Nearly all tested Raspberry Pi Picos have worked correctly at 378MHz
so overclocking can be useful. If the processor fails to restart at its new clock speed you can reset it by loading
this firmware file onto the Pico: https://geoffg.net/Downloads/picomite/Clear_Flash.uf2. The procedure to do
this is same as loading any other firmware.
This option is saved and will be reapplied on power up. When changing the clock speed the PicoMite will be
reset then rebooted so the USB connection will be disconnected.
Power Consumption
The power consumption is dependent on the clock speed. These are typical readings for the PicoMite and do
not include any current sourced or sunk by the I/O pins or the 3V3 pin:
250MHz 43mA
133MHz 21mA
48MHz 10mA.
Program Structure
A BASIC program starts at the first line and continues until it runs off the end of the program or hits an END
command - at which point MMBasic will display the command prompt (>) on the console and wait for
something to be entered.
A program consists of a number of statements or commands, each of which will cause the BASIC interpreter to
do something (the words statement and command generally mean the same and are used interchangeably).
Normally each statement is on its own line but you can have multiple statements in the one line separated by
the colon character (:). For example.
A = 24.6 : PRINT A
Each line can start with a line number. Line numbers were mandatory in the early BASIC interpreters however
modern implementations (such as MMBasic) do not need them. You can still use them if you wish but they
have no benefit and generally just clutter up your programs. This is an example of a program that uses line
numbers:
50 A = 24.6
60 PRINT A
A line can also start with a label which can be used as the target for a program jump using the GOTO
command. For example (the label name is JmpBack):
JmpBack: A = A + 1
PRINT A
GOTO JmpBack
A label has the same specifications (length, character set, etc) as a variable name but it cannot be the
same as a command name. When used to label a line the label must appear at the beginning of a line
but after a line number (if used) and be terminated with a colon character (:).
Editing the Command Line
When entering a line at the command prompt the line can be edited using the left and right arrow keys to move
along the line, the Delete key to delete a character and the Insert key to switch between insert and overwrite.
At any point the Enter key will send the line to MMBasic which will execute it.
The up and down arrow keys will move through a history of previously entered command lines which can be
edited and reused.
Function keys F1, and F5 to F9 can be programmed with custom text. See the OPTION FNKey command.
Setting Options
Many options can be set by using commands that start with the keyword OPTION. They are listed in their own
section of this manual. For example, you can change the CPU clock speed with the command:
OPTION CPUSPEED speed
Saved Variables
Because the PicoMite does not necessarily have a normal storage system it needs to save data that can be
recovered when power is restored. This can be done with the VAR SAVE command which will save the
variables listed on its command line in non-volatile flash memory. The space reserved for saved variables is
16KB.
These variables can be restored with the VAR RESTORE command which will add all the saved variables to
the variable table of the running program. Normally this command is placed near the start of a program so that
the variables are ready for use by the program.
This facility is intended for saving calibration data, user selected options and other items which change
infrequently. It should not be used for high speed saves as you may wear out the flash memory. The flash used
for the Raspberry Pi Pico has a high endurance but this can be exceeded by a program that repeatedly saves
variables. If you do want to save data often you should add a real time clock chip. The RTC commands can
then be used to store and retrieve data from the RTC's battery backed memory. See the RTC command for
more details.
Watchdog Timer
The main use for the PicoMite is as an embedded controller. It can be programmed in MMBasic and when the
program is debugged and ready for "prime time" the OPTION AUTORUN configuration setting can be turned
on. The module will then automatically run its program when power is applied and act as a custom circuit
performing some special task. The user need not know anything about what is running inside it.
However, there is the possibility that a fault in the program could cause MMBasic to generate an error and
return to the command prompt. This would be of little use in an embedded situation as the PicoMite would not
have anything connected to the console. Another possibility is that the BASIC program could get itself stuck in
an endless loop for some reason. In both cases the visible effect would be the same… the program would stop
running until the power was cycled.
To guard against this the watchdog timer can be used. This is a timer that counts down to zero and when it
reaches zero the processor will be automatically restarted (the same as when power was first applied), this will
occur even if MMBasic was sitting at the command prompt. Following the restart the automatic variable
MM.WATCHDOG will be set to true to indicate that the restart was caused by a watchdog timeout.
The WATCHDOG command should be placed in strategic locations in the program to keep resetting the timer
and therefore preventing it from counting down to zero. Then, if a fault occurs, the timer will not be reset, it
will count down to zero and the program will be restarted (assuming the AUTORUN option is set).
The Library
Using the LIBRARY feature it is possible to create BASIC functions, subroutines and embedded fonts and add
them to MMBasic to make them permanent and part of the language. For example, you might have written a
series of subroutines and functions that perform sophisticated bit manipulation; these could be stored as a
library and become part of MMBasic and perform the same as other built in functions that are already part of
the language. An embedded font can also be added the same way and used just like a normal font.
To install components into the library you need to write and test the routines as you would with any normal
BASIC routines. When they are working correctly you can use the LIBRARY SAVE command. This will
transfer the routines (as many as you like) to a non visible part of flash memory where they will be available to
any BASIC program but will not show when the LIST command is used and will not be deleted when a new
program is loaded or NEW is used. However, the saved subroutines and functions can be called from within
the main program and can even be run at the command prompt (just like a built in command or function).
Some points to note:
Library routines act exactly like normal BASIC code and can consist of any number of subroutines,
functions, embedded C routines and fonts. The only difference is that they do not show when a program
is listed and are not deleted when a new program is loaded.
Library routines can create and access global variables and are subject to the same rules as the main
program – for example, respecting OPTION EXPLICIT if it is set.
When the routines are transferred to the library MMBasic will compress them by removing comments,
extra spaces, blank lines and the hex codes in embedded C routines and fonts. This makes the library
space efficient, especially when loading large fonts. Following the save the program area is cleared.
You can use the LIBRARY SAVE command multiple times. With each save the new contents of the
program space are appended to the already existing code in the library.
You can use line numbers in the library but you cannot use a line number on an otherwise empty line as
the target for a GOTO, etc. This is because the LIBRARY SAVE command will remove any blank lines.
You can use READ commands in the library but they will default to reading DATA statements in the
main program memory. If you want to read from DATA statements in the library you must use the
RESTORE command before the first READ command. This will reset the pointer to the library space.
The library is saved to program flash memory Slot 4 and this will not be available for storing a program if
LIBRARY SAVE is used.
You can see what is in the library by using the LIBRARY LIST command which will list the contents of
the library space.
To delete the routines in the library space you use the LIBRARY DELETE command. This will clear the space
and return the Flash Slot 4 used by the library back to being available for storage for normal programs. The
only other way to delete a library is to use OPTION RESET.
Program Initialisation
The library can also include code that is not contained within a subroutine or function. This code (if it exists)
will be run automatically before a program starts running (ie, via the RUN command). This feature can be used
MM.STARTUP
There may be a need to execute some code on initial power up, perhaps to initialise some hardware, set some
options or print a custom start-up banner. This can be accomplished by creating a subroutine with the name
MM.STARTUP. When the PicoMite is first powered up or reset it will search for this subroutine and, if found,
it will be run once.
For example, if the PicoMite has a real time clock attached, the program could contain the following code:
SUB MM.STARTUP
RTC GETTIME
END SUB
This would cause the internal clock within MMBasic to be set to the current time on every power up or reset.
After the code in MM.STARTUP has been run MMBasic will continue with running the rest of the program in
program memory. If there is no other code MMBasic will return to the command prompt.
Note that you should not use MM.STARTUP for general setup of MMBasic (like dimensioning arrays, opening
communication channels, etc) before running a program. The reason is that when you use the RUN command
MMBasic will clear the interpreter's state ready for a fresh start.
MM.PROMPT
If a subroutine with this name exists it will be automatically executed by MMBasic instead of displaying the
command prompt. This can be used to display a custom prompt, set colours, define variables, etc all of which
will be active at the command prompt.
Note that MMBasic will clear all variables and I/O pin settings when a program is run so anything set in this
subroutine will only be valid for commands typed at the command prompt (i.e. in immediate mode).
As an example the following will display a custom prompt:
SUB MM.PROMPT
PRINT TIME$ "> ";
END SUB
Note that while constants can be defined they will not be visible because a constant defined inside a subroutine
is local to a subroutine. However, DIM will create variables that are global that that should be used instead.
When the editor starts up the cursor will be automatically positioned at the last place that you were editing or, if
your program had just been stopped by an error, the cursor will be positioned at the line that caused the error.
At the bottom of the screen the status line lists details such as the current cursor position and the common
functions supported by the editor.
If you have previously used an editor like Windows Notepad you will find that the operation of this editor is
familiar. The arrow keys will move the cursor around in the text, home and end will take you to the beginning
or end of the line. Page up and page down will do what their titles suggest. The delete key will delete the
character at the cursor and backspace will delete the character before the cursor. The insert key will toggle
between insert and overtype modes. About the only unusual key combination is that two home key presses will
take you to the start of the program and two end key presses will take you to the end.
At the bottom of the screen the status line will list the various function keys used by the editor and their action.
In more details these are:
ESC This will cause the editor to abandon all changes and return to the command prompt with the
program memory unchanged. If you have changed the text you will be asked if you really what
want to abandon your changes.
F1: SAVE This will save the program to program memory and return to the command prompt.
F2: RUN This will save the program to program memory and immediately run it.
F3: FIND This will prompt for the text that you want to search for. When you press enter the cursor will
be placed at the start of the first entry found.
SHIFT-F3 Once you have used the search function you can repeat the search by pressing SHIFT-F3.
F4: MARK This is described in detail below.
F5: PASTE This will insert (at the current cursor position) the text that had been previously cut or copied
(see below).
If you pressed the mark key (F4) the editor will change to the mark mode. In this mode you can use the arrow
keys to mark a section of text which will be highlighted in reverse video. You can then delete, cut or copy the
marked text. In this mode the status line will change to show the functions of the function keys in the mark
mode. These keys are:
ESC Will exit mark mode without changing anything.
F4: CUT Will copy the marked text to the clipboard and remove it from the program.
F5: COPY Will just copy the marked text to the clipboard.
DELETE Will delete the marked text leaving the clipboard unchanged.
Flash Slots
There are four of these which can be used to save completely different programs or previous versions of the
program you are working on (in case you need to revert to an earlier version). In addition MMBasic will allow
a BASIC program to load and run another program saved to a numbered flash location while retaining all the
variables and settings of the original program – this is called chaining and allows for a much larger program to
be run than the amount of program memory would normally allow.
To manage these numbered locations in flash you can use the following commands (note that in the following n
is a number from 1 to 4):
FLASH SAVE n Save the program in the program memory to the flash location n.
FLASH LOAD n Load a program from flash location n into the program memory.
FLASH RUN n Run a program from flash location n, clears all variables but does not erase
or change the program held in the main program memory.
FLASH LIST Display a list of all flash locations including the first line of the program.
FLASH LIST n [,all] Lists the program held in location n. Use FLASH LIST n,ALL to list
without page breaks
FLASH ERASE n Erase flash location n.
FLASH ERASE ALL Erase all flash locations.
FLASH CHAIN n Load and run a program from flash location n, leaving all variables intact.
As with FLASH RUN this command but does not erase or change the
program held in the main program memory.
FLASH OVERWRITE n Erase flash location n and then save the program in the program memory to
that location.
In addition the command OPTION AUTORUN can be used to specify a flash program location to be set
running when power is applied or the CPU restarted. This option can also used without specifying a flash
location and in that case MMBasic will automatically load and run the program that is in the program memory.
Notes:
It is highly recommended that you include a comment describing the program as the first line of the
program. This will then be displayed by the FLASH LIST command and will help identify the program.
All BASIC programs saved to flash may be erased if you upgrade (or downgrade) the WebMite firmware.
So make sure that you backup these first.
The LIBRARY command uses Slot 4 for saving library data therefor only 3 slots will be available if the
library feature is used.
Flash Filesystem
This is an area of the Raspberry Pi Pico’s flash memory which is automatically created by the firmware and
will look like a normal disk drive to MMBasic. It is called drive A: and data and programs can be read/written
using the normal BASIC file commands (SAVE, RUN, OPEN, etc). In addition sub directories can be created
and deleted and long filenames used.
For example, to run a program:
RUN "A:/MyProgram.bas"
Open a text file for random access:
OPEN "A:/data/database.dat" FOR RANDOM as #4
Nothing needs to be done to create this drive so it will always be available to the BASIC program.
SD Cards
An SD Card socket can be connected to the PicoMite and accessed as drive B:. Like the Flash Filesystem the
normal BASIC file commands can be used to save/load programs as well as opening data files for read/write.
Cards up to 32 GB formatted in FAT16 or FAT32 are supported and the files created can also be read/written
on personal computers running Windows, Linux or the Mac operating system. The PicoMite uses the SPI
protocol to talk to the card and this is not influenced by the card type, so all types (Class 4, 10, UHS-1 etc) are
supported
The SPI protocol needs to be specifically configured before it can be used. First the “system” SPI port needs to
be configured. This is a port that will be used for system use (SD Card, LCD display and the touch controller
on an LCD panel).
There are a number of ports and pins that can be used (see the section PicoMite Hardware) but this example
uses SPI on pins GP18, GP19 and GP16 for Clock, MOSI and MISO.
OPTION SYSTEM SPI GP18, GP19, GP16
Then MMBasic must be told that there is an SD Card attached and what pin is used for the Chip Select signal:
OPTION SDCARD GP22
These commands must be entered at the command prompt (not in a program) and will cause the PicoMite to
restart. This has the side effect of disconnecting the USB console interface which will need to be reconnected.
When the PicoMite is restarted MMBasic will automatically initialise the SD Card interface. This SPI port will
then not be available to BASIC programs (i.e. it is reserved). To verify the configuration you can use the
command OPTION LIST to list all options that have been set including the configuration of the SD Card.
The basic circuit diagram for connecting the SD Card connector using these pin allocations is illustrated below.
PicoMite
GP22
GP19
GP18
GP16
Note that you can use many different configurations using various pin allocations – this is just an example
based on the configuration commands listed above.
Care must be taken when the SPI port is shared between a number of devices (SD Card, touch, etc). In this case all
the Chip Select signals must configured in MMBasic or alternatively disabled by a permanent connection to 3.3V.
If this is not done any floating Chip Select signal lines will cause the wrong controller to respond to commands on
the SPI bus.
Where no other devices share the SPI bus the SD Card can be set up with:
OPTION SDCARD CSpin, CLKpin, MOSIpin, MISOpin
In this case the pins can be assigned completely flexibly and do not need to be capable of SPI operation.
FILES [wildcard]
Search the current directory and list the files/directories found. Note: Can only be used at the command
prompt, not within a program.
LIST fname$
List the contents of a program or text file on the console.
XModem Transfer
In addition to the standard method of XModem transfer which copies to or from the program memory the
PicoMite can also copy to and from a file on the Flash Filesystem or SD Card. The syntax is:
XMODEM SEND filename$
or
XMODEM RECEIVE filename$
Where ‘filename$’ is the image to load and ‘StartX’/’StartY’ are the coordinates of the top left corner of the
image (these are optional and will default to the top left corner of the display if not specified).
The image must be in the BMP format (for LOAD IMAGE) or JPG format (for LOAD JPG) and MMBasic will
add “.BMP” or “.JPG” to the file name if an extension is not specified. All types of the BMP or JPG formats
are supported including black and white and true colour 24-bit images.
The current image on a ILI9341 based LCD screen can be saved to a file using the following command:
SAVE IMAGE filename$ [,StartX, StartY, width, height]
This will save the image, or part of the image, as a 24-bit true colour BMP file (the extension .BMP) will be
added if an extension is not supplied.
You can read the contents of the file using the LINE INPUT command. For example:
OPEN "fox.txt" FOR INPUT AS #1
LINE INPUT #1,a$
LINE INPUT #1,b$
CLOSE #1
LINE INPUT reads one line at a time so the variable a$ will contain the text "The quick brown fox" and b$
will contain "jumps over the lazy dog".
Another way of reading from a file is to use the INPUT$() function. This will read a specified number of
characters. For example:
OPEN "fox.txt" FOR INPUT AS #1
ta$ = INPUT$(12, #1)
tb$ = INPUT$(3, #1)
CLOSE #1
The first INPUT$() will read 12 characters and the second three characters. So the variable ta$ will contain
"The quick br" and the variable tb$ will contain "own".
Files normally contain just text and the print command will convert numbers to text. So in the following
example the first line will contain the line "123" and the second "56789".
nbr1 = 123 : nbr2 = 56789
OPEN "numbers.txt" FOR OUTPUT AS #1
PRINT #1, nbr1
PRINT #1, nbr2
Again you can read the contents of the file using the LINE INPUT command but then you would need to
convert the text to a number using VAL().
For example:
OPEN "numbers.txt" FOR INPUT AS #1
LINE INPUT #1, a$
LINE INPUT #1, b$
CLOSE #1
x = VAL(a$) : y = VAL(b$)
Following this the variable x would have the value 123 and y the value 56789.
To seek to a record within the file you would use the SEEK command which will position the read/write
pointer to a specific byte. The first byte in a file is numbered one so, for example, the fifth record in a file that
uses 64 byte records would start at byte 257. In that case you would use the following to point to it:
SEEK #1, 257
When reading from a random access file the INPUT$() function should be used as this will read a fixed number
of bytes (i.e. a complete record) from the file. For example, to read a record of 64 bytes you would use:
dat$ = INPUT$(64, #1)
When writing to the file a fixed record size should be used and this can be easily accomplished by adding
sufficient padding characters (normally spaces) to the data to be written. For example:
PRINT #1, dat$ + SPACE$(64 – LEN(dat$);
The SPACE$() function is used to add enough spaces to ensure that the data written is an exact length (64 bytes
in this example). The semicolon at the end of the print command suppresses the addition of the carriage return
and line feed characters which would make the record longer than intended.
Two other functions can help when using random file access. The LOC() function will return the current byte
position of the read/write pointer and the LOF() function will return the total length of the file in bytes.
The following program demonstrates random file access. Using it you can append to the file (to add some data
in the first place) then read/write records using random record numbers. The first record in the file is record
number 1, the second is 2, etc.
RecLen = 64
OPEN "test.dat" FOR RANDOM AS #1
DO
abort: PRINT
PRINT "Number of records in the file =" LOF(#1)/RecLen
INPUT "Command (r = read, w = write, a = append, q = quit): ", cmd$
IF cmd$ = "q" THEN CLOSE #1 : END
IF cmd$ = "a" THEN
SEEK #1, LOF(#1) + 1
ELSE
INPUT "Record Number: ", nbr
IF nbr < 1 or nbr > LOF(#1)/RecLen THEN PRINT "Invalid record" : GOTO abort
SEEK #1, RecLen * (nbr - 1) + 1
ENDIF
IF cmd$ = "r" THEN
PRINT "The record = " INPUT$(RecLen, #1)
ELSE
LINE INPUT "Enter the data to be written: ", dat$
PRINT #1,dat$ + SPACE$(RecLen - LEN(dat$));
Random access can also be used on a normal text file. For example, this will print out a file backwards:
OPEN "file.txt" FOR RANDOM AS #1
FOR i = LOF(#1) TO 1 STEP -1
SEEK #1, i
PRINT INPUT$(1, #1);
NEXT i
CLOSE #1
Variables
Variables can start with an alphabetic character or underscore and can contain any alphabetic or numeric
character, the period (.) and the underscore (_). They may be up to 31 characters long.
A variable name or a label must not be the same as a function or one of the following keywords: THEN, ELSE,
GOTO, GOSUB, TO, STEP, FOR, WHILE, UNTIL, LOAD, MOD, NOT, AND, OR, XOR, AS.
E.g. step = 5 is illegal as STEP is a keyword.
MMBasic supports three types of variables:
1. Double Precision Floating Point.
These can store a number with a decimal point and fraction (e.g. 45.386) however they will lose accuracy
when more than 14 digits of precision are used. Floating point variables are specified by adding the
suffix '!' to a variable's name (e.g. i!, nbr!, etc). They are also the default when a variable is created
without a suffix (e.g. i, nbr, etc).
2. 64-bit Signed Integer.
These can store positive or negative numbers with up to 19 decimal digits without losing accuracy but
they cannot store fractions (i.e. the part following the decimal point). These are specified by adding the
suffix '%' to a variable's name. For example, i%, nbr%, etc.
3. A String.
A string will store a sequence of characters (e.g. "Tom"). Each character in the string is stored as an
eight bit number and can therefore have a decimal value of 0 to 255. String variable names are
terminated with a '$' symbol (e.g. name$, s$, etc). Strings can be up to 255 characters long.
Note that it is illegal to use the same variable name with different types. E.g. using nbr! and nbr% in the
same program would cause an error.
Most programs use floating point variables for arithmetic as these can deal with the numbers used in typical
situations and are more intuitive than integers when dealing with division and fractions. So, if you are not
bothered with the details, always use floating point.
Constants
Numeric constants may begin with a numeric digit (0-9) for a decimal constant, &H for a hexadecimal
constant, &O for an octal constant or &B for a binary constant. For example &B1000 is the same as the
decimal constant 8. Constants that start with &H, &O or &B are always treated as 64-bit unsigned integer
constants.
Decimal constants may be preceded with a minus (-) or plus (+) and may be terminated with 'E' followed by an
exponent number to denote exponential notation. For example 1.6E+4 is the same as 16000.
When a constant number is used it will be assumed that it is an integer if a decimal point or exponent is not
used. For example, 1234 will be interpreted as an integer while 1234.0 will be interpreted as a floating point
number.
String constants must be surrounded by double quote marks ("). E.g. "Hello World".
OPTION DEFAULT
A variable can be used without a suffix (i.e. !, % or $) and in that case MMBasic will use the default type of
floating point. For example, the following will create a floating point variable:
Nbr = 1234
However. the default can be changed with the OPTION DEFAULT command. For example, OPTION
DEFAULT INTEGER will specify that all variables without a specific type will be integer. So, the following
will create an integer variable:
OPTION DEFAULT INTEGER
Nbr = 1234
OPTION EXPLICIT
By default MMBasic will automatically create a variable when it is first referenced. So, Nbr = 1234 will
create the variable and set it to the number 1234 at the same time. This is convenient for short and quick
programs but it can lead to subtle and difficult to find bugs in large programs. For example, in the third line of
this fragment the variable Nbr has been misspelt as Nbrs. As a consequence the variable Nbrs would be
created with a value of zero and the value of Total would be wrong.
Nbr = 1234
Incr = 2
Total = Nbrs + Incr
The OPTION EXPLICIT command tells MMBasic to not automatically create variables. Instead they must be
explicitly defined using the DIM, LOCAL or STATIC commands (see below) before they are used. The use of
this command is recommended to support good programming practice. If it is used it should be placed at the
start of the program before any variables are used.
STATIC
Inside a subroutine or function it is sometimes useful to create a variable which is only visible within the
subroutine or function (like a LOCAL variable) but retains its value between calls to the subroutine or function.
You can do this by using the STATIC command. STATIC can only be used inside a subroutine or function and
uses the same syntax as LOCAL and DIM. The difference is that its value will be retained between calls to the
subroutine or function (i.e. it will not be initialised on the second and subsequent calls).
For example, if you had the following subroutine and repeatedly called it, the first call would print 5, the
second 6, the third 7 and so on.
SUB Foo
STATIC var = 5
PRINT var
var = var + 1
END SUB
Note that the initialisation of the static variable to 5 (as in the above example) will only take effect on the first
call to the subroutine. On subsequent calls the initialisation will be ignored as the variable had already been
created on the first call.
As with DIM and LOCAL the variables created with STATIC can be float, integers or strings and arrays of
these with or without initialisation. The length of the variable name created by STATIC and the length of the
subroutine or function name added together cannot exceed 31 characters.
CONST
Often it is useful to define an identifier that represents a value without the risk of the value being accidently
changed - which can happen if variables were used for this purpose (this practice encourages another class of
difficult to find bugs).
Using the CONST command you can create an identifier that acts like a variable but is set to a value that cannot
be changed. For example:
CONST InputVoltagePin = 31
CONST MaxValue = 2.4
The identifiers can then be used in a program where they make more sense to the casual reader than simple
numbers. For example:
IF PIN(InputVoltagePin) > MaxValue THEN SoundAlarm
A number of constants can be created on the one line:
CONST InputVoltagePin = 31, MaxValue = 2.4, MinValue = 1.5
The value used to initialise the constant is evaluated when the constant is created and can be an expression
including user defined functions.
The type of the constant is derived from the value assigned to it; so for example, MaxValue above will be a
floating point constant because 2.4 is a floating point number. The type of a constant can also be explicitly set
by using a type suffix (i.e. !, % or $) but it must agree with its assigned value.
Arithmetic operators:
^ Exponentiation (e.g. b^n means bn)
* / \ MOD Multiplication, division, integer division and modulus (remainder)
+ - 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. For a right shift any bits introduced are set
to the value of the top bit (bit 63). For a left shift any bits introduced
are set to zero.
Logical operators:
NOT INV invert the logical value on the right (e.g. NOT a=b is a<>b)
or bitwise inversion of the value on the right (e.g. a = INV b)
<> < > <= =< Inequality, less than, greater than, less than or equal to, less than or
>= => equal to (alternative version), greater than or equal to, greater than or
equal to (alternative version)
= equality
AND OR XOR Conjunction, disjunction, exclusive or
For Microsoft compatibility the operators AND, OR and XOR are integer bitwise operators. For example,
PRINT (3 AND 6) will output the number 2. Because these operators can act as both logical operators (for
example, IF a=5 AND b=8 THEN …) and as bitwise operators (e.g. y% = x% AND &B1010) the interpreter
will be confused if they are mixed in the same expression. So, always evaluate logical and bitwise expressions
in separate expressions.
String operators:
+ Join two strings
<> < > <= =< Inequality, less than, greater than, less than or equal to, less than or
>= => equal to (alternative version), greater than or equal to, greater than or
equal to (alternative version)
= Equality
String comparisons respect case. For example "A" is greater than "a".
Subroutines
A subroutine acts like a command and it can have arguments (sometimes called a parameter list). In the
definition of the subroutine they look like this:
SUB MYSUB arg1, arg2$, arg3
<statements>
<statements>
END SUB
And when you call the subroutine you can assign values to the arguments. For example:
MYSUB 23, "Cat", 55
Inside the subroutine arg1 will have the value 23, arg2$ the value of "Cat", and so on. The arguments act
like ordinary variables but they exist only within the subroutine and will vanish when the subroutine ends. You
can have variables with the same name in the main program and they will be hidden by the arguments defined
for the subroutine.
When calling a subroutine you can supply less than the required number of values and in that case the missing
values will be assumed to be either zero or an empty string. You can also leave out a value in the middle of the
list and the same will happen. For example:
MYSUB 23, , 55
Will result in arg2$ being set to the empty string "".
Rather than using the type suffix (e.g. the $ in arg2$) you can use the suffix AS <type> in the definition of the
subroutine argument and then the argument will be known as the specified type, even when the suffix is not
used. For example:
SUB MYSUB arg1, arg2 AS STRING, arg3
IF arg2 = "Cat" THEN …
END SUB
Inside a subroutine you can define a variable using LOCAL (which has the same syntax as DIM). This variable
will only exist within the subroutine and will vanish when the subroutine exits.
Functions
Functions are similar to subroutines with the main difference being that the function is used to return a value in
an expression. The rules for the argument list in a function are similar to subroutines. The only difference is
that brackets are required around the argument list when you are calling a function, even if there are no
arguments (they are optional when calling a subroutine).
To return a value from the function you assign a value to the function's name within the function. If the
function's name is terminated with a $, a % or a ! the function will return that type, otherwise it will return
whatever the OPTION DEFAULT is set to. You can also specify the type of the function by adding AS <type>
to the end of the function definition.
For example:
FUNCTION Fahrenheit(C) AS FLOAT
Fahrenheit = C * 1.8 + 32
END FUNCTION
Passing Arrays
Single elements of an array can be passed to a subroutine or function and they will be treated the same as a
normal variable. For example, this is a valid way of calling the Swap subroutine (discussed above):
Swap dat(i), dat(i + 1)
This type of construct is often used in sorting arrays.
You can also pass one or more complete arrays to a subroutine or function by specifying the array with empty
brackets instead of the normal dimensions. For example, a(). In the subroutine or function definition the
associated parameter must also be specified with empty brackets. The type (i.e., float, integer or string) of the
argument supplied and the parameter in the definition must be the same.
In the subroutine or function the array will inherit the dimensions of the array passed and these must be
respected when indexing into the array. If required the dimensions of the array could be passed as additional
arguments to the subroutine or function so it could correctly manipulate the array. The array is passed by
reference which means that any changes made to the array within the subroutine or function will also apply to
the supplied array.
For example, when the following is run the words "Hello World" will be printed out:
DIM MyStr$(5, 5)
MyStr$(4, 4) = "Hello" : MyStr$(4, 5) = "World"
Concat MyStr$()
PRINT MyStr$(0, 0)
SUB Concat arg$()
arg$(0,0) = arg$(4, 4) + " " + arg$(4, 5)
END SUB
Early Exit
There can be only one END SUB or END FUNCTION for each definition of a subroutine or function. To exit
early from a subroutine (i.e., before the END SUB command has been reached) you can use the EXIT SUB
command. This has the same effect as if the program reached the END SUB statement. Similarly you can use
EXIT FUNCTION to exit early from a function.
Recursion
Recursion is where a subroutine or function calls itself. You can do recursion in MMBasic but there are a
number of issues (these are a direct consequence of the limitations of microcontrollers and the BASIC
language):
There is a fixed limit to the depth of recursion. In the PicoMite this is 50 levels.
If you have many arguments to the subroutine or function and many LOCAL variables (especially strings)
you could easily run out of memory before reaching the 50 level limit.
Any FOR…NEXT loops and DO…LOOPs will be corrupted if the subroutine or function is recursively
called from within these loops.
Digital Inputs
A digital input is the simplest type of input configuration. If the input voltage is higher than 2.5V the logic
level will be true (numeric value of 1) and anything below 0.65V will be false (numeric value of 0). The inputs
use a Schmitt trigger input so anything in between these levels will retain the previous logic level. All pins are
limited to a maximum voltage of 3.6V. This means that resistor divider will be required if they are used with
input voltages greater than that.
In your BASIC program you would set the input as a digital input and use the PIN() function to get its level.
For example:
SETPIN GP4, DIN
IF PIN(GP4) = 1 THEN PRINT "High"
The SETPIN command configures pin GP4 as a digital input and the PIN() function will return the value of that
pin (the number 1 if the pin is high). The IF command will then execute the command after the THEN
statement if the input was high. If the input pin was low the program would just continue with the next line in
the program.
The SETPIN command also recognises a couple of options that will connect an internal resistor from the input
to either the supply or ground. This is called a "pullup" or "pulldown" resistor and is handy when connecting to
a switch as it saves having to install an external resistor to place a voltage across the contacts.
Analog Inputs
Pins marked as ADC can be configured to measure the voltage on the pin. The input range is from zero to 3.3V
and the PIN() function will return the voltage. For example:
> SETPIN 31, AIN
> PRINT PIN(31)
2.345
>
You will need a voltage divider if you want to measure voltages greater than 3.3V. For small voltages you may
need an amplifier to bring the input voltage into a reasonable range for measurement.
The measurement uses 3.3V power supply to the CPU as its reference and it is assumed that this is exactly
3.3V. This value can be changed with the OPTION command.
The ADC commands provide an alternate method of recording analog inputs and are intended for high speed
recording of many readings into an array.
Counting Inputs
Any four pins can be used as counting inputs to measure frequency, period or just count pulses on the input.
The pins used for this function can be configured using the OPTION COUNT command but, if not changed,
will default to GP6, GP7, GP8 and GP9.
As an example, the following will print the frequency of the signal on pin GP7:
> SETPIN GP7, FIN
> PRINT PIN(GP7)
110374
>
In this case the frequency is 110.374 kHz.
By default the gate time is one second which is the length of time that MMBasic will use to count the number
of cycles on the input and this means that the reading is updated once a second with a resolution of 1 Hz. By
specifying a third argument to the SETPIN command it is possible to specify an alternative gate time between
10 ms and 100000 ms. Shorter times will result in the readings being updated more frequently but the value
Digital Outputs
All I/O pins can be configured as a digital output using the DOUT parameter to the SETPIN command. For
example:
SETPIN GP15, DOUT
This means that when an output pin is set to logic low it will pull its output to zero and when set high it will
pull its output to 3.3V. In MMBasic this is done with the PIN command. For example PIN(GP15) = 0
will set pin GP15 to low while PIN(GP15) = 1 will set it high.
Interrupts
Interrupts are a handy way of dealing with an event that can occur at an unpredictable time. An example is
when the user presses a button. In your program you could insert code after each statement to check to see if
the button has been pressed but an interrupt makes for a cleaner and more readable program.
When an interrupt occurs MMBasic will execute a special subroutine and when finished return to the main
program. The main program is completely unaware of the interrupt and will carry on as normal.
Any I/O pin that can be used as a digital input can be configured to generate an interrupt using the SETPIN
command with up to ten interrupts active at any one time. Interrupts can be set up to occur on a rising or falling
digital input signal (or both) and will cause an immediate branch to the specified user defined subroutine. The
target can be the same or different for each interrupt. Return from an interrupt is via the END SUB or EXIT
SUB commands. Note that no parameters can be passed to the subroutine however within the interrupt calls to
other subroutines and functions are allowed.
The list of all these interrupts (in high to low priority ranking) is:
1. ON KEY individual
2. ON KEY general
3. PIO RX FIFO
4. PIO TX FIFO
5. PIO RX DMA completion
6. PIO TX DMA completion
7. GUI Int Down
8. GUI Int Up
9. ADC completion
10. I2C Slave Rx
11. I2C Slave Tx
12. I2C2 Slave Rx
13. I2C2 Slave Tx
14. WAV Finished
15. COM1: Serial Port
16. COM2: Serial Port
17. IR Receive
18. Keypad
19. Interrupt command/CSub Interrupt
20. I/O Pin Interrupts in order of definition
21. Tick Interrupts (1 to 4 in that order)
The audio output can also be generated through a connected MCP48n2 DAC (e.g. MCP4822) in which case it
is configured using the command
In this case there is no requirement for a complex low pass filter and a 120ohm resistor connected to the DAC
output and with the other end of the resistor connected to GND via a 100nF capacitor will be more than
adequate. When a MCP4822 is used the LDAC pin on the DAC should be connected to GND.
This circuit is suitable for general use; however more sophisticated designs can be used to improve the
frequency response and reject more of the carrier frequency.
Using PLAY
It is important to realise that the PLAY command will generate the audio in the background. This allows a
program (for example) to play the sound of a bell while continuing with its control function. Without the
background facility the whole BASIC program would freeze while the sound was heard.
However, generating the audio in the background has some subtle inferences which can trip up newcomers.
For example, take the following program:
PLAY TONE 500, 500, 2000
END
You may expect the 500Hz tone to sound for 2 seconds but in practice it will not make any sound at all. This is
because MMBasic will execute the PLAY TONE command (which will start generating the sound in the
background) and then it will immediately execute the END command which will terminate the program and the
background sound. This will happen so fast that nothing is heard.
Similarly the following program will not work either:
PLAY TONE 500, 500, 2000
PLAY TONE 300, 300, 5000
This is because the first command will set a 500Hz the tone playing but then the second PLAY command will
immediately replace that with a 300Hz tone and following that the program will run off the end terminating the
program (and the background audio), resulting in nothing being heard.
If you want MMBasic to wait while the PLAY command is doing its thing you should use suitable PAUSE
commands. For example:
PLAY TONE 500, 500
PAUSE 2000
PLAY TONE 300, 300
PAUSE 5000
PLAY STOP
This applies to all versions of the PLAY command including PLAY WAV.
Utility Commands
There are a number of commands that can be used to manage the sound output:
PLAY PAUSE Temporarily halt (pause) the currently playing file or tone.
PLAY RESUME Resume playing a file or tone that was previously paused.
Measuring Temperature
The TEMPR() function will get the temperature from a DS18B20
3.3V
temperature sensor. This device can be purchased on eBay for about $5
in a variety of packages including a waterproof probe version. 4.7K
LCD Display
The LCD command will display text on a standard LCD module with the
minimum of programming effort.
This command will work with LCD modules that use the KS0066,
HD44780 or SPLC780 controller chip and have 1, 2 or 4 lines. Typical
displays include the LCD16X2 (futurlec.com), the Z7001
(altronics.com.au) and the QP5512 (jaycar.com.au). eBay is another
good source where prices can range from $10 to $50.
To setup the display you use the BITBANG LCD INIT command:
BITBANG LCD INIT d4, d5, d6, d7, rs, en
d4, d5, d6 and d7 are the numbers of the I/O pins that connect to inputs D4, D5, D6 and D7 on the LCD module
(inputs D0 to D3 and R/W on the module should be connected to ground). 'rs' is the pin connected to the
register select input on the module (sometimes called CMD or DAT). 'en' is the pin connected to the enable or
chip select input on the module.
Any I/O pins on the PicoMite can be used and you do not have to set them up beforehand (the LCD command
automatically does that for you). The following shows a typical set up.
+5V
10K
2 3
Vdd CONTRAST
RS 4
RS
EN 6
EN
LCD Module
PicoMite D7 D6 D5 D4 D3 D2 D1 D0 GND R/W
14 13 12 11 10 9 8 7 1 5
D7
D6
D5
D4
Note that this example also uses the TEMPR() function to get the temperature (described above).
Keypad Interface
A keypad is a low tech method of entering data into a PicoMite based system. The PicoMite supports either a
4x3 keypad or a 4x4 keypad and the monitoring and decoding of key presses is done in the background. When
a key press is detected an interrupt will be issued where the program can deal with it.
Examples of a 4x3 keypad and a 4x4 keypad are the Altronics S5381 and S5383 (go to www.altronics.com).
To enable the keypad feature you use the command:
KEYPAD var, int, r1, r2, r3, r4, c1, c2, c3, c4
Where var is a variable that will be updated with the key code and int is the name of the interrupt subroutine to
call when a new key press has been detected. r1, r2, r3 and r4 are the pin numbers used for the four row
connections to the keypad (see the diagram below) and c1, c2, c3 and c4 are the column connections. c4 is only
used with 4x4 keypads and should be omitted if you are using a 4x3 keypad.
Any I/O pins on the PicoMite can be used and you do not have to set them up beforehand, the KEYPAD
command will automatically do that for you.
R1
1 2 3 20
R2
4 5 6 21
R3
7 8 9 22
R4
10 0 11 23
PicoMite
C1
C2
C3
C4
The detection and decoding of key presses is done in the background and the program will continue after this
command without interruption. When a key press is detected the value of the variable var will be set to the
number representing the key (this is the number inside the circles in the diagram above). Then the interrupt
will be called.
For example:
Keypad KeyCode, KP_Int,GP2,GP3,GP4,GP5,GP21,GP22,GP26 ' 4x3 keybd
DO
< body of the program >
LOOP
PS2 Keyboard
On the PicoMite you can attach a PS2 keyboard and, display the output of the interpreter on the LCD (see the
LCD Display as the Console Output section below). This turns the PicoMite into a completely self contained
computer with its own keyboard and display. Using the built in colour coded editor programs can be entered,
edited and run without requiring another computer.
Because the PicoMite I/O is specified for a maximum of 3.6V and PS2 keyboards
run off 5V level conversion should be used on the CLOCK and DATA pins. A
suitable commercially available Adafruit 4 channel bi-directional level converter is
pictured on the right. The PS2 CLOCK pin should be connected via the level
converter to PicoMite pin 11 (GP8) and the PS2 DATA pin to PicoMite pin 12
(GP9).
Before the keyboard can be used it must first be enabled by specifying the language
of the keyboard:
OPTION KEYBOARD language [,capslock][,numlock][,repeatstart] [,repeatrate]
Where ‘language’ is a two character code such as US for the standard keyboard used in the USA, Australia and
New Zealand. Other keyboard layouts that can be specified are United Kingdom (UK), French (FR), German
(GR), Belgium (BE), Italian (IT) or Spanish (ES). Note that the non US layouts map some of the special keys
present on these keyboards but the corresponding special character will not display as they are not part the
standard PicoMite fonts (another character will be used instead).
This command configures the I/O pins dedicated to the keyboard and initialises it for use. As with similar
commands this option will be saved in flash memory and automatically applied on power up. If you need to
remove the keyboard you can do this with the OPTION KEYBOARD DISABLE command.
See the OPTION KEYBOARD command for details of the optional parameters.
SSD1963 PicoMite
Description
Display
DB0 Parallel Data Bus bit 0 Pin 1/GP0
DB1 Parallel Data Bus bit 1 Pin 2/GP1
DB2 Parallel Data Bus bit 2 Pin 4/GP2
DB3 Parallel Data Bus bit 3 Pin 5/GP3
DB4 Parallel Data Bus bit 4 Pin 6/GP4
DB5 Parallel Data Bus bit 5 Pin 7/GP5
DB6 Parallel Data Bus bit 6 Pin 9/GP6
DB7 Parallel Data Bus bit 7 Pin 10/GP7
CS Chip Select (active low) Ground (ie, always selected)
WR Write (active low) Pin 19/GP14
RD Read (active low) Pin 20/GP15
RS Command/Data Pin 17/GP13
RESET Reset the SSD1963 Pin 21/GP16
LED_A Backlight control for an unmodified display panel Configurable
5V 5V power for the backlight on some displays (most displays use the 3.3V supply for this).
3.3V Power supply.
GND Ground
The following table lists the connections required to support the touch controller interface:
SSD1963 PicoMite
Description
Display
T_CS Touch Chip Select Recommend Pin 24/GP18
T_IRQ Touch Interrupt Recommend Pin 25/GP19
T_DIN Touch Data In (MOSI) Recommend Pin 15/GP11
T_CLK Touch SPI Clock Recommend Pin 14/GP10
T_DO Touch Data Out (MISO) Recommend Pin 16/GP12
The following table lists the connections required to support the SD Card connector:
SSD1963 PicoMite
Description
Display
SD_CS SD Card Chip Select Recommend Pin 29/GP22
SD_DIN SD Card Data In (MOSI) Recommend Pin 15/GP11
SD_CLK SD Card SPI Clock Recommend Pin 14/GP10
SD_DO SD Card Data Out (MISO) Recommend Pin 16/GP12
Where a PicoMite connection is listed as "Recommend" the specific pin should be specified in the appropriate
OPTION command (see below).
GP11
GP16
GP19
GP12
GP18
GP16
GP18
+5V
GP16
GP18
GP19
GP19
GP22
GP15
GP14
GP13
Ground
+5V
To match the above connections the following configuration commands should be entered, one by one at the
command prompt:
OPTION SYSTEM SPI GP18, GP19, GP16
OPTION SDCARD GP22
OPTION LCDPANEL ILI9341, L, GP15, GP14, GP13
OPTION TOUCH GP12, GP11
Configuring Touch
The touch controller on an LCD panel uses the SPI protocol for communications and this needs to be
specifically configured before the panel can be configured. This is the “system” SPI port which is the port that
will be used for system use (SD Card, LCD display and the touch controller on a LCD panel). This SPI port
will then not be available to BASIC programs (i.e., it is reserved)
There are a number of ports and pins that can be used but these are the same as the configuration used for the
example LCD panel interface previously in this manual. This command does not need to be repeated if the
system SPI has already been configured:
OPTION SYSTEM SPI GP18, GP19, GP16
To use the touch facility MMBasic must be told that it is available using the OPTION TOUCH command. This
should be done after the LCD display has been configured. This command tells MMBasic what pins are used for
the Chip Select and Interrupt signals. For example this sets Chip Select to the GP12 pin and Interrupt to GP11:
OPTION TOUCH GP12, GP11
These commands must be entered at the command prompt and will cause the PicoMite to restart. This has the
side effect of disconnecting the USB console interface which will need to be reconnected.
When the PicoMite is restarted MMBasic will automatically initialise the touch controller. To verify the
configuration you can use the command OPTION LIST to list all options that have been set including the
configuration of the display panel and touch.
Note that you can use many different configurations using various pin allocations – this is just an example
based on the configuration commands listed above.
Care must be taken when the SPI port is shared between a number of devices (SD Card, touch, etc). In this case
all the Chip Select signals must configured in MMBasic or alternatively disabled.
Touch Functions
To detect if and where the screen is touched you can use the following functions in a BASIC program:
TOUCH(X)
Returns the X coordinate of the currently touched location or -1 if the screen is not being touched.
TOUCH(Y)
Returns the Y coordinate of the currently touched location or -1 if the screen is not being touched.
Specifying the number zero (single digit) as the argument will cancel both up and down interrupts. ie:
GUI INTERRUPT 0
Fonts
There are eight built in fonts. These are:
Drawing Commands
There are nine basic drawing commands that you can use within MMBasic programs on the PicoMite to
interact with an attached LCD display. There is also a series of more powerful GUI commands for drawing
switches, radio buttons, etc. See the next section Advanced Graphics for more details.
Most of the basic drawing commands have optional parameters. You can completely leave these off the end of
a command or you can use two commas in sequence to indicate a missing parameter. For example, the fifth
parameter of the LINE command is optional so you can use this format:
LINE 0, 0, 100, 100, , rgb(red)
Optional parameters are indicated below by italics, for example: font.
In the following commands C is the drawing colour and defaults to the current foreground colour. FILL is the
fill colour which defaults to -1 which indicates that no fill is to be used.
The drawing commands are:
CLS C
Clears the screen to the colour C. If C is not specified the current default background colour will be used.
PIXEL X, Y, C
Illuminates a pixel. If C is not specified the current default foreground colour will be used.
LINE X1, Y1, X2, Y2, LW, C
Draws a line starting at X1 and Y1 and ending at X2 and Y2.
LW is the line’s width and is only valid for horizontal or vertical lines. It defaults to 1 if not specified or if
the line is a diagonal.
BOX X, Y, W, H, LW, C, FILL
Draws a box starting at X and Y which is W pixels wide and H pixels high.
LW is the width of the sides of the box and can be zero. It defaults to 1.
Rotated Text
As described above the alignment of the text in the TEXT command can be specified by using one or two
characters in a string expression for the third parameter of the command. In this string you can also specify a
third character to indicate the rotation of the text. This character can be one of:
N for normal orientation
V for vertical text with each character under the previous running from top to bottom.
I the text will be inverted (i.e. upside down)
U the text will be rotated counter clockwise by 90º
D the text will be rotated clockwise by 90º
This extra feature applies in the TEXT and GUI CAPTION commands.
As an example, the following will display the text "LCD Display" vertically down the left hand margin of the
display panel and centred vertically:
TEXT 0, 250, "LCD Display", "LMV", 5
Positioning is relative to the top left corner of the character when viewed normally so inverted 100,100 will
have the top left pixel of the first character at 100,100 and the text will then be above y=101 and to the left of
x=101. Similarly “R” in the alignment string is viewed from the perspective of the character in whatever
orientation it is in (not the screen).
Transparent Text
If the display is capable of transparent text the TEXT command will allow the use of -1 for the background
colour. This means that the text is drawn over the background with the background image showing through the
gaps in the letters. Compatible displays use the SSD1963, ILI9341, ST7789_320, or ILI9488 with MISO
connected.
Load Image
The LOAD IMAGE and LOAD JPG commands can be used to load an image from the Flash Filesystem or SD
Card and display it on the LCD display. This can be used to draw a logo or add an ornate background to the
graphics drawn on the display.
Example
As an example the following program will draw a simple digital clock on an ILI9341 based LCD display. The
program will terminate and return to the command prompt if the display screen is touched.
First the display and touch options must be configured by entering the commands listed at the beginning of this
section. The exact format of these will depend on how you have connected the display panel.
Then enter and run the program:
CONST DBlue = RGB(0, 0, 128) ' A dark blue colour
COLOUR RGB(GREEN), RGB(BLACK) ' Set the default colours
FONT 1, 3 ' Set the default font
DO
TEXT MM.HRes/2, MM.VRes/4, TIME$, "CM", 1, 4, RGB(CYAN), DBlue
TEXT MM.HRes/2, MM.VRes*3/4, DATE$, "CM"
IF TOUCH(X) <> -1 THEN END
LOOP
This program starts by defining a constant with a value corresponding to a dark blue colour and then sets the
defaults for the colours and the font. It then draws a box with red walls and a dark blue interior.
Defining Controls
These are some of the advanced GUI controls that you can use:
Each control has a reference number called '#ref' in the description of the control. This can be any number
between 1 and the upper limit set by the OPTION CONTROL command. This reference number is used to
identify a control. For example, a check box can be created with a reference number of #10:
GUI CHECKBOX #10, "Test", 100, 100, 50, rgb(BLUE)
Once created the user can check and uncheck the box using the touch feature of the LCD panel without the
running BASIC program being involved. When needed the program can determine the check box value by
using its reference number in the CtrlVal() function:
IF CtrlVal(#10) THEN ..
The # character is optional but serves to remind the programmer that this is not an ordinary number.
In the following commands any arguments that are in italic font (e.g. Width, Height) are optional and if not
specified will take the value of the previous command that did specify them. This means for example, that a
number of radio buttons with the same size and colour can be specified with only the first button having to list
all the details. Note that with the colour specification this is different to the basic drawing commands which
default to the last COLOUR command.
All strings used in GUI controls and the MsgBox can display multiple lines by using the tilde character (~) to
separate each line in the string. For example, a push button's caption can be "ALARM~TEST" and this would
be displayed as two lines. For all controls the font used for the caption will be whatever is set with the FONT
command and the colours will be whatever was set by the last COLOUR command.
If the display is capable of transparent text these commands will allow the use of -1 for the background colour.
This means that the text is drawn over the background with the background image showing through the gaps in
the letters.
Frame
GUI FRAME #ref, caption$, StartX, StartY, Width, Height, Colour
This will draw a frame which is a box with round corners and a caption. A frame does not respond to touch but
is useful when a group of controls need to be visually brought together. It can also be used to surround a group
of radio buttons and MMBasic will arrange for the radio buttons surrounded by the frame to be exclusive – that
is, when one radio button is selected any other button that was selected and within the frame will be deselected.
LED
GUI LED #ref, caption$, CenterX, CenterY, Diameter, Colour
This will draw an indicator light (it looks like a panel mounted LED). When its value is set to one it will be
illuminated and when it is set to zero it will be off (a dull version of its colour attribute). The LED can be made
to flash by setting its value to the number of milliseconds that it should remain on before turning off.
The caption will be drawn to the right of the LED and will use the colours set by the COLOUR command. The
LED control is not animated when touched but its reference number can be found using TOUCH(REF) and
TOUCH(LASTREF) in the touch interrupts and any required animation can be done in MMBasic.
Check Box
GUI CHECKBOX #ref, caption$, StartX, StartY, Size, Colour
This will draw a check box which is a small box with a caption. Both the height and width are specified with
the 'Size' parameter. When touched an X will be drawn inside the box to indicate that this option has been
selected and the control's value will be set to 1. When touched a second time the check mark will be removed
and the control's value will be zero. The caption will be drawn to the right of the Check Box and will use the
colours set by the COLOUR command.
Push Button
GUI BUTTON #ref, caption$, StartX, StartY, Width, Height, FColour, BColour
This will draw a momentary button which is a square switch with the caption on its face. When touched the
visual image of the button will appear to be depressed and the control's value will be 1. When the touch is
removed the value will revert to zero. Caption can be a single string with two captions separated by a vertical
bar (|) character (e.g. "UP|DOWN"). When the button is up the first string will be used and when pressed the
second will be used.
Switch
GUI SWITCH #ref, caption$, StartX, StartY, Width, Height, FColour, BColour
This will draw a latching switch with the caption on its face. When touched the visual image of the button will
appear to be depressed and the control's value will be 1. When touched a second time the switch will be
released and the value will revert to zero. Caption can be a single string with two captions separated by a |
character (e.g. "ON|OFF"). When this is used the switch will appear to be a toggle switch with each half of the
caption used to label each half of the toggle switch.
Radio Button
GUI RADIO #ref, caption$, CenterX, CenterY, Radius, Colour
This will draw a radio button with a caption. When touched the centre of the button will be illuminated to
indicate that this option has been selected and the control's value will be 1. When another radio button is
selected the mark on this button will be removed and its value will be zero. Radio buttons are grouped together
when surrounded by a frame and when one button in the group is selected all others in the group will be
deselected. If a frame is not used all buttons on the screen will be grouped together.
The caption will be drawn to the right of the button and will use the colours set by the COLOUR command.
Display Box
GUI DISPLAYBOX #ref, StartX, StartY, Width, Height, FColour, BColour
This will draw a box with rounded corners. Any string can be displayed in the box by using the CtrlVal(r) =
command. This is useful for displaying text, numbers and messages. This control is not animated when
touched but its reference number can be found using TOUCH(REF) and TOUCH(LASTREF) in the touch
interrupts and any required animation can be done in MMBasic.
Number Box
GUI NUMBERBOX #ref, StartX, StartY, Width, Height, FColour, BColour
This will draw a box with rounded corners. When
the box is touched a numeric keypad will appear
on the screen as shown on the right. Using this
virtual keypad any number can be entered into the
box including a floating point number in exponen-
tial format. The new number will replace the
number previously in the box.
The Alt key will select an alternative key selection
and the other special keys are the same as with the
text box.
The displayed number can also be set by assigning
a number (float or integer) to the box using the
CtrlVal(r) = command. Similar to the Text Box,
the value of the control can set to a literal string with two leading hash characters (e.g. "##Hint") and in that
case the string (without the leading two characters) will be displayed in the box with reduced brightness.
Reading this will return zero and when a key is pressed the ghost text will vanish.
MMBasic will try to position the virtual keypad on the screen to not obscure the number box that caused it to
appear. A pen down interrupt will be generated just before the keypad is deployed and a key up interrupt will
be generated when the Enter key is touched and the keypad is hidden. Also, when the Enter key is touched the
entered text will be evaluated as a number and the NUMBERBOX control redrawn to display this number.
Caption
GUI CAPTION #ref, text$, StartX, StartY, Alignment, FColour, BColour
This will draw a text string on the screen. It is similar to the basic drawing command TEXT, the difference
being that MMBasic will automatically dim this control if a keyboard or number pad is displayed.
'Alignment' is zero to three characters (a string expression or variable is also allowed) where the first letter is
the horizontal alignment around X and can be L, C or R for LEFT, CENTER, RIGHT and the second letter is
the vertical alignment around Y and can be T, M or B for TOP, MIDDLE, BOTTOM.
A third character can be used to indicate the rotation of the text. This can be 'N' for normal orientation, 'V' for
vertical text with each character under the previous running from top to bottom, 'I' the text will be inverted (i.e.
upside down), 'U' the text will be rotated counter clockwise by 90º and 'D' the text will be rotated clockwise by
90º. The default alignment is left/top with no rotation.
If the colours are not specified this control will use the colours set by the COLOUR command.
Circular Gauge
GUI GAUGE #ref, StartX, StartY, Radius, FColour, BColour, min, max,
nbrdec, units$, c1, ta, c2, tb, c3, tc, c4
This will define a graphical circular analog gauge with a digital display in the centre showing the value and
units. If specified the gauge will be coloured to provide a graphical indication of the signal level (e.g. green for
OK, yellow for warning, etc).
'StartX' and 'StartY' are the coordinates of the centre of the gauge while 'Radius' is
the distance from the centre to the outer edge.
'min' is the value associated with the minimum value of the gauge and 'max' is the
maximum value. When CtrlVal() is used to assign a value (floating point or
integer) to the gauge the analogue portion of the gauge will be drawn to a length
proportional to the range between 'min' and 'max'.
At the same time the digital value will be drawn in the centre of the gauge using the
current font settings (set with the FONT command). 'nbrdec' specifies the number
of decimal places to be used in this display. Under the digital value the 'units$' will
be displayed (this can be skipped or a zero length string used if not required).
Normally the analog graph is drawn using the colour specified in 'Fcolour' however
a multi colour gauge can be created using 'c1' to 'c4' for the colours and 'ta' to 'tc'
for the thresholds used to determine when the colour will change.
Specifically, 'c1' is the colour to be used for values up to 'ta'. 'c2' is the colour to be
used for values between 'ta' and 'tb', 'c3' is used for values between 'tb' and 'tc' and
c4 is used for values above 'tc'. Colours and thresholds not required can be left off
then list. For example, for a two colour gauge only 'c1', 'ta' and 'c2' need to be specified.
When colours and thresholds are specified the background of the gauge will be drawn with a dull version of the
gauge colour at that level ("ghost colouring") so that the user can appreciate how close to the various thresholds
the actual value is. Also the digital value displayed in the centre will also change to the colour specified by the
current value.
If only one colour is required for the whole analogue graph it can be specified by just using 'c1' and leaving all
the following parameters off.
Area
GUI AREA #ref, StartX, StartY, Width, Height
This will define an invisible area of the screen that is sensitive to touch and will set TOUCH(REF) and
TOUCH(LASTREF) accordingly when touched or released. It can be used as the basis for creating a custom
control which is defined and managed by the BASIC program.
CTRLVAL(#ref) =
This command will set the value of a control. For off/on controls like check boxes it will override any
touch input and can be used to depress/release switches, tick/untick check boxes, etc. A value of zero is off
or unchecked and non zero will turn the control on. For a LED it will cause the LED to be illuminated or
turned off. It can also be used to set the initial value of spin boxes, text boxes, etc. For example:
CTRLVAL(#10) = 12.4
MsgBox()
The MsgBox() function will display a message box on the screen and wait for user input. While the message
box is displayed all controls will be disabled so that the message box has the complete focus.
The syntax is:
r = MsgBox(message$, button1$ [, button2$ [, button3$ [, button4$]]])
All arguments are strings. 'message$' is the message to display. This can contain one or more tilde characters
(~) which indicate a line break. Up to 10 lines can be displayed inside the box. 'button1$' is the caption for the
first button, 'button2$' is the caption for the second button, etc. At least one button must be specified and four
is the maximum. Any buttons not included in the argument list will not be displayed.
The font used will be the default font set using the FONT command and the colours used will be the defaults
set by the COLOUR command. The box will be automatically sized taking into account the dimensions of the
default font, the number of lines to display and the number of buttons specified.
When the user touches a button the message box will erase itself, restore the display (e.g. re enable all controls)
and return the number of the button that was touched (the first button will return 1, the second 2, etc). Note
that, unlike all other GUI controls the BASIC program will stop running while the message box is displayed,
interrupts however will be honoured and acted upon.
To illustrate the usage of a message box will the following program fragment will attempt to open a file and if
an error occurs the program will display an error message using the MsgBox() function. The message has two
lines and the box has two buttons for retry and cancel.
Do
On Error Skip
Open "file.txt" For Input As #1
If MM.ErrNo <> 0 Then
if MsgBox("Error~Opening file.txt","RETRY","CANCEL") = 2 Then Exit Sub
EndIf
Loop While MM.ErrNo <> 0
Program Structure
Typically a program would start by defining the controls (which MMBasic will draw on the screen), then it
would set the defaults and finally it would drop into a continuous loop where it would do whatever job it was
design to do. For example, take the case of a simple controller for a motor where the user could select the
speed and cause the motor to run by pressing an on screen button.
To implement this function the program would look something like this:
GUI CAPTION #1, "Speed (rpm)", 200, 50 ' label the number box
GUI NUMBERBOX #2, 200, 100, 150, 40 ' define and draw the number box
CtrlVal(#2) = 100 ' default value for the speed
GUI BUTTON #3, "RUN", 200, 350, 0, RGB(red) ' define and draw the RUN button
Touch Up Interrupt
In most cases you can process all user input in the touch down interrupt. But there are exceptions and a typical
example is when you need to change the characteristics of the control that is being touched. For example, if
you wanted to change the foreground colour of a button from white to red when it is down. When it is returned
to the up state the colour should revert to white.
Setting the colour on the touch down is easy. Just define a touch down interrupt and change the colour in the
interrupt when that control is touched. However, to return the colour to white you need to detect when the
touch has been removed from the control (i.e. touch up). This can be done with a touch up interrupt.
To specify a touch up interrupt you add the name of the subroutine for this interrupt to the end of the GUI
INTERRUPT command. For example:
GUI INTERRUPT IntTouchDown, IntTouchUp
Within the touch up subroutine you can use the same structure as in the touch down sub but you need to find
the reference number of the last control that was touched. This is because the touch has already left the screen
and no control is currently being touched. To get the number of the last control touched you need to use the
function TOUCH(LASTREF)
The following example shows how you could meet the above requirement and implement both a touch down
and a touch up interrupt:
SUB IntTouchDown
SELECT CASE TOUCH(REF)
CASE ButtonRef
GUI FCOLOUR RGB(RED), ButtonRef
END SELECT
END SUB
SUB IntTouchUp
SELECT CASE TOUCH(LASTREF)
CASE ButtonRef
GUI FCOLOUR RGB(WHITE), ButtonRef
END SELECT
END SUB
Multiple Screens
Your program might need a number of screens with differing controls on each screen. This could be
implemented by deleting the old controls and creating new ones when the screen is switched. But another way
to do this is to use the GUI SETUP and GUI PAGE commands. These allow you to organise the controls onto
pages and with one simple command you can switch pages. All controls on the old page will be automatically
hidden and controls on the new page will be automatically shown.
To allocate controls to a page you use the GUI SETUP nn command where nn refers to the page in the range of
1 to 32. When you have used this command any newly created controls will be assigned to that page. You can
use GUI SETUP as many times that you want. For example, in the program fragment below the first two
controls will be assigned to page 1, the second to page 2, etc.
GUI SETUP 1
GUI Caption #1, "Flow Rate", 20, 170,, RGB(brown),0
GUI Displaybox #2, 20, 200, 150, 45
GUI SETUP 2
GUI Caption #3, "High:", 232, 260, LT, RGB(yellow)
GUI Numberbox #4, 318, 6,90, 12, RGB(yellow), RGB(64,64,64)
GUI SETUP 3
GUI Checkbox #5, "Alarms", 500, 285, 25
GUI Checkbox #6, "Warnings", 500, 325, 25
By default only the controls setup as page 1 will be displayed and the others will be hidden.
To switch the screen to page 3 all you need do is use the command GUI PAGE 3. This will cause controls #1
and #2 to be automatically hidden and controls #5 and #6 to be displayed. Similarly GUI PAGE 2 will hide all
except #3 and #4 which will be displayed.
You can specify multiple pages to display at the one time, for example, GUI PAGE 1,3 will display both pages 1
and 3 while hiding page 2. This can be useful if you have a set of controls that must be visible all the time. For
example, GUI PAGE 1,2 and GUI PAGE 1,3 will leave the controls on page 1 visible while the others are
switched on and off.
It is perfectly legal for a program to modify controls on other pages even though they are not displayed at the
time. This includes changing the value and colours as well as disabling or hiding them. When the display is
switched to their page the controls will be displayed with their new attributes.
It is possible to place the GUI PAGE commands in the touch down interrupt so that pressing a certain control or
part of the screen will switch to another page.
Note that when ALL is used for the list of controls in commands such as GUI ENABLE ALL this only refers to
the controls on the pages that are currently selected for display. Controls on other pages will be unaffected.
All programs start with the equivalent of the commands GUI SETUP 1 and GUI PAGE 1 in force. This means
that if the GUI SETUP and GUI PAGE commands are not used the program will run as you would expect with
all controls displayed.
A typical usage of the GUI PAGE command is shown below.
GUI SETUP 2
GUI Caption #1, "Displaying First Page", 20, 20
GUI SETUP 3
GUI Caption #2, "Displaying Second Page", 20, 50
Page 1, 2
GUI INTERRUPT TouchDown
Do
' the main program loop
Loop
Sub TouchDown
If Touch(REF) = 10 Then GUI Page 1, 2
If Touch(REF) = 11 Then GUI Page 1, 3
End Sub
Multiple Interrupts
With many screen pages the interrupt subroutine could get long and complicated. To work around that it is
possible to have multiple interrupt subroutines and switch dynamically between them as you wish (normally
after switching pages). This is done by redefining the current interrupt routines using the GUI INTERRUPT
command.
For example, this program fragment uses different interrupt routines for pages 4 and 5 and they are specified
immediately after switching the pages.
GUI PAGE 4
GUI INTERRUPT P4keydown, P4keyup
..
GUI PAGE 5
GUI INTERRUPT P5keydown, P5keyup
..
Constants
Numeric constants may begin with a numeric digit (0-9) for a decimal constant, &H for a hexadecimal
constant, &O for an octal constant or &B for a binary constant. For example &B1000 is the same as the
decimal constant 8. Constants that start with &H, &O or &B are always treated as 64-bit integer constants.
Decimal constants may be preceded with a minus (-) or plus (+) and may be terminated with 'E' followed by an
exponent number to denote exponential notation. For example 1.6E+4 is the same as 16000.
If the decimal constant contains a decimal point or an exponent, it will be treated as a floating point constant;
otherwise it will be treated as a 64-bit integer constant.
String constants are surrounded by double quote marks ("). E.g. "Hello World".
Implementation Characteristics
Maximum program size (as plain text) is 100KB. Note that MMBasic tokenises the program when it is stored
in flash so the final size in flash might vary from the plain text size.
Maximum length of a command line is 255 characters.
Maximum length of a variable name or a label is 31 characters.
Maximum number of dimensions to an array is 6.
Maximum number of arguments to commands that accept a variable number of arguments is 50.
Maximum number of nested FOR…NEXT loops is 20.
Maximum number of nested DO…LOOP commands is 20.
Maximum number of nested GOSUBs, subroutines and functions (combined) is 320.
Maximum number of nested multiline IF…ELSE…ENDIF commands is 20.
Maximum number of user defined labels, subroutines and functions (combined): 224
Maximum number of interrupt pins that can be configured: 10
Numbers are stored and manipulated as double precision floating point numbers or 64-bit signed integers. The
range of floating point numbers is 1.797693134862316e+308 to 2.225073858507201e-308.
The range of 64-bit integers (whole numbers) that can be manipulated is ± 9223372036854775807.
Maximum string length is 255 characters.
Maximum line number is 65000.
Maximum number of background pulses launched by the PULSE command is 5.
Maximum number of global variables and constants is 256
Maximum number of local variables is 256
The maximum number of files that can be listed by the FILES command is 1000
The maximum length filename supported is 63 characters
MM.VER The version number of the firmware as a floating point number in the form
aa.bbcc where aa is the major version number, bb is the minor version
number and cc is the revision number. For example version 5.03.00 will
return 5.03 and version 5.03.01 will return 5.0301.
MM.CMDLINE$ This constant variable containing any command line arguments passed to the
current program is automatically created when an MMBasic program runs;
see RUN and * commands for details.
• Programs run from the Editor or using OPTION AUTORUN will set
MM.CMDLINE$ to the empty string.
• If not required this constant variable may be removed from memory
using ERASE MM.CMDLINE$
MM.DEVICE$ A string representing the device or platform that MMBasic is running on.
Currently this variable will contain one of the following:
"Maximite" on the standard Maximite and compatibles.
"Colour Maximite" on the Colour Maximite and UBW32.
"Colour Maximite 2" on the Colour Maximite 2.
"DuinoMite" when running on one of the DuinoMite family.
"DOS" when running on Windows in a DOS box.
"Generic PIC32" for the generic version of MMBasic on a PIC32.
"Micromite" on the PIC32MX150/250
"Micromite MkII" on the PIC32MX170/270
"Micromite Plus" on the PIC32MX470
"Micromite Extreme" on the PIC32MZ series
"ARMmite H7" on the ArmmiteH7
"ARMmite F407" on the ArmmiteF4
"ARMmite L4" with chip no. and pin count appended on the ArmmiteL4
“PicoMite” on the Raspberry Pi Pico
“WebMite” on the Raspberry Pi Pico W
"PicoMiteVGA" on the Raspberry Pi Pico VGA Edition
MM.ERRNO If a statement caused an error which was ignored these variables will be set
MM.ERRMSG$ accordingly. MM.ERRNO is a number where non zero means that there was
an error and MM.ERRMSG$ is a string representing the error message that
would have normally been displayed on the console. They are reset to zero
and an empty string by RUN, ON ERROR IGNORE or ON ERROR SKIP.
MM.INFO() These two versions can be used interchangeably but good programming
MM.INFO$() practice would require that you use the one corresponding to the returned
datatype.
MM.INFO$(LCDPANEL) Returns the name of the configured LCD panel or a blank string
MM.INFO$(CURRENT) Returns the name of the current program or NONE if called after a NEW or
EDIT Command
MM.INFO(PATH) Returns the path of the current program or NONE if called after a NEW or
EDIT Command
MM.INFO(DISK SIZE) Returns the capacity of the Flash Filesystem or SD Card, whichever is the
active drive, in bytes
MM.INFO(EXISTS FILE Returns 1 if the file specified exists, returns -1 if fname$ is a directory,
fname$) otherwise returns 0
MM.INFO(EXISTS FILE Returns a Boolean indicating whether the directory specified exits
fname$)
MM.INFO(FREE SPACE) Returns the free space on the Flash Filesystem or SD Card whichever is the
active drive
MM.INFO(FILESIZE file$) Returns the size of file$ in bytes or -1 if not found, -2 if a directory.
MM.INFO$(MODIFIED file$) Returns the date/time that file$ was modified, Empty string if not found
MM.INFO(FONT ADDRESS Returns the address of the memory location with the address of FONT n
n)
MM.INFO(FONTHEIGHT) Integers representing the height and width of the current font (in pixels).
MM.INFO(FONTWIDTH)
MM.INFO(FLASH) Reports which flash slot the program was loaded from if applicable
MM.INFO(HEAP) Returns the amount of MMbasic Heap memory free. MMBasic heap is used
for strings, arrays and various other temporary and permanent buffers (e.g.
audio)
MM.INFO(HPOS) The current horizontal and vertical position (in pixels) following the last
MM.INFO(VPOS) graphics or print command.
MM.INFO(OPTION option) Returns the current value of a range of options that affect how a program
MM.INFO$(PIN pinno) Returns the status of I/O pin 'pinno'. Valid returns are:
INVALID, RESERVED, IN USE, and UNUSED
MM.INFO(PINNO GPnn) Returns the physical pin number for a given GP number. GPnn can be an
unquoted string (GP01), a string literal(“GP01”) or a string variable. Ie,
A$=”GP01”: MM.INFO(PINNO A$)
MM.INFO(PS2) Reports the last raw message received on the PS2 interface if enabled
MM.INFO$(SOUND) Returns the current activity on the audio output (OFF, PAUSED, TONE,
WAV, FLAC, SOUND)
MM.INFO(STACK) Returns the C stack pointer. Complex or recursive Basic code may result in
the error "Stack overflow, expression too complex at depth %" This will
occur when the stack is below &H 2003f800. Monitoring the stack will
allow the programmer to identify simplifications to the Basic code to avoid
the error.
MM.INFO$(TOUCH) Returns the status of the Touch controller. Valid returns are:
“Disabled”, “Not calibrated”, and “Ready”.
MM.INFO$(LINE) Returns the current line number as a string. LIBRARY returned if in the
Library and UNKNOWN if not in a program. Assists in diagnostics while
unit testing.
MM.HRES Integers representing the horizontal and vertical resolution of the LCD
display panel (if configured) in pixels.
MM.VRES
MM.FONTHEIGHT Integers representing the height and width of the current font (in pixels) kept
for compatibility. NB: these are automatically converted into
MM.FONTWIDTH
MM.INFO(FONTHEIGHT) and MM.INFO(FONTWIDTH) by MMBasic
MM.ONEWIRE Following a 1-Wire reset function this integer variable will be set to indicate
the result of the operation: 0 = Device not found, 1 = Device found
MM.I2C Following an I2C write or read command this integer variable will be set to
indicate the result of the operation as follows:
0 = The command completed without error.
1 = Received a NACK response
2 = Command timed out
Permanent?
OPTION ANGLE RADIANS | This command switches trig functions between degrees and radians.
DEGREES Acts on SIN, COS, TAN, ATN, ATAN2, MATH ATAN3, ACOS,
ASIN
OPTION AUTOREFRESH Black and white displays can only be updated a full screen at a time.
OFF | ON By using OPTION AUTOREFRESH OFF/ON you can control
whether a write command immediately updates the display or not. If
AUTOREFRESH is OFF the REFRESH command can be used to
trigger the write. This applies to the following displays: N5110,
SSD1306I2C, SSD1306I2C32, SSD1306SPI, ST7920
OPTION AUTORUN ON
Instructs MMBasic to automatically run a program on power up or
restart.
or
OPTION AUTORUN n ON will cause the the current program to be run.
or Specifying ‘n’ will cause that location in flash memory to be run.
‘n’ must be in the range 1 to 7.
OPTION AUTORUN OFF
OFF will disable the autorun option and is the default for a new
program.
Entering the break key (default CTRL-C) at the console will
interrupt the running program and return to the command prompt.
OPTION BASE 0 | 1 Set the lowest value for array subscripts to either 0 or 1.
This must be used before any arrays are declared and is reset to the
default of 0 on power up.
OPTION BAUDRATE nn Set the baudrate of the serial console (if it is configured).
OPTION COLOURCODE ON
Turn on or off colour coding for the editor's output. Keywords will
be in cyan, comments in yellow, etc. The default is OFF.
or
OPTION COLOURCODE OFF The keyword COLORCODE (USA spelling) can also be used.
This requires a terminal emulator that can interpret the appropriate
escape codes (eg, Tera Term). This command must be run at the
command prompt (not in a program).
OPTION DEFAULT FLOAT | Used to set the default type for a variable which is not explicitly
INTEGER | STRING | NONE defined.
If OPTION DEFAULT NONE is used then all variables must have
their type explicitly defined or the error “Variable type not specified”
will occur.
When a program is run the default is set to FLOAT for compatibility
with Microsoft BASIC and previous versions of MMBasic.
Set the characteristics of the display terminal used for the console.
OPTION DISPLAY lines
[,chars]
Both the LIST and EDIT commands need to know this information
to correctly format the text for display.
'lines' is the number of lines on the display and 'chars' is the width of
the display in characters. The default is 24 lines x 80 chars and when
changed this option will be remembered even when the power is
removed. Maximum values are 100 lines and 240chars.
This command is not available if the display is being used as a
console.
OPTION EXPLICIT Placing this command at the start of a program will require that every
variable be explicitly declared using the DIM, LOCAL or STATIC
commands before it can be used in the program.
This option is disabled by default when a program is run. If it is used
it must be specified before any variables are used.
OPTION HEARTBEAT
ON/OFF
Enables or disables the output of the heartbeat on GP25
OPTION KEYBOARD nn
[,capslock] [,numlock]
Configure a PS2 keyboard. This can be used for console input and
any characters typed will be available via any commands that read
[repeatstart] [repeatrate] from the console (serial over USB).
‘nn is a two character code defining the keyboard layout. The choices
are US for the standard keyboard layout in the USA, Australia and
New Zealand and UK for the United Kingdom, GR for Germany, FR
for France and ES for Spain.
The keyboard must be connected as follows:
Connect GP8 to PS2 socket CLOCK pin.
Connect GP9 to PS2 socket DATA pin.
Connect VBUS (5V) or 3V3 (3,3V) to PS2 socket +5V.
Connect GND to PS2 socket GND.
Some keyboards will run on 3.3V and in that case the clock and data
pins can be directly connected. However, if the keyboard is
powered by 5V, level shifting must be used for these connections
so that the PicoMite I/O pins are not subjected to more than 3.6V
This command can only be run from the command line and will cause
a reboot. This setting can be reset with the command OPTION
KEYBOARD NO_KEYBOARD.
The optional parameters capslock and numlock set the initial state of
the keyboard (default 0, 1). The repeatstart defines how how long
before a character repeats the first time (valid 0-3 = 250mSec,
500mSec, 750mSec, 1S: default 1=500mSec). The repeat rate defines
how fast a character repeats after the first repeat (valid 0-31 = 33mSec
to 500mSec: default 12=100mSec).
OPTION LCDPANEL
CONSOLE [font [, fc [,bc
Configures the LCD display panel for use as the console output. The
LCD must support transparent text (i.e. the SSD1963_x, ILI9341 or
blight]]] ST7789_320 controllers).
or 'font' is the default font, 'fc' is the default foreground colour, 'bc' is the
OPTION LCDPANEL default background colour and 'blight' is the default backlight
NOCONSOLE brightness (2 to 100). These parameters are optional and default to
font 1, white, black and 100%. These settings are applied at power
up.
Note that scrolling for any console output is very slow so this feature
is not recommended for general use. This setting is saved in flash and
will be automatically applied on startup. To disable it use the
OPTION LCDPANEL NOCONSOLE command.
This command must be run at the command prompt.
OPTION LEGACY ON This will turn on or off compatibility mode with the graphic
or commands used in the original Colour Maximite. The commands
COLOUR, LINE, CIRCLE and PIXEL use the legacy syntax and all
OPTION LEGACY OFF
drawing commands will accept colours in the range of 0 to 7. Notes:
Keywords such as RED, BLUE, etc are not implemented so they
should be defined as constants if needed.
Refer to the Colour Maximite MMBasic Language Manual for
the syntax of the legacy commands. This can be downloaded
from https://geoffg.net/OriginalColourMaximite.html .
OPTION LIST This will list the settings of any options that have been changed from
their default setting and are the permanent type. OPTION LIST also
shows the version number and which firmware is loaded.
This command must be run at the command prompt (not in a
program).
OPTION PIN nbr Set 'nbr' as the PIN (Personal Identification Number) for access to
the console prompt. 'nbr' can be any non zero number of up to eight
digits.
Whenever a running program tries to exit to the command prompt
for whatever reason MMBasic will request this number before the
prompt is presented. This is a security feature as without access to
the command prompt an intruder cannot list or change the program
in memory or modify the operation of MMBasic in any way. To
disable this feature enter zero for the PIN number (i.e. OPTION
PIN 0).
A permanent lock can be applied by using 99999999 for the PIN
number. If a permanent lock is applied or the PIN number is lost the
only way to recover is to reload the PicoMite firmware.
OPTION RESET
Reset all saved options to their default values.
This command must be run at the command prompt (not in a
program).
OPTION TAB 2 | 3 | 4 | 8
Set the spacing for the tab key. Default is 2.
OPTION VCC voltage Specifies the voltage (Vcc) supplied to the PicoMite.
When using the ADC pins to measure voltage the PicoMite uses the
voltage on the pin marked VREF as its reference. This voltage can
be accurately measured using a DMM and set using this command
for more accurate measurement.
The parameter is not saved and should be initialised either on the
command line or in a program. The default if not set is 3.3.
‘ (single quotation mark) Starts a comment and any text following it will be ignored. Comments can
be placed anywhere on a line.
*file The star/asterisk command is a shortcut for RUN that may only be used at
the MMBasic prompt. e.g.
* RUN
*foo RUN "foo"
*"foo bar" RUN "foo bar"
*foo –wombat RUN "foo", "--wombat"
*foo "wom" RUN "foo", CHR$(34) + "wom" + CHR$(34)
*foo --wom="bat" RUN "foo","--wom=" + CHR$(34) + "bat" + CHR$(34)
String expressions are not supported/evaluated by this command; any
arguments provided are passed as a literal string to the RUN command.
? (question mark) Shortcut for the PRINT command.
ADC OPEN freq, n_channels This allocates up to 4 ADC channels for use GP26, GP27, GP28, and GP29
[,interrupt] and sets them to be converted at the specified frequency. The maximum
total frequency is 500KHz (e.g. 125KHz if all four channels are to be
sampled). If the number of channels is one then it will always be GP26
used, if two then GP26 and GP27 etc. Sampling of multiple channels is
sequential (there is only one ADC). The specified pins are locked to the
function when ADC OPEN is active
The optional interrupt parameter specifies an interrupt to call when the
conversion completes. If not specified then conversion will be blocking
ADC FREQUENCY freq This changes the sampling frequency of the ADC conversion without
having to close and re-open
ADC CLOSE Releases the pins to normal usage
ADC START array1!() This starts conversion into the specified arrays. The arrays must be floating
point and the same size. The size of the arrays defines the number of
[,array2!()] [,array3!()]
[,array4!()] conversions. The results are returned as a voltage between 0 and OPTION
VCC (defaults to 3.3V).
Start can be called repeatedly once the ADC is OPEN
ARC x, y, r1, [r2], a1, a2 [, c] Draws an arc of a circle with a given colour and width between two radials
(defined in degrees). Parameters for the ARC command are:
x: X coordinate of centre of arc
y: Y coordinate of centre of arc
r1: inner radius of arc
r2: outer radius of arc - can be omitted if 1 pixel wide
a1: start angle of arc in degrees
a2: end angle of arc in degrees
c: Colour of arc (if omitted it will default to the foreground colour)
Zero degrees is at the 12 o'clock position.
AUTOSAVE Enter automatic program entry mode. This command will take lines of text
or from the console serial input and save them to program memory.
AUTOSAVE CRUNCH This mode is terminated by entering Control-Z or F1 which will then cause
the received data to be transferred into program memory overwriting the
Or
previous program. Use F2 to exit and immediately run the program.
COPY A2B fname1$ to Copies a file from drive A: to drive B: respecting the current directory set
fname2$ on each drive (see CHDIR)
FLASH LIST Displays a list of all flash locations including the first line of the program.
FLASH LIST n [,all] List the program saved to slot n. Use ALL to list without page breaks.
FLASH ERASE n Erase a flash program location.
FLASH ERASE ALL Erase all flash program locations.
FLASH SAVE n Save the current program to the flash location specified.
FLASH LOAD n Load a program from the specified flash location into program memory.
Runs the program in flash location n, clear all variables. Does not change
FLASH RUN n
the program memory.
Runs the program in flash location n, leaving all variables intact (allows for
FLASH CHAIN n
a program that is much bigger than the program memory). Does not change
the program memory.
FLASH OVERWRITE n Erase a flash program location and then save the current program to the
flash location specified.
FLUSH [#]fnbr Causes any buffered writes to a file previously opened with the file number
‘#fnbr’ to be written to disk. The # is optional. Using this command ensures
that no data is lost if there is a power cut after a write command.
FONT [#]font-number, scaling This will set the default font for displaying text on an LCD panel.
Fonts are specified as a number. For example, #2 (the # is optional). See
the section Graphics Commands and Functions for details of the available
fonts.
'scaling' can range from 1 to 15 and will multiply the size of the pixels
FRAMEBUFFER CREATE Creates a framebuffer “F” with a RGB121 colour space and resolution to
match the configured SPI colour display
FRAMEBUFFER LAYER Creates a framebuffer “L” with a RGB121 colour space and resolution to
match the configured SPI colour display
FUNCTION xxx (arg1 Defines a callable function. This is the same as adding a new function to
[,arg2, …]) [AS <type>} MMBasic while it is running your program.
<statements> 'xxx' is the function name and it must meet the specifications for naming a
<statements> variable. The type of the function can be specified by using a type suffix
xxx = <return value> (i.e. xxx$) or by specifying the type using AS <type> at the end of the
END FUNCTION functions definition. For example:
FUNCTION xxx (arg1, arg2) AS STRING
'arg1', 'arg2', etc are the arguments or parameters to the function (the
brackets are always required, even if there are no arguments). An array is
specified by using empty brackets. i.e. arg3(). The type of the argument
GUI SPINBOX #ref, startX, This will draw a box with up/down icons on either end. When these icons
startY, width, height, FColour, are touched the number in the box will be incremented or decremented.
BColour, Step, Minimum, Holding down the up/down icons will repeat the step at a fast rate.
Maximum '#ref' is the control's reference number.
'startX' and 'startY' are the top left coordinates while 'width' and 'height' set
the dimensions. ' FColour and 'BColour' are RGB values for the
foreground and background colours.
'width', 'height', FColour and 'BColour' are optional and default to that used
in previous controls.
'Step' sets the amount to increment/decrement the number with each touch.
'Minimum' and 'Maximum' set limits on the number that can be entered.
LONGSTRING TRIM array%(), Will trim ‘nbr’ characters from the left of a long string. array%() must be a
nbr long string variables. 'nbr' must be an integer constant or expression.
LONGSTRING UCASE Will convert any lowercase characters in array%() to uppercase. array%()
array%() must be long string variable.
LOOP [UNTIL expression] Terminates a program loop: see DO.
MATH The math command performs many simple mathematical calculations that
can be programmed in BASIC but there are speed advantages to coding
looping structures in the firmware and there is the advantage that once
debugged they are there for everyone without re-inventing the wheel. Note:
2 dimensional maths matrices are always specified DIM matrix(n_columns,
n_rows) and of course the dimensions respect OPTION BASE. Quaternions
are stored as a 5 element array w, x, y, z, magnitude.
MATH SET nbr, array() Sets all elements in array() to the value nbr. Note this is the fastest way of
clearing an array by setting it to zero.
MATH SCALE in(), scale ,out() This scales the matrix in() by the scalar scale and puts the answer in out().
Works for arrays of any dimensionality of both integer and float and can
convert between. Setting b to 1 is optimised and is the fastest way of
copying an entire array.
MATH V_MULT matrix(), Multiplies matrix() and vector inV() returning vector outV(). The vectors
inV(), outV() and the 2D matrix can be any size but must have the same cardinality.
MATH V_CROSS inV1(), Calculates the cross product of two three element vectors inV1() and inV2()
inV2(), outV() and puts the answer in outV()
Quaternion arithmetic
MATH Q_INVERT inQ(), Invert the quaternion in inQ() and put the answer in outQ()
outQ()
MATH Q_EULER yaw, pitch, Generates a normalised rotation quaternion outRQ() to rotate quaternion
roll, outRQ() vectors as defined by the yaw, pitch and roll angles
With the vector in front of the “viewer” yaw is looking from the top of the
ector and rotates clockwise, pitch rotates the top away from the camera and
roll rotates around the z-axis clockwise.
The yaw, pitch and roll angles default to radians but respect the setting of
OPTION ANGLE
MATH Q_MULT inQ1(), Multiplies two quaternions inQ1() and inQ2() and puts the answer in outQ()
inQ2(), outQ()
Rotates the source quaternion vector inVQ() by the rotate quaternion RQ()
MATH Q_ROTATE , RQ(), and puts the answer in outVQ()
inVQ(), outVQ()
MATH FFT signalarray!(), Performs a fast fourier transform of the data in “signalarray!”. "signalarray"
FFTarray!() must be floating point and the size must be a power of 2 (e.g. s(1023)
assuming OPTION BASE is zero)
"FFTarray" must be floating point and have dimension 2*N where N is the
same as the signal array (e.g. f(1,1023) assuming OPTION BASE is zero)
The command will return the FFT as complex numbers with the real part in
f(0,n) and the imaginary part in f(1,n)
MATH FFT INVERSE Performs an inverse fast fourier transform of the data in “FFTarray!”.
FFTarray!(), signalarray!() "FFTarray" must be floating point and have dimension 2*N where N must
be a power of 2 (e.g. f(1,1023) assuming OPTION BASE is zero) with the
real part in f(0,n) and the imaginary part in f(1,n).
"signalarray" must be floating point and the single dimension must be the
same as the FFT array.
The command will return the real part of the inverse transform in
"signalarray".
MATH FFT MAGNITUDE Generates magnitudes for frequencies for the data in “signalarray!”
signalarray!(),magnitudearray!() "signalarray" must be floating point and the size must be a power of 2 (e.g.
s(1023) assuming OPTION BASE is zero)
"magnitudearray" must be floating point and the size must be the same as
the signal array
The command will return the magnitude of the signal at various frequencies
Notes:
Memory usage is rounded to the nearest 1K byte.
General memory is used by serial I/O buffers, etc.
MEMORY SET address, byte, This command will set a region of memory to a value.
numberofbytes BYTE = One byte per memory address.
SHORT = Two bytes per memory address.
MEMORY SET BYTE address, WORD = Four bytes per memory address.
byte, numberofbytes
FLOAT = Eight bytes per memory address.
‘increment’ is optional and controls the increment of the ‘address’ pointer
MID$( str$, start [, num]) = The characters in 'str$', beginning at position 'start', are replaced by the
str2$ characters in 'str2$'. The optional 'num' refers to the number of characters
from 'str2' that are used in the replacement. If 'num' is omitted, all of 'str2' is
used. Whether 'num' is omitted or included, the replacement of characters
never goes beyond the original length of 'str$'.
NEW Clears the the program memory and all variables including saved variables.
This command also clears the backup copy of the program which is held in
flash memory.
PIO DMA RX pio, sm, nbr, Sets up DMA transfers from PIO to MMBasic memory
data%() [,completioninterrupt] pio specifies which of the two pio instances to use (0 or 1) NB: 0 only for
[,transfersize] [,loopbackcount] the WebMite version
PIO DMA TX pio, sm, nbr, sm specifies which of the state machine to use (0-3)
data%() [,completioninterrupt] nbr specifies how many 32-bit words to transfer
[,transfersize] [,loopbackcount]
data%() is the array that will either supply or receive the PIO data
The optional parameter completioninterrupt is the name of a MMBasic
subroutine rthat will be called when the DMA completes and in the case of
DMA_OUT the FIFO has been emptied.
If the optional interrupt is not used then the status of the DMA can be
checked using the functions
MM.INFO(PIO RX DMA)
MM.INFO(PIO TX DMA)
The optional parameter transfersize allows the user to override the normal
32-bit transfers and select 8, 16, or 32.
The optional parameter loopbackcount specifies how many data items are to
be read or written before the DMA starts again at the beginning of the
PIO INIT MACHINE pio%, Initialises PIO 'pio%' with state machine 'statemachine%'. 'clockspeed' is
statemachine%, clockspeed the clock speed of the state machine in kHz. The four optional arguments
are variables holding initialising values of the state machine registers and
[,pinctrl] [,execctrl] [,shiftctrl]
[,startinstruction] the address of the first instruction to execute (defaults to zero). These
decide how the PIO will operate.
It is anticipated that eventually the PIO assembler will be able to generate
the register values for the user along with the program array based on the
defined assembler directives.
PIO EXECUTE pio, Immediately executes the instruction on the pio and state machine specified.
state_machine, instruction%
PIO WRITE pio, state_machine, Writes the data elements to the pio and state machine specified. The write is
count, data0 [,data1..] blocking so the state machine needs to be able to take the data supplied
NB: this command will probably need additional capability in future
releases
PIO READ pio, state_machine, Reads the data elements from the pio and state machine specified. The read
count, data%[()] is non-blocking so the state machine needs to be able to supply the data
requested. When count is one then an integer can be used to receive the
data, otherwise and integer array should be specified.
NB: this command will probably need additional capability in future
releases
PIO CLEAR pio This stops the pio specified on all statemachines and clears the control
registers for the statemachines PINCTRL, EXECTRL, and SHIFTCTRL to
defaults
PIO PROGRAM LINE pio, line, Programs just the specified line in a PIO program
instruction
PIXEL x, y [,c] Set a pixel on an attached LCD panel to a colour. 'x' is the horizontal
coordinate and 'y' is the vertical coordinate of the pixel. 'c' is a 24 bit
number specifying the colour. 'c' is optional and if omitted the current
foreground colour will be used. All parameters can be expressed as arrays
and the software will plot the number of pixels as determined by the
dimensions of the smallest array. 'x' and 'y' must both be arrays or both be
single variables /constants otherwise an error will be generated. 'c' can be
either an array or a single variable or constant.
See the section Graphics Commands and Functions for a definition of the
colours and graphics coordinates.
PLAY This command will generate a variety of audio outputs.
See the OPTION AUDIO command for setting the I/O pins to be used for
the output. The audio is a pulse width modulated signal so a low pass filter
is required to remove the carrier frequency.
PLAY TONE left [, right [, dur] Generates two separate sine waves on the sound output left and right
[,interrupt]]] channels.
'left' and 'right' are the frequencies in Hz to use for the left and right
channels. The tone plays in the background (the program will continue
running after this command) and 'dur' specifies the number of milliseconds
that the tone will sound for. If the duration is not specified the tone will
continue until explicitly stopped or the program terminates.
'interrupt' is an optional subroutine which will be called when the play
terminates.
The frequency can be from 1Hz to 20KHz and is very accurate (it is based
on a crystal oscillator). The frequency can be changed at any time by
issuing a new PLAY TONE command.
PLAY FLAC file$ [, interrupt] Will play a FLAC file on the sound output.
'file$' is the FLAC file to play (the extension of .wav will be appended if
missing). The sample rate can be up to 48kHz in stereo (96kHz if the Pico
is overclocked)
The FLAC file is played in the background. 'interrupt' is optional and is the
name of a subroutine which will be called when the file has finished
playing.
If file$ is a directory the Pico will play all of the files in that directory in
turn.
PLAY WAV file$ [, interrupt] Will play a WAV file on the sound output.
'file$' is the WAV file to play (the extension of .wav will be appended if
missing). The WAV file must be PCM encoded in mono or stereo with 8 or
16-bit sampling. The sample rate can be up to 48kHz in stereo (96kHz if the
Pico is overclocked).
The WAV file is played in the background. 'interrupt' is optional and is the
name of a subroutine which will be called when the file has finished
playing.
Stops playback of the current audio file and starts the next one in the
PLAY NEXT
directory
Stops playback of the current audio file and starts the previous one in the
PLAY PREVIOUS directory
POKE BYTE addr%, byte Will set a byte or a word within the virtual memory space.
or POKE BYTE will set the byte (i.e. 8 bits) at the memory location 'addr%' to
POKE SHORT addr%, short% 'byte'. 'addr%' should be an integer.
Or POKE SHORT will set the short integer (i.e. 16 bits) at the memory
location
POKE WORD addr%, word%
'addr%' to 'word%'. 'addr%' and short%' should be integers.
or
POKE WORD will set the word (i.e. 32 bits) at the memory location
POKE INTEGER addr%, int%
'addr%' to 'word%'. 'addr%' and 'word%' should be integers.
or
POKE INTEGER will set the MMBasic integer (i.e. 64 bits) at the memory
POKE FLOAT addr%, float! location 'addr%' to int%'. 'addr%' and int%' should be integers.
PWM SYNC s0 This initiates the PWM on channels where a deferred start was defined or
[,s1][,s2][,s3][,s4][,s5][,s6][,s7] just syncs existing running channels. However, the power comes in the
ability to offset the channels one to another (defined as a percentage of the
time period as per the duty cycle - can be a float)
You can use an offset of -1 to omit a channel from the synch
SORT array() [,indexarray()] This command takes an array of any type (integer, float or string) and sorts
[,flags] [,startposition] it into ascending order in place.
[,elementstosort] It has an optional parameter ‘indexarray%()’. If used this must be an integer
array of the same size as the array to be sorted. After the sort this array will
contain the original index position of each element in the array being sorted
before it was sorted. Any data in the array will be overwritten. This allows
connected arrays to be sorted. See the section Sorting Data in the tutorial
Programming with the Colour Maximite 2 for an example.
The ‘flag’ parameter is optional and valid flag values are:
bit0: 0 (default if omitted) normal sort - 1 reverse sort
bit1: 0 (default) case dependent - 1 sort is case independent (strings only).
The optional ‘startposition’ defines which element in the array to start the
sort. Default is 0 (OPTION BASE 0) or 1 (OPTION BASE 1)
The optional ‘elementstosort’ defines how many elements in the array
should be sorted. The default is all elements after the startposition.
Any of the optional parameters may be omitted so, for example, to sort just
the first 50 elements of an array you could use:
SORT array(), , , ,50
SPI OPEN speed, mode, bits Communications via an SPI channel. See Appendix D for the details.
or 'nbr' is the number of data items to send or receive
SPI READ nbr, array() 'data1', 'data2', etc can be float or integer and in the case of WRITE can be a
or constant or expression.
SPI WRITE nbr, data1, data2, If 'string$' is used 'nbr' characters will be sent.
data3, … etc 'array' must be a single dimension float or integer array and 'nbr' elements
or will be sent or received.
SPI WRITE nbr, string$
or
SPI WRITE nbr, array()
or
SPI CLOSE
TRIANGLE RESTORE [#]n Restores a saved triangular region of the screen and deletes the saved
buffer.
UPDATE FIRMWARE Causes the PicoMite to enter the firmware update mode (the same as
applying power while holding down the BOOTSEL button).
Loading the PicoMite firmware will erase the flash memory including the
current program, any programs saved in flash memory slots and all saved
variables. So make sure that you backup this data before you upgrade the
firmware. A firmware load will also reset all options to their defaults.
VAR SAVE var [, var]… VAR SAVE will save one or more variables to non-volatile flash memory
or where they can be restored later (normally after a power interruption).
VAR RESTORE 'var' can be any number of numeric or string variables and/or arrays. Arrays
are specified by using empty brackets. For example: var()
or
VAR RESTORE will retrieve the previously saved variables and insert
VAR CLEAR
them (and their values) into the variable table.
The VAR SAVE command can be used repeatedly. Variables that had been
previously saved will be updated with their new value and any new
variables (not previously saved) will be added to the saved list for later
restoration.
VAR CLEAR will erase all saved variables. Also, the saved variables will
be automatically cleared by a firmware upgrade, by the NEW command or
when a new program is loaded via AUTOSAVE, XMODEM, etc.
This command is normally used to save calibration data, options, and other
data which does not change often but needs to be retained across a power
interruption. Normally the VAR RESTORE command is placed at the start
of the program so that previously saved variables are restored and
immediately available to the program when it starts. Notes:
The storage space available to this command is 16KB.
Using VAR RESTORE without a previous save will have no effect and
will not generate an error.
If, when using RESTORE, a variable with the same name already exists
its value will be overwritten.
Saved arrays must be declared (using DIM) before they can be restored.
Be aware that string arrays can rapidly use up all the memory allocated
ABS( number ) Returns the absolute value of the argument 'number' (i.e. any negative sign
is removed and a positive number is returned).
ACOS( number ) Returns the inverse cosine of the argument 'number' in radians.
ASC( string$ ) Returns the ASCII code (i.e. byte value) for the first letter in ‘string$’.
ASIN( number ) Returns the inverse sine value of the argument 'number' in radians.
ATAN2( y, x ) Returns the arc tangent of the two numbers x and y as an angle expressed in
radians.
It is similar to calculating the arc tangent of y / x, except that the signs of
both arguments are used to determine the quadrant of the result.
BIN$( number [, chars]) Returns a string giving the binary (base 2) value for the 'number'.
'chars' is optional and specifies the number of characters in the string with
zero as the leading padding character(s).
BIN2STR$(type, value [,BIG]) Returns a string containing the binary representation of 'value'.
'type' can be:
INT64 signed 64-bit integer converted to an 8 byte string
UINT64 unsigned 64-bit integer converted to an 8 byte string
INT32 signed 32-bit integer converted to a 4 byte string
UINT32 unsigned 32-bit integer converted to a 4 byte string
INT16 signed 16-bit integer converted to a 2 byte string
UINT16 unsigned 16-bit integer converted to a 2 byte string
INT8 signed 8-bit integer converted to a 1 byte string
UINT8 unsigned 8-bit integer converted to a 1 byte string
SINGLE single precision floating point number converted to a 4 byte
string
DOUBLE double precision floating point number converted to a 8
byte string
By default the string contains the number in little-endian format (i.e. the
least significant byte is the first one in the string). Setting the third
parameter to ‘BIG’ will return the string in big-endian format (i.e. the most
significant byte is the first one in the string) In the case of the integer
conversions, an error will be generated if the ‘value’ cannot fit into the
‘type’ (e.g. an attempt to store the value 400 in a INT8).
This function makes it easy to prepare data for efficient binary file I/O or
for preparing numbers for output to sensors and saving to flash memory.
See also the function STR2BIN
CHOICE(condition, This function allows you to do simple either/or selections more efficiently
ExpressionIfTrue, and faster than using IF THEN ELSE ENDIF clauses.
ExpressionIfFalse) The condition is anything that will resolve to nonzero (true) or zero (false).
The expressions are anything that you could normally assign to a variable or
use in a command and can be integers, floats or strings.
Examples:
PRINT CHOICE(1, "hello","bye") will print "Hello"
PRINT CHOICE (0, "hello","bye") will print "Bye"
a=1 : b=1 : PRINT CHOICE (a=b, 4, 5) will print 4
CINT( number ) Round numbers with fractional portions up or down to the next whole
number or integer.
For example, 45.47 will round to 45
45.57 will round to 46
-34.45 will round to -34
-34.55 will round to -35
See also INT() and FIX().
DATE$ Returns the current date based on MMBasic’s internal clock as a string in
the form "DD-MM-YYYY". For example, "28-07-2012".
The internal clock/calendar will keep track of the time and date including
leap years. To set the date use the command DATE$ =.
DATETIME$(n) Returns the date and time corresponding to the epoch number n (number of
seconds that have elapsed since midnight GMT on January 1, 1970). The
format of the returned string is “dd-mm-yyyy hh:mm:ss”. Use the text
NOW to get the current datetime string, i.e. ? DATETIME$(NOW)
DAY$(date$) Returns the day of the week for a given date as a string “Monday”,
“Tuesday” etc. The format for date$ is "DD-MM-YY", "DD-MM-YYYY",
or "YYYY-MM-DD". Use NOW to get the day for the current date, e.g.
PRINT DAY$(NOW)
DIR$( fspec, type ) Will search the default Flash Filesystem or SD Card for files and return the
or names of entries found.
DIR$( fspec ) 'fspec' is a file specification using wildcards the same as used by the FILES
or command. E.g. "*.*" will return all entries, "*.TXT" will return text files.
DIR$( ) Note that the wildcard *.* does not find files or folders without an
extension.
'type' is the type of entry to return and can be one of:
VOL Search for the volume label only
DIR Search for directories only
FILE Search for files only (the default if 'type' is not specified)
The function will return the first entry found. To retrieve subsequent
entries use the function with no arguments. i.e. DIR$( ). The return of an
empty string indicates that there are no more entries to retrieve.
This example will print all the files in a directory:
f$ = DIR$("*.*", FILE)
DO WHILE f$ <> ""
PRINT f$
f$ = DIR$()
LOOP
You must change to the required directory before invoking this command.
DISTANCE( trigger, echo ) Measure the distance to a target using the HC-SR04 ultrasonic distance
or sensor.
DISTANCE( trig-echo ) Four pin sensors have separate trigger and echo connections. 'trigger' is the
I/O pin connected to the "trig" input of the sensor and 'echo' is the pin
connected to the "echo" output of the sensor.
Three pin sensors have a combined trigger and echo connection and in that
case you only need to specify one I/O pin to interface to the sensor.
Note that any I/O pins used with the HC-SR04 should be 5V capable as the
HC-SR04 is a 5V device. The I/O pins are automatically configured by this
function and multiple sensors can be used on different I/O pins.
The value returned is the distance in centimetres to the target or -1 if no
EOF( [#]fnbr ) Will return true if the file previously opened on the Flash Filesystem or SD
Card for INPUT with the file number ‘#fnbr’ is positioned at the end of the
file.
The # is optional. Also see the OPEN, INPUT and LINE INPUT
commands and the INPUT$ function.
EPOCH(DATETIME$) Returns the epoch number (number of seconds that have elapsed since
midnight GMT on January 1, 1970) for the supplied DATETIME$ string.
The format for DATETIME$ is “dd-mm-yyyy hh:mm:ss”, “dd-mm-yy
hh:mm:ss”, or “yyyy-mm-dd hh:mm:ss”,. Use NOW to get the epoch
number for the current date and time, i.e. PRINT EPOCH(NOW)
EVAL( string$ ) Will evaluate 'string$' as if it is a BASIC expression and return the result.
'string$' can be a constant, a variable or a string expression. The expression
can use any operators, functions, variables, subroutines, etc that are known
at the time of execution. The returned value will be an integer, float or
string depending on the result of the evaluation.
For example: S$ = "COS(RAD(30)) * 100" : PRINT EVAL(S$)
Will display: 86.6025
EXP( number ) Returns the exponential value of 'number', i.e. e^x where x is 'number'.
FIELD$( string1, nbr, string2 [, Returns a particular field in a string with the fields separated by delimiters.
string3] ) 'nbr' is the field to return (the first is nbr 1). 'string1' is the string to search
and 'string2' is a string holding the delimiters (more than one can be used).
'string3' is optional and if specified will include characters that are used to
quote text in 'string1' (ie, quoted text will not be searched for a delimiter).
For example:
S$ = "foo, boo, zoo, doo"
r$ = FIELD$(s$, 2, ",")
will result in r$ = "boo". While:
s$ = "foo, 'boo, zoo', doo"
r$ = FIELD$(s$, 2, ",", "'")
will result in r$ = "boo, zoo".
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 9.89 will return 9 and -2.11 will return -2.
The major difference between FIX() and INT() is that FIX() provides a true
integer function (i.e. does not return the next lower number for negative
numbers as INT() does). This behaviour is for Microsoft compatibility.
See also CINT() .
FORMAT$( nbr [, fmt$] ) Will return a string representing ‘nbr’ formatted according to the
specifications in the string ‘fmt$’.
The format specification starts with a % character and ends with a letter.
Anything outside of this construct is copied to the output as is.
The structure of a format specification is:
% [flags] [width] [.precision] type
GPS() The GPS functions are used to return data from a serial communications
channel opened as GPS.
The function GPS(VALID) should be checked before any of these functions
are used to ensure that the returned value is valid.
GPS(DATE) Returns the normal date string corrected for local time e.g. “12-01-2020”.
GPS(DOP) Returns DOP (dilution of precision) value (if sentence GGA is enabled).
GPS(FIX) Returns non zero (true) if the GPS has a fix on sufficient satellites and is
producing valid data.
GPS(LATITUDE) Returns the latitude in degrees as a floating point number, values are
negative for South of equator
GPS(LONGITUDE) Returns the longitude in degrees as a floating point number, values are
negative for West of the meridian.
GPS(TIME) Returns the normal time string corrected for local time e.g. “12:09:33”.
GPS(TRACK) Returns the track over the ground (degrees true) as a floating point number.
HEX$( number [, chars]) Returns a string giving the hexadecimal (base 16) value for the 'number'.
'chars' is optional and specifies the number of characters in the string with
zero as the leading padding character(s).
INKEY$ Checks the console input buffer and, if there is one or more characters
waiting in the queue, will remove the first character and return it as a single
character in a string.
If the input buffer is empty this function will immediately return with an
empty string (i.e. "").
INPUT$(nbr, [#]fnbr) Will return a string composed of ‘nbr’ characters read from a serial
communications port opened as 'fnbr'. This function will return as many
characters as are waiting in the receive buffer up to ‘nbr’. If there are no
characters waiting it will immediately return with an empty string.
#0 can be used which refers to the console's input buffer.
The # is optional. Also see the OPEN command.
INSTR( [start-position,] string- Returns the position at which 'string-pattern$' occurs in 'string-searched$',
searched$, string-pattern$ ) beginning at 'start-position'. If 'start-position' is not provided it will default
to 1.
Both the position returned and 'start-position' use 1 for the first character, 2
for the second, etc.
The function returns zero if 'string-pattern$' is not found.
INT( number ) Truncate an expression to the next whole number less than or equal to the
argument. For example 9.89 will return 9 and -2.11 will return -3.
This behaviour is for Microsoft compatibility, the FIX() function provides a
true integer function.
See also CINT() .
LCOMPARE(array1%(), Compare the contents of two long string variables array1%() and array2%().
array2%()) The returned is an integer and will be -1 if array1%() is less than array2%().
It will be zero if they are equal in length and content and +1 if array1%() is
greater than array2%(). The comparison uses the ASCII character set and is
case sensitive.
LEFT$( string$, nbr ) Returns a substring of ‘string$’ with ‘nbr' of characters from the left
(beginning) of the string.
LGETBYTE(array%(), n) Returns the numerical value of the 'n'th byte in the LONGSTRING held in
'array%()'. This function respects the setting of OPTION BASE in
determining which byte to return.
LGETSTR$(array%(), start, Returns part of a long string stored in array%() as a normal MMBasic
length) string. The parameters start and length define the part of the string to be
returned.
LOC( [#]fnbr ) For a serial communications port opened as 'fnbr' this function will return
the number of bytes received and waiting in the receive buffer to be read.
#0 can be used which refers to the console's input buffer.
The # is optional.
LOF( [#]fnbr ) For a serial communications port opened as 'fnbr' this function will return
the space (in characters) remaining in the transmit buffer.
Note that when the buffer is full MMBasic will pause when adding a new
character and wait for some space to become available.
The # is optional.
MATH The math function performs many simple mathematical calculations that
can be programmed in Basic but there are speed advantages to coding
looping structures in C and there is the advantage that once debugged they
are there for everyone without re-inventing the wheel.
Simple functions
MATH(CRCn data [,length] Calculates the CRC to n bits (8, 12, 16, 32) of “data”. “data” can be an
[,polynome] [,startmask] integer or floating point array or a string variable. “Length” is optional and
[,endmask] [,reverseIn] if not specified the size of the array or string length is used. The defaults for
startmask, endmask reverseIn, and reversOut are all zero. reverseIn, and
[,reverseOut] reversOut are both Booleans and take the value 1 or 0. The defaults for
polynomes are CRC8=&H07, CRC12=&H80D, CRC16=&H1021,
crc32=&H04C11DB7
e.g. for crc16_CCITT use MATH(CRC16 array(), n,, &HFFFF)
MATH(RAND) Returns a random number 0.0 <= n < 1.0 using the "Mersenne Twister
algorithm. If not seeded with MATH RANDOMIZE the first usage seeds
with the time in microseconds since boot
MATH(CHI a()) Returns the Pearson's chi-squared value of the two dimensional array a())
MATH(CHI_p a()) Returns the associated probability in % of the Pearson's chi-squared value
of the two dimensional array a())
MATH(CORREL a(), a()) Returns the Pearson’s correlation coefficient between arrays a() and b()
MATH(MAX a() [,index%]) Returns the maximum of all values in the a() array, a() can have any
number of dimensions. If the integer variable is specified then it will be
updated with the index of the maximum value in the array. This is only
available on one-dimensional arrays
MATH(MEAN a()) Returns the average of all values in the a() array, a() can have any number
of dimensions
MATH(MEDIAN a()) Returns the median of all values in the a() array, a() can have any number of
dimensions
MATH(MIN a(), [index%]) Returns the minimum of all values in the a() array, a() can have any number
of dimensions. If the integer variable is specified then it will be updated
with the index of the maximum value in the array. This is only available on
one-dimensional arrays.
MATH(SD a()) Returns the standard deviation of all values in the a() array, a() can have
any number of dimensions
Returns the sum of all values in the a() array, a() can have any number of
MATH(SUM a()) dimensions
Vector Arithmetic
MATH(MAGNITUDE v()) Returns the magnitude of the vector v(). The vector can have any number of
elements
MATH(DOTPRODUCT v1(), Returns the dot product of two vectors v1() and v2(). The vectors can have
v2()) any number of elements but must have the same cardinality
Matrix Arithmetic
MATH(M_DETERMINANT Returns the determinant of the array. The array must be square.
array!())
MAX( arg1 [, arg2 [, …]] ) Returns the maximum or minimum number in the argument list.
or Note that the comparison is a floating point comparison (integer arguments
MIN( arg1 [, arg2 [, …]] ) are converted to floats) and a float is returned.
MSGBOX (msg$, b1$ [,b2$ … This function will display a message box on the screen with one to four
b4$]) touch sensitive buttons. All other controls will be disabled until the user
touches one of the buttons. The message box will then be erased, the
previous controls will be restored and the function will return the number of
the button touched (the first button is number one)
'msg$' is the message to display. This can contain one or more tilde
characters (~) which indicate a line break. Up to 10 lines can be displayed
inside the box. 'b1$' is the caption for the first button, 'b2$' is the caption
for the second button, etc. At least one button must be specified and four is
the maximum. Any buttons not included in the argument list will not be
displayed.
OCT$( number [, chars]) Returns a string giving the octal (base 8) representation of 'number'.
'chars' is optional and specifies the number of characters in the string with
zero as the leading padding character(s).
PEEK(BYTE addr%) Will return a byte or a word within the PIC32 virtual memory space.
or BYTE will return the byte (8-bits) located at 'addr%'
PEEK(SHORT addr%) SHORT will return the short integer (16-bits) located at 'addr%'
or
PEEK(WORD addr%) WORD will return the word (32-bits) located at 'addr%'
or
PEEK(INTEGER addr%) INTEGER will return the integer (64-bits) located at 'addr%'
or
PEEK(FLOAT addr%) FLOAT will return the floating point number (32-bits) located at 'addr%'
or
PEEK(VARADDR var) VARADDR will return the address (32-bits) of the variable 'var' in
or memory. An array is specified as var().
PEEK(CFUNADDR cfun) CFUNADDR will return the address (32-bits) of the CFunction 'cfun' in
memory. This address can be passed to another CFunction which can then
or
call it to perform some common process.
PEEK(VAR var, ±offset)
VAR, will return a byte in the memory allocated to 'var'. An array is
or specified as var().
PEEK( VARTBL, ±offset) VARTBL, will return a byte in the memory allocated to the variable table
or maintained by MMBasic. Note that there is a comma after the keyword
PEEK( PROGMEM, ±offset) VARTBL.
PROGMEM, will return a byte in the memory allocated to the program.
Note that there is a comma after the keyword PROGMEM.
Note that 'addr%' should be an integer.
PEEK(BP, n%) peek(bp n%) ' returns the byte at address n% and increments n% to point to
the next byte
peek(sp n%) ' returns the short at address n% and increments n% to point to
PEEK(SP,n%) the next short
peek(wp n%) ' returns the word at address n% and increments n% to point
PEEK(WP,n%) to the next word
PIN( pin ) Returns the value on the external I/O ‘pin’. Zero means digital low, 1
means digital high and for analogue inputs it will return the measured
voltage as a floating point number.
Frequency inputs will return the frequency in Hz. A period input will return
the period in milliseconds while a count input will return the count since
reset (counting is done on the positive rising edge). The count input can be
reset to zero by resetting the pin to counting input (even if it is already so
configured).
This function will also return the state of a pin configured as an output or a
PIO pin.
Also see the SETPIN and PIN() = commands. Refer to the section Using
the I/O pins for a general description of the PicoMite's input/output
capabilities.
PIN( TEMP ) Returns the temperature of the RP2040 chip (see the RP2040 data sheet for
the details)
PIO(DMA RX POINTER) Returns the current data item being written or read by the PIO
PIO(DMA TX POINTER)
PIO (SHIFTCTRL helper function to calculate the value of shiftctrl for the INIT MACHINE
push_threshold command
[,pull_threshold] [,autopush]
[,autopull] [,in_shiftdir]
[,out_shiftdir] [,fjoin_rx]
[,fjoin_tx])
PIO (PINCTRL helper function to calculate the value of pinctrl for the INIT MACHINE
no_side_set_pins command. Note: The pin parameters must be formatted as GPn.
[,no_set_pins] [,no_out_pins]
[,IN base]
[,side_set_base] [,set_base][,
out_base])
PIO (EXECCTRL jmp_pin helper function to calculate the value of execctrl for the INIT MACHINE
,wrap_target, wrap command
[,side_pindir] [,side_en])
PIO (FDEBUG pio) returns the value of the FSDEBUG register for the pio specified
PIO (FSTAT pio) returns the value of the FSTAT register for the pio specified
PIO(FLEVEL pio ,sm, DIR) dir can be RX or TX. Returns the level of the specific fifo
PORT(start, nbr [,start, nbr]…) Returns the value of a number of I/O pins in one operation.
'start' is an I/O pin number and its value will be returned as bit 0. 'start'+1 will
be returned as bit 1, 'start'+2 will be returned as bit 2, and so on for 'nbr'
number of bits. I/O pins used must be numbered consecutively and any I/O
pin that is invalid or not configured as an input will cause an error. The
start/nbr pair can be repeated up to 25 times if additional groups of input pins
need to be added.
This function will also return the state of a pin configured as an output. It
can be used to conveniently communicate with parallel devices like
memory chips. Any number of I/O pins (and therefore bits) can be used
from 1 to the number of I/O pins on the chip.
See the PORT command to simultaneously output to a number of pins.
PIXEL( x, y [,page_number]) Returns the colour of a pixel on an LCD display. 'x' is the horizontal
coordinate and 'y' is the vertical coordinate of the pixel. The display must
use one of the SSD1963, ILI9341, ILI9488, or ST7789_320 controllers.
PULSIN( pin, polarity ) Measures the width of an input pulse from 1µs to 1 second with 0.1µs
or resolution.
PULSIN( pin, polarity, t1 ) 'pin' is the I/O pin to use for the measurement, it must be previously
configured as a digital input. 'polarity' is the type of pulse to measure, if
or
zero the function will return the width of the next negative pulse, if non
PULSIN( pin, polarity, t1, t2 ) zero it will measure the next positive pulse.
't1' is the timeout applied while waiting for the pulse to arrive, 't2' is the
timeout used while measuring the pulse. Both are in microseconds (µs) and
are optional. If 't2' is omitted the value of 't1' will be used for both
timeouts. If both 't1' and 't2' are omitted then the timeouts will be set at
100000 (i.e. 100ms).
This function returns the width of the pulse in microseconds (µs) or -1 if a
timeout has occurred. The measurement is accurate to ±0.5% and
±0.5µsNote that this function will cause the running program to pause while
the measurement is made and interrupts will be ignored during this period.
RIGHT$( string$, number-of- Returns a substring of ‘string$’ with ‘number-of-chars’ from the right (end)
chars ) of the string.
SGN( number ) Returns the sign of the argument 'number', +1 for positive numbers, 0 for 0,
and -1 for negative numbers.
STR$( number ) Returns a string in the decimal (base 10) representation of 'number'.
or If 'm' is specified sufficient spaces will be added to the start of the number
STR$( number, m ) to ensure that the number of characters before the decimal point (including
the negative or positive sign) will be at least 'm' characters. If 'm' is zero or
or
the number has more than 'm' significant digits no padding spaces will be
STR$( number, m, n ) added.
or If 'm' is negative, positive numbers will be prefixed with the plus symbol
STR$( number, m, n, c$ ) and negative numbers with the negative symbol. If 'm' is positive then only
the negative symbol will be used.
'n' is the number of digits required to follow the decimal place. If it is zero
the string will be returned without the decimal point. If it is negative the
output will always use the exponential format with 'n' digits resolution. If 'n'
is not specified the number of decimal places and output format will vary
automatically according to the number.
'c$' is a string and if specified the first character of this string will be used
as the padding character instead of a space (see the 'm' argument).
Examples:
STR$(123.456) will return "123.456"
STR$(-123.456) will return "-123.456"
STR$(123.456, 1) will return "123.456"
STR$(123.456, -1) will return "+123.456"
STR$(123.456, 6) will return " 123.456"
STR$(123.456, -6) will return " +123.456"
STR$(-123.456, 6) will return " -123.456"
STR$(-123.456, 6, 5) will return " -123.45600"
STR2BIN(type, string$ [,BIG]) Returns a number equal to the binary representation in ‘string$’.
‘type’ can be:
INT64 converts 8 byte string representing a signed 64-bit integer to an
integer
UINT64 converts 8 byte string representing an unsigned 64-bit integer to
an integer
INT32 converts 4 byte string representing a signed 32-bit integer to an
integer
UINT32 converts 4 byte string representing an unsigned 32-bit integer to
an integer
INT16 converts 2 byte string representing a signed 16-bit integer to an
integer
UINT16 converts 2 byte string representing an unsigned 16-bit integer to
an integer
INT8 converts 1 byte string representing a signed 8-bit integer to an
integer
UINT8 converts 1 byte string representing an unsigned 8-bit integer to an
integer
SINGLE converts 4 byte string representing single precision float to a float
DOUBLE converts 8 byte string representing single precision float to a
float
By default the string must contain the number in little-endian format (i.e.
the
least significant byte is the first one in the string). Setting the third
parameter to ‘BIG’ will interpret the string in big-endian format (i.e. the
most
significant byte is the first one in the string).
This function makes it easy to read data from binary data files, interpret
numbers from sensors or efficiently read binary data from flash memory
chips.
An error will be generated if the string is the incorrect length for the
conversion requested
See also the function BIN2STR$
STRING$( nbr, ascii ) Returns a string 'nbr' bytes long consisting of either the first character of
or string$ or the character representing the ASCII value 'ascii' which is an
integer or float number in the range of 0 to 255.
STRING$( nbr, string$ )
TAB( number ) Outputs spaces until the column indicated by 'number' has been reached on
the console output.
TIME$ Returns the current time based on MMBasic's internal clock as a string in
the form "HH:MM:SS" in 24 hour notation. For example, "14:30:00".
To set the current time use the command TIME$ = .
TIMER Returns the elapsed time in milliseconds (e.g. 1/1000 of a second) since
reset.
The timer is reset to zero on power up or a CPU restart and you can also
reset it by using TIMER as a command. If not specifically reset it will
continue to count up forever (it is a 64 bit number and therefore will only
roll over to zero after 200 million years).
VAL( string$ ) Returns the numerical value of the ‘string$’. If 'string$' is an invalid
number the function will return zero.
This function will recognise the &H prefix for a hexadecimal number, &O
for octal and &B for binary.
Note that these commands may be removed in the future to recover memory for other features.
GOSUB target Initiates a subroutine call to the target, which can be a line number or a label.
The subroutine must end with RETURN.
New programs should use defined subroutines (i.e. SUB…END SUB).
IF condition THEN linenbr For Microsoft compatibility a GOTO is assumed if the THEN statement is
followed by a number. A label is invalid in this construct.
New programs should use: IF condition THEN GOTO linenbr | label
IRETURN Returns from an interrupt when the interrupt destination was a line number
or a label.
New programs should use a user defined subroutine as an interrupt
destination. In that case END SUB or EXIT SUB will cause a return from
the interrupt.
ON nbr GOTO | GOSUB ON either branches (GOTO) or calls a subroutine (GOSUB) based on the
target[,target, target,..] rounded value of 'nbr'; if it is 1, the first target is called, if 2, the second
target is called, etc. Target can be a line number or a label.
New programs should use SELECT CASE.
POS For the console, returns the current cursor position in the line in characters.
I/O Pins
Before a serial interface can be used the I/O pins must be defined using the following command for the first
channel (referred as COM1):
SETPIN rx, tx, COM1
Valid pins are RX: GP1, GP13 or GP17
TX: GP0, GP12, GP16 or GP28
And the following command for the second channel (referred to as COM2):
SETPIN rx, tx, COM2
Valid pins are RX: GP5, GP9 or GP21
TX: GP4, GP8 or GP20
TX is data from the PicoMite and RX is data to it.
The signal polarity is standard for devices running at TTL voltages. Idle is voltage high, the start bit is voltage
low, data uses a high voltage for logic 1 and the stop bit is voltage high. These signal levels allow you to
directly connect to devices like GPS modules (which generally use TTL voltage levels).
Commands
After being opened the serial port will have an associated file number and you can use any commands that operate
with a file number to read and write to/from it. A serial port can be closed using the CLOSE command.
The following is an example:
SETPIN GP13, GP16, COM1 ' assign the I/O pins for the first serial port
OPEN "COM1:4800" AS #5 ' open the first serial port with a speed of 4800 baud
PRINT #5, "Hello" ' send the string "Hello" out of the serial port
dat$ = INPUT$(20, #5) ' get up to 20 characters from the serial port
CLOSE #5 ' close the serial port
Examples
Opening a serial port using all the defaults:
OPEN "COM1:" AS #2
Opening a serial port specifying only the baud rate (4800 bits per second):
OPEN "COM1:4800" AS #1
Opening a serial port specifying the baud rate (9600 bits per second) and receive buffer size (1KB):
OPEN "COM2:9600, 1024" AS #8
The same as above but with two stop bits enabled:
OPEN "COM2:9600, 1024, S2" AS #8
An example specifying everything including an interrupt, an interrupt level, and two stop bits:
OPEN "COM2:19200, 1024, ComIntLabel, 256, S2" AS #5
Interrupts
The interrupt subroutine (if specified) will operate the same as a general interrupt on an external I/O pin (see
the section Using the I/O pins for a description).
When using interrupts you need to be aware that it will take some time for MMBasic to respond to the interrupt
and more characters could have arrived in the meantime, especially at high baud rates. For example, if you
have specified the interrupt level as 200 characters and a buffer of 256 characters then quite easily the buffer
will have overflowed by the time the interrupt subroutine can read the data. In this case the buffer should be
increased to 512 characters or more.
I/O Pins
Before the I2C interface can be used the I/O pins must be defined using the following command for the first
channel (referred as I2C):
SETPIN sda, scl, I2C
Valid pins are SDA: GP0, GP4, GP8, GP12, GP16, GP20 or GP28
SCL: GP1, GP5, GP9, GP13, GP17 or GP21
And the following command for the second channel (referred to as I2C2):
SETPIN sda, scl, I2C2
Valid pins are SDA: GP2, GP6, GP10, GP14, GP18, GP22 or GP26
SCL: GP3, GP7, GP11, GP15, GP19 or GP27
2
When running the I C bus at above 100 kHz the cabling between the devices becomes important. Ideally the
cables should be as short as possible (to reduce capacitance) and the data and clock lines should not run next to
each other but have a ground wire between them (to reduce crosstalk).
If the data line is not stable when the clock is high, or the clock line is jittery, the I2C peripherals can get
"confused" and end up locking the bus (normally by holding the clock line low). If you do not need the higher
speeds then operating at 100 kHz is the safest choice.
I2C OPEN speed, Enables the I2C module in master mode. The I2C command refers to channel 1
timeout while the command I2C2 refers to channel 2 using the same syntax.
‘speed’ is the clock speed (in KHz) to use and must be either 100 or 400.
‘timeout’ is a value in milliseconds after which the master send and receive
commands will be interrupted if they have not completed. The minimum value is
100. A value of zero will disable the timeout (though this is not recommended).
I2C WRITE addr, Send data to the I2C slave device. The I2C command refers to channel 1 while the
option, sendlen, command I2C2 refers to channel 2 using the same syntax.
senddata [,sendata ..] ‘addr’ is the slave’s I2C address.
‘option’ can be 0 for normal operation or 1 to keep control of the bus after the
command (a stop condition will not be sent at the completion of the command)
‘sendlen’ is the number of bytes to send.
‘senddata’ is the data to be sent - this can be specified in various ways (all data
sent will be sent as bytes with a value between 0 and 255):
The data can be supplied as individual bytes on the command line.
Example: I2C WRITE &H6F, 0, 3, &H23, &H43, &H25
The data can be in a one dimensional array specified with empty brackets (i.e.
no dimensions). ‘sendlen’ bytes of the array will be sent starting with the first
element. Example: I2C WRITE &H6F, 0, 3, ARRAY()
The data can be a string variable (not a constant).
Example: I2C WRITE &H6F, 0, 3, STRING$
I2C CLOSE Disables the master I2C module and returns the I/O pins to a "not configured" state.
This command will also send a stop if the bus is still held.
I2C SLAVE OPEN Enables the I2C module in slave mode. The I2C command refers to channel 1
addr, send_int, while the command I2C2 refers to channel 2 using the same syntax.
rcv_int ‘addr’ is the slave I2C address.
‘send_int’ is the subroutine to be invoked when the module has detected that the
master is expecting data.
‘rcv_int is the subroutine to be called when the module has received data from the
master. Note that this is triggered on the first byte received so your program might
need to wait until all the data is received.
I2C SLAVE WRITE Send the data to the I2C master. The I2C command refers to channel 1 while the
sendlen, senddata command I2C2 refers to channel 2 using the same syntax.
[,sendata ..] This command should be used in the send interrupt (ie in the 'send_int' subroutine
when the master has requested data). Alternatively, a flag can be set in the
interrupt subroutine and the command invoked from the main program loop when
the flag is set.
‘sendlen is the number of bytes to send.
‘senddata’ is the data to be sent. This can be specified in various ways, see the I2C
WRITE commands for details.
I2C SLAVE READ Receive data from the I2C master device. The I2C command refers to channel 1
rcvlen, rcvbuf, rcvd while the command I2C2 refers to channel 2 using the same syntax.
This command should be used in the receive interrupt (ie in the 'rcv_int' subroutine
when the master has sent some data). Alternatively a flag can be set in the receive
interrupt subroutine and the command invoked from the main program loop when
the flag is set.
‘rcvlen’ is the maximum number of bytes to receive.
‘rcvbuf’ is the variable to receive the data. This can be specified in various ways,
see the I2C READ commands for details.
‘rcvd’ is a variable that, at the completion of the command, will contain the actual
number of bytes received (which might differ from ‘rcvlen’).
I2C SLAVE CLOSE Disables the slave I2C module and returns the external I/O pins to a "not
configured" state. They can then be configured using SETPIN.
7-Bit Addressing
The standard addresses used in these commands are 7-bit addresses (without the read/write bit). MMBasic will
add the read/write bit and manipulate it accordingly during transfers.
Some vendors provide 8-bit addresses which include the read/write bit. You can determine if this is the case
because they will provide one address for writing to the slave device and another for reading from the slave. In
these situations you should only use the top seven bits of the address. For example: If the read address is 9B
(hex) and the write address is 9A (hex) then using only the top seven bits will give you an address of 4D (hex).
Another indicator that a vendor is using 8-bit addresses instead of 7-bit addresses is to check the address range.
All 7-bit addresses should be in the range of 08 to 77 (hex). If your slave address is greater than this range then
probably your vendor has provided an 8-bit address.
Examples
As an example of a simple communications where the PicoMite is the master, the following program
will read and display the current time (hours and minutes) maintained by a PCF8563 real time clock
chip connected to the second I2C channel:
DIM AS INTEGER RData(2) ' this will hold received data
SETPIN GP6, GP5, I2C2 ' assign the I/O pins for I2C2
I2C2 OPEN 100, 1000 ' open the I2C channel
I2C2 WRITE &H51, 0, 1, 3 ' set the first register to 3
I2C2 READ &H51, 0, 2, RData() ' read two registers
I2C2 CLOSE ' close the I2C channel
PRINT "Time is " RData(1) ":" RData(0)
This is an example of communications between two PicoMites where one is the master and the other
is the slave.
First the master:
SETPIN GP2, GP3, I2C2
I2C2 OPEN 100, 1000
i = 10
DO
i = i + 1
a$ = STR$(i)
I2C2 WRITE &H50, 0, LEN(a$), a$
PAUSE 200
I2C2 READ &H50, 0, 8, a$
PRINT a$
PAUSE 200
LOOP
SUB rint
LOCAL count, a$
I2C2 SLAVE READ 10, a$, count
PRINT LEFT$(a$, count)
END SUB
SUB tint
LOCAL a$ = Time$
I2C2 SLAVE WRITE LEN(a$), a$
END SUB
After the command is executed, the I/O pin will be set to the not configured state unless flag option 8 is used.
When a reset is requested the automatic variable MM.ONEWIRE will return true if a device was found. This
will occur with the ONEWIRE RESET command and the ONEWIRE READ and ONEWIRE WRITE
commands if a reset was requested (flag = 1 or 2).
The 1-Wire protocol is often used in communicating with the DS18B20 temperature measuring sensor and to
help in that regard MMBasic includes the TEMPR() function which provides a convenient method of directly
reading the temperature of a DS18B20 without using these functions.
I/O Pins
Before an SPI interface can be used the I/O pins for the channel must be allocated using the following
commands. For the first channel (referred as SPI) it is:
SETPIN rx, tx, clk, SPI
Valid pins are RX: GP0, GP4, GP16 or GP20
TX: GP3, GP7 or GP19
CLK: GP2, GP6 or GP18
And the following command for the second channel (referred to as SPI2) is:
SETPIN rx, tx, clk, SPI2
Valid pins are RX: GP8, GP12 or GP28
TX: GP11, GP15 or GP27
CLK: GP10, GP14 or GP26
TX is data from the PicoMite and RX is data to it.
SPI Open
To use the SPI function the SPI channel must be first opened.
The syntax for opening the first SPI channel is (use SPI2 for the second channel):
SPI OPEN speed, mode, bits
Where:
‘speed’ is the speed of the clock. It is a number representing the clock speed in Hz.
'mode' is a single numeric digit representing the transmission mode – see Transmission Format below.
'bits' is the number of bits to send/receive. This can be any number in the range of 4 to 16 bits.
It is the responsibility of the program to separately manipulate the CS (chip select) pin if required.
Transmission Format
The most significant bit is sent and received first. The format of the transmission can be specified by the 'mode'
as shown below. Mode 0 is the most common format.
Mode Description CPOL CPHA
0 Clock is active high, data is captured on the rising edge and output on the falling edge 0 0
1 Clock is active high, data is captured on the falling edge and output on the rising edge 0 1
2 Clock is active low, data is captured on the falling edge and output on the rising edge 1 0
3 Clock is active low, data is captured on the rising edge and output on the falling edge 1 1
For a more complete explanation see: http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus
Standard Send/Receive
When the first SPI channel is open data can be sent and received using the SPI function (use SPI2 for the
second channel). The syntax is:
received_data = SPI(data_to_send)
Note that a single SPI transaction will send data while simultaneously receiving data from the slave.
‘data_to_send’ is the data to send and the function will return the data received during the transaction.
‘data_to_send’ can be an integer or a floating point variable or a constant.
If you do not want to send any data (i.e. you wish to receive only) any number (e.g. zero) can be used for the
data to send. Similarly if you do not want to use the data received it can be assigned to a variable and ignored.
SPI Close
If required the first SPI channel can be closed as follows (the I/O pins will be set to inactive):
SPI CLOSE
Use SPI2 for the second channel.
Examples
The following example shows how to use the SPI port for general I/O. It will send a command 80 (hex) and
receive two bytes from the slave SPI device using the standard send/receive function:
PIN(10) = 1 : SETPIN 10, DOUT ' pin 10 will be used as the enable signal
SETPIN GP20, GP3, GP2, SPI ' assign the I/O pins
SPI OPEN 5000000, 3, 8 ' speed is 5 MHz and the data size is 8 bits
PIN(10) = 0 ' assert the enable line (active low)
junk = SPI(&H80) ' send the command and ignore the return
byte1 = SPI(0) ' get the first byte from the slave
byte2 = SPI(0) ' get the second byte from the slave
PIN(10) = 1 ' deselect the slave
SPI CLOSE ' and close the channel
The following is similar to the example given above but this time the transfer is made using the bulk
send/receive commands:
OPTION BASE 1 ' our array will start with the index 1
DIM data%(2) ' define the array for receiving the data
SETPIN GP20, GP3, GP2, SPI ' assign the I/O pins
PIN(10) = 1 : SETPIN 10, DOUT ' pin 10 will be used as the enable signal
SPI OPEN 5000000, 3, 8 ' speed is 5 MHz, 8 bits data
PIN(10) = 0 ' assert the enable line (active low)
SPI WRITE 1, &H80 ' send the command
SPI READ 2, data%() ' get two bytes from the slave
PIN(10) = 1 ' deselect the slave
SPI CLOSE ' and close the channel
Before a state machine can execute it's program, the program needs to be written to PIO memory,
and the state machine needs to be configured.
This appendix describes the support MMBasic can give in using PIO. It does not contain an
explanation how to write PIO statemachine programs. For better understanding how the PIO
statemachines work look at following thread "PIO explained PICOMITE" on the thebackshed.com
forum:
https://www.thebackshed.com/forum/ViewTopic.php?FID=16&TID=15385
Overview of PIO
A single PIO block has four independent state machines. All four state machines share a single 32
instruction program area of flash memory. This memory has write-only access from the main system,
but has four read ports, one for each state machine, so that each can access it independently at its
own speed. Each state machine has its own program counter.
Each state machine also has two 32-bit "scratchpad" registers, X and Y, which can be used as
temporary data stores.
I/O pins are accessed via an input/output mapping module that can access 32 pins (but limited to 30
for the RP2040). All state machines can access all the pins independently and simultaneously.
The system can write data into the input end of a 4-word 32-bit wide TX FIFO buffer. The state
machine can then use pull to move the output word of the FIFO into the OSR (Output Shift Register).
It can also use out to shift 1-32 bits at a time from the OSR into the output mapping module or other
destinations. AUTOPULL can be used to automatically pull data until the TX FIFO is empty or
reaches a preset level.
The system can read data from the output end of a 4-word 32-bit wide RX FIFO buffer. The state
machine can then use in to shift 1-32 bits of data at a time from the input mapping module into the
ISR (Input Shift Register). It can also use push to move the contents of the ISR into the FIFO.
AUTOPUSH can be used to automatically push data until the RX FIFO is full or reaches a preset
level.
The FIFO buffers can be reconfigured to form a single direction 8-word 32-bit FIFO in a single
direction. The buffers allow data to be passed to and from the state machines without either the
system or the state machine having to wait for the other.
Each of the four state machines in the PIO has four registers associated with it:
• CLKDIV is the clock divider, which has a 16-bit integer divider and an 8-bit fractional divider.
This sets how fast the state machine runs. It divides down from the main system clock.
• EXECCTRL holds information controlling the translation and execution of the program
memory
• PINCTRL controls which and how the GPIO pins are used.
The four state machines of a PIO have shared access to its block of 8 interrupt flags. Any state
machine can use any flag. They can set, reset or wait for them to change. In this way they can be
made to run synchronously if required. The lower four flags are also accessible to and from the main
system, so the PIO can be controlled or pass interrupts back.
DMA can be used to pass information to and from the PIO block via its FIFO from the RP2040's
memory
A PIO has nine possible programming instructions, but there can be many variations on each one.
For example, Mov can have up to 8 sources, 8 destinations, 3 process operations during the copy,
with optional delay and/or side set operations!
• Jmp Jump to an absolute address in program memory if a condition is true (or instantly).
• Push Push the contents of the ISR into the RX FIFO as a single 32-bit word.
• Pull Load a 32-bit word from the TX FIFO into the OSR.
Instructions are all 16-bit and contain both the instruction and all data associated with it. All
instructions operate in 1 clock cycle, but it is possible to introduce a delay of several idle clock cycles
between an instruction and the next.
Additionally, there is a facility called "side-set" which allows a value to be written to some pre-defined
output pins while an instruction is being read from memory. This is transparent to the program.
Programming PIO
Picomite programs the PIO statemachine memory using one of the following commands. Each option
will be explained with an example of the exact same program that toggles one of the GPIO lines of
the Picomite. Which GPIO line is toggled, is determined in the configuration.
PIO ASSEMBLE
This command is used to use the build in assembler to generate the program from mnemonics, then
write it directly into PIO memory.
PIO PROGRAM
This command writes all 32 lines in one PIO from an array. This is useful once a PIO program is
debugged. It is extremely compact.
Dim a%(7)=(&h0001E0000E001E081,0,0,0,0,0,0,0)
PIO program 1,a%()
Configuring PIO
The Picomite can configure each state machine individually. Configuration allows 2 state machines to
run the exact same program lines (e.g. an SPI interface) but operate with different GPIO pins and at
different speeds. There are several configuration fields.
FREQUENCY
Picomite contains a default configuration for each configuration field, except for the frequency. The
frequency is set by a 16 bit divider from the ARM clock. Example: when OPTION CPUSPEED
126000 is set the PIO can run at speeds between 126MHz and 1.922kHz (126000000 / 65536). Be
aware that higher CPU speeds (overclocking) directly impact the state machine frequency.
PIN CONTROL
Picomite defaults the GPIO pins for use by MMBasic. For the PIO to take ownership of a GPIO pin
MMBasic needs to assign it to PIO as below.
A state machine can SET the state of a pin (SET is a state machine instruction), but can also output
serial data to one or more GPIO pins using the OUT instruction. Or read serial data using the IN
instruction. And GPIO pins can be set as a side effect of any state machine instruction (SIDE SET).
For each method of interfacing, different pins can be mapped to the state machine.
It is important to understand is that these instructions work on consecutive pins. This means that
there is a range of pins that can be controlled, starting at the lowest GPx pin number (e.g. GP0), and
pins next to it can be included (up to 5 pins in total). So GP0,GP1,GP2 is a valid set of IO pins.
GP0,GP1,GP6 is not. Consider this when designing a PIO application.
Assigning GPIO pins to a state machine uses the PIO helper function:
PIO(PINCTRL a,b,c,d,e,f,g)
a/ the number of SIDE SET pins (0...5), SIDE SET can write 5 pins at once
b/ the number of SET pins (0...5), SET can write 5 pins at once
c/ the number of OUT pins (0...31), OUT can write 32 pins at once
d/ the lowest pin for IN pins (GP0.....GP31) IN can read up to 32 pins at once
e/ the lowest pin for SIDE SET (GP0.....GP31)
f/ the lowest pin for SET (GP0.....GP31)
g/ the lowest pin for OUT (GP0.....GP31)
If we want the program flow to change in response of a GPIO pin state, a JMP PIN is used. The JMP
pin is assigned in the execute control configuration (there can only be 1 pin per state machine) and
the JMP happens only when the pin is high).
The state machine program starts at the beginning and runs until it reaches the end. In above demo
program, the program loops from the end to beginning using a (unconditional) JMP instruction. An
alternative way to using the JMP instruction is defining the beginning of the loop (WRAP TARGET =
line 1) and end of the loop (WRAP = line 2) and configure the state machine to only execute these
instructions in between. The JMP instruction in line 3 is obsolete when WRAP/WRAP TARGET is
used.
PIO(EXECCTRL a,b,c)
SHIFT CONTROL
The IN and OUT instructions shift data from the FIFO register to the GPIO pins. In between MMBasic
and the PIO, 32bit words can be communicated. Since both the ARM cores and the PIO processors
operate independently, the data is exchanged through FIFO's. The ARM (MMBasic) puts data in the
FIFO, PIO reads it. This uses the TX FIFO. The other way around uses the RX FIFO. The FIFO's are
normally 4 words deep but can be configured to a single 8 word deep RX or TX FIFO.
The PIO can "shift" data IN the RX FIFO from the MSB side, or from the LSB side. That is set with
the IN SHIFTDIR bit. Similar the OUT SHIFTDIR bit for OUT data. The autopull and autopush flags in
combination with the pull and push thresholds determine when FIFO is replenished.
PIO(SHIFTCTRL a,b,c,d,e,f,g,h)
a/ the PIO (0 or 1)
b/ the state machine number (0...3)
c/ frequency (CPUSPEED/65536...CPUSPEED in Hz)
d/ pincontrol value (PIO(PINCTRL ......))
e/ execture control value (PIO(EXECCTRL......))
f/ shiftcontrol value (PIO(SHIFCTRL......))
g/ start address (0....31, the line at which the state machine starts executing)
Note that when stopping a state machine, it stops right where it is. To restart the state machine it is
advisable to PIO INIT MACHINE first.
EXAMPLE PROGRAM 1
A complete PIO implementation that toggles a GPIO pins can be implemented in MMBasic as shown
below. Connect a buzzer to GP0, and hear the audio tone generated by the PIO.
'program pio 1 using an array to write the program in PIO memory, and start
Dim a%(7)=(&h0001E000E001E081,0,0,0,0,0,0,0)
PIO program 1,a%()
Note that the MMBasic program ends, but the sound on the buzzer continues. PIO is independent of
the ARM processor, and continues until it is stopped. Entering the MMBasic editor stops the PIO.
FIFO's
MMBasic and the PIO exchange information using FIFO's. The PIO's PUSH data into the RX FIFO
(MMBasic is the receiver), or PULL data from the TX FIFO (MMBasic is the transmitter).
When PIO is fetching data from the FIFO the data is transferred to the OSR (Output Shift Register),
from there is can be processed. The PIO can push the data from the ISR (Input shift register) into the
FIFO. Additionally, the PIO has 2 registers X and Y that can be used for storage, or counting. PIO
cannot add or subtract or compare.
Data flow:
a/ PIO number (0 or 1)
b/ state machine number (0...3)
c/ number of 32 bit words (1...4)
d/ integer variable name (i.e. variable% or array%())
PIO CLEAR clears all the PIO FIFO's, as does PIO START and PIO INIT MACHINE.
The MMBAsic program doesn't need to wait for data in the FIFO to appear since the RX FIFO can be
assigned an interrupt. The MMBasic interrupt routine can fetch the data from the FIFO.
Similar for TX interrupt in which case MMBasic gets an interrupt when data is needed for the TX
FIFO.
a/ PIO (0 or 1)
b/ state machine (0...3)
c/ Name of RX interrupt handler (i.e. "myRX_Interrupt" or 0 to disable)
d/ Name of TX interrupt handler (i.e. "myTX_Interrupt" or 0 to disable)
EXAMPLE PROGRAM 2
Below program explains many of the above presented MMbasic functions and commands. The
program reads a NES controller (SPI) connected to the Picomite. The NES controller consists of a
HEF4021 shift register connected to 8 push button switches.
Program uses: wrap and wrap target, IN, side set and delay, PUSH, PIO READ. GP0 and GP1 are in
SET for pin direction, and in side set for compact code.
'PIO program
PIO assemble 1,".program NES" 'a program needs a name
PIO assemble 1,".side_set 2" 'use 2 bits for side set, 3 for delay
PIO assemble 1,".line 0" 'start code at line 0
PIO assemble 1,"SET pindirs,&b11" 'set GP0,GP1 output, side GP0,GP1 low
PIO assemble 1,".wrap target" 'wrap target = top of the loop
PIO assemble 1,"IN null,32 side 2" 'set ISR to 0, GP1 high (load), GP0 low
PIO assemble 1,"SET X,7 side 0" 'set X counter to 7, GP0,GP1 low
PIO assemble 1,"loop:" 'inner loop label
PIO assemble 1,"IN pins,1 side 0" 'shift 1 databit in, keep GP0,GP1 low
PIO assemble 1,"JMP X-- loop side 1" 'jmp to loop, dec. X, GP0 high(clock), GP1 low
PIO assemble 1,"PUSH side 0 [7]" 'now X=0, PUSH result into FIFO, delay 7
PIO assemble 1,".wrap" 'end outer loop, repeat
PIO assemble 1,".end program list" 'end of program, list result
'configure pio1
p=Pio(pinctrl 2,2,,gp2,gp0,gp0,) 'GP0,GP1 out (SET and SIDE SET), GP2 IN
When reading from the FIFO the DMA controller waits on data being in the FIFO and when it appears
transfers that data into processor memory. Each time it reads it increments the pointer into the
processor memory so that it can, for example, incrementally fill an array as each and every data item
is made available.
When writing to the FIFO the DMA controller writes data from processor memory to the FIFO
automatically waiting whenever the FIFO is full. Thus, data can be prepared in an array and the DMA
controller will stream that data to the PIO FIFO as fast as the PIO program requires it.
DMA can transfer a 32-bit word, a 16-bit short, or an 8-bit byte and when setting up DMA you need to
tell it the size of the tranfer and how many transfers to make. Because each transfer will increment
the memory pointer by 1,2, or 4 bytes MMBasic must deal with the data packed into memory rather
than the 64-bits used for MMbasic integers and floats. Luckily MMBasic implements two commands
MEMORY PACK and MEMORY UNPACK to do this very efficiently but it could equally be done using
standard BASIC arithmetic.
The DMA can be configured to repeatedly loop data into or out of a section of memory (a ring buffer)
a/ pio (0 or 1)
b/ state machine (0...3)
c/ nbr (number of words to be transferred)
d/ data%() (interger array name)
e/ completioninterrupt (where to go when done, optional)
f/ transfersize (8/16/32, optional)
g/ loopbackcount (used data%() as a ring buffer, optional, loopbackcount = 2^n)
The DMA will start the state machine automatically and there is no need for a PIO START command.
Example :
DIM packed%
This can then be used by the DMA for a loopbackcounter with DMA of 1024 32-bit words, 2048 16-bit
shorts or 4096 8-bit bytes
EXAMPLE PROGRAM 3
This program brings everything together and uses DMA to read 128 samples from the PIO RX FIFO.
For the demonstration, GP0 to GP5 are outputs of 3 PWMS, and are ,at the same time, sampled by
the PIO as a 6 channel logic analyser or oscilloscope. The 128 samples are sent to the serial port as
waveforms.
This program also demonstrates PIO DMA RX, MEMORY UNPACK, the use of buffers.
'generate a 50Hz 3 phase test signal to demonstrate the DMA on 6 GPIO pins.
SetPin gp0,pwm 'CH 0a
SetPin gp1,pwm 'CH 0b
SetPin gp2,pwm 'CH 1a
SetPin gp3,pwm 'CH 1b
SetPin gp4,pwm 'CH 2a
SetPin gp5,pwm 'CH 2b
PIO assemble 1,"IN pins,6" ‘'get 6 bits from GPIO pins (GP0..GP5)
PIO assemble 1,"PUSH block" 'only push data when FIFO has room
'configuration
f=1e4 'PIO run at 10kHz
p=Pio(pinctrl 0,0,0,gp0,,,) 'IN base = GP0
e=Pio(execctrl gp0,PIO(.wrap target),PIO(.wrap)) 'wrap 1 to 0, gp0 is default not used
s=Pio(shiftctrl 0,0,0,0,0,0) 'shift in through LSB, out is not used
'write the configuration, running 10kHz (data in FIFO 10us after rising edge GP0)
PIO init machine 1,0,f,p,e,s,0 'start address = 0
'get the data from the packed DMA buffer and unpack to original 32 bit format
Memory unpack packed%(),data%(),2*length%,32
The PicoMite is programmed using the BASIC programming language. The PicoMite version of
BASIC is called MMBasic which loosely emulates the Microsoft BASIC interpreter that was popular
years ago.
The BASIC language was introduced in 1964 by Dartmouth College in the USA as a computer
language for teaching programming and accordingly it is easy to use and learn. At the same time, it
has proved to be a competent and powerful programming language and as a result it became very
popular in the late 70s and early 80s. Even today some large commercial data systems are still written
in the BASIC language (primarily Pick Basic).
For the PicoMite the greatest advantage of BASIC is its ease of use. Some more modern languages
such as C and C++ can be truly mind bending but with BASIC you can start with a one line program
and get something sensible out of it. MMBasic is also powerful in that you can draw sophisticated
graphics, manipulate the external I/O pins to control other devices and communicate with other
devices using a range of built-in communications protocols.
Command Prompt
Interaction with MMBasic is done via the console at the command prompt (ie, the greater than symbol
(>) on the console). On startup MMBasic will issue the command prompt and wait for some
command to be entered. It will also return to the command prompt if your program ends or if it
generated an error message.
When the command prompt is displayed you have a wide range of commands that you can enter and
execute. Typically they would list the program held in memory (LIST) or edit it (EDIT) or perhaps
set some options (the OPTION command). Most times the command is just RUN which instructs
MMBasic to run the program held in program memory.
Almost any command can be entered at the command prompt and this is often used to test a command
to see how it works. A simple example is the PRINT command (more on this later), which you can
test by entering the following at the command prompt:
PRINT 2 + 2
and not surprisingly MMBasic will print out the number 4 before returning to the command prompt.
This ability to test a command at the command prompt is useful when you are learning to program in
BASIC, so it would be worthwhile having the PicoMite handy for the occasional test while you are
working through this tutorial.
Structure of a BASIC Program
A BASIC program starts at the first line and continues until it runs off the end or hits an END
command - at which point MMBasic will display the command prompt (>) on the console and wait for
something to be entered.
A program consists of a number of statements or commands, each of which will cause the BASIC
interpreter to do something (the words statement and command generally mean the same and are used
interchangeable in this tutorial).
Normally each statement is on its own line but you can have multiple statements in the one line
separated by the colon character (:).
For example;
A = 24.6 : PRINT A
Older BASIC programs used the command REM to start a comment and you can also use that if you
wish but the single quote character is easier to use and more convenient.
The PRINT Command
There are a number of common commands that are fundamental and we will cover them in this
tutorial but arguably the most useful is the PRINT command. Its job is simple; to print something on
the console. This is mostly used to output data for you to see (like the result of calculations) or
provide informative messages.
PRINT is also useful when you are tracing a fault in your program; you can use it to print out the
values of variables and display messages at key stages in the execution of the program.
In its simplest form the command will just print whatever is on its command line. So, for example:
PRINT 54
will display on the console the number 54 followed by a new line.
The data to be printed can be something simple like this or an expression, which means something to
be calculated. We will cover expressions in more detail later but as an example the following:
> PRINT 3/21
0.1428571429
>
would calculate the result of three divided by twenty one and display it. Note that the greater than
symbol (>) is the command prompt produced by MMBasic – you do not type that in.
The output is shown in the following screen grab, which also shows a listing of the program.
You need to work through the logic of this example line by line to understand what it is doing.
Essentially it consists of one loop inside another. The inner loop, which increments the variable
nbr2 prints one horizontal line of the table. When this loop has finished it will execute the following
PRINT command which has nothing to print - so it will simply output a new line (ie, terminate the
line printed by the inner loop).
The program will then execute another iteration of the outer loop by incrementing nbr1 and
re-executing the inner loop again. Finally, when the outer loop is exhausted (when nbr1 exceeds 10)
the program will reach the end and terminate.
One last point, you can omit the variable name from the NEXT statement and MMBasic will guess
which variable you are referring to. However, it is good practice to include the name to make it easier
for someone else who is reading the program to understand it. You can also terminate multiple loops
using a comma separated list of variables in the NEXT statement. For example:
FOR var1 = 1 TO 5
FOR var2 = 10 to 13
PRINT var1 * var2
NEXT var1, var2
The INPUT command can also print your prompt for you, so that you do not need a separate PRINT
command. For example, this will work the same as the above program:
INPUT "Length of side 1"; a
INPUT "Length of side 2"; b
PRINT "Length of the hypotenuse is" SQR(a * a + b * b)
Finally, the INPUT command will allow you to input a series of numbers separated by commas with
each number being saved in different variables.
For example:
INPUT "Enter the length of the two sides: ", a, b
PRINT "Length of the hypotenuse is" SQR(a * a + b * b)
If the user entered 12,15 the number 12 would be saved in the variable a and 15 in b.
Another method of getting input from the console is the LINE INPUT command. This will get the
whole line as typed by the user and allocate it to a string variable. Like the INPUT command you can
also specify a prompt. This is a simple example:
LINE INPUT "What is your name? ", s$
PRINT "Hello " s$
We will cover string variables later in this tutorial but for the moment you can think of them as a
variable that holds a sequence of characters. If you ran the above program and typed in John when
prompted the program would respond with Hello John.
DO
InpErr:
PRINT
INPUT "Enter a number: "; a
IF a < 2 THEN
PRINT "Number must be equal or greater than 2"
GOTO InpErr
ENDIF
Divs = 0
FOR x = 2 TO SQR(a)
r = a/x
This will first prompt (on the console) for a number and, when it has been entered, it will test if that
number is a prime number or not and display a suitable message.
It starts with a DO Loop that does not have a condition – so it will continue looping forever. This is
what we want. It means that when the user has entered a number, it will report if it is a prime number
or not and then loop around and ask for another number. The way that the user can exit the program
(if they wanted to) is by typing the break character (normally CTRL-C).
The program then prints a prompt for the user which is terminated with a semicolon character. This
means that the cursor is left at the end of the prompt for the INPUT command which will get the
number and store it in the variable a.
Following this the number is tested. If it is less than 2 an error message will be printed and the
program will jump backwards and ask for the number again.
We are now ready to test if the number is a prime number. The program uses a FOR loop to step
through the possible divisors testing if each one can divide evenly into the entered number. Each time
it does the program will increment the variable Divs.
Note that the test is done with the function FIX(r) which simply strips off any digits after the decimal
point. So, the condition r = FIX(r) will be true if r is an integer (ie, has no digits after the
decimal point).
Finally, the program will construct the message for the user. The key part is that if the variable Divs
is greater than zero it means that one or more numbers were found that could divide evenly into the
test number. In that case the IF statement inserts the word "not" into the output message.
For example, if the entered number was 21 the user will see this response:
21 is not a prime number.
This is the result of running the program and some of the output:
You can test this program by using the editor (the EDIT command) to enter it.
OPTION EXPLICIT
OPTION DEFAULT NONE
DIM STRING s
DIM FLOAT d1, d2
DO
‘ main program loop
PRINT : PRINT "Enter the date as dd mmm yyyy"
PRINT " First date";
INPUT s
d1 = GetDays(s)
IF d1 = 0 THEN PRINT "Invalid date!" : CONTINUE DO
PRINT "Second date";
INPUT s
d2 = GetDays(s)
IF d2 = 0 THEN PRINT "Invalid date!" : CONTINUE DO
PRINT "Difference is" ABS(d2 - d1) " days"
LOOP
' Calculate the number of days including adjustment for leap years
GetDays = (yr * 365) + FIX((yr - 1) / 4)
IF yr MOD 4 = 0 AND mth >= 2 THEN GetDays = GetDays + 1
GetDays = GetDays + Days(mth) + day
END FUNCTION
Note that the line starting LOCAL STRING Month(11) has been wrapped around because of the
limited page width – it is one line as follows:
LOCAL STRING Month(11) = ("jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec")
This program works by getting two dates from the user at the console and then converting them to
integers representing the number of days since 1900. With these two numbers a simple subtraction
will give the number of days between them.