Interrupts by timer and locked code sections

Discussions and support about ChibiOS/RT, the free embedded RTOS.
User avatar
Crucian-Frik
Posts: 5
Joined: Fri Jul 14, 2023 2:52 pm
Has thanked: 4 times

Interrupts by timer and locked code sections

Postby Crucian-Frik » Wed Jul 26, 2023 11:00 am

Hello
I will be very glad if I get help

I'm really trying to understand how to use interruptions and locked code blocks
I tried to realize interruptions by timer
I have not find smth like "cycle timer" (an timer object, that alarm by a period, until it will be enabled) yet, maybe it does not exist in ChibiOS
So I wanted to restart the timer inside the interrupt

(I'm run this code on nucleo-F411RE using J-link)

I run this code

Code: Select all

#include "ch.h"
#include "hal.h"
#include "rt_test_root.h"
#include "oslib_test_root.h"
#include "submodules/print_lib/print_lib.h"

int timer_time = 500;


static virtual_timer_t vTimer;

void timef_foo(void);

CH_IRQ_HANDLER(foo) {
  CH_IRQ_PROLOGUE();
  printString(" INTERRUPTION ");
  chVTSet(&vTimer, TIME_MS2I(timer_time), (vtfunc_t)timef_foo, NULL);
  CH_IRQ_EPILOGUE();
}
void timef_foo(void){ foo(); }

bool flag = 0;


static THD_WORKING_AREA(waThread1, 256);
static THD_FUNCTION(Thread1, arg) {
  (void)arg;
  chRegSetThreadName("blinker1");
  systime_t prev = chVTGetSystemTime();
  while (true) {
    printString("th1");
    palSetPad(GPIOA, GPIOA_LED_GREEN);
    flag = 1;
    prev = chThdSleepUntilWindowed(prev, chTimeAddX(prev, TIME_MS2I(500)));
    palClearPad(GPIOA, GPIOA_LED_GREEN);
    flag = 0;
    prev = chThdSleepUntilWindowed(prev, chTimeAddX(prev, TIME_MS2I(1000)));
    chThdYield();
  }
}


static THD_WORKING_AREA(waThread2, 256);
static THD_FUNCTION(Thread2, arg) {
  (void)arg;
  chRegSetThreadName("blinker2");
  systime_t prev = chVTGetSystemTime();
  while (true){
    if (!flag){
    chSysLock(); // LOKKING
    printString("th2");
    palClearPad(GPIOA, GPIOA_LED_GREEN);
    printString("3");
    prev = chThdSleepUntilWindowed(prev, chTimeAddX(prev, TIME_MS2I(50)));
    palSetPad(GPIOA, GPIOA_LED_GREEN);
    printString("4");
    prev = chThdSleepUntilWindowed(prev, chTimeAddX(prev, TIME_MS2I(50)));
    printString("5");
    chSysUnlock(); //UNLOKKING
    }
  }
}

int main(void) {
  halInit();
  chSysInit();

  sdStart(&SD2, NULL);
 
  chVTObjectInit(&vTimer);
  chVTSet(&vTimer, TIME_MS2I(timer_time), (vtfunc_t)timef_foo, NULL);
  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO+1, Thread1, NULL);
  chThdCreateStatic(waThread2, sizeof(waThread2), NORMALPRIO, Thread2, NULL);

  while (true) {
    if (!palReadPad(GPIOC, GPIOC_BUTTON)) {
      test_execute((BaseSequentialStream *)&SD2, &rt_test_suite);
      test_execute((BaseSequentialStream *)&SD2, &oslib_test_suite);
    }
    chThdSleepMilliseconds(500);
  }
}


But I get this output

Code: Select all

>> th1 INTERRUPTION th2345th2345th2345th2345th2345th2345th2345th2345th2345th234 INTERRUPTION 5th23
and after this output my nucleo stops (although it should have worked further)
Using debug I found the file and line, where it stops:
file: /home/username/ChibiStudio/chibios_stable-21.11.x/os/common/startup/ARMCMx/compilers/GCC/vectors.S
line: 1027

