Events for serial driver transmission completion

Discussions and support about ChibiOS/RT, the free embedded RTOS.
User avatar
FXCoder
Posts: 384
Joined: Sun Jun 12, 2016 4:10 am
Location: Sydney, Australia
Has thanked: 180 times
Been thanked: 130 times

Re: Events for serial driver transmission completion

Postby FXCoder » Thu Aug 10, 2017 9:13 am

Hi Raul.
I was just putting your code into a test project to dump event sequences out and got a compile error.
Maybe you just retyped the code into your post rather than copy and paste?
If you did copy/paste then do you have two buffers defined?
One named buff and the other buf?

Code: Select all

sdWrite (&SD2, buff, sizeof (buf));


Bob

User avatar
FXCoder
Posts: 384
Joined: Sun Jun 12, 2016 4:10 am
Location: Sydney, Australia
Has thanked: 180 times
Been thanked: 130 times

Re: Events for serial driver transmission completion

Postby FXCoder » Thu Aug 10, 2017 12:27 pm

Hi Raul,
Using an STM32F413 NUCLEO board I couldn't re-create your issue.
In my case I've allowed all flags on the USART side to wake up the user thread.


And here is the test thread code...

Code: Select all

static THD_WORKING_AREA(waThread2, 128);
static THD_FUNCTION(Thread2, arg) {

  (void)arg;
  event_listener_t listener;
  uint8_t buff[] = {0x00, 0x01, 0x02, 0x03};
  chEvtRegisterMaskWithFlags (chnGetEventSource (&SD2),
                                           &listener, EVENT_MASK (0),
                                           ALL_EVENTS);
  char *flag_text;

  while (true) {
    sdWrite (&SD2, buff, sizeof (buff));
    chEvtWaitOne (EVENT_MASK (0));
    eventflags_t source_flags = chEvtGetAndClearFlags (&listener);
    eventmask_t source_mask = EVENT_MASK(0);
    chprintf((BaseSequentialStream *)&SD3, "USART flag test\r\n");
    while (source_flags) {
      switch (source_flags & source_mask) {
        case 0:
          flag_text = NULL;
          break;
        case CHN_CONNECTED:
          flag_text = "Connected";
          break;
        case CHN_DISCONNECTED:
          flag_text = "Disconnected";
          break;
        case CHN_INPUT_AVAILABLE:
          flag_text = "Input available";
          break;
        case CHN_OUTPUT_EMPTY:
          flag_text = "Output empty";
          break;
        case CHN_TRANSMISSION_END:
          flag_text = "Transmission end";
          break;
        default:
          flag_text = "Unknown";
          break;
      } /* End switch. */
      if (flag_text)
        chprintf((BaseSequentialStream *)&SD3, "Flag: %x (%s)\r\n", \
                 source_mask, flag_text);
      source_flags &= ~source_mask;
      source_mask <<= 1U;
    } /* End while. */
    chThdSleepSeconds(2);
  }
}



This is what I get repeating each 2 seconds on SD3...

Code: Select all

USART flag test
Flag: 8 (Output empty)
Flag: 10 (Transmission end)


I'm using default SD baud rate, etc.

Will be interested to know which uC you are using and if the test code produces any more clues.

Bob

Raul
Posts: 43
Joined: Thu Aug 13, 2015 5:15 pm
Has thanked: 3 times
Been thanked: 1 time

Re: Events for serial driver transmission completion

Postby Raul » Thu Aug 10, 2017 5:51 pm

Hi all,

Thanks for looking into this so attentively and apologies for the typographic errors in the original snippet (Any way to amend the original post?), it was just a simplified non-tested fragment I should have mentioned that.

Below there is a minimalist main.c tested against a STM32F407 on a discovery board. It is working perfectly fine, as the capture depicts. So my problem must be somewhere else. I need to go back to my actual set up and see what is actually happening. I'll let you know once I find out.

Code: Select all

#include "ch.h"
#include "hal.h"


static THD_WORKING_AREA(waThread1, 128);
static THD_FUNCTION(Thread1, arg) {

   (void)arg;
   event_listener_t txComplete;
   uint8_t const data[] = {0x00, 0x01, 0x02, 0x03};

   chEvtRegisterMaskWithFlags (chnGetEventSource (&SD2),
                &txComplete, EVENT_MASK (0),
                CHN_TRANSMISSION_END);

  while (true) {

   sdWrite (&SD2, data, sizeof (data));

   chEvtWaitOne (EVENT_MASK (0));

   palSetPad (GPIOD, GPIOD_LED3);

   eventflags_t f = chEvtGetAndClearFlags (&txComplete);

   if (f & CHN_TRANSMISSION_END)
   {
      chThdSleepMilliseconds(250);
      palClearPad(GPIOD, GPIOD_LED3);
      chThdSleepMilliseconds(250);
   }
  }
}

/*
 * Application entry point.
 */
int main(void) {

  halInit();
  chSysInit();

  /*
   * Activates the serial driver 2 using the driver default configuration.
   * PA2(TX) and PA3(RX) are routed to USART2.
   */
  sdStart(&SD2, NULL);
  palSetPadMode(GPIOA, 2, PAL_MODE_ALTERNATE(7));
  palSetPadMode(GPIOA, 3, PAL_MODE_ALTERNATE(7));

  /*
   * Creates the example thread.
   */
  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);

  while (true) {
    chThdSleep(TIME_INFINITE);
  }
}


capture.png
capture.png (8.51 KiB) Viewed 4035 times

