LoginSignup
6
6

More than 5 years have passed since last update.

Python と Numpy で UIO を制御

Last updated at Posted at 2017-11-27

はじめに

UIO とは

UIO はユーザー空間でデバイスドライバを作成する仕組みです。

ユーザー空間で UIO を利用する際は、/dev/uio0 を open して mmap すると、デバイスのレジスタ空間が見えます。この記事では、Python と numpy を使って UIO のデバイスレジスタをアクセスする方法を示します。

Uio クラス

必要なライブラリをインポート

Uio クラスでは numpy、mmap、os パッケージを使うのでインポートします。

uio.py
import numpy as np
import mmap
import os

初期化メソッド

初期化時にデバイス名(例えば 'uio0''uio1' )を指定します。オプションでレジスタ空間の大きさをバイト数で指定できます。省略時は 0x1000(4KByte)です。初期化時に指定されたデバイス名のデバイスドライバを open し、指定された範囲を mmap.mmap でマッピングします。

uio.py
class Uio:
    """A simple uio class"""

    def __init__(self, name, length=0x1000):
        self.name        = name
        self.device_name = '/dev/%s' % self.name
        self.device_file = os.open(self.device_name, os.O_RDWR | os.O_SYNC)
        self.length      = length
        self.memmap      = mmap.mmap(self.device_file,
                                     self.length,
                                     mmap.MAP_SHARED,
                                     mmap.PROT_READ | mmap.PROT_WRITE,
                                     offset=0)

割り込み関連のメソッド

UIO にはデバイスドライバに直接ライト/リードすることで割り込みを制御出来ます。詳しくは次の記事を参照してください。

uio.py
    def irq_on(self):
        os.write(self.device_file, bytes([1, 0, 0, 0]))

    def irq_off(self):
        os.write(self.device_file, bytes([0, 0, 0, 0]))

    def wait_irq(self):
        os.read(self.device_file, 4)

レジスタアクセス用のオブジェクトを生成

UIO のデバイスレジスタをアクセスするための Uio.Regs クラスのインスタンスを生成します。Uio.Regs に関しては次節を参照してください。
インスタンスを生成する際、レジスタの開始アドレスとレジスタ空間の大きさを指定することが出来ます。ここで指定するレジスタの開始アドレスは、UIO で設定された物理アドレスからのオフセット値です。

uio.py
    def regs(self, offset=0, length=None):
        if length == None:
            length = self.length
        if offset+length > self.length:
            raise ValueError("region range error")
        return Uio.Regs(self.memmap, offset, length)

Uio.Regs クラス

mmap.mmap() でマッピングしている空間を numpy の frombuffer() を使って numpy の配列にします。レジスタへのアクセスは、ここで作った numpy の配列にアクセスすることで行います。

uio.py
    class Regs:

        def __init__(self, memmap, offset, length):
            self.memmap     = memmap
            self.offset     = offset
            self.length     = length
            self.word_array = np.frombuffer(self.memmap, np.uint32, self.length>>2, self.offset)
            self.byte_array = np.frombuffer(self.memmap, np.uint8 , self.length>>0, self.offset)

        def read_word(self, offset):
            return int(self.word_array[offset>>2])

        def read_byte(self, offset):
            return int(self.byte_array[offset>>0])

        def write_word(self, offset, data):
            self.word_array[offset>>2] = np.uint32(data)

        def write_byte(self, offset, data):
            self.byte_array[offset>>0] = np.uint8(data)

使用例

sample.py

from uio     import Uio

class Sample:

    START_REGS  = 0x00
    ARG0_REGS   = 0x04
    ARG1_REGS   = 0x08
    RETURN_REGS = 0x0C

    def __init__(self)
        self.uio  = Uio('uio0')
        self.regs = self.uio.regs()

    def func(self, arg0, arg1)
        self.regs.write_word(Sample.ARG0_REGS , arg0)
        self.regs.write_word(Sample.ARG1_REGS , arg1)
        self.regs.write_byte(Sample.START_REGS, 1)
        self.uio.irq_on()
        self.uio.wait_irq()
        return self.regs.read_word(Sample.RETURN_REGS)

if __name__ == '__main__':
    sample = Sample()
    for x in range (0,9):
        for y in range (0,9):
            print ("func({0},{1}) => {2}".format(x, y, sample.func(x,y)))

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6