Пример #1
0
static void taskOnADCComplete(uint16_t initialResumeCondition)
{
    ASSERT(initialResumeCondition == EVT_ADC_CONVERSION_COMPLETE);

#ifdef DEBUG
    /* Test: Our ADC interrupt should be synchronous with Arduino's TIMER0_OVF (see
       wiring.c). */
    extern volatile unsigned long timer0_overflow_count;
    uint32_t deltaCnt = timer0_overflow_count;
#endif

    do
    {
        /* Test: Our ADC interrupt should be synchronous with Arduino's TIMER0_OVF. */
        ASSERT(adc_noAdcResults + deltaCnt == timer0_overflow_count);

        /* Call the actual interrupt handler code. */
        adc_onConversionComplete();
    }
    while(rtos_waitForEvent( EVT_ADC_CONVERSION_COMPLETE | RTOS_EVT_DELAY_TIMER
                           , /* all */ false
                           , /* timeout */ 1
                           )
#ifdef DEBUG
          == EVT_ADC_CONVERSION_COMPLETE
#endif
         );

    /* The following assertion fires if the ADC interrupt isn't timely. The wait condition
       specifies a sharp timeout. True production code would be designed more failure
       tolerant and e.g. not specify a timeout at all. This code would cause a reset in
       case. */
    ASSERT(false);

} /* End of taskOnADCComplete */
Пример #2
0
static void taskButton(uint16_t initialResumeCondition)
{
    ASSERT(initialResumeCondition == EVT_TRIGGER_TASK_BUTTON);
    do
    {
        but_onNewButtonVoltage();
    }
    while(rtos_waitForEvent(EVT_TRIGGER_TASK_BUTTON, /* all */ false, 0));
    ASSERT(false);

} /* End of taskButton */
Пример #3
0
static void taskIdleFollower(uint16_t initialResumeCondition)
{
    ASSERT(initialResumeCondition == EVT_TRIGGER_IDLE_FOLLOWER_TASK);
    do
    {
        dpy_display.printCpuLoad(_cpuLoad);
    }
    while(rtos_waitForEvent(EVT_TRIGGER_IDLE_FOLLOWER_TASK, /* all */ false, 0));
    ASSERT(false);

} /* End of taskIdleFollower */
Пример #4
0
inline boolean dpy_display_t::acquireMutex()
{
    uint16_t gotEvtVec = rtos_waitForEvent( EVT_MUTEX_LCD | RTOS_EVT_DELAY_TIMER
                                          , /* all */ false
                                          , 1 /* unit is 2 ms */
                                          );

    /* Normally, no task will block the display longer than 2ms and the debug compilation
       double-checks this. Production code can nonetheless be implemented safe; in case it
       can simply skip display operation. */
    ASSERT(gotEvtVec == EVT_MUTEX_LCD);
    return (gotEvtVec & EVT_MUTEX_LCD) != 0;

} /* End of dpy_display_t::acquireMutex */
Пример #5
0
static void task00_class00(uint16_t initCondition)

