Author Topic: How to keep the user interface responsive?  (Read 17634 times)

0 Members and 1 Guest are viewing this topic.

Offline e100Topic starter

  • Frequent Contributor
  • **
  • Posts: 567
How to keep the user interface responsive?
« on: October 15, 2013, 12:51:29 pm »
I'm at the beginning of an embedded design for a flow meter which has a software loop with the following tasks:
  • Measure sensor value
  • Update display
  • Listen for communication from computer and send latest results
  • Process user input / update display
The user interface will probably use a rotary encoder with a push switch to move a cursor around a screen and enter data.
What's the normal way of capturing user input while the software is busy doing time critical tasks such as taking a measurement or sending data? Do you hook the input switches to an interrupt then set a flag that marks the interrupted measurement or communication operation as failed, then gracefully exit that section of code and jump to the user interface handler code?
Is there a better way?

Mike




 

Offline nowlan

  • Frequent Contributor
  • **
  • Posts: 649
  • Country: au
Re: How to keep the user interface responsive?
« Reply #1 on: October 15, 2013, 12:56:48 pm »
What is the platform?
Usually your mcu will have serial interrupt handler to manage communication.
The rotary encoder may be on another interrupt (lower priority), or you could just poll it.
I used to just read button during a main loop.
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: How to keep the user interface responsive?
« Reply #2 on: October 15, 2013, 12:59:29 pm »
It sounds like a lot of what you are doing can be done in the background while your code does other things. Just loop through all those tasks and service each one when data is available - don't wait on anything. If you must perform a long computation, use a state machine that performs it in pieces, one piece per loop iteration. Depending on how complex your task is, you may want to code up a simple cooperative task manager. And if your task is very computation-heavy, you might consider a larger microcontroller which can support a real-time system or perhaps an additional, small microcontroller to handle the interface.
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: How to keep the user interface responsive?
« Reply #3 on: October 15, 2013, 01:32:14 pm »
Quote
What's the normal way of capturing user input while the software is busy doing time critical tasks such as taking a measurement or sending data?

1. Use interrupts to capture inputs;
2. Use interrupts / hardware to send data;
3. Use dma, if available.
================================
https://dannyelectronics.wordpress.com/
 

Offline e100Topic starter

  • Frequent Contributor
  • **
  • Posts: 567
Re: How to keep the user interface responsive?
« Reply #4 on: October 15, 2013, 01:36:33 pm »
What is the platform?
It's a atmega328.
My main concern is not losing user input because there's nothing more annoying than having to press a button multiple times because the MCU wasn't ready to receive data.
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: How to keep the user interface responsive?
« Reply #5 on: October 15, 2013, 01:38:13 pm »
If your microcontroller, running at upwards of 20 MHz, is so busy it can't notice a button press lasting at least a handful of milliseconds, your code needs a serious overhaul.
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: How to keep the user interface responsive?
« Reply #6 on: October 15, 2013, 01:44:24 pm »
Quote
your code needs a serious overhaul.

It could be that he is doing long delays, or waiting for a slow peripheral to finish. Yes, I do think there is so much processing power for something like that to happen.
================================
https://dannyelectronics.wordpress.com/
 

Offline denizcan

  • Regular Contributor
  • *
  • Posts: 59
Re: How to keep the user interface responsive?
« Reply #7 on: October 15, 2013, 02:09:39 pm »
If you can use an operation system, it is easier. You may assign a task that scans the buttons. UI work on other task. And listens incoming messages (such as using mailbox) also updates the screen. Wait's are not done by loops, but really handled by OS.

But if this is beyond your aim, the responsiveness may be based on those:

1) UART communication is controlled by interrupt. If you are passing ASCII code, like terminal communication, you can buffer incoming and outgoing to free the main control loop waiting communication to complete.
2) Maim loop consists of state machines. In each state you do one thing. You do not introduce any wait loop. Delaying is made by a timer that ticks in periodic fashion, and a counter that tracks how long in that state the machine should stay..


