External Links

Creative Science Centre


Language Guide 2.30


May 2012 Preliminary mB version 1d
September 2012 Minor corrections
October 2012 This html file is now the most up to date, this supersedes the odt, and pdf documents and contains links to the full descriptions of the built in functions (keywords). To obtain a pdf copy simply use the print/pdf button.
November 2012 Changed the name from machineBASIC to ByPic
January 2013 Update for version 2.08
September 2014 Updates for version 2.30
March 2016 Changed sign on, default does not now echo

Previous Language Guide

New In this guide:

  1. Pointer (address) passing has been updated ** syntax change for '?'
  2. All devices will be user upgradable including the MX170 (DIL IC)
  3. The MX170 will include floating point (with a possible option of none FP firmware)
  4. Global variables now share program space and so there is no pre-determined limit
  5. Doubles are no longer available and so co-ordinates, replaced by pointer passing
  6. Floating point uses 4 bits instead of 8
  7. Constants with {brackets} can now be read as arrays, floating point can now be saved as  {}

Further details and migration information is at the back of this text.


ByPic is an interactive pseudo compiled language designed for use with a microcontroller. It sits in the microcontrollers Flash memory and can be extended by user input. It is a threaded language which takes text as input and then compiles this to the processor memory in the form of addresses.

The syntax is a cross between BASIC and C, Commands can be entered interactively and results instantly obtained. A good example of this is to see what a register value holds, on the PIC32 for instance the contents of port B register would be:

print peek(0xfb886040)

and if you wanted to see this in hex then:

print hex$(peek(0xbf886040))

The interactivity is carried out through one of the microcontrollers serial ports (UART) connected to a terminal emulator on the PC. In other words there is no need to install any specialist software.


In a conventional program such as BASIC, Pascal or C the program starts out life as a text file that is entered into the target device either as text in the case of BASIC or as some kind of compiled file, usually in hex format as in the case of C.

In a conventional development system the program is developed on the PC, compiled and then transferred to a programmer which in turn programs the device and some moments later the device is reset and the program run. The results of the program can then be seen. If the device has a boot loader the programmer would not be required, this does save a little time.

In the ByPic system the interpreter / compiler is already on board and so no tools on the PC are required except of course a terminal emulator for the serial link. This will be one of the COM ports on the PC or a USB connection. Because the interpreter is on the device it will respond immediately to any commands. The program (made up of functions see below) is just text that is stored onto the microcontrollers RAM and can be run from there for testing, at any time it can be saved to Flash to be more permanent.

The MASSIVE advantage here is that and any time a function can be run or a variable (including the processor registers) can be examined.


There is of course some penalty for this flexibility and a great deal of effort has been made to make this as fast as possible. In fact it is 55+ times faster then the original version of BV_Basic. This is due to the threaded nature of the language. For those interested it should be noted that the code is not stored as tokens, as in Java and other P Code languages but actual assembler addresses of the function.

Some simple tests show that this interpreter is at best only 7 times slower than C.

Program Structure

Unconventionally the language does not have a ‘program’ as such but it is made up of discrete functions.

The functionality of the language closely resembles the C model where many functions are brought together by a single function called ‘main’. The advantage of ByPic is that once a function is complete it can be tested, this is not possible to do in C unless it is called from main.

The idea is that the user will build useful functions to carry out specific tasks or part of a task and eventually end up with just one function which will be the program itself. In this way the functions can be thought of as extending the existing keywords. The user will make a set of keywords specifically tailored to the design at hand. At any time, depending on the host microprocessor, the functions in RAM can be saved to flash.

The syntax is based on BASIC but there are lots of elements from C and Pascal which are simply chosen to make more sense in the microcontroller environment.

Keywords & Case

The language is case sensitive. All built-in keywords are lower case. User defined keywords may be any case but a variable or function named Foo will be different from one named foo.

To conserve space only the first 15 characters are stored but a 4 byte hash is created from the name which is used to find the function later on.

Duplicate Functions

Functions may be duplicated, if this happens there will be a warning. Any functions that have been compiled (loaded) with the old function will still use that function. Any new functions will use the later version. The reason for allowing duplicate names is so that when a function is stored to Flash it is not necessary to erase it if a newer version is required.

There are other advantages too in that a collection of functions, say to drive some hardware, can be initialised with main() and later collection of function for some additional hardware can also be initialised with a different main.

The control of function duplication – whether it is allowed or not is determined by a system flag. This can be altered by the user.

When loading from a file only the last duplicate function is shown. The number of warnings will indicate how many duplicates were found during loading.

Semicolon ';'

