AX2 / MachXO2 Hardened User SPI Issues [Solved]


#1

I have been working on a design which uses the hardened User Slave SPI on the Machxo2 and need some pointers/help. The design simulates as expected using Active-HDL but in hardware I’m obviously missing something as it appears to think that the transfer has completed on the first rising edge for the SPI clock. I am using a Raspberry Pi Zero to drive the SPI and I have tried a long list of different transfer speeds with no luck. No matter what the SPI or wishbone speed is, I can see on the first rising clock edge the SPISR register negates the TIP field (Transmission in Progress) which naturally cause my FSM to restart and nothing good happens from there. The expected behavior and what is shown in the simulator is the TIP remains high as long as the SPI Chip Select is asserted (low).

Since it works in simulation, it seems it is an electrical issue. However, the 3.3v rail and signals all look ok. I looked at them directly on the RPi and down stream at the FPGA and they don’t look too concerning to me. There is some softening of the signal edges but that is expected. No real overshoot or ringing, if anything the clock rising time is a little long for my liking. So I’m scratching my head a bit. Speed of the SPI seems to have no effect, I have tried many different builds with fast and slow SPI and/or Wishbone clock rates, etc. all with no real change in behavior. For all these tests I’m using a Raspberry Pi Zero W connected to a custom PCB which has the AX2 board on it. I have tried powering it from the RPi Zero and from an independent supply with no change. Some other things of note which I think should be fine, is that I’m using the on board oscillator (OSCH). It isn’t the most accurate clock with a +/-5% rating but shouldn’t really matter for what I’m using it for.

I have a test build here, you will need a lattice diamond license to run it:

the included README has instructions on what is there and how to run the test bench. The FSM basically implements what is in their document with one change. The reference FSM doesn’t work if you have a chip select asserted more then one cycle from the SPI clock, so I added a step to wait for TX ready under that condition. (See: Using User Flash Memory and Hardened Control Functions in MachXO2 Devices Reference Guide, TN1246, Figure 18)

Any advise would be appreciated. I haven’t yet given up on the User SPI Slave EFB but may have to just use my own SPI slave. I can upload scope captures if needed but don’t have access to do so in the forums.


Using hardend SPI on TinyFPGA A2
#2

Do you have a direct connection between the grounds of the SPI master and the AX2?


#3

I believe my grounding should be sufficient. I have every GND pin on the RPi GPIO header tied to a local ground plane.

The capture is of SCLK and the TIP which I mapped to a pin from the Wishbone read. It goes high when TIP is seen from a status and only goes low when TIP is seen low. So it will stay high until it actually reads a TIP not set.

SPI Clock rising edge

SPI Clock and Chip select.

All of these were taken near the AX2


#4

Just to rule it out, I wired the AX2 board directly to the Raspberry Pi Zero and it performed the exact same way.


#5

Picked up a second AX2 board to rule out any manufacturing related issues. The second board behaves exactly the same as the first.


#6

Since I am no closer to finding a resolution, I opened a support ticket with Lattice, there have been a lot of back and forth emails but no progress as of yet.

Thought I would share what the simulation looks like…

First a little description of what is being sent. The FPGA test case is a fully specified User Slave SPI, so I am not using the Lattice extension which inserts 2 bytes of 0xFF. My FSM is providing all bytes to be transmitted.

The FPGA is configured as a User SPI Slave. The SCSN is routed to a GPIO and SCLK, MOSI and MISO are connected to the hard IP block.

The SPI Slave is expecting a formatted operation and will respond accordingly to a specific command. Each SPI operation can be multiple bytes and the Chip Select must be continuously asserted for the duration of the operation. The format of the operations is the first byte the master transmits is the command and subsequent bytes are just providing clocks for the response and are not used. The first Slave response always starts on the 3rd byte and how it responses is based on the command. The test case supports three commands. A Protocol command, a Revision command, and a Zero Command. 0xF0 is the byte which represents a Protocol command, 0xF1 is the byte which represents the Revision command and 0x00 is the byte that represents the Zero Command.

If the slave receives a Protocol command then the 3rd byte that the SPI Slave (the FPGA) transmits will be a byte of 0x01. The first two bytes are always 0x00. The Protocol operation is only three bytes; 0x00 will be returned for any more than 3 bytes. If the slave receives a Revision command then on the 3rd byte that the SPI Slave (the FPGA) transmits will be a byte of 0xA5. Like the Protocol operation, any more master transmitted bytes will result the slave transmitting 0x00. The Zero Command is different. The SPI slave (the FPGA) will transmit a count starting on the 3rd byte and increment by 1 for each addition byte received by the master. The count is reset for each operation. The first count value is 0x00.

For the Protocol and Revision commands, the included test case is self checking in the test bench.

So in summary. This is what should be transmitted by MOSI and MISO; the chip select is asserted continuously for a given operation:

Protocol:
MOSI: 0xF0, 0x00, 0x00
MISO: 0x00, 0x00, 0x01

Revision:
MOSI: 0xF0, 0x00, 0x00
MISO: 0x00, 0x00, 0xA5

Zero:
MOSI: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
MISO: 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07

Capture1: This shows the entire test. It is three groups of SPI bytes.
Capture2: Shows the Protocol command
Capture3: Shows the Revision command
Capture4: Shows the Zero command
Capture5: Shows the output in the console

The simulation shows what I expect. However, in hardware (after it is programmed), the SPI’s TIP field behaves differently for some reason which I don’t understand. It could be a wishbone configuration issue or something else. At this point I have tired many different SPI clock rates and internal wishbone clock rates without figuring out why the simulation is different. The test case uses the internal clock (OSCH) at 2.08Mhz and an SPI clock (SCLK) of 500khz.

