|
|
|
@ -105,23 +105,21 @@ class NeoPixelEngine(Module, AutoCSR, AutoDoc, ModuleDoc): |
|
|
|
|
self.b8Offset = Signal(8) # Array rover |
|
|
|
|
self.b24GRB = Signal(24) # Current 24-bit data to send |
|
|
|
|
self.b12PulseLen = Signal(12) # Current pulse length |
|
|
|
|
self.b5Count24 = Signal(5) # 24-Bit counter |
|
|
|
|
self.b24GRBmem = Signal(24) # Readout local store |
|
|
|
|
self.b5Count24 = Signal(5) # 24-Bit counter |
|
|
|
|
|
|
|
|
|
storage = Memory(24, n_TABLES * n_LEDs) |
|
|
|
|
self.specials += storage |
|
|
|
|
wrport = storage.get_port(write_capable=True) #, clock_domain="write") |
|
|
|
|
self.specials += wrport |
|
|
|
|
self.comb += [ # Write to memory |
|
|
|
|
wrport.adr.eq(self.b8LoadOffset.storage), |
|
|
|
|
wrport.adr.eq((self.b4LoadTable.storage * n_LEDs) + self.b8LoadOffset.storage), |
|
|
|
|
wrport.dat_w.eq(self.b24Data2Load.storage), |
|
|
|
|
wrport.we.eq(1) |
|
|
|
|
] |
|
|
|
|
rdport = storage.get_port() |
|
|
|
|
self.specials += rdport |
|
|
|
|
self.comb += [ # Read from memory |
|
|
|
|
rdport.adr.eq(self.b8Offset), |
|
|
|
|
self.b24GRBmem.eq(rdport.dat_r) |
|
|
|
|
rdport.adr.eq((self.b4Table * n_LEDs) + self.b8Offset) |
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
# Output |
|
|
|
@ -134,14 +132,14 @@ class NeoPixelEngine(Module, AutoCSR, AutoDoc, ModuleDoc): |
|
|
|
|
fsm.act("IDLETABLE", |
|
|
|
|
If((self.bEnable.storage==True) and (self.b8Len.storage > 0), |
|
|
|
|
NextValue(self.b4Table, 0), # Start @ 1st table |
|
|
|
|
NextValue(self.b8Offset, 0), # Start @ 1st 24-bit data (mem will be ready next cycle) |
|
|
|
|
NextState("IDLE") |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
fsm.act("IDLE", |
|
|
|
|
If((self.bEnable.storage==True) and (self.b8Len.storage > 0), |
|
|
|
|
NextValue(self.b8Offset, 0), # Start @ 1st 24-bit data |
|
|
|
|
NextValue(self.b24GRB, self.b24GRBmem), # Depends upon b8Offset (cycle?) |
|
|
|
|
If((self.bEnable.storage==True) and (self.b8Len.storage > 0), |
|
|
|
|
NextValue(self.b24GRB, rdport.dat_r), # Depends upon b4Table/b8Offset |
|
|
|
|
NextValue(self.b5Count24, 0), # Bit count 0..23 |
|
|
|
|
NextState("PREPAREBIT") |
|
|
|
|
) |
|
|
|
@ -160,8 +158,12 @@ class NeoPixelEngine(Module, AutoCSR, AutoDoc, ModuleDoc): |
|
|
|
|
fsm.act("T1H", |
|
|
|
|
NextValue(self.bDataPin[self.b4Table], 1), |
|
|
|
|
NextValue(self.b12PulseLen, self.b12PulseLen - 1), |
|
|
|
|
If(self.b12PulseLen == 0, |
|
|
|
|
NextValue(self.b12PulseLen, 24), # Compensate for 3 state changes w/o action ... |
|
|
|
|
If(self.b12PulseLen == 0, |
|
|
|
|
If(self.b5Count24 < 23, # Not final pulse of word |
|
|
|
|
NextValue(self.b12PulseLen, 24) # Compensate for 3 state changes w/o action ... |
|
|
|
|
).Else( # Final word pulse special |
|
|
|
|
NextValue(self.b12PulseLen, 21) # Compensate word load cycles |
|
|
|
|
), |
|
|
|
|
NextState("T1L") |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
@ -179,7 +181,11 @@ class NeoPixelEngine(Module, AutoCSR, AutoDoc, ModuleDoc): |
|
|
|
|
NextValue(self.bDataPin[self.b4Table], 1), |
|
|
|
|
NextValue(self.b12PulseLen, self.b12PulseLen - 1), |
|
|
|
|
If(self.b12PulseLen == 0, |
|
|
|
|
NextValue(self.b12PulseLen, 48), # Compensate for 3 state changes w/o action ... |
|
|
|
|
If(self.b5Count24 < 23, # Not final pulse of word? |
|
|
|
|
NextValue(self.b12PulseLen, 48) # Compensate for 3 state changes w/o action ... |
|
|
|
|
).Else( # Final word load special |
|
|
|
|
NextValue(self.b12PulseLen, 45) # Compensate for load word cycles |
|
|
|
|
), |
|
|
|
|
NextState("T0L") |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
@ -199,12 +205,18 @@ class NeoPixelEngine(Module, AutoCSR, AutoDoc, ModuleDoc): |
|
|
|
|
).Else( # GRB word finished. More to come? |
|
|
|
|
NextValue(self.b5Count24,0), # Bit count reset for next word |
|
|
|
|
NextValue(self.b8Offset, self.b8Offset + 1), # Prepare offset for later use |
|
|
|
|
NextState("NEXTWORD") |
|
|
|
|
NextState("NEXTWORD1") |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
fsm.act("NEXTWORD", |
|
|
|
|
fsm.act("NEXTWORD1", |
|
|
|
|
NextState("NEXTWORD2") # Add one cycle for read port propagation! |
|
|
|
|
) |
|
|
|
|
fsm.act("NEXTWORD2", |
|
|
|
|
NextState("NEXTWORD3") # Add one cycle for read port propagation! |
|
|
|
|
) |
|
|
|
|
fsm.act("NEXTWORD3", |
|
|
|
|
If((self.b8Offset < self.b8Len.storage) & (self.bEnable.storage==True), # Still more words to come (& no exit request)? |
|
|
|
|
NextValue(self.b24GRB, self.b24GRBmem), # Depends upon b8Offset! |
|
|
|
|
NextValue(self.b24GRB, rdport.dat_r), # Depends upon b4Table/b8Offset! |
|
|
|
|
NextState("PREPAREBIT") |
|
|
|
|
).Else( |
|
|
|
|
NextValue(self.b12PulseLen, 4095), # >50µs required (3000 not ok!) |
|
|
|
@ -221,7 +233,8 @@ class NeoPixelEngine(Module, AutoCSR, AutoDoc, ModuleDoc): |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
fsm.act("NEXTTABLE", |
|
|
|
|
If(self.b4Table < 16, |
|
|
|
|
If(self.b4Table < 16, |
|
|
|
|
NextValue(self.b8Offset, 0), # Start @ 1st 24-bit data |
|
|
|
|
NextState("IDLE") |
|
|
|
|
).Else( |
|
|
|
|
NextState("IDLETABLE") |
|
|
|
|