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

0 Members and 1 Guest are viewing this topic.

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: How to keep the user interface responsive?
« Reply #50 on: October 17, 2013, 02:05:29 pm »
Quote
I use a lot of RAM and a lot of ROM..

How do you then reconcile with the following statement you made earlier?

Quote
A good RTOS is really but really lightweight.. It just costs tasks stack RAM. Nearly nothing else.

Quote
But I can code really fast, and nearly bug free, and nearly without thinking, and reading PDF's..

Without thinking, without reading datasheets, coding on an OS (any os), yet (nearly) bug free. If that's not a miracle, I don't know what is.

:)

I would submit to you that even if you don't write a single line of code, as long as it runs on an OS, your code has bugs.


All for the fun.
================================
https://dannyelectronics.wordpress.com/
 

Offline denizcan

  • Regular Contributor
  • *
  • Posts: 59
Re: How to keep the user interface responsive?
« Reply #51 on: October 17, 2013, 02:31:03 pm »
LOL, I don't know why, I don't think we can agree on anything.. :) I said "I use a lot of RAM and ROM" because I was sure you were going to ask how much resources the WorkList methodology I gave use.. :))

Nearly bug free is another story. If you add a well tested abstraction to basic functions you do, you would have only application related functions to deal with, and only application related bugs.. If you fix a bug on a framework, you also fixed other projects.. This is better than fixing every project.. Actually this is a knife cuts both side.. If you are not good at framework coding, then you introduce new bugs to all projects.. But as far as I see, if you give enough attention, having a framework is better than not having..

Not kidding.. :)
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 26752
  • Country: nl
    • NCT Developments
Re: How to keep the user interface responsive?
« Reply #52 on: October 17, 2013, 03:21:45 pm »
Now try to use printf in the timer event.

Why do you use printf on IRQ? There is two methods:
1. set an event, and handle it on a task. You can guess how.
Not in an IRQ but just when an event happens. Sometimes I want to print a value every X seconds. If an IRQ is hidden under so many layers of abstraction its easy to put code in a place where it shouldn't be. In some of my projects I have to wait for the UART buffer to become empty. If I write something to the UART in an IRQ and it waits for the buffer to become empty the whole thing is locked because the IRQ from the UART isn't served.
Quote
2. I forgot to mention, there is WorkItem class, which is processed by WorkList..
This is a little interesting.. You register a function or method to WorkItem, and add the WorkItem to WorkList.. Each WorkList has its own task, and a linked list of triggered  WorkItems, and a linked list of idle WorkItem's..
That sounds pretty complicated. I like to test my software on interns and see how long it takes them to figure out how to add new modules and make changes. Its a good measure to see how easy or hard it is to have the software maintained by someone else.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline denizcan

  • Regular Contributor
  • *
  • Posts: 59
Re: How to keep the user interface responsive?
« Reply #53 on: October 17, 2013, 07:39:19 pm »
Quote
Not in an IRQ but just when an event happens. Sometimes I want to print a value every X seconds. If an IRQ is hidden under so many layers of abstraction its easy to put code in a place where it shouldn't be.

You say that someone is prone to put IRQ forbidden stuff on onTick or similar event which is called from an IRQ.. Nice point, and I loved the idea.. I'll think about that.. I may move all timer related stuff to task level. It is easy for timers, however need to think on other peripheral abstractions, and notations.. For instance you would want fast response, in IRQ level on GpioInterrupt class, or ExternalInterrupt which bonds to a pin.. Thinking on this, here comes an idea:

Code: [Select]
timer.onTick = makeAsync(handleTimerTick);

makeIrqSafe or something like that.. now handleTimerTick is handled by task, not irq.. what about this?

Testing on interns are good measure.. But why do you think the second WorkList example is complicated? It just passes flow to a task.. Would it be easier to understand if we drop "workList" idiom, and just do it like that:

Code: [Select]
void doPrintf(void* sender, void* param)
{
  printf("....", (Int)param);
}

void handleTimerTick(void* sender, void* param)
{
  callAsync(doPrintf, 1);
}

I know, as you mentioned and I described above, being able to IRQ safe is the best, however just thinking about calling a function from IRQ.. callAsync hides WorkList stuff, it uses defaultWorkList. It is overloaded to make usage easier, this one uses Int as param..

