2017edan85l4 1
2017edan85l4 1
2017edan85l4 1
Embedded Systems
EDAN85: Lecture 4
Contents
embedded software requirements
CPU
Stack
context = state, registers (program counter,
stack pointer/frame), held resources, etc. Code
(Mem)
Data
(Mem)
Concurrency: Threads
Thread
resources needed for Resources
Stack CPU
independent execution
no resource sharing
Example:
the default (standalone) configuration for Microblaze systems in XPS
Pseudo-MPST
use several processors with SPST
sharing and synchronization is possible, with some work
• common AXI bus = shared peripherals
• FSL can be used to exchange data
• mutexes, mailboxes, etc.
primitive interrupt/exception handlers
Example: the dual Microblaze in EDAN15 labs
More than one thread
Cases B, C, D require support for:
• scheduling: priorities, queues, timers
• contexts: TCBs, create, save/restore
• data sharing/synchronization:
locks, shared memory, messages, buffers,...
• protection: memory spaces, access rights, reentrant code
• interrupts/exceptions:
arithmetic, memory access, I/O, timers, etc.
SPMT
T1 T2 T3 T5 T6
Standalone
OS T4 RTOS
Virtual
VP1 VP2 VP3 virtual comm. structure VP4
Platform
Hypervisor
Real
Real Processor Real Interconnect Real Processor
Platform
Hw virtualization
advantages:
• simplified development!
• OS developers develop for the abstract hypervisor
hardware, not for each specific platform
• Hw developers port the hypervisor (microvisor) once,
and get the benefit of having many OS running on it
• more robust systems!
drawback: performance penalty
Example: OKL4 microvisor
2. Handling I/O
To read and output data: essential in embedded systems!
polling (usually single threaded apps):
1. test the peripheral for new data (non-blocking!)
2. handle the new data if it exists
3. move on to other peripherals or activities
4. go back to 1.
interrupts (multi-threaded apps):
1. write a specific function - handler (usually very short)
2. associate it with the desired peripheral (uses interrupts)
3. expect “normal code” to be interleaved with handler calls
I/O types
A. memory mapped I/O (bus I/O)
• located within the normal memory address space
• accessed using regular memory read/writes
• usually offer both polled or interrupt based handling
• some may use DMA to transfer data (become bus masters)
example: gpio, timer on AXI
B. special I/O (port I/O)
• implemented in the processor by specific instructions/lines
example: FSL on MicroBlaze
MB Interrupts Hw
Peripheral Bus
Micro
Periph
INTC 1 Periph 2
Blaze INT IRQ
IRQ IRQ
• Stadalone-Xilkernel/Microblaze: Hw Hw Hw
An example: Xilkernel
Xilkernel overview (I)
POSIX threads API
• pthread_create, join, yield, detach, kill,...
• round-robin or priority scheduling
POSIX semaphores
• sem_init, destroy, wait, trywait, post,...
XSI/POSIX message queues
• msgget, msgctl, msgsnd, msgrcv
XSI/POSIX shared memory
• shmget, shmctl, shmat, shm_dt
POSIX mutex locks
• pthread_mutex_init, destroy, lock, unlock,...
Xilkernel overview (II)
A. dynamic buffer memory management
• faster but less powerful than malloc/free
• bufcreate, bufdestroy, bufmalloc, buffree
B. software timers
• xget_clock_ticks, time, sleep
C. exceptions (limited)
• registered as faults
• faulting threads are killed and the nature of the exception is
reported on the console (in verbose mode)
• custom handlers cannot be registered
D. memory protection (limited)
• automatic + user spec., code/data/io violations, TLB
more on Xilkernel
Initialization
kernel entry point xilkernel_start() in main.c
all user initialization must be done before
(set up hardware cores)
Thread safety
many library and driver routines are NOT thread safe! (not reentrant,
e.g. printf, sprintf, malloc, free,...)
solution: use locks/semaphores to ensure exclusion
Customization
many parameters (max pthreads, semaphores, sched type)
many modules may be individually included (saves memory)
On MicroBlaze the kernel takes between 7 and 22kb
Using Xilkernel with MB
1. build a system with the XPS wizard
a. add an xps_timer
b. select to use interrupts for the timer and other peripherals
you will handle (this will add xps_intc core)
2. create your application in SDK
c. add a new Xilinx application
d. select the xilkernel (in stead of standalone) in the wizard
e. select the POSIX threads demo as a base
f. modify and add the pthreads program
3. configure the BSP in SDK
g. select BSP created by the wizard in the step above
h. configure its parameters (STDIN/OUT, timer and intc instance,
add modules, clock frequency, table of static threads)
andling
pt Xilkernel interrupts
Xilkernel abstracts away primary interrupt handling requirements from the user application.
g Even though the kernel is functional without any interrupts, the system only makes sense when
it is driven by at least one timer interrupt for scheduling. The kernel handles the main timer
interrupt, using it as the kernel tick to perform scheduling. The timer interrupt is initialized and
needstied
at to
least a timer interrupt
the vectoring (xps_timer)
code during system initialization. This kernel pulse provides software timer
more facilities
can be and time-related routines also. Additionally, Xilkernel can handle multiple interrupts
added with xps_intc
when connected through
(xps_gpio, xps_uartlite, xps_spi,an interrupt
...) controller, and works with the xps_intc interrupt
controller core. The following figure shows a basic interrupt service in Xilkernel.
register, unregister, enable, disable, acknowledge
IE = 1
Executing process
gets interrupted
Resumed process
proceeds
IE = 1 X10229
An example with GPIO
#include "xparameters.h"
#include "xmk.h"
#include <stdio.h>
#include <sys/intr.h>
#include "xgpio.h"
// start xilkernel
// enable GPIO interrupts by bit
xilkernel_start();
XGpio_InterruptEnable(&ButtonsInput, 0xFFFFFFFF);
}
// enable GPIO interrupts globally
XGpio_InterruptGlobalEnable(&ButtonsInput);
}
void* my_main(void) {
// xilkernel is started.
// set up interrupt handlers
setUpButtonsHandler(); void setUpButtonsHandler() {
// associate interrupt channel with handler in INTC
// enable interrupts in Microblaze register_int_handler(XPAR_XPS_INTC_0_PUSH_BUTTONS_3BIT_IP2INTC_IRPT_INTR,
microblaze_enable_interrupts(); buttonsHandler, &pbValue);
// enable interrupt channel in INTC
// a simple loop enable_interrupt(XPAR_XPS_INTC_0_PUSH_BUTTONS_3BIT_IP2INTC_IRPT_INTR);
// to check whether the interrupts work }
{
u32 oldB = pbValue;
while(1) { void buttonsHandler(void *p) {
while(oldB == pbValue) { /* busy wait */ }; // read data from the GPIO
xil_printf("buttons pushed %d", pbValue); *(u32*)p = XGpio_DiscreteRead(&ButtonsInput, 1);
oldB = pbValue; // clear interrupt in the GPIO
} XGpio_InterruptClear(&ButtonsInput, 0xFFFFFFFF );
return NULL; // never reached // ack interrupt to the INTC
} acknowledge_interrupt(XPAR_XPS_INTC_0_PUSH_BUTTONS_
3BIT_IP2INTC_IRPT_INTR);
}
OS choices for Nexys4