EEVblog Electronics Community Forum

Electronics => Microcontrollers => Topic started by: DVX on July 31, 2017, 03:29:24 pm

Title: techniques for writing non blocking code
Post by: DVX on July 31, 2017, 03:29:24 pm
User button presses is one area my code which could be improved, I have been looking for a good way to detect the level changes when a user applies a button (push to make switch) input. Currently when a button input change is detected the program branches to a routine which then waits in a loop until the button is released. To keep things simple the code is blocking, it just waits until the button level changes to show it no longer pressed down. I read button level changes and do screen updates by calling routines with in the button waiting loop but there has to be a better way. I don't have any experience for using RTOS or scheduler and wonder how else this can be done and still detect fast button level changes. I poll the buttons as the external interrupt on change pins on my PIC32 are all used by LCD connections.
Title: Re: techniques for writing non blocking code
Post by: joshtyler on July 31, 2017, 03:41:59 pm
Is there anything stopping you from polling the button once on each processing loop, and remembering the previous value?

Something like this?

Code: [Select]
bool buttonState;
int main(void)
{
while(1) //Main processing loop
{
buttonState = readButton(); //Non blocking read of button state

//All the rest of your processing happens here
}
}
Title: Re: techniques for writing non blocking code
Post by: Kalvin on July 31, 2017, 03:53:14 pm
1. Run-to-completion scheduler and the tasks/processes are implemented as finite state machines.

- Consumes very little RAM but splitting processes to state machines may require some effort.

2. Co-operative scheduler and each process shall yield to allow other tasks/processes run.

- Consumes more RAM as each process/task will have it own stack.

3. Protothreads are a mix of the 1 and 2.

- Requires typically static variables or similar mechanism as the process/task doesn't have its own stack frame.
Title: Re: techniques for writing non blocking code
Post by: JPortici on July 31, 2017, 03:55:47 pm
what i usually do, leaving out debouncing
- sample the port
- xor with previous saved value
- for every "1" in the xor's value go to check if current port value is zero (depressed) or 1 (pressed). This will set flags depending on current state. Other state machines will use these flags
- update previous saved value
Title: Re: techniques for writing non blocking code
Post by: andyturk on July 31, 2017, 04:20:14 pm
3. Protothreads are a mix of the 1 and 2.

- Requires typically static variables or similar mechanism as the process/task doesn't have its own stack frame.

Protothreads can be interesting in C++. If you have a Thread class from which you derive application specific threads, you can put your state in there as member variables rather than the typical static/global variables.
Title: Re: techniques for writing non blocking code
Post by: Sal Ammoniac on July 31, 2017, 04:42:07 pm
Another technique is to connect the button to an external interrupt input and process the button press in the interrupt handler (or set a flag in the ISR and handle the event elsewhere).

If you do this, you'll need to debounce the button in hardware (unless your MCU has a glitch filter on its external interrupt inputs) to prevent entering the ISR multiple times as the contacts bounce.

If you don't have hardware interrupts available (you said they're all in use) and you can't free any up, a pre-emptive RTOS makes this very straightforward. You just use a dedicated task to poll the button periodically. Just set the priority of the button polling task lower than the important tasks and you won't have to worry about the polling interfering with everything else.
Title: Re: techniques for writing non blocking code
Post by: Kalvin on July 31, 2017, 04:53:09 pm
If you don't have hardware interrupts available (you said they're all in use) and you can't free any up, a pre-emptive RTOS makes this very straightforward. You just use a dedicated task to poll the button periodically. Just set the priority of the button polling task lower than the important tasks and you won't have to worry about the polling interfering with everything else.

This can be implemented also in a non-pre-emptive system: Just poll and debounce the button in a periodic ISR and update the global flag containing the filtered button state. The main program can read the filtered button state and act accordingly.
Title: Re: techniques for writing non blocking code
Post by: DVX on July 31, 2017, 05:08:41 pm
I forgot to mention the port with the button sense press and release also has a rotary encoder connected to it, so JPORTci's sampling of the port and XOR's the previous value would not be hard to implement and would cover reading the encoder. Currently polling is via a timer set to 5ms rollover and placing the current and previous port values and XOR'ing then in the timer interrupt + setting flags for changes should give a fast response. I prefer to keep code in the interrupt routines short but sometimes its a good way to get a fast response to external changes.   
Title: Re: techniques for writing non blocking code
Post by: nctnico on July 31, 2017, 07:33:27 pm
Another technique is to connect the button to an external interrupt input and process the button press in the interrupt handler (or set a flag in the ISR and handle the event elsewhere).
Please don't do this! Worse advice ever! The occurence of interrupts has to be well defined and an external button is far from it. Think about  what happens when a button wears out, gets wet and/or is connected to a long cable which picks up noise: you'll get loads of interrupts which will screw up the timing of other processes. And things can be made far worse by a microcontroller with poorly defined logic input levels. The end result is that the device misbehaves in odd ways at customers and it is impossible to figure out why.

A method which works well is to increment a counter in a timer interrupt. Use this counter in the main loop to define an interval with which the buttons are polled. In each poll increment a counter (up to a limited number) when a button is pressed and reset (or decrement) when released. When the count hits a certain value mark the button as pressed.
Title: Re: techniques for writing non blocking code
Post by: Mechatrommer on July 31, 2017, 08:49:39 pm
Another technique is to connect the button to an external interrupt input and process the button press in the interrupt handler (or set a flag in the ISR and handle the event elsewhere).
Please don't do this! Worse advice ever! The occurence of interrupts has to be well defined and an external button is far from it. Think about  what happens when a button wears out, gets wet and/or is connected to a long cable which picks up noise: you'll get loads of interrupts which will screw up the timing of other processes.
not necessarily the worse advice, interrupt is meant to screw process timing, and the process should be able to cope with that. the problem is not the method, but the external device itself (switch). not much difference if you put the misbehaving switch into a pool process. having said that, imho, interrupt is meant for non-predictable event, or pooling will not be fast enough for detecting it.. making switch (that can be pooled) will waste one interrupt pin that can be made usefull to other unpredictable event.

btw back to OP, the picture should be worth of many words... (attached) that is one way to do it (pooling method) sorry for my doctorate writing style...
Title: Re: techniques for writing non blocking code
Post by: Sal Ammoniac on July 31, 2017, 11:19:43 pm
Another technique is to connect the button to an external interrupt input and process the button press in the interrupt handler (or set a flag in the ISR and handle the event elsewhere).
Please don't do this! Worse advice ever!

This technique wouldn't be my first choice, but with proper hardware conditioning of the input it's not the worst way to implement a button.
Title: Re: techniques for writing non blocking code
Post by: gnif on July 31, 2017, 11:29:26 pm
I have used interrupts in the past to detect presses on a keypad, but to avoid the issue of screwing with the timing, or bad interrupts I did three things.

1) Debounced the interrupt input.
2) Buffered the interrupt input through a Schmidt trigger (not sure if this was warranted, but I had a spare gate)
3) In the interrupt handler I disabled the interrupt after setting a flag to process the keypad input. The interrupt was re-enabled after a timeout of 20ms, so worst case an interrupt could only occur once every 20ms which would not have any detrimental effect on the system.
Title: Re: techniques for writing non blocking code
Post by: HackedFridgeMagnet on August 01, 2017, 12:15:11 am

Please don't do this! Worse advice ever! The occurence of interrupts has to be well defined and an external button is far from it.

Lol I thought interrupts where used when the occurrence of an event wasn't well defined.

I get your point though, you don't want lots of interrupts hogging the processor if the input is somehow suspect.

But you could interrupt on a button and reset the interrupt after a timeout. Also the interrupt could only trigger on a transition instead of a level.
Title: Re: techniques for writing non blocking code
Post by: cv007 on August 01, 2017, 01:11:16 am
Spare uart rx? built-in debounce (baud rate as needed),  buffer a few presses, framing error to detect long presses, rx data would give additional info on press length if wanted
 :)
Title: Re: techniques for writing non blocking code
Post by: nctnico on August 01, 2017, 06:33:23 am
Another technique is to connect the button to an external interrupt input and process the button press in the interrupt handler (or set a flag in the ISR and handle the event elsewhere).
Please don't do this! Worse advice ever!
This technique wouldn't be my first choice, but with proper hardware conditioning of the input it's not the worst way to implement a button.
You have to define 'proper hardware conditioning'  8) It will take several extra parts to filter unwanted signals (if you take EMC immunity tests in mind you'll see it isn't that trivial) and you will lose the flexibility to change the response time if necessary. Filtering can be done in software just as easely if you poll the buttons at a certain interval. It isn't even a fast process with critical timing constraints (compared to handling a UART for example).
Title: Re: techniques for writing non blocking code
Post by: poorchava on August 01, 2017, 06:50:00 am
My standard solution, which works well unless you have a very large number of buttons:
-assign a press time counter and 2 flags to each button
-call readButtonState periodically (eg. 100Hz)
-if button is pressed, increment the press time counter, otherwise zero the counter
-if counter exceeds the press time limit, set the 'pressed' flash, if it exceeds time required for hold set 'hold' flag
-in ui part of software reset or not the button press/hold flag after it has been serviced

Perhaps it could be easier done with RTOS, but I have little experience with those as I prefer to write on bare metal
Title: Re: techniques for writing non blocking code
Post by: John Coloccia on August 01, 2017, 08:06:52 am
Another technique is to connect the button to an external interrupt input and process the button press in the interrupt handler (or set a flag in the ISR and handle the event elsewhere).
Please don't do this! Worse advice ever! The occurence of interrupts has to be well defined and an external button is far from it. Think about  what happens when a button wears out, gets wet and/or is connected to a long cable which picks up noise: you'll get loads of interrupts which will screw up the timing of other processes. And things can be made far worse by a microcontroller with poorly defined logic input levels. The end result is that the device misbehaves in odd ways at customers and it is impossible to figure out why.

A method which works well is to increment a counter in a timer interrupt. Use this counter in the main loop to define an interval with which the buttons are polled. In each poll increment a counter (up to a limited number) when a button is pressed and reset (or decrement) when released. When the count hits a certain value mark the button as pressed.


Putting a button on an interrupt is perfectly fine. Assuming the input hasn't already been filtered, after you get the interrupt disable that interrupt, debounce in the program, and then reenable the interrupt. Basically, every pass through my main loop I'll call a debounce routine that goes out and debounces anything that needs it. I've also done it in a timer interrupt, which is maybe the slickest solution...debounced I/O just magically appears and the main program never needs to worry about it.

If the button is broken to the point that it's signaling it's pushed when it's not, then the button needs to be replaced. Regardless, you either spend the time handling a noisy button in the interrupt, or you spend the time handling it in the main program. It really doesn't matter. Either way something will detect that the button has been pressed, and then the button is out of commission until the debounce time is up.

I'm not sure what the "button on a long cable" thing is all about either. If you have something that susceptible to noise, why would you dump it directly into a micro? It would make far more sense to have a slightly more sophisticated circuit which was not as susceptible to noise. I can probably make up all sorts of problem scenarios, but I'm pretty sure the OP is asking about a normal button.
Title: Re: techniques for writing non blocking code
Post by: newbrain on August 01, 2017, 08:10:49 am
I'll just do some coming out with the code I use whenever I need buttons.

It is based on keeping a simple FSM for each button.
The debouncing time, the minimum time to register a short or a long press are defined by the constants CLICKDEBOUNCE, CLICKSHORT, and CLICKLONG.
A short press will register when the button is released, a long one when its time has elapsed.

The ServeButton() routine must be invoked for each button at a sensible interval (some ms).
It returns a key value (enum) associated with the defined events (long and short press) or NoKey if nothing happened.

The routine can be called in the main loop, or in a periodic ISR (it's lightweight enough, if the number of key is limited, but YMMV).
In the last case, the key press can be passed to main loop in the usual ways (e.g. in a volatile variable, or enqueued in an input queue if needed).

The specific example is from my PSU controller, for encoders' shaft clicks, but the code is generic enough: change the Key enum to suit your needs (hence not shown here).
It uses the ST HAL, but it's quite portable: the only requirements are reading a GPIO pin (duh!) and having a tick counter.

Code: [Select]
typedef enum
{
  Idle       = 0,
  Debouncing,
  Pressed,
  Waiting
} BtnState;


typedef struct
{
  uint16_t      pin;     /* GPIO pin */
  GPIO_TypeDef *port;    /* GPIO port */
  GPIO_PinState pol;     /* polarity: SET active high, RESET active low */
  BtnState      state;   /* current state */
  uint32_t      tick;    /* time of press */
  Key           kShort;  /* key enum value for short press */
  Key           kLong;   /* key enum value for long press */
} Button;

#define CLICKDEBOUNCE 30    /* 30ms for debouncing   */
#define CLICKLONG     1000  /* 1s for long click     */
#define CLICKSHORT    75    /* 75ms for short click */

#define BUTTONS 2

Button buttons[BUTTONS] =
{
  {
    .pin    = ENC1_BTN,
    .port   = ENC1_BTN_GPIO,
    .pol    = GPIO_PIN_SET,
    .kShort = ClickVKey,
    .kLong  = LongVKey
  },
  {
    .pin    = ENC2_BTN,
    .port   = ENC2_BTN_GPIO,
    .pol    = GPIO_PIN_SET,
    .kShort = ClickIKey,
    .kLong  = LongIKey
  }
};

Key serveButton( Button *b )
{
  Key key      = NoKey;
  uint32_t now = HAL_GetTick(); // What's the time?
  bool btn     = b->pol == HAL_GPIO_ReadPin( b->port, b->pin );

  switch( b->state )
  {
  case Idle:
    if( btn )
    {
      /* The button has been pressed */
      /* Remember when */
      b->tick  = now;
      /* and move to Debouncing state */
      b->state = Debouncing;
    }
    break;

  case Debouncing:
    if( btn )
    {
      if( now - b->tick > CLICKDEBOUNCE )
        /* Real press */
        b->state = Pressed;
    }
    else
    {
      /* It was a bounce, start over */
      b->state = Idle;
    }
    break;

  case Pressed:
    if( btn )
    { /* Still pressed, is this a long press? */
      if( now - b->tick > CLICKLONG )
      {
        /* A long press has been detected */
        key      = b->kLong;
        /* Wait for release */
        b->state = Waiting;
      }
    }
    else
    { /* Released, is it a short press? */
      if( now - b->tick > CLICKSHORT )
      {
        /* A short press has been detected */
        key      = b->kShort;
      }
      /* Return to idle */
      b->state = Idle;
    }
    break;

  case Waiting:
    if( !btn )
    {
      b->state = Idle;
    }
    break;
  }
  return key;
}
Title: Re: techniques for writing non blocking code
Post by: Yansi on August 01, 2017, 08:28:38 am
1) Sample buttons at 10-20ms interval using tim isr.
2) make a lock bit variable and event bit variable for each button
3) compare actual sampled button state to the locked state. If not locked and pressed, set the event variable and lock it. If locked and not pressed, then unlock (optionally clear the event bit).
4) check the event bit in main loop, if set, clear it and you know the button was pressed.

You can even use two event bits, one for press event, other for depressed event.
Key repeat functionality can be easily implemented in this.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 01, 2017, 11:46:35 am
Putting a button on an interrupt is perfectly fine.

You can do it, just as you can use asynchronous monostables (like a 74123) in clocked logic circuits. Occasionally there are good reasons for those techniques.

But both techniques smell because they introduce subtle failure mechanisms (analogue and digital), can make it difficult to reason about "edge case" operation of the complete system, and difficult to test in production.
Title: Re: techniques for writing non blocking code
Post by: David Hess on August 01, 2017, 12:22:32 pm
Here is what I do:

1. One of the timer interrupts (1) regularly executes a routine which scans the inputs and sends display outputs if the outputs are on the same interface.  If interrupt on change is supported, then it could also call this routine although this complicates debouncing.
2. The keyboard inputs are processed to detect change of state which is stored in shadow registers.
3. The main routine only accesses the shadow registers.

The shadow registers include the last key state which is used by the interrupt routine to detect state changes and a pair of other registers which indicate key press and key release.  When the main routine acts on a key press or key release, it resets that bit.  Key state might be used for press and hold functions but the main routine never alters it.

(1) A divide chain is used to create multiple timer interrupts with different rates so the fastest timer interrupt chains to the others to produce slower timer interrupts for tasks which do not need to operate at the fastest rate.
Title: Re: techniques for writing non blocking code
Post by: nctnico on August 01, 2017, 07:22:44 pm
I'm not sure what the "button on a long cable" thing is all about either. If you have something that susceptible to noise, why would you dump it directly into a micro?
People do that AND use interrupts without masking. I've seen it myself otherwise I wouldn't believe it either.
Title: Re: techniques for writing non blocking code
Post by: Sal Ammoniac on August 01, 2017, 08:25:07 pm
But both techniques smell

Define smell. Roses smell. Freshly baked bread smells.
Title: Re: techniques for writing non blocking code
Post by: andyturk on August 01, 2017, 08:43:28 pm
Obligatory reading: http://www.ganssle.com/debouncing.htm (http://www.ganssle.com/debouncing.htm)
Title: Re: techniques for writing non blocking code
Post by: Yansi on August 01, 2017, 09:03:32 pm
Hence why I suggest sampling the buttons at 10 to 20ms intervals.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 01, 2017, 09:30:24 pm
But both techniques smell

