写入和读取寄存器的Linux基于ARM
我想读和我下面这些步骤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 Fault
在printf
之后执行我的主板上的程序。
我知道地址是正确的......那么,为什么我有这个错误?
这是好方法吗?
谢谢你的帮助!
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;
你不能直接访问寄存器,因为Linux使用MMU,这为应用程序创建虚拟地址空间比物理MCU地址空间和访问不同的OU这个虚拟地址空间导致分段错误。
必由之路在Linux下访问这些寄存器(如果你不想写内核驱动程序)是打开文件/ dev/MEM文件和与mmap
比如我有小Python库图吧用于访问Atmel SAM MCU上的GPIO寄存器gpiosam。您可以启发和移植到C.
非常感谢@vlk!我可以写一个适当的mmap!但我有一些关于你的图书馆的问题。 ** 1)**我并不真正了解' Gpio._mm [self._addr +寄存器:self._addr +寄存器+ 4] = struct.pack( '
** 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
** 3)**为什么改变''从到0xFFFFF000''0xFFFFFA00'(银行d)导致'MMAP _PIO_OFFSET':无效argument'?感谢您的帮助 ! – Tagadac
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
不错,谢谢!我会在稍后测试它:) – Tagadac
阅读:从用户空间访问物理地址(https://stackoverflow.com/questions/12040303/accessing-physical-address-from-user-space) –
您无法访问他们直接从像您可以使用mmap通过操作系统打眼,或者写一个内核驱动程序或运行baremetal,但写它应该赛格故障的应用空间。 –