This is effectively a new line and can be used at the end of a line like C and other languages but is optional. The main purpose is to allow functions to be placed on the same line, for example:

while comkey(2) = 0; wend

The above will wait until a key is pressed and is directly equivalent to:

while comkey?(2) = 0


Data Types

There are three data types, string, integer and Float.

Type Identifier Space Examples
Integer none 4 bytes a,b,fred,variable_1
Float # 4 bytes a#,b#
String $ variable a$,fred$

Data types are identified by a postfix symbol. The default data type is the integer which is the size of the CPU register. To create a variable the keyword “dim” is used and the variable name will determine what type of data it will hold.

dim a=9,b#=33.2,c$=”hello” // ** see global variables

If a floating point number is required then the ‘.’ must be used: 12 is an integer and will occupy 4 bytes, 12.0 is a float and will occupy 4 bytes. Strings require double quotes thus “hello”

In general most built in functions will automatically convert one type to the other, for example the sin() function to obtain the sin of an angle (in radians) should specify a float, e.g. print sin(90.0), however if an integer is used “print sin(90)” then the 90 will be converted to float.

This is not always the case as some keywords may have to guess the type required. For example print 12+sin(90) may return 12 but 12.0+sin(90) will return the correct answer 12.894. This is because ‘print’ will assume that the answer is to be an integer based on the first item ‘12’ in the first case. When in doubt do some tests or use the conversion functions.


Variables are stored in the microcontrollers RAM and are specified by a keyword ‘dim’ see the section on data types for how to specify a variable of a particular type.

dim a=7,b,c=66 // ** see global variables

Variables can be specified in one of two places, either outside a function, this is a global variable or inside a function which will be a local variable. ** see Variables and Flash of global initialisation.

Global Variables

These are created when the source code is compiled, or they can be created simply by typing at the terminal. If a save to flash is carried out then they too are saved as a permanent feature until the flash is cleared.

Initialisation of global variables, e.g. dim a=3 has been disabled, why? To explain; when a global is saved to flash and used as part of a function the initialisation at that time cannot take place and so by disallowing it forces the programmer to initialise the variable in a function. Of course this can be overridden with:

dim a a=3

which will compile but if saved to flash the 'a=3' bit will not be compiled leading to unpredictable results later on.

Local Variables

Local variables are created within a function using the same ‘dim’ keyword.

 dim a,b
 function k()
    dim c,d=3

In the above variables a and b are global but c and d are local. Local variables are created when a function is entered (at run time) and destroyed when exited. This has two advantages 1) the names can be reused in different functions without a clash and 2) the space taken up by the variable is reclaimed when the function ends. Local variables should always be used in preference to global variables.

Variable Types

There are three variable types, integer, float and string. All are defined using the ‘dim’ keyword and must be defined before use. The variable type is specified by its postfix:

Integer type has no post fix, examples: a,fred,variable_1

Float types use #, examples: a#,fred#,variable_1#

String types use $, examples: a$,fred$,variable_1$


An integer variable is a signed 32 bit number and is the default type. This is the most useful type for use with a microcontroller as it is the same size as the register and can be used to interrogate and set registers. This can be done interactively which is impossible to do with C and other compiled languages.

The integer is the native data storage and so any calculations or data manipulation will be achieved much quicker with this data type than any other. Wherever possible this is the one to use.


Floating point value stored as 32 bits (4 bytes) and should be used for maths routines. Floating point types can be very useful for sensor measurement. A floating point variable is distinguished from another type of variable by using a # as a postfix to its name. e.g. var#


A string is a series of characters (bytes). Internally a sting is stored with the last byte having a value of 0 but also the first 4 bytes determine the maximum number of characters a string can hold. A string can be created using two methods:

dim a$ dim a$[128]

The first method will create a string with the default string size, set by a system variable and at the time of writing is 128 bytes. The second method allows a size to be specified thus overriding the system size. Strings are identified by always giving a $ as the postfix to the name.

A string has a dual purpose in that when used as a string with the string functions such as strlen() is is treated as a series of bytes terminated with 0. It can also be used a buffer or byte storage and be manipulated by the string or peek, poke functions.


Any of the above three types can also be arrays. An array is specified using brackets after the name, some examples:

a(3,3) An integer array with 2 dimensions, of size 3 each

fl#(5,2,2) A 3 dimension float array

buf$[256](5) A single dimension string array, each string is 256 bytes big. This will occupy 1280+ bytes of ram which is a heavy resource for some microcontrollers.

Array dimensions begin at 0 thus if a(3,3) is specified then the last element is a(2,2) because 0 to 2 is 3 placeholders.

Constants can also be treated as an array see the section on constants.

Name Hash

Variable names are stored internally as hash values, this is a numeric representation of the name which is easier to manipulate and may occupy less space. In exceptional circumstances two differing variable names may produce the same hash value. In this case an error will occur as two (global) variables may not share the same name (depending on the system flag). If this happens then simply choose a slightly different name for one of the variables.

This will also apply to functions which are stored in the same way.

Variables and Flash

When saving to flash the global variable name is stored in flash but the variable content is stored (or not) in RAM, obviously, because flash is read only. This has implications in that when the device resets the global variable values will have an undetermined value. For this reason when dim is used as a global (outside a function) you can't initialise it, e.g. dim a=12. It must be initialised later, probably in a start up function. To emphasise this when using global dim, the values put into the variables are purposely odd, i.e. not zero.

Optimisation & Variables

If speed is important then there are some ways of speeding things up. In general it is not a good idea to use global variables but they do have a speed advantage. The reason is that when a local variable is used it is created each time the function is called and this does cause a speed overhead.

A global on the other hand has already been created and therefore this overhead does not exist. Another advantage is that because a global variable has a fixed address in RAM, the address can be used directly. A local variable on the other hand has no such fixed address and so a function stores its hash name, this hash is used to look up the address of the variable.


Conventional BASIC uses subroutines and occasional functions. The program is laid out on the page and is executed from start to finish, sometimes even line numbers are used.

In this language there is no common starting point, a ‘program’ is started by typing a function name at the console or at start up. Of course the function may not be a program but a simple routine that satisfies a single purpose.

The idea is that if enough of these small functions are collected and put together then a complete program can be assembled that is started by the top function. The analogy is like components for a machine.


function rotate(x,y)
    dim b
    if x<33 then
    return y

In the above example all functions begin with the keyword ‘function’ following this is the function name followed by optional parameters. If no parameters are required the brackets are still needed but just empty.

function swap()