Define smell. Roses smell. Freshly baked bread smells.

Sigh, the standard meaning in the context of code, to wit: https://en.wikipedia.org/wiki/Code_smell
Title: Re: techniques for writing non blocking code
Post by: Sal Ammoniac on August 01, 2017, 10:06:16 pm
But both techniques smell

Define smell. Roses smell. Freshly baked bread smells.

Sigh, the standard meaning in the context of code, to wit: https://en.wikipedia.org/wiki/Code_smell

Sorry. Was just pulling your chain.  8) I'm not a big fan of some of these hipster terms such as code smell, refactoring, and technical debt.
Title: Re: techniques for writing non blocking code
Post by: John Coloccia on August 01, 2017, 11:04:42 pm
Putting a button on an interrupt is perfectly fine.

You can do it, just as you can use asynchronous monostables (like a 74123) in clocked logic circuits. Occasionally there are good reasons for those techniques.

But both techniques smell because they introduce subtle failure mechanisms (analogue and digital), can make it difficult to reason about "edge case" operation of the complete system, and difficult to test in production.

What is the subtle failure? The interrupt fires saying "something changed"...then you debounce the switch in a timer, or whatever your favorite method is....then you re-enable the interrupt. How is that more prone to failure than polling to see that something changed, debouncing and polling some more? If you can't make it reliably work in an interrupt, then you can't make it reliably work polling either. You're just depending on the polling not polling at exactly the wrong time. Either the debounce technique works or it doesn't. The thing that triggers it is not important.
Title: Re: techniques for writing non blocking code
Post by: andyturk on August 01, 2017, 11:38:36 pm
A war story:

One project I worked on used interrupts to read a few external signals. Most of these were controlled either with hardware debounce or were generated by circuits that had well defined behavior. But one of these was just tied to an uncontrolled input with no hardware debounce. The signal had to do with whether the device was being charged or not, and since that signal wouldn't change very often, not much thought was put into the implementation.

After some time, we noticed that some devices would simply lock up and become unresponsive. These locked devices were still operational, the kernel was still running and in fact, we could still communicate with them remotely. But they weren't responding to  external interrupts any more.

Hmm....

Turns out the mcu used for this project has a race condition in the silicon for its GPIO interrupt generation. If edges arrived in the right order and sufficiently quickly, the interrupt hardware would lock up and cease to sense external changes. WTF?  :palm: It turned out that there was a firmware workaround (which is how the OEM fixed the problem, which still doesn't appear in their errata), but it's very cumbersome and involves loops inside the interrupt handler.

The moral of this story might be to avoid mcus with dodgy silicon, or maybe to avoid using GPIO interrupts without hardware debounce, but I think the real lesson is to expect the unexpected--especially when tying interrupts to external signals.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 01, 2017, 11:49:45 pm
Putting a button on an interrupt is perfectly fine.

You can do it, just as you can use asynchronous monostables (like a 74123) in clocked logic circuits. Occasionally there are good reasons for those techniques.

But both techniques smell because they introduce subtle failure mechanisms (analogue and digital), can make it difficult to reason about "edge case" operation of the complete system, and difficult to test in production.

What is the subtle failure? The interrupt fires saying "something changed"...then you debounce the switch in a timer, or whatever your favorite method is....then you re-enable the interrupt. How is that more prone to failure than polling to see that something changed, debouncing and polling some more? If you can't make it reliably work in an interrupt, then you can't make it reliably work polling either. You're just depending on the polling not polling at exactly the wrong time. Either the debounce technique works or it doesn't. The thing that triggers it is not important.

You need to do failure analysis, and that depends on identifying all the components, hardware and software, in the complete system. Thereafter you can consider how they can completely or partially fail, and how the system will react.

I suggest you should look at comp.risks to see subtle and unexpected failure modes in systems, including real-time systems created by intelligent and dedicated people. Comp.risks as a very high SNR, appears roughly weekly, and the last 30 years archives can be found at http://catless.ncl.ac.uk/Risks/ (http://catless.ncl.ac.uk/Risks/)
Title: Re: techniques for writing non blocking code
Post by: John Coloccia on August 02, 2017, 01:55:26 am
Putting a button on an interrupt is perfectly fine.

You can do it, just as you can use asynchronous monostables (like a 74123) in clocked logic circuits. Occasionally there are good reasons for those techniques.

But both techniques smell because they introduce subtle failure mechanisms (analogue and digital), can make it difficult to reason about "edge case" operation of the complete system, and difficult to test in production.

What is the subtle failure? The interrupt fires saying "something changed"...then you debounce the switch in a timer, or whatever your favorite method is....then you re-enable the interrupt. How is that more prone to failure than polling to see that something changed, debouncing and polling some more? If you can't make it reliably work in an interrupt, then you can't make it reliably work polling either. You're just depending on the polling not polling at exactly the wrong time. Either the debounce technique works or it doesn't. The thing that triggers it is not important.

You need to do failure analysis, and that depends on identifying all the components, hardware and software, in the complete system. Thereafter you can consider how they can completely or partially fail, and how the system will react.

I suggest you should look at comp.risks to see subtle and unexpected failure modes in systems, including real-time systems created by intelligent and dedicated people. Comp.risks as a very high SNR, appears roughly weekly, and the last 30 years archives can be found at http://catless.ncl.ac.uk/Risks/ (http://catless.ncl.ac.uk/Risks/)

So what's the subtle failure mechanism? Maybe it's because my background is software that I don't consider any of these subtleties to be big deals, or difficult to handle, or whatever, but it seems pretty darn straightforward to me. Interrupt says something changed, software properly debounces, and life goes on. If that doesn't work, then it also won't work if you're polling because you can always poll at exactly the wrong time. You're just masking the problem and turning a 1 in 1,000 failure into a 1 in 10,000 failure.

I think the article that was posted makes some argument that edges can come in that may trigger an interrupt but won't be caught polling. Big deal. Bad/noisy/spurious edges can come in that trigger both. What then? One way or another, you need to decide what kind of signal means pushed and what kind doesn't, and then design your hardware and software around that.

There are lots of scenarios where monitoring in an interrupt is NOT an appropriate solution, but that's really beside the point. For example, if you're monitoring multiple buttons that can be pushed simultaneously and can't mask each other, then you either need robust hardware debouncing or polling. That said, the idea that monitoring in an interrupt is inherently bad is just complete nonsense. What's inherently bad is bad design where hardware, software and design requirements aren't working in harmony with each other.
Title: Re: techniques for writing non blocking code
Post by: Mechatrommer on August 02, 2017, 06:01:15 am
But both techniques smell
Define smell. Roses smell. Freshly baked bread smells.
Sigh, the standard meaning in the context of code, to wit: https://en.wikipedia.org/wiki/Code_smell
neither polling or interrupt method listed in the definition. i guess you just made up your own defintion. most of the definitions are relating to code redundancy/inefficiency which in turn means codes that havent been refactored or analyzed properly. those are anti-definition of KISS principle (https://en.wikipedia.org/wiki/KISS_principle).
Title: Re: techniques for writing non blocking code
Post by: nctnico on August 02, 2017, 06:33:13 am
Putting a button on an interrupt is perfectly fine.

You can do it, just as you can use asynchronous monostables (like a 74123) in clocked logic circuits. Occasionally there are good reasons for those techniques.

But both techniques smell because they introduce subtle failure mechanisms (analogue and digital), can make it difficult to reason about "edge case" operation of the complete system, and difficult to test in production.

What is the subtle failure? The interrupt fires saying "something changed"...then you debounce the switch in a timer, or whatever your favorite method is....then you re-enable the interrupt. How is that more prone to failure than polling to see that something changed, debouncing and polling some more? If you can't make it reliably work in an interrupt, then you can't make it reliably work polling either. You're just depending on the polling not polling at exactly the wrong time. Either the debounce technique works or it doesn't. The thing that triggers it is not important.
Why would you want to use an interrupt if you are going to poll anyway? If you use an interrupt the way you describe then somewhere the software has to check (poll) the state of the flag that interrupt has set. Then it needs to deal with debouncing as well. It sounds complicated and in some cases I rather have less interrupts running when I have the microcontroller handle some realtime signal processing.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 02, 2017, 08:15:04 am
Putting a button on an interrupt is perfectly fine.

You can do it, just as you can use asynchronous monostables (like a 74123) in clocked logic circuits. Occasionally there are good reasons for those techniques.

But both techniques smell because they introduce subtle failure mechanisms (analogue and digital), can make it difficult to reason about "edge case" operation of the complete system, and difficult to test in production.

What is the subtle failure? The interrupt fires saying "something changed"...then you debounce the switch in a timer, or whatever your favorite method is....then you re-enable the interrupt. How is that more prone to failure than polling to see that something changed, debouncing and polling some more? If you can't make it reliably work in an interrupt, then you can't make it reliably work polling either. You're just depending on the polling not polling at exactly the wrong time. Either the debounce technique works or it doesn't. The thing that triggers it is not important.

You need to do failure analysis, and that depends on identifying all the components, hardware and software, in the complete system. Thereafter you can consider how they can completely or partially fail, and how the system will react.

I suggest you should look at comp.risks to see subtle and unexpected failure modes in systems, including real-time systems created by intelligent and dedicated people. Comp.risks as a very high SNR, appears roughly weekly, and the last 30 years archives can be found at http://catless.ncl.ac.uk/Risks/ (http://catless.ncl.ac.uk/Risks/)

So what's the subtle failure mechanism? Maybe it's because my background is software that I don't consider any of these subtleties to be big deals, or difficult to handle, or whatever, but it seems pretty darn straightforward to me.

Ah, right, that explains a lot. I presume your expertise is in digital hardware, otherwise I won't be able to point you in the right direction within a reasonable time. An analogy to get you started thinking in the right direction...

Most software is written in a way that presumes that control flows linearly, and that the control flow is the only thing that can mutate memory and i/o. That specifically includes the compilers, which have widely misunderstood and misapplied constructs for situations where that isn't the case. Prime example: C on multicore processors with multiple levels of cache and shared memory, where compiler and/or program bugs are legion.

Most digital hardware is constructed in a way that presumes changes only occur at specific instants, due to the clocked synchronous methodology. It is very very difficult to design unclocked asynchronous logic where inputs can change at any instant. Predictable design is, with significant effort and understanding, possible if you consider two inputs that can change asynchronously w.r.t. each other. With three or more it is effectively impossible. In addition, the design tools make it effectively impossible, since they habitually "optimise out" the necessary constructs inserted, e.g. Karnaugh map bridging terms.

Interrupts in software systems have the same effect as adding an extra core to a processor. They are analogous to turning a clocked synchronous hardware design into an asynchronous digital design.

And that doesn't even consider the timing implications of having your code arbitrarily suspended, which is analogous to the potentially infinite delay due to metastable behaviour in a synchroniser.
Title: Re: techniques for writing non blocking code
Post by: Bruce Abbott on August 02, 2017, 09:01:40 am
What's inherently bad is bad design where hardware, software and design requirements aren't working in harmony with each other.
Agreed. You can't say which method is best without looking at the entire system.

Quote from: DVX
Currently when a button input change is detected the program branches to a routine which then waits in a loop until the button is released. To keep things simple the code is blocking, it just waits until the button level changes to show it no longer pressed down. I read button level changes and do screen updates by calling routines with in the button waiting loop but there has to be a better way.
What is the problem with how you are doing it now?
Title: Re: techniques for writing non blocking code
Post by: Vtile on August 02, 2017, 09:15:29 am
What's inherently bad is bad design where hardware, software and design requirements aren't working in harmony with each other.
Agreed. You can't say which method is best without looking at the entire system.

Quote from: DVX
Currently when a button input change is detected the program branches to a routine which then waits in a loop until the button is released. To keep things simple the code is blocking, it just waits until the button level changes to show it no longer pressed down. I read button level changes and do screen updates by calling routines with in the button waiting loop but there has to be a better way.
What is the problem with how you are doing it now?
It freezes the system until the button is released. That is how it looks to me.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 02, 2017, 09:26:30 am
What's inherently bad is bad design where hardware, software and design requirements aren't working in harmony with each other.
Agreed. You can't say which method is best without looking at the entire system.

As I explicitly pointed out in the message to which Coloccia replied, you do indeed need to consider all components in a system. But "working in harmony" is insufficient, albeit pleasing.

However Coloccia's point is quite revealing. He is considering how things work; professional engineers have to prove how things work, and consider system behaviour when (not if) things fail.

If you are, say, making traffic light controllers for children's toy cars sets, you probably don't have to consider the failures mechanisms in much detail. But if you are developing real traffic light controllers, you sure do!
Title: Re: techniques for writing non blocking code
Post by: Kalvin on August 02, 2017, 10:05:17 am
One way of achieving a deterministic and a robust system is to use time-triggered software architecture:

https://www.safetty.net/products/publications/pttes (https://www.safetty.net/products/publications/pttes)

In a time-triggered system there are no interrupts which would interrupt the program execution. There may be a timer-based, deterministic interrupt which will run the actual program. The main program loop will consist only of while (1) loop with the sleep() function which will keep the system in a low-power mode when it is not executing the code. The system is built using state machines and the program will be run to completion within each timer tick. Essentially the system will use only periodic polling to interact with external buttons and other peripherals. Instead of using a timer interrupt, the main program can be constructed so that it will wait for a periodic timer overflow, which will then start the program execution.

Using this time-triggered software architecture one can create a system which is easy to debug and which will perform deterministically. These techniques are used in systems that require robust software execution.
Title: Re: techniques for writing non blocking code
Post by: John Coloccia on August 02, 2017, 10:25:55 am
What's inherently bad is bad design where hardware, software and design requirements aren't working in harmony with each other.
Agreed. You can't say which method is best without looking at the entire system.

As I explicitly pointed out in the message to which Coloccia replied, you do indeed need to consider all components in a system. But "working in harmony" is insufficient, albeit pleasing.

However Coloccia's point is quite revealing. He is considering how things work; professional engineers have to prove how things work, and consider system behaviour when (not if) things fail.

If you are, say, making traffic light controllers for children's toy cars sets, you probably don't have to consider the failures mechanisms in much detail. But if you are developing real traffic light controllers, you sure do!

We do safety critical software and have probably forgotten more about proving a system works than most engineers know.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 02, 2017, 10:26:48 am
One way of achieving a deterministic and a robust system is to use time-triggered software architecture:

https://www.safetty.net/products/publications/pttes (https://www.safetty.net/products/publications/pttes)

In a time-triggered system there are no interrupts which would interrupt the program execution. There may be a timer-based, deterministic interrupt which will run the actual program. The main program loop will consist only of while (1) loop with the sleep() function which will keep the system in a low-power mode when it is not executing the code. The system is built using state machines and the program will be run to completion within each timer tick. Essentially the system will use only periodic polling to interact with external buttons and other peripherals. Instead of using a timer interrupt, the main program can be constructed so that it will wait for a periodic timer overflow, which will then start the program execution.

Using this time-triggered software architecture one can create a system which is easy to debug and which will perform deterministically. These techniques are used in systems that require robust software execution.

A quick scan of that book shows nothing I disagree with; remarkable :)

I particularly like the way the author has adopted the "design pattern" method of structuring each chapter, and that each pattern contains a section about reliability and safety implications.

But I don't like the way the C code is formatted: it uses up too much vertical space, thus splitting the code across more pages than necessary :)
Title: Re: techniques for writing non blocking code
Post by: Kalvin on August 02, 2017, 10:42:14 am
One way of achieving a deterministic and a robust system is to use time-triggered software architecture:

https://www.safetty.net/products/publications/pttes (https://www.safetty.net/products/publications/pttes)

In a time-triggered system there are no interrupts which would interrupt the program execution. There may be a timer-based, deterministic interrupt which will run the actual program. The main program loop will consist only of while (1) loop with the sleep() function which will keep the system in a low-power mode when it is not executing the code. The system is built using state machines and the program will be run to completion within each timer tick. Essentially the system will use only periodic polling to interact with external buttons and other peripherals. Instead of using a timer interrupt, the main program can be constructed so that it will wait for a periodic timer overflow, which will then start the program execution.

Using this time-triggered software architecture one can create a system which is easy to debug and which will perform deterministically. These techniques are used in systems that require robust software execution.

A quick scan of that book shows nothing I disagree with; remarkable :)

I particularly like the way the author has adopted the "design pattern" method of structuring each chapter, and that each pattern contains a section about reliability and safety implications.

But I don't like the way the C code is formatted: it uses up too much vertical space, thus splitting the code across more pages than necessary :)

Yes, the ideas and the concepts in the book are very sound and practical. The source code formatting could be made more compact, but I do not find that too annoying.
Title: Re: techniques for writing non blocking code
Post by: Kalvin on August 02, 2017, 11:00:42 am
Another recommended book for the embedded designers is "Practical UML Statecharts in C/C++", 2nd ed by Miro Samek. The concepts are well presented, although I do not really like the actual implementation, but the book provides a usable starting point for the actual implementation and framework. Anyway, this is a good book for those who want to learn about hierarchical state machines, embedded systems architecture and framework, and possibly want get some good ideas when implementing their own framework. Like I said earlier, I do not really like the actual implementation, but otherwise the book will provide valuable information for every embedded designer who wants to improve their systems architecture.

