| 262 | | Pour vous aider, voici un code qui fait clignoter la LED du `GPIO04` dans le module noyau. |
| 263 | | * Pour l'accès aux GPIOs vous voyez que l'on peut simplifier les calculs d'adresses en utilisant une structure représentant l'organisation des registres. |
| 264 | | * Vous noterez également que l'adresse physique de base des GPIO (ici 0x20200000) est mappé dans l'espace virtuel du noyau à l'adresse '''io_addresse'''. |
| 265 | | * Vous trouvez aussi le moyen de faire faire périodiquement une fonction au système grâce à une file d'attente temporelle. |
| 266 | | Inspirez-vous de code pour votre pilote. |
| | 280 | Nous devons pouvoir accéder aux registres de configuration des GPIO. |
| | 281 | * Pour l'accès aux GPIOs, vous voyez que l'on peut simplifier les calculs d'adresses en utilisant une structure représentant l'organisation des registres. |
| | 282 | * Vous noterez également que l'adresse physique de base des GPIO (GPIO_BASE 0x20200000) est mappée dans l'espace virtuel du noyau à l'adresse '''io_addresse''' et récupérer avec la macro du noyau `__io_address()`. |
| | 309 | *gpio_regs = (struct gpio_s *)__io_address(GPIO_BASE); |
| | 310 | }}} |
| | 311 | |
| | 312 | Les deux fonctions `gpio_fsel()` et `gpio_write()` possibles sont données juste après. Vous pouvez voir comment exploiter la structure. |
| | 313 | Nous vous laissons le soin de faire `gpio_read()`, puis d'invoquer ces fonctions dans les fonctions `open_ledbp()`, `read_ledbp()`, etc. |
| | 314 | |
| | 315 | {{{#!c |
| | 316 | static void gpio_fsel(int pin, int fun) |
| | 317 | { |
| | 318 | uint32_t reg = pin / 10; |
| | 319 | uint32_t bit = (pin % 10) * 3; |
| | 320 | uint32_t mask = 0b111 << bit; |
| | 321 | gpio_regs->gpfsel[reg] = (gpio_regs->gpfsel[reg] & ~mask) | ((fun << bit) & mask); |
| | 322 | } |
| | 323 | |
| | 324 | static void gpio_write(int pin, bool val) |
| | 325 | { |
| | 326 | if (val) |
| | 327 | gpio_regs->gpset[pin / 32] = (1 << (pin % 32)); |
| | 328 | else |
| | 329 | gpio_regs->gpclr[pin / 32] = (1 << (pin % 32)); |
| | 330 | } |
| | 331 | }}} |
| | 332 | |
| | 333 | == Étape 5 : Usage d'un timer dans le noyau pour faire clignoter (optionnel) == |
| | 334 | |
| | 335 | Le code suivant fait clignoter la led GPIO04. |
| | 336 | Vous pouvez adapter votre driver, pour demander un clignotement plutôt qu'un allumage. |
| | 337 | En effet, il existe un moyen de faire faire périodiquement une fonction au système grâce à une file d'attente temporelle. |
| | 338 | Inspirez-vous de code pour votre pilote. |
| | 339 | |
| | 340 | {{{#!c |
| | 341 | #include <linux/module.h> |
| | 342 | #include <linux/init.h> |
| | 343 | #include <asm/io.h> |
| | 344 | #include <mach/platform.h> |
| | 345 | |
| | 346 | static const int LED0 = 2; |
| | 347 | |
| | 348 | //------------------------------------------------------------------------------ |
| | 349 | // GPIO ACCES |
| | 350 | //------------------------------------------------------------------------------ |
| | 351 | |
| | 352 | struct gpio_s |
| | 353 | { |
| | 354 | uint32_t gpfsel[7]; |
| | 355 | uint32_t gpset[3]; |
| | 356 | uint32_t gpclr[3]; |
| | 357 | uint32_t gplev[3]; |
| | 358 | uint32_t gpeds[3]; |
| | 359 | uint32_t gpren[3]; |
| | 360 | uint32_t gpfen[3]; |
| | 361 | uint32_t gphen[3]; |
| | 362 | uint32_t gplen[3]; |
| | 363 | uint32_t gparen[3]; |
| | 364 | uint32_t gpafen[3]; |
| | 365 | uint32_t gppud[1]; |
| | 366 | uint32_t gppudclk[3]; |
| | 367 | uint32_t test[1]; |
| | 368 | } |