Raul
Posts: 43
Joined: Thu Aug 13, 2015 5:15 pm
Has thanked: 3 times
Been thanked: 1 time

Re: Events for serial driver transmission completion

Postby Raul » Fri Aug 11, 2017 4:30 pm

Hi,

So, going back to my problematic case, chEvtWaitOne returns immediately because when it gets called the pending flag for the events seems to be already set. I set a breakpoint at chevents.c line 390 and it's never hit. Although when it returns ctp->p_epending has the event reset, as it should.

Code: Select all

 eventmask_t chEvtWaitOne(eventmask_t events) {
384│   thread_t *ctp = currp;
385│   eventmask_t m;
386│
387│   chSysLock();
388│   m = ctp->p_epending & events;
389│   if (m == (eventmask_t)0) {
390│     ctp->p_u.ewmask = events;
391│     chSchGoSleepS(CH_STATE_WTOREVT);
392│     m = ctp->p_epending & events;
393│   }
394|   m ^= m & (m - (eventmask_t)1);
395│   ctp->p_epending &= ~m;
396│   chSysUnlock();
397│
398│   return m;
399│ }


After that finding I decided to perform sdWrites only if there are no pending event flags, and if there were any I would clear them explicitly and return. See below.
Every single time trySend is called it evaluates ctp->p_epending with a set event mask, at this point I get very confused, note that sd write operations are not happening in this case. A silly question, that could explain it all, if data is received by the same serial drive. Would it also trigger an event 0 even though only the CHN_TRANSMISSION_END event flag is registered?

Code: Select all

bool trySend (uint8_t *data, uint8_t n)
{
             thread_t *ctp = currp;
             chSysLock ();
             eventmask_t s = ctp->p_epending;
             chSysUnlock ();
             
              if (s == EVENT_MASK (0))
              {
                      chSysLock ();
                      ctp->p_epending = 0;
                      chSysUnlock ();
                     return false;
              }
   
             sdWrite (&SD2, data, n);
             chEvtWaitOne (EVENT_MASK (0));
   
             eventflags_t f = chEvtGetAndClearFlags (&txComplete);
 
             return f & CHN_TRANSMISSION_END;
}


Update, If I clear the flags as well as the pending events it only meets the first if condition once. The system works as expected from that point onwards. So, I would answer my previous question with a no, as subsequent events and activity don't trigger event 0.
Now here is THE question, why do you guys think it is doing it initially? At that point some data would have been received but nothing transmitted.

Code: Select all

bool trySend (uint8_t *data, uint8_t n)
{
             thread_t *ctp = currp;
             chSysLock ();
             eventmask_t s = ctp->p_epending;
             chSysUnlock ();
             
              // It gets here only once, the first time it gets called, and after the system becomes "synced up".     
              if (s == EVENT_MASK (0))
              {
                      chSysLock ();
                      txComplete.el_flags = 0;
                      ctp->p_epending = 0;
                      chSysUnlock ();
                     return false;
              }
   
             sdWrite (&SD2, data, n);
             chEvtWaitOne (EVENT_MASK (0));
   
             eventflags_t f = chEvtGetAndClearFlags (&txComplete);
 
             return f & CHN_TRANSMISSION_END;
}


Thanks

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

Re: Events for serial driver transmission completion

Postby Giovanni » Sat Aug 12, 2017 6:15 am

Hi,

What version of ChibiOS are you using? that "p_epending" suggests it is very old.

Giovanni

Raul
Posts: 43
Joined: Thu Aug 13, 2015 5:15 pm
Has thanked: 3 times
Been thanked: 1 time

Re: Events for serial driver transmission completion

Postby Raul » Sat Aug 12, 2017 7:23 am

Hi Giovanni,

It is release 16.1.0, about 9/8 months old, would you suggest running it against Adagio?

Raul

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

Re: Events for serial driver transmission completion

Postby Giovanni » Sat Aug 12, 2017 7:36 am

17.6.0 or 16.1.8, lots of bugs get fixed with time.

Giovanni

Raul
Posts: 43
Joined: Thu Aug 13, 2015 5:15 pm
Has thanked: 3 times
Been thanked: 1 time

Re: Events for serial driver transmission completion

Postby Raul » Mon Aug 14, 2017 12:48 pm

Hi Giovanni,

Same results with 17.6.0. However, I have narrowed it down further. In my project I am performing the event registration, chEvtRegisterMaskWithFlags, right after starting the serial driver, sdStart. If I induce a delay between those calls of at least 100 system ticks then all works as it should right from the beginning. What do you make of this?

Raul

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

Re: Events for serial driver transmission completion

Postby Giovanni » Mon Aug 14, 2017 5:18 pm

It could be a glitch on the serial port triggering an RX error event, do you switch pins to alternate before or after the call to sdStart()? Anyway I am beginning to think to something electric in nature.

Giovanni

Raul
Posts: 43
Joined: Thu Aug 13, 2015 5:15 pm
Has thanked: 3 times
Been thanked: 1 time

Re: Events for serial driver transmission completion

Postby Raul » Mon Aug 14, 2017 9:37 pm

The pins are configured before calling sdStart (), all of them done as as per their board definition file.
The event flags returned by the unexpected event contained a value of 20, TRANSMISSION_END and INPUT_AVAILABLE. I can understand the latter but no the former at that point, unless caused by some electrical side effect. It's probably down to some initial condition that must be triggering the tx interrupt somehow.

Thanks


Return to “ChibiOS/RT”

Who is online

Users browsing this forum: No registered users and 40 guests