I am sending bytes from SPI master (FTDI FT2232H) over SPI to the SPI slave (FPGA). SPI master is actually a C program that implements libMPSSE directly from the FTDI.
C program looks like this:
// POSIX headers
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
// Other headers
#include "libMPSSE_spi.h"
#include "WinTypes.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// This function prints an array and then exits. We will use it for error printing.
////////////////////////////////////////////////////////////////////////////////////////////////////
void print_and_quit(char array[]){
printf("%s\n", array);
getchar();
exit(1);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Entry point.
////////////////////////////////////////////////////////////////////////////////////////////////////
int main(int argc, char ** argv){
// A:
Init_libMPSSE();
FT_STATUS status; // B:
FT_DEVICE_LIST_INFO_NODE channel_info; // C:
FT_HANDLE handle; // D:
ChannelConfig channel_configuration;
unsigned int channel = 0;
unsigned int channel_count = 0;
int i;
// E:
status = SPI_GetNumChannels(&channel_count);
if (status != FT_OK){
print_and_quit("MASTER: Error while checking number of available MPSSE channels.");
}
else if (channel_count < 1){
print_and_quit("MASTER: There are no MPSSE channels available.");
}
else{
printf("MASTER: There are %d MPSSE channels available.\n", channel_count);
}
// F:
for (i = 0; i < channel_count; i++){
status = SPI_GetChannelInfo(i, &channel_info);
if (status != FT_OK){
print_and_quit("MASTER: Error getting channel info.");
}
else{
printf("MASTER: Channel number: %d\n", i);
printf("MASTER: Channel description: %s\n", channel_info.Description);
printf("MASTER: Channel serial number: %s\n", channel_info.SerialNumber);
}
}
// G:
printf("MASTER: Enter a channel number to use: ");
scanf("%u", &channel);
// H:
status = SPI_OpenChannel(channel, &handle);
if (status != FT_OK){
print_and_quit("MASTER: Error openning desired MPSSE channel.");
}
// I:
channel_configuration.ClockRate = 1000;
channel_configuration.configOptions = SPI_CONFIG_OPTION_MODE0 | SPI_CONFIG_OPTION_CS_DBUS4 |
SPI_CONFIG_OPTION_CS_ACTIVELOW;
channel_configuration.LatencyTimer = 30;
status = SPI_InitChannel(handle, &channel_configuration);
if (status != FT_OK){
print_and_quit("MASTER: Error configuring & initializing selected MPSSE channel.");
}
// J:
uint8_t send_buffer[8] = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x11
};
uint32_t transfer_count = 0;
uint32_t transfer_options = SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES |
SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE | SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE;
status = SPI_Write(handle, send_buffer, 8, &transfer_count, transfer_options);
if (status != FT_OK){
print_and_quit("MASTER: SPI communication error.");
}
status = SPI_CloseChannel(handle);
if (status != FT_OK){
print_and_quit("MASTER: SPI channel closed.");
}
Cleanup_libMPSSE();
return 0;
}
For some reason, sometimes the communication looks like this (signals are MOSI & SCK):
But sometimes communication is different like this:
and whenever I get the second signal, FPGA goes into a state which is reset state or idle state. I am not sure about which one it is.
In both cases FTDI chip sends 8 bytes i.e. 0x00
, 0x00
, 0x00
, 0x00
, 0x00
, 0x00
, 0x00
, 0x11
but when this is done in 1st case, MOSI data falls just a little which is correct, and in second case MOSI data remains high and also some high frequency clock can be seen on the SCK!
Why could this happen?
ADD1:
After suggested I measured GND directly on the PCB and I get some 2.5 kHz noise. This is the same frequency that can be seen in a scenario when after the data transmission, PCB goes in an idle / reset state.
Here is the noise from afar:
And a closeup to take the measurement of the frequency (2.5 kHz):
ADD2:
After discovering 2.5 kHz "noise" on the GND I assume that probably my oscilloscope is not connected properly. GND wires of the probes are properly connected to the GND, but there is a GND plug on the front of the oscilloscope which is not connected currently.
Could this be my problem?
ADD3:
After dissconnecting my oscilloscope from my system and discovering that symptoms remain, I am sure that oscilloscope is not part of the problem of going in a reset/idle state. Therefore I am suspecting that the problem is the PCB design which I already linked to in my first paragraph. Because link that I posted has Kicad project file, I am posting a PDF of the schematics here as well, so that somebody might check the SPI signal lines - I am using MODE0 as can be seen from the C program. SPI clock is 1kHz. FPGA's SPI slave is driven by 12 MHz external oscillator.
ADD4:
Measuring the output of 1.2 V and 3.3 V voltage regulators revelas that on power-on 1.2 V power supply comes online approximately 3ms after the 3.3 V power supply.
This is an excerpt from the Lattice Ultra Plus UP5k datasheet that I already linked to:
4.5. Power-up Supply Sequence
It is recommended to bring up the power supplies in the following order. Note that there is no specified timing delay between the power supplies, however, there is a requirement for each supply to reach a level of 0.5 V, or higher, before any subsequent power supplies in the sequence are applied.
- VCC and VCCPLL should be the first two supplies to be applied. Note that these two supplies can be tied together subject to the recommendation to include a RC-based noise filter on the VCCPLL. Refer to iCE40 Hardware Checklist (FPGA-TN-02006).
- SPI_VCCIO1 should be the next supply, and can be applied any time after the previous supplies (VCC and VCCPLL) have reached as level of 0.5 V or higher.
- VPP_2V5 should be the next supply, and can be applied any time after previous supplies (VCC, VCCPLL and SPI_VCCIO1) have reached a level of 0.5 V or higher.
- Other Supplies (VCCIO0 and VCCIO2) do not affect device power-up functionality, and they can be applied any time after the initial power supplies (VCC and VCCPLL) have reached a level of 0.5 V or greater. There is no power down sequence required. However, when partial power supplies are powered down, it is required the above sequence to be followed when these supplies are re-powered up again.
ADD5:
Investigating further reveals that in the scenario when board goes in a reset/idle state chip select (CS) line has some sort of a glitch soon after data is transfered and CS returns high (this glitch is always present when board goes in a reset/idle state):
This however is not present when sending data suceeds and board does not go in a reset/idle state:
ADD6:
Regarding ADD5... Signals are much nicer if I put external pullup resistors on CS, MOSI, MISO and SCK lines (there are no more any weird voltages between 0V and 3.3V).
But when the glitch, mentioned in ADD5 happens, board still goes in reset/idle state. It looks like this:
And without a glitch when PCB continues to work normally after the data transfer:
So that glitch is probably source of my problems.