for instance, the main loop shall like this:
Code: [Select]
while(1)
{
  processTimer();
  processUI();
  processButtons();
}

processTimer checks the timeout of the timer, and sets timerTick value to 1 if timeout happens, for just 1 loop.. that way you may increment each state machine's own timer..

suppose you are blinking a text, and processUI module is something like this:
Code: [Select]

void handleMainScreen()
{
  if (timerTick)
  {
    if (++flashCounter == 500)
    {
      flashState = !flashState;
      if (flashState)
        paintInverted();
      else
        paintNormal();
    }
  }
}

void processUI()
{
    switch (uiState)
    {
      case US_MAINSCREEN: handleMainScreen(); break;
      case US_SOMEVALUE: handleSomeValue(); break;
      ...
    }
}


As you see, there is no wait loop that prevents other parts of the program to hang.. Timing is done by "timerTick" variable, that is set for just one loop when periodic timeout (for instance in each 1ms) happens.. You may use same timerTick to check the buttons in processButtons function. Use simple filtering to prevent glitches etc..

It is a lot easier if you use OS though.. But it also has some learning curve and daemons in it aswell :)..
 

Offline Harvs

  • Super Contributor
  • ***
  • Posts: 1202
  • Country: au
Re: How to keep the user interface responsive?
« Reply #8 on: October 15, 2013, 02:11:15 pm »
If you can find yourself a cheap copy of this book, it's got some good basics for multitasking with small MCUs:
http://www.amazon.com/Embedded-Multitasking-Technology-Keith-Curtis/dp/0750679182
 

Offline Kjelt

  • Super Contributor
  • ***
  • Posts: 6460
  • Country: nl
Re: How to keep the user interface responsive?
« Reply #9 on: October 15, 2013, 02:19:03 pm »
As denizcan already said don't use a loop which does not guarantee that each event will be handled in time but write a simple scheduler.

You  measure the minimum interval each possible events (without interrupt) needs to be handled/checked/polled, the lowest will be your timertick base time the others are related to this.
Then measure the processing time for each task (best and worst case).
Then make the timing puzzle complete and see if your microcontroller can handle if all tasks are worst case and interrupts are handled.
Or write the program and measure and log the idle time of the microcontroller.
 

Offline Bored@Work

  • Super Contributor
  • ***
  • Posts: 3932
  • Country: 00
Re: How to keep the user interface responsive?
« Reply #10 on: October 15, 2013, 07:09:52 pm »
I can't remember if the MEGA series lets you clock timers using an external clock source,

Yes you can, but really ...

Clocking a Mega with 20 MHz gives you a lot of ompf. When we were young we used to code interactive computer games on 1 MHz machines. With one hand tied to the back. In winter. Uphill. No shoes. If you get the idea.

If you go, for example, for a screen update rate of 10 fps you have 100 ms per main loop iteration, or 2 000 000 CPU cycles per loop. Most (all?) ATMega instructions are single cycle. That is a lot of instructions you can execute  per loop iteration. In fact I wouldn't even start with 20 MHz CPU clock. The ATmegas default 8 MHz or 1 MHz is a good start.
I delete PMs unread. If you have something to say, say it in public.
For all else: Profile->[Modify Profile]Buddies/Ignore List->Edit Ignore List
 

Offline Kremmen

  • Super Contributor
  • ***
  • Posts: 1289
  • Country: fi
Re: How to keep the user interface responsive?
« Reply #11 on: October 15, 2013, 08:28:41 pm »
OK, is it my turn now?

What others have suggested will certainly work and i'm not saying you shouldn't do it that way. But, if it was me i would most likely grab a small real-time OS and use that. More specifically in this case, the FreeRTOS that will definitely work for a 328. Some will argue that it is overkill, but so what.
As i see it, the pros and cons:
+ The functionality and processing can be truly separated into isolated tasks with little or no interference.
+ Tasks can be written as easily re-usable modules (think UI/CLI for instance). Easy to transplant into the next project with hardly any strings attached.
+ Avoid many pitfalls in interactions between independent functionality
+ depending on choice of OS, you might get some of your high level functionality for free (check FreeRTOS and ChibiOS at least)

