AXI SPI python code

I guess you will have to enable SPI kernel configurations and rebuild the linux kernel. One way to do it is to patch your own bsp, like this:

Well, if pynq is hugely good for anything, IMHO, it is for not having to rebuild the kernel when a different overlay is loaded… I am writing a simple AxiSPI.py module that allow me to read\write the quad spi peripheral registers, and for now it will be enough.
In the future I would like to write a class like AxiIIC using libspi.so, but it must be seen if I am going to be able (and have the time) to do so
Cheers
PS I am a board level engineer by trade and the “class” codeword in any software source still give me the shivering!!! :grinning:

Well, we cannot enable every configuration in the kernel… that will make the kernel pretty heavy… we will enable SPI in the next release though.

Just in case someone want to work on improving it. It’s rough, undocumented and garage-electronics style code as you would expect from a board designer, but works (for me…)
spi.py (3.0 KB)
it comes with no guarantees whatsoever! :grinning:

5 Likes

Thanks for sharing!

Cathal

Hello,thank your for your sharing,I have open You code spi.py. Is the coderesp.append() could be used for read data?

Hello Allen,
in SPI protocol you do not “read”… you push n bytes out with xfer and read n bytes in from DRR; So you do not use resp.append(), you use spi.xfer() pushing dummy bytes (using packet) and the function returns resp, i.e. a list of the read bytes
Best regards

1 Like

Hi gpcus, I have some trouble with SPI master on PL, I’m using your python code (thanks a lot! looking to pynq drivers it seems that is definetly correct) can you share your Vivado design? I’m using Pynq Z2 board but without success (it’s seems that SS pin is ok, but MISO, MOSI and CLK doesn’t send anything, tested with an oscilloscope)
Thanks in advance!

Hi Enrico,
As you can probably guess from my post date, a lot of water has gone under the bridge…
I do not have the pynq design any more, unfortunately, but, in truth, I do not recall having had any problem at the time or ever with the SPI xilinx IP… if the problem persist and keep bothering you would you consider sending me your Vivado project so I can have a look and see if anything is odd?
Best regards

Guido

Thanks Guido for your help!
Of course, I share with you all the project here for Vivado 2020.1 (for pynq 2.6) in this link:

In particular, the complete block design is in this picture:

I set the constraints similar to pynq SPI (in order to use the Arduino pins of the PZ2 board):

set_property -dict {PACKAGE_PIN W15 IOSTANDARD LVCMOS33} [get_ports spi_rtl_io1_io]
set_property -dict {PACKAGE_PIN T12 IOSTANDARD LVCMOS33} [get_ports spi_rtl_io0_io]
set_property -dict {PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports spi_rtl_sck_o]
set_property -dict {PACKAGE_PIN F16 IOSTANDARD LVCMOS33} [get_ports spi_rtl_ss_o]

I have tried to change the ports name as spi_rtl_io1_o, spi_rtl_io0_i, but without success (MOSI and CLK in transactions doesn’t send anything).

The axi_quad_spi is set as master, standard mode, transaction width 8, frequency ratio 8x1, FIFO depth 16.
I also use a clocking wizard because in several tutorial I see that is necessary, so I set it with clock out 40MHz without reset and power_down.

Any suggestions?

Thanks in advance!

Hello there,
I can’t see anything evidently wrong or odd about the design… I hope you already found the problem root cause, but my suggestion is trying to proceed by isolating the potential source of the mistake. To do that I will simulate an SPI transaction and see if I\O move at least at that level, then insert in the vivado project an ILA to emulate the same signals “live”. Additionally maybe something is wrong with passing SPI signals through the I\O interface port and you can try expanding it in single signals, each one with its own i\o port
Best regards

Guido

Hello there,
I have tried the same design and the same code on a MicroZed7010 and it works without problem (I have used the Arduino ASI Carrier Board with the Arduino pinout) with my PYNQ 2.6 build for MicroZed.
So, I think there is a problem on PYNQ Z2 board and PYNQ 2.6 , I don’t know why… any suggestions?