The debug[5] signal is the TIP field as read out of the SPISR register over wishbone.

Capture1

Capture2

Capture3

Capture4

Capture5


#7

I have found the cause of the issue and have a fix. In addition I have uncovered a minor issue with the Lattice EBF simulation model.

The really, really short version is that I was not adhering to one of the additional MachXO2 Wishbone requirements. The EFB Wishbone interface requires 3 cycles for every read or write operation. Basically there has to be at least one cycle where the controls are not asserted between each operation. (Negated controls, followed by asserted controlled followed by the assertion of ACK). In my original design I was performing back to back Wishbone operations without negatting the controls (CYC, STB). Changing the state machine which interfaces to the EFB to perform three cycle operations seems to have resolved the issue.

So the simulation model. In my original design the simulation model that is used by ActiveHDL did not have any issue with the controller issuing single cycle Wishbone operations. The design simulated as I expected it to. It wasn’t until I put the design in hardware did I see an issue. The simulation and hardware behavior diverged right around the time the controller issued it’s first write to the TX buffer following the start of the transfer. So it makes sense that something was getting corrupt going from a read of the status register directly to a write of the TX buffer. This likely corrupted something or wrote to the wrong internal register location leading to the SPI logic to reset or abort which I saw as TIP being negated.

I have updated the Github project with the corrected code if anyone is interested.


#8

Hi I just found this thread and I’m glad it’s very recent. I was wondering if you have any resources/tutorials on getting started with the Slave SPI EFB as there aren’t many examples online about to use it, other than the sample project that’s provided by Lattice. For my implementation, I copied over the code from the RD1125 reference code and created a “top” module to instantiate that SPI slave. I used the internal oscillator set at 16.63MHz and passed in only a reset and wrote a constant to GPI_0 port of 8’b10101010. I then used an Arduino as the SPI master to try to read this port but I keep getting a constant 0xFF, so I’m not sure what I’m missing. I put the traces on a scope and can definitely see the SPI Master sending the signals and the response from my MachXO2 fpga. (I have the SPI inputs/outputs in my top module connected to the SPI slave module ports and assigned them to the dedicated SPI pinouts according to the spec sheet too)

Doing some searches online, I’ve got a few questions: 1) Do you need to purchase license to use the SPI EFB? 2) Do you need to use the IP Express to generate this EFB for my specific FPGA, instead of taking it from the reference code? 3) Is there an error in the reference code that needs to be modified?

Can you outline what steps I need to take to properly implement the SPI?

Thanks,
Samson


#9

Unfortunately, I don’t have much more then what you have already come across and what I put on github. The RD1125 example, in my opinion, is not the easist thing to go through. It tries to cover a couple device families (MachX02 and MachXO3) and doesn’t target a specific device, so you are left filling in the blanks (the IO definition for example).

As for an SPI Master, please ensure you are only using 3.3V IO devices. The offical Arduino Uno R3’s ATmega328P only has 5V IO. The FPGA is not 5V tolerant and you will quickly damage the FPGA using 5V.

In my hardware test enviornment I am using a Raspberry Pi Zero and some Python code (rpi/rpi_spi_test.py). Just a side note, my test build uses a protocol that is similiar but not the same as the RD1125 reference design so my spi master test code would need to be changed to work with the RD1125 design. Some other things that come to mind, 1) make sure that the SPI Clock is not greater then half of your internal wishbone clock. This is a requirement of the EFB. 2) make sure the design has a cycle between Wishbone operations where the controls are negated (what I learned the hard way). 3) the RD1125 does not use the internal TIP register field for defining the boundaries of the protocol. It uses the SS_N signal directly. So make sure your logic is using it, my example uses the intern TIP. Both should work though using TIP in theory makes working with the last received byte easier. 4) I would recommend that you simulate the design and capture some of the operations on the wishbone interface. The Diamond license includes a license for ActiveHDL. There is a pretty specific order of operations detailed on “Figure 18. SPI Slave Read/Write Example (via WISHBONE) - Production Silicon” of the “Using User Flash Memory and Hardened Control Functions in MachXO2 Devices Reference Guide”. Though there is a little issue with the statemachine flow they provide. It assumes one clock between SS_N and the first SCK. Their design would have you put a byte in the TX buffer before it was ready to accept it when there was a multi SCK delay between SS_N and the first SCK. My fix was simply to wait for the TX buffer ready when in the “wait for TIP” state.

To answer your questions,

1) Do you need to purchase license to use the SPI EFB? No. It is included in the Lattice Diamond license (which is also free). In Windows, there is a separate icon for it and you can launch it from within diamond. This file (https://github.com/LucAce/MachXO2-SpiSlaveTestBuild/blob/master/rtl/slave_efb.v) is one of the outputs of IPExpress. It should be all you need but the Lattice AE recommend that the .ipx file that is generated be included in the source list instead of the .v file. (Though both should build correctly).

2) Do you need to use the IP Express to generate this EFB for my specific FPGA, instead of taking it from the reference code? It is highly recommended you use IPExpress to generate the files for the EFB. Specifically you need to make sure the Wishbone clock rate in IPExpress is set to the wishbone clock you are using in the FPGA fabric. See captures below.

3) Is there an error in the reference code that needs to be modified? I don’t know, I didn’t spend a lot of time trying to build it. If you want a AX1/2 specific example, I recommend using my test build. It includes everything you should need.

If you have a design to share, it might make things easier. Baring that I would look at the wishbone interface and make sure it is reading and writting the EFB registers correctly. Using the SPI Slave EFB requires timely reading and writting the registers as there is no flow control.


#10


#11

Added Slave EFB IPExpress files:


#12

Hi there
Checked out the latest release on GITHUB but this is not working. In fact I get some courious results but not what should be read via SPI. Still working.