Together with this book "Practical UML Statecharts in C/C++", and the previous book I mentioned https://www.safetty.net/products/publications/pttes (https://www.safetty.net/products/publications/pttes) one can build a nice, small, portable, responsive and robust embedded framework.
Title: Re: techniques for writing non blocking code
Post by: legacy on August 02, 2017, 02:04:14 pm
The Two-culture Problem

There are two very definite views of interrupts depending on whether or not you are working with real time systems or bigger information processors, but!

Consider for a moment the way that non-interrupt-using programs are debugged and tested. They are taken through a standard sequence of inputs and actions. Such programs always produce the same outputs for the same explicit inputs (if they don’t we generally suspect a hardware fault of some kind)

Now consider a program with a number of interrupt routines. In this case the exact sequence of events depends on the exact timing as well as the order of the interrupts. Perhaps an error only makes itself known when interrupt.54632110459 occurs while interrupt routine@0xdeadbead is working after interrupt routine@0xdeadbeaf.

What. The. Frog.  :wtf: :wtf: :wtf:

You can see that because the interrupts are caused by the outside world the number of ways that the program can execute the instructions is huge and the potential for undiscovered unwanted interactions is also huge.

And if look at cases, they exponentially grow as a tree.

So, someone not involved in RT believes that the interrupt-driven environment is hard not to think about interrupts as a blessing (really ?) , but I wonder ... how can you trust it?
Title: Re: techniques for writing non blocking code
Post by: legacy on August 02, 2017, 02:11:28 pm
You can also believe that you can successfully write interrupt handlers for all of the hardware devices that need to be use and ensure that they all interact to just the right degree.

Good in theory, but!

Actually in practice this isn’t as easy as it sounds and any bug that does get into the system can be next to impossible to find.

Thus, interruts are not a blessing since they drive you to go nut (especially if you are under pressure, as when your boss gives you a deadline, because of time-to-market) :D
Title: Re: techniques for writing non blocking code
Post by: Mechatrommer on August 02, 2017, 02:39:43 pm
You can see that because the interrupts are caused by the outside world the number of ways that the program can execute the instructions is huge and the potential for undiscovered unwanted interactions is also huge.
are you saying avoid using interrupt at all? not just necessarily switch, interrupt like sensors, glitches or pulses from external hardware, lcd pin (just as in the OP) and anything for detecting unpredictable outside events? just because it will open infinite possibilities of entry points in the program? that there will be no way of telling to client that it will work or not? are you going to poll tens of input pins because interrupt method is an abomination? is it like that?

edit: how are you going to time 2 consecutive events at greater accuracy, for example calculating rpm for a high speed motor or velocity of a bullet? while at the same time the processor need to do other complex stuffs? just to give you a picture.

Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 02, 2017, 02:43:42 pm
Actually in practice this isn’t as easy as it sounds and any bug that does get into the system can be next to impossible to find.
Thus, interruts are not a blessing since they drive you to go nut (especially if you are under pressure, as when your boss gives you a deadline, because of time-to-market) :D

Yes indeed. During development any such rare problems are usually ignored, since at that point there are common/frequent bugs to remove.

Here's an infamous classic that all embedded software engineers need to understand: https://catless.ncl.ac.uk/Risks/19.49.html#subj1 Note that both technical factors and human factors were involved, and that the engineers were knowledgeable and dedicated.