Hello there again,
configuring on PMODB on PYNQ Z2 it works!
Later me and my company will publish a git repo for this project (we often publish pynq tutorial).

2 Likes

Hi Enrico,
If you have tutorials or examples, feel free to post them to the Learn or Community sections of the forum.

Cathal

1 Like

Dear all,
we have prepared the github repo here:

Now I post it also on tutorial section :+1:

4 Likes

Hello @Enrico_Giordano ,

Using the design for AXI quad SPI given in the github link, I tried to implement pmod spi control using pynq z2. I have been trying to write bit values to the SPI Control Register (SPICR), where writing to TX_FIFO_Reset register and RX_FIFO_Reset register isn’t working, whereas for the 1st 5 register values, that is, for LOOP, SPE, Master, CPOL, CPHA is working, as you can see in the image

Would you be able to help with this issue?

Hey, thank you very much for your code. I really would like to understand that better so my question is how did you figure it out?

Is there any documentation which says about values below?

XSP_DGIER_OFFSET = 0x1C
XSP_IISR_OFFSET = 0x20
XSP_IIER_OFFSET = 0x28
XSP_SRR_OFFSET = 0x40
XSP_CR_OFFSET = 0x60
XSP_SR_OFFSET = 0x64
XSP_DTR_OFFSET = 0x68
XSP_DRR_OFFSET = 0x6C
XSP_SSR_OFFSET = 0x70
XSP_TFO_OFFSET = 0x74
XSP_RFO_OFFSET = 0x78
XSP_REGISTERS = [0x40, 0x60, 0x64, 0x68, 0x6c, 0x70, 0x74, 0x78, 0x1c, 0x20, 0x28]

XSP_SRR_RESET_MASK = 0x0A
XSP_SR_TX_EMPTY_MASK = 0x04
XSP_SR_TX_FULL_MASK = 0x08
XSP_CR_TRANS_INHIBIT_MASK = 0x100
XSP_CR_LOOPBACK_MASK = 0x01
XSP_CR_ENABLE_MASK = 0x02
XSP_CR_MASTER_MODE_MASK = 0x04
XSP_CR_CLK_POLARITY_MASK = 0x08
XSP_CR_CLK_PHASE_MASK = 0x10
XSP_CR_TXFIFO_RESET_MASK = 0x20
XSP_CR_RXFIFO_RESET_MASK = 0x40
XSP_CR_MANUAL_SS_MASK = 0x80

SLAVE_NO_SELECTION = 0xFFFFFFFF

Hello there,
it’s a long time I did this, but I assume the Xilinx quad AXI SPi IP docs is the place to look at
Best regards

1 Like

Well, I’m a bit late to the party, but, yes, you can. I did exactly that:

  • By default the EMIO pins are routed to the PL.
  • If you enable the spidev node in the devicetree (which requires a DIFFERENT compatible name these days (e.g. “spi-petra”)) (which you can do by dynamically loading and overlay in /sys/kernel/config/device-tree/overlays), the kernel will dynamically load the spidev driver, and as long as you create a bitfile which routes the EMIO pins to the correct outputs, this actually works.

That being said, there was a bug in the v2021 kernel that I ran into, which caused glitches in the driver. It seems to be fixed in the v2022.1 release.

(Obviously using the AXI-SPI block will also work, but then you basically move all the work into userspace – which indeed is the whole point of the pynq I guess – but for stuff that’s already built-in into the PS, there’s no need to reinvent the wheel)

Hope this helps someone,
Kr,
Arnout

I am not sure if there is progress of axi spi python code driver available in pynq. I am trying to interface with an AFE chip (Analog Front End) that can go up to 85MSPS. Is there anything available I can use that to interface with type high speed chip? hopefully one I can change the clock rate. I have tried spidev but I get an error that a file does not exits.

Any help is truly appreciated.

Regards