Registres WRITE et READ sous Linux sur ARM

J’essaie de lire et d’écrire des registres sur mon ARM9 (SAM9X25) en suivant ces étapes: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3750.html
J’ai fini avec le code suivant:

#include "stdio.h" #define PIO_WPMR_BANK_D 0xFFFFFAE4 // PIO Write Protection Mode Register Bank D #define PIO_PUER_BANK_D 0xFFFFFA64 // PIO Pull-Up Enable Register Bank D #define PIO_PUSR_BANK_D 0xFFFFFA68 // PIO Pull-Up Status Register Bank D #define MASK_LED7 0xFFDFFFFF // LED7 Mask #define DESABLE_WRITE_PROTECTION_BANK_D 0x50494F00 // Desable write protection Bank D int main(void) { printf("test"); unsigned int volatile * const register_PIO_WPMR_BANK_D = (unsigned int *) PIO_WPMR_BANK_D; unsigned int volatile * const register_PIO_PUSR_BANK_D = (unsigned int *) PIO_PUSR_BANK_D; unsigned int volatile * const port_D = (unsigned int *) PIO_PUER_BANK_D; *register_PIO_WPMR_BANK_D = DESABLE_WRITE_PROTECTION_BANK_D; *port_D = *register_PIO_PUSR_BANK_D & MASK_LED7; return 0; } 

Je croise compilé mon code dans Ubuntu 16.04 comme si arm-linux-gnueabi-gcc gpio.c -o gpio
Mais j’ai une Segmentation Fault juste après le printf pendant l’exécution du programme sur mon tableau.
Je sais que les adresses sont exactes … Alors pourquoi ai-je cette erreur?
Est-ce la bonne façon?
Merci de votre aide !

SOLUTION :
Merci à @vlk je pourrais le faire fonctionner! Voici un petit exemple pour basculer une LED:

 #include  #include  #include  #include  #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) #define _PIOD_BANK_D 0xA00 #define _PIO_OFFSET 0xFFFFF000 /* When executing this on the board : long sz = sysconf(_SC_PAGESIZE); printf("%ld\n\r",sz); We have 4096. */ #define _MAP_SIZE 0x1000 // 4096 #define _WPMR_OFFSET 0x0E4 // PIO Write Protection Mode Register Bank D #define _PIO_ENABLE 0x000 #define _PIO_DISABLE 0x004 #define _PIO_STATUS 0x008 #define _OUTPUT_ENABLE 0x010 #define _OUTPUT_DISABLE 0x014 #define _OUTPUT_STATUS 0x018 #define _FILTER_ENABLE 0x020 #define _FILTER_DISABLE 0x024 #define _FILTER_STATUS 0x028 #define _OUTPUT_DATA_SET 0x030 #define _OUTPUT_DATA_CLEAR 0x034 #define _OUTPUT_DATA_STATUS 0x038 #define _PIN_DATA_STATUS 0x03c #define _MULTI_DRIVER_ENABLE 0x050 #define _MULTI_DRIVER_DISABLE 0x054 #define _MULTI_DRIVER_STATUS 0x058 #define _PULL_UP_DISABLE 0x060 #define _PULL_UP_ENABLE 0x064 #define _PULL_UP_STATUS 0x068 #define _PULL_DOWN_DISABLE 0x090 #define _PULL_DOWN_ENABLE 0x094 #define _PULL_DOWN_STATUS 0x098 #define _DISABLE_WRITE_PROTECTION 0x50494F00 // Desable write protection #define LED_PIN 21 int main(void) { volatile void *gpio_addr; volatile unsigned int *gpio_enable_addr; volatile unsigned int *gpio_output_mode_addr; volatile unsigned int *gpio_output_set_addr; volatile unsigned int *gpio_output_clear_addr; volatile unsigned int *gpio_data_status_addr; volatile unsigned int *gpio_write_protection_addr; int fd = open("/dev/mem", O_RDWR|O_SYNC); if (fd < 0){ fprintf(stderr, "Unable to open port\n\r"); exit(fd); } gpio_addr = mmap(NULL, _MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, _PIO_OFFSET); if(gpio_addr == MAP_FAILED){ handle_error("mmap"); } gpio_write_protection_addr = gpio_addr + _PIOD_BANK_D + _WPMR_OFFSET; gpio_enable_addr = gpio_addr + _PIOD_BANK_D + _PIO_ENABLE; gpio_output_mode_addr = gpio_addr + _PIOD_BANK_D + _OUTPUT_ENABLE; gpio_output_set_addr = gpio_addr + _PIOD_BANK_D + _OUTPUT_DATA_SET; gpio_output_clear_addr = gpio_addr + _PIOD_BANK_D + _OUTPUT_DATA_CLEAR; gpio_data_status_addr = gpio_addr + _PIOD_BANK_D + _OUTPUT_DATA_STATUS; *gpio_write_protection_addr = _DISABLE_WRITE_PROTECTION; *gpio_enable_addr = 1 << LED_PIN; *gpio_output_mode_addr = 1 << LED_PIN; // Output // If LED if((*gpio_data_status_addr & (1< 0){ *gpio_output_clear_addr = 1 << LED_PIN; }else{ *gpio_output_set_addr = 1 << LED_PIN; } return 0; } 

MODIFIER :
Répondez pour le 3) dans les commentaires. Vous devez changer le mmap et les assignations comme si vous voulez que cela fonctionne avec tous les décalages (exemple: exemple avec mmap ):

 #define _PIO_OFFSET 0xFFFFFA00 // Instead of 0xFFFFF000 #define _MAP_SIZE 0x1000 // 4096 #define _MAP_MASK (_MAP_SIZE - 1) #define _PA_OFFSET _PIO_OFFSET & ~_MAP_MASK 

Et le mmap:

 gpio_addr = mmap(NULL, _MAP_SIZE + _PIO_OFFSET - _PA_OFFSET, PROT_READ | PROT_WRITE, MAP_SHARED, fd, _PA_OFFSET); 

Et pour l’assignation:

 gpio_enable_addr = gpio_addr + _PIO_OFFSET - (_PA_OFFSET) + _PIO_ENABLE; 

Vous ne pouvez pas accéder directement aux registres, car Linux utilise MMU et cela crée pour votre application un espace d’adressage virtuel différent de celui de l’espace d’adressage MCU physique et l’access en dehors de cet espace d’adressage virtuel entraîne une erreur de segmentation.

Le seul moyen d’accéder à ces registres sous Linux (si vous ne voulez pas écrire les pilotes du kernel) est d’ouvrir le fichier / dev / mem en tant que fichier et de le mapper avec mmap

Par exemple, j’ai une petite bibliothèque python pour accéder aux registres GPIO sur Atmel SAM MCU gpiosam . Vous pouvez l’inspirer et le porter en C.

busybox devmem

busybox devmem est un petit utilitaire CLI que mmaps /dev/mem .

Vous pouvez l’obtenir dans Ubuntu avec: sudo apt-get install busybox

Utilisation: lit 4 octets à partir de l’adresse physique 0x12345678 :

 sudo busybox devmem 0x12345678 

Écrivez 0x9abcdef0 à cette adresse:

 sudo busybox devmem 0x12345678 w 0x9abcdef0 

Voir ceci pour quelques conseils sur la façon de le tester: Accès à une adresse physique à partir de l’espace utilisateur

Également mentionné à l’ adresse : https://unix.stackexchange.com/questions/4948/shell-command-to-read-device-registers