- learning curve if you never did this before (but +: once you do, you have a new powerful tool at your disposal)
- some extra resources (RAM mostly) needed to maintain task context. Not a real problem in most cases.
- you need to do a bit more overall system design and some of it under the constraints of the OS. This could also be a + as it makes you actually design certain things and not just wing it.

Having done this who knows how many times, for me it is almost a no-brainer. Who cares if you could do it without an OS, with one you will standardize the solution logic and that will carry on to the next project and the next, iteratively shortening development time. I mean, you don't get money back from unused memory so by all means trade overkill for standardization.


As to user interface, you of course code that as a separate task receiving input from a message queue and pushing output to another queue. You then have other tasks to write user input into, and read responses from, those queues as appropriate. Now the input can come from a serial channel in this project or from a touch screen in the next and your UI task never needs to care. And so on.

Edit: typos.
« Last Edit: October 15, 2013, 08:32:41 pm by Kremmen »
Nothing sings like a kilovolt.
Dr W. Bishop
 

Offline tszaboo

  • Super Contributor
  • ***
  • Posts: 7392
  • Country: nl
  • Current job: ATEX product design
Re: How to keep the user interface responsive?
« Reply #12 on: October 15, 2013, 09:27:33 pm »
I did ultrasonic flow sensing projects in the past. In fact my thesis was ultrasonic flow sensing. People tend to under-estimate the required computing power required for such task. It is not a catwalk.
I think 20MHz and 8 bit is far from enough power to process all the data. One working application was using PIC32@80Mhz, mine was dsPIC33 and 40MHz, and it did not cut it with the required resolution.
You just need too much time to process all the data, and there aren't too many cpu cycles to process it. Even if it works, you add 1-2 extra features, and the whole system breaks, as interrupts run on top of each other. DMA can help, but not on an atmega.
So use more power, and plan before, when the CPU is going to do what. And use some decent architecture, with 32 bit and lots of MHz.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: How to keep the user interface responsive?
« Reply #13 on: October 15, 2013, 09:30:56 pm »
Quote
I think 20MHz and 8 bit is far from enough power to process all the data.

It is always easier to use a bigger / faster chip to do a given job.

It is much harder to do the opposite.
================================
https://dannyelectronics.wordpress.com/
 

Offline Stonent

  • Super Contributor
  • ***
  • Posts: 3824
  • Country: us
Re: How to keep the user interface responsive?
« Reply #14 on: October 15, 2013, 10:57:46 pm »
Quote
I think 20MHz and 8 bit is far from enough power to process all the data.

It is always easier to use a bigger / faster chip to do a given job.

It is much harder to do the opposite.

As the great Colin Chapman is quoted as saying "Simplify, then add lightness"
The larger the government, the smaller the citizen.
 

Offline sleemanj

  • Super Contributor
  • ***
  • Posts: 3025
  • Country: nz
  • Professional tightwad.
    • The electronics hobby components I sell.
Re: How to keep the user interface responsive?
« Reply #15 on: October 16, 2013, 05:54:15 am »
There is always the "throw hardware at it" solution - dedicate a very small microcontroller (ATTiny etc) to handling all the UI, then have the primary microcontroller (ATMega etc) communicate with the UI one to get current settings, pass collected and processed data for display etc when it's good and ready.

~~~
EEVBlog Members - get yourself 10% discount off all my electronic components for sale just use the Buy Direct links and use Coupon Code "eevblog" during checkout.  Shipping from New Zealand, international orders welcome :-)
 

Offline Kremmen

  • Super Contributor
  • ***
  • Posts: 1289
  • Country: fi
Re: How to keep the user interface responsive?
« Reply #16 on: October 16, 2013, 07:22:45 am »
What is the platform?
It's a atmega328.
My main concern is not losing user input because there's nothing more annoying than having to press a button multiple times because the MCU wasn't ready to receive data.
User input is by nature slow. You will have to make some truly rookie mistakes to miss any of that, whatever the nature of signaling will be. That said, i would still come up with an interrupt based input collector because it makes the architecture cleaner and avoids unwanted strings between unrelated functions.