I can not understand, why it stop every time and why locking section does not work
( I see this:
lock thread block
print: th2
print: 3
print: 4
print from IQR: INTERRUPTION (why IQR interrupting my locked block here??)
print: 5
unlock thread block
)

P.s.: perhaps there are grammatical errors in my address.. please excuse me, this is not my native language

User avatar
Giovanni
Site Admin
Posts: 14458
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: Interrupts by timer and locked code sections

Postby Giovanni » Wed Jul 26, 2023 2:22 pm

Hi,

Not sure what you are trying to do but you are mixing virtual timers callbacks with IRSs, no need to use those macros in callbacks.

There are examples in the book here: http://chibios.org/dokuwiki/doku.php?id ... :kernel_vt

Also, you need to use I-class functions in callbacks chVTSet() is different from chVTSetI(), note the final I. Calling the wrong function causes errors, you can catch those by enabling the "state checker" in chconf.h.

Giovanni

psyco
Posts: 21
Joined: Fri May 22, 2020 1:40 am
Been thanked: 11 times

Re: Interrupts by timer and locked code sections

Postby psyco » Thu Jul 27, 2023 2:57 am

The reason th2 is getting interrupted between 4 and 5 is you are using the wrong sleep calls for an OS lock section. You should be using an S-Class function like chSysSleepS (I don't think there is an S-Class windowed function). The non-S ones internally lock and unlock, probably undoing your lock.

However, sleeping or suspending won't keep the critical section held. The OS will just suspend the calling thread, allow another ready thread to run, and enable interrupts. chSysLock / Unlock just guarantee that any I or X-Class OS functions will happen sequentially without ISRs occurring. S-Class functions need to internally release the critical section to operate properly (note the critical section is re-taken before returning back to your thread). See here for more info.

Ditto for enabling CH_DBG_SYSTEM_STATE_CHECK which would also catch a wrong sleep in a lock zone.

User avatar
Crucian-Frik
Posts: 5
Joined: Fri Jul 14, 2023 2:52 pm
Has thanked: 4 times

Re: Interrupts by timer and locked code sections

Postby Crucian-Frik » Sun Jul 30, 2023 1:02 pm

Hello
thank you so much for your help :D

(my question arose when I was experimenting with the library's capabilities)
That code I divided into 2 parts

This example demonstrates the operation of critical code blocks in threads

Code: Select all

#include "ch.h"
#include "hal.h"
#include "rt_test_root.h"
#include "oslib_test_root.h"
#include "submodules/DebugLib/print_lib.h"

int timer_time = 500;

static THD_WORKING_AREA(waThread1, 256);
static THD_FUNCTION(Thread1, arg) {
  (void)arg;
  systime_t prev = chVTGetSystemTime();
  while (true) {
    printString("th1 Step 1\n");
    prev = chThdSleepUntilWindowed(prev, chTimeAddX(prev, TIME_MS2I(50)));

    printString("th1 Step 2\n");
    prev = chThdSleepUntilWindowed(prev, chTimeAddX(prev, TIME_MS2I(150)));
  }
}


static THD_WORKING_AREA(waThread2, 256);
static THD_FUNCTION(Thread2, arg) {
  (void)arg;
  while (true){
    chSysLock(); // LOKKING
    printString("th2");
    for (int i = 0; i < 100; i++)
      printString(".");
    printString("\n");
    chSysUnlock(); //UNLOKKING
  }
}

int main(void) {
  halInit();
  chSysInit();

  sdStart(&SD2, NULL);
 
  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO+1, Thread1, NULL);
  chThdCreateStatic(waThread2, sizeof(waThread2), NORMALPRIO, Thread2, NULL);

  while (true) {
    if (!palReadPad(GPIOC, GPIOC_BUTTON)) {
      test_execute((BaseSequentialStream *)&SD2, &rt_test_suite);
      test_execute((BaseSequentialStream *)&SD2, &oslib_test_suite);
    }
    chThdSleepMilliseconds(500);
  }
}


And another example for Virtual timer

Code: Select all

#include "ch.h"
#include "hal.h"
#include "rt_test_root.h"
#include "oslib_test_root.h"
#include "submodules/DebugLib/print_lib.h"

int timer_time = 370;

static virtual_timer_t vTimer;

void callback(void){
  printString("callback interruption \n");
  chVTSetI(&vTimer, TIME_MS2I(timer_time), (vtfunc_t)callback, NULL);
}

static THD_WORKING_AREA(waThread1, 256);
static THD_FUNCTION(Thread1, arg) {
  (void)arg;
  systime_t prev = chVTGetSystemTime();
  while (true) {
    printString("th1 Step 1\n");
    prev = chThdSleepUntilWindowed(prev, chTimeAddX(prev, TIME_MS2I(50)));

    printString("th1 Step 2\n");
    prev = chThdSleepUntilWindowed(prev, chTimeAddX(prev, TIME_MS2I(150)));
  }
}


static THD_WORKING_AREA(waThread2, 256);
static THD_FUNCTION(Thread2, arg) {
  (void)arg;
  while (true){
    chSysLock(); // LOKKING
    printString("th2");
    for (int i = 0; i < 100; i++)
      printString(".");
    printString("\n");
    chSysUnlock(); //UNLOKKING
  }
}

int main(void) {
  halInit();
  chSysInit();

  sdStart(&SD2, NULL);
 
  chVTObjectInit(&vTimer);
  chVTSet(&vTimer, TIME_MS2I(timer_time), (vtfunc_t)callback, NULL);
  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO+1, Thread1, NULL);
  chThdCreateStatic(waThread2, sizeof(waThread2), NORMALPRIO, Thread2, NULL);

  while (true) {
    if (!palReadPad(GPIOC, GPIOC_BUTTON)) {
      test_execute((BaseSequentialStream *)&SD2, &rt_test_suite);
      test_execute((BaseSequentialStream *)&SD2, &oslib_test_suite);
    }
    chThdSleepMilliseconds(500);
  }
}


