This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

RTOS task swtiching faliure

I have a bunch of tasks running in Round robin fashion. They perform the task of reading from four serial ports and polling a push button state plus one more task to print data on serial port. The problem I am facing is that if I try to initialize peripheral modules using "C1_init()" in the "task_init" task, the scheduler does not pass to the main task. But if I remove those functions the scheduler then cycles through all the tasks perfectly. I wonder if anyone can help me out here.

__task void task_uart0(void) {

        for(;;)
        {
                                read_uart0();
                        os_evt_set(0x0004,id0);
        }
}

__task void task_uart1(void) {

        for(;;) {
                                //read_uart1();
                                os_evt_set(0x0004,id0);
        }
}

__task void task_usart0(void) {
        for(;;) {
                                        read_usart0();
                                os_evt_set(0x0004,id0);

        }
}

__task void task_usart1(void) {
        for(;;) {
                                        read_usart1();
                                os_evt_set(0x0004,id0);
        }
}

__task void task_swdbutton(void) {

        for(;;) {
                                if ((button_get() != 0) && (buttonState !=1)) {
                                        buttonState = 1;
                                        LED_on(0);
                                } else if ((button_get() == 0) && (buttonState ==1)){
                                        printf("Button press and release\n\r");
                                        LED_blink(3);
                                        //LED_off(0);
                                        ser_print(C1,"stop\r\n");
                                        ser_print(C2,"stop\r\n");
                                        ser_print(C3,"stop\r\n");
                                        buttonState = 0;
                                }
                                os_evt_set(0x0004,id0);
        }
}

__task void task_other(void) {

        for(;;){
        printf("RA0: %d",REG_TC0_RA0);
        printf("RB0: %d",REG_TC0_RB0);
        printf("RC0: %d",REG_TC0_RC0);
        printf("CV0: %d",REG_TC0_CV0);

        os_evt_set(0x0004,id0);

        }
}

__task void task_main(void) {
        id2 = os_tsk_create(task_usart1,0);
        id3 = os_tsk_create(task_uart0,0);
        id4 = os_tsk_create(task_usart0,0);
        id5 = os_tsk_create(task_uart1,0);
        id6 = os_tsk_create(task_swdbutton,0);
        id7 = os_tsk_create(task_other,0);
        printf("Initialized\r\n");
        for(;;) {
                // UARTS & USARTS
                os_evt_set(0x0004,id2);
                os_evt_wait_or(0x0004,0xFFFF);
                os_evt_set(0x0004,id3);
                os_evt_wait_or(0x0004,0xFFFF);
                os_evt_set(0x0004,id4);
                os_evt_wait_or(0x0004,0xFFFF);

                os_evt_set(0x0004,id5);
                os_evt_wait_or(0x0004,0xFFFF);

                os_evt_set(0x0004,id6);
                os_evt_wait_or(0x0004,0xFFFF);

                os_evt_set(0x0004,id7);
                os_evt_wait_or(0x0004,0xFFFF);

        }
}

__task void task_init(void) {

        for(;;){

                id1 = os_tsk_self();
                if(init_flg==0){

                        C1_init(); // functions to initialize peripheral modules
                        C2_init();
                        C3_init();
                        Cn_start();
                        init_flg=1;
                }
                id0 = os_tsk_create(task_main,0);
                os_dly_wait(5);
                os_tsk_delete_self();
        }
}

  • But haven't you verified that your functions C1_init(), C2_init(), ... actually manages to initialize the respective modules and return? If any of these functions doesn't return, then you will never get to the part where you create the "main" thread.

    This is a typical situation where _you_ must spend some time doing some debugging.

    Why did you even bring in a loop in task_init()? It contain nothing that is expected to loop. And why does it even have to look at any init_flg variable? Shouuld that task really be started more than once so it happens that it does not need to run that section? And should any other taks ever be started without this task having performed the initialization?

    Another thing - "flag" in a variable name doesn't tell much. So it's a flag. But the name can't tell a reader if "init_flg" means you need to initialize. Or if you have initialized. Nor does it tell the reader what it is you have initialized - or needs to initialize. Better with a variable "peripherials_initialized" - then the name clearly indicates the meaning if the variable is true or false. But as noted earlier - I can't see why you would need such a global state variable in the first place.

    Next thing - why implement your complicated round robin of the tasks? Tasks means you allocate many individual stacks. Multiple stacks just to allow you lots of concurrency.

    If all you do is round-robin, then you could just use normal functions and do:

    task1_state_t task1_state;
    task2_state_t task2_state;
    ...
    
    void task1() {
        switch (task1_state.state) {
            ...
        }
    }
    
    void main() {
        init();
        for (;;) {
            call_task1();
            call_task2();
            call_task3();
            ...
        }
    }
    

    If you do want individual tasks with own stacks because you want to be able to have them yield in the middle of something without a complicated state machine, then you can get the OS to round-robin them without preemption. Then you still don't need any "main" thread that do the round-robin assignments. Each task just yields and the OS moves to the next ready task.

    But in the end - the great thing with tasks and an RTOS is that they can just sleep while waiting for something that needs to be serviced. And the sequence of events and individual thread priorities decides exactly which thread will run. So one UART may run at high baudrate requiring quick service. While another UART runs at low baudrate and doesn't need to react within a fraction of a millisecond when data arrives. Your round-robin implementation adds complexity without giving you any advantages. The goal with an RTOS is to the reverse - to give you advantages while avoiding complexities.