ctimerfpgaxilinxmicroblaze

Setting up a timer with Microblaze?


What is the best way to create a timer with Microblaze which would allow me to have it work more similarly to a function like delay_ms() or sleep() in more conventional scripts?

Easily, I can create a stupid function like this:

void delay_ms(int i) {
    //mind that I am doing this on the top of my head
    for(delays=0; delay<(i*((1/frequency of the device)/2)); delays++) {
    }
}

... but that would only have processor process nothing until it finishes, while in reality I need it to have the function allow me to do stop one process for a certain period of time while another one continues working.

Such thing is possible, no doubt about that, but what would the simplest solution to this problem be?

(I am using Spartan-3A, but I believe the solution would work for different kits, FPGAs as well.)


Solution

  • TL;DR

    Use a micro OS, like FreeRTOS.

    Bad answer

    Well, if you have no OS, no task commutation but have an external timer, you can use the following approach:

    Enable interruption for your hardware timer, and manage a counter driven by this interrution:

    You should have something like

    /**timer.c**/
    
    /* The internal counters
     * each task have its counter
     */
    static int s_timers[NUMBER_OF_TASKS] = {0,0};
    
    /* on each time tick, decrease timers */
    void timer_interrupt()
    {
        int i;
        for (i = 0; i < NUMBER_OF_TASKS; ++i)
        {
            if (s_timer[i] > 0)
            {
                s_timer[i]--;
            }
        }
    }
    
    /* set wait counter:
     * each task says how tick it want to wait
     */
    void timer_set_wait(int task_num, int tick_to_wait)
    {
        s_timer[task_num] = tick_to_wait;
    }
    
    /**
     * each task can ask if its time went out
     */
    int timer_timeout(int task_num)
    {
        return (0 == s_timer[task_num]);
    }
    

    Once you have something like a timer (the code above is easily perfectible), program your tasks:

    /**task-1.c**/
    
    /*TASK ID must be valid and unique in s_timer */
    #define TASK_1_ID 0
    
    void task_1()
    {
        if (timer_timeout(TASK_1_ID))
        {
            /* task has wait long enough, it can run again */
    
            /* DO TASK 1 STUFF */
            printf("hello from task 1\n");
    
            /* Ask to wait for 150 ticks */
            timer_set_wait(TASK_1_ID, 150);
        }
    }
    
    /**task-2.c**/
    
    /*TASK ID must be valid and unique in s_timer */
    #define TASK_2_ID 1
    
    void task_2()
    {
        if (timer_timeout(TASK_2_ID))
        {
            /* task has wait long enough, it can run again */
    
            /* DO TASK 2 STUFF */
            printf("hello from task 2\n");
    
            /* Ask to wait for 250 ticks */
            timer_set_wait(TASK_2_ID, 250);
        }
    }
    

    And schedule (a big word here) the tasks:

    /** main.c **/
    
    int main()
    {
        /* init the program, like set up the timer interruption */
        init() 
    
        /* do tasks, for ever*/
        while(1)
        {
            task_1();
            task_2();
        }
        return 0;
    }
    

    I think what I have described is a lame solution that should not be seriously used.

    The code I gave is full of problems, like what happens if a task become to slow to execute...

    Instead, you --could-- should use some RT Os, like FreeRTOS which is very helpful in this kind of problems.