Conclusions I made:
1) The critical section ensures that the context of the current thread does not switch to any other context,
but allows for processing interrupts within itself
2) Sleep mode (or other suspension of work) may lead to context switching during this delay, but then resources will be given back to the thread
3) The critical section cannot be interrupted by the callback of the virtual timer, but can be interrupted by the ISR

If anyone has any advice or comments - I will be glad to read))

User avatar
Giovanni
Site Admin
Posts: 14458
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: Interrupts by timer and locked code sections

Postby Giovanni » Sun Jul 30, 2023 1:50 pm

My comment: you need to enable the "state checker" in chconf.h, you still have obvious violations in that code.

Giovanni

User avatar
Crucian-Frik
Posts: 5
Joined: Fri Jul 14, 2023 2:52 pm
Has thanked: 4 times

Re: Interrupts by timer and locked code sections

Postby Crucian-Frik » Mon Jul 31, 2023 10:08 am

Thanks!
I have designated CH_DBG_SYSTEM_STATE_CHECK as TRUE in chconf.h, but now my nucleo freezes after the callback is triggered
Did I do something wrong?
What other violations are there?

User avatar
Giovanni
Site Admin
Posts: 14458
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: Interrupts by timer and locked code sections

Postby Giovanni » Mon Jul 31, 2023 12:41 pm

Hi,

Look at the stack trace after the halt, it will point you to the invalid call.

Some suggestions here: http://www.chibios.org/dokuwiki/doku.ph ... ebug_guide

Giovanni

User avatar
Crucian-Frik
Posts: 5
Joined: Fri Jul 14, 2023 2:52 pm
Has thanked: 4 times

Re: Interrupts by timer and locked code sections

Postby Crucian-Frik » Mon Aug 21, 2023 10:37 am

Hello, thanks for support

I kind of fixed timer's callback
And added a mutex to the critical section as well

Everything works, but since there was a comment indicating the erroneous use of critical sections, I decided to attach the code again

If it's not difficult, please take a look: is everything right now?

Code: Select all