{
    for(;;)
    {
        ++ _noLoopsTask00_C0;

        /* To see the stack reserve computation working we invoke a nested sub-routine
           after a while. */
        if(millis() > 20000ul)
            subRoutine(1);
        if(millis() > 30000ul)
            subRoutine(2);
        if(millis() > 40000ul)
            subRoutine(3);
        
        /* The next operation (Arduino delay function) takes the demanded world time in ms
           (as opposed to CPU time) even if it is interrupted because of an elapsed round
           robin counter.
             This task has a round robin time slice of 10 tics (20 ms) only, so it should
           surely be interrupted during execution of delay. The other round robin task has
           a time slice of 4 ms. No other tasks demand the CPU significantly. Consequently,
           the code in delay should not be interrupted for longer than about 4 ms. Coming
           back here means to immediately do the next check if the demanded time has
           elapsed. We expect thus to not prolongue the demanded time by more than about 4
           ms. */
        uint32_t ti0 = millis();
        delay(600 /* ms */);
        uint16_t dT = (uint16_t)(millis() - ti0);
        ASSERT(dT >= 599)
        ASSERT(dT < 609);

        /* Wait for an event from the idle task. The idle task is asynchrounous and its
           speed depends on the system load. The behavior is thus not perfectly
           predictable. Let's have a look on the overrrun counter for this task. It might
           occasionally be incremented. */
        if(rtos_waitForEvent( /* eventMask */ RTOS_EVT_EVENT_03 | RTOS_EVT_DELAY_TIMER
                            , /* all */ false
                            , /* timeout */ 1000 /* unit 2 ms */
                            )
           == RTOS_EVT_DELAY_TIMER
          )
        {
            ++ _task00_C0_cntWaitTimeout;
        }
    }
} /* End of task00_class00 */
Пример #6
0
static void taskDisplayVoltage(uint16_t initialResumeCondition)
{
    ASSERT(initialResumeCondition == EVT_TRIGGER_TASK_DISPLAY_VOLTAGE);
    
    /* The rate of the result values is about once every 133 ms, which makes the display
       quite nervous. And it would become even faster is the averaging constant
       ADC_NO_AVERAGED_SAMPLES would be lowered. Therefore we average here again to get are
       better readable, more stable display.
         The disadvantage: The state machine in module adc synchronizes switching the ADC
       input with the series of averaged samples. This is impossible here, which means that
       - in the instance of switching to another ADC input - the averaging series formed
       here typically consist of some samples from the former input and some from the new
       input. We do no longer see a sharp switch but a kind of cross fading. */
#define NO_AVERAGED_SAMPLES     5
#define SCALING_BIN_TO_V(binVal)                                                            \
        ((ADC_U_REF/(double)((uint32_t)NO_AVERAGED_SAMPLES*ADC_NO_AVERAGED_SAMPLES)/1024.0) \
         *(double)(binVal)                                                                  \
        )

    static uint32_t accumuatedAdcResult_ = 0;
    static uint8_t noMean_ = NO_AVERAGED_SAMPLES;
    do
    {
        /* This low priority task needs to apply a critical section to read the result of
           the ADC interrupt task of high priority. */
        cli();
        accumuatedAdcResult_ += adc_inputVoltage;
        sei();
        
        if(--noMean_ == 0)
        {
            dpy_display.printVoltage(SCALING_BIN_TO_V(accumuatedAdcResult_));
            
            /* Start next series on averaged samples. */
            noMean_ = NO_AVERAGED_SAMPLES;
            accumuatedAdcResult_ = 0;
        }
    }        
    while(rtos_waitForEvent(EVT_TRIGGER_TASK_DISPLAY_VOLTAGE, /* all */ false, 0));
    ASSERT(false);
    
#undef NO_AVERAGED_SAMPLES
#undef SCALING_BIN_TO_V
} /* End of taskDisplayVoltage */
Пример #7
0
static RTOS_TRUE_FCT void getResource()
{
    /* The task which calls this routine suspends itself by waiting only for the mutex
       which indicates ownership of the shared resource. No timeout is specified.
       Therefore, testing the return code of the suspend command is superflous; any value
       other than the mutex event would be an error of RTuinOS.
         Don't be confused that the same function getResource can individually suspend
       different tasks all calling this function - even overlappingly in time. This is
       what reentrant actually means: The same function code operates individually and
       independently for each caller.
         Only to prove this statement we declared the functions as RTOS_TRUE_FCT. Otherwise
       gcc would simply inline it and there was no issue with reentrance at all. */
#ifdef DEBUG
    uint16_t postedEvtVec =
#endif
    rtos_waitForEvent(EVT_MUTEX_OWNING_RESOURCE, false, 0);
    ASSERT(postedEvtVec == EVT_MUTEX_OWNING_RESOURCE);

} /* End of getResource */
static void task00_class00(uint16_t initCondition)

{
    uint32_t ti1, ti2=0;

    for(;;)
    {
        ++ _noLoopsTask00_C0;

        /* To see the stack reserve computation working we invoke a nested sub-routine
           after a while. */
        if(millis() > 20000ul)
            subRoutine(1);
        if(millis() > 30000ul)
            subRoutine(2);
        if(millis() > 40000ul)
            subRoutine(3);

        /* Wait for an event from the idle task. The idle task is asynchrounous and its
           speed depends on the system load. The behavior is thus not perfectly
           predictable. */
        if(rtos_waitForEvent( /* eventMask */ RTOS_EVT_EVENT_03 | RTOS_EVT_DELAY_TIMER
                            , /* all */ false
                            , /* timeout */ 200 /*ms*/
                            )
           == RTOS_EVT_DELAY_TIMER
          )
        {
            ++ _task00_C0_cntWaitTimeout;
        }

        /* This tasks cycles with the lowest frequency, once per system timer cycle.
            CAUTION: Normally, this is not permitted. If the suspend time is more than
           half the range of the data type chosen for its system time RTuinOS is no longer
           capable to safely recognize task overruns. False recognitions would lead to bad
           task timing as the corrective action is to make the (only seemingly) late task
           due immediately. */
        rtos_suspendTaskTillTime(/* deltaTimeTillRelease */ 0);

        /* A task period of more than half the system timer cycle leads to a high
           probability of seeing task overruns where no such overruns happen. (See RTuinOS
           manual.)
             We therefore disable the standard corrective action in case of overruns; macro
           RTOS_OVERRUN_TASK_IS_IMMEDIATELY_DUE is set to RTOS_FEATURE_OFF.
             The false overruns are counted nonetheless by rtos_getTaskOverrunCounter.
           Here, we implement our own overrun counter by comparing the task cycle time with
           the Arduino timer which coexists with the RTuinOS system timer. */
        ti1 = millis();
        if(ti2 > 0)
        {
            ti2 = ti1-ti2;
            if(ti2 < (uint32_t)(0.9*256.0*RTOS_TIC*1000.0)
               ||  ti2 > (uint32_t)(1.1*256.0*RTOS_TIC*1000.0)
              )
            {
                ++ _task00_C0_trueTaskOverrunCnt;
            }
        }
        ti2 = ti1;

        /* What looks like CPU consuming floating point operations actually is a
           compile time operation. Here's the prove - which also produces no CPU load
           as it is removed by the optimizer. (Sounds contradictory but it isn't.) */
        ASSERT(__builtin_constant_p((uint32_t)(0.9*256.0*RTOS_TIC*1000.0))
               &&  __builtin_constant_p((uint32_t)(1.1*256.0*RTOS_TIC*1000.0))
              );

    } /* End for(ever) */

} /* End of task00_class00 */