I did ultrasonic flow sensing projects in the past. In fact my thesis was ultrasonic flow sensing. People tend to under-estimate the required computing power required for such task. It is not a catwalk.
I think 20MHz and 8 bit is far from enough power to process all the data. One working application was using PIC32@80Mhz, mine was dsPIC33 and 40MHz, and it did not cut it with the required resolution.
You just need too much time to process all the data, and there aren't too many cpu cycles to process it. Even if it works, you add 1-2 extra features, and the whole system breaks, as interrupts run on top of each other. DMA can help, but not on an atmega.
So use more power, and plan before, when the CPU is going to do what. And use some decent architecture, with 32 bit and lots of MHz.
There are many kinds of flow sensors. Let's hear from the OP if this is at all relevant before jumping to conclusions. His could be a simple aperture disk with differential pressure sensors, making the measurement almost trivial in comparison. Then again, it may not.

Since this is a "real" product, a proper complexity analysis should be performed to get an idea about the required processor capacity to run the tasks, especially the calculation part. The complexity can be roughly estimated by characterizing the measurement algorithms. I assume the complexity to be closed form polynomial time,  but depending on the selected tech and the resulting nature of the data in the worst case a linear optimization could be needed in which case the nature of the beast changes radically.

Assuming polynomial it should be straightforward to write down the closed form, account for transformations to and from internal presentation and calculate the processor time for one iteration. Based on iteration frequency you then get the rough performance requirement in floating or fixed-point ops per second.
Until you do something like that, or actually try a prototype in practice, it is premature to say whether a given MCU has the kick do do it.
I am not saying you are wrong and if you have experience that indicates more calc power is needed then that may well be the case. First it should be made sure however that you are not comparing apples and oranges here. So let's hear from the OP hopefully, what kind of flow meter he has in his hands.
Nothing sings like a kilovolt.
Dr W. Bishop
 

Offline tszaboo

  • Super Contributor
  • ***
  • Posts: 7392
  • Country: nl
  • Current job: ATEX product design
Re: How to keep the user interface responsive?
« Reply #17 on: October 16, 2013, 07:59:21 am »

There are many kinds of flow sensors.
Yes, I specially marked, "ultrasonic" in my post. This is usually the easiest to implement mechanically, requiring only some cheap 1$ transducers. The drawback is the required processing power.
People tend to under estimate (financially) the cost of their own time. My experience it they rather spend countless hours of time to make a high processing power algorithm working on a inappropriately slow architecture, while for 2-3$ more, they would have enough to make it easy. And then they  make 2-3 of it.
I get that it is challenging, and optimizing code is awesome. But then you optimized the whole project the wrong way.
 

Offline mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 13748
  • Country: gb
    • Mike's Electric Stuff
Re: How to keep the user interface responsive?
« Reply #18 on: October 16, 2013, 08:30:17 am »
You should never sit waiting for anything.
Your main program should be a loop that polls all the tasks in turn, and each task should return immediately if there is nothing to do.

