2017-06-01 98 views
2

我想讀和我下面這些步驟ARM9(SAM9X25)寫寄存器:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3750.html
我用下面的代碼結束:寫入和讀取寄存器的Linux基於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; } 


我交叉編譯了代碼在Ubuntu 16.04像這樣arm-linux-gnueabi-gcc gpio.c -o gpio
但我有一個Segmentation Faultprintf之後執行我的主板上的程序。
我知道地址是正確的......那麼,爲什麼我有這個錯誤?
這是好方法嗎?
謝謝你的幫助!

SOLUTION:
謝謝@vlk我可以讓它工作!下面是切換LED一個小例子:

#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; 
} 

編輯:
答案在評論3)。你必須改變MMAP和喜歡,所以如果你想讓它與所有的補償工作的幽會(即: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 

而且MMAP:

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

而對於分配:

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

閱讀:從用戶空間訪問物理地址(https://stackoverflow.com/questions/12040303/accessing-physical-address-from-user-space) –

+1

您無法訪問他們直接從像您可以使用mmap通過操作系統打眼,或者寫一個內核驅動程序或運行baremetal,但寫它應該賽格故障的應用空間。 –

回答

2

你不能直接訪問寄存器,因爲Linux使用MMU,這爲應用程序創建虛擬地址空間比物理MCU地址空間和訪問不同的OU這個虛擬地址空間導致分段錯誤。

必由之路在Linux下訪問這些寄存器(如果你不想寫內核驅動程序)是打開文件/ dev/MEM文件和與mmap

比如我有小Python庫圖吧用於訪問Atmel SAM MCU上的GPIO寄存器gpiosam。您可以啓發和移植到C.

+0

非常感謝@vlk!我可以寫一個適當的mmap!但我有一些關於你的圖書館的問題。 ** 1)**我並不真正瞭解' Gpio._mm [self._addr +寄存器:self._addr +寄存器+ 4] = struct.pack( ' Tagadac

+0

** 2)**在數據表中,我們可以讀到:'在讀PIO_PUSR一個 指上拉被禁用和閱讀 零意味着上拉是enabled.'。所以'回報(self._reg_get(Gpio._PULL_DOWN_STATUS)self._bitval)> 0'應該是'回到** **不(self._reg_get(Gpio._PULL_UP_STATUS)self._bitval)> 0'或類似的不?用這種方法,如果位寄存器是'1',那麼你就有'FALSE'和'TRUE'。沒有? (和同爲下拉) – Tagadac

+0

** 3)**爲什麼改變''從到0xFFFFF000''0xFFFFFA00'(銀行d)導致'MMAP _PIO_OFFSET':無效argument'?感謝您的幫助 ! – Tagadac

1

busybox devmem

busybox devmem是一個很小的CLI工具,mmaps /dev/mem

你可以得到它在Ubuntu:sudo易於得到安裝busybox的

用法:

sudo busybox devmem 0x12345678 

0x9abcdef0到該地址:

sudo busybox devmem 0x12345678 w 0x9abcdef0 
從物理地址 0x12345678讀取4個字節

看到這個關於如何測試它的幾個提示:Accessing physical address from user space

在還提到:https://unix.stackexchange.com/questions/4948/shell-command-to-read-device-registers

+0

不錯,謝謝!我會在稍後測試它:) – Tagadac