HACKING DuinoMite BASIC

Image

There is FIRMWARE WISHLIST on Ken Segler Designs forum and I post there a lot with requests for this or that command to be add 🙂

As the DM-BASIC code is over 30 000 lines I never looked at it in detail, just if wanted to see how some command works I was looking at the specific code which implements it.

Overall I though it’s difficult and confusing to touch in so big code as I could easily mess up something with the other commands.

Iggy from KSD forum did some commands recently for me and when he submited them to Ken to include in the mainstream code I was amazed how simple was to add command to DM-BASIC.

For instance he implemented function DM.VMEM which returns the first address of the video RAM as Nick requested on TBS forum, the code insertion was:

in graphics.h there is one line to add:

// Ingmar
{ “DM.VMEM”, T_FNA | T_NBR, 0, fun_vmem },

this row define the name of the new statement: “DM.VMEM” then define it as FUNCTION returning NUMBER and will call fun_vmem() to get it’s value

and in graphics.c there is this code snip to add:

/////////////////////////////////////////////
// Returns lower 16 bits of video buffer.
// This assumes the upper 16 bits always start 0xa000, maybe we should return all 32 bits?
/////////////////////////////////////////////
void fun_vmem(void) {
int vmem = (int)VA;

vmem &= 0x0000ffff;
fret = (float)vmem;
}

so with adding 5 lines of code we already have new DM.VMEM function which returns the address of the Video buffer!

WOW! I didn’t expect it to be SO easy!

now let’s see how he implemented SHIFTOUT:

first define it in external.h
// Ingmar
{ “SHIFTOUT”, T_CMD, 0, cmd_shiftout },

this time this is COMMAND i.e. do not return value and the code is at cmd_shiftout()

and the code is put in external.c

///////////////////////////////////////////////
// This is invoked as a command (ie, shiftout(Dpin, Clkpin, Mode, OutStr, NumBits) )
// Remember that the string returned in outstr will have the length in byte 0, outstr[0]

#define uDly(a) {WriteCoreTimer(0); while(ReadCoreTimer() < a);}

void cmd_shiftout(void) {
int dpin, cpin, mode, nbits;
int ix, iy; // loop counter
int cnt; // number of bytes to output.
unsigned char mybyte;

char * outstr;

const int BDLY = 3; // Determines clocking rate. # of CoreTimer cycles.

getargs(&cmdline, 9, “,”); // Get the arguments, we should have five, comma seperated.

if (argc < 9) error(“Invalid syntax”); // Test number of arguments given.

dpin = getinteger(argv[0]); // Data pin
cpin = getinteger(argv[2]); // Clock pin
mode = getinteger(argv[4]); // Mode
outstr = getstring(argv[6]); // String to clock out,treated as an array of bytes.
nbits = getinteger(argv[8]); // Number of bits to clock out

if (nbits < 1 || nbits > (outstr[0] * 8)) error(“Too many/few bits”);

if (dpin < 0 || dpin > NBRPINS || cpin < 0 || cpin > NBRPINS) error(“Invalid pin number”);
if (ExtCurrentConfig[dpin] >= EXT_COM_RESERVED || ExtCurrentConfig[cpin] >= EXT_COM_RESERVED) error(“Pin is allocated to a communications function”);

// At this point we should have a valid number of arguments and some possibly valid IO pins.

cnt = (nbits – 1) / 8; // Tells us who many complete bytes to loop over.
cnt++; // at least one byte even if it is a partial byte.

ExtSet(cpin,0); // CLK pin low
uDly(BDLY);

if (mode == 0) { // shift bits out LSB first starting at the END of the string.

for (ix=0; ix<nbits; ix++) { // loop through all bits
iy = ix / 8; // byte offset

mybyte = outstr[outstr[0]-iy]; // current byte being output

if (mybyte & (1 << (ix & 0x07))) {
ExtSet(dpin,1); // output a 1
} else {
ExtSet(dpin,0);
}

uDly(BDLY);
ExtSet(cpin,1); // CLK high
uDly(BDLY);
ExtSet(cpin,0); // CLK low
uDly(BDLY);

} // next bit

} else { // shift bits out MSB first starting at the BEGINNING of the string.

for (ix=0; ix<nbits; ix++) { // loop through all bits
iy = (ix / 8) + 1; // byte offset

mybyte = outstr[iy]; // current byte being output

if (mybyte & (128 >> (ix & 0x07))) {
ExtSet(dpin,1); // output a 1
} else {
ExtSet(dpin,0);
}

uDly(BDLY);
ExtSet(cpin,1); // CLK high
uDly(BDLY);
ExtSet(cpin,0); // CLK low
uDly(BDLY);

} // next bit
}

}

