def __init__(self, platform, sys_clk_freq): self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_por = ClockDomain() # # # # Clocking clk12 = platform.request("clk12") rst_n = platform.request("user_btn_n") if sys_clk_freq == 12e6: self.comb += self.cd_sys.clk.eq(clk12) else: self.submodules.pll = pll = iCE40PLL(primitive="SB_PLL40_PAD") pll.register_clkin(clk12, 12e6) pll.create_clkout(self.cd_sys, sys_clk_freq) platform.add_period_constraint(self.cd_sys.clk, 1e9/sys_clk_freq) # Power On Reset por_cycles = 4096 por_counter = Signal(log2_int(por_cycles), reset=por_cycles-1) self.comb += self.cd_por.clk.eq(self.cd_sys.clk) platform.add_period_constraint(self.cd_por.clk, 1e9/sys_clk_freq) self.sync.por += If(por_counter != 0, por_counter.eq(por_counter - 1)) self.specials += AsyncResetSynchronizer(self.cd_por, ~rst_n) self.specials += AsyncResetSynchronizer(self.cd_sys, (por_counter != 0))
def __init__(self, platform, sys_clk_freq): self.rst = Signal() self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_por = ClockDomain(reset_less=True) # # # # Clk/Rst clk12 = platform.request("clk12") rst_n = platform.request("user_btn_n") # Power On Reset por_count = Signal(16, reset=2**16 - 1) por_done = Signal() self.comb += self.cd_por.clk.eq(ClockSignal()) self.comb += por_done.eq(por_count == 0) self.sync.por += If(~por_done, por_count.eq(por_count - 1)) # PLL self.submodules.pll = pll = iCE40PLL(primitive="SB_PLL40_PAD") self.comb += pll.reset.eq(~rst_n | self.rst) pll.register_clkin(clk12, 12e6) pll.create_clkout(self.cd_sys, sys_clk_freq, with_reset=False) self.specials += AsyncResetSynchronizer(self.cd_sys, ~por_done | ~pll.locked) platform.add_period_constraint(self.cd_sys.clk, 1e9 / sys_clk_freq)
def __init__(self, platform, sys_clk_freq): assert sys_clk_freq == 12e6 self.rst = Signal() self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_por = ClockDomain(reset_less=True) self.clock_domains.cd_usb_12 = ClockDomain() self.clock_domains.cd_usb_48 = ClockDomain() # # # # Clk/Rst clk48 = platform.request("clk48") platform.add_period_constraint(clk48, 1e9/48e6) # Power On Reset por_count = Signal(16, reset=2**16-1) por_done = Signal() self.comb += self.cd_por.clk.eq(ClockSignal()) self.comb += por_done.eq(por_count == 0) self.sync.por += If(~por_done, por_count.eq(por_count - 1)) # USB PLL self.submodules.pll = pll = iCE40PLL() #self.comb += pll.reset.eq(self.rst) # FIXME: Add proper iCE40PLL reset support and add back | self.rst. pll.clko_freq_range = ( 12e6, 275e9) # FIXME: improve iCE40PLL to avoid lowering clko_freq_min. pll.register_clkin(clk48, 48e6) pll.create_clkout(self.cd_usb_12, 12e6, with_reset=False) self.comb += self.cd_usb_48.clk.eq(clk48) self.specials += AsyncResetSynchronizer(self.cd_usb_12, ~por_done | ~pll.locked) self.specials += AsyncResetSynchronizer(self.cd_usb_48, ~por_done | ~pll.locked) # Sys Clk self.comb += self.cd_sys.clk.eq(self.cd_usb_12.clk) self.specials += AsyncResetSynchronizer(self.cd_sys, ~por_done | ~pll.locked)
def __init__(self, platform, test=False): clk100 = platform.request('clk100') self.clock_domains.cd_sys = ClockDomain(reset_less=True) self.sync += [self.cd_sys.clk.eq(clk100)] platform.add_period_constraint(self.cd_sys.clk, 10) #rst_n = platform.request("rst_n") self.clock_domains.cd_slow = ClockDomain(reset_less=True) platform.add_period_constraint(self.cd_slow.clk, 50) n = 4 self.counter = Signal(max=n + 1) self.sync += If(self.counter == 0, self.cd_slow.clk.eq(~self.cd_slow.clk), self.counter.eq(n)).Else( self.counter.eq(self.counter - 1)) self.clock_domains.cd_slow_pll = ClockDomain(reset_less=True) platform.add_period_constraint(self.cd_slow_pll.clk, 50) if not test: self.submodules.pll = pll = iCE40PLL() #self.comb += pll.reset.eq(~rst_n) pll.register_clkin(clk100, 100e6) pll.create_clkout(self.cd_slow_pll, 20e6) self.test = platform.request('led2') self.sync.slow += self.test.eq(~self.test) self.testfsm = platform.request('led3') self.submodules.fsm = ClockDomainsRenamer('slow_pll')( FSM(reset_state="RESET")) self.fsm.act("RESET", NextState("IDLE")) self.fsm.act("IDLE", NextValue(self.testfsm, ~self.testfsm))
def __init__(self, platform, sys_clk_freq): self.rst = Signal() self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_por = ClockDomain(reset_less=True) # # # # Clk/Rst clk100 = platform.request("clk100") rst_n = platform.request("user_btn_n") # Power On Reset por_count = Signal(16, reset=2**16 - 1) por_done = Signal() self.comb += self.cd_por.clk.eq(ClockSignal()) self.comb += por_done.eq(por_count == 0) self.sync.por += If(~por_done, por_count.eq(por_count - 1)) # PLL self.submodules.pll = pll = iCE40PLL() self.comb += pll.reset.eq( rst_n ) # FIXME: Add proper iCE40PLL reset support and add back | self.rst. pll.register_clkin(clk100, 100e6) pll.create_clkout(self.cd_sys, sys_clk_freq, with_reset=False) self.specials += AsyncResetSynchronizer(self.cd_sys, ~por_done | ~pll.locked) platform.add_period_constraint(self.cd_sys.clk, 1e9 / sys_clk_freq) # SDRAM clock self.specials += DDROutput(0, 1, platform.request("sdram_clock"), ClockSignal("sys"))
def __init__(self, platform, sys_clk_freq): self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_por = ClockDomain() # # # # Clocks clk16 = platform.request("clk16") platform.add_period_constraint(clk16, 1e9 / 16e6) if sys_clk_freq == 16e6: self.comb += self.cd_sys.clk.eq(clk16) else: self.submodules.pll = pll = iCE40PLL() pll.register_clkin(clk16, 16e6) pll.create_clkout(self.cd_sys, sys_clk_freq, with_reset=False) platform.add_period_constraint(self.cd_sys.clk, 1e9 / sys_clk_freq) # Power On Reset self.reset = Signal() por_cycles = 8 por_counter = Signal(log2_int(por_cycles), reset=por_cycles - 1) self.comb += self.cd_por.clk.eq(self.cd_sys.clk) platform.add_period_constraint(self.cd_por.clk, 1e9 / sys_clk_freq) self.sync.por += If(por_counter != 0, por_counter.eq(por_counter - 1)) self.comb += self.cd_sys.rst.eq(por_counter != 0) self.specials += AsyncResetSynchronizer(self.cd_por, self.reset)
def __init__(self, platform, sys_clk_freq): self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_por = ClockDomain() self.clock_domains.cd_vga = ClockDomain() # # # # Clocks clk12 = platform.request("clk12") self.submodules.pll = pll = iCE40PLL(primitive="SB_PLL40_PAD") pll.register_clkin(clk12, 12e6) pll.create_clkout(self.cd_vga, 40e6) clk_counter = Signal() self.sync.vga += clk_counter.eq(clk_counter - 1) self.comb += self.cd_sys.clk.eq(clk_counter[0]) platform.add_period_constraint(self.cd_sys.clk, 1e9 / sys_clk_freq) platform.add_period_constraint(self.cd_vga.clk, 1e9 / 40e6) # Power On Reset self.reset = Signal() por_cycles = 4096 por_counter = Signal(log2_int(por_cycles), reset=por_cycles - 1) self.comb += self.cd_por.clk.eq(self.cd_vga.clk) platform.add_period_constraint(self.cd_por.clk, 1e9 / sys_clk_freq) self.sync.por += If(por_counter != 0, por_counter.eq(por_counter - 1)) self.comb += self.cd_sys.rst.eq(por_counter != 0) self.specials += AsyncResetSynchronizer(self.cd_por, self.reset)
def __init__(self, vga, clk12): self.clock_domains.sys = ClockDomain() self.comb += self.sys.clk.eq(clk12) self.clock_domains.vga = ClockDomain() self.vga_clk_pll = iCE40PLL(primitive='SB_PLL40_PAD') self.submodules.vga_clk_pll = self.vga_clk_pll self.vga_clk_pll.register_clkin(self.sys.clk, 12e6) self.vga_clk_pll.create_clkout(self.vga, 25.175e6) self.vga_timing = VgaTiming() self.submodules.vga_timing = self.vga_timing self.submodules.test_pattern = TestPattern(vga) self.comb += [ vga.hsync.eq(self.vga_timing.hsync), vga.vsync.eq(self.vga_timing.vsync), ]
def __init__(self, platform, test=False): # variables self.ticksinfacet = round( self.VARIABLES['CRYSTAL_HZ'] / (self.VARIABLES['RPM'] / 60 * self.VARIABLES['FACETS'])) LASERTICKS = int(self.VARIABLES['CRYSTAL_HZ'] / self.VARIABLES['LASER_HZ']) self.JITTERTICKS = round(0.5 * LASERTICKS) if self.VARIABLES['END%'] > round(1 - (self.JITTERTICKS + 1) / self.ticksinfacet): raise Exception("Invalid settings, END% too high") self.BITSINSCANLINE = round( (self.ticksinfacet * (self.VARIABLES['END%'] - self.VARIABLES['START%'])) / LASERTICKS) if self.BITSINSCANLINE <= 0: raise Exception("Bits in scanline invalid") self.bytesinline = math.ceil( self.BITSINSCANLINE / 8) + 1 # command byte is equal to 1 if self.VARIABLES['SINGLE_LINE'] == 1: self.MEMDEPTH = self.bytesinline elif (self.MEMWIDTH * self.MEMDEPTH) // self.BITSINSCANLINE < 5: raise Exception("Memory too small for 5 lines") # clock; routing was not able to reach speed higher than 70 MHz # for entire circuit on iCE40, so clock is contraint to 50 MHz clk100 = platform.request('clk100') self.clock_domains.cd_sys = ClockDomain(reset_less=True) platform.add_period_constraint(self.cd_sys.clk, 20) if not test: self.submodules.pll = pll = iCE40PLL() #self.comb += pll.reset.eq(~rst_n) pll.register_clkin(clk100, 100e6) pll.create_clkout(self.cd_sys, self.VARIABLES['CRYSTAL_HZ']) # three submodules; SPI receiver, memory and laser state machine # full byte state self.laserfsmstate = Signal(3) # state laser module 5-8 bit self.error = Signal(5) # error 0-5 bit debug = Signal(8) # optional # Memory element # Rules: # read cannot be set equal to write address --> handled by laser ledfsm # write cannot be set equal to read address --> handled by receiver statemachne # readbit, current bit read # written to detect if already information is written to memory # written can go zero after a write... if the memory is complety read --> it is no longer "written" # dat_r_temp , data is shifted after read. It is believed that this is not possible on the memory element # As a result data is copied to another element first. # sram memory is 32 blocks... each block has its own ports # one block 8*512 = 4096 bits currently used self.specials.mem = Memory(width=self.MEMWIDTH, depth=self.MEMDEPTH) writeport = self.mem.get_port(write_capable=True, mode=READ_FIRST) self.readport = self.mem.get_port(has_re=True) self.specials += writeport, self.readport self.ios = { writeport.adr, writeport.dat_w, writeport.we, self.readport.dat_r, self.readport.adr, self.readport.re } readbit = Signal(max=self.MEMWIDTH) written = Signal() self.dat_r_new = Signal(self.MEMWIDTH) dat_r_old = Signal(self.MEMWIDTH) # Receiver State Machine # TODO: tried to paralize receiver and parser but this gives errors # I am not able achieve agreement between Linux host and FPGA on memfull # Memfull is not correctly propagated every 10K operations which results in failure. # Consists out of component from litex and own custom component # Detects whether new command is available self.spi = platform.request("spi") spislave = SPISlave(self.spi, data_width=8) self.submodules.slave = spislave # Done detector done_d = Signal() done_rise = Signal() self.sync += done_d.eq(spislave.done) self.comb += done_rise.eq(spislave.done & ~done_d) # Start detector start_d = Signal() start_rise = Signal() self.sync += start_d.eq(spislave.start) self.comb += start_rise.eq(spislave.start & ~start_d) # Memfull trigger dummyf = Signal(max=2 * self.MEMDEPTH) dummyb = Signal(min=-self.MEMDEPTH, max=self.MEMDEPTH) self.sync += dummyf.eq(writeport.adr + self.CHUNKSIZE + 1) self.sync += dummyb.eq(writeport.adr + self.CHUNKSIZE + 1 - (self.MEMDEPTH - 1)) self.submodules.parser = FSM(reset_state="RESET") spi_mosi = Signal(self.MEMWIDTH) parsertrigger = Signal() memfulld = Signal() command = Signal() chunkcnt = Signal(max=self.CHUNKSIZE + 1) self.parser.act("RESET", NextValue(command, 1), NextValue(chunkcnt, 0), NextState('WAITFORSTART')) self.parser.act( "WAITFORSTART", If(start_rise, NextState("WAITFORDONE")).Else( If((written == 1) & (self.VARIABLES['SINGLE_LINE'] == False), If((dummyf > self.readport.adr) & (self.readport.adr > writeport.adr), NextValue(self.error[self.ERRORS.MEMFULL], 1)).Elif( (dummyb > self.readport.adr) & (self.readport.adr < writeport.adr), NextValue(self.error[self.ERRORS.MEMFULL], 1)).Else( NextValue( self.error[self.ERRORS.MEMFULL], 0))).Else( NextValue( self.error[self.ERRORS.MEMFULL], 0)), NextValue(spislave.miso, Cat([self.error, self.laserfsmstate])), NextValue(memfulld, self.error[self.ERRORS.MEMFULL]))) self.parser.act( "WAITFORDONE", NextValue(spi_mosi, spislave.mosi), If( done_rise, #TODO: don't overfloat bug with not stable NextValue(spislave.miso, 4), If(command, NextState("PROCESSCOMMAND")).Else( If(chunkcnt >= self.CHUNKSIZE - 1, NextValue(chunkcnt, 0), NextValue(command, 1)).Else(NextValue(chunkcnt, chunkcnt + 1)), NextValue(command, 1), NextValue(writeport.dat_w, spislave.mosi), NextValue(writeport.we, 1), NextState("WRITE")))) # command is now used as extra parameter for state and makes it more confusing self.parser.act( "PROCESSCOMMAND", NextState("WAITFORSTART"), If(spi_mosi == self.COMMANDS.STOP, NextValue(self.laserfsmstate, self.STATES.STOP)).Elif( spi_mosi == self.COMMANDS.START, NextValue(self.laserfsmstate, self.STATES.START)).Elif( spi_mosi == self.COMMANDS.LASERTEST, NextValue(self.laserfsmstate, self.STATES.LASERTEST)).Elif( spi_mosi == self.COMMANDS.MOTORTEST, NextValue(self.laserfsmstate, self.STATES.MOTORTEST)). Elif( spi_mosi == self.COMMANDS.LINETEST, NextValue(self.laserfsmstate, self.STATES.LINETEST)).Elif( spi_mosi == self.COMMANDS.PHOTODIODETEST, NextValue( self.laserfsmstate, self.STATES.PHOTODIODETEST)).Elif( spi_mosi == self.COMMANDS.WRITE_L, If(memfulld == 0, NextValue(command, 0))).Elif( spi_mosi == self.COMMANDS.STATUS).Elif( spi_mosi != 0, NextValue(self.error[self.ERRORS.INVALID], 1))) self.parser.act( "WRITE", NextState("WAITFORSTART"), NextValue(written, 1), # Write address position If(writeport.adr + 1 == self.MEMDEPTH, NextValue(writeport.adr, 0)). # wrap around is different in single line mode Elif((writeport.adr == math.ceil( self.BITSINSCANLINE / self.MEMWIDTH)) & (self.VARIABLES['SINGLE_LINE'] == True), NextValue(writeport.adr, 0)).Else(NextValue(writeport.adr, writeport.adr + 1)), NextValue(writeport.we, 0)) # the original motor driver was designed for 6 facets and pulsed for eached facet polyperiod = int(self.VARIABLES['CRYSTAL_HZ'] / (self.VARIABLES['RPM'] / 60) / (6 * 2)) pwmcounter = Signal(max=polyperiod) self.poly_pwm = platform.request("poly_pwm") self.sync += If(pwmcounter == 0, self.poly_pwm.eq(~self.poly_pwm), pwmcounter.eq(polyperiod - 1)).Else( pwmcounter.eq(pwmcounter - 1)) # Laser FSM # Laser FSM controls the laser, polygon anld output to motor self.facetcnt = Signal(max=self.VARIABLES['FACETS']) # stable counter used for both spinup and photo diode stable spinupticks = round(self.VARIABLES['SPINUP_TIME'] * self.VARIABLES['CRYSTAL_HZ']) stableticks = round(self.VARIABLES['STABLE_TIME'] * self.VARIABLES['CRYSTAL_HZ']) stablecounter = Signal(max=max( spinupticks, stableticks)) # counter is used twice, hence the max stablethresh = Signal(max=stableticks) self.lasercnt = Signal(max=LASERTICKS) self.scanbit = Signal(max=self.BITSINSCANLINE + 1) self.tickcounter = Signal(max=int(self.ticksinfacet * 2)) self.submodules.laserfsm = FSM(reset_state="RESET") # leesfoutdetectie: # in het begin zijn lees en schrijfadres gelijk # als er geschreven is dan is het schrijf adres een groter dan lees adres # als er geschreven is en het volgende adres waarvan je gaat lezen nog niet beschreven is --> lees fout # op het moment kost lezen een tick, dit zou voorkomen kunnen worden # tick counter; number of ticks in a facet for the oscillator # laser counter; laser operates at reduced speed this controlled by this counter # readbit counter; current bit position in memory # scanbit counter; current bit position along scanline readtrig = Signal() self.submodules.readmem = FSM(reset_state="RESET") self.readmem.act("RESET", NextValue(self.readport.adr, 0), NextValue(self.readport.re, 1), NextValue(written, 0), NextState("WAIT")) self.readmem.act( "WAIT", If(readtrig, NextValue(self.readport.re, 0), NextState("READ"))) self.readmem.act( "READ", NextValue(readtrig, 0), NextValue(self.readport.re, 1), If( (self.readport.adr == writeport.adr) & (written == 0), NextValue(self.error[self.ERRORS.MEMREAD], 1), ).Else( #TODO: you could split into two signals --> one if ever memread occured, other memread signal NextValue(self.error[self.ERRORS.MEMREAD], 0), NextValue(self.dat_r_new, self.readport.dat_r)), # always increase address, if you move over the write set written to zero If( self.readport.adr + 1 == self.MEMDEPTH, NextValue(self.readport.adr, 0), If((writeport.adr == 0) & (self.VARIABLES['SINGLE_LINE'] == False), NextValue(written, 0))).Else( NextValue(self.readport.adr, self.readport.adr + 1), If((self.readport.adr + 1 == writeport.adr) & (self.VARIABLES['SINGLE_LINE'] == False), NextValue(written, 0))), NextState("WAIT")) self.laserfsm.act("RESET", NextValue(self.readport.adr, 0), NextValue(writeport.adr, 0), NextState("STOP")) self.laser0 = platform.request("laser0") self.poly_en = platform.request("poly_en") self.photodiode = platform.request("photodiode") self.laserfsm.act( "STOP", NextValue(stablethresh, stableticks - 1), NextValue(stablecounter, 0), NextValue(self.facetcnt, 0), NextValue(self.tickcounter, 0), NextValue(self.scanbit, 0), NextValue(self.lasercnt, 0), NextValue(self.laser0, 0), NextValue(self.poly_en, 1), NextValue(readbit, 0), If( self.laserfsmstate == self.STATES.START, If(self.photodiode == 0, NextValue(self.laserfsmstate, self.STATES.STOP), NextState("STOP")).Else( NextValue(readtrig, 1), NextValue(self.error[self.ERRORS.NOTSTABLE], 0), NextValue(self.error[self.ERRORS.MEMREAD], 0), NextValue(self.poly_en, 0), NextState("SPINUP"))).Elif( self.laserfsmstate == self.STATES.MOTORTEST, NextValue(self.poly_en, 0), NextState("MOTORTEST")).Elif( self.laserfsmstate == self.STATES.LASERTEST, NextValue(self.laser0, 1), NextState("LASERTEST")).Elif( self.laserfsmstate == self.STATES.LINETEST, NextValue(self.laser0, 1), NextValue(self.poly_en, 0), NextState("LINETEST")). Elif( self.laserfsmstate == self.STATES.PHOTODIODETEST, # photodiode should be high with laser off # something is wrong, this makes sure error is produced If(self.photodiode == 0, NextValue(self.laser0, 1), NextValue(self.poly_en, 1)).Else( NextValue(self.laser0, 1), NextValue(self.poly_en, 0), ), NextState("PHOTODIODETEST"))) self.laserfsm.act( "MOTORTEST", If(self.laserfsmstate != self.STATES.MOTORTEST, NextState("STOP"))) self.laserfsm.act( "LASERTEST", If(self.laserfsmstate != self.STATES.LASERTEST, NextState("STOP"))) self.laserfsm.act( "LINETEST", If(self.laserfsmstate != self.STATES.LINETEST, NextState("STOP"))) # Photodiode rising edge detector photodiode_d = Signal() self.laserfsm.act( "PHOTODIODETEST", If((self.photodiode == 0) & (self.poly_en == 0), NextValue(self.laserfsmstate, self.STATES.STOP), NextState("STOP")).Elif( self.laserfsmstate != self.STATES.PHOTODIODETEST, NextState("STOP"))) self.laserfsm.act( "SPINUP", NextValue(stablecounter, stablecounter + 1), If( stablecounter > spinupticks - 1, NextState("STATE_WAIT_STABLE"), NextValue(self.laser0, 1), NextValue(stablecounter, 0), )) self.laserfsm.act( "STATE_WAIT_STABLE", NextValue(stablecounter, stablecounter + 1), NextValue(photodiode_d, self.photodiode), If(stablecounter >= stablethresh, NextValue(self.error[self.ERRORS.NOTSTABLE], 1), NextValue(self.laserfsmstate, self.STATES.STOP), NextState('RESET')). Elif( ~self.photodiode & ~photodiode_d, NextValue(self.tickcounter, 0), NextValue(self.laser0, 0), If( (self.tickcounter > self.ticksinfacet - self.JITTERTICKS) & (self.tickcounter < self.ticksinfacet + self.JITTERTICKS), If(self.facetcnt == self.VARIABLES['FACETS'] - 1, NextValue(self.facetcnt, 0)).Else( NextValue(self.facetcnt, self.facetcnt + 1)), NextValue(stablecounter, 0), If((self.VARIABLES['SINGLE_FACET'] == True) & (self.facetcnt > 0), NextState('WAIT_END')).Else( NextValue( stablethresh, min(round(10.1 * self.ticksinfacet), stableticks)), #TODO: lower! NextState('READ_INSTRUCTION'))).Else( NextState('WAIT_END'))).Elif( self.laserfsmstate != self.STATES.START, NextState("RESET")).Else( NextValue(self.tickcounter, self.tickcounter + 1))) self.laserfsm.act( 'READ_INSTRUCTION', NextValue(self.tickcounter, self.tickcounter + 1), If( readtrig == 0, If( self.error[self.ERRORS.MEMREAD] == 1, # move back the address and read again If(self.readport.adr == 0, NextValue(self.readport.adr, self.MEMDEPTH - 1)).Else( NextValue(self.readport.adr, self.readport.adr - 1)), NextValue(readtrig, 1), NextState("WAIT_END")).Elif( self.dat_r_new == self.INSTRUCTIONS.STOP, NextState("RESET"), NextValue(self.laserfsmstate, self.STATES.STOP)).Elif( self.dat_r_new == self.INSTRUCTIONS.SCAN, NextState('WAIT_FOR_DATA_RUN'), NextValue(readtrig, 1), ).Else( NextState("RESET"), NextValue(self.laserfsmstate, self.STATES.STOP), NextValue(self.error[self.ERRORS.INVALIDLINE], 1), ))) self.laserfsm.act( 'WAIT_FOR_DATA_RUN', NextValue(self.tickcounter, self.tickcounter + 1), If( readtrig == 0, If(self.error[self.ERRORS.MEMREAD] == 1, NextValue(dat_r_old, 0)).Else(NextValue(dat_r_old, self.dat_r_new)), NextValue(readbit, 0), NextValue(self.scanbit, 0), NextValue(self.lasercnt, 0), If( self.tickcounter == int(self.VARIABLES['START%'] * self.ticksinfacet - 2), NextState('DATA_RUN')). Elif( self.tickcounter > int(self.VARIABLES['START%'] * self.ticksinfacet - 2), #NextValue(self.error[self.ERRORS.INVALID], 1), #TODO: replace with timeout NextState('DATA_RUN')))) self.laserfsm.act( "DATA_RUN", NextValue(self.tickcounter, self.tickcounter + 1), If( self.lasercnt == 0, #NOTE: readbit and scanbit counters can be different # readbit is your current position in memory and scanbit your current byte position in scanline If( self.scanbit >= self.BITSINSCANLINE, NextState("WAIT_END") ).Else( NextValue(self.lasercnt, LASERTICKS - 1), NextValue(self.scanbit, self.scanbit + 1), # read from memory before the spinup # it is triggered here again, so fresh data is available once the end is reached # if read bit is 0, trigger a read out unless the next byte is outside of line If(readbit == 0, NextValue(readtrig, 1), NextValue(readbit, readbit + 1), NextValue(dat_r_old, dat_r_old >> 1)). # final read bit copy memory # move to next address, i.e. byte, if end is reached Elif( readbit == self.MEMWIDTH - 1, If(self.error[self.ERRORS.MEMREAD] == 1, NextValue(dat_r_old, 0)).Else( NextValue(dat_r_old, self.dat_r_new)), NextValue(readbit, 0)).Else( NextValue(readbit, readbit + 1), NextValue(dat_r_old, dat_r_old >> 1)), NextValue(self.laser0, dat_r_old[0]))).Else( NextValue(self.lasercnt, self.lasercnt - 1))) self.laserfsm.act( "WAIT_END", NextValue(stablecounter, stablecounter + 1), NextValue(self.tickcounter, self.tickcounter + 1), If( self.tickcounter >= round(self.ticksinfacet - self.JITTERTICKS - 1), NextState("STATE_WAIT_STABLE"), NextValue(self.laser0, 1), ))