Author Topic: Using uDisable_Interrupt() and uEnable_Interrupt()  (Read 6156 times)

Offline FAQ

  • Newbie
  • *
  • Posts: 27
    • View Profile
Using uDisable_Interrupt() and uEnable_Interrupt()
« on: May 31, 2009, 12:18:52 AM »

When and how are the functions uDisable_Interrupt() and uEnable_Interrupt() to be used?

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: Using uDisable_Interrupt() and uEnable_Interrupt()
« Reply #1 on: May 31, 2009, 12:23:44 AM »
Hi

These functions are only needed when there is a section of code which should not be disturbed by interrupts/an interrupt.
They should always be used together as a pair.

Eg. If you have an interrupt routine incrementing a variable called iCounter and some ‘normal’ code decrementing it after a task it has been woken by the interrupt there is a risk involved.

Int iCounter = 0;

Interrupt()
{
    iCounter++;
}

Task()
{
    iCounter--;
}



When the task decrements the counter it generally does:
-   Read counter value from memory
-   Decrement the counter value in the CPU register
-   Write the new value back to the variable in memory

However if the interrupt were called during the “Decrement the counter value in CPU register”. The value which is written back to memory would be incorrect – it will have missed the new increment!
Therefore this sequence requires protection:

Task()
{
    uDisable_Interrupt();
    iCounter--;
    uEnable_Interrupt();
}



There are several critical regions in the drivers and scheduler which have to use this technique. When you call uTasker OS calls they always protect themselves against such possible problems.
If you haven’t added your own interrupt routines you probably don't generally need to use this technique.
In fact there is only one use of this in the demo application code. This is in the following routine in application.c:


// Save time to RTC and save user settings
//
static void fnSaveTime(void)
{
    unsigned char ucSetRTC[9]; //= {ADDRTC_WRITE, 0, 0, 0, 0, 0, 0, 0, 0}; {35}
    uMemset(ucSetRTC, 0, sizeof(ucSetRTC));
    ucSetRTC[0] = ADDRTC_WRITE;

    uDisable_Interrupt();                                                // protect from interrupts (increments of time) when converting
    ucSetRTC[2] = fnBCD(stPresentTime.ucSeconds);                        // Convert local time format to RTC format before saving
    ucSetRTC[3] = fnBCD(stPresentTime.ucMinuteOfHour);
    ucSetRTC[4] = fnBCD(stPresentTime.ucHourOfDay);
    ucSetRTC[6] = fnBCD(stPresentTime.ucDayOfMonth);
    ucSetRTC[7] = fnBCD(stPresentTime.ucMonthOfYear);
    ucSetRTC[8] = fnBCD(stPresentTime.ucYear);
    uEnable_Interrupt();

    fnWrite(IICPortID, (unsigned char *)ucSetRTC, sizeof(ucSetRTC));     // set new date and time
}


The reason is because the time value is being incremented every second using an interrupt. If this region were not protected from this interrupt it would be possible for the time to be modified between setting the seconds and the year – this could cause a strange time value to be set, which would only be false when the interrupt happens to occur at this critical time. Such errors can sometimes be quite hard to find because they only happen infrequently!!

Regards

Mark