I want to call the pollkey function once per millisecond and increment the time variable (timeloc) once per second. I think that it should work if I add a call pollkey
to the delay subroutine so why is it not working?
.equ delaycount, 16911 #set right delay value here!
.text # Instructions follow
.global delay # Makes "main" globally known
delay: beq r4,r0,fin # exit outer loop
movi r8,delaycount # delay estimation for 1ms
inner: beq r8,r0,outer # exit from inner loop
subi r8,r8,1 # decrement inner counter
br inner
outer: subi r4,r4,1 # decrement outer counter
call pollkey
br delay
fin: ret
The above I ran with C that is
#include <stdio.h>
#include "system.h"
#include "altera_avalon_pio_regs.h"
extern void puttime(int* timeloc);
extern void puthex(int time);
extern void tick(int* timeloc);
extern void delay(int millisec);
extern int hexasc(int invalue);
#define TRUE 1
#define KEYS4 ( (unsigned int *) 0x840 )
int timeloc = 0x5957; /* startvalue given in hexadecimal/BCD-code */
int RUN = 1;
void pollkey() {
int action = IORD_ALTERA_AVALON_PIO_DATA(DE2_PIO_KEYS4_BASE);
if (action == 7) {
timeloc = 0x0;
} else if (action == 13) {
RUN = 0;
} else if (action == 14) {
RUN = 1;
} else if (action == 11) {
tick(&timeloc);
}
}
int main() {
while (TRUE) {
puttime(&timeloc);
delay(1);
IOWR_ALTERA_AVALON_PIO_DATA(DE2_PIO_REDLED18_BASE, timeloc);
if (RUN == 1) {
tick(&timeloc);
puthex(timeloc);
}
}
return 0;
}
int hex7seg(int digit) {
int trantab[] = { 0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00,
0x10, 0x08, 0x03, 0x46, 0x21, 0x06, 0x0e };
register int tmp = digit & 0xf;
return (trantab[tmp]);
}
void puthex(int inval) {
unsigned int hexresult;
hexresult = hex7seg(inval);
hexresult = hexresult | (hex7seg(inval >> 4) << 7);
hexresult = hexresult | (hex7seg(inval >> 8) << 14);
hexresult = hexresult | (hex7seg(inval >> 12) << 21);
IOWR_ALTERA_AVALON_PIO_DATA(DE2_PIO_HEX_LOW28_BASE, hexresult);
}
int hex7seg2(int digit) {
int trantab[] = { 0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00,
0x10, 0x08, 0x03, 0x46, 0x21, 0x06, 0x0e };
register int tmp = digit & 0xf0;
return (trantab[tmp]);
}
The polling works if it polls every second but I want to poll every millisecond and the only way I think I can do it is the call the pollkey from the dely subroutine but if I do that it's like nothing happens. Can you help me? I asked how to do it before and got an answer in C only while I think that the answer should be to change the assembly.
How to develop this algorithm?
Update
I'm getting much better results using br
instead of call
so I must check the difference. This is what I'm using that works better:
.equ delaycount, 16911 #set right delay value here!
.text # Instructions follow
.global delay # Makes "delay" globally known
delay: beq r4,r0,fin # exit outer loop
movi r8,delaycount # delay estimation for 1ms
inner: beq r8,r0,outer # exit from inner loop
subi r8,r8,1 # decrement inner counter
br inner
outer: subi r4,r4,1 # decrement outer counter
br pollkey
br delay
fin: ret
Now only problem is that the clock is ticking too fast.
Update
I think I solved it by introducing a counter that breaks modulo 1000 for seconds:
#include <stdio.h>
#include "system.h"
#include "altera_avalon_pio_regs.h"
extern void puttime(int* timeloc);
extern void puthex(int time);
extern void tick(int* timeloc);
extern void delay(int millisec);
extern int hexasc(int invalue);
#define TRUE 1
#define KEYS4 ( (unsigned int *) 0x840 )
int timeloc = 0x5957; /* startvalue given in hexadecimal/BCD-code */
int RUN = 0;
void pollkey() {
int action = IORD_ALTERA_AVALON_PIO_DATA(DE2_PIO_KEYS4_BASE);
if (action == 7) {
timeloc = 0x0;
puttime(&timeloc);
puthex(timeloc);
} else if (action == 13) {
RUN = 0;
} else if (action == 14) {
RUN = 1;
} else if (action == 11) {
tick(&timeloc);
puttime(&timeloc);
puthex(timeloc);
delay(1000);
}
}
int main() {
int counter = 0;
while (TRUE) {
pollkey();
delay(1);
++counter;
if (counter % 1000 == 0) {
IOWR_ALTERA_AVALON_PIO_DATA(DE2_PIO_REDLED18_BASE, timeloc);
if (RUN == 1) {
tick(&timeloc);
puttime(&timeloc);
puthex(timeloc);
}
}
}
return 0;
}
int hex7seg(int digit) {
int trantab[] = { 0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00,
0x10, 0x08, 0x03, 0x46, 0x21, 0x06, 0x0e };
register int tmp = digit & 0xf;
return (trantab[tmp]);
}
void puthex(int inval) {
unsigned int hexresult;
hexresult = hex7seg(inval);
hexresult = hexresult | (hex7seg(inval >> 4) << 7);
hexresult = hexresult | (hex7seg(inval >> 8) << 14);
hexresult = hexresult | (hex7seg(inval >> 12) << 21);
IOWR_ALTERA_AVALON_PIO_DATA(DE2_PIO_HEX_LOW28_BASE, hexresult);
}
int hex7seg2(int digit) {
int trantab[] = { 0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00,
0x10, 0x08, 0x03, 0x46, 0x21, 0x06, 0x0e };
register int tmp = digit & 0xf0;
return (trantab[tmp]);
}
.equ delaycount, 16911 #set right delay value here!
.text # Instructions follow
.global delay # Makes "delay" globally known
delay: beq r4,r0,fin # exit outer loop
movi r8,delaycount # delay estimation for 1ms
inner: beq r8,r0,outer # exit from inner loop
subi r8,r8,1 # decrement inner counter
br inner
outer: subi r4,r4,1 # decrement outer counter
br delay
fin: ret
The right way to run routines in an embedded system on particular timescales is to use a hardware timer and put the action (assuming it is relatively small!) into the interrupt service routine for that timer, or use that function to tell longer routines to run in the background loop.
Bodging the
delay()
function is going to result inOnce you have a 1ms timer, you can run the
pollkey
function from it and also schedule longer events accurately too.Of course at that point you've started to build an RTOS, so you might want to use one anyway :)