Plug In's - Introduction
Plug-ins are programs written in C and then called from the Basic Interpreter. The 'plug-in' C program is compiled so that it will run in flash above the main Basic application. The reason that this may be required is for items that need to be handled quicker than BASIC can do or to respond to interrupts in real time. Keeping BASIC gives the opportunity for plug-ins to be written by others but used in a simple way without any knowledge of C. This text introduces plug-ins, how to write and use them.
Resources
- MPELAB with the PIC32 compiler would be useful but not necessary for this text
- Hex to binary convertor hexFbin.exe (see download section)
- Demonstration files plug_in_simple.zip (see downloads section)
- Template file plug_in_template.zip (see downloads section)
Writing a Simple Plug-In
A plug-In is a self contained C program that has been compiled to a memory address above the application. The code is installed in that Flash and the required routines are called using 'ccall' and supplying the correct address.

The system constant 'SYS_FLASH_END' determines the start of the plug-in area an by default is set approximately midway between the start of user flash and the physical end of flash. This system constant can be changes by doing the following.
constant SYS_FLASH_END 0x9d050000
fsave all
When the PIC is reset the new value will be picked up from the constant now saved in flash. The C binary plug-in file is saved using the command 'plugin', the full statement is:
plugin to <page number>
Where <page number> starts at 0 and 0 is the address of 'SYS_END_FLASH'. The plug-in can be saved to any available page, a page is 4096 (0x1000) bytes. The 'sys' command will give valuable information of memory and its usage.
| Addresss | Page |
| 9D05C000 | 0 |
| 9D05D000 | 1 |
| 9D05E000 | 2 |
| 9D05F000 | 3 |
| etc..... | |
| 9D07F000 | 35 |
Assuming that SYS_END_FLASH is set to 0x9d05c000, the statement plugin to 3 will load the binary compiled C file to address 0x9d05f000. The flash is erased page by page as required and so no separate erase command is needed.
Writing the C Plug-In
In order for the plug-in file to compile in the correct memory space, the 'procdefs.ld' will need to be found and placed in the current directory. This file tells the linker where, in memory space, to place the program. The important lines are explained below:
kseg0_program_mem (rx) : ORIGIN = 0x9D05c000, LENGTH = 0x9d080000-0x9d05f000 /* 4 pages */
The above line controls where the linker places the program in flash, in this case it is set for 0x9d05c000 which must match the page you use to load the eventual binary file. Using the above table as an illustration this program will be plugged in to page 0. The length has been set at 4 pages but this can be increased if required. Initially the 'procdefs.ld' file supplied with the example should be used as this also contains RAM and exception addresses that match the Application.
When the application is compiled it must be converted to a binary file using the hexFbin.exe utility, it can then be plugged into the Flash using the xmodem transfer (full details later).
Passing Parameters
Under normal compilations, the library files and C source code contain sufficient information for parameter passing to take place, the compiler knows what's being called and the target function. In a plug-in the compilation is carried out separately from the main code. The main code therefore cannot know in advance what the parameters will be.
To get round this a structure is created that contains most of the parameters that may be required and this is compiled in advance, only those parameters that are needed are used. The structure is passed as a pointer and so there should be little by way of stack overhead. It should be noted though that the ccall() function does not use these once they have been passed and although the C program can change them this will not be reflected back to the basic program.
char c[MAX_P];
char *cp[MAX_P];
int i[MAX_P];
unsigned u[MAX_P];
double d[MAX_P];
} GPS;
The structure is called GPS and is used for every function of a plug in that is called form Basic. A function would therefore look like:
{
return a->i[0] * s->i[1];
}
Basic will pass the structure into the function and from here the structure names are used as the parameters, the first integer parameter passes is i[0] and the second is i[1]. To call this function from Basic the following would be used:
dim r
r=ccall(PI_TIMES, int a, int b)
print "r=";r
endf
Ccall requires a C function address and optional parameters, the parameters are prefixed with the desired type.
char goes into c[n]
string goes into cp[n]
int goes into i[n]
unsigned goes into u[n]
float goes into d[n]
In the above tt function the first defined integer 'int a' goes into i[0] and the second defined integer goes into i[1] and so on. The maximum number has been fixed to 4 (x[0] to x[3]). In order to actually call the C function, its address must be known. This is discovered from the '.map' file. The actual file segment is here:
.text 0x9d05c018 0x58 plug_in.o
0x9d05c018 pi_times
0x9d05c050 main
Which is about half way down the '.map' file, the address found here can be used as the value for the constant PI_TIMES, thus:
It doesn't need to be defined as a constant, the address can be directly entered as part of the ccall statement. The code for the above is in a zip file called plug-in-simple along with the hex convertor and Basic file.
Plug In Installation
Installation of a plug-in requires that the C compiled binary file is placed in flash at a known address. This is carried out by using the statement 'plugin'. The binary file can be either transferred over the USB using xmodem or it can reside on the SD Card. To transfer the file using xmodem, this synatx is used:
plugin to 0
The system will now wait until you activate the xmodem transfer. As an alternative the following can be used:
plugin from "plug-in.bin' to 0
The file 'plug-in.bin' must of course exist on the SD Card. Once the plug-in is in the flash it will stay there until erased either by using 'plugin' statement again or using the 'fclear' keyword. The '0' refers to the page that the address in flash that the plug-in is loaded to, this is directly related to the system constant 'SYS_FLASH_END, this must match where the plug-in was intended to go in memory. In other words if the plug-in is compiled (linked) for 0x9d05c000, then it must be loaded there in flash.
Plug In Template
There are three possible types that a plug-in may return, integer, double (64bit floating point) and String, these are invoked with ccall(),ccall#() and ccall$(). To illustrate how to use them see the 'plug_in_template' file. This is a demonstration of all three types with basic and C functions.
Integer
This has been covered before in the above text but it returns a 32 bit signed integer.
Float
This returns a 64bit (8 bytes) double value representing a floating point value.
String
This will fill a sting variable which can be anything up to 128 bytes. When passing a sting variable as in:
ccall(<address>, string a$)
The whole sting is not passed to C, juts a pointer to the first character of a$, this is picked up in C as s->cp[0]. This has implications in that the string value passed to the C function is the SAME as in Basic and so any manipulation of this is C will alter the variable in Basic. For example the C function *pi_cat() in the template example takes the two stings passed to it an returns them both added together, but it uses the first string as a buffer and then passes the first string.
{
strcat(s->cp[0],s->cp[1]);
return s->cp[0];
}
If two global variables are created say a$="fred", b$=bob" and the C function is called:
print ccall$(PI_CAT, string a$, string b$)
This will print 'fredbob' as expected, bit a$ will also be equal to 'fredbob'. Keep this in mind when using strings it can be useful or it can create surprises.