Anything that is time-critical - encoder, serial input, buttons should be handled by an interrupt which does as little as possible to record & service the event, and sets a flag to tell the foreground task to deal with it next time it gets polled. (And don't forget to use the volatile qualifier on any flags set by interrupts - this is extremely important - look it up)

Anything where you are sending out data to a slow interface - serial, LCD etc. can be handled by using a buffer - put your data (e.g. a text prompt) in the buffer, and the buffer gets emptied as & when space becomes available either by an interrupt or by a polled task.
As long as you deal with high-priority stuff in an interrupt, your foreground task latency can be a few tens of milliseconds before anything gets noticeably sluggish. That's tens of thousands of instructions, so all but the most complex tasks can usually be done in one go as required.

State machines are your friend.

It's all about starting with the right structure.
 
   
Youtube channel:Taking wierd stuff apart. Very apart.
Mike's Electric Stuff: High voltage, vintage electronics etc.
Day Job: Mostly LEDs
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 26907
  • Country: nl
    • NCT Developments
Re: How to keep the user interface responsive?
« Reply #19 on: October 16, 2013, 10:30:13 am »
I agree with Mike.
My software is divided in modules each with a specific function. Handle input, process data, handle an EEPROM, etc, etc. Each module has an init() and a run() function. The init function is called at startup the run function is being called from main continuously. The run functions should never  wait for a long time. If I need a long delay I use a timer. This timer gets incremented from the timer interrupt. In a run function I simple do this:
Code: [Select]
unsigned int local_delay;

void run()
{
//do something every second
  if ((systimer-local_delay)>TICKS_PER_SECOND)
    {
    local_delay=systimer;
    }
}
With the use of statemachine you can extend this mechanism by resetting the local_delay in one state and wait for it to expire in another state.
« Last Edit: October 16, 2013, 10:32:06 am by nctnico »
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline Kjelt

  • Super Contributor
  • ***
  • Posts: 6460
  • Country: nl
Re: How to keep the user interface responsive?
« Reply #20 on: October 16, 2013, 11:16:30 am »
I agree with Mike.
Do you agree on everything with Mike? Because the last time I suggested the same as Mike in a different topic you found it bad advice and said that the processing should be done in the ISR  :-//
Anything that is time-critical -........ should be handled by an interrupt which does as little as possible to record & service the event, and sets a flag to tell the foreground task to deal with it next time it gets polled.
For the record I agree fully with Mike but also with Kremmen that if an RTOS is a feasible option one should really consider using it instead of programming it your self.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: How to keep the user interface responsive?
« Reply #21 on: October 16, 2013, 11:16:38 am »
Quote
In a run function I simple do this:

There are quite a few issues in that short piece of code.

I would instead do something like this:

Code: [Select]
void run(void (*func_ptr)(void))
{
  static uint32_t local_delay=0;

  if ((systimer_get()-local_delay)>=TICKS_PER_SECOND) {
      local_delay+=TICKS_PER_SECOND;  //keep the timing errors / residuals
      func_ptr(); //do something every second
  }
}

It provides more of a modular structure. If you know which functional calls it executes, you don't need the function pointer.
================================
https://dannyelectronics.wordpress.com/
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: How to keep the user interface responsive?
« Reply #22 on: October 16, 2013, 11:26:16 am »
Quote
if an RTOS is a feasible option one should really consider using it instead of programming it your self.

Not sure. And RTOS adds considerable complexity + overhead.

Pus, a state machine is essentially a rtos in that it is a scheduler.

Something like this would basically work:

Code: [Select]
  switch (proc_cnt) {
    case PROC_1: proc1(); break;
    case PROC_2: proc2(); break;
    ...
    case PROC_N: procN(); break;
    default: proc_all();
  }
  proc_cnt=(proc_cnt==PROC_N)?0:(proc_cnt+1); //advance to the next proc

Each time you run that block, it executes a different process. It does make certain assumptions about the processes but that's the basic framework for a rtos.
================================
https://dannyelectronics.wordpress.com/
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: How to keep the user interface responsive?
« Reply #23 on: October 16, 2013, 11:31:34 am »
My opinion in the whole RTOS thing is that you probably don't need it. Basic task scheduling can be done in literally less work than figuring out and implementing the RTOS. Just cycle through tasks, like Mike said, and never wait on anything. For anything time-oriented, I keep a tick counter at a fixed frequency, and either selectively execute tasks when their time is up, or just make the counter available to the tasks. Your whole scheduler can be a couple dozen words of ROM.
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: How to keep the user interface responsive?
« Reply #24 on: October 16, 2013, 11:35:41 am »
Quote
the processing should be done in the ISR

Because the wind was blowing in a different direction then, :)
================================
https://dannyelectronics.wordpress.com/
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf