2017-06-01 100 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