What do you think?
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 26752
  • Country: nl
    • NCT Developments
Re: How to keep the user interface responsive?
« Reply #54 on: October 17, 2013, 08:06:40 pm »
Now you have to pass parameters from the IRQ thread to the main thread. Printf is a fine example because it can have a variable list of parameters and in some cases these parameters are pointers (a string for example). So you'd have to allocate a buffer, use snprintf inside the IRQ to fill the buffer, pass the buffer and de-allocate the buffer in doPrintf.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Online mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 13695
  • Country: gb
    • Mike's Electric Stuff
Re: How to keep the user interface responsive?
« Reply #55 on: October 17, 2013, 08:18:23 pm »
I know, as you mentioned and I described above, being able to IRQ safe is the best, however just thinking about calling a function from IRQ..

If your IRQ code is so big you need to call functions, chances are you're doing it wrong
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: 26752
  • Country: nl
    • NCT Developments
Re: How to keep the user interface responsive?
« Reply #56 on: October 17, 2013, 08:46:21 pm »
I know, as you mentioned and I described above, being able to IRQ safe is the best, however just thinking about calling a function from IRQ..

If your IRQ code is so big you need to call functions, chances are you're doing it wrong
That depends on what you are doing. For DSP like applications it would be foolish not to do all the processing inside the interrupt so calling functions is perfectly normal in those situations. Another nice example is an USB stack. These are often so complicated that an interrupt consists of calling lots of functions.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline denizcan

  • Regular Contributor
  • *
  • Posts: 59
Re: How to keep the user interface responsive?
« Reply #57 on: October 17, 2013, 09:51:41 pm »
I know, as you mentioned and I described above, being able to IRQ safe is the best, however just thinking about calling a function from IRQ..

If your IRQ code is so big you need to call functions, chances are you're doing it wrong

Mike, calling function, actually calling through Callback, makes IRQ handling a little longer but flexible.. For instance, to bind an GPIO interrupt to a function:

Code: [Select]
GpioInterrupt syncIrq;
int main()
{
  syncIrq.setPin(P1_0);
  syncIrq.onTrigger = handleSyncEvent;
  syncIrq.enable(IS_RISING);
}

Here you binded P1_0's rising edge to your handleSyncEvent function, even without knowing the actual implementation..

This also gives plasticity. For instance CC1101 chip uses 2 GPIO pins to report it's state. You may pass what pins it shall use to CC1101Spi class, then it will direct those pin irq's to its method, as sample above.. So, you don't have to write an irq handler function and direct it to CC1101 vice versa..

I know it will make irq a little longer, but I think it is worth.. Especially on ARM as nested irq handling is intrinsic and one IRQ with higher order does not wait lower one.. Still, you have to make sure that you made IRQ callback as light as possible..
 

Offline denizcan

  • Regular Contributor
  • *
  • Posts: 59
Re: How to keep the user interface responsive?
« Reply #58 on: October 17, 2013, 10:01:16 pm »
Now you have to pass parameters from the IRQ thread to the main thread. Printf is a fine example because it can have a variable list of parameters and in some cases these parameters are pointers (a string for example). So you'd have to allocate a buffer, use snprintf inside the IRQ to fill the buffer, pass the buffer and de-allocate the buffer in doPrintf.

Do you think you really have to pass whole processed value to a task? Why don't we just use Timer as a trigger? Because one might write printf on onTick event? In the example callAsync triggers defaultWorkList's task to run given function, with given simple pointer size parameter (32 bit on ARM, 16 bit on MSP and AVR).. It runs as such it runs in IRQ.. So you may handle as you are in IRQ, but you are in task level..
 

Offline e100Topic starter

  • Frequent Contributor
  • **
  • Posts: 563
Re: How to keep the user interface responsive?
« Reply #59 on: October 17, 2013, 11:13:03 pm »
I found a scheduler and explanation here
http://bleaklow.com/2010/07/20/a_very_simple_arduino_task_manager.html
with downloadable source code here
http://bleaklow.com/files/2010/Task.tar.gz
The comments at the bottom seem favourable.
Does this look like a reasonable way of doing things?

Mike
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 26752
  • Country: nl
    • NCT Developments
