Case Studies For RT Linux
Case Studies For RT Linux
Case Studies For RT Linux
iii
List of Tables
1. Project Co-ordinator .........................................................................................................i
2. Participant List.................................................................................................................i
A-1. Bill of Materials .........................................................................................................14
List of Figures
1-1. The simplest Linux module (threads0.c).................................................................1
1-2. Creation of RT-Linux threads (threads1.c) .............................................................1
1-3. Body of the thread ........................................................................................................2
1-4. Setting of thread priorities...........................................................................................3
1-5. A periodic thread ..........................................................................................................3
3-1. Decalration of struct motor ..........................................................................................8
3-2. Measurement of position............................................................................................11
A-1. Motor controller scheme ............................................................................................13
A-2. Scheme of connectors for motor controller................................................................13
iv
Document presentation
Table 1. Project Co-ordinator
Organisation: UPVLC
Responsible person: Alfons Crespo
Address: Camino Vera, 14. CP: 46022, Valencia, Spain
Phone: +34 9877576
Fax: +34 9877579
E-mail: alfons@disca.upv.es
i
Chapter 1. RT-Linux Threads
1.1. Introduction
This case study introduces RT-Linux basics—threads. First, the concept of Linux kernel
modules is briefly explained and then follows a description of threads creation, chaniging
priorities and periodic threads.
int init_module(void)
{
printk("Init\n");
return 0;
}
void cleanup_module(void)
{
printk("Cleanup\n");
}
MODULE_LICENSE("GPL");
1.3. Threads
RT-Linux implements a POSIX API for threads manipulation. If you are familiar with
POSIX threads library (pthread) in user-space, it should not be a problem for you to
manage threads in RT-Linux. A thread is created by calling the pthread_create()
function. The third parameter of pthread_create() is function which contains the
code executed by the thread.
1
Chapter 1. RT-Linux Threads
int init_module(void)
{
pthread_create(&t1, NULL, &thread_code, "this is thread 1");
rtl_printf("Thread 1 started\n");
pthread_create(&t2, NULL, &thread_code, "this is thread 2");
rtl_printf("Thread 2 started\n");
pthread_create(&t3, NULL, &thread_code, "this is thread 3");
rtl_printf("Thread 3 started\n");
return 0;
}
pthread_attr_init(&attr);
param.sched_priority = 1;
pthread_attr_setschedparam(&attr, ¶m);
pthread_create(&t1, &attr, &thread_code, "this is thread 1");
rtl_printf("Thread 1 started\n");
...
Figure 1-4. Setting of thread priorities
while (!terminate) {
rtl_printf("#");
do_some_work();
pthread_wait_np();
}
This example contains two threads. One thread with high and one thread with low pri-
ority. The high priority thread has shorter period (300 ms) and have also less to do. The
low priority thread has period of 2 seconds and has five times more to do. When an ex-
ample is run, one can see (by watching the printing of # character), that the high priority
thread runs very regularly regardless of whether the low priority thread does something
or not.
For educational purposes, this function is called from another function called
my_function. When we try to insert buggy0 module by running insmod buggy0, an
oops message appears:
4
Chapter 2. Debugging Techniques
Code: a3 00 00 00 00 c3 90 8d 74 26 00 e8 db ff ff ff 31 c0 c3 90
We see that we are accessing memory at address 0, which is the only meaningful in-
formation for this time. To obtain more information, we need to run this oops mes-
sage through ksymoops utility. The easiest way of doing this is running command
dmesg|ksymoops (using a pipe to pass output of dmesg to the ksymoops). Possible
output of this command is shown here:
Unable to handle kernel NULL pointer dereference at virtual address 00000000
c8852075
*pde = 00000000
Oops: 0002
CPU: 0
EIP: 0010:[<c8852075>] Not tainted
Using defaults from ksymoops -t elf32-i386 -a i386
EFLAGS: 00010282
eax: 0000007b ebx: c8852000 ecx: c02dd010 edx: c118a244
esi: 00000000 edi: 00000000 ebp: ffffffea esp: c69c9f18
ds: 0018 es: 0018 ss: 0018
Process insmod (pid: 145, stackpage=c69c9000)
Stack: c8852085 c0118ebb c8852060 080add18 00000100 00000000 080add4c 00000094
00000060 00000060 00000006 c691b1e0 c691a000 c691d000 00000060 c8841000
c8852060 00000160 00000000 00000000 00000000 00000000 00000000 00000000
Call Trace: [<c8852085>] [<c0118ebb>] [<c8852060>] [<c8852060>] [<c0107617>]
Code: a3 00 00 00 00 c3 90 8d 74 26 00 e8 db ff ff ff 31 c0 c3 90
➊ Here we can see a value of an instruction pointer (EIP) and in which function this
vaue is. We see it is in function called buggy, which is 0x10 (16) bytes long and EIP
points to the 5th byte of this function.
➋ Starting with this line, here is a stack trace. These lines show possible order of
called functions. In our example the order shown here differs a little bit from real
situation on the stack, but it can also help us. With a little imagination we see
that the buggy function was called from my_fuction and this was called from
init_module.
➌ On this line is shown exact instruction that caused the fault. Here the value of eax
register was written to address 0x0.
Now we have all needed peaces of information and can continue with Section 2.2.3,
Finding an Error in Source Code.
This command dissassembles the module and prints assembler code intermixed with C
source code. Here is a listing of buggy function:
Disassembly of section .text:
00000000 <buggy>:
void buggy(void)
{
int *p = NULL;
Notes
1. The RT-Linux debugging facility is implemented in module rtl_debug.o.
3.1. Introduction
This article is documentation for a case study for RT-Linux. The goal of this case study is
to control velocity of DC motor with IRC (Incremental Radial Counter) sensor. The motor
is connected to a PC through a simple board consisting of a motor driver and basic logic
circuits. This board is connected to a PC printer port. Schematics for the board can be
found in Appendix A, Schematics of Motor Driver Board.
The case study consists of two programs. One is a RT-Linux kernel module that forms
a real-time part of a controller and the second is a user-space program, which displays
current status of the controller to the user and let him to change desired value of veloc-
ity. This program communicates with real-time part via real-time FIFO. The user-space
program is very simple and if someone wants it could be for example nice GUI applica-
tion.
In the following sections we are going to describe parts of the program in more detailed
manner. It can be useful if you can look at the source codes when reading this. There
are lots of comments in the source code and if you don’t understand some part of this
documentation, the comments may help you.
8
Chapter 3. Controller of DC motor
3.2.2. Initialization
Initialization is done in function motor_init. We call the function (method)
start_motor, which initializes the motor structure, mutexes, FIFOs and so on. It also
starts three threads that implement the controller. These threads are:
motor rotates with constant velocity to one direction, than it quickly rotates to other
direction and finally it rotates to the same direction as at beginning.
position
pos_corr
3
pos_corr
2
last_irq_interval
irq
time
sample 0 sample 1 sample 2 sample 3 sample 4
Figure 3-2. Measurement of position
The simpler version of an algorithm should do only these steps:
• delta_pos is saved to temporal variable and zeroed. When this is being done, inter-
rupts should be disabled.
• The saved value of delta_pos (position change since last sample period) is added to
position.
• Actual motor velocity is computed depending on value of delta_pos.
This method of measuring position gives us the results that are depicted in Figure 3-2
by the black dashed line. The inaccurate measuring of position in this simple version
isn’t big issue. Measuring of a velocity is worse. When motor rotates with constant ve-
locity, the measured velocity isn’t constant and oscillates between two adjacent values.
Because we use measured velocity to close feedback loop in PSD controller, we need
better measuring of velocity.
The better method tries to estimate a real position depending on time elapsed since last
IRQ. In each sampling period the correction of position is calculated. The calculation
is based on linear extrapolation of position between last two IRQs. Variables used in
this calculation are: last_irq_interval, last_irq_time and current time. What
the controller thinks about current position measured in this manner is depicted in
Figure 3-2 by red dash-and-dot line.
Whenever the correction is bigger than one, we trim it to one. This can be seen for
example before sample 4.
3.2.6. Compilation
Compilation of this case study is a little bit harder than of other RT-Linux projects. The
reason of this is that we need 64-bit division. This functionality is contained in libgcc
library. When compiling user-space application, this library is automatically linked with
the application. This is not true with kernel modules and we have explicitly link the
kernel module with libgcc. We can determine the exact name of the library by gcc
-print-libgcc-file-name command. Then we use ld command to link the module with
the library.
ld -r -o motor_ok.o motor.o $(gcc -print-libgcc-file-name)
3.4. Conclusion
In this case study we have developed functional controller of DC motor. There is space
for extending its functionality, but it wouldn’t show us more RT-Linux features. One
could for example write support for changing parameters of PSD regulator by user or
there could be a better (nicer) user-space program.
An important notice: When someone would solve the same task as in this case study in
an industrial environment, he will probably use some hardware for PWM signal gen-
eration and/or position measuring. Almost every modern microprocessor dedicated to
control applications can do these very easily.
Notes
1. In a fact, there are more differences. We don’t have for example a polymorphism
feature, but when we manually create virtual methods table, we can use this feature
in C language too. This is common practice in Linux kernel and some other bigger C
projects.
2. This is quite common practice in Unix programs
2
3
D1 U1 R14 390R
MOTOR-
1 +24V 2 4 VCC 1 3
-24V +Vin +Vout IN OUT
2
1N4007 1 3 C9
+ C1 -Vin -Vout + C2
GND
napajeni 100M/35V 47M/10V R1 100n
CH12405
D U5 78L05 1k D
2
VCC
5
9 2 R3
Vref Vs ISO2
C10 100n 5 7
IN1 IN2 1k 6N137
R2 1k 4 8
R13 390R ISO1 BOOT1 BOOT2
2 8 3 1
8
7
6
GND
C4 C5 C6
6N137 U2
6
MOTOR+ L6203
10n 10n 2N3904
C C
R4 10n
5
1R/2W
U3A
2
3 J2 PC
1
MOTOR- 2 1 MOTOR+
74HCT86 FAZE_2 4 3 FAZE_1 C8
6 5 R11 J3 MOTOR
U3B INT_RQ
5 R5 R6
6 10R/2W 8k2 8k2
2
1
22n
4
U4A 7
74HCT86 R7 1k
2 1
B U3C 14 2 1 B
INT_RQ
10 74HCT14 4 3
8 6 5
9 U4B 8 7
FAZE_1
10 9 R8 1k
74HCT86 4 3 12 11
14 13 VCC
74HCT14
U4C U4D U3D J4 IRC+LED
R9 1k8 13 U4E
Title
74HCT14 motor controller scheme
R10 1k
Size Document Number Rev
1 1
13
Appendix A. Schematics of Motor Driver Board
5 4 3 2 1
D1
FAZE_1
D D
D2
J1
FAZE_2 1
2
3
4
D3 5
6
J2 7
Vcc 8
2 1 9
4 3 10
D4 6 5 11
C 12 C
13
OUT2 PC 14
15
16
17
D5 18
19
20
OUT1 21
22
23
24
J3 25
2 1 CANNON25
B
4 3 B
6 5
8 7
10 9
INKR_2 12 11 INKR_1
14 13
A A
Title
Zapojeni konektoru