The parameter type must be specified; in the above case x and y are integer because there is no postfix character (# or $). The comma is also required between the parameters. Parameters are passed by value and will not be modified by the function as far as the calling routine is concerned (see later).

Optionally functions may return a value and this is determined by the ‘return’ keyword which can be used anywhere in the function but when it is encountered the function is left at that point. This is useful for leaving a function early, see also break and continue. If no return keyword is used or there is no value after the return then the function will not return any value.

The type (integer, float or string) of value that a function returns is determined by its name just as used in variable names so in this example:

function k$()
   return 12

The function k$ will return a string and in the example “12” is returned as a string not as an integer.

Returning More than One Value (Pass by Reference)

There are occasions when more than one value is needed from a function and for this pointers are used, this is sometimes known as passing by by reference. This method will also enable a function to modify a a variable passed to it.

There are two aspects to a function. The defining function, the code with the word function in front, i.e.

function bob(a,b)  << defining

And the calling of that function, i.e

function test()
<< calling

When a reference is passed to a function that function is able to use the actual variable passed to it. Normally it would just have a copy of the variable and could not change it. This would be better illustrated with an example.

function add(*a,b)
    a = a + b

function test()
dim x=0
    print x

Result 10

In the above the defining function specifies the first variable needs to be a reference, this means that when a variable is passed to it, in this case 'x' it is not a copy of 'x' but x itself and so in the defining function 'a' is effectively x. i.e. 'a' is the same as 'x'.

When passing by reference a '*' is required at each end as in the example above. An error is generated if a function requires a reference and a none reference is passed to it.

Some 'built in' functions require a reference rather than a value. An example of this is the built in file function for reading data.


Nearly all file function return an error value but in the case of fread we also need to know how many bytes have been read. This is stored in a variable provided by the user called count. If a variable was passed here then it would not be modified by the fread function as functions do not modify variables passed to them. To get round this we pass the address of the variable.


These can also be passed to and from functions via the same method using the following syntax.

function test(*a())
     a(1,1) = 12

function go()
dim a(3,4)
    print a(1,1)

the result of running go() is 12

Depreciate method

The old method for a function to return a value was to use the variables address and store to that address as shown below. This can still be done for user defined functions but built in functions will cause and error.

function test(value)
   // @value=50 // alternative to poke

function tt()
dim a=33
   print a
   print a

In the above the test function accepts the argument (parameters) as normal but notice that in function tt the address of a (?a) has been passed to the function test. Because function test has the address it can change the contents using poke. This means that when tt gets 'a' back its value has changed.

Applies to variables and constants only it is also possible to use a @ as a shortcut.

? is the address of @ is the contents of


All variables defined within a function are local to that function and are created on entering and destroyed on leaving. This includes the variables used as parameters.

A function must be defined before its use, this implies that when compiling a set of functions the order is important. The main reason for this is so that error checking can be done at compile time which greatly increases the execution speed and reduces hard to find errors.

A return will exit the function at that point and the rest of the function will be ignored, returns are allowed within FOR/NEXT and WHILE loops.

Constants & Numbers

This is a specified fixed value and can be integer, decimal, hex, floating point or string.

An integer decimal is specified by 1,500,20093 etc. A hex number is specified by preceding it with zero x, for example 0x123, 0x8a7b

A floating point number MUST contain a period even though it may not be needed for example 10 is an integer but 10.0 is a floating point number. This may be important in certain circumstances although most of the time automatic conversion takes place for example.


The above would be acceptable as 12 is automatically converted to 12.0. This cannot always be relied upon for example, the atan of 90 is 1.55969 so you would expect:

print 12+atan(90)

to print 13.55969. However the result from this is 13. The reason is that the 'print' keyword has to guess at the type of variable and it makes this guess as integer because that is the first token (12) it encounters.

print 12.0+atan(90) print atan(90)+12

Both of the above give the correct result.

Strings are specified using double quotes these must appear at the beginning and end of the string. Non-printable characters are specified with a preceding backslash, the following are acceptable:

\r Byte value 13 (carriage return)
\n Byte value 10 (line feed)
\e Byte value 27 (escape)
\\ Byte value 92 (the \ character)
\<number> A number following the backslash will be accepted and compiled into the string. It must have a value less than 255 and can be specified as hex, thus \0x0d or decimal \13


A constant can be defined and will be compiled just as any function would be. The format is constant <name> <expression>

The constant expression can evaluate to integer, float or string for using the postfix naming convention; example.

constant foo 12+77

will evaluate to an integer expression because there is no (# or $ in the name foo). The constant created will take on the type of expression that follows. A constant can also use previously defined constants thus:

constant top 127 constant mid top+50

Constants are always global and cannot be used inside functions.

Constants can also specify a list of numbers that can be integer (32 bits) byte (8 bits) or floating point. The list can be any length but if the list is likely to go over the set input line length (normally 80 or 128 characters) then a continuation '\' can be used.

constant value$ { 0x33,124,77,9, \
32,200,0xea }

constant value {1277895, 0xff3312, 0, 1,2}

constant value#{12.21,8.00932,7.44,12}

In the above three examples the first stores the numbers as byte values and so each element (number) can be 0 to 255. This is the most compact storage. In the second example the numbers are stored as 32 bits, thus giving a much larger range but each of the numbers takes up 4 bytes. The last example is a table of floating point numbers.

To gain access to the values in the above constants the array specifier can be used, thus:

print value$(3) will output 9
print value(3) will output 1
print value#(0) will output 12.21

As these are constants then it is not possible to change them with for example value(0)=2 and an error will be given.

Warning: These are not arrays and as such no boundary checking is implemented, it is quite possible to print value(10) without error but the value returned will of course be unpredictable.

Saving to flash

Any constant value can be saved to flash in the normal way just as a function by compiling to RAM first and then using flsave(""). However some tables may be too large to fit in ram first so by using the 'flash' keyword in front of the constant name will make the constant be saved immediately to flash.

constant flash value$ { 0x33,124,77,9, \
32,200,0xea }

The above will be saved directly to flash. The primary intention for this keyword is to allow large fonts and pictures to be saved as constants for devices with screens.


As a general rule conversion functions will not be needed as the language, most of the time, knows what is expected and converts automatically. For example the maths function atan() requires a floating point type to specify the angle thus:

print atan(90.0)

However ByPic knows this and so will convert anything in the argument (the 90.0) to floating point even ridiculous values, all of the following work:

print atan(90)

print atan(“90”) print atan(“45”+”45”)

There may be some circumstances where conversion is required and to this end the following are available.

Byte to String byte2str(byte) returns int *
integer to float int2float(<integer expression>) returns float
integer to string int2str(<integer expression>) returns a string
float to integer float2int(<float expression>) returns an integer
float to string float2str(<float expression>) returns a string
string to integer str2int(<string expression>) returns an integer
string to float str2float (<string expression>) returns a float

*byte2str() added in version 2.08 - 24. This is intended for adding bytes to the end of a string. It behaves exactly like chr$() except unlike chr$() it does not convert characters to '.' if the value of the byte is below 32.

Register Access

When working with a microcontroller is important to be able to directly access the registers and indeed any allowable memory address. When direct access is available it is possible to set up hardware without relying on specially provided keywords. So for example to set up a particular port for output on the PIC32 simply write to the required port register.

To access memory the familiar peek and poke are used. There are two variants, peek will access an integer word which is 4 bytes and peekc will access just one byte. To give an example. The RTC register on the PIC 32 has an address 0xbf800220

print hex$(peek(0xbf800220))

The above will return the contents of the register, hex$ is simply used to convert the value to hex as this makes it easier to read. The value returned from peek is 32 bits (4 bytes). It is sometimes useful to obtain a single byte, in this case use peekc(<address>). To change the contents of the address use poke(). The syntax is poke(<address>,value)

As an alternative the shortcut @ can be used which is “the contents of”, this is limited in that it will only applies to single integer constants or variables. So for example:

constant PORTB 0xbf886050

print @PORTB // prints the contents of port B @PORTB = 1 // sets PORTB to 1

Allowable Addresses

There are some rules that must obeyed to avoid exception errors. This will vary from processor to processor but in general the following will apply.

  • The address must be on a 4 byte boundary in other words it must be divisible by 4 or if using hex must end in 0,4,8, or c. For example 0xa000300c will be okay but 0xa000300d will produce an error.
  • Most processors have a restricted access to memory. Only certain addresses can be accessed for example on nearly every processor peek(0) will cause an exception error.


Operators are statements that work as part of an expression and usually require two operands, for example in this expression “1+2” the ‘+’ is the operator. The following can be used anywhere to form part of an expression. Functions and variables are taken to be operands.

Operators in order of precedence:

* Multiply
% Modulus
/ Divide
- Minus
+ Plus
<< Shift left
>> Shift Right
& Bitwise and
^ Bitwise xor
| Bitwise or
&& Logical and
|| Logical or

The following do not have precedence and are used for comparison, typically used in IF or WHILE statements

= Equality
<> Does not equal
<= Less than or equal
>= Greater then or equal

The following modify the access to a constant or variable.

? Means the address of

@ Means the contents of

The above access modifiers will only work on single items for multiple items (an expression) peek and poke should be used, for example peek(REGISER1+4)

Some Examples

dim j,k

j=0xff, k=0xa000030000

print j & 2 // will print 2

print j >> 4 // will print 15

print j | 0x100 // will print 511 (0x1ff)


print @k, k

Looping and Branching

Program decision making is the ‘if’ ‘endif’ construct and generally follows the BASIC syntax. Details are in the keywords section.

if/else/endif: decision making

select/case: multiple decision making

while/wend: looping - may not loop

do/until: looping will always loop at least once

for/next: counted loop

break: both WHILE/WEND and FOR/NEXT loops can be prematurely exited using the ‘break’ statement.

return: premature end to function OR when returning a value

continue: this can be used in the while/wend loop. If is is encountered the execution will continue from the start of the while statement.

Maths Functions

The following functions expect a floating point parameter and return a floating point.

Function Syntax Notes
sin sin(x) returns sin of x
asin asin(x) returns arcsin of x
cos cos(x) returns cosin of x
tan tan(x) returns tangent of x
atan atan(x) returns arctan of x
log log(x) returns natural logarithm
exp exp(x) returns natural antilogarithm
pow pow(x,y)  
sqrt sqrt(x) returns the square route of x
rand rand(min.max) returns a random integer value between the maximum-1 and minimum values supplied

File System

Most implementations will have a file system, probably using an SD or MMC card on Linux or a PC this will take advantage of the host file system but on a stand alone microcontroller use is made of a “FatFs” which is a stand alone filing system designed for microcontrollers and created by ChaN (http://elm-chan.org/http://elm-chan.org/ ). This is also supported by Microchip on their download site. Please read the licence on terms of use. There is no guarantee or warranty that the system will operate to any defined standard. Having said that it is pretty good.

The implementation uses long file names.

See the data sheet for the particular device but in general if there is no filing system available or no card has been inserted then the prompt will be a simple ok, thus: ok If a card has been inserted and it is mounted properly then the prompt will include the path: 0:/ ok Forward slashes '/' are used but the system will equally well accept '\' the 0 (zero) refers to the current mounted card, some systems support more than one card in which case the zero may change to one or two. The following built in keywords will be available details of what they do are in the keyword section.

dir lists the current directory

cd changes the current drive / directory All of the other available file operation keywords are functions.


Possibly the most important part of this language is the ability to save user functions to Flash. This will in effect extend the language and customise it to the users needs, as a user function is exactly the same as a built in function.

Unlike other memory there are some restrictions in using the Flash that is built into a microcontroller and this will vary depending on the device used. However most devices will allow writing of byte values but will only allow the erase of a full page. A page will vary in size but is quite often 4k Bytes (4096) (1k for the MX1). This needs to be taken into consideration by the software and it does this by saving on page boundaries. The consequences of which are that if only one function is saved then this may occupy the whole 4096 bytes.

Flash words are prefixed with fl and are described in the keywords document. A summary is provided here.

fltell Displays information about the current Flash memory

flsave Saves the current memory contents to flash. The action of this is to effectively move the contents of RAM into Flash.

There are two options, a null string “” and an item (function, variable or constant). When a null string is specified all of the loaded items will be moved to Flash, when an item is specified only those items including and after that will be moved into Flash.

flclear Clears the flash and has two options. flclear(0) will clear all of the flash (not the ByPic firmware of course) and flclear(1) will clear the last saved set of functions.

System Constants

The following special names can be saved as a constant and they will alter the behavior of ByPic at start up. For example the following sequence:

constant SYS_COMBAUD 9600

The above will create a constant called SYS_COMBAUD and set its value to 9600. This is saved to flash, along with any other functions previously defined and then the device is reset. On reset instead of the default 115200 Baud the device will operate at 9600 Baud.

To clear it use flclear.

The following are available.

SYS_STACKLEN Stack Length: the size of this is in 4 byte words and by default it is set to about 50. This can be reduced if more space is required for other areas. If it is reduces too much the run time error 2 “stack overflow” may be encountered. ** This should not need changing by the user **

SYS_RSTACKLEN Return Stack Length: the size of this is in 4 byte words and by default it is set to about 50. This can be reduced if more space is required for other areas. If it is reduced too much the run time error 4 “return stack overflow” may be encountered. ** This should not need changing by the user **

SYS_HEAP Heap Length: this is specified in 4 byte words and is the program storage. User functions are compiled to this space. It will normally be set to the maximum available but can be reduced to make more room for say local variables.

SYS_TEMPSTRL Temporary String Length: the system uses a temporary string for operations such as string copy and various other operations. The number specified here should be in bytes. The maximum is 256.

SYS_TEMPSTRN Number of Temporary Strings: see identifier 4, this is the number of strings available for the system. They are used on a round robin (circular) basis. 4 is the minimum that should be set.

SYS_VARLOCAL Local Variable Storage: this value is specified in 4 byte words. This is the allocation for local variable storage. Local variables are created and destroyed as a function is run and exited so this space can be quite small. Don t forget though that a string array may take up a considerable space.

SYS_STRLEN Default String Length: this is specified in bytes. When a string variable is created without a length specifier, i.e. a$, its length is set by this default. This may be set quite small (10) in systems that do not have much RAM resource.

SYS_STACKFOR loop Max: this will set the maximum number of nested loop statements. When using for/next within for/next or while this consumes resources and this system variable will set the maximum nesting depth. The default is 10. ** This should not need changing by the user **

SYS_COMPORT COM port: this sets the default COM port, normally associated with the UART. This will be set by default to the normal hardware default. For PIC32 it is set to 2

SYS_COMBAUD Baud Rate: sets the system Baud rate. This can also be set with comopen().

SYS_COMSIZE UART Buffer Size: all input is buffered through a software buffer, this will set the size of that buffer. The UART buffer will fill on interrupt and so the program may be doing something else yet it will still capture the input providing the buffer is big enough. The buffer is emptied by using the com read functions.

The following also applies to com port 1


SYS_FLAG System Flags: this is a 32 bit word and each bit set or cleared will control some aspect of system behavior. This is set as a single value so all relevant bits must be cleared or set at once. See the table above for the meaning of the bits.

Bit (x currently not used, set to 1) Description when set
xxxx:xxxx:xxxx:xxxx:xxxx:xxx0:0000:0001 Miscellaneous messages at start up and hardware detect messages
xxxx:xxxx:xxxx:xxxx:xxxx:xxx0:0000:0010 Prints memory allocation messages
xxxx:xxxx:xxxx:xxxx:xxxx:xxx0:0000:0100 Prints sign on message
xxxx:xxxx:xxxx:xxxx:xxxx:xxx0:0000:1000 Prints error messages in full
xxxx:xxxx:xxxx:xxxx:xxxx:xxx0:0001:0000 Global re-definitions - will not allow re-definitions if set to 1
xxxx:xxxx:xxxx:xxxx:xxxx:xxx0:0010:0000 Prints message “isn't unique” when a global or function is re-defined
xxxx:xxxx:xxxx:xxxx:xxxx:xxx0:0100:0000 Prints miscellaneous system messages for example when a cold start occurs the message cold start will be displayed.
xxxx:xxxx:xxxx:xxxx:xxxx:xxx0:1000:0000 Echo on if set to 1 (default 0)
xxxx:xxxx:xxxx:xxxx:xxxx:xxx1:0000:0000 Send ok prompt if set to 1
xxxx:xxxx:xxxx:xxxx:xxxx:xx10:0000:0000 Prompt '>' instead of ok
xxxx:xxxx:xxxx:xxxx:xxxx:x100:0000:0000 Start up printing
1111:1111:1111:1111:1111:0001:0011:1100 Default setting (0xfffff13c)

cold: performs a cold start. This will clear all of the memory and stacks. This would normally be used when loading fresh data or starting again. It is not quite as severe as reset and will not run the function 'main' main()

main(): this function does not exist on a new system and can be created by the user. This function will be run at start up (if it exists). The function can exist on SD Card if one is present or in Flash. If main exists both on Flash and SD Card then the one on the SD Card will be run first. This function will eventually contain a continuous loop for stand alone applications, if you need to get out of the loop at a future date then the following techniques can be used:

MX3 type devices that have an SD Card: 1) Create another main on SD Card that will be run first or 2) reinstall the firmware again using BC_COMM with the erase all flash option checked.

MX1 type devices. Within 0.5 seconds of reset send byte 0x5c. This is the '\' on the keyboard, so use BV_COMM, press reset and then \ straight away. This will stop main from being executed and give the opportunity to erase the flash as flclear(0) would.

There is also a '.loopbreak' command in BvSerial that will attempt to reset the MX1 and erase the flash, thus breaking the continual loop.

Example of using main Saving main to Flash – if an SD Card is available then try it there first.

function main()
    print “\nThis is function main”

flsave("") // saves to system flash reset // main will be run on reset

lookup: this will return the address of an item name if it exists or 0 if it doesn't. An item is a function, keyword, constant or variable. The main purpose of this function is to check to see if a function exists.

There is a comprehensive list of built in functions in the keyword guide, the index is organised by function and the guide itself is organised alphabetically below is some more general details.

Input / Output

This is done via the built in UART and by default will be UART 2, print for example outputs to UART 2. The functions for this are generally lower level then 'print' to reflect the nature of use.

In practice UART 2 is used for system and debugging functions and the other UARTS are used to connect to other devices.

Loading & Running

This section deals with how to get functions into the system, RAM or Flash and then run them other then typing them directly into the console. This is also covered elsware on this site and in the tutorials section.

tload The purpose of this function is to get text programs from the host into the device RAM. This uses a very simple protocol of ACK and NAC.

The host will send a line of data and then wait for the target to send an ACK before sending the next line. The target may also send NACK in which case the host should terminate. A line is text followed by CRLF or some combination, ACK is 6 and NACK is 5.

The host can also send directives to the target when using tload and are shown below. NOTE that the user is unlikely to use any of these unless writing a host loading device. Normally BV_COM will send these to get or send more information about the system.

#1 <function> The target will look up the word following #1 and return to the target ACK if it exists in its memory and NACK if it doesn't

#2 <function> The target will execute this function as if it were typed into the console. Some functions will not work within tload. Returns ACK on success.

#3 <filename> Opens a file on the SD card with the given name, returns ACK on success NACK on fail. All of the input from the host will now go to file as well as the RAM (see #6)

#4 Closes the file opened by #3 – only one file can be opened at once. The file will also be closed automatically when downloading ends. An ACK is sent on completion.

#5 Resets the line number count. An ACK is sent back to the host.

#6 [“on”“off”] When #6 on is sent the will stop all output going to ram and thus being compiled. This is useful when used in conjunction with #3 to just send text to a file. Returns ACK. #6 off will resume normal operations

fload: as tload but loads a function or set of functions from the given file on the SD Card. The file must exists on the SD Card. Functions will be loaded on top of existing functions.

frun: this will load the functions contained in the file given by “filename” into ram and then run the function specified in the second parameter. The third parameter can be a function, constant or variable name or “”. If a null string is sent (“”) then all of the existing functions, constants and variables (items) will be removed before loading the new file. If however an item is specified for “forget” then that item and items after that will be removed leaving behind any previous items. This is useful for keeping functions or variables that may be needed when the new file is loaded.

Numbers & Other & Mscl.

list: this will list the functions that exist in Flash and or RAM depending on the value of the supplied parameter.

forget: functions are compiled one after the other. This will forget all functions including and after the one specified.

Screen Operations

This will only apply to devices fitted with screens, the keywords guide and the actual documentation for the device should be consulted.

Interrupts PIC32

As it says in the title this refers to the PIC32 microcontroller although this may apply to other MIPS based microcontrollers. The scheme used is a single vectored interrupt. This means that when an interrupt occurs it jumps to one place and is handled there.

This is not as efficient as a multi vectored interrupt that would jump to a different address but as they are being defined by the user it is not possible, or more accurately less efficient to have spaces occupier by interrupt vectors that may never be used.

The system also uses this single vector for the UART reception so there are already U1RX and U2RX (and possibly others) interrupts in place. When the interrupt is serviced the routine will also look through a user table and service any interrupts there. The user table is set up by the irset keyword.

Interrupt Notes

The interrupts are already globaly enabled because the communication UART requires this for buffered input. The priority is fixed at level 3 and the routine that handles the interrupt must handle all of the interrupts. There are some rules to be observed when using interrupts:

  • An interrupt function cannot return anything (use a global variable).
  • Parameters must not be passed into an interrupt.
  • The interrupt should be kept as short as possible and preferably not call any other functions.
  • The user must enable the interrupt and priority for level 3     

Release Details

1. Introduces is a new syntax; prefixing a variable with * (*a$ for example) will indicate the reference of that variable. This allows better handling of passing and obtaining variables between functions. For example it is now possible to pass arrays. Further details are here. It should be noted that the ? modifier still works the same way.

2. All devices including the DIL MX1 types have a boot loader and so are user updateable.

4. Prior to this version a limit had to be set on the space that global variable occupied even if there were plenty of room in the program area. Now global variables share the same space as the program and so the limit is now when the RAM is actually full.

5. Double values (var!) are no longer available. To streamline the program all variable values now occupy 32 bits. In addition floating point values that used to occupy 64 bits now only use 32

7. Constants have been upgraded and this applies to the constant type with the {curly} brackets. These can now be considered as constant arrays with a single dimension and should be very useful for static data. Floating point type are now also allowed, further details are here. See also the migration section below as there is a significant change to byte data.


The following are syntax changes and so will effect existing code.

References for built in functions

The following functions and references to those functions will need changing as they used the ? address modifier they now use the * reference modifier.

  • error=ffree(<disk>,?x) is now error=ffree(<disk>,*x)
  • error=fread(s$,length,?count,file) is now error=fread(s$,length,*count,file)
  • error=fwrite(s$,length,?written,file) is now error=fwrite(s$,length,*written,file)
  • result=i2cgetc(<channel>,?v,timeout,last) is now result=i2cgetc(<channel>,*v,timeout,last)
  • s$=token$(a$,?position,'delimiter') is now s$=token$(a$,*position,'delimiter')
  • call() This remains the same,it still requires an address, see constants below

User functions written using ? will not be effected although see constants migration.

Double Values

These are no longer available and so any variable with a post fix of ! will just be a normal integer. This also effects the Cartesian system used mainly for specifying co-ordinates of a screen which will now be replaced by passing arrays or constant arrays. The following will be specifically effected:

  • cart()  no longer exists
  • x0 no longer exists
  • x1 no longer exists
  • y0 no longer exists
  • y1 no longer exists

Releases that were specifically designed for devices with screens such as the BV523 will have a separate note detailing the built in commands used.


There are two significant changes for constants that have been defined with {} and this will effect all functions that use the contents of the constant using the ? modifier.

First: As this type of constant is now considered an array the ? modifier has to be used as if it were an array and the index of 0 needs to be specified thus a(0). As an example.

constant a{55,56,57}

Prior to this release, the first value '56' would be obtained by peek(?a+4)

From this release the same result is obtained by a(1)

In some circumstances the address of 'a' is still required, in which case ?a(0) should be used.

NOTE: Byte array (a${1.2...}) does not work in 2.3 and should be avoided, an integer array can be used instead. This will be fixed in the coming release and is likely not to be a string but a separate byte type.

Second: This only effects the byte (a${1,2,3} example) type constant. All of the other constant definitions remain unchanged in this respect.

The byte array (a${1,2,3}) is not a string and to reflect this there is now no 4 byte offset at the beginning of the constant so it can be treated in exactly the same way as above.

constant Old Method Equivalent Preferred
a{55,56,57} peek(?a+4) peek(?a(0)+4) a(1)
a${55,56,57} peek(?a$+4+1) peek(a$(0)+1) a$(1)
plug_in{....} call(?plug_in,0)   call(?plug_in(0),0)

Plug In

See the table above, substitute call(?pliug_in,0) for call(?plug_in(0),0)