Re: How to keep the user interface responsive?
« Reply #60 on: October 17, 2013, 11:47:15 pm »
Now you have to pass parameters from the IRQ thread to the main thread. Printf is a fine example because it can have a variable list of parameters and in some cases these parameters are pointers (a string for example). So you'd have to allocate a buffer, use snprintf inside the IRQ to fill the buffer, pass the buffer and de-allocate the buffer in doPrintf.

Do you think you really have to pass whole processed value to a task? Why don't we just use Timer as a trigger? Because one might write printf on onTick event? In the example callAsync triggers defaultWorkList's task to run given function, with given simple pointer size parameter (32 bit on ARM, 16 bit on MSP and AVR).. It runs as such it runs in IRQ.. So you may handle as you are in IRQ, but you are in task level..
That depends on where the text for the printf is originating from. You can't just pass a pointer to data from the IRQ thread to the user thread. You never know whether the pointer still points to valid data. You need to wrap the data to which the pointer points into a package and hand that over to the other thread OR safeguard the data the pointer points to remains valid.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline denizcan

  • Regular Contributor
  • *
  • Posts: 59
Re: How to keep the user interface responsive?
« Reply #61 on: October 18, 2013, 12:14:47 am »
I found a scheduler and explanation here
http://bleaklow.com/2010/07/20/a_very_simple_arduino_task_manager.html
with downloadable source code here
http://bleaklow.com/files/2010/Task.tar.gz
The comments at the bottom seem favourable.
Does this look like a reasonable way of doing things?

Mike

Don't stick your self to a chip and to a system that is designed for/has 2KB RAM.. If you can do, go with ARM, and RTOS'es that run on them.. That way, if memory is not enough, you can switch one size larger.. :)
 

Offline denizcan

  • Regular Contributor
  • *
  • Posts: 59
Re: How to keep the user interface responsive?
« Reply #62 on: October 18, 2013, 12:23:10 am »
Now you have to pass parameters from the IRQ thread to the main thread. Printf is a fine example because it can have a variable list of parameters and in some cases these parameters are pointers (a string for example). So you'd have to allocate a buffer, use snprintf inside the IRQ to fill the buffer, pass the buffer and de-allocate the buffer in doPrintf.

Do you think you really have to pass whole processed value to a task? Why don't we just use Timer as a trigger? Because one might write printf on onTick event? In the example callAsync triggers defaultWorkList's task to run given function, with given simple pointer size parameter (32 bit on ARM, 16 bit on MSP and AVR).. It runs as such it runs in IRQ.. So you may handle as you are in IRQ, but you are in task level..
That depends on where the text for the printf is originating from. You can't just pass a pointer to data from the IRQ thread to the user thread. You never know whether the pointer still points to valid data. You need to wrap the data to which the pointer points into a package and hand that over to the other thread OR safeguard the data the pointer points to remains valid.

In timer I don't think you create large data.. I think what's on your mind is UART.. I have really unusual and effective different approach on UART.. However, lets assume we created large data in IRQ, that does not fit in pointer size value, then mailbox might be the solution..

Code: [Select]
typedef struct
{
  Int something;
  UInt otherThing;
} SomeData;

Mailbox<SomeData, 8> mailbox;

void handleSomeEvent(void* sender, void* param)
{
  // prepare data
  SomeData data;
  data.something = 1234;
  data.otherThing = 5678;
  mailbox.tryPush(data);
}

void handleTask(Task* t, void* param)
{
  while (1)
  {
    SomeData data;
    mailbox.pop(data);
    printf("etc etc", data.something, data.otherThing);
  }
}


The loop in handleTask is on hold until something is pushed into mailbox..
 

Offline denizcan

  • Regular Contributor
  • *
  • Posts: 59
Re: How to keep the user interface responsive?
« Reply #63 on: October 18, 2013, 12:42:10 am »
Also suppose you made printing central, that prints different incoming data from multiple sources.. Than multiple mailbox's you may wait:

Code: [Select]
void handlePrintingTask(Task* t, void* param)
{
  while (1)
  {
    Result r = waitAny(mailbox1.getPushEvent(), mailbox2.getPushEvent(), 100);
    if (r == 0)
    {
      printf("timeout");
      continue;
    }

    if (r & BIT0)
    {
      DataType1 data;
      mailbox1.pop(data)
      printf(..)
    }

    if (r & BIT1)
    {
      DataType2 data;
      mailbox2.pop(data)
    }
  }
}

I know a little odd approach.. :)
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf