ARM上的Linux中的WRITE和READ寄存器

时间:2017-06-01 16:18:07

标签: c linux arm cpu-registers gpio

我正在尝试按照以下步骤在我的ARM9(SAM9X25)上读取和写入寄存器:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3750.html我以下面的代码结束:

                    try{
                        System.Reflection.Assembly sampleAssembly = System.Reflection.Assembly.LoadFrom(dll);

                        List<Type> list= sampleAssembly.GetTypes().Where(p =>
                                             p.Namespace == dll &&
                                             p.Name.Contains("Plugin")
                                            ).ToList();
                        Type myType=list.FirstOrDefault();

                        //Type myType = sampleAssembly.GetType("Plugin");
                        System.Reflection.MethodInfo method = myType.GetMethod("activate");
                        object myInstance = Activator.CreateInstance(myType);
                        method.Invoke(myInstance, new object[]{this});

                    }


我在Ubuntu 16.04中交叉编译了我的代码#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; } ,但我在程序执行期间arm-linux-gnueabi-gcc gpio.c -o gpio之后有一个Segmentation Fault我的董事会。
我知道地址是对的...那么为什么我会有这个错误呢?这是好方法吗?
谢谢你的帮助!

解决方案:
谢谢@vlk我可以让它工作!这是切换LED的一个小例子:

printf

编辑:
在评论中回答 3)。如果你想让它适用于所有的偏移量(即:mmap example),你必须改变mmap和如此的分配:

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

和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

对于作业:

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

2 个答案:

答案 0 :(得分:3)

您无法直接访问寄存器,因为Linux使用MMU,这会为您的应用创建与物理MCU地址空间不同的虚拟地址空间,并且在此虚拟地址空间之外的访问会导致分段错误。

只有在Linux中访问这些寄存器的方法(如果你不想编写内核驱动程序)是打开文件/ dev / mem作为文件并用mmap

映射它

例如,我有一个小型python库,用于访问Atmel SAM MCU gpiosam上的GPIO寄存器。你可以启发并将它移植到C。

答案 1 :(得分:1)

<强> import java.awt.*; import javax.swing.*; //https://stackoverflow.com/questions/35287367/changing-desktopicon-width-on-nimbus public class DesktopIconWidthTest2 { public JComponent makeUI() { JDesktopPane desktop = new JDesktopPane(); desktop.setDesktopManager(new DefaultDesktopManager() { @Override public void iconifyFrame(JInternalFrame f) { Rectangle r = this.getBoundsForIconOf(f); r.width = f.getDesktopIcon().getPreferredSize().width; f.getDesktopIcon().setBounds(r); super.iconifyFrame(f); } }); desktop.add(createFrame("looooooooooooong title #", 1)); desktop.add(createFrame("#", 0)); return desktop; } private JInternalFrame createFrame(String t, int i) { JInternalFrame f = new JInternalFrame(t + i, true, true, true, true); f.setDesktopIcon(new JInternalFrame.JDesktopIcon(f) { @Override public Dimension getPreferredSize() { Dimension d = f.getMinimumSize(); String title = f.getTitle(); FontMetrics fm = getFontMetrics(getFont()); //Magic Number 16: margin? d.width += SwingUtilities.computeStringWidth(fm, title) - 16; return d; } }); f.setSize(200, 100); f.setVisible(true); f.setLocation(5 + 40 * i, 5 + 50 * i); return f; } public static void main(String[] args) { EventQueue.invokeLater(() -> { try { UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel"); // MetalLookAndFeel: UIManager.put("DesktopIcon.width", 500); } catch (Exception e) { e.printStackTrace(); } JFrame f = new JFrame(); f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); f.getContentPane().add(new DesktopIconWidthTest2().makeUI()); f.setSize(320, 240); f.setLocationRelativeTo(null); f.setVisible(true); }); } }

busybox devmem是一个很小的CLI实用程序,可以映射busybox devmem

你可以在Ubuntu中使用:sudo apt-get install busybox

用法:从物理地址/dev/mem读取4个字节:

0x12345678

sudo busybox devmem 0x12345678 写入该地址:

0x9abcdef0

有关如何测试的一些提示,请参阅此处:Accessing physical address from user space

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