Raspberry pi で AP のレジスタを操作する前に

Linux からのレジスタ操作

仮想アドレス

OS上の通常のプログラムはハードウェアのアドレス(物理アドレス)からは隔離されていて、 仮想的なアドレス空間上で動作しています。 その仮想アドレスがOSとHW(MMU)で変換されて、一部が物理アドレスです。

そのため、AP の仕様書に記載されている物理アドレスへアクセスするにはひと工夫が必要です。

mmap()

Linuxシステムコールmmap()を使って、物理アドレスへアクセスすることができます。

Man page of MMAP

今回は SRAM の開始アドレスが仕様書から 0x0000_0000 であることがわかるので、 これを基準にしてGPIOなどへアクセスします。

mmap() の概要

物理アドレスをプログラムの仮想アドレス上に割り当てることができます。 (これ以外の目的に使うこともあります。) ただし、ファイルシステムや、HW の制約により Block/Pase size に気をつける必要があります。 Block/Page size は予め決められたアドレスマップ上の区切りのことです。

サンプルコード

volatile unsigned * io_mapping(int base_addr)
{
    char *gpio_mem, *gpio_map;
    
    if (!mem_fd) {
      mem_fd = open("/dev/mem", O_RDWR|O_SYNC);
      check((mem_fd < 0), "can't open /dev/mem \n");
    }
    
    gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1));
    check( ( gpio_mem == NULL), "allocation error \n");

    // Make sure pointer is on 4K boundary
    if ((unsigned long) gpio_mem % PAGE_SIZE)
      gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE);
    
    // Now map it
    gpio_map = (char *)mmap((caddr_t)gpio_mem, 
                            BLOCK_SIZE, 
                            PROT_READ|PROT_WRITE, 
                            MAP_SHARED|MAP_FIXED, 
                            mem_fd, 
                            base_addr );

    check( ((long)gpio_map < 0), "mmap error \n");

    return (volatile unsigned *)gpio_map;
}

io_mapping() は、 SRAM のアドレスを基準にして、アクセスしたい領域のベースアドレスをオフセットにして 物理アドレスの割当用に確保した仮想アドレス空間gpio_memを戻り値とします。