litex-hub / litespi Goto Github PK
View Code? Open in Web Editor NEWSmall footprint and configurable SPI core
License: BSD 2-Clause "Simplified" License
Small footprint and configurable SPI core
License: BSD 2-Clause "Simplified" License
I'm updating some older icebreaker litex examples to use more upstream LiteX features. One of which is LiteSPI
The SoC works, as expected, but it appears I'm no longer able to generate documentation...
I've been able to replicate this in the litex_boards.1bitsquared_icebreaker
target.
diff --git a/litex_boards/targets/1bitsquared_icebreaker.py b/litex_boards/targets/1bitsquared_icebreaker.py
index 0ab0434..a2c0daf 100755
--- a/litex_boards/targets/1bitsquared_icebreaker.py
+++ b/litex_boards/targets/1bitsquared_icebreaker.py
@@ -160,6 +160,9 @@ def main():
builder = Builder(soc, **builder_argdict(args))
builder.build(run=args.build)
+ from litex.soc.doc import generate_docs
+ generate_docs(soc, "build/docs/")
+
if args.load:
prog = soc.platform.create_programmer()
prog.load_bitstream(os.path.join(builder.gateware_dir, soc.build_name + ".bin"))
Then running creates the following error.
$ ./1bitsquared_icebreaker.py
--- snip ---
Traceback (most recent call last):
File "/home/greg/Projects/icebreaker-litex-examples/soc/deps/litex-boards/litex_boards/targets/1bitsquared_icebreaker.py", line 174, in <module>
main()
File "/home/greg/Projects/icebreaker-litex-examples/soc/deps/litex-boards/litex_boards/targets/1bitsquared_icebreaker.py", line 164, in main
generate_docs(soc, "build/docs/")
File "/home/greg/Projects/icebreaker-litex-examples/soc/deps/litex/litex/soc/doc/__init__.py", line 99, in generate_docs
documented_region = DocumentedCSRRegion(
File "/home/greg/Projects/icebreaker-litex-examples/soc/deps/litex/litex/soc/doc/csr.py", line 80, in __init__
docs = module.get_module_documentation()
File "/home/greg/Projects/icebreaker-litex-examples/soc/deps/litex/litex/soc/integration/doc.py", line 141, in gatherer
return sorted(r, key=lambda x: x.duid)
File "/home/greg/Projects/icebreaker-litex-examples/soc/deps/litex/litex/soc/integration/doc.py", line 141, in <lambda>
return sorted(r, key=lambda x: x.duid)
File "/home/greg/Projects/icebreaker-litex-examples/soc/deps/migen/migen/fhdl/module.py", line 136, in __getattr__
raise AttributeError("'"+self.__class__.__name__+"' object has no attribute '"+name+"'")
AttributeError: 'LiteSPISDRPHYCore' object has no attribute 'duid'
https://github.com/mithro/litex/tree/spi-module/litex/soc/cores/spi
And anything else in that repository.
Originally posted by @DurandA in enjoy-digital/litex#522 (comment)
@mithro Thanks! Strangely, LiteSPI doesn't define a sector size so I wonder how partial erase is done.
I see that in examples/arty.py
we use spiflash_mmap
name for LiteSPI instance (link). In my opinion it could be quite confusing since LiteSPI by default is configured to have both Master and MMAP mode (link). I think we should decide either we change the name to something more generic like spiflash_core
or we should remove default master mode.
While looking at the generic PHY code I noticed that amount of actual dummy cycles depends on number of pins used by the command when sending an address (ie. if command sends address on 4 lanes then 8 dummy bits will result in only 2 dummy cycles).
I think we should check if those cases are currently handled correctly and if not then fix them.
The HackADay badge has
two Lyontek LY68L6400 64 Mbit SPI SRAM chips
These SPI SRAM chips, kinda look like SPI NOR chips.
It would be good to have these devices supported as memory mappable for both read and write.
Clock rate:
Datasheet -> https://www.electrodragon.com/w/images/0/04/LY68L6400_0.3.pdf
The PHY is currently always shared between 2 Modules and when a Module is disabled, a dummy one is inserted. We could make things dynamic, like for example what is done in LiteEth for the UDP ports:
https://github.com/enjoy-digital/liteeth/blob/master/liteeth/core/udp.py#L32
or in LiteDRAM for the DRAM ports:
https://github.com/enjoy-digital/litedram/blob/master/litedram/core/crossbar.py
This way, when only 1 Module is used, it would have a direct connection to the PHY, and when several Modules are sharing the PHY the mux logic will be inserted to share it.
The current implementation will not prevent things to work and will not necessarily use more resources (since the dummy Modules will be simplified at synthesis), but improving it would make things closer to the others cores and will provide more flexibility for future features. (ex another type of Module that would be connected to the PHY).
To be sure the place and route tools will be able to use IO flip-flops on the synchronous inputs/outputs.
I tried getting DDR SPI on Fomu by editing https://github.com/litex-hub/litex-boards/blob/master/litex_boards/targets/kosagi_fomu.py:
- self.add_spi_flash(mode="4x", module=spi_flash_modules[spi_flash_module](), with_master=False)
+ self.add_spi_flash(mode="4x", module=spi_flash_modules[spi_flash_module](), with_master=False, rate='1:2')
The build attempt gave me the error
Info: Placed 14 cells based on constraints.
ERROR: Unable to find a placement location for cell 'SB_IO_13'
0 warnings, 1 error
Looking at the generated SoC rtl build/kosagi_fomu_pvt/gateware/kosagi_fomu_pvt.v
I saw this pattern:
SB_IO #(
.IO_STANDARD("SB_LVCMOS"),
.PIN_TYPE(6'd0)
) SB_IO_13 (
.CLOCK_ENABLE(1'd1),
.INPUT_CLK(sys_clk),
.PACKAGE_PIN(builder_inferedddrtristate2__i),
.D_IN_0(main_basesoc_litespiddrphycore2[2]),
.D_IN_1(main_basesoc_litespiddrphycore3[2])
);
SB_IO #(
.PIN_TYPE(6'd41)
) SB_IO_14 (
.D_OUT_0(builder_inferedddrtristate2__o),
.OUTPUT_ENABLE(builder_inferedddrtristate2_oe),
.PACKAGE_PIN(spiflash4x_dq[2]),
.D_IN_0(builder_inferedddrtristate2__i)
);
These two IOs are connected by wire builder_inferedddrtristate2__i
. I suspect this is not quite correct, in particular the connection to PACKAGE_PIN
of the first IO.
The auto-generated modules seem to be missing some opcodes. When switch the different LiteX-Boards targets to LiteSPI, modifications have been made to be able to enable Quad SPI mode on some boards, for ex:
So it seems the script generating the modules is not listing all supported the opcodes.
Hi @pawelsag, @piotr-binkowski,
I did some simplifications to to the generic_sdr PHY and tested it on the iCEBreaker/Arty boards while doing these changes. Could you check that it's still also working correctly on your boards?
I tried to commit each simplification step, could you try to also apply similar silmplifications to the generic_ddr PHY?
Thanks,
Florent
With that we could run the rest of the SoC at a slower frequency while running the SPI core at a higher frequency to get better SPI/XIP performance. I think that this could be achieved by simply adding AsyncFIFOs to streams between SPI cores and the PHY.
What do you think? @enjoy-digital @mithro
In d436b02 a small change was made to the sr_in source when operating in x1 mode. This works in x1 mode with the other changes. But unfortunately this breaks x1 CPU controlled commands when the core is configured in x2 or x4 modes
Here is the change:
diff --git a/litespi/phy/generic_sdr.py b/litespi/phy/generic_sdr.py
index c5446fe..a39ac23 100644
--- a/litespi/phy/generic_sdr.py
+++ b/litespi/phy/generic_sdr.py
@@ -158,7 +169,7 @@ def __init__(self, pads, flash, device, clock_domain, default_divisor, cs_delay)
# Data In Shift.
self.sync += If(sr_in_shift,
Case(sink.width, {
- 1 : sr_in.eq(Cat(dq_i[1], sr_in)), # 1: pads.miso
+ 1 : sr_in.eq(Cat(dq_i[:1], sr_in)),
2 : sr_in.eq(Cat(dq_i[:2], sr_in)),
4 : sr_in.eq(Cat(dq_i[:4], sr_in)),
8 : sr_in.eq(Cat(dq_i[:8], sr_in)),
When configured for x4 mode with a CSR controller enabled most config/status commands operate in 1bit mode. The controller talks on DQ0 and they respond on DQ1.
This commit breaks this behavior, as the controller is now listening for a response on DQ0, which is simply the data it's just sent out.
It appears that on NeTV2 board, data read from flash is the same as compared to hexdump output.
On Arty board it is not. It looks like there is a problem with sampling process. Example:
Binary data:
00000000 48 00 49 00 bb 00 11 |H.I....|
Data read using BIOS:
Memory dump: 0x80000000 24 00 24 80 dd 80 08 ff ff ff ff ff ff ff ff ff $.$.............
When we take for instance:
0x48 = 0b1001000
in flash it seems to be: 0x24 = 0b100100
, so one bit is missing.
Comparison of whole binary (original vs. flash):
0b1001000000000000100100100000000101110110000000000010001
0b100100000000000010010010000000110111011000000000001000x
Overall:
Hi, I'm testing on the ECPIX-5 which has an IS25LP256D, configured to do READ_1_4_4 with 6 dummy cycles as per the flash datasheet. Everything appears to work fine except the speed test fails for DIV=0:
Initializing SPIFlash...
Testing against CRC32: feba9ad6
[DIV: 9] feba9ad6
[DIV: 8] feba9ad6
[DIV: 7] feba9ad6
[DIV: 6] feba9ad6
[DIV: 5] feba9ad6
[DIV: 4] feba9ad6
[DIV: 3] feba9ad6
[DIV: 2] feba9ad6
[DIV: 1] feba9ad6
[DIV: 0] 312f98e1
SPIFlash freq configured to 18 MHz
According to the datasheet, this mode should be good for 81 MHz:
My sysclk is 75 MHz, so DIV=0 should result in 37.5 MHz, which is nowhere close to the maximum. The calculated checksum for DIV=0 is also identical if I run it multiple times. This suggests that there's a deterministic logic error.
As an aside, I also doubt that a speed test like this is actually useful -- in a configuration where the flash is not rated for the max speed the core can do, it can still work well enough to pass the test, but fail later.
SD Cards support "SPI Mode";
It would be good to be able to do XIP reads from an SD Card attached this way.
How to use litespi to perform flash write?
I am trying to integrate litespi and use bios to download images to flash.
Hi,
has anyone accomplished to store the gateware on the SPIflash on an Arty A7 already? Do we have a documentation available for this? What is the most reasonable way to make it very easy to use (e.g. --store
instead of --load
after building the gateware?)
Looking forward to your ideas!
Currently have
litespi/litespi/modules/modules.py
Line 5 in 8075781
We should have at least one non-generated SPI NOR chip example in the code to make sure that it actually works.
It would be nice to have a generic SPI NOR flash emulation model that the LiteSPI core could be tested against.
litespi/tools/spi_nor_config_generator/spi_nor_cfg_gen.py
Lines 351 to 355 in 8075781
Also see textwrap.dedent
Hi, currently there can be two modules attached to the crossbar; one LiteSPIMMAP
and one LiteSPIMaster
. Arbitration between the two is handled by the mux_sel
CSR bit. Software sets it to use the master interface, and clears it to allow the MMAP interface to be used.
I'm planning to add a couple more modules that needs to be hooked up to the crossbar:
USBRequestHandler
to implement DFU directly in gateware.To allow this, we need to implement a better arbitration mechanism. Any thoughts on how to go about this?
I imagine there might be situations where one module needs to send multiple commands uninterrupted, so I figure the arbitration mechanism should be decoupled from both first/last flags on the streams and the chip select signal.
XIP can be a bit confusing, we are in fact providing a MMAP interface to the SPI Flash and one if its usecase is indeed XIP when we are executing code directly from the Flash. But this will also be used to copy blocks of data from the SPI Flash to RAM, store a file system, etc... so MMAP would probably give a better description of the purpose of the core.
LiteSPI is working correctly with good performance on the different boards it has been tested but uses more resources than the LiteX SPIFlash core that was used previously.
When testing different configurations on the iCEBreaker (with python3 -m litex_boards.targets.1bitsquared_icebreaker --cpu-type=serv --build
) we get the following resource usage:
No SPIFlash | LiteX's SPIFlash | LiteSPI (no Master) | LiteSPI (with Master (depth=1))) |
---|---|---|---|
1883 LCs | 2036 LCs | 2353 LCs | 2921 LCs |
Ref | +153 LCs | +470 LCs | +1038 LCs |
- | Ref | +317 LCs | + 885 LCs |
The LiteX's SPIFlash core was equivalent to LiteSPI with Master enabled, so we should reduce resource usage to be able to do efficient designs on small FPGAs.
@xobs what do you think?
Currently clkgen.py has support for xc7 devices using a Xilinx STARTUPE2 instance. Similar support could be added for ECP5 using the Lattice USRMCLK instance. From looking at other code, without understanding much about what is required, it looks like USRMCLK does a similar thing to STARTUPE2. I added the following in clkgen.py and it seems to work.
elif device == "ecp5":
self.specials += Instance("USRMCLK",
i_USRMCLKI = clk,
i_USRMCLKTS = 0
)
This code is selected by passing thedevice = "ecp5"
parameter to LiteSPIPHY
.
I can try the whole pull request process if required.
https://github.com/litex-hub/litespi/blob/master/litespi/core/mmap.py#L106
When used in https://github.com/litex-hub/litex-boards/blob/master/litex_boards/targets/digilent_arty.py, litespi has a 10000 cycle delay for each non-sequential load from flash. If flash is read sequentially, I don't see the delay.
For some reason, I don't see this large delay on the (internal) HPS board, even for non-sequential loads. I haven't had time to investigate why the behavior is different. Instantiation: https://github.com/google/CFU-Playground/blob/main/soc/hps_soc.py#L143-L150
@kgugala FYI
This applies to my version of the icebreaker, and is a follow up of a conversation with @smunaut.
Some SPI flashes, like some part numbers in the W25Q128JV family, support 4x
operation, but are not enabled for 4x
on power-on. My icebreaker uses one of these flashes where the default is 1x
on power on, and therefore 4x
operation does not work out-of-the-box. This can be surprising behavior, and I think initializing to 4x
mode if a user requested a 4x
may be a user-invisible solution :D!
The PHY supports doing 1x
reads even if you supply pads for 4x
operation. I think the easiest way to add support for this is to add some init steps to the LiteSPIMMAP
FSM, which does the following (based on W25Q128JV datasheet):
50h
(Write Enable for Volatile Status Register)35h
)QE
bit (bit 1) in the read value31h
)After these 5 steps have occurred, your SPI flash will be in quad mode until power is cycled.
However, I haven't done this myself because I'm not sure the best way to represent "flash may need to be initialized into 4x
mode" per SpiNorFlashModule
. In the case of W25Q128JV, different part numbers have different defaults (although initializing a part that doesn't need to be initialized is harmless). There's plenty of ways to represent "needs 4x init", but which way is best? Can it be done without regenerating the entirity of generated_modules.py
?
My original Python code cross checked that the total size / page size / page count values all cross checked together.
See https://github.com/mithro/litex/blob/spi-module/litex/soc/cores/spi/modules.py#L22-L137
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.