Skip to content

Millis Accuracy and Interrupt Overhead On the 1806

March 17, 2017

I’m working on an Arduino-style millis() function for the 1806. The idea is that I set a timer to interrupt every ms and increment a variable in memory that i can query from my code. A complication is that at 4mhz the timer counts down once every 64us which doesn’t divide evenly into 1000 – the closest you get is 16 counts for 1.024ms. So I set the counter to 16 and let it interrupt the cpu every time it counts down to 0. I increment the millis location in storage and also add 3 to a fraction variable. If the fraction goes over 125 i clear it and boost millis by one. The arduino uses exactly the same factors which is the only reason i figured it out!

unsigned int millis=0; unsigned char fractmillis=0;
void LDC(unsigned char c){
	asm(" glo r12 ; pick up the value\n"
		" LDC ;		set the timer\n");
unsigned char GEC(){
	asm(" GEC ;		get the value\n"
		" plo r15\n ldi 0\n phi r15 \n"
		" cretn ;	this is the actual return\n");
	return 42;//just to keep the compiler happy
void initmillis(){
	asm(" CID; disable timer interrupts\n");
	LDC(16);//load the timer
	asm(" ldaD R1,.handler\n");
	asm(" STM; start the timer\n");
	asm(" CIE; enable timer interrupts\n");
	asm(".done: ;millis interrupt cleanup\n"
		" INC 2	  ; X=2!\n"
		" RLXA r15\n"
		" RLXA r14\n"
		" LDA 2	  ; RESTORE DF\n"
		" SHR\n"
		" LDA 2	  ; NOW D\n"
		" RET	  ; now X&P\n");

	asm(".handler: ;actual interrupt handler prolog\n"
		" DEC 2	  ; prepare stack to\n"
		" SAV	  ; SAVE X AND P (from T)\n"
		" BCI .go ; clear timer int\n"
		".go: \n"
		" DEC 2\n"
		" STXD	  ; SAVE D\n"
		" SHLC	  \n"
		" STXD	  ; SAVE DF\n"
		" RSXD r14  ;save memaddr helper reg\n"
		" RSXD r15  ;save work reg\n");

	asm(" ld2 r15,'D',(_millis),0 ;load current millis value\n"
		" inc r15	;increase millis\n"
		" inc r14	;point to fractional part of millis\n"
		" ldn r14	;pick up fractional value immediately following\n"
		" adi 3\n str r14 ;add 3 to the fractional part and put it back\n"
		" smi 125	;test for extra count\n"
		" lbnf 		.noxtra ;no borrow, no extra counts\n"
		" str r14	;store the fraction\n"
		" inc r15	;add extra count to millis\n"
		".noxtra: 	;bypass extra count\n"
		" dec r14\n glo r15\n str r14\n"
		" dec r14\n ghi r15\n str r14\n"
		" lbr .done\n");
//timer test 1 - 1806 timer counter demo
#include <olduino.h>
#include <nstdlib.h>
#include <cpu1802spd4port7.h>
#include "timer1806.h"
void main()
	unsigned int t1,t2;
	int i,d=100;
	printf("Hello Timer Fans\n");
	asm(" seq\n");
	asm(" req\n");
	printf("Now we're clocking!\n");
	asm(" seq\n");
	asm(" req\n");
	printf("t1=%d, t2=%d\n\n",t1,t2);
	printf("spin delay of %d ms\n",d);
	printf("covered %d timer ms\n",t2-t1);
#include <nstdlib.c>
#include <olduino.c>

17-03-17 timer117-03-17 timer2
So, the bad news is in that first image where it compares the results of my millis calculation with the spin delay showing a spin delay of 100ms compared to 137ms calculated with millis. The better news is the second image which shoes two things: The actual time is almost bang on the 137ms reported by millis and the spin delay’s 100ms is actuslly 113 ms.  Still, that’s an overhead of more than 20% for tracking millis.  I can improve that in a few ways:
I Can reduce the resolution to say 10ms; I can reduce the accuracy and accept that a millisecond will be 1.024ms; I can keep the millis value in a register rather than a global memory variable. I think I’ll try reducing the resolution to 2ms and giving up the fractional ms accuracy.

Also: Ahah! I took out the timer stuff and recompiled for the 1802, then re-measured the spin delay with the logic analyzer. A 100ms nominal spin delay took 103ms with the 1802 instruction set. I think the difference is down to reserving registers 0 and 1 making them unavailable for variables.

Yup: Due to an error in the machine description file, reserving regs 0 and 1 left the compiler with only reg 7 for variable and it was going nuts spilling and reloading. I fixed the error(adding regs 4 and 5 to the pool at the same time) and the spin delay went down to almost the nominal value. Interestingly(to me) I had realized a while ago that R6 was always available for variables even though it’s the link register. Both the SCRT and SCAL/SRET always save it before using it.

So, in the end, I may leave things as they are. I bought 20% in performance with the 1806 and if i give that up for better timing, so be it.

From → Uncategorized

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: