embarqu´ee 14/16 J.-M Friedt
Informatique embarqu´ ee 14/16
J.-M Friedt
FEMTO-ST/d´epartement temps-fr´equence jmfriedt@femto-st.fr
transparents `ajmfriedt.free.fr
20 mars 2018
1 / 17
embarqu´ee 14/16
J.-M Friedt
Acc` es m´ emoire par le noyau
• Liste des ressources occup´ees
# cat /proc/iomem ...
01c20800-01c20bff : /soc@01c00000/pinctrl@01c20800
• Requˆete de ressource par un pilote
#d e f i n e PWM BASE 0 x 0 1 c 2 0 c 0 0
i n t h e l l o s t a r t ( ) // i n i t m o d u l e ( v o i d )
{s t a=r e q u e s t m e m r e g i o n (PWM BASE, 1 2 ," PWM t e s t ") ; i f ( s t a==NULL )
p r i n t k ( KERN ALERT " mem r e q u e s t f a i l e d ") ; e l s e
{j m f g p i o = ( u32 ) i o r e m a p (PWM BASE, 1 2 ) ;
w r i t e l ((1< <4) , (v o i d∗) ( j m f g p i o ) ) ; // 24000/120=200 kHz w r i t e l ((100< <16) +50 ,(v o i d∗) ( j m f g p i o +4) ) ;
} r e t u r n 0 ; }
# cat /proc/iomem
01c20800-01c20bff : /soc@01c00000/pinctrl@01c20800 ...
01c20c00-01c20c0b : PWM test
embarqu´ee 14/16
J.-M Friedt
Acc` es aux GPIO par le noyau :
gpiolib
Configuration du noyau Linux pour int´egrergpiolib
CONFIG_GPIO_ZYNQ:
Say yes here to support Xilinx Zynq GPIO controller.
Symbol: GPIO_ZYNQ [=y]
Type : tristate
Prompt: Xilinx Zynq GPIO support Location:
-> Device Drivers
-> GPIO Support (GPIOLIB [=y]) -> Memory mapped GPIO drivers Defined at drivers/gpio/Kconfig:514
Depends on: GPIOLIB [=y] && HAS_IOMEM [=y] && (ARCH_ZYNQ [=y] || \ ARCH_ZYNQMP)
Selects: GPIOLIB_IRQCHIP [=y]
Pour utiliser PS-MIO Redpitaya : 906+broche (comme en espace utilisateur)
3 / 17
embarqu´ee 14/16
J.-M Friedt
Acc` es aux GPIO par le noyau :
gpiolib
Le noyau fournit des m´ethodes pour acc´eder aux GPIO :
#i n c l u d e <l i n u x / g p i o . h>
i n t m y g p i o =906+7; // GPIO ID
g p i o i s v a l i d ( m y g p i o ) ;
g p i o r e q u e s t o n e ( m y g p i o , GPIOF OUT INIT LOW , " j m f _ g p i o ") ; g p i o s e t v a l u e ( m y g p i o , j m f s t a t ) ;
g p i o f r e e ( m y g p i o ) ;
1 V´erifier si le GPIO existe sur cette architecture (906+pin)
2 Requ´erir la broche (direction, ´etat par d´efaut)
3 Manipuler l’´etat de la broche
4 Relacher la ressource
MODULE LICENSE (" GPL ") ;
sinon
[ 525.704550] 4mymod_version_gpiolib: module license ’unspecified’ taints kern.
[ 525.711983] Disabling lock debugging due to kernel taint
[ 525.717944] 4mymod_version_gpiolib: Unknown symbol gpiod_set_raw_value (err ) [ 525.725256] 4mymod_version_gpiolib: Unknown symbol gpio_free (err 0) [ 525.731627] 4mymod_version_gpiolib: Unknown symbol gpio_request_one (err 0) [ 525.738610] 4mymod_version_gpiolib: Unknown symbol gpio_to_desc (err 0)
embarqu´ee 14/16
J.-M Friedt
Module noyau : gestion des
interruptions
Seul un module noyau peut acc´eder aux interruptions du processeur (exemple : interruption 7 est associ´ee `a la broche 10 du port parall`ele).
jmfriedt@(none):~$ cat /proc/interrupts | grep parp 7: 0 IO-APIC-edge parport0
qui se g`ere par1
#d e f i n e PARALLEL PORT INTERRUPT 7
#d e f i n e BASEPORT 0 x 3 7 8
i n t s =0;
s t a t i c i n t i n t h a n d l e r (v o i d){p r i n t k (" > > > P A R A L L E L P O R T INT \ n ") ; s =1;}
s t a t i c i n t i n i t j m f p p o r t i n i t m o d u l e (v o i d){ r e t = r e q u e s t i r q ( PARALLEL PORT INTERRUPT , &i n t h a n d l e r ,
SA INTERRUPT , " p a r a l l e l p o r t ", NULL ) ; e n a b l e i r q ( 7 ) ;
o u t b p ( 0 x10 , BASEPORT + 2 ) ; }
s t a t i c s s i z e t s k e l e t o n r e a d (s t r u c t f i l e ∗f i l e , c h a r∗b u f , s i z e t c o u n t , l o f f t ∗p p o s ){
[ . . . ]
do{}w h i l e ( s o r t i r ==0) ; // i n t e r r u p t i b l e s l e e p o n (& s k e l e t o n w a i t ) ; e r r = c o p y t o u s e r ( b u f , s t r i n g , c o u n t e r ) ;
. . . }
1. www.captain.at/howto-linux-device-driver-template-skeleton.php
5 / 17
embarqu´ee 14/16
J.-M Friedt
Interruptions et gpiolib
(Probl`eme d’incompatibilit´e avec Xenomai sur Repditaya pour le moment ...) m y g p i o =(’ B ’−’ A ’)∗32+2; // PB2
e r r= g p i o i s v a l i d ( m y g p i o ) ;
e r r=g p i o r e q u e s t o n e ( m y g p i o , GPIOF IN , " j m f _ i r q ") ; i r q = g p i o t o i r q ( m y g p i o ) ;
i r q s e t i r q t y p e ( i r q , IRQ TYPE EDGE BOTH ) ;
e r r = r e q u e s t i r q ( i r q , i r q h a n d l e r , IRQF SHARED , " G P I O jmf→
,→", &d e v i d ) ; . . .
f r e e i r q ( i r q ,& d e v i d ) ;
g p i o f r e e ( m y g p i o ) ; // l i b e r e GPIO
appellerairq handlerchaque fois que l’interruption se d´eclenche.
irq handlerfinit par return IRQ HANDLED;
[ 4446.692969] gpio_request 34=0 [ 4446.696059] gpio_to_irq=47 [ 4446.698827] finished IRQ: error=0
# cat /proc/interrupts ...
47: 1 sunxi_pio_edge 16 Edge GPIO jmf
embarqu´ee 14/16
J.-M Friedt
Les signaux : pr´ evenir d’un
´
ev` enement
Equivalent logiciel : les signaux´
#i n c l u d e <s i g n a l . h>
v o i d m y h a n d l e r (i n t s i g ) {
p r i n t f (" I got SIGINT , n u m b e r % d \ n ", s i g ) ;}
i n t main ( v o i d ) {
s i g n a l ( SIGINT , m y h a n d l e r ) ; w h i l e ( 1 ) {}
}
qui donne chaque fois qu’on appuie sur CTRL-C (tuer parkill -9 PID) jmfriedt@(none):~$ ./sigint
I got SIGINT, number 2 I got SIGINT, number 2
7 / 17
embarqu´ee 14/16
J.-M Friedt
Distribution du signal
d’interruption
Distribution d’interruption par signaux
1 un unique point de gestion d’une interruption mat´erielle (module noyau)
2 une multitude de processus utilisateurs r´eagissent `a l’interruption
3 chaque processus s’enregistre aupr`es du module
4 le module r´eagit au plus vite `a l’interruption ...
5 ... puis, quand il a le temps, pr´evient tous les processus identif´es par leur ID.
embarqu´ee 14/16
J.-M Friedt
G´ en´ eration du signal
Depuis le noyau : identifier le processus par son PID et envoyer le signal
s t r u c t s i g i n f o s i n f o ; s t r u c t t a s k s t r u c t∗t a s k ;
// on c h e r c h e PID au c a s ou ‘ l e p r o c e s s a u r a i t d i s p a r u memset(& s i n f o , 0 , s i z e o f(s t r u c t s i g i n f o ) ) ;
s i n f o . s i s i g n o = SIGUSR1 ; // d e p u i s s o n e n r e g i s t r e m e n t s i n f o . s i c o d e = SI USER ;
t a s k = p i d t a s k ( f i n d v p i d ( p i d ) , PIDTYPE PID ) ; i f ( t a s k == NULL ) {p r i n f o (" C a n n o t f i n d PID \ r \ n ") ;}
e l s e s e n d s i g i n f o ( SIGUSR1 , &s i n f o , t a s k ) ;
Processus potentiellement lent ⇒ex´ecuter dans une sous-tˆache
s t a t i c v o i d d o s o m e t h i n g (u n s i g n e d l o n g d a t a ) {. . . } i n t h e l l o s t a r t ( ) // i n i t m o d u l e ( v o i d )
{INIT WORK(& i r q w o r k , d o s o m e t h i n g ) ;
r e q u e s t i r q ( i r q , i r q h a n d l e r , IRQF SHARED , " G P I O jmf ", & i r q i d ) ; . . .
}
s t a t i c i r q r e t u r n t i r q h a n d l e r (i n t i r q , v o i d∗d e v i d )
{s c h e d u l e w o r k (& i r q w o r k ) ; // on l e f e r a quand on a u r a l e te m p s r e t u r n IRQ HANDLED ;
}
9 / 17
embarqu´ee 14/16
J.-M Friedt
Distribution du signal
d’interruption
Solution alternative (thread)
1 un processus d´esire ˆetre inform´e de l’interruption au cours de son ex´ecution
2 g´en`ere un thread qui bloque en lecture sur un point d’entr´ee de /sys/class ou/dev
3 quand l’interruption se d´eclenche, le module d´ebloque le processus en lecture ...2 3
4 ... et le thread pr´evient son p`ere de l’´ev`enement.
2. http://www.makelinux.net/ldd3/chp-6-sect-2
3. http://www.makelinux.net/ldd3/chp-5-sect-3pour les s´emaphores en espace noyau
embarqu´ee 14/16
J.-M Friedt
S´ emaphore
... pour d´ebloquer la lecture, ici sur un timer.
s t a t i c i n t d e v r e a d (s t r u c t f i l e ∗f i l ,c h a r ∗b u f f , s i z e t l e n→ ,→, l o f f t ∗o f f )
{
down (&mysem ) ; . . .
r e t u r n l e n ; }
s t a t i c v o i d d o s o m e t h i n g (u n s i g n e d l o n g d a t a ) {up (&mysem ) ;}
i n t h e l l o s t a r t ( ) // i n i t m o d u l e ( v o i d )
{s e m a i n i t (&mysem , 1 ) ; /∗ i n i t t h e s e m a p h o r e a s f u l l ∗/
// s i m u l e d e c l . i n t e r r u p t i o n p o u r d e b l o q u e r s e m a p h o r e i n i t t i m e r o n s t a c k (& e x p t i m e r ) ;
e x p t i m e r . e x p i r e s = j i f f i e s + d e l a y ∗ HZ ; e x p t i m e r . d a t a = 0 ;
e x p t i m e r . f u n c t i o n = d o s o m e t h i n g ; a d d t i m e r (& e x p t i m e r ) ;
r e t u r n t ; }
m o d u l e i n i t ( h e l l o s t a r t ) ;
11 / 17
embarqu´ee 14/16
J.-M Friedt
Protection des donn´ ees
Plusieurs tˆaches g`erent une mˆeme donn´ee⇒risque d’incoh´erence Trois m´ethodes pour prot´eger une donn´ee :
• s´emaphore (compteur)
• mutex (binaire avec passage en mode veille de la tˆache)
• spin-lock (binaire avec test du v´erou)
Producteur-consommateur :
1 une tˆache produit des donn´ees
2 un utilisateur demande ces donn´ees
3 la lecture estbloqu´eetant que les donn´ees n’ont pas ´et´e produites
tableau de donn´ees Production
(e.g. ADC)
Consommation
(e.g. affichage, traitement)
embarqu´ee 14/16
J.-M Friedt
Protection des donn´ ees :
s´ emaphore
• Abaisser le s´emaphore bloque s’il est nul
• Relever le s´emaphore d´ebloque le processus en attent
• Le compteur peut croˆıtre pour d´ebloquer plusieurs processus
#include <linux/semaphore.h>
struct semaphore mysem;
sema_init(&mysem, 0); // init the semaphore as empty down (&mysem); // bloque le consommateur
...
up (&mysem); // producteur debloque
13 / 17
embarqu´ee 14/16
J.-M Friedt
Protection des donn´ ees : mutex
Bloque-d´ebloque une zone de code qui acc`ede `a une ressource commune :
une seule instance d’un mutex peut acc´eder `a ce segment de code `a un instant donn´e
#include <linux/mutex.h>
struct mutex mymutex;
mutex_init(&mymutex);
mutex_lock(&mymutex); // bloque ...
mutex_unlock(&mymutex); // debloque
embarqu´ee 14/16
J.-M Friedt
Protection des donn´ ees : spinlock
Le mutex met la tˆache en veille ⇒proc´edure lourde et lente
Pour des op´erations rapides (interruptions), sonder continuellement le v´erou :spinlock
#include <linux/spinlock.h>
static DEFINE_SPINLOCK(myspin);
spin_lock_init(&myspin);
spin_lock(&myspin);
...
spin_unlock(&myspin);
MODULE_LICENSE("GPL");
Probl`eme dedeadlock: deux processus faisant appel `a un m´ecanisme de bloquage sont imbriqu´es.
15 / 17
embarqu´ee 14/16
J.-M Friedt
Protection des donn´ ees : spinlock
Le mutex met la tˆache en veille ⇒proc´edure lourde et lente
Pour des op´erations rapides (interruptions), sonder continuellement le v´erou :spinlock
#include <linux/spinlock.h>
static DEFINE_SPINLOCK(myspin);
spin_lock_init(&myspin);
spin_lock(&myspin);
...
spin_unlock(&myspin);
MODULE_LICENSE("GPL");
...
...
Consommateur Mutex prot`ege S´emaphore bloque Mutex lib`ere
Mutex prot`ege
Mutex lib`ere S´emaphore d´ebloque Producteur
Probl`eme dedeadlock: deux processus faisant appel `a un m´ecanisme de bloquage sont imbriqu´es.
embarqu´ee 14/16
J.-M Friedt
Mise en pratique
1 Mise en pratique degpiolibpour exploiter une broche
2 ... et s’en attribuer l’interruption mat´erielle (complexe `a la lecture de ladatasheet)
3 License GNU pour pouvoir exploiter les fonctionnalit´es d’autres modules noyau (abstraction du mat´eriel)
4 Exploitation des fonctionnalit´es du noyau pour ´echanger avec l’espace utilisateur : s´emaphore et tasklet/timer.
Exercices :
1 requ´erir une broche et la commander par gpiolib
2 faire clignoter cette broche sous contrˆole d’untimerdu noyau
3 clignoter la LED sur d´eclenchement de cette interruptionavec attenteavant de changer `a nouveau d’´etat (debounce)
17 / 17