Assignment title: Information


DIT165 Development of Embedded system 2017-02-16 Exercises and assignments, Part 3 Page nr 1 Exercises and assignments for the course DIT165 Development of Embedded systems _ Part 3 Work package nr 6 : Event driven door automat ( for XCC users) (Total points 10 p) (Note : !! For not XCC user see further on after this part) In this exercises you can write control programs for the MCC12 system with a connected door unit ML13. The unit has the base address of 0xB00. The idea is to design programs, taking care of opening and closing of the door. You will during the exercises develop three different programs with different principles regarding the way of reading events such as sensor (or push button), door opened and door closed event and finally a time out event for the end of a delay function. The programs should be developed in the XCC12 and only be tested and verified in its simulator. If you not have access to work in Windows which is necessary for installing XCC12 there are alternative exercises 6_1alt to 6_4alt further on after 6_4 for you to do. Exercise nr 6_1. Time based control program (exerc_6_1.c) (2p) First you are going to develop a time-based implementation of the automatic door. The door will operate in the following manner:  If someone approaches the door space (button pushed) the door will open.  After the door had been open (in several seconds, controlled by a simple loop) the door should close automatically.  If someone approaches the door space while the door is closing, it shall immediately reopen.  The main structure of the program is described roughly by the following flowchart: The implementation will be done entirely in the programming language C and in one single module (file). Control of the door unit ML13. The door is controlled via four different 8 bits registers which is possible to read from or write to depending on the register. The addresses for the registers is the unit's base address (Address 0xB00) or base address +1. You will find details about the register and what each bit in the different registers are controlling in the XCC12 Help>>Help on XCC12 and IO simulator.DIT165 Development of Embedded system 2017-02-16 Exercises and assignments, Part 3 Page nr 2 In general: Control register: Address 0xB00 (write operation), same as base address for the ML13 unit. By bit 0 you are able to start opening the door, it will open slowly and you can follow the opening process bay watching the LED:s going on. By bit 1 you can start closing the door. Closing and opening of the door could be done anytime even if the door is in its opening or closing phase. Bit 7-2, Not used. Bit 1, CLOSE 1 = Actuate "Close Door" Bit 0, OPEN 1 = Actuate "Open Door" Status register : Address 0xB00 ( read operation). Each bit describes a certain state of the door. For example door is closed, door is opened …You can by this register check the actual state of the door. Bit 7, CLOSING. 1 = The door is closing. Bit 6, OPENING. 1 = Door is opening Bit 5, S2: Sense 2. 1 = Door is closed Bit 4, Not of interest Bit 3, S1: Sense 1. 1 = Door is wide open. Bit 2, Not of interest Bit 1, RIGHT: Sensor B. 1 = Sensor B is activated (Button S2) Bit 0, LEFT: Sensor A. 1 = Sensor A is activated (Button S1) To do: Your task is to write an ordinary control program in C with a structure as the flowchart above views and verify its function in the simulator. For verifying the program, you must connect the door unit ML13 to the simulator. For controlling the door opened time in this first exercise you can use a simple for loop. Exercise 6_2 Event (IRQ) driven control program (exerc_6_2) (3p) In this task you shall develop an event driven implementation of the automatic door. The door will operate in the same manner as before but every event at the door ( push of button, door opened, and so on …) will be indicated by a interrupt request signal from the ML13 unit instead of repeatedly read the control register to determinate if any event had occurred. The IRQ signal is in simulator connected to the IRQ in pin on the CPU card if you on the door unit enable IRQ in menu "Interrupt" on the ML13 unit. Every event in the ML13 module will generate a hardware IRQ signal which is connected to the CPU IRQ in port. The IRQ will, if the system is initiated for allowing interrupts, call for the defined IRQ service routine. The IRQ service routines start address shall be stored in the vector table at the position for the hardware interrupt IRQ (Address 0x3FF2). The IRQ service routine can then check the source for the IRQ-request (Sensor, door closed,..) in the IRQ status register (base address+1) and by use of a global variable send information of which eventDIT165 Development of Embedded system 2017-02-16 Exercises and assignments, Part 3 Page nr 3 in ML13 unit that caused the interrupt to the main control function. (Note: An interrupt function can´t return a value) due to the way it is called. Besides the interrupt from events in ML13 (IRQ) we will also use the microcontrollers Real Timer Clock unit. This clock module can be configured to periodical generate a RTI interrupt (Real Timer Interrupt). For doing this you shall use an assembly – file (ML13_irq_asm_dit165.s12 ) with a number of functions that can be used by calling them by a normal call from your own C-program module as described below. The file could be downloaded from the course homepage in GUL. You can configure the RTC module, through some registers, to generate a timer interrupt every x millisecond. The configuration is in our case done by the function timerSetup() in the assembly file ML13_irq_asm_dit165.s12. . Before calling the assembly function from your C-program module (file) you must :  Included the .s12 file into the project in the XCC12 IDE.  In your C-program declare it in the program head as : extern void timerSetup() The you can call the function from the C-program module as a normal call by : timerSetup();. In this case we also will using the RTC to create a setTimeout(x) function for controlling the door opened time. By calling this function with setTimeout (x), where x is the number of second's delay we wish to create, you start a time delay that will cause a TIME_OUT interrupt to the system after desired time defined by x. The IRQ routine will set the value of a global integer interruptType to TIME_OUT indicating that the door should be closed. [ Just for information if you look through the assembly code: After the call of setTimeout (x) the RTC will generate RTI interrupts with a periodicity depending on the configuration in timerSetup(). At every RTI interrupt the RTI routine (ptimirq) will decrease a counter. After a number of RTI:s the counter will be zero and the function passes the TIME_OUT value to the the global variable (interruptType). By this the main program gets the information of that the delay time is ended and in this case the door shall be closed.] Below is a roughly description of the main structure of the program. The program shall consist of at least two modules (files) one entirely written in C for the main control program including the ML13 interrupt service routines and one for all regarding the timer module written in assembly. The last module you can download from the course home page (ML13_irq_asm_dit165.s12). For the C-module you can download a first draft for the program to use for further develop to a solution ML13_irq_prog_draft.c . Both files should be included in the project when compiled. ML13 configure Wait for an interrupt Interrupt service routines RTCDIT165 Development of Embedded system 2017-02-16 Exercises and assignments, Part 3 Page nr 4 On the course homepage you find the two files to download: ML13_irq_asm_dit165.s12 Routines in assembly for initiate the system for managing of the Real Time Clock module. You should just include the file in your project and use the functions. This module you should just use, not changed anything in it. It shall be included in the project. The module includes the functions: void standby(), _timerSetup() and setTimeout (x). The function void standby() is a routin in assembly that just stop executing of the program until next interrupt call is generated. ML13_irq_prog_draft.c A main program in C to be further developed to a working program for this exercise. The control loop in the main program shall, in the beginning of the loop, call the function, standby(), that's just stops the execution of the program and waits until an interrupt occurs. When a TIME_OUT irq is generated the ptimirq will be executed and set the global variable to TIME_OUT. For all door events ( Sensor A , door opened …) the system is design to call the C-function : __interrupt void ML13_interrupt( void ) In which you need to decide the source for the interrupt (for example door closed, door opened, right sensor pushed…) by reading the ML13_IRQ_Status register and set the value on interrupType to a value corresponding to the interrupt source. The main program continue then after the interrupt routines with the code after standby() and now with a value in interruptType that will be used to determine what to do before it once again run standby(). You should do the following: Create a workplace and a project for this exercise. Include both files above. Continue to develop the C-program in order to get the system working as the first program. In the simulator we just use setTimeout(1) or setTimeout(2) otherwise it will be to long delay. The delay function will generate a TIME_OUT interruptType ( assigning the value of TIME_OUT to the variable) after the delayed time has fulfilled. The best way of working is to first develop a solution without any use of the delay-function. And when that works include a delay by use of the setTimer(x) function. Note: Do not forget to activate interrupt mode in the ML13 unit in the simulator. Exercise 6_3 Non Preemptive Scheduling (Note : Exercises 6_3 shall not be handed in. You do them just to be able to solve the exercises 6_4 and 6_5) During this part, you will be introduced to a simple real-time kernel, RTK12. The kernel could be included to a program that is developed in the XCC12 environment. The program using RTK12 kernel could also be simulated in XCC12 as normal programs. You can find more information about the RTK12 kernel in the XCC12 help system about libraries.DIT165 Development of Embedded system 2017-02-16 Exercises and assignments, Part 3 Page nr 5 A process A RTK12 process has the same appearance as a C function without parameters. However, there are some important differences that you have to consider when programming processes:  A process is not a function in the sense that it can be called from another process (or function).  The execution of a process can, at any time, be interrupted and later continue its executing.  Several processes can share the same features, i.e. calling the same functions read and write to the same variables (global). Please note that the global variables that are shared by multiple processes (or used by functions that are shared by multiple processes) generally must be protected from inconsistent update with mutual exclusion. A typical program for executing of several processes is build up as follows: // RTK12 - application // Non preemptive scheduling #include <_rtk.h> #define TIMESLICE 5 // 5 for simulator mode and 100 for hardware void AtInterrupt(void); // Declaration of the function that is called at the end of every TIMESLICE PROCESS P1(void); // PROCESS is defined in rtk.h as void. PROCESS P2(void); // This is a declaration of the actual processes. // P2 is the process name int main(void){ /* This main function will be executed just once to set up the processes and the kernel. It must contain the following:  Initiate RTK12  Create all processes  Start the kernel RTK12 // for running in simulator or in hardware */ InitKernel(TIMESLICE, AtInterrupt); if( CreateProcess("P1", P1) == -1){ printl("\nCan't create process"); exit(); } if( CreateProcess("P2", P2) == -1){ printl("\nCan't create process"); exit(); } StartKernelForSim(); // This ends the execution of main() return(0); } // End mainDIT165 Development of Embedded system 2017-02-16 Exercises and assignments, Part 3 Page nr 6 // ----------------------------- First process ------------------------------- PROCESS P1(void) { DO_FOREVER // DO_FOREVER defined as while(1) // This is the process loop that normally never should end. { outchar('1'); // A special putchar() function in startup.asm module } } // ----------------------------- Next process ----------------------------- PROCESS P2(void){ DO_FOREVER { _outchar('2'); } } //------------- Interrupt routine called at the end of each TIMESLICE . void AtInterrupt(void){ // Calls by a IRQ –routine after each full TIMESLICE // Decides if time_irq should suspend the running process and start the next process // in QUE or anything else // Doing nothing will make the previous process to continue executing } Exercise 6_3_1 First you should use RTK12 to perform three processes during a "non-preemptive" scheduling strategy. The application of this exercise, consists of a main program, two processes (P1 and P2) and an interrupt handler. The main program follows exactly the structure described above. Note in particular that an interrupt handler must be provided even if, as in this case, nothing special is done at interrupt. We want to illustrate the non-preemptive scheduling and write therefore two processes to be performed sequentially. Note that in general one can't make any assumption about the order in which processes will be started by the real-time kernel. For RTK12 however the rule is that processes are started in the order they created.DIT165 Development of Embedded system 2017-02-16 Exercises and assignments, Part 3 Page nr 7 Processes P1 and P2 are similar, and they look as follows: PROCESS P1(void) { int i; for(i=0;i < 100;i++) _outchar('1'); TerminateProcess(0); } PROCESS P2(void) { int i; for(i=0;i < 100;i++) _outchar('2'); TerminateProcess(0); } The interrupt handler should in this case do nothing, but must be included: void AtInterrupt(void) { } To do : Write a needed main program and the above processes and test to run it in the simulator. For seeing anything you must connect the console to the simulator. Exercise 6_3_2 Preemptive Scheduling , Timesharing Write a main program setting up three processes and write the processes. Each process should be designed to run forever as below: PROCESS P1(void){ DO_FOREVER { // program code; } } Each process should only print out the number of the process using the special function: _outchar('nr') The kernel will then through its Real Time Clock generate interrupts periodical and count the system time. For each time the time reach the end of the time period specified by TIMESLICE the kernel will change execution to the next process if we modify the AtInterrupt() function as shown below.DIT165 Development of Embedded system 2017-02-16 Exercises and assignments, Part 3 Page nr 8 void AtInterrupt(void){ // Call of two kernel functions. For information se lecture OH nr 6_1.pdf in GUL insert_last(Running, &ReadyQ); Running= remque(&ReadyQ); } To do: Write the program and test in the simulator and see what happens. Exercise 6_4 : Use of semaphores ( Hand in as exerc_6_4.c) (1p) In the previous chapter we learned how to implement a parallel programming model in a timesharing system. By considering each program as a process and let a real-time kernel manage these processes, we can, in principle build a multi-tasking system. If the system comprises of a number of independent processes it is relatively simple to implement but this is never the case in reality. In fact, there is usually very close dependencies between the different processes in a real-time system. Often, these dependencies consist of shared global data and special time dependencies. To cope with these dependencies the processes must in a way be synchronize with each other. Process synchronization in RTK12 is done by using semaphores. In RTK12 the Semaphores are implemented as blocking / Queue type. The maximum number of semaphores is given by the constant MAX_SEM_ID defined in the header file rtk.h. The following operations can be performed on a semaphore: void initsem (int id, int count); The first parameter is an identification number between 1 and MAX_SEM_ID. The second parameter assigns an initial value to the semaphore. Each semaphore is initialized once by the main program, this occurs between the execution of InitKernel () and Start Kernel () or StartKernelForSim(). void waitsem (int); The parameter is an identification number as above defined by initsem() . The process performs the wait semaphore specified by the parameter. The routine assumes that the semaphore is initiated by initsem (). void signalsem (int); The parameter is an identification number 1-MAX_SEM_ID. The process signals on the semaphore specified by the parameter. The routine assumes that the semaphore is initiated by initsem (). Time synchronization of processes The task in this exercise is to construct a chain of events of synchronized processes. Processes "P1", "P2", "P3" and "P4" from the previous exercise shall be executed in this order and be repeated in an unfinished chain. The processes must be modified so that they only write one character at a time to the screen. Tip: You can call the semaphore (waitsem (Sx)) in one process while releasing the semaphore by (signalsem (Sx)) in another process. In this way, you can synchronize the execution order. Modify the processes in the previous step so that the printout from the processes changed to '1234123412341234 ... ' etc.. Synchronization is done by using semaphores.DIT165 Development of Embedded system 2017-02-16 Exercises and assignments, Part 3 Page nr 9 Exercise 6_5 controlling the door system with process synchronization (4p) After a series of operations aimed to make you familiar with a real-time kernel and get an idea of how it can be used, it is time for you to solve a minor task namely the controlling of the door as you done previously but now we will split the program to several processes. Overall description. The control of the door ML13 will now be implemented in a C program structured in several processes with the support of the real-time kernel RTK12. We will use semaphores for synchronize between the processes and by that ensure that only processes that for the moment is useful for the system due to the system status. For example if the door is closed its only of interest to check if any pushes the sensor for open the door and no meaning of checking the sensor for opened door. In addition to earlier demand, open and close the door, we have the following demands: The door shall be possible to 'lock' by pushing the key 'l' on the PC keyboard and unlocked if pushing the 'u' key. Locking/unlocking the door may be made at any time and shall be manage by a separate process reading the keyboard. ( Tip : to read the key use the special XCC function _tstchar()) . A way to indicating the status locked / unlocked for the door is to use a global variable (int locked). With "locked" door it means that it can´t be opened by pressing any of the buttons on the ML13. The door should be locked from the start. Below you will find a proposal on how to fundamentally solve the task. You are not bound to in detail follow these steps, however, the "execution model" (see below) should be used in some ways and the idea of several processes shall be adopted. Execution Model The program will be buildup by a number of processes that are synchronized with help of semaphores and has a structure as below figure: In the center we have a main process that provides all control signals to the door. The main process can be synchronized with the processes that check the status of the door unit, preferably with semaphores. The following pseudo-code indicates a possible solution: status-signals from ML13 Checking event 1 Checking event 2 Delay function Main control process Control signals from ML13 Read keyboard Information transferred by use of Semaphores Information transfer by use of a common global variable Control signals to ML13DIT165 Development of Embedded system 2017-02-16 Exercises and assignments, Part 3 Page nr 10 PROCESS manage_door () { systemSetup do forever { enable "open_door_event" -process // (release the semaphore) wait for "open-door" signal // ( wait for the event to occur) open the door; enable "door_opened_event" -process wait for "door-opened signal" wait for 5 seconds close the door } } Note below especially how semaphores can be used to "enable-events". The execution model above shows how a number of processes monitoring the various events that can occur in the door unit. For example:  Sensor is activated  The door is wide open  The door is fully closed ( not necessary to use in this solution) Such a process can be designed, for example, as follows: begin do forever: wait for the event monitoring is enabled by a semaphore; begin do forever if (sensor pushed and not locked) signal (open_the_door_sem) break inner loop else call yield() function// shift to next process end end The "yield" function Most RT operating Systems has a yield-function which when it´s called leaves rest of the calling process TIMESLICE to next executable process in the ready queue. In RTK12 there is no such feature, so you have to write it by yourselves. It is a rather easy function but you have to use a number of functions from the RT Kernel so you just get it here and you can copy it to your program.DIT165 Development of Embedded system 2017-02-16 Exercises and assignments, Part 3 Page nr 11 The code for the function is as below: void yield(int dummy) { // Dummy parameter is for the 'suspend' to work well DISABLE; // can't take process switch here insert_last(Running, &ReadyQ); // Calling Process last in Rea suspend(Running); // Saving context for Calling process dispatch(); // Start next process in ready que } The Sleep() function To create a delay time, in our case a time during which the door is fully open, you can create a function that waits until the RT-kernel system clock reaches a certain time. The function consists of an infinite loop in which it tests if the clock has reached the end time. If not the function call yield() and by that start the next process in the queue. Next time the calling process get execution time the function again tests the time. When the time at last reach the end time the function will end and the calling process can execute further. In our hardware the sleep function will give a delay of (delay*100) ms but in the simulator mode it will longer delays, approximately (delay)* 1 seconds. The following code shows a simple implementation of the "sleep" function: void sleep(int delay){ int wakeup; wakeup = get_rtk_time() + delay; /* sleep for delay * TIMESLICE*/ while(1){ if( wakeup > get_rtk_time() ) yield(0); /* not morning yet... */ else return; } } What to do: You shall develop a C-program that controls the opening and closing of the door with the same demand as in the exercise 6_2. Additional it shall be possible to, via a key on the PC keyboard, at any time lock or unlock the possibility to open the door. The program shall follow the above described principles of using several processes. If you think there is some missing in the description of how the opening/closing of the door shall function feel free to decide by yourself but of course it shall be a realistic way of function. For alternative WP 6 exercises se next page.DIT165 Development of Embedded system 2017-02-16 Exercises and assignments, Part 3 Page nr 12 Alternative WP 6 exercises for those not using the Windows based XCC12 IDE for a MCC12 CPU. Below is a number of exercises that could be done of you not having access to XC12 IDE. Exercise 6_1alt (exerc 6_1alt.c) Time based control program (2p) In this first exercise you should develop a draft for a program, possible to compile but not possible to run or test. You should just show and explain the solution for the TA. You shall develop a time-based implementation of the automatic door. The door will operate in the following manner:  If someone approaches the door space (button S1 /S2 pushed) the door will open.  After the door had been open (in several seconds, controlled by a simple loop) the door should close automatically.  If someone approaches the door space while the door is closing, it shall immediately reopen.  The main structure of the program is described roughly by the following flowchart: The implementation will be done entirely in the programming language C and in one single module (file). Control of the door unit ML13. The door is connected to the computer system and controlled via four different 8 bits registers which is possible to read or write to depending on the register. The addresses for the registers is the units base address ( Address 0xB00 ) or base address +1. In general: Control register: Address 0xB00 (write operation). By bit 0 you are able to start opening the door, it will open slowly and you can follow the opening process bay watching the LED:s going on. By bit 1 you can start closing the door. Closing and opening of the door could be done anytime even if the door is in its opening or closing phase. Bit 7-2, Not used. Bit 1, CLOSE write 1 = > Actuate "Close Door" Bit 0, OPEN write 1 = >Actuate "Open Door"DIT165 Development of Embedded system 2017-02-16 Exercises and assignments, Part 3 Page nr 13 Status register : Address 0xB00 ( read operation). Each bit is represented the state of the door. For example door is closed, door is opened …You can by reading the bits in this register check the actual state of the door. Bit 7, CLOSING. 1 = The door is closing. Bit 6, OPENING. 1 = Door is opening Bit 5, S2: Sense 2. 1 = Door is closed Bit 4, Not of interest Bit 3, S1: Sense 1. 1 = Door is wide open. Bit 2, Not of interest Bit 1, RIGHT: Sensor B. 1 = Sensor B is activated (Button S2) Bit 0, LEFT: Sensor A. 1 = Sensor A is activated (Button S1) To do: Your task is to write a draft for a control program. Below you have a program head with some declarations and other initiations. Try to make a draft control program that solve the problem with a structure that the flowchart above views. The Dalay() function can be implemented as a simple for loop with a conter. Compile the program to ensure the syntax. You can´t test the program. The only thing you can do is to explain the program to the TA and they will respond if it seems to be a working solution or not. If rather good he will give you a pass code and you can hand in the solution. #define ML13_Status 0x0B00 #define ML13_Control 0x0B00 #define read_control *((char *)ML13_Status) #define set_control(x) *((char *)ML13_Control)=x void main () { … } Exercise 6_2alt (exerc 6_2alt.c) (1p) At GUL homepage you can find a file sortandfind_wp6_6_2.c The code contained in file performs the following operations: 1. It creates an array of integer numbers with the given number of elements. 2. Fills such array with random integer numbers whose max value is given by the user [STEP 1]. 3. Sorts such array [STEP 2]. 4. Looks for a specific value given by the user using binary search [STEP 3].DIT165 Development of Embedded system 2017-02-16 Exercises and assignments, Part 3 Page nr 14 Answer the following questions: 1. How many threads (in total) are created during the execution of the program? 2. What are lines 13, 14, 16, 21 and 22 intended for? 3. How many parameters are passed to function runner? 4. How can function runner know the values for parameters that, such as max value, are not passed to it? 5. How would the behavior of the program change if line 22 was omitted? To do : Study the program and write your answer in a simple text document exerc6_2alt.txt and view it for the TA and they will give you a pass code if ok. Hand it in together with the other files. Exercise 6_3alt (exerc 6_3alt.c) (2p) Rewrite the application contained in sortandfind_wp6_6_2.c so that each of the three main steps (filling the array / sorting and the array / finding the value given by the user) are executed by 3 different threads. Enrich the function run by each thread with a printf( ) stating which of the 3 steps the thread is running. Exercise 6_4alt (exerc 6_4alt.c) (5p) Testing synchronization of threads in C-programming By using a library pthread.h you can create a number of theads (light weight processes) from your program. This task for you is to test threads and some synchronization primitives (semaphores and condition variables). You can find related information about this at: http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html The main task for you is to try to develop a program demonstrating a circular buffer in which it should be possible for threads to write in buffer ( in this case a character) and to read a character (take out) from buffer. All writing and reading from buffer should be without losing data or getting it out in wrong order. The Buffer and its two index number is global Global / Shared variables char buffer[MAX]; // circular buffer . Test for MAX 5 and 10. int write_pos; // index for next character to be put in buffer (put) int read_pos; // index for next character to be read ( fetch ) int count; // the number of characters in buffer not fetched.DIT165 Development of Embedded system 2017-02-16 Exercises and assignments, Part 3 Page nr 15 For synchronization there are some function in the pthread library you can use: pthread_mutex_init(); pthread_mutex_lock(); phtread_mutex_unlock() and pthread_cond_signal(),pthread_cond_wait. To compile the program you have to add the library pthread when compiled as follows: gcc filename.c -o program -lpthread The program should have the following structure and function. A main program for setting up and start running two threads as described below. The main program should after started up the threads continue in a loop as you can see in the program skeleton below. (You find the code at the homepage in file skeleton_wp6_6_4.c) The first thread, producer(), should create characters a,b,c…z ; a,b,c…. and store them in the buffer in a infinitive loop. For every character stored it should call a cond_signal telling other threads that buffer not empty. If buffer full (MAX number of characters in buffer) the thread should wait for a cond_signal 'not full' from the other consuming thread telling that buffer is not full. The second thread, consumer(), should fetch out the character in first position to be fetched from the buffer and print it out in the console window. If no character in buffer it should wait for a cond_signal 'not empty' from the producer thread that signal every time it stores a new character in buffer. The result should be that the program prints out 'abcdef…z''abcd…z' in correct alphabetical order. Between the letters the main() loop prints out the textstring when it is running as the picture in figure below shows one possible example of output. You can find additional information regarding circular buffer, pthread and so on internet