def elaborate(self, platform): m = Module() m.submodules += self.ila # Generate our clock domains. clocking = LunaECP5DomainGenerator(clock_frequencies=CLOCK_FREQUENCIES) m.submodules.clocking = clocking # Clock divider / counter. m.d.fast += self.counter.eq(self.counter + 1) # Set our ILA to trigger each time the counter is at a random value. # This shows off our example a bit better than counting at zero. m.d.comb += self.ila.trigger.eq(self.counter == 7) # Grab our I/O connectors. leds = [platform.request("led", i, dir="o") for i in range(0, 6)] spi_bus = synchronize(m, platform.request('debug_spi'), o_domain='fast') # Attach the LEDs and User I/O to the MSBs of our counter. m.d.comb += Cat(leds).eq(self.counter[-7:-1]) # Connect our ILA up to our board's aux SPI. m.d.comb += self.ila.spi.connect(spi_bus) # Return our elaborated module. return m
def elaborate(self, platform): m = Module() m.submodules += self.ila # Clock divider / counter. m.d.sync += self.counter.eq(self.counter + 1) # Set our ILA to trigger each time the counter is at a random value. # This shows off our example a bit better than counting at zero. m.d.comb += self.ila.trigger.eq(self.counter == 7) # Grab our I/O connectors. leds = [ platform.request_optional("led", i, default=NullPin(), dir="o") for i in range(0, 6) ] spi_bus = synchronize(m, platform.request('debug_spi')) # Attach the LEDs and User I/O to the MSBs of our counter. m.d.comb += Cat(leds).eq(self.counter[-7:-1]) # Connect our ILA up to our board's aux SPI. m.d.comb += self.ila.spi.connect(spi_bus) # Return our elaborated module. return m
def elaborate(self, platform): m = Module() board_spi = platform.request("debug_spi") # Create a set of registers, and expose them over SPI. spi_registers = SPIRegisterInterface( default_read_value=0x4C554E41) #default read = u'LUNA' m.submodules.spi_registers = spi_registers # Fill in some example registers. # (Register 0 is reserved for size autonegotiation). spi_registers.add_read_only_register(1, read=0xc001cafe) led_reg = spi_registers.add_register(2, size=6, name="leds") spi_registers.add_read_only_register(3, read=0xdeadbeef) # ... and tie our LED register to our LEDs. led_out = Cat( [platform.request("led", i, dir="o") for i in range(0, 6)]) m.d.comb += led_out.eq(led_reg) # Connect up our synchronized copies of the SPI registers. spi = synchronize(m, board_spi) m.d.comb += spi_registers.spi.connect(spi) return m
def elaborate(self, platform): m = Module() m.submodules += self.ila # Grab a reference to our debug-SPI bus. board_spi = synchronize(m, platform.request("debug_spi")) # Clock divider / counter. m.d.sync += self.counter.eq(self.counter + 1) # Another example signal, for variety. m.d.sync += self.toggle.eq(~self.toggle) # Create an SPI bus for our ILA. ila_spi = SPIBus() m.d.comb += [ self.ila.spi .connect(ila_spi), # For sharing, we'll connect the _inverse_ of the primary # chip select to our ILA bus. This will allow us to send # ILA data when CS is un-asserted, and register data when # CS is asserted. ila_spi.cs .eq(~board_spi.cs) ] # Create a set of registers... spi_registers = SPIRegisterInterface() m.submodules.spi_registers = spi_registers # ... and an SPI bus for them. reg_spi = SPIBus() m.d.comb += [ spi_registers.spi .connect(reg_spi), reg_spi.cs .eq(board_spi.cs) ] # Multiplex our ILA and register SPI busses. m.submodules.mux = SPIMultiplexer([ila_spi, reg_spi]) m.d.comb += m.submodules.mux.shared_lines.connect(board_spi) # Add a simple ID register to demonstrate our registers. spi_registers.add_read_only_register(REGISTER_ID, read=0xDEADBEEF) # Create a simple SFR that will trigger an ILA capture when written, # and which will display our sample status read. spi_registers.add_sfr(REGISTER_ILA, read=self.ila.complete, write_strobe=self.ila.trigger ) # Attach the LEDs and User I/O to the MSBs of our counter. leds = [platform.request("led", i, dir="o") for i in range(0, 6)] m.d.comb += Cat(leds).eq(self.counter[-7:-1]) # Return our elaborated module. return m
def elaborate(self, platform): m = Module() # Generate our clock domains. clocking = LunaECP5DomainGenerator() m.submodules.clocking = clocking # Grab a reference to our debug-SPI bus. board_spi = synchronize(m, platform.request("debug_spi")) # Create our SPI-connected registers. m.submodules.spi_registers = spi_registers = SPIRegisterInterface( 7, 32) m.d.comb += spi_registers.spi.connect(board_spi) # Create our UMTI translator. ulpi = platform.request("sideband_phy") m.submodules.umti = umti = UMTITranslator(ulpi=ulpi) # Strap our power controls to be in VBUS passthrough by default, # on the target port. m.d.comb += [ platform.request("power_a_port").eq(0), platform.request("pass_through_vbus").eq(1), ] # Hook up our LEDs to status signals. m.d.comb += [ platform.request("led", 0).eq(umti.vbus_valid), platform.request("led", 1).eq(umti.session_valid), platform.request("led", 2).eq(umti.session_end), platform.request("led", 3).eq(umti.rx_active), platform.request("led", 4).eq(umti.rx_error) ] spi_registers.add_read_only_register(1, read=umti.last_rx_command) # For debugging: mirror some ULPI signals on the UIO. user_io = Cat( platform.request("user_io", i, dir="o") for i in range(0, 4)) m.d.comb += [ user_io[0].eq(ClockSignal("ulpi")), user_io[1].eq(ulpi.dir), user_io[2].eq(ulpi.nxt), user_io[3].eq(ulpi.stp), ] # Return our elaborated module. return m
def elaborate(self, platform): m = Module() # Create a set of registers, and expose them over SPI. board_spi = platform.request("debug_spi") spi_registers = SPIRegisterInterface(default_read_value=-1) m.submodules.spi_registers = spi_registers # Identify ourselves as the SPI flash bridge. spi_registers.add_read_only_register(REGISTER_ID, read=0x53504946) # # SPI flash passthrough connections. # flash_sdo = Signal() spi_flash_bus = platform.request('spi_flash') spi_flash_passthrough = ECP5ConfigurationFlashInterface( bus=spi_flash_bus) m.submodules += spi_flash_passthrough m.d.comb += [ spi_flash_passthrough.sck.eq(board_spi.sck), spi_flash_passthrough.sdi.eq(board_spi.sdi), flash_sdo.eq(spi_flash_passthrough.sdo), ] # # Structural connections. # spi = synchronize(m, board_spi) # Select the passthrough or gateware SPI based on our chip-select values. gateware_sdo = Signal() with m.If(board_spi.cs): m.d.comb += board_spi.sdo.eq(gateware_sdo) with m.Else(): m.d.comb += board_spi.sdo.eq(flash_sdo) # Connect our register interface to our board SPI. m.d.comb += [ spi_registers.spi.sck.eq(spi.sck), spi_registers.spi.sdi.eq(spi.sdi), gateware_sdo.eq(spi_registers.spi.sdo), spi_registers.spi.cs.eq(spi.cs) ] return m
def elaborate(self, platform): m = Module() board_spi = platform.request("debug_spi") # Use command interface. m.submodules.interface = self.interface # Synchronize and connect SPI. spi = synchronize(m, board_spi) m.d.comb += self.interface.spi.connect(spi) # Turn on a single LED, to show something's running. led = platform.request('led', 0) m.d.comb += led.eq(1) # Echo back the last received data. m.d.comb += self.interface.word_out.eq(self.interface.word_in) return m
def elaborate(self, platform): m = Module() # Generate our clock domains. clocking = LunaECP5DomainGenerator() m.submodules.clocking = clocking # Grab a reference to our debug-SPI bus. board_spi = synchronize(m, platform.request("debug_spi")) # Create a set of registers... spi_registers = SPIRegisterInterface(7, 32) m.submodules.spi_registers = spi_registers m.d.comb += spi_registers.spi.connect(board_spi) # # HyperRAM test connections. # ram_bus = platform.request('ram') psram = HyperRAMInterface(bus=ram_bus, **platform.ram_timings) m.submodules += psram psram_address_changed = Signal() psram_address = spi_registers.add_register( REGISTER_RAM_REG_ADDR, write_strobe=psram_address_changed) spi_registers.add_sfr(REGISTER_RAM_VALUE, read=psram.read_data) # Hook up our PSRAM. m.d.comb += [ ram_bus.reset.eq(0), psram.single_page.eq(0), psram.perform_write.eq(0), psram.register_space.eq(1), psram.final_word.eq(1), psram.start_transfer.eq(psram_address_changed), psram.address.eq(psram_address), ] # Return our elaborated module. return m
def elaborate(self, platform): m = Module() # Generate our clock domains. clocking = LunaECP5DomainGenerator(clock_frequencies=CLOCK_FREQUENCIES) m.submodules.clocking = clocking # Create a set of registers, and expose them over SPI. board_spi = platform.request("debug_spi") spi_registers = SPIRegisterInterface(default_read_value=-1) m.submodules.spi_registers = spi_registers # Simple applet ID register. spi_registers.add_read_only_register(REGISTER_ID, read=0x54455354) # LED test register. led_reg = spi_registers.add_register(REGISTER_LEDS, size=6, name="leds", reset=0b10) led_out = Cat([platform.request("led", i, dir="o") for i in range(0, 6)]) m.d.comb += led_out.eq(led_reg) # # Target power test register. # Note: these values assume you've populated the correct AP22814 for # your revision (AP22814As for rev0.2+, and AP22814Bs for rev0.1). # bits [1:0]: 0 = power off # 1 = provide A-port VBUS # 2 = pass through target VBUS # power_test_reg = Signal(3) power_test_write_strobe = Signal() power_test_write_value = Signal(2) spi_registers.add_sfr(REGISTER_TARGET_POWER, read=power_test_reg, write_strobe=power_test_write_strobe, write_signal=power_test_write_value ) # Store the values for our enable bits. with m.If(power_test_write_strobe): m.d.sync += power_test_reg[0:2].eq(power_test_write_value) # Decode the enable bits and control the two power supplies. power_a_port = platform.request("power_a_port") power_passthrough = platform.request("pass_through_vbus") with m.If(power_test_reg[0:2] == 1): m.d.comb += [ power_a_port .eq(1), power_passthrough .eq(0) ] with m.Elif(power_test_reg[0:2] == 2): m.d.comb += [ power_a_port .eq(0), power_passthrough .eq(1) ] with m.Else(): m.d.comb += [ power_a_port .eq(0), power_passthrough .eq(0) ] # # User IO GPIO registers. # # Data direction register. user_io_dir = spi_registers.add_register(REGISTER_USER_IO_DIR, size=4) # Pin (input) state register. user_io_in = Signal(4) spi_registers.add_sfr(REGISTER_USER_IO_IN, read=user_io_in) # Output value register. user_io_out = spi_registers.add_register(REGISTER_USER_IO_OUT, size=4) # Grab and connect each of our user-I/O ports our GPIO registers. for i in range(4): pin = platform.request("user_io", i) m.d.comb += [ pin.oe .eq(user_io_dir[i]), user_io_in[i] .eq(pin.i), pin.o .eq(user_io_out[i]) ] # # ULPI PHY windows # self.add_ulpi_registers(m, platform, ulpi_bus="target_phy", register_base=REGISTER_TARGET_ADDR ) self.add_ulpi_registers(m, platform, ulpi_bus="host_phy", register_base=REGISTER_HOST_ADDR ) self.add_ulpi_registers(m, platform, ulpi_bus="sideband_phy", register_base=REGISTER_SIDEBAND_ADDR ) # # HyperRAM test connections. # ram_bus = platform.request('ram') psram = HyperRAMInterface(bus=ram_bus) m.submodules += psram psram_address_changed = Signal() psram_address = spi_registers.add_register(REGISTER_RAM_REG_ADDR, write_strobe=psram_address_changed) spi_registers.add_sfr(REGISTER_RAM_VALUE, read=psram.read_data) # Hook up our PSRAM. m.d.comb += [ ram_bus.reset .eq(0), psram.single_page .eq(0), psram.perform_write .eq(0), psram.register_space .eq(1), psram.final_word .eq(1), psram.start_transfer .eq(psram_address_changed), psram.address .eq(psram_address), ] # # SPI flash passthrough connections. # flash_sdo = Signal() spi_flash_bus = platform.request('spi_flash') spi_flash_passthrough = ECP5ConfigurationFlashInterface(bus=spi_flash_bus) m.submodules += spi_flash_passthrough m.d.comb += [ spi_flash_passthrough.sck .eq(board_spi.sck), spi_flash_passthrough.sdi .eq(board_spi.sdi), flash_sdo .eq(spi_flash_passthrough.sdo), ] # # Synchronize each of our I/O SPI signals, where necessary. # spi = synchronize(m, board_spi) # Select the passthrough or gateware SPI based on our chip-select values. gateware_sdo = Signal() with m.If(spi_registers.spi.cs): m.d.comb += board_spi.sdo.eq(gateware_sdo) with m.Else(): m.d.comb += board_spi.sdo.eq(flash_sdo) # Connect our register interface to our board SPI. m.d.comb += [ spi_registers.spi.sck .eq(spi.sck), spi_registers.spi.sdi .eq(spi.sdi), gateware_sdo .eq(spi_registers.spi.sdo), spi_registers.spi.cs .eq(spi.cs) ] return m
def elaborate(self, platform): m = Module() # Generate our clock domains. clocking = LunaECP5DomainGenerator() m.submodules.clocking = clocking # Grab a reference to our debug-SPI bus. board_spi = synchronize(m, platform.request("debug_spi")) # Create our SPI-connected registers. m.submodules.spi_registers = spi_registers = SPIRegisterInterface(7, 8) m.d.comb += spi_registers.spi.connect(board_spi) # Create our UMTI translator. ulpi = platform.request("target_phy") m.submodules.umti = umti = UMTITranslator(ulpi=ulpi) # Strap our power controls to be in VBUS passthrough by default, # on the target port. m.d.comb += [ platform.request("power_a_port").eq(0), platform.request("pass_through_vbus").eq(1), ] # Set up our parameters. m.d.comb += [ # Set our mode to non-driving and to the desired speed. umti.op_mode.eq(0b01), umti.xcvr_select.eq(self.usb_speed), # Disable all of our terminations, as we want to participate in # passive observation. umti.dm_pulldown.eq(0), umti.dm_pulldown.eq(0), umti.term_select.eq(0) ] read_strobe = Signal() # Create a USB analyzer, and connect a register up to its output. m.submodules.analyzer = analyzer = USBAnalyzer(umti_interface=umti) # Provide registers that indicate when there's data ready, and what the result is. spi_registers.add_read_only_register(DATA_AVAILABLE, read=analyzer.data_available) spi_registers.add_read_only_register(ANALYZER_RESULT, read=analyzer.data_out, read_strobe=read_strobe) m.d.comb += [ # Internal connections. analyzer.next.eq(read_strobe), # LED indicators. platform.request("led", 0).eq(analyzer.capturing), platform.request("led", 1).eq(analyzer.data_available), platform.request("led", 2).eq(analyzer.overrun), platform.request("led", 3).eq(umti.session_valid), platform.request("led", 4).eq(umti.rx_active), platform.request("led", 5).eq(umti.rx_error), ] # Return our elaborated module. return m
def elaborate(self, platform): m = Module() if platform and self.top: board_spi = platform.request("debug_spi") spi2 = synchronize(m, board_spi) m.d.comb += self.spi.connect(spi2) if self.platform: platform = self.platform spi = self.spi interf = SPICommandInterface(command_size=COMMAND_BYTES*8, word_size=WORD_BYTES*8) m.d.comb += interf.spi.connect(spi) m.submodules.interf = interf # FIFO connection fifo = TransactionalizedFIFO(width=MEMWIDTH, depth=platform.memdepth) if platform.name == 'Test': self.fifo = fifo m.submodules.fifo = fifo m.d.comb += [self.read_data.eq(fifo.read_data), fifo.read_commit.eq(self.read_commit), fifo.read_discard.eq(self.read_discard), fifo.read_en.eq(self.read_en), self.empty.eq(fifo.empty)] # Parser mtrcntr = Signal(range(platform.motors)) wordsreceived = Signal(range(wordsinmove(platform.motors)+1)) error = Signal() # Peripheral state state = Signal(8) m.d.sync += [state[STATE.PARSING].eq(self.execute), state[STATE.FULL].eq(fifo.space_available <= 1), state[STATE.ERROR].eq(self.dispatcherror | error)] # remember which word we are processing instruction = Signal(8) with m.FSM(reset='RESET', name='parser'): with m.State('RESET'): m.d.sync += [self.execute.eq(1), wordsreceived.eq(0), error.eq(0)] m.next = 'WAIT_COMMAND' with m.State('WAIT_COMMAND'): with m.If(interf.command_ready): word = Cat(state[::-1], self.pinstate[::-1]) with m.If(interf.command == COMMANDS.EMPTY): m.next = 'WAIT_COMMAND' with m.Elif(interf.command == COMMANDS.START): m.next = 'WAIT_COMMAND' m.d.sync += self.execute.eq(1) with m.Elif(interf.command == COMMANDS.STOP): m.next = 'WAIT_COMMAND' m.d.sync += self.execute.eq(0) with m.Elif(interf.command == COMMANDS.WRITE): m.d.sync += interf.word_to_send.eq(word) with m.If(state[STATE.FULL] == 0): m.next = 'WAIT_WORD' with m.Else(): m.next = 'WAIT_COMMAND' with m.Elif(interf.command == COMMANDS.READ): m.d.sync += interf.word_to_send.eq(word) m.next = 'WAIT_COMMAND' with m.Elif(interf.command == COMMANDS.POSITION): # position is requested multiple times for multiple # motors with m.If(mtrcntr < platform.motors-1): m.d.sync += mtrcntr.eq(mtrcntr+1) with m.Else(): m.d.sync += mtrcntr.eq(0) m.d.sync += interf.word_to_send.eq( self.position[mtrcntr]) m.next = 'WAIT_COMMAND' with m.State('WAIT_WORD'): with m.If(interf.word_complete): byte0 = interf.word_received[:8] with m.If(wordsreceived == 0): with m.If((byte0 > 0) & (byte0 < 6)): m.d.sync += [instruction.eq(byte0), fifo.write_en.eq(1), wordsreceived.eq(wordsreceived+1), fifo.write_data.eq( interf.word_received)] m.next = 'WRITE' with m.Else(): m.d.sync += error.eq(1) m.next = 'WAIT_COMMAND' with m.Else(): m.d.sync += [fifo.write_en.eq(1), wordsreceived.eq(wordsreceived+1), fifo.write_data.eq(interf.word_received)] m.next = 'WRITE' with m.State('WRITE'): m.d.sync += fifo.write_en.eq(0) wordslaser = wordsinscanline( params(platform)['BITSINSCANLINE']) wordsmotor = wordsinmove(platform.motors) with m.If(((instruction == INSTRUCTIONS.MOVE) & (wordsreceived >= wordsmotor)) | (instruction == INSTRUCTIONS.WRITEPIN) | (instruction == INSTRUCTIONS.LASTSCANLINE) | ((instruction == INSTRUCTIONS.SCANLINE) & (wordsreceived >= wordslaser) )): m.d.sync += [wordsreceived.eq(0), fifo.write_commit.eq(1)] m.next = 'COMMIT' with m.Else(): m.next = 'WAIT_COMMAND' with m.State('COMMIT'): m.d.sync += fifo.write_commit.eq(0) m.next = 'WAIT_COMMAND' return m
def elaborate(self, platform): m = Module() # Parser parser = SPIParser(self.platform) m.submodules.parser = parser # Busy used to detect move or scanline in action # disabled "dispatching" busy = Signal() # Polynomal Move polynomal = Polynomal(self.platform, self.divider) m.submodules.polynomal = polynomal if platform: board_spi = platform.request("debug_spi") spi = synchronize(m, board_spi) m.submodules.car = platform.clock_domain_generator() laserheadpins = platform.request("laserscanner") steppers = [res for res in get_all_resources(platform, "stepper")] assert len(steppers) != 0 else: platform = self.platform self.spi = SPIBus() self.parser = parser self.pol = polynomal spi = synchronize(m, self.spi) self.laserheadpins = platform.laserhead self.steppers = steppers = platform.steppers self.busy = busy laserheadpins = self.platform.laserhead # Local laser signal clones enable_prism = Signal() lasers = Signal(2) # Laserscan Head if self.simdiode: laserhead = DiodeSimulator(platform=platform, addfifo=False) lh = laserhead m.d.comb += [lh.enable_prism_in.eq(enable_prism | lh.enable_prism), lh.laser0in.eq(lasers[0] | lh.lasers[0]), laserhead.laser1in.eq(lasers[1] | lh.lasers[1])] else: laserhead = Laserhead(platform=platform) m.d.comb += laserhead.photodiode.eq(laserheadpins.photodiode) m.submodules.laserhead = laserhead if platform.name == 'Test': self.laserhead = laserhead # position adder busy_d = Signal() m.d.sync += busy_d.eq(polynomal.busy) coeffcnt = Signal(range(len(polynomal.coeff))) # connect laserhead m.d.comb += [ laserheadpins.pwm.eq(laserhead.pwm), laserheadpins.en.eq(laserhead.enable_prism | enable_prism), laserheadpins.laser0.eq(laserhead.lasers[0] | lasers[0]), laserheadpins.laser1.eq(laserhead.lasers[1] | lasers[1]), ] # connect Parser m.d.comb += [ self.read_data.eq(parser.read_data), laserhead.read_data.eq(parser.read_data), laserhead.empty.eq(parser.empty), self.empty.eq(parser.empty), parser.read_commit.eq(self.read_commit | laserhead.read_commit), parser.read_en.eq(self.read_en | laserhead.read_en), parser.read_discard.eq(self.read_discard | laserhead.read_discard) ] # connect motors for idx, stepper in enumerate(steppers): if idx != (list(platform.stepspermm.keys()) .index(platform.laser_axis)): step = (polynomal.step[idx] & ((stepper.limit == 0) | stepper.dir)) direction = polynomal.dir[idx] # connect the motor in which the laserhead moves to laser core else: step = ((polynomal.step[idx] | laserhead.step) & ((stepper.limit == 0) | stepper.dir)) direction = ((polynomal.dir[idx] & polynomal.busy) | (laserhead.dir & laserhead.process_lines)) m.d.comb += [stepper.step.eq(step), stepper.dir.eq(direction), parser.pinstate[idx].eq(stepper.limit)] m.d.comb += (parser.pinstate[len(steppers):]. eq(Cat(laserhead.photodiode_t, laserhead.synchronized))) # Busy signal m.d.comb += busy.eq(polynomal.busy | laserhead.process_lines) # connect spi m.d.comb += parser.spi.connect(spi) with m.If((busy_d == 1) & (busy == 0)): for idx, position in enumerate(parser.position): m.d.sync += position.eq(position+polynomal.totalsteps[idx]) # pins you can write to pins = Cat(lasers, enable_prism, laserhead.synchronize) with m.FSM(reset='RESET', name='dispatcher'): with m.State('RESET'): m.next = 'WAIT_INSTRUCTION' m.d.sync += pins.eq(0) with m.State('WAIT_INSTRUCTION'): m.d.sync += [self.read_commit.eq(0), polynomal.start.eq(0)] with m.If((self.empty == 0) & parser.execute & (busy == 0)): m.d.sync += self.read_en.eq(1) m.next = 'PARSEHEAD' # check which instruction we r handling with m.State('PARSEHEAD'): byte0 = self.read_data[:8] m.d.sync += self.read_en.eq(0) with m.If(byte0 == INSTRUCTIONS.MOVE): m.d.sync += [polynomal.ticklimit.eq(self.read_data[8:]), coeffcnt.eq(0)] m.next = 'MOVE_POLYNOMAL' with m.Elif(byte0 == INSTRUCTIONS.WRITEPIN): m.d.sync += [pins.eq(self.read_data[8:]), self.read_commit.eq(1)] m.next = 'WAIT' with m.Elif((byte0 == INSTRUCTIONS.SCANLINE) | (byte0 == INSTRUCTIONS.LASTSCANLINE)): m.d.sync += [self.read_discard.eq(1), laserhead.synchronize.eq(1), laserhead.expose_start.eq(1)] m.next = 'SCANLINE' with m.Else(): m.next = 'ERROR' m.d.sync += parser.dispatcherror.eq(1) with m.State('MOVE_POLYNOMAL'): with m.If(coeffcnt < len(polynomal.coeff)): with m.If(self.read_en == 0): m.d.sync += self.read_en.eq(1) with m.Else(): m.d.sync += [polynomal.coeff[coeffcnt].eq( self.read_data), coeffcnt.eq(coeffcnt+1), self.read_en.eq(0)] with m.Else(): m.next = 'WAIT' m.d.sync += [polynomal.start.eq(1), self.read_commit.eq(1)] with m.State('SCANLINE'): m.d.sync += [self.read_discard.eq(0), laserhead.expose_start.eq(0)] m.next = 'WAIT' # NOTE: you need to wait for busy to be raised # in time with m.State('WAIT'): m.d.sync += polynomal.start.eq(0) m.next = 'WAIT_INSTRUCTION' # NOTE: system never recovers user must reset with m.State('ERROR'): m.next = 'ERROR' return m
def elaborate(self, platform): m = Module() # Generate our clock domains. clocking = LunaECP5DomainGenerator(clock_frequencies=CLOCK_FREQUENCIES) m.submodules.clocking = clocking # Create a set of registers, and expose them over SPI. board_spi = platform.request("debug_spi") spi_registers = SPIRegisterInterface(default_read_value=-1) m.submodules.spi_registers = spi_registers # Simple applet ID register. spi_registers.add_read_only_register(REGISTER_ID, read=0x54455354) # LED test register. led_reg = spi_registers.add_register(REGISTER_LEDS, size=5, name="leds", reset=0b1) led_out = Cat( [platform.request("led", i, dir="o") for i in range(0, 6)]) m.d.comb += led_out[1:].eq(led_reg) # # User IO GPIO registers. # # Data direction register. user_io_dir = spi_registers.add_register(REGISTER_USER_IO_DIR, size=4) # Pin (input) state register. user_io_in = Signal(4) spi_registers.add_sfr(REGISTER_USER_IO_IN, read=user_io_in) # Output value register. user_io_out = spi_registers.add_register(REGISTER_USER_IO_OUT, size=4) # Grab and connect each of our user-I/O ports our GPIO registers. for i in range(4): pin = platform.request("user_io", i) m.d.comb += [ pin.oe.eq(user_io_dir[i]), user_io_in[i].eq(pin.i), pin.o.eq(user_io_out[i]) ] # # ULPI PHY windows # self.add_ulpi_registers(m, platform, ulpi_bus="host_phy", register_base=REGISTER_HOST_ADDR) self.add_ulpi_registers(m, platform, ulpi_bus="sideband_phy", register_base=REGISTER_SIDEBAND_ADDR) # # HyperRAM test connections. # ram_bus = platform.request('ram') psram = HyperRAMInterface(bus=ram_bus) m.submodules += psram psram_address_changed = Signal() psram_address = spi_registers.add_register( REGISTER_RAM_REG_ADDR, write_strobe=psram_address_changed) spi_registers.add_sfr(REGISTER_RAM_VALUE, read=psram.read_data) # Hook up our PSRAM. m.d.comb += [ ram_bus.reset.eq(0), psram.single_page.eq(0), psram.perform_write.eq(0), psram.register_space.eq(1), psram.final_word.eq(1), psram.start_transfer.eq(psram_address_changed), psram.address.eq(psram_address), ] # # SPI flash passthrough connections. # flash_sdo = Signal() spi_flash_bus = platform.request('spi_flash') spi_flash_passthrough = ECP5ConfigurationFlashInterface( bus=spi_flash_bus) m.submodules += spi_flash_passthrough m.d.comb += [ spi_flash_passthrough.sck.eq(board_spi.sck), spi_flash_passthrough.sdi.eq(board_spi.sdi), flash_sdo.eq(spi_flash_passthrough.sdo), ] # # Synchronize each of our I/O SPI signals, where necessary. # spi = synchronize(m, board_spi) # Select the passthrough or gateware SPI based on our chip-select values. gateware_sdo = Signal() with m.If(spi_registers.spi.cs): m.d.comb += board_spi.sdo.eq(gateware_sdo) with m.Else(): m.d.comb += board_spi.sdo.eq(flash_sdo) # Connect our register interface to our board SPI. m.d.comb += [ spi_registers.spi.sck.eq(spi.sck), spi_registers.spi.sdi.eq(spi.sdi), gateware_sdo.eq(spi_registers.spi.sdo), spi_registers.spi.cs.eq(spi.cs) ] # Radio SPI window radio = platform.request("radio") radio_spi = RadioSPI(clk_freq=CLOCK_FREQUENCIES["sync"] * 1e6) m.submodules += radio_spi radio_address_changed = Signal() radio_address = spi_registers.add_register( REGISTER_RADIO_ADDR, write_strobe=radio_address_changed) radio_value_changed = Signal() spi_registers.add_sfr( REGISTER_RADIO_VALUE, read=radio_spi.read_value, write_signal=radio_spi.write_value, write_strobe=radio_value_changed, ) # Hook up our radio. m.d.comb += [ radio.rst.eq(0), # SPI outputs radio.sel.eq(radio_spi.sel), radio.sclk.eq(radio_spi.sclk), radio.mosi.eq(radio_spi.mosi), # SPI inputs radio_spi.miso.eq(radio.miso), radio_spi.write.eq(radio_value_changed), radio_spi.start.eq(radio_address_changed | radio_value_changed), radio_spi.address.eq(radio_address), ] # Radio LVDS loop-back # Set up radio clock domain from rxclk, and pass it through to txclk m.domains.radio = ClockDomain() m.d.comb += [ ClockSignal("radio").eq(radio.rxclk), ResetSignal("radio").eq(ResetSignal()), radio.txclk.eq(ClockSignal("radio")), ] # TX a pattern tx = Signal(8, reset=0x2e) m.d.radio += [ tx.eq(Cat(tx[7], tx[:-1])), radio.txd.eq(tx[7]), ] # ... and receive it back. rx = Signal(8) rx_counter = Signal(range(8)) m.d.radio += rx.eq(Cat(radio.rxd09, rx[:-1])) m.d.radio += rx_counter.eq(rx_counter - 1) # Sync up to the pattern got_sync = Signal() with m.FSM() as fsm: with m.State("start"): with m.If(rx == 0x2e): m.next = "sync" m.d.radio += got_sync.eq(1) m.d.radio += rx_counter.eq(7) with m.State("sync"): with m.If(rx_counter == 0): with m.If(rx != 0x2e): m.next = "start" m.d.radio += got_sync.eq(0) with m.State("error"): pass got_sync_reg = Signal() m.submodules += FFSynchronizer(got_sync, got_sync_reg) spi_registers.add_read_only_register(REGISTER_RADIO_SYNC, read=got_sync_reg) m.d.comb += led_out[0].eq(got_sync) return m
def elaborate(self, platform): m = Module() # Generate our clock domains. clocking = LunaECP5DomainGenerator() m.submodules.clocking = clocking # Grab a reference to our debug-SPI bus. board_spi = synchronize(m, platform.request("debug_spi").i) # Create our SPI-connected registers. m.submodules.spi_registers = spi_registers = SPIRegisterInterface(7, 8) m.d.comb += spi_registers.spi.connect(board_spi) # Create our UTMI translator. ulpi = platform.request(platform.default_usb_connection) m.submodules.utmi = utmi = UTMITranslator(ulpi=ulpi) # Strap our power controls to be in VBUS passthrough by default, # on the target port. m.d.comb += [ platform.request("power_a_port").o.eq(0), platform.request("pass_through_vbus").o.eq(1), ] # Hook up our LEDs to status signals. m.d.comb += [ platform.request("led", 2).o.eq(utmi.session_valid), platform.request("led", 3).o.eq(utmi.rx_active), platform.request("led", 4).o.eq(utmi.rx_error) ] # Set up our parameters. m.d.comb += [ # Set our mode to non-driving and full speed. utmi.op_mode.eq(0b01), utmi.xcvr_select.eq(0b01), # Disable the DP/DM pull resistors. utmi.dm_pulldown.eq(0), utmi.dm_pulldown.eq(0), utmi.term_select.eq(0) ] read_strobe = Signal() # Create a USB analyzer, and connect a register up to its output. m.submodules.analyzer = analyzer = USBAnalyzer(utmi_interface=utmi) # Provide registers that indicate when there's data ready, and what the result is. spi_registers.add_read_only_register(DATA_AVAILABLE, read=analyzer.data_available) spi_registers.add_read_only_register(ANALYZER_RESULT, read=analyzer.data_out, read_strobe=read_strobe) m.d.comb += [ platform.request("led", 0).o.eq(analyzer.capturing), platform.request("led", 1).o.eq(analyzer.data_available), platform.request("led", 5).o.eq(analyzer.overrun), analyzer.next.eq(read_strobe) ] # Debug output. m.d.comb += [ platform.request("user_io", 0, dir="o").eq(ClockSignal("usb")), platform.request("user_io", 1, dir="o").eq(ulpi.dir), platform.request("user_io", 2, dir="o").eq(ulpi.nxt), platform.request("user_io", 3, dir="o").eq(analyzer.sampling), ] # Return our elaborated module. return m
def elaborate(self, platform): m = Module() # Parser parser = SPIParser(self.platform) m.submodules.parser = parser # Busy used to detect move or scanline in action # disabled "dispatching" busy = Signal() # Polynomal Move polynomal = Polynomal(self.platform) m.submodules.polynomal = polynomal if platform: board_spi = platform.request("debug_spi") spi = synchronize(m, board_spi) laserheadpins = platform.request("laserscanner") steppers = [res for res in get_all_resources(platform, "stepper")] bldc = platform.request("bldc") leds = [res.o for res in get_all_resources(platform, "led")] assert len(steppers) != 0 else: platform = self.platform self.spi = SPIBus() self.parser = parser self.pol = polynomal spi = synchronize(m, self.spi) self.laserheadpins = platform.laserhead self.steppers = steppers = platform.steppers self.busy = busy laserheadpins = platform.laserhead bldc = platform.bldc leds = platform.leds # Local laser signal clones enable_prism = Signal() lasers = Signal(2) # Laserscan Head if self.simdiode: laserhead = DiodeSimulator(platform=platform, addfifo=False) lh = laserhead m.d.comb += [ lh.enable_prism_in.eq(enable_prism | lh.enable_prism), lh.laser0in.eq(lasers[0] | lh.lasers[0]), laserhead.laser1in.eq(lasers[1] | lh.lasers[1]) ] else: laserhead = Laserhead(platform=platform) m.d.comb += laserhead.photodiode.eq(laserheadpins.photodiode) m.submodules.laserhead = laserhead if platform.name == 'Test': self.laserhead = laserhead # polynomal iterates over count coeffcnt = Signal(range(len(polynomal.coeff) + 1)) # Prism motor prism_driver = Driver(platform) m.submodules.prism_driver = prism_driver # connect prism motor for idx in range(len(leds)): m.d.comb += leds[idx].eq(prism_driver.leds[idx]) m.d.comb += prism_driver.enable_prism.eq(enable_prism) m.d.comb += [ bldc.uL.eq(prism_driver.uL), bldc.uH.eq(prism_driver.uH), bldc.vL.eq(prism_driver.vL), bldc.vH.eq(prism_driver.vH), bldc.wL.eq(prism_driver.wL), bldc.wH.eq(prism_driver.wH) ] m.d.comb += [ prism_driver.hall[0].eq(bldc.sensor0), prism_driver.hall[1].eq(bldc.sensor1), prism_driver.hall[2].eq(bldc.sensor2) ] # connect laserhead m.d.comb += [ # TODO: fix removal # laserheadpins.pwm.eq(laserhead.pwm), # laserheadpins.en.eq(laserhead.enable_prism | enable_prism), laserheadpins.laser0.eq(laserhead.lasers[0] | lasers[0]), laserheadpins.laser1.eq(laserhead.lasers[1] | lasers[1]), ] # connect Parser m.d.comb += [ self.read_data.eq(parser.read_data), laserhead.read_data.eq(parser.read_data), laserhead.empty.eq(parser.empty), self.empty.eq(parser.empty), parser.read_commit.eq(self.read_commit | laserhead.read_commit), parser.read_en.eq(self.read_en | laserhead.read_en), parser.read_discard.eq(self.read_discard | laserhead.read_discard) ] # connect motors for idx, stepper in enumerate(steppers): step = (polynomal.step[idx] & ((stepper.limit == 0) | stepper.dir)) if idx != (list(platform.stepspermm.keys()).index( platform.laser_axis)): direction = polynomal.dir[idx] m.d.comb += [ stepper.step.eq(step), stepper.dir.eq(direction), parser.pinstate[idx].eq(stepper.limit) ] # connect the motor in which the laserhead moves to laser core else: m.d.comb += [ parser.pinstate[idx].eq(stepper.limit), stepper.step.eq((step & (~laserhead.process_lines)) | (laserhead.step & (laserhead.process_lines))), stepper.dir.eq( (polynomal.dir[idx] & (~laserhead.process_lines)) | (laserhead.dir & (laserhead.process_lines))) ] m.d.comb += (parser.pinstate[len(steppers):].eq( Cat(laserhead.photodiode_t, laserhead.synchronized))) # update position stepper_d = Array(Signal() for _ in range(len(steppers))) for idx, stepper in enumerate(steppers): pos = parser.position[idx] m.d.sync += stepper_d[idx].eq(stepper.step) with m.If(stepper.limit == 1): m.d.sync += parser.position[idx].eq(0) # assuming position is signed # TODO: this might eat LUT, optimize pos_max = pow(2, pos.width - 1) - 2 with m.Elif((pos > pos_max) | (pos < -pos_max)): m.d.sync += parser.position[idx].eq(0) with m.Elif((stepper.step == 1) & (stepper_d[idx] == 0)): with m.If(stepper.dir): m.d.sync += pos.eq(pos + 1) with m.Else(): m.d.sync += pos.eq(pos - 1) # Busy signal m.d.comb += busy.eq(polynomal.busy | laserhead.process_lines) # connect spi m.d.comb += parser.spi.connect(spi) # pins you can write to pins = Cat(lasers, enable_prism, laserhead.synchronize) with m.FSM(reset='RESET', name='dispatcher'): with m.State('RESET'): m.next = 'WAIT_INSTRUCTION' m.d.sync += pins.eq(0) with m.State('WAIT_INSTRUCTION'): m.d.sync += [self.read_commit.eq(0), polynomal.start.eq(0)] with m.If((self.empty == 0) & parser.parse & (busy == 0)): m.d.sync += self.read_en.eq(1) m.next = 'PARSEHEAD' # check which instruction we r handling with m.State('PARSEHEAD'): byte0 = self.read_data[:8] m.d.sync += self.read_en.eq(0) with m.If(byte0 == INSTRUCTIONS.MOVE): m.d.sync += [ polynomal.ticklimit.eq(self.read_data[8:]), coeffcnt.eq(0) ] m.next = 'MOVE_POLYNOMAL' with m.Elif(byte0 == INSTRUCTIONS.WRITEPIN): m.d.sync += [ pins.eq(self.read_data[8:]), self.read_commit.eq(1) ] m.next = 'WAIT' with m.Elif((byte0 == INSTRUCTIONS.SCANLINE) | (byte0 == INSTRUCTIONS.LASTSCANLINE)): m.d.sync += [ self.read_discard.eq(1), laserhead.synchronize.eq(1), laserhead.expose_start.eq(1) ] m.next = 'SCANLINE' with m.Else(): m.next = 'ERROR' m.d.sync += parser.dispatcherror.eq(1) with m.State('MOVE_POLYNOMAL'): with m.If(coeffcnt < len(polynomal.coeff)): with m.If(self.read_en == 0): m.d.sync += self.read_en.eq(1) with m.Else(): m.d.sync += [ polynomal.coeff[coeffcnt].eq(self.read_data), coeffcnt.eq(coeffcnt + 1), self.read_en.eq(0) ] with m.Else(): m.next = 'WAIT' m.d.sync += [polynomal.start.eq(1), self.read_commit.eq(1)] with m.State('SCANLINE'): m.d.sync += [ self.read_discard.eq(0), laserhead.expose_start.eq(0) ] m.next = 'WAIT' # NOTE: you need to wait for busy to be raised # in time with m.State('WAIT'): m.d.sync += polynomal.start.eq(0) m.next = 'WAIT_INSTRUCTION' # NOTE: system never recovers user must reset with m.State('ERROR'): m.next = 'ERROR' return m
def elaborate(self, platform): m = Module() state = Signal(3) def get_all_resources(name): resources = [] for number in itertools.count(): try: resources.append(platform.request(name, number)) except ResourceError: break return resources if platform and self.top: board_spi = platform.request("debug_spi") spi2 = synchronize(m, board_spi) leds = [res.o for res in get_all_resources("led")] bldc = platform.request("bldc") m.d.comb += self.spi.connect(spi2) m.d.comb += [ leds[0].eq(bldc.sensor0), leds[1].eq(bldc.sensor1), leds[2].eq(bldc.sensor2) ] # tested by trying out all possibilities m.d.sync += state.eq(Cat(bldc.sensor0, bldc.sensor1, bldc.sensor2)) else: platform = self.platform bldc = platform.bldc target = 200000 max_measurement = target * 10 measurement = Signal(range(max_measurement)) timer = Signal().like(measurement) statefilter = Signal(3) stateold = Signal(3) max_delay = 1000 delay = Signal(range(max_delay)) # Statefilter with m.If((state >= 1) & (state <= 6)): m.d.sync += statefilter.eq(state) m.d.sync += stateold.eq(statefilter) # PID controller step = max_delay // 100 with m.If((measurement > target) & (delay >= step)): m.d.sync += delay.eq(delay - step) with m.Elif((measurement < target) & (delay < (max_delay - step))): m.d.sync += delay.eq(delay + step) with m.Else(): m.d.sync += delay.eq(0) # Measure Cycle with m.If(timer >= max_measurement - 1): m.d.sync += [timer.eq(0), measurement.eq(timer)] with m.Elif((statefilter == 1) & (stateold != 1)): m.d.sync += [measurement.eq(timer), timer.eq(0)] with m.Else(): m.d.sync += timer.eq(timer + 1) spi = self.spi interf = SPICommandInterface(command_size=1 * 8, word_size=4 * 8) m.d.comb += interf.spi.connect(spi) m.submodules.interf = interf m.d.sync += interf.word_to_send.eq(measurement) off = Signal() duty = Signal(range(max_delay)) # Duty timer with m.If(duty < max_delay): m.d.sync += duty.eq(0) with m.Else(): m.d.sync += duty.eq(duty + 1) # Motor On / Off with m.If(duty < delay): m.d.sync += off.eq(1) with m.Else(): m.d.sync += off.eq(0) # https://www.mathworks.com/help/mcb/ref/sixstepcommutation.html with m.If(off): m.d.comb += [ bldc.uL.eq(0), bldc.uH.eq(0), bldc.vL.eq(0), bldc.vH.eq(0), bldc.wL.eq(0), bldc.wH.eq(0) ] with m.Elif(statefilter == 1): # V --> W, 001 m.d.comb += [ bldc.uL.eq(0), bldc.uH.eq(0), bldc.vL.eq(0), bldc.vH.eq(1), bldc.wL.eq(1), bldc.wH.eq(0) ] with m.Elif(statefilter == 3): # V --> U, 011 m.d.comb += [ bldc.uL.eq(1), bldc.uH.eq(0), bldc.vL.eq(0), bldc.vH.eq(1), bldc.wL.eq(0), bldc.wH.eq(0) ] with m.Elif(statefilter == 2): # W --> U, 010 m.d.comb += [ bldc.uL.eq(1), bldc.uH.eq(0), bldc.vL.eq(0), bldc.vH.eq(0), bldc.wL.eq(0), bldc.wH.eq(1) ] with m.Elif(statefilter == 6): # W --> V, 110 m.d.comb += [ bldc.uL.eq(0), bldc.uH.eq(0), bldc.vL.eq(1), bldc.vH.eq(0), bldc.wL.eq(0), bldc.wH.eq(1) ] with m.Elif(statefilter == 4): # U --> V, 100 m.d.comb += [ bldc.uL.eq(0), bldc.uH.eq(1), bldc.vL.eq(1), bldc.vH.eq(0), bldc.wL.eq(0), bldc.wH.eq(0) ] with m.Elif(statefilter == 5): # U --> W, 101 m.d.comb += [ bldc.uL.eq(0), bldc.uH.eq(1), bldc.vL.eq(0), bldc.vH.eq(0), bldc.wL.eq(1), bldc.wH.eq(0) ] # with m.Else(): # disabled # m.d.comb += [bldc.uL.eq(0), # bldc.uH.eq(0), # bldc.vL.eq(0), # bldc.vH.eq(0), # bldc.wL.eq(0), # bldc.wH.eq(0)] return m