node programming models - cpe.ku.ac.thcpj/204525/slides/03-programming.pdf · node programming...
TRANSCRIPT
Node Programming Models
Chaiporn Jaikaeo([email protected])
Department of Computer EngineeringKasetsart University
Materials taken from lecture slides by Karl and WilligCliparts taken from openclipart.org
01204525 Wireless Sensor Networks and Internet of Things
Last updated: 2018-09-08
2
Outline•Microcontroller programming◦ Software development cycle
•Operating Systems and Execution environments
•Concurrent programming◦ Event-driven programming model
◦ Multithreaded programming model
◦ Coroutines
3
• Firmware flashing with an external chip programmer
Typical Development Process
Source code(C/Assembly)
Cross Compiler/Assembler
Machine code(hex/binary)
010101011101110110
Microcontroller
Serial/USBport
Chip Programmer
Uploader
4
• Firmware flashing with on-chip bootstrap loader
Typical Development Process
flash memory
BootstrapLoader (BSL)
Microcontroller
Serial/USBport
Source code(C/Assembly)
Cross Compiler/Assembler
Machine code(hex/binary)
010101011101110110 Uploader
5
• Script uploading with MicroPython firmware
Typical Development Process
flash memory
MicroPython
Microcontroller
Serial/USBport
Source code(Python)
Uploader
6
OS and Execution Environments•Usual operating system goals◦ Make access to device resources abstract (virtualization)
◦ Protect resources from concurrent access
•Usual means ◦ Protected operation modes of the CPU
◦ Process with separate address spaces
• These are not available in microcontrollers◦ No separate protection modes, no MMU
◦ Would make devices more expensive, more power-hungry
7
Levels of Abstraction •Direct hardware access (bare-metal)◦ Pure C/C++/Assembly
•Hardware abstraction layer◦ E.g., C/C++ using Arduino-provided libraries
• Task scheduling◦ Allows concurrency among multiple tasks in the same app
•Resource Virtualization◦ Makes some limited resources (e.g., timers) virtually available
◦ Memory usually not virtualized
8
Case Study #1: Tmote Sky
9
Case Study #2: IWING-MRFRadio
transceiver
8-bit AVR MicrocontrollerUSB Connector
(for reprogrammingand power)
Analog/Digital sensor connectors
External battery connector
UART Connector
10
Tmote Sky: Schematic
11
IWING-MRF: Schematic
12
Tmote Sky: LED Blinking Code#include <msp430x16x.h>
int main(){
WDTCTL = WDTPW | WDTHOLD;P5DIR |= (1 << 6);for (;;){P5OUT |= (1 << 6);__delay_cycles(500000L);P5OUT &= ~(1 << 6);__delay_cycles(500000L);
}return 0;
}
Make pin P5.6 output
Send logic 1 to pin P5.6
Send logic 0 to pin P5.6
Stop watchdog timer
13
IWING-MRF: LED Blinking Code#include <avr/io.h>#include <util/delay.h>
#define F_CPU 12000000L
main(){
DDRD |= (1 << 5);while (1){
PORTD &= ~(1 << 5);_delay_ms(500);PORTD |= (1 << 5);_delay_ms(500);
}}
Make pin PD5 output
Send logic 1 to pin PD5
Send logic 0 to pin PD5
14
Tmote Sky: Compiling• Tmote Sky uses MSP430 chip by Texas Instruments
• It requires MSP430 cross-compiler
$ msp430-gcc -mmcu=msp430f1611 -o blink.elf blink.c
15
IWING-MRF: Compiling• IWING-MRF uses AVR chip by Atmel/Microchip
• It requires the AVR cross-compiler
$ avr-gcc -mmcu=atmega328p –o blink.elf blink.c
16
Hardware Abstraction Layer
Tmote Sky Hardware
Tmote Sky API Implementation
17
Hardware Abstraction Layer
IWING-MRF Hardware
IWING-MRF API Implementation
18
LED Blinking: Arduino Code•With appropriate Arduino ports for MSP430 and AVR
provided, the following code can be used in both TmoteSky and IWING-MRF with minimal change
#define LED 13
void setup() {pinMode(LED,OUTPUT);
}
void loop() {digitalWrite(LED,HIGH);delay(500);digitalWrite(LED,LOW);delay(500);
}
19
LED Blinking: MicroPython Code•MicroPython provides both a hardware abstraction layer
and an execution environment
•A Python "app" is interpreted by MicroPython firmware
from machine import Pinfrom time import sleep
led = Pin(2,Pin.OUT)while True:
led.value(1)sleep(0.5)led.value(0)sleep(0.5)
20
Concurrent Programming Models• IoT applications tend to get too complex to be
implemented as a sequential program
• E.g., the app needs to◦ Monitor various sensor status
◦ Wait for and respond to user switch
◦ Wait for and respond to requests from the network
21
Example: Concurrent Tasks•Create an application that performs the following subtasks
concurrently◦ Subtask#1
repeatedly turns LED on and off every 500 milliseconds
◦ Subtask#2
when the switch (IO0) is pressed, displays the number of total switch presses on the OLED display
22
Setting Up LED and Switch•On-board LED (GPIO2)
•On-board SW (GPIO0)
from machine import Pinled = Pin(2, Pin.OUT)led.value(1) # turn LED onled.value(0) # turn LED off
from machine import Pinsw = Pin(0, Pin.IN)if sw.value == 0:
print("SW is pressed")else:
print("SW is released")
23
Wiring the OLED Display• Connect VCC/GND to OLED board
• Connect Pins GPIO4 and GPIO5 to OLED's SCL and SDA, respectively
24
Controlling the OLED Display
from machine import Pin, I2Cimport ssd1306import time
i2c = I2C(scl=Pin(4), sda=Pin(5))oled = ssd1306.SSD1306_I2C(128, 64, i2c)
while True:oled.text("Hello",0,0) # display "Hello" at (0,0)time.sleep(1)oled.fill(0) # clear screenoled.text("Goodbye",0,10) # display "Goodbye" at (0,10)oled.show()time.sleep(1)oled.fill(0) # clear screenoled.show()
25
Subtask #1 Only (No Concurrency)
repeatedly turns LED on and off every 500 milliseconds
from machine import Pinimport time
led = Pin(2,Pin.OUT)while True:
led.value(1)time.sleep(0.5)led.value(0)time.sleep(0.5)
26
Subtask #2 Only (No Concurrency)displays total switch count on OLED
from machine import Pin, I2Cimport ssd1306import time
sw = Pin(0, Pin.IN)i2c = I2C(scl=Pin(4), sda=Pin(5))oled = ssd1306.SSD1306_I2C(128, 64, i2c)count = 0while True:
while sw.value() != 0:time.sleep(0.01) # wait until switch is pressed
count += 1oled.fill(0) # clear screenoled.text(str(count),0,0)oled.show()while sw.value() != 1:
time.sleep(0.01) # wait until switch is released
27
Attempt to Combine Subtasks• Simply combining the
two subtasks in a sequential manner will NOT achieve what we expected
from machine import Pin, I2Cimport ssd1306import time
led = Pin(2, Pin.OUT)sw = Pin(0, Pin.IN)i2c = I2C(scl=Pin(4), sda=Pin(5))oled = ssd1306.SSD1306_I2C(128, 64, i2c)count = 0while True:
# Subtask 1led.value(1)time.sleep(0.5)led.value(0)time.sleep(0.5)
# Subtask 2while sw.value() != 0:
time.sleep(0.01) # wait until switch is pressedcount += 1oled.fill(0) # clear screenoled.text(str(count),0,0)oled.show()while sw.value() != 1:
time.sleep(0.01) # wait until switch is released
blocking
blocking
blocking
blocking
28
Concurrent Programming Models• Event driven
•Multithreading
•Coroutines
29
Event-Driven Model•Perform regular processing or be idle
•React to events when they happen immediately
• To save power, CPU can be put to sleep during idle
Idle/regular processing
Radio event handler
Sensor event handler
30
Event-Driven Codeimport timeimport micropythonfrom machine import Pin, I2C, Timerimport ssd1306
def handle_switch(pin):micropython.schedule(switch_pressed,None)
def handle_timer(timer):micropython.schedule(timer_fired,None)
def switch_pressed(arg):global countcount += 1oled.fill(0)oled.text(str(count),0,0)oled.show()time.sleep(0.01) # prevent sw bouncing
def timer_fired(arg):led.value(1-led.value())
# I/O setupled = Pin(2, Pin.OUT)sw = Pin(0, Pin.IN)i2c = I2C(scl=Pin(4), sda=Pin(5))oled = ssd1306.SSD1306_I2C(128,64,i2c)count = 0
# initialize event triggerstimer = Timer(0)timer.init(
period=500,mode=Timer.PERIODIC,callback=handle_timer)
sw.irq(trigger=Pin.IRQ_FALLING,handler=handle_switch)
while True:pass
Ideally, CPU should go to sleep here instead of idle loop
31
Problem with Event-Driven Model•Unstructured code flow
Very much like programming with GOTOs!
32
Multithreading Model•Based on interrupts, context
switching
•Difficulties◦ Too many context switches
◦ Each process required its own stack
•Not much of a problem on modern microcontrollers
Handle subtask#1 Handle subtask#2
OS-mediatedprocess switching
33
Multithreading Codeimport _threadfrom machine import Pin, I2Cimport ssd1306import time
def blink_led():while True:
led.value(1)time.sleep(.5)led.value(0)time.sleep(.5)
def count_switch():count = 0while True:
while sw.value() != 0:time.sleep(0.01) # wait until sw is pressed
count += 1oled.fill(0) # clear screenoled.text(str(count),0,0)oled.show()while sw.value() != 1:
time.sleep(0.01) # wait until sw is released
# I/O setupled = Pin(2, Pin.OUT)sw = Pin(0, Pin.IN)i2c = I2C(scl=Pin(4), sda=Pin(5))oled = ssd1306.SSD1306_I2C(128, 64, i2c)
# create and run threads_thread.start_new_thread(blink_led, ())_thread.start_new_thread(count_switch, ())
while True:pass
Thread #1
Thread #2
34
Problems with Multithreads• Each thread requires its own stack to hold local variables◦ Not much of a problem for modern microcontrollers
Thread 1 Thread 2 Thread 3 Thread 4
35
Problems with Multithreads•Code employing preemptive threading library must ensure
thread-safe operations
36
Coroutines•Generalized subroutines◦ Allow multiple entry points for suspending and resuming execution
at certain locations
•Can be used to implement:◦ Cooperative multitasking
◦ Actor model of concurrency
•No worry about thread-safe operations
36
37
Routine 2
Subroutines vs. Coroutines
Routine 1
Subroutines
Routine 2Routine 1
Coroutines
call
call
return
return
yield yield
yield
yield
“Subroutines are a special case of coroutines.”--Donald Knuth
Fundamental Algorithms. The Art of Computer Programming
38
Coroutines in MicroPython•Can be achieved using◦ The uasyncio module with async/await pattern
◦ Generators
39
Coroutines: Code•Require uasyncio module
from machine import Pin, I2Cimport uasyncio as asyncioimport ssd1306
async def blink_led():while True:
await asyncio.sleep_ms(500)led.value(1-led.value())
async def count_switch():count = 0while True:
while sw.value() != 0:await asyncio.sleep_ms(1)
count += 1oled.fill(0) # clear screenoled.text(str(count),0,0)oled.show()while sw.value() == 0:
await asyncio.sleep_ms(1)
# I/O setupled = Pin(2,Pin.OUT)sw = Pin(0,Pin.IN)i2c = I2C(scl=Pin(4), sda=Pin(5))oled = ssd1306.SSD1306_I2C(128,64,i2c)
# create and run async tasksloop = asyncio.get_event_loop()loop.create_task(blink_led())loop.create_task(count_switch())loop.run_forever()
40
Conclusion•Microcontroller programming requires cross-compiler to
build a firmware, which must be uploaded to the chip
• IoT devices usually do not require full-featured operating systems; only hardware abstraction and task scheduling
•Hardware abstraction allows code reuse across different platforms
•Complex applications often require concurrency◦ Event-driven programming model
◦ Multithreaded programming model
◦ Coroutines