/**********************************************/

the code above is well commented and do not need my comments, again it was very simple to add!

Now let’s hack a bit! I wanted to make my own command to prove the concept!

If you want to do the same:

First you have to obtain the tools to compile DM sources from Microchip web

Download MPLAB 8.80 (166MB) and PIC C32 compiler v1.11b (73 MB) and install them

Then download DM-BASIC latest sources from Olimex Web page http://www.olimex.com/dev/

Unpack them in working directory and try the project. Note I had to setup the C32 locations manually and to change search path for Olimex.h to build the project successfully. The HEX is compiled and located in OUTPUT directory and named OLIMEX.HEX, use the Bootloader tool to burn in DuinoMite.

I compiled the source first and downloaded to DuinoMite. Everything works OK!

OK then let me try to add HELLO command which writes “Hello World” on the screen

I add in misc.h this line which defines my command:

{ “HELLO”, T_CMD, 0, cmd_hello },

and in misc.c the code to be executed when HELLO is met in BASIC:

void cmd_hello(void) {

MMPrintString(“Hello world!\r\n”);
}

Now let’s compile everything and bootload and try!

Image
it works!

So using this approach you can define ANYTHING you want to have in DM but you miss it, only you should have some basic C knowledge, then to be not afraid of learning new stuff and hacking.

I will personally try to implement next: RCTIME command which will measure capacitance on the GPIO pin in the next days and post the result.

This way you can build your own version of DM-BASIC which to add specific functionallity which is not possible to be done otherwise in pure BASIC. Do not forget DM-BASIC is open source project with GPL 3.0 licensee so whatever you do do not forget to make your sources also available, so the community can benefit from your contribution and the project move forward!

Happy hacking!

DuinoMite: Working with 1-wire devices

Image

Maxim-Dallas iButton 1-wire devices are widely used in security, timekeeping, temperature measuring and so on applications.

Gerard Sexton added iButton 1-wire support for DuinoMite so I decided to try it today.

We used to produce car immobilizers 20 years ago (when I type this I feel old 🙂 ) so I found in our stock one iButton receptacle and Dallas DS1990 ROM button.

Image

and wrote simple code to test it:

10 SETPIN 1,8 ‘LED output

as the receptacle have LED on it I decided to drive the LED with PIN(1) and to read the iButton with PIN(18) which is open collector

20 dim ar(10) ‘read iButton info

this defines the array where the read iButton info will be stored, later we can save this on file or to “learn” it and if later matched to open door lock, unlock car etc.

30 p = 18 ‘PIN(18) is used as iButton read as Open collector
40 PRINT “TOUCH iBUtton Please!”

now we are set and wait button to be pressed to the receptacle:

50 owreset p,presence ‘check for present
60 if presence = 1 then gosub 100 ‘if present read and display it
70 goto 50

if button is present the variable PRESENT =1 else 0

when the button is detected we write the info on the screen and blink the LED for 1/2 second:

100 ? “iButton detected:”;
110 owsearch p,1,ar(0): FOR I = 1 to 8: ? HEX$(AR(I));” “;:NEXT I: ?
120 PIN(1)=1: PAUSE 500: PIN(1) = 0 ‘blink the LED
130 RETURN

now let’s see what happend when we run this code:

Image

success, Well done Gerard!

DUINOMITE BASIC INSTRUCTIONS PER SECOND SPEED (BIPS)

Image

We got question on Duinomite support forum if small delays of 10 uS could be implemented with Duinomite Basic (DM-BASIC).

Duinomite Basic is interpreted language and it’s relatively slow, I write relatively as for some applications it’s still fast but for other slow. So I was interested how much time DM-BASIC needs to execute one BASIC instruction.

It was easy to implement as DM-BASIC have TIMER which increments every 1 mS, so I wrote this code:

10 TIMER = 0     ‘ clear the TIMER

20 I = I + 1         ‘ do one basic command like adding 1 to I variable

30 IF TIMER < 1000 THEN 20   ‘and execute this command until 1 second pass

40 PRINT “Speed approx.: “;I*3;” BIPS” ‘ print the result

RUN

Speed approx.: 31044 BIPS

BIPS = BASIC instructions per second

In the result we multiply I * 3 as the IF statement is composed by two instructions – the IF and the GOTO which forward the code to line 20

so the one simple BASIC instruction in DM-BASIC takes approximately 32 uS.

32 uS is slow for some processes, but if you want to do something fast you can always include it in the firmware as it’s open source and available for users to modify. this way was added support for the iButtons they require uS timing for communication and was impossible to do this in BASIC, so Gerard Sexton wrote additional BASIC commands which to communicate with MAXIM-DALLAS iBUTTONs.

Next Newer Entries