
{"id":788,"date":"2019-09-27T08:25:21","date_gmt":"2019-09-27T08:25:21","guid":{"rendered":"http:\/\/blogs.plymouth.ac.uk\/embedded-systems\/?page_id=788"},"modified":"2019-10-10T09:05:46","modified_gmt":"2019-10-10T09:05:46","slug":"performing-real-time-tasks-with-interrupts","status":"publish","type":"page","link":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/microcontrollers\/mbed-os-2\/courses\/level-5-embedded-and-real-time-systems\/performing-real-time-tasks-with-interrupts\/","title":{"rendered":"Performing Real-Time Tasks with Interrupts"},"content":{"rendered":"<p><a href=\"http:\/\/blogs.plymouth.ac.uk\/embedded-systems\/microcontrollers\/mbed-os-2\/courses\/level-5-embedded-and-real-time-systems\/\">Table of Contents<\/a><\/p>\n<hr \/>\n<h1>Interrupts &#8211; a first look<\/h1>\n<p>Although simple, polling has some major disadvantages:<\/p>\n<ol>\n<li>It uses a lot of CPU resource even when there are no changes in the inputs. This is unlike most modern computer systems which are event driven and can idle.<\/li>\n<li>The loop cycle time is variable (e.g. due to conditional statements). Therefore the \u201csampling interval\u201d of the inputs is not constant and is said to \u201cjitter\u201d. This can be a problem for certain types of input signal such as audio.<\/li>\n<li>If the loop cycle is ever too long, input changes could be missed and data lost. The delay gets longer as more code is added.<\/li>\n<li>Any blocking in the loop would result in inputs being ignored. For example, we cannot easily read the terminal in the polling loop and the C-Standard <code>fgets<\/code> and <code>scanf<\/code> are blocking functions.<\/li>\n<\/ol>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-769 size-medium\" style=\"letter-spacing: 0.8px\" src=\"http:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/reminder-platform-300x157.png\" alt=\"\" width=\"300\" height=\"157\" srcset=\"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/reminder-platform-300x157.png 300w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/reminder-platform-768x401.png 768w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/reminder-platform.png 778w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-797\" src=\"http:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-2-5.png\" alt=\"\" width=\"438\" height=\"420\" srcset=\"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-2-5.png 438w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-2-5-300x288.png 300w\" sizes=\"auto, (max-width: 438px) 100vw, 438px\" \/><\/p>\n<p>Note how the main loop simply puts the MCU in a low power sleep state. This means when there is nothing to do, the CPU does not waste cycles (and hence power). When the interrupt occurs, it wakes. This is the basis of event driven computing.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-798\" src=\"http:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-2-6.png\" alt=\"\" width=\"439\" height=\"433\" srcset=\"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-2-6.png 439w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-2-6-300x296.png 300w\" sizes=\"auto, (max-width: 439px) 100vw, 439px\" \/><\/p>\n<p>This solution is an improvement, but still does not work perfectly.<\/p>\n<blockquote><p><strong>Key Points:<\/strong><\/p><\/blockquote>\n<p>This solution used two types of interrupt. One is driven from the GPIO and switch, the other from an internal hardware timer.<\/p>\n<ul>\n<li>When a rising edge is detected, the rising-edge detection is immediately deactivated and a \u201cone-shot\u201d timer is started.<\/li>\n<li>The a one-shot timer (known as a <code>Timeout<\/code>) is used to add a 200ms delay. When this time has elapsed, its own ISR is called in which the rising edge interrupt is re-enabled.<\/li>\n<li>The timer is an internal device that still operates even when the CPU is in sleep mode.<\/li>\n<\/ul>\n<p>The remaining problem is that a switch release sometimes registers a rising edge (due to switch bounce). In the next solution we address with with a state-machine design.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-799\" src=\"http:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-2-7.png\" alt=\"\" width=\"439\" height=\"462\" srcset=\"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-2-7.png 439w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-2-7-285x300.png 285w\" sizes=\"auto, (max-width: 439px) 100vw, 439px\" \/><\/p>\n<p>You have probably found that the two switches and LEDs don\u2019t share any state (variables, hardware etc..), so don\u2019t interfere with each other.<\/p>\n<blockquote><p>Key Points:<\/p><\/blockquote>\n<ul>\n<li>In this example, it was possible to virtually duplicate code (and change some names) to add the extra switch and LED. This is because they are completely independent and share no (mutable) state.<\/li>\n<li>In general, it is not usually so simple to extend functionality. Safe interrupt code can be hard to write.<\/li>\n<li>The main routine once again just puts the MCU into a low-power sleep state. This solution is power efficient.<\/li>\n<li>All interrupt service routines are fast and short. None have any blocking calls in them, making this solution very responsive.<\/li>\n<li>Interrupts can only be preempted by higher priority interrupts. No priorities have been assigned in this code, so blocking inside an ISR could potentially delay others.<\/li>\n<li>There are many functions that should not be be called by an interrupt (such as <code>printf<\/code>).<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h1>Race Conditions and Corruption<\/h1>\n<p>Interrupt service routines can be dangerous. The danger centers around \u201c<strong>shared mutable state<\/strong>\u201d &#8211; i.e. variables (but not constants) accessed from more than one interrupt.<\/p>\n<p>In this section we will take a closer look at the origins of this problem.<\/p>\n<p>In the previous example, the interrupt service routines (ISRs) for each switch had some global data that was shared between different ISRs. However, none of the interrupts were able to preempt each other meaning this data was always accessed <strong>exclusively<\/strong>.<\/p>\n<blockquote><p>Note &#8211; the <code>main()<\/code> function can always be interrupted by any of the ISRs. This can often be overlooked.<\/p><\/blockquote>\n<p>Let\u2019s now take a look under the hood of an interrupt driven application and witness data corruption. For this, we it is advised that you use the debugging facilities of Keil uVision.<\/p>\n<p>Go to the source site and export for Keil uVision 5 (v5.28a or later)<\/p>\n<p>https:\/\/os.mbed.com\/teams\/University-of-Plymouth-Stage-2-and-3\/code\/Task328\/<\/p>\n<blockquote><p>To see how to export from Mbed-os to Keil uVision, <a href=\"https:\/\/plymouth.cloud.panopto.eu\/Panopto\/Pages\/Viewer.aspx?id=6c63377d-7fa4-4fbd-b1dc-aadb00d23750\" target=\"_blank\" rel=\"noopener\">watch this video (includes captions)<\/a><\/p><\/blockquote>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-803\" src=\"http:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-2-8.png\" alt=\"\" width=\"441\" height=\"444\" srcset=\"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-2-8.png 441w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-2-8-150x150.png 150w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-2-8-298x300.png 298w\" sizes=\"auto, (max-width: 441px) 100vw, 441px\" \/><\/p>\n<p>In the second experiment, you should have found that the green light stayed on. This means the final value of the counter is NOT zero!<\/p>\n<blockquote><p>Note &#8211; this experiment depends on timing &#8211; If it the green light went out, find the line that reads: \u2028t1.attach_us(&amp;countDown, 15); and try tweaking the delay slightly.<\/p><\/blockquote>\n<p>&nbsp;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-807\" src=\"http:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-2-8b.png\" alt=\"\" width=\"441\" height=\"245\" srcset=\"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-2-8b.png 441w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-2-8b-300x167.png 300w\" sizes=\"auto, (max-width: 441px) 100vw, 441px\" \/><\/p>\n<p>The ONLY difference between the two experiments is the timing of the timer interrupt &#8211; <em>the function of the code has NOT changed, yet the results are different.<\/em><\/p>\n<p>Note that <code>counter--<\/code> requires multiple instructions and thus can be interrupted by an ISR. If an ISR interrupts this code, and itself modifies counter, then it\u2019s stored value will become inconsistent. <strong>This is a key point for software safety<\/strong>.<\/p>\n<p>This is the assembler for <code>counter--<\/code><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-808\" src=\"http:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/assembler-for-counter-.png\" alt=\"\" width=\"439\" height=\"314\" srcset=\"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/assembler-for-counter-.png 439w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/assembler-for-counter--300x215.png 300w\" sizes=\"auto, (max-width: 439px) 100vw, 439px\" \/><\/p>\n<p><strong>Question<\/strong>: When a timer interrupt occurs, many registers will be pushed to the stack, <em>including<\/em>\u00a0<code>{r0-r3}<\/code>. When it returns they will be popped off again. Given this information, <em>can you explain the final value of counter<\/em>? Discuss with the tutor if not sure.<\/p>\n<h2>Recap &#8211; Multiple Outputs with <code>BusOut<\/code><\/h2>\n<p>The mbed website contains a lot of useful reference and tutorial information. A great place to start is the <a href=\"https:\/\/os.mbed.com\/docs\/mbed-os\/v5.14\/apis\/index.html\">online API guide for mbed-os<\/a>. So far, we have only read from a single input pin or asserted a single output pin at a time. We often want to read groups of pins at the same time. In the next task, we are going to convert decimal numbers to binary using the LEDs as an output display.<\/p>\n<p>The red LED will be the <a href=\"http:\/\/blogs.plymouth.ac.uk\/embedded-systems\/glossary-2\/most-significant-bit-msb-glossary-entry\/\"><strong>most significant bit<\/strong><\/a> (BIT2) and the greed LED the <a href=\"http:\/\/blogs.plymouth.ac.uk\/embedded-systems\/glossary-2\/least-significant-bit-lsb-glossary-entry\/\"><strong>least significant bit<\/strong><\/a> (BIT0)<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-809\" src=\"http:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/LED-pin-assignments.png\" alt=\"\" width=\"392\" height=\"177\" srcset=\"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/LED-pin-assignments.png 392w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/LED-pin-assignments-300x135.png 300w\" sizes=\"auto, (max-width: 392px) 100vw, 392px\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-810\" src=\"http:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-3-1.png\" alt=\"\" width=\"439\" height=\"278\" srcset=\"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-3-1.png 439w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/Task-3-3-1-300x190.png 300w\" sizes=\"auto, (max-width: 439px) 100vw, 439px\" \/><\/p>\n<p>&nbsp;<\/p>\n<pre class=\"lang:c++ decode:true \">#include \"mbed.h\"\r\n\r\n\/\/lsb first\r\nBusOut binaryOutput(D5, D6, D7);\r\n\r\nint main() {\r\n\r\n    \/\/Try different values\r\n    binaryOutput = 3;\r\n    \r\n    while (1) { }\r\n}<\/pre>\n<h3><code>BusOut<\/code><\/h3>\n<p>The new software component is <a href=\"https:\/\/os.mbed.com\/docs\/mbed-os\/v5.9\/reference\/busout.html\" target=\"_blank\" rel=\"noopener\"><code>BusOut<\/code> <\/a>which takes a variable number of parameters. These parameters specify (lsb first) which pins to use for the binary output. Assigning a decimal to the instance <code>binaryOutput<\/code> converts the decimal to binary, and sets the pins accordingly.<\/p>\n<p>Be aware that <code>BusOut<\/code>is a convenience class. It simply maintains an internal array of <code>DigitalOut<\/code>type objects. When you set a value (scalar integer), it sets each output in turn. This means that they do not change simultaneously. For that, you are advised to<a href=\"https:\/\/os.mbed.com\/docs\/mbed-os\/v5.9\/reference\/portout.html\" target=\"_blank\" rel=\"noopener\"> read the documentation on <code>PortOut<\/code><\/a><\/p>\n<h1>Some Important Terminology<\/h1>\n<p>Before we move on to analogue I\/O with Mbed-os, it\u2019s important to review some important terminology:<\/p>\n<h2>Blocking<\/h2>\n<p>Where a given thread of code stops and waits for a resource to become available (such as a ADC conversion, or a network transaction), and does not proceed, we say this is <strong>blocking<\/strong>. Blocking is a term used in more than one context however.<\/p>\n<p>&nbsp;<\/p>\n<h3>Busy Wait Loop (spinning)<\/h3>\n<p>When an embedded application needs to read data from multiple sources, one method is to read each device in turn. As each device is being read, the code does not proceed\u00a0until data is available before resuming. This is depicted in the figure below (right hand side).<\/p>\n<blockquote><p>Busy wait is considered an \u201canti-pattern\u201d and is not generally recommended (but it has its place).<\/p><\/blockquote>\n<p>As a general point, busy-wait loops\u00a0are not efficient in terms of CPU usage or power consumption as it can consume all the CPU time doing nothing useful. However, if all the devices are fast or have a known worst case latency, then this approach might still work and still meet all the timing deadlines \/ power requirements.<\/p>\n<ul>\n<li>One advantage is that this method (in the absence of any other concurrent task) does not risk race conditions.<\/li>\n<li>The approach also tends to promote a coding style that is very clear and simple, whereby everything is done in sequence. In terms of programming, an advantage is that this is easy to for a human to write and to follow. This point should not be neglected.<\/li>\n<\/ul>\n<p>When you rapidly poll a single device in a tight loop as depicted below, this is sometimes known as \u201cspinning\u201d. It is usually only used when the device being waited on will finish it&#8217;s task very quickly.<\/p>\n<h3>In a multi-threaded environment<\/h3>\n<p>At risk of getting ahead of ourselves, it may be worth flagging (for future reference) that blocking in general is not always negative, and in the context of real-time operating systems (covered in level 6), this can be the right way to interface with hardware.<\/p>\n<ul>\n<li>It is advantageous to retain the simplicity of busy-wait, where each task is performed in sequence and to completion. This is somewhat <em>humanistic<\/em>.<\/li>\n<li>When we encounter multi-threaded programming later in the course,\u00a0we discover that it is possible to block on a resource in a separate parallel\u00a0<em>thread<\/em>\n<ul>\n<li>This allows other functionality to continue unimpeded while blocking on a device.<\/li>\n<li>This can also be CPU and power-efficient as well. The clever part is that while it is blocking, no CPU cycles are used until the device signals (to the operating system via an interrupt) that it is ready. For this, you need something known as a scheduler and compatible <em>device drivers<\/em>.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<figure id=\"attachment_813\" aria-describedby=\"caption-attachment-813\" style=\"width: 736px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-813\" src=\"http:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/polling-vs-busywait.png\" alt=\"\" width=\"736\" height=\"688\" srcset=\"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/polling-vs-busywait.png 736w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2019\/09\/polling-vs-busywait-300x280.png 300w\" sizes=\"auto, (max-width: 736px) 100vw, 736px\" \/><figcaption id=\"caption-attachment-813\" class=\"wp-caption-text\"><strong>Left<\/strong>: Rapid polling loop\u00a0(non blocking). Note that all reads are non-blocking, so only query the device status without waiting; <strong>Right:<\/strong> Busy-Wait loop where the code rapidly polls each device in sequence, and does not proceed until each device is ready.<\/figcaption><\/figure>\n<h2>Rapid Polling (non-blocking)<\/h2>\n<p>This is a technique to read data from multiple input sources without blocking and waiting for any hardware device. All we need is the (rapid) ability to check if a device is ready. This is known as polling a device (read without wait).<\/p>\n<p>In the figure above (left hand side), each device is queried (polled) to see if it has any available data (or if there has been any change in status). If yes, then data is retrieved and stored. The next device is then polled.<\/p>\n<p>This method does not block the current thread of execution, so all devices can be polled at high rates. It does not suffer from problems with race conditions as (in the absence of any other concurrent tasks) there is no preemption.<\/p>\n<p>This method does have some disadvantages however. The loop must repeat fast enough to read all devices before any data is missed and lost. This again means CPU cycles and power are being consumed even where there is no new input to process. Furthermore, the presence of conditional statements means the execution path through the code will vary, and thus the loop timing is likely to jitter. This can cause problems where data must be read at fixed intervals.<\/p>\n<p>Rapid polling is relatively complex compared to simple busy-wait code, but does not come with the risks of interrupts. Devices are rapidly polled, and then the rest of the software needs to determine (i) if anything has changed and (ii) what to update as a consequence. One strategy is to combine rapid polling with one or more state machines. In terms of power, one compromise is to slow the loop down with sleeping waits (putting the CPU into sleep states for a period of time).<\/p>\n<h2>Some thoughts on Interrupts<\/h2>\n<p>Hardware events are typically asynchronous, and interrupt are the ideal mechanism to detect an external change and react on demand. This is why modern computer systems (at the lowest level) are all ultimately driven on interrupts.<\/p>\n<ul>\n<li>In general, hardware interrupts are the most elegant mechanism for the CPU to respond to a hardware device in a timely way.<\/li>\n<li>As a general rule (and I&#8217;ve seen it broken!), interrupts should be kept short. This is to allow other interrupts (of equal or lower priority) to respond in a timely fashion.Interrupts can have different priorities, and if nested (we did not use this), can preempt lower priority interrupts.<\/li>\n<\/ul>\n<p>Interrupts communicate through shared mutable state (global variables typically, but could be hardware device). <strong>This introduce the risk of race conditions and data corruption<\/strong>.<\/p>\n<p>A major advantage of interrupts is that a CPU can enter a low power idle \/ sleep state when there are no tasks remaining. Hardware interrupts will wake the CPU when there is some useful work to be done. This is in contrast with polling methods where CPU cycles are consumed constantly.<\/p>\n<p>The main disadvantage of using interrupt is scalability &#8211; as more interrupts are added, so it becomes more challenging to follow the code, optimise the priorities and to guarantee that all device response times are always honoured. There is also the issue of race conditions which should never be underestimated.<\/p>\n<p><strong>GREAT BIG WARNING (with flashing lights on it)<\/strong><\/p>\n<p>Note that <strong>not all functions are interrupt safe<\/strong>. In fact, the number of functions that may be safely used in an interrupt service routine are a minority. This includes functions such as <code>printf<\/code>, the <code>SPI,<\/code>\u00a0<code>I2C<\/code>, <code>ADC<\/code> and <code>DAC<\/code> drivers in Mbed-os!<\/p>\n<blockquote><p>It is quite easy to write a function that is not interrupt safe. You might want to research the term <strong><em>reentrant<\/em><\/strong> function.<\/p><\/blockquote>\n<p>In short, it is all-to-easy to make a mistake with interrupts that results in a bug that may go undetected for a long time.<\/p>\n<p>&nbsp;<\/p>\n<p>Later we will meet \u201cthreads\u201d which are often considered to be a safer and more scalable alternative, and where the majority of device drivers are compatible.<\/p>\n<h2>Self-Study Challenge: Interrupts<\/h2>\n<p>You are now to solve the previous self-study task, only this time with interrupts, and safely!<\/p>\n<p><strong>Self-Directed Task<\/strong><\/p>\n<p>Using the same hardware as above, write a new project to do the following:<\/p>\n<ul>\n<li>On power up, the Green LED should flash once a second (1Hz).<\/li>\n<li>Pressing (and releasing) SW1 should reduce the flashing rate (frequency)<\/li>\n<li>Pressing (and releasing) SW2 should increase the flashing rate<\/li>\n<li>Pressing SW1 and SW2 together should reset the frequency to 1Hz<\/li>\n<li>Take steps to avoid switch bounce. You may use a <code>Timer<\/code> or better, a <code>Timeout<\/code>. Do not use <code>wait()<\/code><\/li>\n<\/ul>\n<p><strong>Tips:<\/strong><\/p>\n<p>Use one state machine per switch \/ timer pair. You might want to show the tutor your state-diagram before you write the code. Document this in your log book. Include any state diagrams.<\/p>\n<p>You can use a <code>Ticker<\/code> to flash an LED. To change the frequency, you must <em>detach<\/em> the ticker and attach it again with the new rate.<\/p>\n<p>Watch out for race conditions. Remember to temporarily turn off interrupts to protect critical sections.<\/p>\n<p>Remember you can \u201cdetach\u201d interrupt sources in mbed. A switch interrupt could detach itself and attach a Timeout. When the timeout ISR runs, it detaches itself, and reattaches the switch interrupt etc.. etc.. One approach is that each \u201cstate becomes a function\u201d. I\u2019ll leave you to think about that one, but I give hints when asked \ud83d\ude09<\/p>\n<p>State diagrams can be sketched on paper, photographed with a smartphone or tablet and inserted into your logbook \/ notes.<\/p>\n<p>You are strongly advised to complete this task before the next lab session. Remember you should spend approximately 16 hours \/ week on each module.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Table of Contents Interrupts &#8211; a first look Although simple, polling has some major disadvantages: It uses a lot of CPU resource even when there are no changes in the inputs. This is unlike most modern computer systems which are event driven and can idle. The loop cycle time is variable (e.g. due to conditional&hellip; <a class=\"more-link\" href=\"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/microcontrollers\/mbed-os-2\/courses\/level-5-embedded-and-real-time-systems\/performing-real-time-tasks-with-interrupts\/\">Continue reading <span class=\"screen-reader-text\">Performing Real-Time Tasks with Interrupts<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"parent":719,"menu_order":3,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-788","page","type-page","status-publish","hentry","entry"],"_links":{"self":[{"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/pages\/788","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/comments?post=788"}],"version-history":[{"count":12,"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/pages\/788\/revisions"}],"predecessor-version":[{"id":828,"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/pages\/788\/revisions\/828"}],"up":[{"embeddable":true,"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/pages\/719"}],"wp:attachment":[{"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/media?parent=788"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}