(And that's one of many examples of the high SNR in comp.risks)
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 02, 2017, 02:51:19 pm
You can see that because the interrupts are caused by the outside world the number of ways that the program can execute the instructions is huge and the potential for undiscovered unwanted interactions is also huge.
are you saying avoid using interrupt at all? not just necessarily switch, interrupt like sensors, glitches or pulses from external hardware, lcd pin (just as in the OP) and anything for detecting unpredictable outside events? just because it will open infinite possibilities of entry points in the program? that there will be no way of telling to client that it will work or not? are you going to poll tens of input pins because interrupt method is an abomination? is it like that?

To a good first approximation, yes.

I'll make a very limited exception for a regular tick timer, and for panics that result in a controlled shutdown.

Here's an infamous classic that all embedded software engineers need to understand: https://catless.ncl.ac.uk/Risks/19.49.html#subj1 (https://catless.ncl.ac.uk/Risks/19.49.html#subj1)

Quote
edit: how are you going to time 2 consecutive events at greater accuracy, for example calculating rpm for a high speed motor or velocity of a bullet? while at the same time the processor need to do other complex stuffs? just to give you a picture.

You capture the time-of-arrival of an event in a hardware counter, and read that time when you get around to processing the event.

Modern embedded processors have such facilities built-in and easy-to-use, e.g. http://www.xmos.com/download/private/XS1-Ports-Specification(X1373A).pdf (http://www.xmos.com/download/private/XS1-Ports-Specification(X1373A).pdf) plus the software primitives to use them effectively, e.g https://www.xmos.com/published/xmos-programming-guide (https://www.xmos.com/published/xmos-programming-guide)

Note that those processors have no cache and no interrupts - and they are a delight to use due their high performance, simplicity, and predictability.
Title: Re: techniques for writing non blocking code
Post by: Sal Ammoniac on August 02, 2017, 04:27:15 pm
One way of achieving a deterministic and a robust system is to use time-triggered software architecture:

https://www.safetty.net/products/publications/pttes (https://www.safetty.net/products/publications/pttes)

In a time-triggered system there are no interrupts which would interrupt the program execution. There may be a timer-based, deterministic interrupt which will run the actual program. The main program loop will consist only of while (1) loop with the sleep() function which will keep the system in a low-power mode when it is not executing the code. The system is built using state machines and the program will be run to completion within each timer tick.

I've worked with systems written using techniques like those described in that book and found the pervasive use of state machines makes the code tedious to write and maintain. Since everything is run from a timer interrupt, you have to maintain state yourself between each task invocation and you have to make sure that each task (and each group that runs from the same timer interrupt) doesn't take longer to execute than the timer period. Except for the very first task run when the timer tick interrupt is entered, all other tasks will experience scheduling jitter because the time they start running depends on how long all of the tasks ahead of them in the queue run, and this can vary from one tick to the next.

The code in the book also seems to rely a lot on global variables to pass information from task to task, and that's generally not a good idea.

All-in-all, I prefer to design embedded systems (except for extremely simple ones) using an RTOS with good task synchronization facilities.
Title: Re: techniques for writing non blocking code
Post by: legacy on August 02, 2017, 04:39:16 pm
is it like that?

umm, it's more like don't abuse of them. A message in the bottle to those who promote theories like "everything interrupts driven". Be warned.

But of course, in avionics interrupts are not completely banned, their use is greatly reduced  :popcorn:
Title: Re: techniques for writing non blocking code
Post by: legacy on August 02, 2017, 05:40:14 pm
yup, with interrupts and tasks competing on shared resources we need mutex (special semaphores) reflecting the relative urgency of these tasks to access the shared resource.

This makes things more complex and more difficult to be analyzed.

Most of the time the combination works fine, and you can believe your system works.  However, very infrequently, it is also possible for an interrupt to occur in the way that it can introduce the perfect scenario of priority inversion and ...

... ops, Shit Happens ... if you aren't aware of consequences, and able to sort it out.

~ ~ ~ ~ ~ ~ ~ ~

interrupts + shared resources(on mutex) = more cares  :D
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 02, 2017, 05:49:17 pm
One way of achieving a deterministic and a robust system is to use time-triggered software architecture:

https://www.safetty.net/products/publications/pttes (https://www.safetty.net/products/publications/pttes)

In a time-triggered system there are no interrupts which would interrupt the program execution. There may be a timer-based, deterministic interrupt which will run the actual program. The main program loop will consist only of while (1) loop with the sleep() function which will keep the system in a low-power mode when it is not executing the code. The system is built using state machines and the program will be run to completion within each timer tick.

I've worked with systems written using techniques like those described in that book and found the pervasive use of state machines makes the code tedious to write and maintain.

Writing the code is usually a trivial part of the implementation. Deciding what needs to be done, how to do it, and then ensuring that it does it takes far more time and brain power. Validation and verification is usually much more awkward than writing code.

FSMs come with important side benefits

I've used that in anger; in one production system I was able to rapidly demonstrate that another company's code wasn't doing what it needed to do. That avoided recrimination and lawsuits.


Quote
Since everything is run from a timer interrupt, you have to maintain state yourself between each task invocation and you have to make sure that each task (and each group that runs from the same timer interrupt) doesn't take longer to execute than the timer period. Except for the very first task run when the timer tick interrupt is entered, all other tasks will experience scheduling jitter because the time they start running depends on how long all of the tasks ahead of them in the queue run, and this can vary from one tick to the next.

That's rather in the nature of code that shares a single resource, in this case a processor.

Quote
All-in-all, I prefer to design embedded systems (except for extremely simple ones) using an RTOS with good task synchronization facilities.

That's valid. Of course - whether or not you realise it - you are creating an FSM implemented using the RTOS facilities. Personally I prefer to go the whole hog and code FSMs explicitly.

And whenever possible I like RTOS features to be implemented in hardware, e.g. http://www.xmos.com/download/private/xCORE-Architecture-Flyer(1.1).pdf (http://www.xmos.com/download/private/xCORE-Architecture-Flyer(1.1).pdf) :)
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 02, 2017, 05:52:18 pm
yup, with interrupts and tasks competing on shared resources we need mutex (special semaphores) reflecting the relative urgency of these tasks to access the shared resource.

This makes things more complex and more difficult to be analyzed.

Most of the time the combination works fine, and you can believe your system works.  However, very infrequently, it is also possible for an interrupt to occur in the way that it can introduce the perfect scenario of priority inversion and ...

... ops, Shit Happens ... if you aren't aware of consequences, and able to sort it out.

~ ~ ~ ~ ~ ~ ~ ~

interrupts + shared resourced(on mutex) = more cares  :D

Precisely. Too many embedded developers have never even heard of priority inversion!

Debugging the Mars Pathfinder on the surface of Mars? Wozzat?
Title: Re: techniques for writing non blocking code
Post by: Mechatrommer on August 02, 2017, 05:58:11 pm
You capture the time-of-arrival of an event in a hardware counter, and read that time when you get around to processing the event.
Modern embedded processors have such facilities built-in and easy-to-use,
what about mcu that doesnt have the feature?

Here's an infamous classic that all embedded software engineers need to understand: https://catless.ncl.ac.uk/Risks/19.49.html#subj1
irrelevant. interrupt routine is not to be blamed. a simple switch to priority inversion parameter value fix everything, interrupt still runs. i would say it has something to do with the complexity of the program and as they put it "HUMAN NATURE, DEADLINE PRESSURE" the real lesson is, dont push your employee too hard. people nowadays have put DEADLINE ahead of HUMAN NATURE, thats the root of all problems. anyway, its irrelevant to this topic, the problem does not apply to simpler project.

interrupts + shared resourced(on mutex) = more cares
true but... DEADLINE = less care..

Debugging the Mars Pathfinder on the surface of Mars? Wozzat?
no, debugging was conducted in simulation on earth from received data. the fix is sending single line interpreted C command to the mars. the lesson, leave your debugging feature intact, how luxurious, it was a beta version.
Title: Re: techniques for writing non blocking code
Post by: legacy on August 02, 2017, 07:36:04 pm
In micro-robotics (I sometimes help a friend) we use MPUs with built in features like quadrature encoders and dedicated hardware (MPU built-in or inside an external fpga) which helps at motor controlling. These features do their job very well and can reduce the interrupt requests.

Of course you have to go to specialized pieces of hardware, but it's greatly better by several orders of magnitude. At least from my point of view  :-//
Title: Re: techniques for writing non blocking code
Post by: Sal Ammoniac on August 02, 2017, 08:40:52 pm
Writing the code is usually a trivial part of the implementation. Deciding what needs to be done, how to do it, and then ensuring that it does it takes far more time and brain power. Validation and verification is usually much more awkward than writing code.

By "writing code" I also meant its design, plus I did use the word "maintain" in there too.

Quote
FSMs come with important side benefits

Sure, FSMs have benefits, but writing an entire complex application as a series of interacting state machines can quickly get out of hand, especially if more than one person is involved with the development work.

Quote
That's rather in the nature of code that shares a single resource, in this case a processor.

True, but I'd rather use facilities provided by the OS than have to worry about such things myself. For instance, every time you add code to one or more tasks running from a timer tick interrupt, you have to ensure that the total execution time is less than the tick period. It's a pain to have to do this manually. Ditto for task latency. Every time tasks in the queue ahead of the one you're working on changes, it changes the relative timing of that task. If timing is critical, this can lead to subtle bugs that are hard to find. With a pre-emptive RTOS, you can arrange the task priorities such that a task that needs to meet a certain timing requirement is only subject to the (usually fixed) context switch time of the OS itself.

Quote
Quote
All-in-all, I prefer to design embedded systems (except for extremely simple ones) using an RTOS with good task synchronization facilities.

That's valid. Of course - whether or not you realise it - you are creating an FSM implemented using the RTOS facilities. Personally I prefer to go the whole hog and code FSMs explicitly.

Sometimes FSMs are necessary, and in that case a hybrid OS (one that implements regular tasking plus timer queue execution of a list of C functions) can come in handy. You can have the best of both worlds.

Quote
And whenever possible I like RTOS features to be implemented in hardware, e.g. http://www.xmos.com/download/private/xCORE-Architecture-Flyer(1.1).pdf (http://www.xmos.com/download/private/xCORE-Architecture-Flyer(1.1).pdf) :)

XMOS is an interesting architecture, but rather niche, with only one vendor and one tool set (which sucks if you hate Eclipse like a lot of people do).
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 02, 2017, 10:50:02 pm
That xCORE devices are single vendor is a valid concern. however, the xC code can also be run on ARMs, and one of their devices even has one out of eight cores being an ARM.

The architecture is unique, but I don't think it is niche. I think it confronts head-on the problems that are arising with modern semiconductor technology, and deals with them very effectively. Most architecture and tools skirt around the modern problems, wishing they weren't there, and blaming the developer for not understanding all the arcane caveats in the specification and implementation. (Yes C/C++, I'm pointing a finger at you!)

As for not liking Eclipse, I don't think that should be a valid criticsm - just us whatever tool is necessary to get the job done. Even Visual Studio is OK,if unremarkable ;)
Title: Re: techniques for writing non blocking code
Post by: Sal Ammoniac on August 02, 2017, 11:58:16 pm
The architecture is unique, but I don't think it is niche. I think it confronts head-on the problems that are arising with modern semiconductor technology, and deals with them very effectively. Most architecture and tools skirt around the modern problems, wishing they weren't there, and blaming the developer for not understanding all the arcane caveats in the specification and implementation.

Yet millions of embedded applications are successfully developed every year with traditional architectures. XMOS seems to have only made inroads in the voice and audio arenas. Perhaps I'll consider them if they start to become more mainstream.
Title: Re: techniques for writing non blocking code
Post by: legacy on August 03, 2017, 12:53:34 am
Yet millions of embedded applications are successfully developed every year with traditional architectures.

so, this theory smells interesting and millions of flies are right because they fly on a common poop on the grass  :wtf:

Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 03, 2017, 02:03:41 am
Concerning Interrupts vs FSM vs RTOS.

If you want the lower possible latency, you have to use interrupts.

If you don't need urgency them either FSM or cooperative scheduler or RTOS will work. They all will produce jitter and won't have perfect timing. It is impossible to have perfect timing on a single CPU for several tasks. Nor do you need it.

FSM will be more work, but if you have lots of tasks which you have already written for FSM, you can often mix them freely, so it might be actually the easiest way.

RTOS consumes lots of resources and forces you to do lots of manual synchronization between tasks. It cannnot run on smaller MCUs at all.

Cooperative scheduler is much more lightweight and at the same time more efficient. Would be my best choice most of the time.

Of course you can combine these 3 with interrupts - the highest priority task is driven by interrupts, but everything else forms the mix where the timing is less important.

In case of the button, there's no need for urgency and the timing is very relaxed. Therefore there are lots of different way to handle it, and it really doesn't matter what you choose. The most important thing is to make sure it doesn't interfere with more urgent tasks (if any).
Title: Re: techniques for writing non blocking code
Post by: Mechatrommer on August 03, 2017, 05:28:40 am
Yet millions of embedded applications are successfully developed every year with traditional architectures.
so, this theory smells interesting and millions of flies are right because they fly on a common poop on the grass  :wtf:
what he's saying is... we dont need xmos to make things work. you can keep how holy the xmos to yourself. "poop" is a bad analogy, "cake" should be the good one. btw, we can always outsource tasks to another mcu doing particular/specialized task like many i2c chips do. so the main process only need to ask and the external mcu may provide the data in silver plater through i2c/spi (controlled event), no problem, this stuff has many solutions to it, rather than limiting oneself to one particular architecture or school of thought.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 03, 2017, 07:25:47 am
Concerning Interrupts vs FSM vs RTOS.

If you want the lower possible latency, you have to use interrupts.

What is the guaranteed latency using interrupts? Make sure you include the effects of any caches and already being inside an ISR.

I'll bet it is orders of magnitude worse than with the xCORE processors. The £12 board I am using will respond to 8 different inputs simultaneously within <100ns. Guaranteed.

Quote
If you don't need urgency them either FSM or cooperative scheduler or RTOS will work. They all will produce jitter and won't have perfect timing. It is impossible to have perfect timing on a single CPU for several tasks. Nor do you need it.

I am getting guaranteed perfect timing for two hard real time inputs (capturing and counting the transitions in two 62.5Mb/s data streams) plus front panel buttons and LCD, plus USB comms with a PC.

That application requires zero jitter, and is achieving it; naturally other applications don't require that and zero jitter can't be achieved on most architectures.

Quote
RTOS consumes lots of resources and forces you to do lots of manual synchronization between tasks. It cannnot run on smaller MCUs at all.

The xCORE "RTOS" is effectively in hardware; zero resources.

Quote
Cooperative scheduler is much more lightweight and at the same time more efficient. Would be my best choice most of the time.

Agreed, within your constraints.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 03, 2017, 07:35:31 am
The architecture is unique, but I don't think it is niche. I think it confronts head-on the problems that are arising with modern semiconductor technology, and deals with them very effectively. Most architecture and tools skirt around the modern problems, wishing they weren't there, and blaming the developer for not understanding all the arcane caveats in the specification and implementation.

Yet millions of embedded applications are successfully developed every year with traditional architectures. XMOS seems to have only made inroads in the voice and audio arenas. Perhaps I'll consider them if they start to become more mainstream.

Nobody would claim that XMOS is the only game in town. But it is the only one I have seen directly addressing using multiple independent cores. There aren't millions of such applications, partly there are many infrequent latent bugs when using C/C++ and shared memory.

As for mainstream, that's difficult to quantify. Certainly XMOS has big powerful backers and lots of investment, and they have been developing and shipping this architecture for a decade (based on fundamental concepts from 30/40 years ago).
Title: Re: techniques for writing non blocking code
Post by: Sal Ammoniac on August 03, 2017, 05:06:43 pm
Nobody would claim that XMOS is the only game in town. But it is the only one I have seen directly addressing using multiple independent cores. There aren't millions of such applications, partly there are many infrequent latent bugs when using C/C++ and shared memory.

Some applications do need the timing guarantees that XMOS supports, but those are probably in the minority. For such applications I've usually resorted to pairing a microcontroller with an FPGA where the FPGA does the heavy lifting and provides more flexibility than XMOS can. XMOS, as an integrated solution, is probably more cost effective for high-volume products.

Quote
As for mainstream, that's difficult to quantify. Certainly XMOS has big powerful backers and lots of investment, and they have been developing and shipping this architecture for a decade (based on fundamental concepts from 30/40 years ago).

Perhaps. I think you're probably referring to the Transputer from the 1980s here. I think David May had something to do with that and the XMOS architecture. The transputer was certainly hyped in its day, but it kind of ran out of steam in the early 1990s and fell off the map. I hope XMOS doesn't suffer that fate.
Title: Re: techniques for writing non blocking code
Post by: Kalvin on August 03, 2017, 05:58:29 pm
If you don't need urgency them either FSM or cooperative scheduler or RTOS will work. They all will produce jitter and won't have perfect timing. It is impossible to have perfect timing on a single CPU for several tasks. Nor do you need it.

There are some techniques which can be used to reduce or eliminate the task jitter:

"Employing Two “Sandwich Delay” Mechanisms to Enhance Predictability of Embedded Systems Which Use Time-Triggered Co-operative Architectures"
http://file.scirp.org/pdf/JSEA20110700008_45225471.pdf (http://file.scirp.org/pdf/JSEA20110700008_45225471.pdf)
Title: Re: techniques for writing non blocking code
Post by: Wilksey on August 03, 2017, 06:17:07 pm
I use a software debounce routine inside a timer, and I have a state machine, several in fact, and the main loop goes through each machine in turn, the timers are interrupt driven and just set flags, if I have multiple buttons / LEDs I will use an array to keep track.

Perhaps a better way is mentioned elsewhere, but that's how I do it and it works for me.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 03, 2017, 07:51:51 pm
Nobody would claim that XMOS is the only game in town. But it is the only one I have seen directly addressing using multiple independent cores. There aren't millions of such applications, partly there are many infrequent latent bugs when using C/C++ and shared memory.

Some applications do need the timing guarantees that XMOS supports, but those are probably in the minority. For such applications I've usually resorted to pairing a microcontroller with an FPGA where the FPGA does the heavy lifting and provides more flexibility than XMOS can. XMOS, as an integrated solution, is probably more cost effective for high-volume products.

I wouldn't disagree with any of that. My attitude is that xCORE is encroaching into FPGA territory, no more.

xCORE/xC is based on CSP, which is a sound tested paradigm for parallel programming: you can even see CSP's influence in Go and Rust.

But my jibe at C/C++ wasn't to do with speed, it was to do with the behaviour that is deliberately left unspecified in those languages, plus their complexity. They were designed for single processors with uniform memory and no caches, and have struggled to produce clean simple behaviour with modern SMP machines. A simple example of that is that the committees have only just got around to creating a memory model specification, and I don't know how well or poorly that is implemented in various compilers (for that minority that can use the latest compilers).

Quote
Quote
As for mainstream, that's difficult to quantify. Certainly XMOS has big powerful backers and lots of investment, and they have been developing and shipping this architecture for a decade (based on fundamental concepts from 30/40 years ago).

Perhaps. I think you're probably referring to the Transputer from the 1980s here. I think David May had something to do with that and the XMOS architecture. The transputer was certainly hyped in its day, but it kind of ran out of steam in the early 1990s and fell off the map. I hope XMOS doesn't suffer that fate.

Basically yes. XMOS xC and xCORE has been around for a decade, and is continuing to gatheher investment. The Transputer and Occam are from the 80s, and CSP is from the 70s. Not a bad track record!
Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 04, 2017, 01:17:17 am
There are some techniques which can be used to reduce or eliminate the task jitter:

Yes, for example you can run only one task per interrupt. One timer interrupt - you run task one. Second time interrupt - you run task two. And so on. And you repeat this loop over and over again. The jitter will be minimal.

But what is the reason to have less jitter?

The tasks don't need to be called at the exact interval. All they need to do is to meet their timing requirements. For example, if you debounce a button, you want to check the button state every 20 ms, but really anything from 10 to 50 ms will do. Jitter is clearly not a problem here. And if you look at your tasks, many of them can leave with quite significant jitter, and if not then you can use FIFOs, DMA or other methods to relax time requirements.

If you make good use of your chip's peripheral, you don't really need to get to the processing immediately - periphery has buffers, may be able to tolerate significant delays, so jitter will not pose much problems.

Of course, you may have something time critical which cannot tolerate any delays, but you cannot have very many of these, otherwise they will interfere with each other. Such time critical tasks cannot be treated just as others. You have to process them in high priority interrupts, possible write the interrupts in assembler to avoid C prologue/epilogue. There's no techniques which will help you with this - nothing you can do can give your interrupts better latency than your hardware can provide.


Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 04, 2017, 01:34:49 am
I'll bet it is orders of magnitude worse than with the xCORE processors. The £12 board I am using will respond to 8 different inputs simultaneously within <100ns. Guaranteed.

I am getting guaranteed perfect timing for two hard real time inputs (capturing and counting the transitions in two 62.5Mb/s data streams) plus front panel buttons and LCD, plus USB comms with a PC.

Of course, if you have multiple cores they won't interfere with each other. The same way as if I had multiple MCUs on a board where each of them works on its own time-critical task without any interference.

However, the techniques for achieving multitasking in such a system would be completely different than with a single MCU. You don't need to lift a finger to ensure simultaneous action - each CPU does its own job.

Implementing multitasking on a single CPU is a little bit more complicated. You can use several different techniques. These techniques help you avoid adding extra CPUs to your system. IMHO, this thread is about such techniques.

Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 04, 2017, 07:04:03 am
There are some techniques which can be used to reduce or eliminate the task jitter:
...
If you make good use of your chip's peripheral, you don't really need to get to the processing immediately - periphery has buffers, may be able to tolerate significant delays, so jitter will not pose much problems.

The extent to which that can be achieved depends on the application, the inputs, and a computer's peripherals.

For the specific case of debouncing a switch, there ought to be peripheral support in an MCU.

Quote
Of course, you may have something time critical which cannot tolerate any delays, but you cannot have very many of these, otherwise they will interfere with each other. Such time critical tasks cannot be treated just as others. You have to process them in high priority interrupts, possible write the interrupts in assembler to avoid C prologue/epilogue. There's no techniques which will help you with this - nothing you can do can give your interrupts better latency than your hardware can provide.

You are confusing "time critical" with "fast". The two concepts are orthogonal, and completely different design techniques and implementation techniques are required to address each of them.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 04, 2017, 07:27:34 am
I'll bet it is orders of magnitude worse than with the xCORE processors. The £12 board I am using will respond to 8 different inputs simultaneously within <100ns. Guaranteed.

I am getting guaranteed perfect timing for two hard real time inputs (capturing and counting the transitions in two 62.5Mb/s data streams) plus front panel buttons and LCD, plus USB comms with a PC.
Quote

Of course, if you have multiple cores they won't interfere with each other. The same way as if I had multiple MCUs on a board where each of them works on its own time-critical task without any interference.

However, the techniques for achieving multitasking in such a system would be completely different than with a single MCU. You don't need to lift a finger to ensure simultaneous action - each CPU does its own job.

Implementing multitasking on a single CPU is a little bit more complicated. You can use several different techniques. These techniques help you avoid adding extra CPUs to your system. IMHO, this thread is about such techniques.

I did note write that. I will answer on the basis that you simply messed up the quote delimiters.

You appear not to understand the relevance of the classic "dining philosophers" problem to your position.

Your statements are only true in a limited and uninteresting way. (Plus if you use common implementation techniques they are frequently inapplicable; and people often do just that :( )

Fundamentally your statement is only true so long as the threads/cores/tasks are independent and to not have to communicate with each other.  When, as happens in all non-trivial systems, one task/thread/core's progress depends on another, then you have time dependency. That leads to jitter and or deadlock/livelock.

And that is why CSP (Communicating Sequential Processes) is so valuable in such systems, whether on single processor or multiprocessor systems, whether in languages that directly support CSP concepts (e.g.xC, Go) or as an architectural design pattern realised in a common language.
Title: Re: techniques for writing non blocking code
Post by: legacy on August 04, 2017, 11:36:31 am
as an architectural design pattern realised in a common language.

Exactly the point.
Perhaps those who like the C language will have a shock reading a paper like this (http://www.hpl.hp.com/techreports/2004/HPL-2004-209.pdf)  :o :o :o
Title: Re: techniques for writing non blocking code
Post by: Kalvin on August 04, 2017, 11:58:49 am
There are some techniques which can be used to reduce or eliminate the task jitter:

Yes, for example you can run only one task per interrupt. One timer interrupt - you run task one. Second time interrupt - you run task two. And so on. And you repeat this loop over and over again. The jitter will be minimal.

But what is the reason to have less jitter?
<snip>

Yes, there are many different techniques one can use to reduce task jitter. I just wanted to post the paper as there were some discussion about task timing jitter. In most application the jitter is not a problem as long as the tasks meet the timing requirements. Obviously there are some applications that require more strict, hard realtime timing and and tolerate only very little jitter, and the techniques presented in the paper address those systems.

Of course, in order to achieve the best performance the on-chip hardware peripherals, dedicated hardware (ie. FPGA etc.) and/or using processor architectures designed for accurate timing purposes (ie. DSP and XMOS) is used when possible.

In some high reliability systems one just cannot use the state of the art compilers, embedded devices, peripheral components and FPGA etc. as they are not certified to be used in high reliability systems. In these systems one has to use the devices that are certified, but these devices may not contain necessary optimized hardware resources and the designers need to use other techniques in order to meet the requirements.

In some systems the cost is the driving force to use the cheapest device possible and use software techniques to meet the requirements. If the manufacturer can reduce device cost $1 for each device manufactured and they manufacture those device in millions, then the financial gains are quite high even if the actual development costs will be somewhat higher.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 04, 2017, 12:55:19 pm
as an architectural design pattern realised in a common language.

Exactly the point.
Perhaps those who like the C language will have a shock reading a paper like this (http://www.hpl.hp.com/techreports/2004/HPL-2004-209.pdf)  :o :o :o

C/C++ zealots are often willfully blind, preferring to blame all the developers rather than admit the tool is causing the problems. The C++ FQA is entertaining.

Thanks for the decent reference. Boehm is not a fool, even if he did chase after an "often works but you can't rely on it" GC for C.

I knew the PThreads/C problem existed, based the summation of the statements about what is explictly not defined in C. However, it is useful to have a pointer to a high quality paper bringing the arguments together.

I note the paper referred to a Java-like memory model. I believe a dozen(!) or so years later one has been produced. If so, it will be interesting to see how well it is implemented and how well it works. Based on the C/C++ 99 experience, I'm not going to hold my breath!
Title: Re: techniques for writing non blocking code
Post by: JPortici on August 04, 2017, 01:16:24 pm
as an architectural design pattern realised in a common language.

Exactly the point.
Perhaps those who like the C language will have a shock reading a paper like this (http://www.hpl.hp.com/techreports/2004/HPL-2004-209.pdf)  :o :o :o

not shocking by any means :) I already pondered on many of the problems described in the paper, and i have never ever used an RTOS or used anything else than C/basic for microcontrollers.
Just state machines and interrupt-enabled code.
one just have to spend a single minute to think and wonder at what would happen if the variable he's using -not in accumulators or onto the stack- changes its value during a functions, because DMA or a piece of code during interrupts altered the memory content... i think it was even mentioned by my high-school (!) teachers once or twice
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 04, 2017, 02:55:30 pm
as an architectural design pattern realised in a common language.

Exactly the point.
Perhaps those who like the C language will have a shock reading a paper like this (http://www.hpl.hp.com/techreports/2004/HPL-2004-209.pdf)  :o :o :o

not shocking by any means :) I already pondered on many of the problems described in the paper, and i have never ever used an RTOS or used anything else than C/basic for microcontrollers.
Just state machines and interrupt-enabled code.
one just have to spend a single minute to think and wonder at what would happen if the variable he's using -not in accumulators or onto the stack- changes its value during a functions, because DMA or a piece of code during interrupts altered the memory content... i think it was even mentioned by my high-school (!) teachers once or twice

Good for you :) It is pleasing always to come across people that think, and to have switched-on high school teachers :)

Unfortunately it is normal for such considerations to not be understood. All too often people haven't considered it, and/or think "you declare function as an ISR", and/or "the library takes care of that", and/or "that's why you use volatile". As for considering the interactions between L1/L2/L3 caches, main memory and the cores - dream on!

I've heard all of those - more than once :(
Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 04, 2017, 03:46:22 pm
I did note write that.

Of course you didn't. I fixed the quotation.

You appear not to understand the relevance of the classic "dining philosophers" problem to your position.

The deadlock problem has nothing to do with real-time performance. Avoiding deadlocks is algorithmic question. Think about it. It is possible to find a solution  for the "philosophers" problem before you even think of the hardware platform you're going to use.

We're discussing here real-time systems, which heavily depend on the hardware architecture.

Real-time performance is the ability to act at a specified point of time. When something happens, your program needs to take control and do something. The time between the triggering event and the moment where the program acts is called latency. Sometimes, if your event is predictable (such as periodic timer) you can master zero-latency. Other times, the event is unpredictable and thus zero-latency is impossible. The lowest latency you can master is most likely interrupt latency, or if you can dedicate your entire CPU to this single event, it is the duration of the shortest loop capable of detecting an event.

Now imagine you have two real-time tasks. Say, task A is doing something at fixed period with zero-latency. At the same time, task B is doing something when a rising edge from an external line arrives. Thus task B has interrupt latency. What happens if the events happen as follows:

- a rising edge for task B arrives
- the interrupt latency time passes so that task B has to run now
- at exactly the same time the period for task A expires

If you have only one CPU, it is absolutely impossible for these two tasks to run at the same time. What you can do about this? You can run task A. This increases the latency of task B, and it is no longer equal to interrupt latency, but is equal  to (interrupt latency + time to do the minimum processing for task A). Or, you can run task B, then the latency of task A will not be zero any longer, but will be equal to the time necessary to do some minimum processing for task B. If neither of these meets your timing requirements, nothing you can do. This is interference caused by multitasking. A can be served alone, B can be served alone, but A and B together cannot.

The only solution is to run tasks A and B on two different physical devices. Say, you get two PIC16s, one is doing task A, the other is doing task B. Then they somehow communicate when neither task A or task B is running. For 2 tasks we need 2 CPUs. For 8 tasks we need 8 CPUs.

What XMOS does? If I understand correctly, it has many CPU (cores) which can be dynamically assigned to the tasks as necessary. How many cores do we need to make sure 2 tasks never interfere with each other in a way I explained before. Two. How many cores do we need for 8 tasks? Eight. Well, we could probably get away with 6, but if there's any probability that all 8 events happen all at the same time, then 6 wouldn't be robust, would it? In short, to handle N tasks we need N CPUs. This is the same number of CPUs as if we had one CPU dedicated to one task. This is  practically the same as a system with N different MCUs on the board.

What most others do? They have peripheral modules which can handle common tasks, so that the time-critical portions of the tasks can be performed entirely by the peripheral modules without any CPU intervention. Say, you can have a PIC with 16 input capture modules. Each of the modules can capture edges with 10-20 ns resolution. Or you can have a number of PWM modules which will produce accurate signal with transitions timed at 10 ns resolution. And so on, and so on. As a result, a single PIC can perform way more tasks than a multi-core solution, and they totally do not interfere with each other in a sense that the time-critical actions are never postponed.

The question is, what to do if the real time requirements are so complex that they cannot be handled by peripherals? Very simple, put an extra MCU or 2 on the board for just that purpose. Not enough? Go to FPGA.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 06, 2017, 10:11:08 am
You appear not to understand the relevance of the classic "dining philosophers" problem to your position.

The deadlock problem has nothing to do with real-time performance. Avoiding deadlocks is algorithmic question. Think about it. It is possible to find a solution  for the "philosophers" problem before you even think of the hardware platform you're going to use.

We're discussing here real-time systems, which heavily depend on the hardware architecture.

If you think about it, those two paragraphs are mutually contradictory. The issue is that real-time systems' required behaviour doesn't depend heavily on hardware architecture. (But a choice of inadequate hardware and software can prevent it).

Remember, realtime != fast.


Quote
If you have only one CPU, it is absolutely impossible for these two tasks to run at the same time. What you can do about this? You can run task A. This increases the latency of task B, and it is no longer equal to interrupt latency, but is equal  to (interrupt latency + time to do the minimum processing for task A). Or, you can run task B, then the latency of task A will not be zero any longer, but will be equal to the time necessary to do some minimum processing for task B. If neither of these meets your timing requirements, nothing you can do. This is interference caused by multitasking. A can be served alone, B can be served alone, but A and B together cannot.

Not necessarily: providing constraints are met, interference can be absent. Meeting constraints can be aided/prevented by appropriate hardware+software mechanisms.

Quote
What XMOS does? If I understand correctly, it has many CPU (cores) which can be dynamically assigned to the tasks as necessary.

The tasks are statically allocated; that's required for the IDE to define execution times without executing code and measuring a subset of the possible times.

The interesting point about the XMOS devices is that the combination of hardware+software enables such predictions in a way that is impossible for bog-standard processors.

Quote
The question is, what to do if the real time requirements are so complex that they cannot be handled by peripherals? Very simple, put an extra MCU or 2 on the board for just that purpose. Not enough? Go to FPGA.

Extra MCUs won't, on their own, solve fundamental real-time problems.

The XMOS devices are no more magic than FPGAs and bog-standard processors. But the XMOS devices do have a set of unique beneficial characteristics - which illuminate the limitations of mainstream technologies.
Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 06, 2017, 02:29:24 pm
The issue is that real-time systems' required behaviour doesn't depend heavily on hardware architecture.

What do you mean by that? Are you suggesting that any hardware has equal (or similar) real-time capabilities?

Remember, realtime != fast.

Depends on what you mean by "fast". Not fast as a runner, but fast as a gun fighter.

Title: Re: techniques for writing non blocking code
Post by: David Hess on August 06, 2017, 02:50:51 pm
The issue is that real-time systems' required behavior doesn't depend heavily on hardware architecture.

What do you mean by that? Are you suggesting that any hardware has equal (or similar) real-time capabilities?

It means that how the software is designed has more of an effect on real time performance than the hardware.  Bad software can ruin the real time performance of any hardware.

Quote
Remember, realtime != fast.

Depends on what you mean by "fast". Not fast as a runner, but fast as a gun fighter.

Real time means bounded latency.  Almost all systems using high performance multi-core processors have an order of magnitude worse latency than 20+ year old systems using processors with 4 orders of magnitude less performance because of software limitations.

For example my HP50g calculator with a 50MHz 32 bit processor has higher latency than the HP48g it replaced which had a 4MHz 4-bit processor.  From the perspective of the user, it is *slower* and less power efficient.  That is the cost of progress.

Title: Re: techniques for writing non blocking code
Post by: legacy on August 06, 2017, 04:59:10 pm
Because pipeline
worst caste: long pipeline with short icache.
Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 06, 2017, 05:46:49 pm
It means that how the software is designed has more of an effect on real time performance than the hardware.  Bad software can ruin the real time performance of any hardware.

Hardware sets the limit which you cannot jump over. Then it is up to you to meet this limit with your software or overbloat your software beyond any reason. If most people chose the overbloat, does it really mean that real time performance doesn't depend on hardware?

Remember, realtime != fast.

Depends on what you mean by "fast". Not fast as a runner, but fast as a gun fighter.

Real time means bounded latency.  Almost all systems using high performance multi-core processors have an order of magnitude worse latency than 20+ year old systems using processors with 4 orders of magnitude less performance because of software limitations.

These are not software limitations. This is just the way the software is written today.

However, you always can use assembler to re-write your time-critical sections. This way you remove any dependency on software, and you will get the best possible latency from the device. But then you will find out that the so called "performance" of modern processors is predicated by pipelines and caches which increase throughput, but do not help with latency (especially worst-case latency). So, the super-duper ARM processor may have worse latency than a small PIC.

Title: Re: techniques for writing non blocking code
Post by: nctnico on August 06, 2017, 07:01:08 pm
Perhaps but better pheripherals may have more relaxed interrupt reaction times. Also on a small 8 bit micro you may need to save the registers on the stack first which is something a Cortex Mx does in hardware.
Title: Re: techniques for writing non blocking code
Post by: David Hess on August 06, 2017, 07:33:07 pm
These are not software limitations. This is just the way the software is written today.

If it is how software is written today, then it is a software limitation.

This is like how Intel argued that their Itanium processor had a massive performance edge over other processors while showing off a few hundred lines of hand optimized assembly code.  This performance was not achievable with the compiler so where was the fault?  The hardware or compiler?  It is irrelevant and Intel's benchmark was irrelevant also.  The processor sucked except for killing the competition.

Quote
However, you always can use assembler to re-write your time-critical sections. This way you remove any dependency on software, and you will get the best possible latency from the device. But then you will find out that the so called "performance" of modern processors is predicated by pipelines and caches which increase throughput, but do not help with latency (especially worst-case latency). So, the super-duper ARM processor may have worse latency than a small PIC.

This is way beyond the limits imposed by pipelining and caches and language choice is irrelevant when the programmer is using things like just in time compiling, dynamic memory allocation, (1) and screwed up library code.

Garbage collection is usually always a killer.  (2) I remember Sun saying that JAVA would be used everywhere from the smallest microcontrollers to the largest multiprocessors.  I just laughed.

If the programming ecosystem does not allow programmers to achieve the performance that the hardware is capable of, then that performance does not exist.

(1) Dynamic memory allocation is feasible in real time environments but you have to use the right memory allocator and use it correctly.  I always thought Knuth's memory allocator could do it but I never tried implementing it.

(2) There might be a real time memory allocator which uses garbage collection but I have never seen it and the attempts to make one have been disappointing.  It seems like something which could be integrated into a RTOS but I assume this is one of those intractable hard problems.
Title: Re: techniques for writing non blocking code
Post by: Bruce Abbott on August 06, 2017, 07:35:30 pm
on a small 8 bit micro you may need to save the registers on the stack first which is something a Cortex Mx does in hardware.
Really?

https://www.adamheinrich.com/blog/2016/07/context-switch-on-the-arm-cortex-m0/ (https://www.adamheinrich.com/blog/2016/07/context-switch-on-the-arm-cortex-m0/)
Quote
Context Switch

The context switch happens in an interrupt handler. Once an interrupt occurs, the NVIC hardware automatically stacks an exception frame (registers xPSR, PC, LR, r12 and r3-r0) onto the Process Stack (PSP) and branches to the interrupt handler routine in Handler Mode (which uses the Main Stack).

The context switch routine has to:

    Manually stack remaining registers r4-r11 on the Process Stack
    Save current task’s PSP to memory
    Load next task’s stack pointer and assign it to PSP
    Manually unstack registers r4-r11
    Call bx 0xfffffffD which makes the processor switch to Unprivileged Handler Mode, unstack next task’s exception frame and continue on its PC.
Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 06, 2017, 07:50:51 pm
If the programming ecosystem does not allow programmers to achieve the performance that the hardware is capable of, then that performance does not exist.

What the hell is "programming ecosystem"? You're free to write your software as you please. There are lots of people out there who write good software.
Title: Re: techniques for writing non blocking code
Post by: David Hess on August 06, 2017, 08:02:40 pm
If the programming ecosystem does not allow programmers to achieve the performance that the hardware is capable of, then that performance does not exist.

What the hell is "programming ecosystem"? You're free to write your software as you please. There are lots of people out there who write good software.

It is the tools and libraries available to the programmer for whatever reason.
Title: Re: techniques for writing non blocking code
Post by: nctnico on August 06, 2017, 08:07:27 pm
on a small 8 bit micro you may need to save the registers on the stack first which is something a Cortex Mx does in hardware.
Really?

https://www.adamheinrich.com/blog/2016/07/context-switch-on-the-arm-cortex-m0/ (https://www.adamheinrich.com/blog/2016/07/context-switch-on-the-arm-cortex-m0/)
There must be something wrong with that because it implies you can't use plain C functions as interrupt handlers which a Cortex Mx can use. OTOH it may be not all registers are used. Either way it doesn't negate the fact Cortex Mx controllers do in hardware what is typically done in software on an 8 bit microcontroller.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 06, 2017, 08:29:12 pm
Garbage collection is usually always a killer.
...
(1) Dynamic memory allocation is feasible in real time environments but you have to use the right memory allocator and use it correctly.  I always thought Knuth's memory allocator could do it but I never tried implementing it.

(2) There might be a real time memory allocator which uses garbage collection but I have never seen it and the attempts to make one have been disappointing.  It seems like something which could be integrated into a RTOS but I assume this is one of those intractable hard problems.

While I agree with your other points, those points turn out not to be the case.

Many misconceptions about GCs are based on partial information of obsolete GC technology. Modern GCs have improved enormously, to the extent there are many commercially and technically successful real time systems written in Java; I have personally created a few.

Classic examples are "high frequency trading", which is critically latency-sensitive, and telecoms systems where soft real time performance is specified and achieved.

Of course, if hard realtime performance is specified, GC is almost always contra-indicated.
Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 06, 2017, 08:31:11 pm
It is the tools and libraries available to the programmer for whatever reason.

IMHO, the available tools let you fully realize the hardware potential if you're inclined to do so.
Title: Re: techniques for writing non blocking code
Post by: legacy on August 06, 2017, 08:34:10 pm
What the hell is "programming ecosystem"? You're free to write your software as you please.

LOL  :-DD :-DD :-DD :-DD :-DD

Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 06, 2017, 08:37:56 pm
It is the tools and libraries available to the programmer for whatever reason.

IMHO, the available tools let you fully realize the hardware potential if you're inclined to do so.

That's a meaningless statement. Depending on interpretation, it is either wrong or trivially true.
Title: Re: techniques for writing non blocking code
Post by: legacy on August 06, 2017, 08:54:13 pm
about transputer, this (http://wordpress-transputeriot.rhcloud.com/wp-content/uploads/2015/03/poster.pdf) seems to be an interesting modern reboot (for fpga).
Title: Re: techniques for writing non blocking code
Post by: andyturk on August 06, 2017, 09:15:55 pm
There must be something wrong with that because it implies you can't use plain C functions as interrupt handlers which a Cortex Mx can use. OTOH it may be not all registers are used. Either way it doesn't negate the fact Cortex Mx controllers do in hardware what is typically done in software on an 8 bit microcontroller.
Both the link and your interpretation are correct. An RTOS context switch has to save the entire state of the machine, so it can restore it later. A "normal" interrupt can just be straight C code.

Context switches with hard floating point can get pretty expensive because the floating point registers have to be saved/restored too.
Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 06, 2017, 09:31:42 pm
Both the link and your interpretation are correct. An RTOS context switch has to save the entire state of the machine, so it can restore it later. A "normal" interrupt can just be straight C code.

Many modern CPUs have shadow register sets which are automatically swapped by hardware before launching the ISR, so you don't need to save registers. PIC16/18 too.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 06, 2017, 09:32:58 pm
about transputer, this (http://wordpress-transputeriot.rhcloud.com/wp-content/uploads/2015/03/poster.pdf) seems to be an interesting modern reboot (for fpga).

Hmmm....

Personally I'm more interested in, for lack of a better term, the philosophy rather than a specific implementation of the philosophy.

Hence my being "satisfied" by xCORE+xC.

... so I suppose I'll regard that proposal as being interesting historically, but I'll reserve judgement about its practical interest.
Title: Re: techniques for writing non blocking code
Post by: JPortici on August 06, 2017, 09:33:58 pm
What the hell is "programming ecosystem"? You're free to write your software as you please.
LOL

please guys, stop be so condescending. you are just as annoying as PSOC pretyped walls of text or even ADA and SUBLEQ crusaders, just to mention a couple.

that is the only reason why i bothered to comment before.

there is a chance that there are people who can think but are not as knowledgeable as you are or hasn't worked in avionics or don't know what an ingenious things xmos is yed and may be just humble programmers who think they can still write a good piece of software with their unsafe tools, as it happens and is still happening and will always happen as long as C exists... so a very long time.
and they may be asking what are, from their point of view, legitimate questions.

i see no reason to mock them (us)
this is not /g/ or reddit or whatever garbage community of elites
Title: Re: techniques for writing non blocking code
Post by: Bruce Abbott on August 06, 2017, 09:45:14 pm
it may be not all registers are used.
Sure, but that's only useful if you limit your code to using a reduced register set. Even lowly 8 bit PICs and AVRs can do that.

Quote
Either way it doesn't negate the fact Cortex Mx controllers do in hardware what is typically done in software on an 8 bit microcontroller.
My definition of 'in hardware' would be using eg. shadow registers or bank switching, not just automatically saving registers on the stack (the STM8, 68HC11, and even the ancient MC6801 do that).
   
Title: Re: techniques for writing non blocking code
Post by: KL27x on August 06, 2017, 11:18:38 pm
^ This what I was thinking. Who cares if it automatically saves registers? Newer 8 bit PIC have automatic context saving. Older ones don't. Only difference to me is 6 lines of assembly, 3 in the beginning of ISR and 3 at the end. This is pretty much saying "new model has 6 extra words of instructions and 3 extra bytes of memory compared to older model." You can also conisder those resources are automaticallly reserved for isr, which deprives the user in case he didnt need them for ISR. This is nice to the programmer but not an actual improvement in specs.

If it did this in parallel to core processor which reduces latency, then that's different.

I went my round with TGZZZZ several months ago. It's matter of perspective, which I accept as assembly programmer of simple device, I have complete control over actual hardware limitations. So I see North Guy's perspective as valid. But if you are using RTOS, you are using more complex toolchain which you can't completely rewrite or circumvent with inline assembly unless you are in a very specialized business. Most people are paid to get a job done, efficiently. Not to fine tune tools to make tools specific to a given end product.
Title: Re: techniques for writing non blocking code
Post by: Mechatrommer on August 06, 2017, 11:44:56 pm
please guys, stop be so condescending. you are just as annoying as PSOC pretyped walls of text or even ADA and SUBLEQ crusaders, just to mention a couple.
that is the only reason why i bothered to comment before.
there is a chance that there are people who can think but are not as knowledgeable as you are or hasn't worked in avionics
+1. let them try to define or impose on our reality with their own reality, its quite amusing watching from here. for us, their theories seems or sounds plausible yet confusing in multitude grade of levels, but above all, unproven or in another simpler word... nonsense... from a simple switch non blocking single cored code to multicores, parallelism, resources sharing, priority inversion, real time, ecosystem and whatever sheets thats going to be arised next... afaik most of those terms are very well defined and known since before our birth or probably since the invention of Babbage machine, then here they are come up with probably their own delusional meaning in this ever growing thread, just like the fate of the other threads.. the first rule of thumb is, when the slightest correlation between a noob thread and programming, you'll see long winded people with long winded theory try promoting this and that and how unholy C/C++ is... dont you ever try to correct the path to the laymen ship otherwise you'll be dragged away with all these confusing theories and will be doomed to look just like a fool... well... weekend is over... the fuck with the theories, we only care about practical and workable codes. we harness machines to do our jobs, not the other way around...
Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 07, 2017, 12:21:09 am
^ This what I was thinking. Who cares if it automatically saves registers? Newer 8 bit PIC have automatic context saving. Older ones don't. Only difference to me is 6 lines of assembly, 3 in the beginning of ISR and 3 at the end. This is pretty much saying "new model has 6 extra words of instructions and 3 extra bytes of memory compared to older model." You can also conisder those resources are automaticallly reserved for isr, which deprives the user in case he didnt need them for ISR. This is nice to the programmer but not an actual improvement in specs.

If it did this in parallel to core processor which reduces latency, then that's different.

PICs don't use extra cycles to store registers. They're stored automatically and restored back automatically. This is all done in hardware at the very moment the interrupt is taken. No single cycle is added.

PIC16F1* stores 8 different registers, which saves 16 instructions at the beginning of the ISR, which gives you 2 cycle latency (250 ns, or 166 ns on PIC16F14* which can use 48MHz clock). If you would do savings manually, it would give you 18 cycle latency - 4.5 us (plus 16 cycles when you leave the interrupt). 4.5 us is way bigger latency than 250 ns, so the auto-save is very important - it lets you achieve much higher performance.

The newest PIC18F - K42 series save 13 registers thus gaining 26 cycle time. In non-vectored mode the latency is 2 cycles too - you get control with all registers saved 125 ns after the interrupt. This is compared to 3.5 us if you had to save them manually. This is an extremely useful feature.

With PIC24EP/dsPIC33EP, some of which have so called "Alternate register sets", it avoids saving 15 registers, saving 15 cycles. But here the interrupt latency is 11 cycles, so you only get 157 ns at 140 MHz clock, but it's still better than 371 ns you get on the PIC24EPs without the shadow registers.
Title: Re: techniques for writing non blocking code
Post by: KL27x on August 07, 2017, 02:49:22 am
^Total sidetrack, but NorthGuy, can you explain this one?

Using 16F1xxx enhanced midrange. I happen to have an older code which has a long subroutine which wraps across page boundary. It's absolute code and there are so many local sub subroutines in it, I can't easily extract it. In this particular code, I have to put "pagesel $" as the first line of the ISR, or I get a bad jump. I assume it is due to presence of this weird subroutine, but I can't understand why. Is it possible that the hardware is saving and restoring the address of the initial call and does not update itself when the subroutine crosses page boundary? But then I don't get how putting pagesel $ at the beginning of the ISR would fix anything.... yet it does. I treat the subroutine in question as a long call (I can actually call it locally from the first page, but pagesel $ after the call), and it works fine, except I have to put that pagesel in the ISR.

(I know this doesn't make any sense; the only way it can run that instruction is if it goes to the right page to begin with). :-//

+1 Re: Mechatrommer. I accept that depending on context/POV, some things are not practical. But in theoretical argument it is maybe confusing to state as fact things which are dependent on theory of practical problems and further confusing when refuting something that is at least perhaps theoretically, if not empirically, correct as false, based on theoretical issue of what is practical.  :-DD 
Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 07, 2017, 03:33:18 am
Using 16F1xxx enhanced midrange. I happen to have an older code which has a long subroutine which wraps across page boundary. It's absolute code and there are so many local sub subroutines in it, I can't easily extract it. In this particular code, I have to put "pagesel $" as the first line of the ISR, or I get a bad jump. I assume it is due to presence of this weird subroutine, but I can't understand why. Is it possible that the hardware is saving and restoring the address of the initial call and does not update itself when the subroutine crosses page boundary? But then I don't get how putting pagesel $ at the beginning of the ISR would fix anything.... yet it does. I treat the subroutine in question as a long call (I can actually call it locally from the first page, but pagesel $ after the call), and it works fine, except I have to put that pagesel in the ISR.

The "call" and "goto" instructions require PCLATH set to the page which you're calling. A standard way of doing this:

Code: [Select]
pagesel Something
call Something

When you enter the ISR, it saves the old PCLATH (and will restore it when you return), but it doesn't load any new value. So, when you enter the ISR, PCLATH could be anything (whatever it was at the moment when the interrupt has happened). All the "goto" and "call" instructions which you do inside the ISR will use this random PCLATH. Therefore, if you have any "goto" or "call" inside your ISR, you need to make sure, the PCLATH is pointing to the destination of the "goto" and "call". I guess that's why you need "pagesel $" at the beginning of the ISR. Alternatively, you can use "bra" instead of "goto". It has shorter reach, but it doesn't require "pagesel".
Title: Re: techniques for writing non blocking code
Post by: KL27x on August 07, 2017, 03:55:11 am
^Ahh, ok. Good to know I'm maybe not crazy for putting pagesel $ in my ISR.

I thought it was due to this subroutine, but in hindsight perhaps just a factor of the first time I crossed over to page 1 in my life. And yeah, I put that pagesel there, everafter.

So ISR vector is special and pointer gets there without any paging address? I wonder if RESET vector the same? (I am putting "pagesel START, goto START" even when START is on page 0 but I'm not sure that's really necessary.)

These addresses are 0x0000 and 0x0004... and same addresses exist on page 1 (0x0800 and 0x0804) and every other page...  :-//  I take it they reach reset and isr vector by pure hardware?
Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 07, 2017, 05:04:14 am
^Ahh, ok. Good to know I'm maybe not crazy for putting pagesel $ in my ISR.

I thought it was due to this subroutine, but in hindsight perhaps just a factor of the first time I crossed over to page 1 in my life. And yeah, I put that pagesel there, everafter.

So ISR vector is special and pointer gets there without any paging address? I wonder if RESET vector the same? (I am putting "pagesel START, goto START" even when START is on page 0 but I'm not sure that's really necessary.)

These addresses are 0x0000 and 0x0004... and same addresses exist on page 1 (0x0800 and 0x0804) and every other page...  :-//  I take it they reach reset and isr vector by pure hardware?

The jump doesn't go to the page where the execution is at the moment. For example, if your code flows through the page boundary, it doesn't change anything. The program counter (PC) consists of two parts - high byte (PCH) and low byte (PCL). Say, when you execute at 0x0804, PCH is 0x08 and PCL is 0x04.

When you execute goto, such as

Code: [Select]
goto 0x0220
PCL is loaded from the instruction code (becomes 0x20 in this case).
The low 3 bits of the PCH are also loaded from the instruction code (0x02 in this case).
But the instruction is only 14 bits and doesn't have any room for more bits. So, the rest of the destination address goes from the special PCLATH register:

Code: [Select]
PCH = (3 bits from the instruction code) | (PCLATH & 0xf8);
PCLATH doesn't change by itself. Nor when you jump, nor when the code crosses page boundary. It only changes when you do "pagesel" (which is in fact movlp instruction which sets PCLATH) or explicitly write to PCLATH.

So, if you have any "goto" or "call" inside your ISR then you do need "pagesel" which will make sure that the PCLATH is set correctly for these jumps. Otherwise, they'll jump astray.
Title: Re: techniques for writing non blocking code
Post by: JPortici on August 07, 2017, 05:55:48 am
@northguy: i finally have a couple of 26k42 with the latest components order. What i'm interested at is to test
-IF the IVT can help me reduce the jitter in generating square waves with the timer countdown method... not that there is need to, i have microseconds jitter on a constantly changing 1-10 kHz signals (airflow sensor), though i have to adjust corretions factor to have a linear response over the entire range. It's more to amuse myself AND be ready for when i will actually need it
-IF with the DMA and ADC-Squared i can siplify the analog input routine and further slow down the processor
last one is more related to the topic: what if the inputs are changed by DMA in the middle of the routine :P? Simple answer: i make a temp variable (hoping that a hardware (DMA)/compiler (Compiled stack) bug doesn't make the chip modify it)

dspic: was the latency that high? I know there's a higher latency from interrupt to code, but another 11 cycles for context switching? I remember that EP/EV has single cycle push+pop instructions, but they only save W0 to W3.
I shall take out the programmer's manual...
By the way I never use shadow registers/context saving as i always have more problems with them that the benefits i gain
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 07, 2017, 06:38:20 am
I went my round with TGZZZZ several months ago. It's matter of perspective, which I accept as assembly programmer of simple device, I have complete control over actual hardware limitations. So I see North Guy's perspective as valid. But if you are using RTOS, you are using more complex toolchain which you can't completely rewrite or circumvent with inline assembly unless you are in a very specialized business. Most people are paid to get a job done, efficiently. Not to fine tune tools to make tools specific to a given end product.

I agree with that.

In particular I agree with the concept that for very simple applications you can use many techniques. However, such techniques aren't necessarily scalable to larger and/or more complex applications. I believe it is important that people understand that.

The mechanical engineers get frustrated when people implicitly or explicitly expect that their application can be made with a few bits of string and sheet metal. This is an analogue of that!

I also agree that people are paid to get a job done and not to fine tune tools. That should be extended to finding bugs and subtle problems in tools, and inventing workarounds.
Title: Re: techniques for writing non blocking code
Post by: David Hess on August 07, 2017, 03:28:26 pm
PICs don't use extra cycles to store registers. They're stored automatically and restored back automatically. This is all done in hardware at the very moment the interrupt is taken. No single cycle is added.

PIC16F1* stores 8 different registers, which saves 16 instructions at the beginning of the ISR, which gives you 2 cycle latency (250 ns, or 166 ns on PIC16F14* which can use 48MHz clock). If you would do savings manually, it would give you 18 cycle latency - 4.5 us (plus 16 cycles when you leave the interrupt). 4.5 us is way bigger latency than 250 ns, so the auto-save is very important - it lets you achieve much higher performance.

How many times can they do that without restoring?  Once like on a Z80 with its duplicate register set?

Being able to save and restore the entire register set is nice but what I usually do is rely on the ISR to save *only* the registers that it is going to use to save time which is neatly undone with a RTOS that lacks knowledge of which registers those are.  Maybe if that matters, one should be using a faster processor.

The original ARM was designed with this in mind.  Its pipeline and instruction timing was closely linked to fast page mode (or nibble mode?) DRAM allowing the multiple save and restore register instructions executed as quickly as possible.
Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 07, 2017, 03:49:53 pm
@northguy: i finally have a couple of 26k42 with the latest components order. What i'm interested at is to test
-IF the IVT can help me reduce the jitter in generating square waves with the timer countdown method... not that there is need to, i have microseconds jitter on a constantly changing 1-10 kHz signals (airflow sensor), though i have to adjust corretions factor to have a linear response over the entire range. It's more to amuse myself AND be ready for when i will actually need it

If you want the best possible latency you need to eliminate everything which can negatively affect the latency. You cannot disable interrupts (because the time when they're disabled is added to your latency) and you need to make sure that there's no other interrupts on the same or higher level (because while these interrupts are being served yours is pending). Then, if you eliminate all other interrupts, IVT doesn't benefit you any more, but it does add 1 cycle to the interrupt latency (PIC uses the extra cycle to fetch the vector).

If you don't need very short latencies (which is usually the case) and you have many interrupts then IVT is very beneficial. It completely eliminates the code necessary to figure out which interrupt has happened. Thus it reduces latencies and jitter.

For the 1-10kHz signal you can use PWM. If PWM is impossible for some reason, then you can try to use CLC triggered by timer, although using CLCs usually takes some design effort.

-IF with the DMA and ADC-Squared i can siplify the analog input routine and further slow down the processor
last one is more related to the topic: what if the inputs are changed by DMA in the middle of the routine :P? Simple answer: i make a temp variable (hoping that a hardware (DMA)/compiler (Compiled stack) bug doesn't make the chip modify it)

Usually, you can use some sort of ping-pong buffer. DMA writes to one half while you read the other half, then it switches.

dspic: was the latency that high?

They run at 140 MHz (70 MIPS) but flash is the same speed, so it takes 4 or 5 cycles to fetch something from the flash. It needs to fetch the vector and then fetch the first instruction. Hence the latency.

Title: Re: techniques for writing non blocking code
Post by: legacy on August 07, 2017, 03:59:36 pm
let them try to define or impose on our reality with their own reality, its quite amusing watching from here. for us, their theories seems or sounds plausible yet confusing in multitude grade of levels, but above all, unproven or in another simpler word... nonsense... from a simple switch non blocking single cored code to multicores, parallelism, resources sharing, priority inversion, real time, ecosystem and whatever sheets thats going to be arised next... afaik most of those terms are very well defined and known since before our birth or probably since the invention of Babbage machine, then here they are come up with probably their own delusional meaning in this ever growing thread, just like the fate of the other threads.. the first rule of thumb is, when the slightest correlation between a noob thread and programming, you'll see long winded people with long winded theory try promoting this and that and how unholy C/C++ is... dont you ever try to correct the path to the laymen ship otherwise you'll be dragged away with all these confusing theories and will be doomed to look just like a fool... well... weekend is over... the fuck with the theories, we only care about practical and workable codes. we harness machines to do our jobs, not the other way around...

I have only read the first line and thought that it seems a baby who cries if someone points him on a different way to kick the ball. Do as you want, man. Never imposed anything. I have simply contributed with the hope that hearing our (avionics) experience was useful.

Wasn't? Have a basket of power-cords alone.
Title: Re: techniques for writing non blocking code
Post by: legacy on August 07, 2017, 04:04:10 pm
Personally I'm more interested in, for lack of a better term, the philosophy rather than a specific implementation of the philosophy.

Hence my being "satisfied" by xCORE+xC.

Yup. Thought it can be useful for those want to see the fpga-implementation, and the only way is reading HDL source  :-//
Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 07, 2017, 04:07:31 pm
How many times can they do that without restoring?

PIC16 has only one interrupt level, hence one shadow set. PIC18 K42 has two interrupt levels, so it has two shadow sets.

Being able to save and restore the entire register set is nice but what I usually do is rely on the ISR to save *only* the registers that it is going to use to save time which is neatly undone with a RTOS that lacks knowledge of which registers those are.

If it stores them all automatically without taking any extra time, you don't need to work on deciding what to save and what not.

Maybe if that matters, you should be using a faster processor.

What faster processor would you suggest which would give you 125 ns interrupt latency?
Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 07, 2017, 04:24:35 pm
In particular I agree with the concept that for very simple applications you can use many techniques. However, such techniques aren't necessarily scalable to larger and/or more complex applications. I believe it is important that people understand that.

Any project has some level of complexity. You cannot make your project less complex than it is. You can, however, make it as simple as possible (but not simpler than that Einstein says). The simplest possible solution has more chances of being developed faster and cheaper and also has better chance of being scalable and maintainable.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 07, 2017, 04:40:45 pm
Maybe if that matters, you should be using a faster processor.
What faster processor would you suggest which would give you 125 ns interrupt latency?

Well, one of these (https://www.digikey.co.uk/product-detail/en/xmos/XEF232-1024-FB374-C40/880-1107-ND/5358020) 4000MIPS (£25 unit price) processors will deal with up to 32 "interrupts" simultaneously within <100ns :) If you want more, then you can add extra processor ICs at the cost of a little latency.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 07, 2017, 04:49:56 pm
In particular I agree with the concept that for very simple applications you can use many techniques. However, such techniques aren't necessarily scalable to larger and/or more complex applications. I believe it is important that people understand that.

Any project has some level of complexity. You cannot make your project less complex than it is. You can, however, make it as simple as possible (but not simpler than that Einstein says). The simplest possible solution has more chances of being developed faster and cheaper and also has better chance of being scalable and maintainable.

I'm happy for people to suggest simple techniques and to note that they are limited to simple small applications. That's reasonable and valid.

I'm not happy for people to suggest such techniques and omit to mention that they aren't scaleable to interesting applications (interesting = non-trivial or complex or large). Any such omissions suggest a lack of experience/knowledge, and will probably mislead the inexperienced.
Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 07, 2017, 05:13:43 pm
I'm happy for people to suggest simple techniques and to note that they are limited to simple small applications. That's reasonable and valid.

I'm not happy for people to suggest such techniques and omit to mention that they aren't scaleable to interesting applications (interesting = non-trivial or complex or large). Any such omissions suggest a lack of experience/knowledge, and will probably mislead the inexperienced.

You really need to clarify what techniques you're talking about and what interesting applications your have in mind. Otherwise, it just doesn't make any sense.

So far we've seen 15MHz frequency counter on $30 MCU which you have built in just two days. This doesn't sound very interesting. Anyone can build 50MHz frequency counter with 60-cent PIC12F1501, and I cannot see how this can possibly take more than two hours.
Title: Re: techniques for writing non blocking code
Post by: Mechatrommer on August 07, 2017, 06:03:56 pm
his counter is scalable allright... a professor trying to teach 5 yrs old kids quantum mechanics, the kid may not come across this subject in his entire life ever, he just like to play music, and the proffesor keep giving hints that music is not good. not that quantum mechanic is not good, its just its not in the right place... btw, latency sometime is not applicable to some applications. no pun and no offense intended, i just find it amusing how some people took some subjects too seriously... i assume the OP has already found solution to his problem, so... there is no stopping rule from ever expanding this basic thread anyway...
Title: Re: techniques for writing non blocking code
Post by: David Hess on August 07, 2017, 06:25:24 pm
Maybe if that matters, you should be using a faster processor.

What faster processor would you suggest which would give you 125 ns interrupt latency?

Solder and discrete logic.  :) Or some programmable logic if you must.

PICs and similar microcontrollers are so inexpensive that there is some advantage to using them for single tasks instead of aggregating everything into one larger processor or FPGA allowing optimum interrupt latency.  A small package can be deployed close to the interface not to lower latency but to ease layout considerations.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 07, 2017, 06:43:09 pm
I'm happy for people to suggest simple techniques and to note that they are limited to simple small applications. That's reasonable and valid.

I'm not happy for people to suggest such techniques and omit to mention that they aren't scaleable to interesting applications (interesting = non-trivial or complex or large). Any such omissions suggest a lack of experience/knowledge, and will probably mislead the inexperienced.

You really need to clarify what techniques you're talking about and what interesting applications your have in mind. Otherwise, it just doesn't make any sense.

So far we've seen 15MHz frequency counter on $30 MCU which you have built in just two days. This doesn't sound very interesting. Anyone can build 50MHz frequency counter with 60-cent PIC16F1501, and I cannot see how this can possibly take more than two hours.

Advancing strawman arguments doesn't make you look good. The frequency counter was a trivial kick-the-tyres exercise to see if the tools lived up to their claims (they did).

I've mentioned various techniques in other posts; I suggest you re-read them. I'm not going to waste my life repeating them to people with a short attention span.
Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 07, 2017, 07:06:14 pm
I'm not happy for people to suggest such techniques and omit to mention that they aren't scaleable to interesting applications (interesting = non-trivial or complex or large). Any such omissions suggest a lack of experience/knowledge, and will probably mislead the inexperienced.

You really need to clarify what techniques you're talking about and what interesting applications your have in mind. Otherwise, it just doesn't make any sense.

I've mentioned various techniques in other posts; I suggest you re-read them. I'm not going to waste my life repeating them to people with a short attention span.

I don't really understand whether all of the techniques you mentioned in your 5226 posts are not scalable, or only some of them are not scalable? And if some of the techniques mentioned in your posts are not scalable and you omitted to disclose this, does it "suggest a lack of experience/knowledge, and will probably mislead the inexperienced"?
Title: Re: techniques for writing non blocking code
Post by: nctnico on August 07, 2017, 07:21:39 pm
^ This what I was thinking. Who cares if it automatically saves registers? Newer 8 bit PIC have automatic context saving. Older ones don't. Only difference to me is 6 lines of assembly, 3 in the beginning of ISR and 3 at the end. This is pretty much saying "new model has 6 extra words of instructions and 3 extra bytes of memory compared to older model." You can also conisder those resources are automaticallly reserved for isr, which deprives the user in case he didnt need them for ISR. This is nice to the programmer but not an actual improvement in specs.

If it did this in parallel to core processor which reduces latency, then that's different.

PICs don't use extra cycles to store registers. They're stored automatically and restored back automatically. This is all done in hardware at the very moment the interrupt is taken. No single cycle is added.

PIC16F1* stores 8 different registers, which saves 16 instructions at the beginning of the ISR, which gives you 2 cycle latency (250 ns, or 166 ns on PIC16F14* which can use 48MHz clock). If you would do savings manually, it would give you 18 cycle latency - 4.5 us (plus 16 cycles when you leave the interrupt). 4.5 us is way bigger latency than 250 ns, so the auto-save is very important - it lets you achieve much higher performance.
But -correct me if I'm wrong- it makes having nested interrupts much harder because you'll need to save the context of the previous interrupt. The ARM7TDMI cpu core also has shadow registers but doing nested interrupts takes a lot of extra assembly. The ARM Cortex-M OTOH does need extra cycles at the beginning of the interrupt but it can deal with several interrupts at once without restoring the context in between and it can do nested interrupts as well. All in all that makes it a whole lot more flexible then having a set of shadow registers. Sure the latency is longer but who cares if you have peripherals with FIFOs and/or DMA capability (which in the end have better realtime performance than you can even achieve using software especially with multiple high priority tasks).
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 07, 2017, 07:43:19 pm
I'm happy for people to suggest simple techniques and to note that they are limited to simple small applications. That's reasonable and valid.

I'm not happy for people to suggest such techniques and omit to mention that they aren't scaleable to interesting applications (interesting = non-trivial or complex or large). Any such omissions suggest a lack of experience/knowledge, and will probably mislead the inexperienced.

You really need to clarify what techniques you're talking about and what interesting applications your have in mind. Otherwise, it just doesn't make any sense.

So far we've seen 15MHz frequency counter on $30 MCU which you have built in just two days. This doesn't sound very interesting. Anyone can build 50MHz frequency counter with 60-cent PIC16F1501, and I cannot see how this can possibly take more than two hours.

Advancing strawman arguments doesn't make you look good. The frequency counter was a trivial kick-the-tyres exercise to see if the tools lived up to their claims (they did).

I've mentioned various techniques in other posts; I suggest you re-read them. I'm not going to waste my life repeating them to people with a short attention span.

I omitted to mention "interesting" applications, because I was wondering how to get the concepts over to someone that, presumably, has yet to encounter them.

"Interesting" applications are legion; there's no way to begin listing them. Instead consider some characteristics (from systems/applications I've developed) which frequently hint an application is non-trivial:
And if I thought for a little while longer, I'm sure I could add to that list.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 07, 2017, 07:49:12 pm
I'm not happy for people to suggest such techniques and omit to mention that they aren't scaleable to interesting applications (interesting = non-trivial or complex or large). Any such omissions suggest a lack of experience/knowledge, and will probably mislead the inexperienced.

You really need to clarify what techniques you're talking about and what interesting applications your have in mind. Otherwise, it just doesn't make any sense.

I've mentioned various techniques in other posts; I suggest you re-read them. I'm not going to waste my life repeating them to people with a short attention span.

I don't really understand whether all of the techniques you mentioned in your 5226 posts are not scalable, or only some of them are not scalable? And if some of the techniques mentioned in your posts are not scalable and you omitted to disclose this, does it "suggest a lack of experience/knowledge, and will probably mislead the inexperienced"?

All you have to do is look at my earlier postings in this thread. That's not too difficult is it?
Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 07, 2017, 08:02:23 pm
But -correct me if I'm wrong- it makes having nested interrupts much harder because you'll need to save the context of the previous interrupt. The ARM7TDMI cpu core also has context switching but doing nested interrupts takes a lot of extra assembly. The ARM Cortex-M OTOH does need extra cycles at the beginning of the interrupt but it can deal with several interrupts at once without restoring the context in between and it can do nested interrupts as well. All in all that makes it a whole lot more flexible then having a set of shadow registers. Sure the latency is longer but who cares if you have peripherals with FIFOs and/or DMA capability (which in the end have better realtime performance than you can even achieve using software especially with multiple high priority tasks).

PIC16 doesn't have nested interrupts. Theoretically, you can do it in software, but it is so inefficient that it certainly isn't worth it.

PIC18 has two levels of interrupt, high priority and low priority. Correspondingly, K42 has two sets of shadow registers. If a low priority interrupt happens, it saves the context into the shadow register set designated for low priority interrupt. If a high priority interrupt happens, it saves the context into its own set of shadow registers. The nesting is completely seamless. High priority interrupts don't feel any delays from low priority interrupts being executed.

PIC24/dsPIC33 have 7 levels of interrupts, but don't have so many register sets. You have to select which interrupt levels get shadow registers and which don't. But the nesting is still seamless - higher priority interrupts can pre-empt lower priority interrupts at any time - no extra assembler is necessary to ensure this.

Older PIC32s (MIPS) required some quite extensive code at the beginning of the interrupt before it could enable the interrupts back, which would hurt latency dramatically. In PIC32MZ and PIC32MK, they switched to microAptiv MIPS. It appears that it has processor ASE extensions which are supposed to fix this and make nested interrupts quicker, but the C compiler doesn't seem to support this yet. When such support is added, they promise 50ns latency, but I haven't looked into this in details. The microAptiv core has several sets of shadow registers too.

Of course, this all is mostly to decrease the latency. If the latency doesn't matter for the application then the shadow registers are not as important - everything can be saved/restored by software just as well (C will generate the code).

Title: Re: techniques for writing non blocking code
Post by: NorthGuy on August 07, 2017, 08:13:27 pm
I omitted to mention "interesting" applications, because I was wondering how to get the concepts over to someone that, presumably, has yet to encounter them.

"Interesting" applications are legion; there's no way to begin listing them. Instead consider some characteristics (from systems/applications I've developed) which frequently hint an application is non-trivial:
  • a need for formal validation and verification processes
  • a bug costs a year's salary, and/or the re-spin latency is measured in agricultural seasons
  • someone gets hurt if it fails; worse, someone dies when it works as designed
  • remote operation in unattended buildings that you don't have key access to
  • high availability, where parts of the system will fail in normal operation, and the system must continue to function 24/7
  • development teams split across continents
  • development teams split across companies
  • customers that throw chairs at FSEs when the product doesn't work as they were expecting
  • there is a probability that during commissioning different companies will attempt to shift blame onto other companies, and their lawyers are ready and waiting
  • enhancements will be made over many years, and the development team has departed for pastures new
And if I thought for a little while longer, I'm sure I could add to that list.

Like this: https://gizmodo.com/the-f-35-amazingly-has-even-more-problems-than-we-thoug-1791285476

Such applications could be interesting technically, but there's a pale cast of government bureaucracy, high politics, special interests etc. But of course, the same laws of physics apply to these too. It's all top secret, so it's hard to tell what methods they're using, but whatever they're doing doesn't seem to be working very well.
Title: Re: techniques for writing non blocking code
Post by: KL27x on August 07, 2017, 09:19:03 pm
Quote
PIC16 doesn't have nested interrupts. Theoretically, you can do it in software, but it is so inefficient that it certainly isn't worth it.
If some of your ISR are very long, you can put periodic checks in them at convenient locations to check flag and have them CALL other ISRs. This doesn't result in an instant response, so adds some variable delay. And it only works if you are careful to identify and sort out any memory conflicts. The memory conflicts are not necessarily overwhelming. It depends on what the ISR's are doing. They might be completely unrelated and/or use not much memory. This would be unusual situation perhaps, and you won't get nanosecond latency, of course. Unless you were doing this check/poll at super high speed in a "dead delay" such as waiting for ADC pin to stabilize(Leave it to imagination why you would be doing this in an ISR, but I've done ADC read in ISR, yeah).

I normally write my ISR as series of subroutines called by the main ISR in series, anyway. If one were to be called by other ISR, it is self-contained. If/when it gets called again in the main ISR, it will be serviced, already, and the ISR will move on to the next in line, down the checklist.

Unless you have a single interrupt in any given priority level, first thing ISR has to do is check if it is enabled and triggered, anyhow. Theoretical minimum latency based on hardware is only going to be achievable in this scenario. Using PIC with single interrupt priority level this is a rare luxury.

Back to topic, though: I think EE's and hobbyists have more varied interest than just ballistic missile guidance systems. I agree to some extent that as you work with more complex device and tools, it rarely makes sense to go back to more basic strategy/tools. If you can do the job with 100x more memory and transistors and multiple layers of software, why "relearn" how to do it more directly? You have worked so hard to learn the "best" way to do things with the complex tools and devices. But when you mention bugs which take years to sort, maybe it's partly because you are relying on all these layers for too many things... We landed people on the moon without 32 bit microprocessors and fancy compilers.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 07, 2017, 09:51:52 pm
Quote
PIC16 doesn't have nested interrupts. Theoretically, you can do it in software, but it is so inefficient that it certainly isn't worth it.
If some of your ISR are very long,...

If your ISRs are very long, then you are "Doing Something Very Wrong"TM.

An ISR should
Title: Re: techniques for writing non blocking code
Post by: KL27x on August 07, 2017, 10:20:24 pm
Tggzzz. Let me guess. Are you by any chance a senior level engineer who manages a bunch of immigrant programmers who write all the code, and you spend 90% of your time learning ways to make them feel inferior and otherwise boosting your perceived value to the guy writing the checks? I'm not gonna say this isn't an important job. My GF is incredibly productive. She gets more done in a day than I do in a month. But her primary mode of getting things done is to pick up the phone and convince other people into doing things.

There are many instances where you might want to do things in the ISR. One of the main purposes, for example, for one of my project is to get 2 ADC reads from single randomly triggered signals but which must happen in a small microsecond window. In this case, it is easier to put the ADC acquisition time in the ISR and has no significant detriment to the rest of the code. Yes, I could have done ADC acquisition delay as a timer interrupt. But this was not a necessary complication. I could have even dedicated a micro just to get these reads and have the master request this data at its leisure. But it was not necessary.

As I said this is unusual situation where you might want to do this. If all your ISR is super short, then priority doesn't matter anyway, does it? They all get done in plenty of time, since they only take a few instructions cycles to complete.

Microcontrollers are not necessarily needing to calculate ballistic trajectory in nanoseconds with floating point math. And for someone so concerned with bugs, you seem to miss the forest for the trees.

If you want to treat your coders as disposable, then yes. It is better for them to follow your mandate to the letter, despite all the other problems and inefficiencies it may cause. You can dictate what hardware and ide they must use and how to write the code to the letter. This way you can fire them and plug in another brown/yellow engineer and continue with your bug ridden, bloated, overbudget project (sometimes this ends up the best or only solution, for complexity and/or security reason,  but as engineers we don't have to LIKE it; and I bet a heck of a lot of the visitors/participants on this forum are doing one man projects as the norm). But if you have coder you can depend on to do the project start to finish and support/maintenance, following strict mandate with no room for change may not be the best way to go. Believe it or not, he may have a better way to get it done. Sometimes exceptions to the rule can have more pros than cons.
Title: Re: techniques for writing non blocking code
Post by: Sal Ammoniac on August 07, 2017, 11:10:43 pm
What the hell is "programming ecosystem"?

It's just another of those hipster terms like code smells, refactoring, and technical debt. Why use simple language when you can embellish it and make it sound grandiose?
Title: Re: techniques for writing non blocking code
Post by: Sal Ammoniac on August 07, 2017, 11:22:45 pm
Context switches with hard floating point can get pretty expensive because the floating point registers have to be saved/restored too.

The Cortex-M4 and M7 have a feature called lazy stacking. If the outgoing task didn't use the FPU (as indicated by a bit in the link register), the context switch code doesn't need to save the floating point registers.
Title: Re: techniques for writing non blocking code
Post by: andyturk on August 08, 2017, 12:25:19 am
The Cortex-M4 and M7 have a feature called lazy stacking. If the outgoing task didn't use the FPU (as indicated by a bit in the link register), the context switch code doesn't need to save the floating point registers.

 :-+

I think it still adjusts the stack pointer as if they were saved, right?
Title: Re: techniques for writing non blocking code
Post by: Sal Ammoniac on August 08, 2017, 12:31:47 am
The Cortex-M4 and M7 have a feature called lazy stacking. If the outgoing task didn't use the FPU (as indicated by a bit in the link register), the context switch code doesn't need to save the floating point registers.

 :-+

I think it still adjusts the stack pointer as if they were saved, right?

Yes. It reserves space on the stack whether it saves anything or not.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 08, 2017, 06:30:37 am
Tggzzz. Let me guess. Are you by any chance a senior level engineer who manages a bunch of immigrant programmers who write all the code, and you spend 90% of your time learning ways to make them feel inferior and otherwise boosting your perceived value to the guy writing the checks?

Nope, completely and 100% off-beam; a fantasy.

In my mid-20s in a contract r&D house I tested whether or not I was interested in technical management and business. I decided I wasn't, and studiously avoided climbing that ladder. Instead I spent the largest part of my career doing hardcore engineering in the R&d part of a large company, surrounded by extremely competent engineers distributed across the world.

I saw one (new) employee attempt to boost our self respect by claiming we were better than other parts of the company; that was exquisitely embarrassing and they were shown the door very quickly.

Quote
There are many instances where you might want to do things in the ISR. One of the main purposes, for example, for one of my project is to get 2 ADC reads from single randomly triggered signals but which must happen in a small microsecond window. In this case, it is easier to put the ADC acquisition time in the ISR and has no significant detriment to the rest of the code. Yes, I could have done ADC acquisition delay as a timer interrupt. But this was not a necessary complication. I could have even dedicated a micro just to get these reads and have the master request this data at its leisure. But it was not necessary.

Well, that isn't a long time, and the ADC readings are the necessary context, so I don't see any relevance to what I wrote.

For the avoidance of doubt, the context you decided to snip was that you wrote "If some of your ISR are very long,...". My statements were in that context, and they stand.

Quote
As I said this is unusual situation where you might want to do this. If all your ISR is super short, then priority doesn't matter anyway, does it? They all get done in plenty of time, since they only take a few instructions cycles to complete.

It wouldn't matter how long/short it was if the system jammed due to priority inversion - in which case priority would definitely matter.

Quote
If you want to treat your coders as disposable, then yes. It is better for them to follow your mandate to the letter, despite all the other problems and inefficiencies it may cause. You can dictate what hardware and ide they must use and how to write the code to the letter. This way you can fire them and plug in another brown/yellow engineer and continue with your bug ridden, bloated, overbudget project (sometimes this ends up the best or only solution, for complexity and/or security reason,  but as engineers we don't have to LIKE it; and I bet a heck of a lot of the visitors/participants on this forum are doing one man projects as the norm). But if you have coder you can depend on to do the project start to finish and support/maintenance, following strict mandate with no room for change may not be the best way to go. Believe it or not, he may have a better way to get it done. Sometimes exceptions to the rule can have more pros than cons.

That's an irrelevant strawman rant.
Title: Re: techniques for writing non blocking code
Post by: KL27x on August 08, 2017, 08:33:35 am
Quote
Well, that isn't a long time, and the ADC readings are the necessary context, so I don't see any relevance to what I wrote.
Quote
For the avoidance of doubt, the context you decided to snip was that you wrote "If some of your ISR are very long,...". My statements were in that context, and they stand.
"Very long" is relative. If it's long enough that you may want to prioritize other interrupt, then it is "very long." If I'm burning potentially a hundred instruction cycles just waiting for ADC cap to stabilize after switching the pin MUX, that might be considered long. We were just discussing how micro X has 125nS latency by virtue of saving registers by hardware, were we not? And by virtue of you recognizing that this "isn't very long" but that I consider it as potentially being "very long," why you feel need to lecture me by saying I AM DOING SOMETHING VERY WRONG!? But for sake of argument, who cares if ISR takes even 5 minutes, if it serves the purpose?

My point was that while waiting for cap to stabilize, I could potentially do software prioritization of higher interrupt by polling (or I could divide the ADC ISR into 2 and finish it with a timer interrupt). This was reply to preceeding post about how software prioritization of ISR is difficult. I contend that it can be very easy, given certain conditions, namely lack of memory conflict. At least it is very easy in assembly. ISR organization/flow/prioritization seems to be one place where assembly can be easier. I find it very hard to understand how ISR is organized in C, not that I'm very good with the language.

Quote
It wouldn't matter how long/short it was if the system jammed due to priority inversion - in which case priority would definitely matter.

If priority inversion causes bug (for example someone brought up the Mar's Rover, where the bug was, IIUC, that a lower priority interrupt never finished if it was interrupted), then presumably some of the interrupts ARE relatively long. Prioritizing interrupts obviously takes some extra code and memory and uses up stack and creates potential for RARELY SEEN BUG.* In the Mars Rover case, who knows how bad the screwup was? It could have been complete and utter laziness. Giving it a fancy name doesn't mean it wasn't necessarily a grievously stupid oversight. Maybe device's hardware interrupt priority failed. Maybe compiler had error. Or maybe some dumbass did software prioritization and forget that he was pusing the stack. And if ISRs are all very short, you can just NOT do it.

Quote
That's an irrelevant strawman rant.
What I should have meant was a metaphorical "you." Or "one." I got carried away, and I apologize, Tggzzzz, because I see why you would have taken that personally.

*This seems to be one of your many issues with interrupts. But I don't understand why this can't be tested. You can create this condition on demand with testing setup. Sure, it takes some work, but what doesn't?
Title: Re: techniques for writing non blocking code
Post by: nctnico on August 08, 2017, 08:41:15 am
Quote
PIC16 doesn't have nested interrupts. Theoretically, you can do it in software, but it is so inefficient that it certainly isn't worth it.
If some of your ISR are very long,...

If your ISRs are very long, then you are "Doing Something Very Wrong"TM.

An ISR should
  • determine the source of the interrupt
  • gather neccessary context
  • create an Event containing the necessary context
  • submit that Event for consumption and processing by a background task/thread/process, probably via a FIFO or mailbox
  • and exit the ISR A.S.A.P.
Utter nonsense! There are two reasons for this: shuffling data around in events & buffers means extra overhead and it puts unnecessary timing requirements on the rest of the software which complicates things a lot (*). It really is much better to process everything inside an interrupt and use nested interrupts to perform higher priority tasks if necessary. You need to look at an interrupt controller as an OS time slicer in hardware. This keeps things simple because the time critical stuff stays in a small area.

Ofcourse all bets are off if you need to handle bursts of data but even then it may be better to use a timer interrupt for processing chunks of data at regular intervals so the timing requirements don't not leak into a slow (housekeeping) main loop.
Title: Re: techniques for writing non blocking code
Post by: legacy on August 08, 2017, 09:13:16 am
they were shown the door very quickly

I frankly appreciate a lot when you talk, your English sounds so elegant that I find it a pleasure to read, but I also appreciate the concept you expose since I work in avionics and we have a lot of problems in common.

I like it, because usually people in avionics don't like to talk for free, courses and the business of giving expert advice to other professionals, typically in financial and business matters, all of these things cost a lot of money as well a full training costs a lot of time.

Something like K euro. May be your boss pay it for you, may be not, may be you are a person who works freelance, thus it's all on your wallet *IF* your can invest money on it.

Someone here simply assumes that he/she can access everything everytime everywhere for free. Like when he/she clones a git repository in a couple of seconds. That's the problem of "opensource" which always introduce a distorted prospect of the reality, because of course, these kind of people believe they can access concept online, thus they have no respect when someone has the intention to talk.

The problem of modern computer science is also that even a nogooder can access internet and claim that he/she can programs something. It should be proved, in first place. I see Km of fsking garbage online.

But who cares? I am not interested to have the proof of expert skill and knowledge in a particular field from people in the topic, not interested in showing any supremacy about who is allowed to talk, and who should shut the fsking, but!

But I can't ignore that someone here comes from a more relaxed area, like Home automation, where you have light constraints and requirements to be respected in your code and you are 100% guaranteed that nobody will ever die even if you write poor quality code: never thought that these kind of people have ever felt the forum talk on mission critical field as the quality of being arrogantly superior and disdainful against them.

Thus, let me summarize: you spend your coffee-break time contributing on things that usually kept in-doors, therefore cost money on courses and consulting, and  people believe that it's a manifest of your arrogantly superior.

Does it make sense? For me, they can have shown the door very quickly.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 08, 2017, 09:21:59 am
Quote
It wouldn't matter how long/short it was if the system jammed due to priority inversion - in which case priority would definitely matter.

If priority inversion causes bug (for example someone brought up the Mar's Rover, where the bug was, IIUC, that a lower priority interrupt never finished if it was interrupted), then presumably some of the interrupts ARE relatively long. Prioritizing interrupts obviously takes some extra code and memory and uses up stack and creates potential for RARELY SEEN BUG.* In the Mars Rover case, who knows how bad the screwup was? It could have been complete and utter laziness. Giving it a fancy name doesn't mean it wasn't necessarily a grievously stupid oversight. And if ISRs are all very short, you can just NOT do it.

Clearly you don't understand what priority inversion is, its causes, and its cures.

Quote
Quote
That's an irrelevant strawman rant.
What I should have meant was a metaphorical "you." Or "one." I got carried away, and I apologize, Tggzzzz.

No problem; I didn't take it personally :)

Quote
*This seems to be one of your many issues with interrupts. But I don't understand why this can't be tested. You can create this on demand with testing setup. Sure, it takes some work, but what doesn't?

It isn't my issue with interrupts; it is a well-recognised problematic characteristic.

You shouldn't feel bad that "...I don't understand why this can't be tested" - nobody understands how to adequately test that! Actually it is worse - people understand why you cannot do such tests.

Testing cannot be done for several reasons:

You have to adopt implementation strategies that avoid typical common problems in the first place.
Title: Re: techniques for writing non blocking code
Post by: tggzzz on August 08, 2017, 09:41:43 am
they were shown the door very quickly
I frankly appreciate a lot when you talk, your English sounds so elegant that I find it a pleasure to read, but I also appreciate the concept you expose since I work in avionics and we have a lot of problems in common.

Thanks; I try :) I also try to spot weaknesses in what I've done and to figure out how I would avoid them in practice.

Quote
Someone here simply assumes that he/she can access everything everytime everywhere for free. Like when he/she clones a git repository in a couple of seconds. That's the problem of "opensource" which always introduce a distorted prospect of the reality, because of course, these kind of people believe they can access concept online, thus they have no respect when someone has the intention to talk.

The problem of modern computer science is also that even a nogooder can access internet and claim that he/she can programs something. It should be proved, in first place. I see Km of fsking garbage online.

Yes and yes. Some people should be physically prevented from touching a keyboard or soldering iron!

Quote
But I can't ignore that someone here comes from a more relaxed area, like Home automation, where you have light constraints and requirements to be respected in your code and you are 100% guaranteed that nobody will ever die even if you write poor quality code: never thought that these kind of people have ever felt the forum talk on mission critical field as the quality of being arrogantly superior and disdainful against them.

Even home automation isn't as simple and safe as people seem to imagine.
Consider remotely turning a fridge off for a day, then turning it back on. The food might have become dangerous, which isn't too bad if it is obviously dangerous.
Consider remotely starting the heating and setting the thermostat to maximum; pets might get heatstroke.
Consider remotely turning off heating and setting the thermostat to minimum; water pipes freeze, then burst, and the water causes electrical fires.
Consider publishing the electricity consumption, so that a burglar can predict when the house is occupied.
Consider using a webcam to remotely spy on the inhabitants.
Consider suboptimal security, so that a device is pwned and becomes an attack vector for other devices in the home.

Note that some of those aren't only theoretical; they have been seen in the wild.

Quote
Thus, let me summarize: you spend your coffee-break time contributing on things that usually kept in-doors, therefore cost money on courses and consulting, and  people believe that it's a manifest of your arrogantly superior.

Does it make sense? For me, they can have shown the door very quickly.

I'm probably retired, so I have more than a coffee break!

I also like helping youngsters improve and make new mistakes. OTOH, I hate unnecessarily repeating old mistakes.

I've also seen many problems (and created a few myself :( ), and so I'm often a step ahead of those with less experience. Been there, done that, got the T-shirt.
Title: Re: techniques for writing non blocking code
Post by: Kalvin on August 08, 2017, 09:54:44 am
Nested interrupts are quite handy if you want to make "long interrupt handlers" and your system tolerates nested interrupts (ie. interrupts may be interrupted). The main program context will be run at the main() context. There may be some interrupt-driven activity like ADC-reading which may contain some delays, thus creating "long interrupt handler". At a higher interrupt priority level there may be a timer tick which may perform some periodic activity above all other processes/tasks. It is just a matter of systems engineering and architecture design how you implement the system. There is no single right way of doing things, although there are numerous ways of doing things wrong.
Title: Re: techniques for writing non blocking code
Post by: KL27x on August 08, 2017, 10:10:38 am
Edited:

Tggzzz, I am sorry I brought up Mars Rover and priority inversion, but feel free to continue the lecture. All I was initially discussing were the use of interrupts in an 8 bit PIC.

You suggest that my consideration for length of ISR is evidence I don't know what I'm even talking about. You state flatly that the length of ISR must be short. But even if it is short or long, it doesn't matter when considering whether or not and/or how you prioritize them (thru hardware or software). But I don't see your reasoning.

The way I see it:
If ISR are all relatively short, you would NOT HAVE TO PRIORITIZE or NEST the INTERRUPTS to begin with. They will all get done sequentially, and none will have to be interrupted, themselves. If one is relatively long, you might consider interrupting it with a technically lower importance interrupt which is both very brief and which can't repeat within timeframe of the longer one. I don't know why you bring FSM and event driven code and RTOS into it in the first place. I wasn't part of that discussion, but it seems impossible to avoid when you are in the thread. You see things only thru lens of event driven code and xCORE. I wish I would learn something useful when you "correct me." It almost seems possible.
Title: Re: techniques for writing non blocking code
Post by: legacy on August 08, 2017, 10:15:51 am
Nested interrupts are quite handy

In avionics, we are usually not allowed to use nested interrupts. In this moment I am writing the final report (hopefully the last one before vacation), and I have to spend time on a specific set of test cases whose meaning is: assuring that the firmware inside the fly-board doesn't use nested-interrupt since it's a low-level requisite committed by the final user.

It's easy, you have to show a few points in the source code, but mind the point: they don't want nested interrupts used, and they are paying guys to check it.

Funny, ain't it :D ?

(it's my turn, because other people is already on vacation)
Title: Re: techniques for writing non blocking code
Post by: Kalvin on August 08, 2017, 10:34:51 am
Nested interrupts are quite handy

In avionics, we are usually not allowed to use nested interrupts. In this moment I am writing the final report (hopefully the last one before vacation), and I have to spend time on a specific set of test cases whose meaning is: assuring that the firmware inside the fly-board doesn't use nested-interrupt since it's a low-level requisite committed by the final user.

It is all about systems requirements. Using nested interrupts may or may not be suitable/allowed. Using interrupts may or may not be suitable/allowed. It all depends on the requirements.
Title: Re: techniques for writing non blocking code
Post by: Mechatrommer on August 08, 2017, 12:01:44 pm
Nested interrupts are quite handy
In avionics, we are usually not allowed to use nested interrupts.
here, in not avionics, we are allowed.

Title: Re: techniques for writing non blocking code
Post by: KL27x on August 08, 2017, 12:58:23 pm
When something has to explicitly disallowed, it is usually useful. If they do it in a 4mph rc moon car, it must be good.
Title: Re: techniques for writing non blocking code
Post by: nctnico on August 08, 2017, 01:08:39 pm
When something has to explicitly disallowed, it is usually useful.
Usually it is to prevent rookie mistakes but look how the MISRA rules have evolved over the past decades.
Title: Re: techniques for writing non blocking code
Post by: KL27x on August 08, 2017, 11:50:15 pm
I have been motivated to go back and read some of the previous posts. Namely because certain person has annoyed me.

Quote
Quote
If you have only one CPU, it is absolutely impossible for these two tasks to run at the same time. What you can do about this? You can run task A. This increases the latency of task B, and it is no longer equal to interrupt latency, but is equal  to (interrupt latency + time to do the minimum processing for task A). Or, you can run task B, then the latency of task A will not be zero any longer, but will be equal to the time necessary to do some minimum processing for task B. If neither of these meets your timing requirements, nothing you can do. This is interference caused by multitasking. A can be served alone, B can be served alone, but A and B together cannot.




Not necessarily: providing constraints are met, interference can be absent. Meeting constraints can be aided/prevented by appropriate hardware+software mechanisms.
How in the world do you refute this with "not necessarily." NorthGuy has stated a concrete scenario. Single processor. Two external inputs requiring immediate action. Nowhere do I see NorthGuy state that either event can be logged as future event to be processed later.

Adding to that, perhaps some explanation of how xCORE responds to 8 external random events at a time within 100nS, without having any interrupts, can be offered.
Quote
The XS1 architecture is event-driven. It has an instruction that can dispatch an external events in addition to traditional interrupts. If the program chooses to use events, then the underlying processor has to expect an event and wait in a specific place so that it can be handled synchronously. If desired, I/O can be handled asynchronously using interrupts. Events and interrupts can be used on any resource that the implementation supports.
Unless you dedicate a core to do nothing but poll for each input, you would have to use interrupts. Unless you can explain how it is possible plan events around an event which is random. So technically, yes, you can dedicate an entire cpu to something to remove need for an interrupt. I get that there's a benefit to this setup due to communication between cored and shared memory (also many drawbacks). But you can't have your cake and eat it, too.

Title: Re: techniques for writing non blocking code
Post by: nctnico on August 09, 2017, 06:53:28 am
The bottom line is: one processor can deal with one instruction at a time so you can't handle two (or more) interrupts (with equal priority) at exactly the same time. But this is turning into a semantic discussion anyway.
At the system design stage I make an analysis of the processor power required and latency requirements. Based on that I select the appropriate hardware and decide on what priorities each task gets. At this point I have not written a single line of code or created a new schematic for the final product.
Title: Re: techniques for writing non blocking code
Post by: Mechatrommer on August 09, 2017, 08:01:25 am
Based on that I select the appropriate hardware and decide on what priorities each task gets.
there are broad engineering and economic requirements that results in a very different hardware choices. in the narrow band highly safety priority of avionics there probably not much to choose, so they avionics people are locked to the very narrow band of techniques set. even in the mechanical aspects of avionics will entirely not be applicable to automotive industry, this will result in a car that 10-100X more expensive than they already are. so people from other industries need to be aware of this economical vs engineering facts.
Title: Re: techniques for writing non blocking code
Post by: MT on August 09, 2017, 01:22:31 pm
Anyhow i sometimes try to use DMA sequences to offload blocking situations, i wish ST could
have made their DMA engine abit clever by implementing some sort of a tiny programmable
sequenciator as to behave more like a very simple coprocessor.
Title: Re: techniques for writing non blocking code
Post by: andyturk on August 09, 2017, 04:41:53 pm
Anyhow i sometimes try to use DMA sequences to offload blocking situations, i wish ST could
have made their DMA engine abit clever by implementing some sort of a tiny programmable
sequenciator as to behave more like a very simple coprocessor.

You can do some tricky stuff with STM32 DMA when it's controlled by timers. The bigger timers can generate half a dozen different events that you can plumb into different DMA streams. Use one of those streams to reprogram the timer itself along the way for complex (and difficult to maintain) behavior.
Title: Re: techniques for writing non blocking code
Post by: David Hess on August 09, 2017, 05:46:51 pm
Anyhow i sometimes try to use DMA sequences to offload blocking situations, i wish ST could
have made their DMA engine abit clever by implementing some sort of a tiny programmable
sequenciator as to behave more like a very simple coprocessor.

I was very impressed with TI's solution which is available on the BeagleBone boards:

http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit_Subsystem (http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit_Subsystem)
Title: Re: techniques for writing non blocking code
Post by: MT on August 09, 2017, 08:14:22 pm
You can do some tricky stuff with STM32 DMA when it's controlled by timers. The bigger timers can generate half a dozen different events that you can plumb into different DMA streams. Use one of those streams to reprogram the timer itself along the way for complex (and difficult to maintain) behavior.

That's what i indirectly hinted about, an extension of ST implementation sort of , the problem with ST solutions is that the timers dont stretch beyond the timers and if one timer is used to cause multiple streams it eat DMA streams and still the whole thing is merely about shuffling data from one place to another. Still better to have it then not.

I was very impressed with TI's solution which is available on the BeagleBone boards:

http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit_Subsystem (http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit_Subsystem)

Thats interesting!