#include "ch.h"
#include "hal.h"
#include "rt_test_root.h"
#include "oslib_test_root.h"
#include "submodules/DebugLib/print_lib.h"

int timer_time = 500;
int counter = 0;
static mutex_t mut;

static virtual_timer_t vTimer;

void callback(void){
  chSysLockFromISR();
  printString("callback interruption \n");
  chVTSetI(&vTimer, TIME_MS2I(timer_time), (vtfunc_t)callback, NULL);
  chSysUnlockFromISR();
}

static THD_WORKING_AREA(waThread1, 256);
static THD_FUNCTION(Thread1, arg) {
  (void)arg;
  systime_t prev = chVTGetSystemTime();
  while (true) {

    chMtxLock(&mut);
    counter *= 10;
    printPInt(counter);
    chMtxUnlock(&mut);

    printString("\nth1 Step 1\n");
    prev = chThdSleepUntilWindowed(prev, chTimeAddX(prev, TIME_MS2I(0.1*timer_time)));

    printString("th1 Step 2\n");
    prev = chThdSleepUntilWindowed(prev, chTimeAddX(prev, TIME_MS2I(0.1*timer_time)));
  }
}


static THD_WORKING_AREA(waThread2, 256);
static THD_FUNCTION(Thread2, arg) {
  (void)arg;
  while (true){
    chSysLock();

    printString("th2 ");

    chMtxLockS(&mut);
    counter++;
    printPInt(counter);
    printString("\n");
    chMtxUnlockS(&mut);

    chSysUnlock();
  }
}

int main(void) {
  halInit();
  chSysInit();

  sdStart(&SD2, NULL);
 
  chVTObjectInit(&vTimer);
  chMtxObjectInit(&mut);

  chVTSet(&vTimer, TIME_MS2I(timer_time), (vtfunc_t)callback, NULL);
  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO+1, Thread1, NULL);
  chThdCreateStatic(waThread2, sizeof(waThread2), NORMALPRIO, Thread2, NULL);

  while (true) {
    if (!palReadPad(GPIOC, GPIOC_BUTTON)) {
      test_execute((BaseSequentialStream *)&SD2, &rt_test_suite);
      test_execute((BaseSequentialStream *)&SD2, &oslib_test_suite);
    }
    chThdSleepMilliseconds(500);
  }
}

User avatar
Giovanni
Site Admin
Posts: 14458
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: Interrupts by timer and locked code sections

Postby Giovanni » Mon Aug 21, 2023 1:10 pm

It depends on what those "print" functions do, calling those from threads AND from callback does not look right, the mutex will not prevent the callback from calling that.

Giovanni

User avatar
Crucian-Frik
Posts: 5
Joined: Fri Jul 14, 2023 2:52 pm
Has thanked: 4 times

Re: Interrupts by timer and locked code sections

Postby Crucian-Frik » Mon Aug 21, 2023 3:38 pm

The mutex should protect the "counter" variable in this example
And every time before using "counter" mutex also is used
The print function works using this:

Code: Select all

void SWO_PrintChar(char const c, uint8_t const portNo)
{
    volatile int timeout;

    /* Check if Trace Control Register (ITM->TCR at 0xE0000E80) is set */
    /* check Trace Control Register if ITM trace is enabled*/
    if ((ITM->TCR & ITM_TCR_ITMENA_Msk) == 0)
    {
        return; /* not enabled? */
    }
    /* Check if the requested channel stimulus port (ITM->TER at 0xE0000E00) is enabled */
    /* check Trace Enable Register if requested port is enabled */
    if ((ITM->TER & (1ul << portNo)) == 0)
    {
        return; /* requested port not enabled? */
    }
    timeout = 5000; /* arbitrary timeout value */
    while (ITM->PORT[0].u32 == 0)
    {
        /* Wait until STIMx is ready, then send data */
        if (--timeout == 0)
        {
            return; /* not able to send */
        }
    }
    ITM->PORT[0].u8 = (uint8_t)c;
}


Return to “ChibiOS/RT”

Who is online

Users browsing this forum: No registered users and 3 guests