Wishbone accessible version ready ...

master
kaqu 2 years ago
parent 18bfecde54
commit f6fa3950f3
  1. 2
      .gitignore
  2. 52
      neopixelar.py
  3. 88
      neopixelengine.py
  4. 83905
      npe.vcd
  5. 98
      remotetest.py

2
.gitignore vendored

@ -1,3 +1,3 @@
build/*
__pycache__/*
backup/*

@ -46,6 +46,8 @@ from litex.soc.cores.gpio import GPIOOut
from litex.soc.integration.soc_core import *
from litex.soc.integration.builder import *
from litex.soc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage, CSRField
from litedram.modules import M12L16161A, M12L64322A
from litedram.phy import GENSDRPHY, HalfRateGENSDRPHY
@ -331,53 +333,9 @@ class BaseSoC(SoCCore):
platform.add_extension(_gpios) # General LED outputs
self.submodules.npe = NeoPixelEngine()
self.add_csr("npe")
# Working def.
#sw_gpio = Signal(24)
#self.submodules.npe_data = GPIOOut(sw_gpio)
#self.comb += self.npe.b24GRBArray[0].eq(sw_gpio) # 1st LED G(reen) Bit4
#self.add_csr("npe_data")
# Inputs 1st
#self.comb += self.npe.b24GRBArray[0].eq(0x330000) # 1st: G
#self.comb += self.npe.b24Data.fields.fields[1].eq(0x004400) # 2nd: R
#self.comb += self.npe.b24Data.fields.fields[2].eq(0x000055) # 3rd: B
#self.comb += self.npe.b24Data.fields.fields[3].eq(0x330000) # 1st: G
#self.comb += self.npe.b24Data.fields.fields[4].eq(0x004400) # 2nd: R
#self.comb += self.npe.b24Data.fields.fields[5].eq(0x000055) # 3rd: B
#self.comb += self.npe.b24Data.fields.fields[6].eq(0x330000) # 1st: G
#self.comb += self.npe.b24Data.fields.fields[7].eq(0x004400) # 2nd: R
#self.comb += self.npe.b24Data.fields.fields[8].eq(0x000055) # 3rd: B
#self.comb += self.npe.b24Data.fields.fields[9].eq(0x330000) # 1st: G
#self.comb += self.npe.b24Data.fields.fields[10].eq(0x004400) # 2nd: R
#self.comb += self.npe.b24Data.fields.fields[11].eq(0x000055) # 3rd: B
#self.comb += self.npe.b24Data.fields.fields[12].eq(0x330000) # 1st: G
#self.comb += self.npe.b24Data.fields.fields[13].eq(0x004400) # 2nd: R
#self.comb += self.npe.b24Data.fields.fields[14].eq(0x000055) # 3rd: B
#self.comb += self.npe.b24Data.fields.fields[15].eq(0x330000) # 1st: G
#self.comb += self.npe.b24Data.fields.fields[16].eq(0x004400) # 2nd: R
#self.comb += self.npe.b24Data.fields.fields[17].eq(0x000055) # 3rd: B
#self.comb += self.npe.b24Data.fields.fields[18].eq(0x330000) # 1st: G
#self.comb += self.npe.b24Data.fields.fields[19].eq(0x004400) # 2nd: R
#self.comb += self.npe.b24Data.fields.fields[20].eq(0x000055) # 3rd: B
#self.comb += self.npe.b24Data.fields.fields[21].eq(0x330000) # 1st: G
#self.comb += self.npe.b24Data.fields.fields[22].eq(0x004400) # 2nd: R
#self.comb += self.npe.b24Data.fields.fields[23].eq(0x000055) # 3rd: B
#self.comb += self.npe.b24Data.fields.fields[24].eq(0x330000) # 1st: G
#self.comb += self.npe.b24Data.fields.fields[25].eq(0x004400) # 2nd: R
#self.comb += self.npe.b24Data.fields.fields[26].eq(0x000055) # 3rd: B
self.comb += self.npe.b8Len.eq(27) # 27 24-bit 'words'
self.comb += self.npe.bEnable.eq(True) # Free running
# Outputs 2nd
# Do output on J4
for i in range(42,56):
self.comb += platform.request("gpio", i).eq(self.npe.bDataPin) # Output data pin
#self.comb += platform.request("gpio", 42).eq(counter[1]) # For measurement of freq#!
#self.comb += platform.request("gpio", 43).eq(counter[23]) # Test LEDs
#self.comb += platform.request("gpio", 46).eq(counter[22])
self.add_csr("npe")
for i in range(42,56): # Do output on J4
self.comb += platform.request("gpio", i).eq(self.npe.bDataPin) # Output data pin
# Build --------------------------------------------------------------------------------------------

@ -23,53 +23,47 @@ class NeoPixelEngine(Module, AutoCSR):
"""NeoPixelEngine class provides the protocol logic to drive NeoPixel LED strips
Inputs:
b24GRBArray[256] 24-bit data entries (one per NeoPixel)
b8Len length of actual 24-bit data entries (i.e. # of NeoPixels)
bEnable to enable running (after data preparation)
b24Data2Load New data to be loaded (24 bits)
b8LoadOffset (0..255) Offset into b24GRBArray to load b24Data2Load to
b8Len (0..255) Length of actual 24-bit data entries (i.e. # of NeoPixels)
bEnable To enable running (after data preparation)
Output:
bDataPin NeoPixel 'Din' pin output
bDataPin NeoPixel 'Din' pin output
"""
def __init__(self):
#self.b24GRBArray = Array(Signal(24) for word24 in range(255)) # External input: 24-bit data Array
n_words = 27
self.b24Data = CSRStorage(n_words*24, reset_less=True, fields=
#Array(CSRField("_{:03d}".format(word24), size=24, description="G/R/B entry #{}".format(word24)) for word24 in range(n_words)),
Array(CSRField("_{:03d}".format(word24), size=24, description="G/R/B entry #{}".format(word24)) for word24 in range(n_words-1,-1,-1)),
#[
# CSRField("_0", size=24, description="24-bit entry #0"),
# CSRField("_1", size=24, description="24-bit entry #1"),
# CSRField("_2", size=24, description="24-bit entry #2"),
# CSRField("_3", size=24, description="24-bit entry #3"),
#],
description="24-bit data entry table"
)
self.b8Len = Signal(8) # External input: No. of 24-bit data to transfer (unsigned)
self.bEnable = Signal() # External input: Enable free run signal (start & abort)
def __init__(self):
self.b24GRBArray = Array(Signal(24) for word24 in range(27)) # Local 24-bit data Array
# Inputs
self.b24Data2Load = CSRStorage(24, reset_less=True, description="Load value (GRB)")
self.b8LoadOffset = CSRStorage(8, reset_less=True, description="Offset to store (GRB) value")
self.b8Len = CSRStorage(8, reset_less=True, description="No. of active (GRB) entries")
self.bEnable = CSRStorage(8, reset_less=True, description="Enable free run signal (start & abort)")
self.b8Offset = Signal(8) # Local: Array rover
self.b24GRB = Signal(24) # Local: Current 24-bit data to send
self.b12PulseLen = Signal(12) # Local: Current pulse length
self.b5Count24 = Signal(5) # Local: 24-Bit counter
# Local data
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.bDataPin = Signal() # Output: To be wired to data pin ...
# Output
self.bDataPin = Signal() # To be wired to data pin ...
###
fsm = FSM(reset_state="IDLE") # FSM starts idling ...
self.submodules += fsm
self.sync += self.b24GRBArray[self.b8LoadOffset.storage].eq(self.b24Data2Load.storage) # Loader is allways active!
fsm.act("IDLE",
If((self.bEnable==True) and (self.b8Len > 0),
If((self.bEnable.storage==True) and (self.b8Len.storage > 0),
NextValue(self.b8Offset, 0), # Start @ 1st 24-bit data
#NextValue(self.b24GRB, self.b24GRBArray[0]), # ... but load 1st right away!
NextValue(self.b24GRB, self.b24Data.fields.fields[0]), # ... but load 1st right away!
NextValue(self.b24GRB, self.b24GRBArray[0]), # ... but load 1st right away!
NextValue(self.b5Count24,0), # Bit count 0..23
NextState("PREPAREBIT")
)
)
# Protocol: T0H=400ns/T0L=850ns, T1H=800ns/T1L=450ns, RST>50µs(>50000ns)
# Simulator: T0H=6/T0L=13, T1H=12/T1L=7, RST=1400
# Actual: T0H=23/T0L=48, T1H=47/T1L=24, RST=3100
fsm.act("PREPAREBIT",
If(self.b24GRB[23],
NextValue(self.b12PulseLen,47), # Compensate for 1 state changes w/o action ...),
@ -125,12 +119,8 @@ class NeoPixelEngine(Module, AutoCSR):
)
)
fsm.act("NEXTWORD",
#If(self.bEnable==False, # Exit requested?
# NextState("RST") # Yap!
#).El
If((self.b8Offset < self.b8Len) & (self.bEnable==True), # Still more words to come (& no exit request)?
#NextValue(self.b24GRB, self.b24GRBArray[self.b8Offset]), # Load in advance
NextValue(self.b24GRB, self.b24Data.fields.fields[self.b8Offset]),
If((self.b8Offset < self.b8Len.storage) & (self.bEnable.storage==True), # Still more words to come (& no exit request)?
NextValue(self.b24GRB, self.b24GRBArray[self.b8Offset]), # Load in advance
NextState("PREPAREBIT")
).Else(
NextValue(self.b12PulseLen, 4095), # >50µs required (3000 not ok!)
@ -143,22 +133,24 @@ class NeoPixelEngine(Module, AutoCSR):
If(self.b12PulseLen == 0,
NextState("IDLE")
)
)
)
def npe_testbench(npe):
print("----- npe testbench -----")
#yield npe.b24GRBArray[0].eq(0x123456)
yield npe.b24Data.fields.fields[0].eq(0x123456)
print("----- npe testbench -----")
yield npe.b8LoadOffset.storage.eq(3)
yield
yield npe.b24Data2Load.storage.eq(0x100000)
yield
yield npe.b24GRBArray[0].eq(0x123456)
yield
#yield npe.b24GRBArray[1].eq(0x223344)
yield npe.b24Data.fields.fields[1].eq(0x223344)
yield npe.b24GRBArray[1].eq(0x223344)
yield
#yield npe.b24GRBArray[2].eq(0x654321)
yield npe.b24Data.fields.fields[2].eq(0x654321)
yield npe.b24GRBArray[2].eq(0x654321)
yield
yield npe.b8Len.eq(3)
yield npe.b8Len.storage.eq(3)
yield
yield npe.bEnable.eq(True)
yield npe.bEnable.storage.eq(True)
yield
#
for i in range(10000): # Send the whole data & restart ...
@ -166,7 +158,7 @@ def npe_testbench(npe):
print((yield npe.bDataPin)) # Actual pin to move
yield
if i == 5000:
yield npe.bEnable.eq(True) # Enable quickest restart ...
yield npe.bEnable.storage.eq(True) # Enable quickest restart ...
yield
if __name__ == "__main__":

83905
npe.vcd

File diff suppressed because it is too large Load Diff

@ -20,82 +20,38 @@ def test(csr_csv):
print("NeoPixel #0 on & off test: ")
for i in range(10):
print(".",end="")
#Added manually: ~/fpga/litex/litex/litex/tools/remote/csr_builder.py
#You may add manually: ~/fpga/litex/litex/litex/tools/remote/csr_builder.py
# def writearray(self, value): #21.09.20/KQ
# if self.mode not in ["rw", "wo"]:
# raise KeyError(self.name + "register not writable")
# self.writefn(self.addr, value)
#wb.regs.npe_data_out.write(0x100000)
wb.regs.npe_b24Data.writearray(
[
#00,00,15,
#0,19,0,
#20,0,0, #25
#00,00,15,
#0,19,0,
#20,0,0, #22
#00,00,15,
#0,19,0,
#20,0,0, #19
#00,00,15,
#0,19,0,
#20,0,0, #16
#00,00,15,
#0,19,0,
#20,0,0, #13
#00,00,15,
#0,19,0,
#20,0,0, #10
#00,00,15,
#0,19,0,
#20,0,0, #7
#00,00,15,
#0,19,0,
20,0,0, #4
00,00,15,
0,19,0,
20,0,0 #1
]
) # Width 27
#wb.regs.npe_b24Datawrite(0x001000)
#wb.regs.npe_b24Data.write(0x000010)
time.sleep(0.5)
#wb.regs.npe_data_out.write(0)
wb.regs.npe_b24Data.writearray(
[
#0,0,0,
#0,0,0,
#0,0,0, #25
#0,0,0,
#0,0,0,
#0,0,0, #22
#0,0,0,
#0,0,0,
#0,0,0, #19
#0,0,0,
#0,0,0,
#0,0,0, #16
#0,0,0,
#0,0,0,
#0,0,0, #13
#0,0,0,
#0,0,0,
#0,0,0, #10
#0,0,0,
#0,0,0,
#0,0,0, #7
#0,0,0,
#0,0,0,
0,0,0, #4
0,0,0,
0,0,0,
0,0,0 #1
]
)
#wb.regs.npe_b24Data_1.write(0)
#wb.regs.npe_b24Data_2.write(0)
time.sleep(0.5)
# From build/csr.csv we know:
#csr_register,npe_b24Data2Load,0x82004000,3,rw
#csr_register,npe_b8LoadOffset,0x8200400c,1,rw
#csr_register,npe_b8Len,0x82004010,1,rw
#csr_register,npe_bEnable,0x82004014,1,rw
for j in range(0,27,3):
wb.regs.npe_b8LoadOffset.write(j) # @Offset 0
wb.regs.npe_b24Data2Load.write(0x100000) # G
wb.regs.npe_b8LoadOffset.write(j+1) # @Offset 0
wb.regs.npe_b24Data2Load.write(0x001100) # R
wb.regs.npe_b8LoadOffset.write(j+2) # @Offset 0
wb.regs.npe_b24Data2Load.write(0x000012) # B
if i==0: # Only on init. ...
wb.regs.npe_b8Len.write(27) # Length
wb.regs.npe_bEnable.write(1) # Enable!
time.sleep(0.2)
for j in range(0,27,3):
wb.regs.npe_b8LoadOffset.write(j) # @Offset 0
wb.regs.npe_b24Data2Load.write(0x000000) # G
wb.regs.npe_b8LoadOffset.write(j+1) # @Offset 0
wb.regs.npe_b24Data2Load.write(0x000000) # R
wb.regs.npe_b8LoadOffset.write(j+2) # @Offset 0
wb.regs.npe_b24Data2Load.write(0x000000) # B
time.sleep(0.2)
wb.close() # Close wishbone access
print(" Done.")

Loading…
Cancel
Save