review rpgpio

This commit is contained in:
Nikolay Khabarov
2017-05-20 00:54:49 +03:00
parent 989478d06f
commit 78804a438a
2 changed files with 35 additions and 31 deletions
+23 -23
View File
@@ -5,7 +5,6 @@ from .rpgpio_private import *
import time import time
import logging import logging
import sys import sys
import struct
class GPIO(object): class GPIO(object):
@@ -45,7 +44,7 @@ class GPIO(object):
v = self._mem.read_int(addr) v = self._mem.read_int(addr)
v &= ~(7 << ((pin % 10) * 3)) # input value v &= ~(7 << ((pin % 10) * 3)) # input value
if mode == self.MODE_OUTPUT: if mode == self.MODE_OUTPUT:
v |= (1 << ((pin % 10) * 3)) # output value, base on input v |= (1 << ((pin % 10) * 3)) # output value, base on input
self._mem.write_int(addr, v) self._mem.write_int(addr, v)
else: else:
self._mem.write_int(addr, v) self._mem.write_int(addr, v)
@@ -83,7 +82,7 @@ class GPIO(object):
# clock for delay). So, do not create two or more instances of DMAGPIO. # clock for delay). So, do not create two or more instances of DMAGPIO.
class DMAGPIO(DMAProto): class DMAGPIO(DMAProto):
_DMA_CONTROL_BLOCK_SIZE = 32 _DMA_CONTROL_BLOCK_SIZE = 32
_DMA_CHANNEL = 5
def __init__(self): def __init__(self):
""" Create object which control GPIO pins via DMA(Direct Memory """ Create object which control GPIO pins via DMA(Direct Memory
Access). Access).
@@ -94,7 +93,7 @@ class DMAGPIO(DMAProto):
otherwise memory will be unlocked and it could be overwritten by otherwise memory will be unlocked and it could be overwritten by
operating system. operating system.
""" """
super(DMAGPIO, self).__init__(31 * 1024 * 1024) super(DMAGPIO, self).__init__(31 * 1024 * 1024, 5)
self.__current_address = 0 self.__current_address = 0
# get helpers registers, this class uses PWM module to create precise # get helpers registers, this class uses PWM module to create precise
@@ -106,7 +105,7 @@ class DMAGPIO(DMAProto):
self._delay_info = DMA_TI_NO_WIDE_BURSTS | DMA_SRC_IGNORE \ self._delay_info = DMA_TI_NO_WIDE_BURSTS | DMA_SRC_IGNORE \
| DMA_TI_PER_MAP(DMA_TI_PER_MAP_PWM) \ | DMA_TI_PER_MAP(DMA_TI_PER_MAP_PWM) \
| DMA_TI_DEST_DREQ | DMA_TI_DEST_DREQ
self._delay_destination = PHYSICAL_PWM_BUS + 0x18 self._delay_destination = PHYSICAL_PWM_BUS + PWM_FIFO
self._delay_stride = 0 self._delay_stride = 0
self._pulse_info = DMA_TI_NO_WIDE_BURSTS | DMA_TI_TDMODE \ self._pulse_info = DMA_TI_NO_WIDE_BURSTS | DMA_TI_TDMODE \
@@ -138,16 +137,16 @@ class DMAGPIO(DMAProto):
source3 = next3 - 8 source3 = next3 - 8
data = ( data = (
self._pulse_info, source1, self._pulse_destination, self._pulse_info, source1, self._pulse_destination,
self._pulse_length, self._pulse_length,
self._pulse_stride, next1, pins_mask, 0, self._pulse_stride, next1, pins_mask, 0,
self._delay_info, 0, self._delay_destination, length2, self._delay_info, 0, self._delay_destination, length2,
self._delay_stride, next2, 0, 0, self._delay_stride, next2, 0, 0,
self._pulse_info, source3, self._pulse_destination, self._pulse_info, source3, self._pulse_destination,
self._pulse_length, self._pulse_length,
self._pulse_stride, next3, 0, pins_mask self._pulse_stride, next3, 0, pins_mask
) )
self._physmem.write(self.__current_address, data) self._physmem.write(self.__current_address, "24I", data)
self.__current_address = next_cb self.__current_address = next_cb
def add_delay(self, delay_us): def add_delay(self, delay_us):
@@ -157,14 +156,14 @@ class DMAGPIO(DMAProto):
next_cb = self.__current_address + self._DMA_CONTROL_BLOCK_SIZE next_cb = self.__current_address + self._DMA_CONTROL_BLOCK_SIZE
if next_cb > self._physmem.get_size(): if next_cb > self._physmem.get_size():
raise MemoryError("Out of allocated memory.") raise MemoryError("Out of allocated memory.")
next = self._physmem.get_bus_address() + next_cb next1 = self._physmem.get_bus_address() + next_cb
source = next - 8 # last 8 bytes are padding, use it to store data source = next1 - 8 # last 8 bytes are padding, use it to store data
length = 16 * delay_us length = 16 * delay_us
data = ( data = (
self._delay_info, source, self._delay_destination, length, self._delay_info, source, self._delay_destination, length,
self._delay_stride, next, 0, 0 self._delay_stride, next1, 0, 0
) )
self._physmem.write(self.__current_address, data) self._physmem.write(self.__current_address, "8I", data)
self.__current_address = next_cb self.__current_address = next_cb
def finalize_stream(self): def finalize_stream(self):
@@ -188,7 +187,7 @@ class DMAGPIO(DMAProto):
self._clock.write_int(CM_CNTL, CM_PASSWORD | CM_SRC_PLLD | CM_ENABLE) self._clock.write_int(CM_CNTL, CM_PASSWORD | CM_SRC_PLLD | CM_ENABLE)
self._pwm.write_int(PWM_RNG1, 100) self._pwm.write_int(PWM_RNG1, 100)
self._pwm.write_int(PWM_DMAC, PWM_DMAC_ENAB self._pwm.write_int(PWM_DMAC, PWM_DMAC_ENAB
| PWM_DMAC_PANIC(15) | PWM_DMAC_DREQ(15)) | PWM_DMAC_PANIC(15) | PWM_DMAC_DREQ(15))
self._pwm.write_int(PWM_CTL, PWM_CTL_CLRF) self._pwm.write_int(PWM_CTL, PWM_CTL_CLRF)
self._pwm.write_int(PWM_CTL, PWM_CTL_USEF1 | PWM_CTL_PWEN1) self._pwm.write_int(PWM_CTL, PWM_CTL_USEF1 | PWM_CTL_PWEN1)
super(DMAGPIO, self)._run_dma() super(DMAGPIO, self)._run_dma()
@@ -222,10 +221,10 @@ class DMAGPIO(DMAProto):
class DMAPWM(DMAProto): class DMAPWM(DMAProto):
_DMA_CHANNEL = 14
_DMA_CONTROL_BLOCK_SIZE = 32 _DMA_CONTROL_BLOCK_SIZE = 32
_DMA_DATA_OFFSET = 24 _DMA_DATA_OFFSET = 24
_TOTAL_NUMBER_OF_BLOCKS = 256 _TOTAL_NUMBER_OF_BLOCKS = 256
def __init__(self): def __init__(self):
""" Initialise PWM. PWM has 8 bit resolution and fixed frequency """ Initialise PWM. PWM has 8 bit resolution and fixed frequency
(~11.5 KHz and may flow). Though duty cycle is quite precise and (~11.5 KHz and may flow). Though duty cycle is quite precise and
@@ -239,7 +238,7 @@ class DMAPWM(DMAProto):
Cycles in info field of control blocks. Cycles in info field of control blocks.
""" """
super(DMAPWM, self).__init__(self._TOTAL_NUMBER_OF_BLOCKS super(DMAPWM, self).__init__(self._TOTAL_NUMBER_OF_BLOCKS
* self._DMA_CONTROL_BLOCK_SIZE) * self._DMA_CONTROL_BLOCK_SIZE, 14)
self._clear_pins = dict() self._clear_pins = dict()
# first control block always set pins # first control block always set pins
self.__add_control_block(0, GPIO_SET_OFFSET) self.__add_control_block(0, GPIO_SET_OFFSET)
@@ -266,7 +265,7 @@ class DMAPWM(DMAProto):
0, # padding, uses as data storage 0, # padding, uses as data storage
0 # padding 0 # padding
) )
self._physmem.write(address, data) self._physmem.write(address, "8I", data)
def add_pin(self, pin, duty_cycle): def add_pin(self, pin, duty_cycle):
""" Add pin to PMW with specified duty cycle. """ Add pin to PMW with specified duty cycle.
@@ -321,6 +320,7 @@ class DMAPWM(DMAProto):
self.remove_pin(pin) self.remove_pin(pin)
assert len(self._clear_pins) == 0 assert len(self._clear_pins) == 0
# for testing purpose # for testing purpose
def main(): def main():
pin = 21 pin = 21
@@ -340,7 +340,7 @@ def main():
print("clear " + str(g.read(pin))) print("clear " + str(g.read(pin)))
time.sleep(1) time.sleep(1)
cma = CMAPhysicalMemory(1*1024*1024) cma = CMAPhysicalMemory(1*1024*1024)
print(str(cma.get_size() / 1024 / 1024) + "MB of memory allocated at " \ print(str(cma.get_size() / 1024 / 1024) + "MB of memory allocated at "
+ hex(cma.get_phys_address())) + hex(cma.get_phys_address()))
a = cma.read_int(0) a = cma.read_int(0)
print("was " + hex(a)) print("was " + hex(a))
+12 -8
View File
@@ -122,6 +122,7 @@ class PhysicalMemory(object):
self._rmap = mmap.mmap(fd, size, flags=mmap.MAP_SHARED, self._rmap = mmap.mmap(fd, size, flags=mmap.MAP_SHARED,
prot=mmap.PROT_READ | mmap.PROT_WRITE, prot=mmap.PROT_READ | mmap.PROT_WRITE,
offset=phys_address) offset=phys_address)
self._close_dev(fd)
atexit.register(self.cleanup) atexit.register(self.cleanup)
def cleanup(self): def cleanup(self):
@@ -139,14 +140,13 @@ class PhysicalMemory(object):
os.close(fd) os.close(fd)
def write_int(self, address, int_value): def write_int(self, address, int_value):
self._rmap[address:address + 4] = struct.pack("I", int_value) ctypes.c_uint32.from_buffer(self._rmap, address).value = int_value
def write(self, address, data): def write(self, address, fmt, data):
self._rmap.seek(address) struct.pack_into(fmt, self._rmap, address, *data)
self._rmap.write(struct.pack(str(len(data)) + "I", *data))
def read_int(self, address): def read_int(self, address):
return struct.unpack("I", self._rmap[address:address + 4])[0] return ctypes.c_uint32.from_buffer(self._rmap, address).value
def get_size(self): def get_size(self):
return self._size return self._size
@@ -154,6 +154,7 @@ class PhysicalMemory(object):
class CMAPhysicalMemory(PhysicalMemory): class CMAPhysicalMemory(PhysicalMemory):
IOCTL_MBOX_PROPERTY = ctypes.c_long(0xc0046400).value IOCTL_MBOX_PROPERTY = ctypes.c_long(0xc0046400).value
def __init__(self, size): def __init__(self, size):
""" This class allocates continuous memory with specified size, lock it """ This class allocates continuous memory with specified size, lock it
and provide access to it with Python's mmap. It uses RPi video and provide access to it with Python's mmap. It uses RPi video
@@ -162,10 +163,12 @@ class CMAPhysicalMemory(PhysicalMemory):
""" """
size = (size + PAGE_SIZE - 1) // PAGE_SIZE * PAGE_SIZE size = (size + PAGE_SIZE - 1) // PAGE_SIZE * PAGE_SIZE
self._vcio_fd = self._open_dev("/dev/vcio") self._vcio_fd = self._open_dev("/dev/vcio")
self._handle = self._send_data(0x3000c, [size, PAGE_SIZE, 0xC]) # allocate memory # allocate memory
self._handle = self._send_data(0x3000c, [size, PAGE_SIZE, 0xC])
if self._handle == 0: if self._handle == 0:
raise OSError("No memory to allocate with /dev/vcio") raise OSError("No memory to allocate with /dev/vcio")
self._busmem = self._send_data(0x3000d, [self._handle]) # lock memory # lock memory
self._busmem = self._send_data(0x3000d, [self._handle])
if self._busmem == 0: if self._busmem == 0:
# memory should be freed in __del__ # memory should be freed in __del__
raise OSError("Failed to lock memory with /dev/vcio") raise OSError("Failed to lock memory with /dev/vcio")
@@ -201,10 +204,11 @@ class CMAPhysicalMemory(PhysicalMemory):
class DMAProto(object): class DMAProto(object):
def __init__(self, memory_size): def __init__(self, memory_size, dma_channel):
""" This class provides basic access to DMA and creates buffer for """ This class provides basic access to DMA and creates buffer for
control blocks. control blocks.
""" """
self._DMA_CHANNEL = dma_channel
# allocate buffer for control blocks # allocate buffer for control blocks
self._physmem = CMAPhysicalMemory(memory_size) self._physmem = CMAPhysicalMemory(memory_size)
# prepare dma registers memory map # prepare dma registers memory map