2017-06-01 2 views
2

Je suis en train de lire et écrire des registres sur mon ARM9 (SAM9X25) suivant ces étapes: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3750.html
j'ai fini avec le code suivant:ECRITURE et registres de lecture sous Linux sur ARM

#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 croix compilé mon code dans Ubuntu 16.04 comme si arm-linux-gnueabi-gcc gpio.c -o gpio
Mais j'ai un Segmentation Fault juste après le printf lors de l'exécution du programme sur ma carte.
Je sais que les adresses sont correctes ... Alors, pourquoi ai-je cette erreur?
Est-ce le bon moyen?
Nous vous remercions de votre aide!

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

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/mman.h> 
#include <fcntl.h> 


#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<<LED_PIN)) > 0){ 
     *gpio_output_clear_addr = 1 << LED_PIN; 
    }else{ 
     *gpio_output_set_addr = 1 << LED_PIN; 
    } 

    return 0; 
} 

EDIT:
Réponse du 3) dans les commentaires. Vous devez changer le mmap et les assignations comme si vous voulez travailler avec tous les compensations (: mmap example):

#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 mmap:

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

Et pour l'attribution:

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

Lire ceci: [Accès à l'adresse physique de l'espace utilisateur] (https://stackoverflow.com/questions/12040303/accessing-physical-address-from-user-space) –

+1

vous ne pouvez pas accéder les directement à partir de l'espace d'application comme cela vous pouvez utiliser mmap pour percer un trou à travers l'os, ou écrire un pilote noyau ou exécuter baremetal, mais comme écrit il devrait seg faute. –

Répondre

2

Vous ne pouvez pas accéder aux registres directement, car utiliser Linux MMU et cela créer pour votre application espace d'adressage virtuel qui est différent de l'espace physique d'adresse MCU et l'accès OU Cette zone d'adresse virtuelle provoque un défaut de segmentation.

seule façon d'accéder à ces registres sous Linux (si vous ne voulez pas d'écrire des pilotes du noyau) est d'ouvrir le fichier/dev/mem sous forme de fichier et la carte avec mmap

Par exemple, j'ai une petite bibliothèque de python pour accéder aux registres GPIO sur Atmel SAM MCU gpiosam. Vous pouvez inspirer et le port à C.

+0

Merci beaucoup @vlk! Je pourrais écrire un mmap approprié! Mais j'ai quelques questions à propos de votre bibliothèque. ** 1) ** Je ne comprends pas vraiment ' Gpio._mm [self._addr + registre: self._addr + register + 4] = struct.pack (' Tagadac

+0

** 2) ** Dans la fiche technique, nous pouvons lire: 'La lecture d'un dans PIO_PUSR signifie que le pull-up est désactivé et en lisant un zéro signifie que le pull-up est activé. Donc 'return (self._reg_get (Gpio._PULL_DOWN_STATUS) & self._bitval)> 0' devrait être' return ** not ** (self._reg_get (Gpio._PULL_UP_STATUS) & self._bitval)> 0' ou similaire non? De cette façon, si le registre de bits est '1', vous avez' FALSE' et 'TRUE' à la place. Non? (et même pour le pull-down) – Tagadac

+0

** 3) ** Pourquoi changer '_PIO_OFFSET' de' 0xFFFFF000' à '0xFFFFFA00' (Banque D) aboutit à' mmap: Argument invalide'? Merci de votre aide ! – Tagadac

1

busybox devmem

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

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

Utilisation: lire 4 octets de l'adresse physique 0x12345678:

sudo busybox devmem 0x12345678 

Ecrire 0x9abcdef0 à cette adresse:

sudo busybox devmem 0x12345678 w 0x9abcdef0 

Voir ceci pour quelques conseils sur la façon de le tester: Accessing physical address from user space

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

+0

Nice, merci! Je vais le tester plus tard :) – Tagadac