Polling with C and assembly for Nios 2

1.3k views Asked by At

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
1

There are 1 answers

0
Martin Thompson On BEST ANSWER

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 in

  • variable delays - the delay function is already an approximation using instruction cycles, and if you run off to call another function in the middle sometimes it'll only get worse
  • inaccurate 1ms polling - the level of inaccuracy may or may not be good enough for your purposes.

Once 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 :)