Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to achieve multitasking in a microcontroller?

I wrote a program for a wrist watch utilizing a 8051 micro-controller using Embedded (C). There are a total of 6 7-segment displays as such:

         _______________________
        |      |       |        |   two 7-segments for showing HOURS
        | HR   | MIN   |   SEC  |   two 7-segments for showing MINUTES and
        |______._______.________|   two 7-segments for showing SECONDS
          7-segment LED display

To update the hours, minutes and seconds, we used 3 for loops. That means that first the seconds will update, then the minutes, and then the hours. Then I asked my professor why can't we update simultaneously (I mean hours increment after an hour without waiting for the minutes to update). He told me we can't do parallel processing because of the sequential execution of the instructions.

Question:

A digital birthday card which will play music continuously whilst blinking LED's simultaneously. A digital alarm clock will produce beeps at particular time. While it is producing sound, the time will continue updating. So sound and time increments both are running in parallel. How did they achieve these results with sequential execution?

How does one run multiple tasks simultaneously (scheduling) in a micro-controller?

like image 745
gangadhars Avatar asked May 22 '14 08:05

gangadhars


People also ask

What is multitasking in microcontroller?

The term multitasking means that several tasks are processed in parallel on the same CPU. In a multitasking system, several tasks to run on a single CPU at the same time. Therefore, task switching is done where the tasks share the CPU time.

CAN microcontroller perform multiple tasks?

Microcontroller Units (MCUs) are all around us powering many of our so called smart devices. Most programs running on MCUs are control applications performing multiple jobs at the same time. Examples of these jobs are: blinking a status LED, reading button states, talking to sensors or communicating with the world.

What is the secret to success for multitasking?

Example: "The only secret to successful multitasking is prioritization. Multitasking is a combination of tasks. You break each task down into smaller tasks and set them into a priority sequence.


1 Answers

First, what's with this sequential execution. There's just one core, one program space, one counter. The MPU executes one instruction at a time and then moves to another, in sequence. In this system there's no inherent mechanism to make it stop doing one thing and start doing another - it's all one program, and it's entirely in hands of programmer what the sequence will be and what it will do; it will last uninterrupted, one instruction at a time in sequence, as long as the MPU is running, and nothing else will happen, unless the programmer made it happen first.

Now, to multitasking:

Normally, operating systems provide multitasking, with quite complex scheduling algorithms.

Normally, microcontrollers run without operating system.

So, how do you achieve multitasking in microcontroller?

The simple answer is "you don't". But as usually, the simple answer rarely covers more than 5% cases...

You'd have an extremely hard time writing a real, preemptive multitasking. Most microcontrollers just don't have the facilities for that, and things an Intel CPU does with a couple specific instructions would require you to write miles of code. Better forget classic multitasking for microcontrollers unless you really have nothing better to do with your time.

Now, there are two usual approaches that are frequently used instead, with far less hassle.

Interrupts

Most microcontrollers have different interrupt sources, often including timers. So, the main loop runs one task continuously, and when the timer counts to zero, interrupt is issued. The main loop is stopped and execution jumps to an address known as 'interrupt vector'. There, a different procedure is launched, performing a different one-off task. Once that finishes (possibly resetting the timer if need be), you return from the interrupt and main loop is resumed.

Microcontrollers often have a few timers, and you can assign one task per timer, not to mention tasks on other, external interrupts (say, keyboard input - key pressed, or data arriving over RS232.)

While this approach is very limited, it really suffices for great most cases; specifically yours: set up the timer to cycle 1s, on interrupt calculate the new hour, change display, then leave the interrupt. In main loop wait for date to reach birthday, and when it does start playing the music and blinking the LEDs.

Cooperative multitasking

This is how it was done in the early days. You need to write your 'tasks' as subroutines, each with a finite state machine (or a single pass of a loop) inside, and the "OS" is a simple loop of jumps to consecutive tasks, in sequence.

After each jump the MPU starts executing given task, and will continue until the task returns control, after first saving up its state, to recover it when it's started again. Each pass of the task job should be very short. Any delay loops must be replaced with wait states in the finite state engine (if the condition is not satisfied, return. If it is, change the state.) All longer loops must be unrolled into distinct states ("State: copying block of data, copy byte N, increase N, N=end? yes: next state, no: return control)

Writing that way is more difficult, but the solution is more robust. In your case you might have four tasks:

  • clock
  • display update
  • play sound
  • blink LED

Clock returns control if no new second arrived. If it did, it recalculates the number of seconds, minutes, hours, date, and then returns.

Display updates the displayed values. If you multiplex over the digits on the 8-segment display, each pass will update one digit, next pass - next one etc.

Playing sound will wait (yield) while it's not birthday. If it's birthday, pick the sample value from memory, output it to speaker, yield. Optionally yield if you were called earlier than you were supposed to output next sound.

Blinking - well, output the right state to LED, yield.

Very short loops - say, 10 iterations of 5 lines - are still allowed, but anything longer should be transformed into a state of the finite state engine which the process is.

Now, if you're feeling hardcore, you may try going about...

pre-emptive multitasking.

Each task is a procedure that would normally execute infinitely, doing just its own thing. written normally, trying not to step on other procedures' memory but otherwise using resources as if there was nothing else in the world that could need them.

Your OS task is launched from a timer interrupt.

Upon getting started by the interrupt, the OS task must save all current volatile state of the last task - registers, the interrupt return address (from which the task should be resumed), current stack pointer, keeping that in a record of that task.

Then, using the scheduler algorithm, it picks another process from the list, which should start now; restores all of its state, then overwrites own return-from-interrupt address with the address of where that process left off, when preempted previously. Upon ending the interrupt normal operation of the preempted process is resumed, until another interrupt which switches control to OS again.

As you can see, there's a lot of overhead, with saving and restoring the complete state of the program instead of just what the task needs at the moment, but the program doesn't need to be written as a finite state machine - normal sequential style suffices.

like image 150
SF. Avatar answered Sep 17 '22 20:09

SF.