def __init__(self, bitfile, **kwargs): """Initializes a new sharedmemOverlay object. """ # The following lines do some path searching to enable a # PYNQ-Like API for Overlays. For example, without these # lines you cannot call sharedmemOverlay('sharedmem.bit') because # sharedmem.bit is not on the bitstream search path. The # following lines fix this for any non-PYNQ Overlay # # You can safely reuse, and ignore the following lines # # Get file path of the current class (i.e. /opt/python3.6/<...>/sharedmem.py) file_path = os.path.abspath(inspect.getfile(inspect.currentframe())) # Get directory path of the current class (i.e. /opt/python3.6/<...>/sharedmem/) dir_path = os.path.dirname(file_path) # Update the bitfile path to search in dir_path bitfile = os.path.join(dir_path, bitfile) # Upload the bitfile (and parse the colocated .tcl script) super().__init__(bitfile, **kwargs) # Manually define the GPIO pin that drives reset self.__resetPin = GPIO(GPIO.get_gpio_pin(0), "out") self.nreset() # Define a Register object at address 0x0 of the mmult address space # We will use this to set bits and start the core (see start()) # Do NOT write to __ap_ctrl unless __resetPin has been set to __NRESET_VALUE self.__ap_ctrl = Register(self.mmultCore.mmio.base_addr, 32) self.__a_offset = Register( self.mmultCore.mmio.base_addr + self.__MMULT_ADDR_A_DATA, 32) self.__bt_offset = Register( self.mmultCore.mmio.base_addr + self.__MMULT_ADDR_BT_DATA, 32) self.__c_offset = Register( self.mmultCore.mmio.base_addr + self.__MMULT_ADDR_C_DATA, 32) self.xlnk = Xlnk()
def __init__(self, iop_name, addr_base, addr_range, gpio_uix, mb_program, intr_pin=None, intr_ack_gpio=None): """Create a new _IOP object. Parameters ---------- iop_name : str The name of the IP corresponding to the I/O Processor. addr_base : int The base address for the MMIO. addr_range : int The address range for the MMIO. gpio_uix : int The user index of the GPIO, starting from 0. mb_program : str The Microblaze program loaded for the IOP. """ self.iop_name = iop_name self.mb_program = mb_program self.state = 'IDLE' self.gpio = GPIO(GPIO.get_gpio_pin(gpio_uix), "out") self.mmio = MMIO(addr_base, addr_range) if intr_pin and intr_ack_gpio: self.interrupt = _IOPInterruptEvent(intr_pin, intr_ack_gpio) self.program()
def __init__(self, description, gpio_name=None): """Return a new Audio object based on the hierarchy description. Parameters ---------- description : dict The hierarchical description of the hierarchy gpio_name : str The name of the audio path selection GPIO. If None then the GPIO pin in the hierarchy is used, otherwise the gpio_name is searched in the list of pins on the hierarchy and the PL.gpio_dict. """ super().__init__(description) if gpio_name is None: if len(self._gpio) == 0: raise RuntimeError('Could not find audio path select GPIO.') elif len(self._gpio) > 1: raise RuntimeError('Multiple possible audio path select GPIO.') pin_name = next(iter(self._gpio.keys())) self.gpio = getattr(self, pin_name) else: if gpio_name in self._gpio: self.gpio = getattr(self, gpio_name) elif gpio_name in PL.gpio_dict: pin = GPIO.get_gpio_pin(PL.gpio_dict[gpio_name]['index']) self.gpio = GPIO(pin, 'out') else: raise RuntimeError('Provided gpio_name not found.') self._ffi = cffi.FFI() self._libaudio = self._ffi.dlopen(LIB_SEARCH_PATH + "/sources/libaudio.so") self._ffi.cdef("""unsigned int Xil_Out32(unsigned int Addr, unsigned int Value);""") self._ffi.cdef("""unsigned int Xil_In32(unsigned int Addr);""") self._ffi.cdef("""void record(unsigned int BaseAddr, unsigned int * BufAddr, unsigned int Num_Samles_32Bit);""") self._ffi.cdef("""void playinit(unsigned int BaseAddr, unsigned int * BufAddr, unsigned int Num_Samles_32Bit);""") self._ffi.cdef("""void playend(unsigned int BaseAddr, unsigned int * BufAddr, unsigned int Num_Samles_32Bit);""") self._ffi.cdef("""void play(unsigned int BaseAddr, unsigned int * BufAddr, unsigned int Num_Samles_32Bit);""") self._ffi.cdef("""void recordinit(unsigned int BaseAddr, unsigned int * BufAddr, unsigned int Num_Samles_32Bit);""") char_adrp = self._ffi.from_buffer(self.mmio.mem) self._uint_adrpv = self._ffi.cast('unsigned int', char_adrp) self.buffer = numpy.zeros(0).astype(numpy.int) self.sample_rate = 0 self.sample_len = 0
def __init__(self, bitfile, **kwargs): """ Constructor (load the bit file) """ file_path = os.path.abspath(inspect.getfile(inspect.currentframe())) dir_path = os.path.dirname(file_path) bitfile = os.path.join(dir_path, bitfile) super().__init__(bitfile, **kwargs) # Manually define the GPIO pin that drives reset self.__resetPin = GPIO(GPIO.get_gpio_pin(0), "out") self.nreset() # For convenience self.__hough = self.image_processing.hough_accel_0 self.__dma = self.image_processing.axi_dma_0 # Define a Register object at address 0x00 of the overlay address space base_addr = self.__hough.mmio.base_addr self.__ap_ctrl = Register(base_addr, 32) self.__outrho_offset = Register(base_addr + self.__OUTRHO_ADDR, 32) self.__outtheta_offset = Register(base_addr + self.__OUTTHETA_ADDR, 32) self.__num_of_lines_offset = Register(base_addr + self.__NUM_OF_LINES_ADDR, 32) self.__segments_offset = Register(base_addr + self.__LINES_SEGMENTS_ADDR, 32) self.__num_of_segments_offset = Register(base_addr + self.__NUM_OF_SEGMENTS_ADDR, 32) # DMA transfer engine self.__xlnk = Xlnk() # Memory pre-allocation self.__cma_rho = self.__xlnk.cma_array(self.__LINES, np.single) self.__cma_theta = self.__xlnk.cma_array(self.__LINES, np.single) self.__cma_numoflines = self.__xlnk.cma_array(1, np.int32) self.__cma_segments = self.__xlnk.cma_array((self.__SEGMENTS, 4), np.int32) self.__cma_numofsegments = self.__xlnk.cma_array(1, np.int32) self.__cmabuf_dest = self.__xlnk.cma_array((self.__HEIGHT, self.__WIDTH, 3), np.uint8) # public self.frame = self.__xlnk.cma_array((self.__HEIGHT, self.__WIDTH, 3), np.uint8) # Write address of M_AXI to HLS core self.__outrho_offset[31:0] = self.__xlnk.cma_get_phy_addr(self.__cma_rho.pointer) self.__outtheta_offset[31:0] = self.__xlnk.cma_get_phy_addr(self.__cma_theta.pointer) self.__num_of_lines_offset[31:0] = self.__xlnk.cma_get_phy_addr(self.__cma_numoflines.pointer) self.__segments_offset[31:0] = self.__xlnk.cma_get_phy_addr(self.__cma_segments.pointer) self.__num_of_segments_offset[31:0] = self.__xlnk.cma_get_phy_addr(self.__cma_numofsegments.pointer) # Performs the computation for the first time to avoid bad behavior on the first call. # For a small number of segments, maybe not all segments will be detected if we don't # call the HoughLines function for the first time here. self.frame[:] = cv2.imread(dir_path+'/star.png') self.HoughLines(20,30,80,5,30)
def __init__(self, intr_pin, intr_ack_gpio): """Create a new _MBInterruptEvent object Parameters ---------- intr_pin : str Name of the interrupt pin for the Microblaze. intr_ack_gpio : int Number of the GPIO pin used to clear the interrupt. """ self.interrupt = Interrupt(intr_pin) self.gpio = GPIO(GPIO.get_gpio_pin(intr_ack_gpio), "out")
def bypass_stop(self): """Stop streaming input to output directly. Parameters ---------- None Returns ------- None """ gpio_idx = GPIO.get_gpio_pin(PL.gpio_dict["audio_path_sel/Din"][0]) gpio_pin = GPIO(gpio_idx, 'out') gpio_pin.write(0) del gpio_pin
def bypass_start(self): """Stream audio controller input directly to output. Parameters ---------- None Returns ------- None """ gpio_idx = GPIO.get_gpio_pin(PL.gpio_dict["audio_path_sel/Din"][0]) gpio_pin = GPIO(gpio_idx, 'out') gpio_pin.write(1) del gpio_pin
def clk(self,index): """Generate one rising edge clock cycle at the specified bit position. Parameters ---------- index : integer value indicating bit position The bit position ranges from 0 to 31 corresponding to Dout_00 to Dout_31. """ if index not in range (0, 32): raise ValueError("bit number must be between 0 and 31.") else: clkpin = GPIO(GPIO.get_gpio_pin(index), 'out') clkpin.write(1) clkpin.write(0)
def init(self, mode=None, pull=None): if mode != None: if mode == self.IN: self._mode = self.IN # GPIO.setup(self.id, GPIO.IN) if self.pynq_gpio != None: self.pynq_gpio.release() self.pynq_gpio = GPIO(self.id, 'in') elif mode == self.OUT: self._mode = self.OUT # GPIO.setup(self.id, GPIO.OUT) if self.pynq_gpio != None: self.pynq_gpio.release() self.pynq_gpio = GPIO(self.id, 'out') else: raise RuntimeError("Invalid mode for pin: %s" % self.id)
class UcsdOverlay(Overlay): """A UCSD-Overlay Superclass for PYNQ """ # GPIO Reset Values __RESET_VALUE = 0 __NRESET_VALUE = 1 def __init__(self, odir, bitfile, **kwargs): """Initializes a new UcsdOverlay object. """ # The following lines do some path searching to enable a PYNQ-Like API # for Overlays. For example, without these lines you cannot call # myFabulousOverlay('myFabulousOverlay.bit') because # myFabulousOverlay.bit is not on the bitstream search path. The # following lines fix this for any non-PYNQ Overlay # # You can safely reuse, and ignore the following lines # # Get file path of the current class (i.e. /opt/python3.6/<...>/sharedmem.py) file_path = os.path.abspath(inspect.getfile(inspect.currentframe())) # Get directory path of the current class (i.e. /opt/python3.6/<...>/sharedmem/) dir_path = os.path.dirname(file_path) # Update the bitfile path to search in dir_path bitfile = os.path.join(dir_path, odir, bitfile) # Upload the bitfile (and parse the colocated .tcl script) super().__init__(bitfile, **kwargs) # Manually define the GPIO pin that drives reset self.__resetPin = GPIO(GPIO.get_gpio_pin(0), "out") self.nreset() self._xlnk = Xlnk() def nreset(self): """Set the reset pin to self.__NRESET_VALUE to place the core into not-reset (usually run) """ self.__resetPin.write(self.__NRESET_VALUE) def reset(self): """Set the reset pin to self.__RESET_VALUE to place the core into reset """ self.__resetPin.write(self.__RESET_VALUE)
def bit_write(self,index,value): """Write a value to the specified bit position. Parameters ---------- index : integer value indicating bit position The bit position ranges from 0 to 31 corresponding to Dout_00 to Dout_31. value : integer The value to be written, valid value being 0 or 1. """ if index not in range (0, 32): raise ValueError("bit number must be between 0 and 31.") else: bitwrite = GPIO(GPIO.get_gpio_pin(index), 'out') bitwrite.write(value)
def download(self, partial_bit=None): if partial_bit is not None: decoupler = GPIO(int(partial_bit[len(self.PARTIAL_BITSTREAM_PATH) + 3]) + GPIO.get_gpio_base(), 'out') decoupler.write(1) super().download(partial_bit) if partial_bit is not None: decoupler.write(0)
def bit_read(self,index): """Read a value from the specified bit position. Parameters ---------- index : integer value indicating bit position The bit position ranges from 0 to 31 corresponding to Dout_00 to Dout_31. Returns ------- integer Read value. """ if index not in range (0, 32): raise ValueError("bit number must be between 0 and 31.") else: bitread = GPIO(GPIO.get_gpio_pin(index+32), 'in') result=bitread.read() return result
class MBInterruptEvent: """The class provides and asyncio Event-like interface to the interrupt subsystem for a Microblaze. The event is set by raising an interrupt and cleared using the clear function. Typical use is to call clear prior to sending a request to the Microblaze and waiting in a loop until the response is received. This order of operations will avoid race conditions between the Microblaze and the host code. """ def __init__(self, intr_pin, intr_ack_gpio): """Create a new _MBInterruptEvent object Parameters ---------- intr_pin : str Name of the interrupt pin for the Microblaze. intr_ack_gpio : int Number of the GPIO pin used to clear the interrupt. """ self.interrupt = Interrupt(intr_pin) self.gpio = GPIO(GPIO.get_gpio_pin(intr_ack_gpio), "out") @asyncio.coroutine def wait(self): """Coroutine to wait until the event is set by an interrupt. """ yield from self.interrupt.wait() def clear(self): """Clear the interrupt and reset the event. Resetting the event should be done before sending a request that will be acknowledged interrupts. """ self.gpio.write(1) self.gpio.write(0)
def __init__(self, bitfile, **kwargs): super().__init__(bitfile, **kwargs) if self.is_loaded(): self.iop_pmoda.mbtype = "Pmod" self.iop_pmodb.mbtype = "Pmod" self.iop_arduino.mbtype = "Arduino" self.iop_rpi.mbtype = "Rpi" self.PMODA = self.iop_pmoda.mb_info self.PMODB = self.iop_pmodb.mb_info self.ARDUINO = self.iop_arduino.mb_info self.RPI = self.iop_rpi.mb_info self.pin_select = GPIO( GPIO.get_gpio_pin(self.gpio_dict['pmoda_rp_pin_sel']['index']), "out") self.audio = self.audio_codec_ctrl_0 self.audio.configure() self.leds = self.leds_gpio.channel1 self.switches = self.switches_gpio.channel1 self.buttons = self.btns_gpio.channel1 self.leds.setlength(4) self.switches.setlength(2) self.buttons.setlength(4) self.leds.setdirection("out") self.switches.setdirection("in") self.buttons.setdirection("in") self.rgbleds = ([None] * 4) + [pynq.lib.RGBLED(i) for i in range(4, 6)] self.trace_rpi = TraceAnalyzer( self.trace_analyzer_pi.description['ip'], PYNQZ2_RPI_SPECIFICATION) self.trace_pmoda = TraceAnalyzer( self.trace_analyzer_pi.description['ip'], PYNQZ2_PMODA_SPECIFICATION) self.trace_pmodb = TraceAnalyzer( self.trace_analyzer_pmodb.description['ip'], PYNQZ2_PMODB_SPECIFICATION)
def __init__(self, ip='SEG_d_axi_pdm_1_S_AXI_reg', rst="audio_path_sel"): """Return a new Audio object. The PL is queried to get the base address and length. Parameters ---------- ip : str The name of the IP required for the audio driver. rst : str The name of the GPIO pins used as reset for the audio driver. """ if ip not in PL.ip_dict: raise LookupError("No such audio IP in the overlay.") if rst not in PL.gpio_dict: raise LookupError("No such reset pin in the overlay.") self.mmio = MMIO(PL.ip_dict[ip][0], PL.ip_dict[ip][1]) self.gpio = GPIO(GPIO.get_gpio_pin(PL.gpio_dict[rst][0]), 'out') self._ffi = cffi.FFI() self._libaudio = self._ffi.dlopen(LIB_SEARCH_PATH + "/libaudio.so") self._ffi.cdef("""unsigned int Xil_Out32(unsigned int Addr, unsigned int Value);""") self._ffi.cdef("""unsigned int Xil_In32(unsigned int Addr);""") self._ffi.cdef("""void _Pynq_record(unsigned int BaseAddr, unsigned int * BufAddr, unsigned int Num_Samles_32Bit);""") self._ffi.cdef("""void _Pynq_play(unsigned int BaseAddr, unsigned int * BufAddr, unsigned int Num_Samles_32Bit);""") char_adrp = self._ffi.from_buffer(self.mmio.mem) self._uint_adrpv = self._ffi.cast('unsigned int', char_adrp) self.buffer = numpy.zeros(0).astype(numpy.int) self.sample_rate = 0 self.sample_len = 0
def __init__(self, iop_name, addr_base, addr_range, gpio_uix, mb_program): """Create a new _IOP object. Parameters ---------- iop_name : str The name of the IP corresponding to the I/O Processor. addr_base : int The base address for the MMIO. addr_range : int The address range for the MMIO. gpio_uix : int The user index of the GPIO, starting from 0. mb_program : str The Microblaze program loaded for the IOP. """ self.iop_name = iop_name self.mb_program = iop_const.BIN_LOCATION + mb_program self.state = 'IDLE' self.gpio = GPIO(GPIO.get_gpio_pin(gpio_uix), "out") self.mmio = MMIO(addr_base, addr_range) self.program()
def __init__(self, iop_name, addr_base, addr_range, gpio_uix, mb_program): """Create a new _IOP object. Parameters ---------- iop_name : str The name of the IP corresponding to the I/O Processor. addr_base : str The base address for the MMIO in hex format. addr_range : str The address range for the MMIO in hex format. gpio_uix : int The user index of the GPIO, starting from 0. mb_program : str The Microblaze program loaded for the IOP. """ self.iop_name = iop_name self.mb_program = iop_const.BIN_LOCATION + mb_program self.state = 'IDLE' self.gpio = GPIO(GPIO.get_gpio_pin(gpio_uix), "out") self.mmio = MMIO(int(addr_base, 16), int(addr_range,16)) self.program()
def test_gpio(): """ Test whether the GPIO class is working properly. Note ---- The gpio_min is the GPIO base pin number + minimum user pin The gpio_max is the smallest power of 2 greater than the GPIO base. """ # Find the GPIO base pin for root, dirs, files in os.walk('/sys/class/gpio'): for name in dirs: if 'gpiochip' in name: index = int(''.join(x for x in name if x.isdigit())) base = GPIO.get_gpio_base() gpio_min = base + general_const.GPIO_MIN_USER_PIN gpio_max = 2**(math.ceil(math.log(gpio_min, 2))) for index in range(gpio_min, gpio_max): g = GPIO(index, 'in') with pytest.raises(Exception) as error_infor: # GPIO type is 'in'. Hence g.write() is illegal. # Test will pass if exception is raised. g.write() g = GPIO(index, 'out') with pytest.raises(Exception) as error_infor: # GPIO type is 'out'. Hence g.read() is illegal. # Test will pass if exception is raised. g.read() with pytest.raises(Exception) as error_infor: # write() only accepts integer 0 or 1 (not 'str'). # Test will pass if exception is raised. g.write('1') del g
class LED: def __init__(self, r, g, b): self.r = GPIO(GPIO.get_gpio_pin(r), 'out') self.g = GPIO(GPIO.get_gpio_pin(g), 'out') self.b = GPIO(GPIO.get_gpio_pin(b), 'out') def write(self, color): self.r.write(color[0]) self.g.write(color[1]) self.b.write(color[2]) def on(self): color = 1, 1, 1 self.write(color) def off(self): color = 0, 0, 0 self.write(color)
def __init__(self, r, g, b): self.r = GPIO(GPIO.get_gpio_pin(r), 'out') self.g = GPIO(GPIO.get_gpio_pin(g), 'out') self.b = GPIO(GPIO.get_gpio_pin(b), 'out')
class BaseOverlay(pynq.Overlay): """ The Base overlay for the Pynq-Z2 This overlay is designed to interact with all of the on board peripherals and external interfaces of the Pynq-Z2 board. It exposes the following attributes: Attributes ---------- iop_pmoda : IOP IO processor connected to the PMODA interface iop_pmodb : IOP IO processor connected to the PMODB interface iop_arduino : IOP IO processor connected to the Arduino interface iop_rpi : IOP IO processor connected to the RPi interface trace_rpi : pynq.logictools.TraceAnalyzer Trace analyzer block on RPi interface, controlled by PS. trace_pmoda : pynq.logictools.TraceAnalyzer Trace analyzer block on PMODA interface, controlled by PS. trace_pmodb : pynq.logictools.TraceAnalyzer Trace analyzer block on PMODB interface, controlled by PS. leds : AxiGPIO 4-bit output GPIO for interacting with the green LEDs LD0-3 buttons : AxiGPIO 4-bit input GPIO for interacting with the buttons BTN0-3 switches : AxiGPIO 2-bit input GPIO for interacting with the switches SW0 and SW1 rgbleds : [pynq.board.RGBLED] Wrapper for GPIO for LD4 and LD5 multicolour LEDs video : pynq.lib.video.HDMIWrapper HDMI input and output interfaces audio : pynq.lib.audio.Audio Headphone jack and on-board microphone pin_select : GPIO The pin selection between PMODA (0) and RPI header (1). """ def __init__(self, bitfile, **kwargs): super().__init__(bitfile, **kwargs) if self.is_loaded(): self.iop_pmoda.mbtype = "Pmod" self.iop_pmodb.mbtype = "Pmod" self.iop_arduino.mbtype = "Arduino" self.iop_rpi.mbtype = "Rpi" self.PMODA = self.iop_pmoda.mb_info self.PMODB = self.iop_pmodb.mb_info self.ARDUINO = self.iop_arduino.mb_info self.RPI = self.iop_rpi.mb_info self.pin_select = GPIO( GPIO.get_gpio_pin(self.gpio_dict['pmoda_rp_pin_sel']['index']), "out") self.audio = self.audio_codec_ctrl_0 self.audio.configure() self.leds = self.leds_gpio.channel1 self.switches = self.switches_gpio.channel1 self.buttons = self.btns_gpio.channel1 self.leds.setlength(4) self.switches.setlength(2) self.buttons.setlength(4) self.leds.setdirection("out") self.switches.setdirection("in") self.buttons.setdirection("in") self.rgbleds = ([None] * 4) + [pynq.lib.RGBLED(i) for i in range(4, 6)] self.trace_rpi = TraceAnalyzer( self.trace_analyzer_pi.description['ip'], PYNQZ2_RPI_SPECIFICATION) self.trace_pmoda = TraceAnalyzer( self.trace_analyzer_pi.description['ip'], PYNQZ2_PMODA_SPECIFICATION) self.trace_pmodb = TraceAnalyzer( self.trace_analyzer_pmodb.description['ip'], PYNQZ2_PMODB_SPECIFICATION) def select_pmoda(self): """Select PMODA in the shared pins. This is done by writing a `0` (default) to the `pin_select` GPIO instance. """ self.pin_select.write(0) def select_rpi(self): """Select RASPBERRYPI in the shared pins. This is done by writing a `1` to the `pin_select` GPIO instance. """ self.pin_select.write(1)
class _IOP: """This class controls the active IOP instances in the system. Attributes ---------- mb_program : str The absolute path of the Microblaze program. state : str The status (IDLE, RUNNING, or STOPPED) of the IOP. gpio : GPIO The GPIO instance associated with the IOP. mmio : MMIO The MMIO instance associated with the IOP. """ def __init__(self, iop_name, addr_base, addr_range, gpio_uix, mb_program): """Create a new _IOP object. Parameters ---------- iop_name : str The name of the IP corresponding to the I/O Processor. addr_base : str The base address for the MMIO in hex format. addr_range : str The address range for the MMIO in hex format. gpio_uix : int The user index of the GPIO, starting from 0. mb_program : str The Microblaze program loaded for the IOP. """ self.iop_name = iop_name self.mb_program = iop_const.BIN_LOCATION + mb_program self.state = 'IDLE' self.gpio = GPIO(GPIO.get_gpio_pin(gpio_uix), "out") self.mmio = MMIO(int(addr_base, 16), int(addr_range,16)) self.program() def start(self): """Start the Microblaze of the current IOP. This method will update the status of the IOP. Parameters ---------- None Returns ------- None """ self.state = 'RUNNING'; self.gpio.write(0) def stop(self): """Stop the Microblaze of the current IOP. This method will update the status of the IOP. Parameters ---------- None Returns ------- None """ self.state = 'STOPPED' self.gpio.write(1) def program(self): """This method programs the Microblaze of the IOP. This method is called in __init__(); it can also be called after that. It uses the attribute "self.mb_program" to program the Microblaze. Parameters ---------- None Returns ------- None """ self.stop() PL.load_ip_data(self.iop_name, self.mb_program) self.start()
class _IOP: """This class controls the active IOP instances in the system. Attributes ---------- mb_program : str The absolute path of the Microblaze program. state : str The status (IDLE, RUNNING, or STOPPED) of the IOP. gpio : GPIO The GPIO instance associated with the IOP. mmio : MMIO The MMIO instance associated with the IOP. """ def __init__(self, iop_name, addr_base, addr_range, gpio_uix, mb_program): """Create a new _IOP object. Parameters ---------- iop_name : str The name of the IP corresponding to the I/O Processor. addr_base : int The base address for the MMIO. addr_range : int The address range for the MMIO. gpio_uix : int The user index of the GPIO, starting from 0. mb_program : str The Microblaze program loaded for the IOP. """ self.iop_name = iop_name self.mb_program = iop_const.BIN_LOCATION + mb_program self.state = 'IDLE' self.gpio = GPIO(GPIO.get_gpio_pin(gpio_uix), "out") self.mmio = MMIO(addr_base, addr_range) self.program() def start(self): """Start the Microblaze of the current IOP. This method will update the status of the IOP. Returns ------- None """ self.state = 'RUNNING' self.gpio.write(0) def stop(self): """Stop the Microblaze of the current IOP. This method will update the status of the IOP. Returns ------- None """ self.state = 'STOPPED' self.gpio.write(1) def program(self): """This method programs the Microblaze of the IOP. This method is called in __init__(); it can also be called after that. It uses the attribute "self.mb_program" to program the Microblaze. Returns ------- None """ self.stop() PL.load_ip_data(self.iop_name, self.mb_program) self.start()
class PynqMicroblaze: """This class controls the active Microblaze instances in the system. Attributes ---------- ip_name : str The name of the IP corresponding to the Microblaze. rst_name : str The name of the reset pin for the Microblaze. mb_program : str The absolute path of the Microblaze program. state : str The status (IDLE, RUNNING, or STOPPED) of the Microblaze. reset_pin : GPIO The reset pin associated with the Microblaze. mmio : MMIO The MMIO instance associated with the Microblaze. interrupt : Event An asyncio.Event-like class for waiting on and clearing interrupts. """ def __init__(self, mb_info, mb_program, force=False): """Create a new Microblaze object. It looks for active instances on the same Microblaze, and prevents users from silently reloading the Microblaze program. Users are notified with an exception if a program is already running on the selected Microblaze, to prevent unwanted behavior. Two cases: 1. No previous Microblaze program loaded in the system, or users want to request another instance using the same program. No exception will be raised in this case. 2. There is a previous Microblaze program loaded in the system. Users want to request another instance with a different program. An exception will be raised. Note ---- When a Microblaze program is already loaded in the system, and users want to instantiate another object using a different Microblaze program, users are in danger of losing existing objects. Parameters ---------- mb_info : dict A dictionary storing Microblaze information, such as the IP name and the reset name. mb_program : str The Microblaze program loaded for the processor. Raises ------ RuntimeError When another Microblaze program is already loaded. Examples -------- The `mb_info` is a dictionary storing Microblaze information: >>> mb_info = {'ip_name': 'mb_bram_ctrl_1', 'rst_name': 'mb_reset_1', 'intr_pin_name': 'iop1/dff_en_reset_0/q', 'intr_ack_name': 'mb_1_intr_ack'} """ ip_dict = PL.ip_dict gpio_dict = PL.gpio_dict intr_dict = PL.interrupt_pins # Check program path if not os.path.isfile(mb_program): raise ValueError('{} does not exist.'.format(mb_program)) # Get IP information ip_name = mb_info['ip_name'] if ip_name not in ip_dict.keys(): raise ValueError("No such IP {}.".format(ip_name)) addr_base = ip_dict[ip_name]['phys_addr'] addr_range = ip_dict[ip_name]['addr_range'] ip_state = ip_dict[ip_name]['state'] # Get reset information rst_name = mb_info['rst_name'] if rst_name not in gpio_dict.keys(): raise ValueError("No such reset pin {}.".format(rst_name)) gpio_uix = gpio_dict[rst_name]['index'] # Get interrupt pin information if 'intr_pin_name' in mb_info: intr_pin_name = mb_info['intr_pin_name'] if intr_pin_name not in intr_dict.keys(): raise ValueError( "No such interrupt pin {}.".format(intr_pin_name)) else: intr_pin_name = None # Get interrupt ACK information if 'intr_ack_name' in mb_info: intr_ack_name = mb_info['intr_ack_name'] if intr_ack_name not in gpio_dict.keys(): raise ValueError( "No such interrupt ACK {}.".format(intr_ack_name)) intr_ack_gpio = gpio_dict[intr_ack_name]['index'] else: intr_ack_gpio = None # Set basic attributes self.ip_name = ip_name self.rst_name = rst_name self.mb_program = mb_program self.state = 'IDLE' self.reset_pin = GPIO(GPIO.get_gpio_pin(gpio_uix), "out") self.mmio = MMIO(addr_base, addr_range) # Check to see if Microblaze in user if (ip_state is not None) and (ip_state != mb_program): if force: self.reset() else: raise RuntimeError( 'Another program {} already running.'.format(ip_state)) # Set optional attributes if (intr_pin_name is not None) and (intr_ack_gpio is not None): self.interrupt = MBInterruptEvent(intr_pin_name, intr_ack_gpio) else: self.interrupt = None # Reset, program, and run self.program() def run(self): """Start the Microblaze to run program loaded. This method will update the status of the Microblaze. Returns ------- None """ self.state = 'RUNNING' self.reset_pin.write(0) def reset(self): """Reset the Microblaze to stop it from running. This method will update the status of the Microblaze. Returns ------- None """ self.state = 'STOPPED' self.reset_pin.write(1) def program(self): """This method programs the Microblaze. This method is called in __init__(); it can also be called after that. It uses the attribute `self.mb_program` to program the Microblaze. Returns ------- None """ self.reset() PL.load_ip_data(self.ip_name, self.mb_program) if self.interrupt: self.interrupt.clear() self.run() def write(self, offset, data): """This method write data into the shared memory of the Microblaze. Parameters ---------- offset : int The beginning offset where data are written into. data : int/list A list of 32b words to be written. Returns ------- None """ if type(data) is int: self.mmio.write(offset, data) elif type(data) is list: for i, word in enumerate(data): self.mmio.write(offset + 4 * i, word) else: raise ValueError('Type of write data has to be int or lists.') def read(self, offset, length=1): """This method reads data from the shared memory of Microblaze. Parameters ---------- offset : int The beginning offset where data are read from. length : int The number of data (32-bit int) to be read. Returns ------- int/list An int of a list of data read from the shared memory. """ if length == 1: return self.mmio.read(offset) elif length > 1: return [self.mmio.read(offset + 4 * i) for i in range(length)] else: raise ValueError('Length of read data has to be 1 or more.')
# PS pin EMIO2 is connected to slot 1 RST # PS pin EMIO3 is connected to slot 2 RST # Linux pin number to Xilinx pin numbers are weird and have a large # base number than can change between different releases of Linux # The pynq base fcn will help here! #mio_linux_number = GPIO.get_gpio_base() + 37 # EMIOs start after MIO and there # is fixed offset for ZYNQ (54) and ZYNQ US+ (78) # offset = 2 corresonds to mikroBUS site 1 on Click Mezzanine v1.03 # HD_GPIO_7 # offset = 9? corresonds to mikroBUS site 2 on Click Mezzanine v1.03 # HD_GPIO_14 emio_linux_number = GPIO.get_gpio_base() + 78 + 2 rst_pin = GPIO(emio_linux_number, 'out') # Convert signed into unsigned from i2c read byte def i2c_read_byte(i2c, DA, DR): return (0xff & i2c.read_byte_data(DA, DR)) def i2c_write_byte(i2c, DA, DR, val): return (i2c.write_byte_data(DA, DR, val)) # Reset is usually active LOW, hold Click in reset while I2C is setup # and reset the i2c mux
def __init__(self, mb_info, mb_program, force=False): """Create a new Microblaze object. It looks for active instances on the same Microblaze, and prevents users from silently reloading the Microblaze program. Users are notified with an exception if a program is already running on the selected Microblaze, to prevent unwanted behavior. Two cases: 1. No previous Microblaze program loaded in the system, or users want to request another instance using the same program. No exception will be raised in this case. 2. There is a previous Microblaze program loaded in the system. Users want to request another instance with a different program. An exception will be raised. Note ---- When a Microblaze program is already loaded in the system, and users want to instantiate another object using a different Microblaze program, users are in danger of losing existing objects. Parameters ---------- mb_info : dict A dictionary storing Microblaze information, such as the IP name and the reset name. mb_program : str The Microblaze program loaded for the processor. Raises ------ RuntimeError When another Microblaze program is already loaded. Examples -------- The `mb_info` is a dictionary storing Microblaze information: >>> mb_info = {'ip_name': 'mb_bram_ctrl_1', 'rst_name': 'mb_reset_1', 'intr_pin_name': 'iop1/dff_en_reset_0/q', 'intr_ack_name': 'mb_1_intr_ack'} """ ip_dict = PL.ip_dict gpio_dict = PL.gpio_dict intr_dict = PL.interrupt_pins # Check program path if not os.path.isfile(mb_program): raise ValueError('{} does not exist.'.format(mb_program)) # Get IP information ip_name = mb_info['ip_name'] if ip_name not in ip_dict.keys(): raise ValueError("No such IP {}.".format(ip_name)) addr_base = ip_dict[ip_name]['phys_addr'] addr_range = ip_dict[ip_name]['addr_range'] ip_state = ip_dict[ip_name]['state'] # Get reset information rst_name = mb_info['rst_name'] if rst_name not in gpio_dict.keys(): raise ValueError("No such reset pin {}.".format(rst_name)) gpio_uix = gpio_dict[rst_name]['index'] # Get interrupt pin information if 'intr_pin_name' in mb_info: intr_pin_name = mb_info['intr_pin_name'] if intr_pin_name not in intr_dict.keys(): raise ValueError( "No such interrupt pin {}.".format(intr_pin_name)) else: intr_pin_name = None # Get interrupt ACK information if 'intr_ack_name' in mb_info: intr_ack_name = mb_info['intr_ack_name'] if intr_ack_name not in gpio_dict.keys(): raise ValueError( "No such interrupt ACK {}.".format(intr_ack_name)) intr_ack_gpio = gpio_dict[intr_ack_name]['index'] else: intr_ack_gpio = None # Set basic attributes self.ip_name = ip_name self.rst_name = rst_name self.mb_program = mb_program self.state = 'IDLE' self.reset_pin = GPIO(GPIO.get_gpio_pin(gpio_uix), "out") self.mmio = MMIO(addr_base, addr_range) # Check to see if Microblaze in user if (ip_state is not None) and (ip_state != mb_program): if force: self.reset() else: raise RuntimeError( 'Another program {} already running.'.format(ip_state)) # Set optional attributes if (intr_pin_name is not None) and (intr_ack_gpio is not None): self.interrupt = MBInterruptEvent(intr_pin_name, intr_ack_gpio) else: self.interrupt = None # Reset, program, and run self.program()
class ioOverlay(Overlay): """A simple Physical IO Overlay for PYNQ. This overlay is implemented with a single CtrlLoop core connected directly to the ARM Core AXI interface. """ __RESET_VALUE = 0 __NRESET_VALUE = 1 """ For convenince, we define register offsets that are scraped from the HLS implementation header files. """ __IO_AP_CTRL_OFF = 0x00 __IO_AP_CTRL_START_IDX = 0 __IO_AP_CTRL_DONE_IDX = 1 __IO_AP_CTRL_IDLE_IDX = 2 __IO_AP_CTRL_READY_IDX = 3 __IO_AP_CTRL_AUTORESTART_IDX = 7 __IO_GIE_OFF = 0x04 __IO_IER_OFF = 0x08 __IO_ISR_OFF = 0x0C """These define the 'reg' argument to the 'io' HLS function. The memory space defined here is shared between the HLS core and the ARM PS. """ __IO_REG_OFF = 0x200 __IO_REG_LEN = 0x100 def __init__(self, bitfile, **kwargs): """Initializes a new ioOverlay object. """ # The following lines do some path searching to enable a # PYNQ-Like API for Overlays. For example, without these # lines you cannot call ioOverlay('io.bit') because # io.bit is not on the bitstream search path. The # following lines fix this for any non-PYNQ Overlay # # You can safely reuse, and ignore the following lines # # Get file path of the current class (i.e. /opt/python3.6/<...>/stream.py) file_path = os.path.abspath(inspect.getfile(inspect.currentframe())) # Get directory path of the current class (i.e. /opt/python3.6/<...>/stream/) dir_path = os.path.dirname(file_path) # Update the bitfile path to search in dir_path bitfile = os.path.join(dir_path, bitfile) # Upload the bitfile (and parse the colocated .tcl script) super().__init__(bitfile, **kwargs) # Manually define the GPIO pin that drives reset self.__resetPin = GPIO(GPIO.get_gpio_pin(0), "out") # Define a Register object at address 0x0 of the IO address space # We will use this to set bits and start the core (see start()) # Do NOT write to __ap_ctrl unless __resetPin has been set to __NRESET_VALUE self.nreset() self.__ap_ctrl = Register(self.ioCore.mmio.base_addr, 32) self.__hls_reg = MMIO(self.ioCore.mmio.base_addr + self.__IO_REG_OFF, self.__IO_REG_LEN) def __set_autorestart(self): """ Set the autorestart bit of the HLS core """ self.__ap_ctrl[self.__IO_AP_CTRL_AUTORESTART_IDX] = 1 def __clear_autorestart(self): """ Clear the autorestart bit """ self.__ap_ctrl[self.__IO_AP_CTRL_AUTORESTART_IDX] = 0 def __start(self): """Raise AP_START and enable the HLS core """ self.__ap_ctrl[self.__IO_AP_CTRL_START_IDX] = 1 def __stop(self): """Lower AP_START and disable the HLS core """ self.__ap_ctrl[self.__IO_AP_CTRL_START_IDX] = 0 def nreset(self): """Set the reset pin to self.__NRESET_VALUE to place the core into not-reset (usually run) """ self.__resetPin.write(self.__NRESET_VALUE) def reset(self): """Set the reset pin to self.__RESET_VALUE to place the core into reset """ self.__resetPin.write(self.__RESET_VALUE) def launch(self): """ Start and detatch computation on the io HLS core Returns ------- Nothing """ self.__set_autorestart() self.__start() return def land(self): """ Re-Connect and Terminate Computation on the io HLS core Returns ------- The 4-bit value representing the value of the buttons. """ self.__clear_autorestart() while(not self.__ap_ctrl[self.__IO_AP_CTRL_DONE_IDX]): pass self.__stop() return self.__hls_reg.read(0) def run(self): """ Launch computation on the io HLS core Returns ------- The 4-bit value representing the value of the buttons. """ self.__start() while(not self.__ap_ctrl[self.__IO_AP_CTRL_DONE_IDX]): pass self.__stop() return self.__hls_reg.read(0)
class Pin: IN = 0 OUT = 1 LOW = 0 HIGH = 1 PULL_NONE = 0 PULL_UP = 1 PULL_DOWN = 2 id = None _value = LOW _mode = IN pynq_gpio = None def __init__(self, pin_id): self.id = pin_id def __repr__(self): return str(self.id) def __eq__(self, other): return self.id == other def init(self, mode=None, pull=None): if mode != None: if mode == self.IN: self._mode = self.IN # GPIO.setup(self.id, GPIO.IN) if self.pynq_gpio != None: self.pynq_gpio.release() self.pynq_gpio = GPIO(self.id, 'in') elif mode == self.OUT: self._mode = self.OUT # GPIO.setup(self.id, GPIO.OUT) if self.pynq_gpio != None: self.pynq_gpio.release() self.pynq_gpio = GPIO(self.id, 'out') else: raise RuntimeError("Invalid mode for pin: %s" % self.id) # if pull != None: # if self._mode != self.IN: # raise RuntimeError("Cannot set pull resistor on output") # if pull == self.PULL_UP: # GPIO.setup(self.id, GPIO.IN, pull_up_down=GPIO.PUD_UP) # elif pull == self.PULL_DOWN: # GPIO.setup(self.id, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) # else: # raise RuntimeError("Invalid pull for pin: %s" % self.id) def value(self, val=None): if val != None: if val == self.LOW: self._value = val # GPIO.output(self.id, val) self.pynq_gpio.write(val) elif val == self.HIGH: self._value = val # GPIO.output(self.id, val) self.pynq_gpio.write(val) else: raise RuntimeError("Invalid value for pin") else: # return GPIO.input(self.id) return self.pynq_gpio.read()
class houghOverlay(Overlay): """ This overlay contains the inferface to the PL image processing filter. It extracts the edges of the image, the lines polar parameters and the lines segments as well. The image size is 640x480. """ __HEIGHT = 480 __WIDTH = 640 __LINES = 100 __SEGMENTS = 200 __RESET_VALUE = 0 __NRESET_VALUE = 1 # Registers offset __HOUGH_AP_CTRL_OFF = 0x00 __HOUGH_AP_CTRL_START_IDX = 0 __HOUGH_AP_CTRL_DONE_IDX = 1 __HOUGH_AP_CTRL_IDLE_IDX = 2 __HOUGH_AP_CTRL_READY_IDX = 3 __HOUGH_GIE_OFF = 0x04 __HOUGH_IER_OFF = 0x08 __HOUGH_ISR_OFF = 0x0C # M_AXI offset __OUTRHO_ADDR = 0x10 __OUTTHETA_ADDR = 0x18 __NUM_OF_LINES_ADDR = 0x20 __LINES_SEGMENTS_ADDR = 0x28 __NUM_OF_SEGMENTS_ADDR = 0x30 # S_AXILITE offset __EDGES_LTHR_ADDR = 0x38 __EDGES_HTHR_ADDR = 0x40 __LINES_THR_ADDR = 0x48 __GAP_SIZE_ADDR = 0x50 __MIN_LENGTH_ADDR = 0x58 def __init__(self, bitfile, **kwargs): """ Constructor (load the bit file) """ file_path = os.path.abspath(inspect.getfile(inspect.currentframe())) dir_path = os.path.dirname(file_path) bitfile = os.path.join(dir_path, bitfile) super().__init__(bitfile, **kwargs) # Manually define the GPIO pin that drives reset self.__resetPin = GPIO(GPIO.get_gpio_pin(0), "out") self.nreset() # For convenience self.__hough = self.image_processing.hough_accel_0 self.__dma = self.image_processing.axi_dma_0 # Define a Register object at address 0x00 of the overlay address space base_addr = self.__hough.mmio.base_addr self.__ap_ctrl = Register(base_addr, 32) self.__outrho_offset = Register(base_addr + self.__OUTRHO_ADDR, 32) self.__outtheta_offset = Register(base_addr + self.__OUTTHETA_ADDR, 32) self.__num_of_lines_offset = Register(base_addr + self.__NUM_OF_LINES_ADDR, 32) self.__segments_offset = Register(base_addr + self.__LINES_SEGMENTS_ADDR, 32) self.__num_of_segments_offset = Register(base_addr + self.__NUM_OF_SEGMENTS_ADDR, 32) # DMA transfer engine self.__xlnk = Xlnk() # Memory pre-allocation self.__cma_rho = self.__xlnk.cma_array(self.__LINES, np.single) self.__cma_theta = self.__xlnk.cma_array(self.__LINES, np.single) self.__cma_numoflines = self.__xlnk.cma_array(1, np.int32) self.__cma_segments = self.__xlnk.cma_array((self.__SEGMENTS, 4), np.int32) self.__cma_numofsegments = self.__xlnk.cma_array(1, np.int32) self.__cmabuf_dest = self.__xlnk.cma_array((self.__HEIGHT, self.__WIDTH, 3), np.uint8) # public self.frame = self.__xlnk.cma_array((self.__HEIGHT, self.__WIDTH, 3), np.uint8) # Write address of M_AXI to HLS core self.__outrho_offset[31:0] = self.__xlnk.cma_get_phy_addr(self.__cma_rho.pointer) self.__outtheta_offset[31:0] = self.__xlnk.cma_get_phy_addr(self.__cma_theta.pointer) self.__num_of_lines_offset[31:0] = self.__xlnk.cma_get_phy_addr(self.__cma_numoflines.pointer) self.__segments_offset[31:0] = self.__xlnk.cma_get_phy_addr(self.__cma_segments.pointer) self.__num_of_segments_offset[31:0] = self.__xlnk.cma_get_phy_addr(self.__cma_numofsegments.pointer) # Performs the computation for the first time to avoid bad behavior on the first call. # For a small number of segments, maybe not all segments will be detected if we don't # call the HoughLines function for the first time here. self.frame[:] = cv2.imread(dir_path+'/star.png') self.HoughLines(20,30,80,5,30) def __del__(self): self.__cmabuf_dest.freebuffer() self.__cma_rho.freebuffer() self.__cma_theta.freebuffer() self.__cma_numoflines.freebuffer() self.__cma_segments.freebuffer() self.__cma_numofsegments.freebuffer() self.frame.freebuffer() def __start(self): """ Raise AP_START and enable the HLS core """ self.__ap_ctrl[self.__HOUGH_AP_CTRL_START_IDX] = 1 pass def __stop(self): """ Lower AP_START and disable the HLS core """ self.__ap_ctrl[self.__HOUGH_AP_CTRL_START_IDX] = 0 pass def nreset(self): """ Set the reset pin to self.__NRESET_VALUE to place the core into not-reset (usually run) """ self.__resetPin.write(self.__NRESET_VALUE) def reset(self): """ Set the reset pin to self.__RESET_VALUE to place the core into reset """ self.__resetPin.write(self.__RESET_VALUE) def __loadParameters(self, **kwargs): """ Load the Hough overlay coefficients into the HLS core """ edges_lthr = kwargs.get('edges_lthr') edges_hthr = kwargs.get('edges_hthr') lines_thr = kwargs.get('lines_thr') gap_size = kwargs.get('gap_size') min_length = kwargs.get('min_length') self.__hough.write(self.__EDGES_LTHR_ADDR, edges_lthr) self.__hough.write(self.__EDGES_HTHR_ADDR, edges_hthr) self.__hough.write(self.__LINES_THR_ADDR, lines_thr) self.__hough.write(self.__GAP_SIZE_ADDR, gap_size) self.__hough.write(self.__MIN_LENGTH_ADDR, min_length) def HoughLines(self, ed_lthr, ed_hthr, thr, gap, minL, canny = None): """ Launch computation on the HLS core """ self.__loadParameters(edges_lthr = ed_lthr, edges_hthr = ed_hthr, lines_thr = thr, gap_size = gap, min_length = minL) # To check when the computation will finish self.__cma_numofsegments[0] = -1 # impossible to have numofsegments < 0 # FPGA --> ARM self.__dma.recvchannel.transfer(self.__cmabuf_dest) # ARM --> FPGA self.__dma.sendchannel.transfer(self.frame) # Raise the AP_START bit of the AP_CTRL to initiate computation self.__start() # Wait for the DMA engines to finish self.__dma.sendchannel.wait() self.__dma.recvchannel.wait() # delay to wait for the m_axi output while(self.__cma_numofsegments[0] == -1): continue # Lower the AP_START bit of the AP_CTRL to terminate computation self.__stop() # Return the values as numpy arrays n_lines = self.__cma_numoflines[0] n_segments = self.__cma_numofsegments[0] lines = np.zeros((n_lines,2), dtype = np.single) segments = np.zeros((n_segments,4), dtype = np.int32) lines[:,0] = self.__cma_rho[0:n_lines] lines[:,1] = self.__cma_theta[0:n_lines] segments = self.__cma_segments[0:n_segments][:] if (type(canny) is np.ndarray and canny.shape == (self.__HEIGHT, self.__WIDTH, 3) and canny.dtype == np.uint8): canny[:] = self.__cmabuf_dest[:] return [lines, segments]
class sharedmemOverlay(Overlay): """A simple Mem-Mapped Overlay for PYNQ. This overlay is implemented with a single Matrix Multiply Core fed connected directly to the ARM Core AXI interface. """ __RESET_VALUE = 0 __NRESET_VALUE = 1 """ For convenince, we define register offsets that are scraped from the HLS implementation header files. """ __MMULT_AP_CTRL_OFF = 0x00 __MMULT_AP_CTRL_START_IDX = 0 __MMULT_AP_CTRL_DONE_IDX = 1 __MMULT_AP_CTRL_IDLE_IDX = 2 __MMULT_AP_CTRL_READY_IDX = 3 __MMULT_GIE_OFF = 0x04 __MMULT_IER_OFF = 0x08 __MMULT_ISR_OFF = 0x0C __MMULT_ADDR_A_DATA = 0x10 __MMULT_ADDR_BT_DATA = 0x18 __MMULT_ADDR_C_DATA = 0x20 __MMULT_A_SHAPE = (100, 100) __MMULT_BT_SHAPE = (100, 100) __MMULT_C_SHAPE = (100, 100) __MMULT_A_SIZE = __MMULT_A_SHAPE[0] * __MMULT_A_SHAPE[1] __MMULT_BT_SIZE = __MMULT_BT_SHAPE[0] * __MMULT_BT_SHAPE[1] __MMULT_C_SIZE = __MMULT_C_SHAPE[0] * __MMULT_C_SHAPE[1] def __init__(self, bitfile, **kwargs): """Initializes a new sharedmemOverlay object. """ # The following lines do some path searching to enable a # PYNQ-Like API for Overlays. For example, without these # lines you cannot call sharedmemOverlay('sharedmem.bit') because # sharedmem.bit is not on the bitstream search path. The # following lines fix this for any non-PYNQ Overlay # # You can safely reuse, and ignore the following lines # # Get file path of the current class (i.e. /opt/python3.6/<...>/sharedmem.py) file_path = os.path.abspath(inspect.getfile(inspect.currentframe())) # Get directory path of the current class (i.e. /opt/python3.6/<...>/sharedmem/) dir_path = os.path.dirname(file_path) # Update the bitfile path to search in dir_path bitfile = os.path.join(dir_path, bitfile) # Upload the bitfile (and parse the colocated .tcl script) super().__init__(bitfile, **kwargs) # Manually define the GPIO pin that drives reset self.__resetPin = GPIO(GPIO.get_gpio_pin(0), "out") self.nreset() # Define a Register object at address 0x0 of the mmult address space # We will use this to set bits and start the core (see start()) # Do NOT write to __ap_ctrl unless __resetPin has been set to __NRESET_VALUE self.__ap_ctrl = Register(self.mmultCore.mmio.base_addr, 32) self.__a_offset = Register( self.mmultCore.mmio.base_addr + self.__MMULT_ADDR_A_DATA, 32) self.__bt_offset = Register( self.mmultCore.mmio.base_addr + self.__MMULT_ADDR_BT_DATA, 32) self.__c_offset = Register( self.mmultCore.mmio.base_addr + self.__MMULT_ADDR_C_DATA, 32) self.xlnk = Xlnk() def __start(self): """Raise AP_START and enable the HLS core """ self.__ap_ctrl[self.__MMULT_AP_CTRL_START_IDX] = 1 pass def __stop(self): """Lower AP_START and disable the HLS core """ self.__ap_ctrl[self.__MMULT_AP_CTRL_START_IDX] = 0 pass def nreset(self): """Set the reset pin to self.__NRESET_VALUE to place the core into not-reset (usually run) """ self.__resetPin.write(self.__NRESET_VALUE) def reset(self): """Set the reset pin to self.__RESET_VALUE to place the core into reset """ self.__resetPin.write(self.__RESET_VALUE) def run(self, A, B): """ Launch computation on the mmult HLS core Parameters ---------- A : Numpy ndarray of at most size TODOxTODO (it will be padded) A buffer containing ND Array Elements to be transferred to the core B : Numpy ndarray of at most size TODOxTODO (it will be padded) A buffer containing ND Array Elements to be transferred to the core """ if (not isinstance(A, np.ndarray)): raise TypeError("Parameter A must be an instance of " "numpy.ndarray") if (not isinstance(B, np.ndarray)): raise RuntimeError("Parameter B must be an instance of " "numpy.ndarray") sza = A.shape if (sza[0] > self.__MMULT_A_SHAPE[0]): raise RuntimeError( f"Dimension 0 of A must be less than or equal to" f"{self.__MMULT_A_SHAPE[0]}") if (sza[1] > self.__MMULT_A_SHAPE[1]): raise RuntimeError( f"Dimension 1 of A must be less than or equal to" f"{self.__MMULT_A_SHAPE[1]}") szb = B.shape if (szb[0] > self.__MMULT_BT_SHAPE[1]): raise RuntimeError( f"Dimension 0 of B must be less than or equal to" f"{self.__MMULT_BT_SHAPE[0]}") if (szb[1] > self.__MMULT_BT_SHAPE[0]): raise RuntimeError( f"Dimension 1 of B must be less than or equal to" f"{self.__MMULT_BT_SHAPE[1]}") # Check size of A # Check size of B # Allocate C a = self.xlnk.cma_array(self.__MMULT_A_SHAPE, "int") bt = self.xlnk.cma_array(self.__MMULT_BT_SHAPE, "int") c = self.xlnk.cma_array(self.__MMULT_C_SHAPE, "int") # Copy A->a a[:A.shape[0], :A.shape[1]] = A # Copy BT->bt bt[:B.shape[1], :B.shape[0]] = B.transpose() # TODO: Enable Interrupts # Write address of a, bt, c to HLS core self.__a_offset[31:0] = self.xlnk.cma_get_phy_addr(a.pointer) self.__bt_offset[31:0] = self.xlnk.cma_get_phy_addr(bt.pointer) self.__c_offset[31:0] = self.xlnk.cma_get_phy_addr(c.pointer) self.__start() # TODO: Wait for ASYNC Interrupt # TODO: Clear Interrupt import time time.sleep(1) self.__stop() C = np.zeros((A.shape[0], B.shape[1]), np.int32) # Transform C into a Numpy Array C[:A.shape[0], :B.shape[1]] = c[:A.shape[0], :B.shape[1]] a.freebuffer() bt.freebuffer() c.freebuffer() return C
from pynq import GPIO import time import smbus # This will minipulate a LED Ring R Click Board in Slot 1 # of the Ultra96 mikro click mezzanine board # Obtain the reset pin of slot 1 of the Ultra96 mikro mezzanine board # PS pin MIO37 is connected to slot 1 RST # PS pin MIO40 is connected to slot 2 RST # Linux pin number to Xilinx pin numbers are weird and have a large # base number than can change between different releases of Linux # The pynq base fcn will help here! base for 2018.2 was 338 mio_linux_number = GPIO.get_gpio_base() + 37 # EMIOs start after MIO and there # is fixed offset for ZYNQ (54) and ZYNQ US+ (78) # emio_linux_number = GPIO.get_gpio_pin(emio_offset) rst_pin = GPIO(mio_linux_number, 'out') # Reset is usually active LOW rst_pin.write(1) time.sleep(.1) rst_pin.write(0) time.sleep(.1) rst_pin.write(1) print("Start I2C Test\n")