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

View File

@@ -5,7 +5,6 @@ from .rpgpio_private import *
import time
import logging
import sys
import struct
class GPIO(object):
@@ -45,7 +44,7 @@ class GPIO(object):
v = self._mem.read_int(addr)
v &= ~(7 << ((pin % 10) * 3)) # input value
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)
else:
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.
class DMAGPIO(DMAProto):
_DMA_CONTROL_BLOCK_SIZE = 32
_DMA_CHANNEL = 5
def __init__(self):
""" Create object which control GPIO pins via DMA(Direct Memory
Access).
@@ -94,7 +93,7 @@ class DMAGPIO(DMAProto):
otherwise memory will be unlocked and it could be overwritten by
operating system.
"""
super(DMAGPIO, self).__init__(31 * 1024 * 1024)
super(DMAGPIO, self).__init__(31 * 1024 * 1024, 5)
self.__current_address = 0
# 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 \
| DMA_TI_PER_MAP(DMA_TI_PER_MAP_PWM) \
| DMA_TI_DEST_DREQ
self._delay_destination = PHYSICAL_PWM_BUS + 0x18
self._delay_destination = PHYSICAL_PWM_BUS + PWM_FIFO
self._delay_stride = 0
self._pulse_info = DMA_TI_NO_WIDE_BURSTS | DMA_TI_TDMODE \
@@ -138,16 +137,16 @@ class DMAGPIO(DMAProto):
source3 = next3 - 8
data = (
self._pulse_info, source1, self._pulse_destination,
self._pulse_length,
self._pulse_stride, next1, pins_mask, 0,
self._delay_info, 0, self._delay_destination, length2,
self._delay_stride, next2, 0, 0,
self._pulse_info, source3, self._pulse_destination,
self._pulse_length,
self._pulse_stride, next3, 0, pins_mask
self._pulse_info, source1, self._pulse_destination,
self._pulse_length,
self._pulse_stride, next1, pins_mask, 0,
self._delay_info, 0, self._delay_destination, length2,
self._delay_stride, next2, 0, 0,
self._pulse_info, source3, self._pulse_destination,
self._pulse_length,
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
def add_delay(self, delay_us):
@@ -157,14 +156,14 @@ class DMAGPIO(DMAProto):
next_cb = self.__current_address + self._DMA_CONTROL_BLOCK_SIZE
if next_cb > self._physmem.get_size():
raise MemoryError("Out of allocated memory.")
next = self._physmem.get_bus_address() + next_cb
source = next - 8 # last 8 bytes are padding, use it to store data
next1 = self._physmem.get_bus_address() + next_cb
source = next1 - 8 # last 8 bytes are padding, use it to store data
length = 16 * delay_us
data = (
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
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._pwm.write_int(PWM_RNG1, 100)
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_USEF1 | PWM_CTL_PWEN1)
super(DMAGPIO, self)._run_dma()
@@ -222,10 +221,10 @@ class DMAGPIO(DMAProto):
class DMAPWM(DMAProto):
_DMA_CHANNEL = 14
_DMA_CONTROL_BLOCK_SIZE = 32
_DMA_DATA_OFFSET = 24
_TOTAL_NUMBER_OF_BLOCKS = 256
def __init__(self):
""" Initialise PWM. PWM has 8 bit resolution and fixed frequency
(~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.
"""
super(DMAPWM, self).__init__(self._TOTAL_NUMBER_OF_BLOCKS
* self._DMA_CONTROL_BLOCK_SIZE)
* self._DMA_CONTROL_BLOCK_SIZE, 14)
self._clear_pins = dict()
# first control block always set pins
self.__add_control_block(0, GPIO_SET_OFFSET)
@@ -266,7 +265,7 @@ class DMAPWM(DMAProto):
0, # padding, uses as data storage
0 # padding
)
self._physmem.write(address, data)
self._physmem.write(address, "8I", data)
def add_pin(self, pin, duty_cycle):
""" Add pin to PMW with specified duty cycle.
@@ -321,6 +320,7 @@ class DMAPWM(DMAProto):
self.remove_pin(pin)
assert len(self._clear_pins) == 0
# for testing purpose
def main():
pin = 21
@@ -340,7 +340,7 @@ def main():
print("clear " + str(g.read(pin)))
time.sleep(1)
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()))
a = cma.read_int(0)
print("was " + hex(a))

View File

@@ -122,6 +122,7 @@ class PhysicalMemory(object):
self._rmap = mmap.mmap(fd, size, flags=mmap.MAP_SHARED,
prot=mmap.PROT_READ | mmap.PROT_WRITE,
offset=phys_address)
self._close_dev(fd)
atexit.register(self.cleanup)
def cleanup(self):
@@ -139,14 +140,13 @@ class PhysicalMemory(object):
os.close(fd)
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):
self._rmap.seek(address)
self._rmap.write(struct.pack(str(len(data)) + "I", *data))
def write(self, address, fmt, data):
struct.pack_into(fmt, self._rmap, address, *data)
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):
return self._size
@@ -154,6 +154,7 @@ class PhysicalMemory(object):
class CMAPhysicalMemory(PhysicalMemory):
IOCTL_MBOX_PROPERTY = ctypes.c_long(0xc0046400).value
def __init__(self, size):
""" This class allocates continuous memory with specified size, lock it
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
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:
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:
# memory should be freed in __del__
raise OSError("Failed to lock memory with /dev/vcio")
@@ -201,10 +204,11 @@ class CMAPhysicalMemory(PhysicalMemory):
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
control blocks.
"""
self._DMA_CHANNEL = dma_channel
# allocate buffer for control blocks
self._physmem = CMAPhysicalMemory(memory_size)
# prepare dma registers memory map