Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
16 years ago

SPI doesn't work at all

Hi,

I need collect data from PIC18F4550 by SPI connection.

The PIC is the Master running with Polarity = 0 and Phase = 1.

The FPGA uses Altera IP SPI (3 wires Serial). All wires [SCK, MISO, MOSI and SS] are correct connected.

The transfer works but with a lot of errors. A huge part of bytes toggle one or more bits. The problem can occur in all eight bits. Sometimes correct transfers are done.

Tracking the origin of errors, I implement a function on PIC, controlling the SPI wires, for

emulate the SPI transfer and certify about what's is happening. This function controls the time between bits and time between transfers. The code are below.

In FPGA side, I'm polling for detection of new byte and print it in NIOS console.

I tried different byte patterns for my tests and yours inverse.

Pattern from PIC to FPGA

01010101

11001100

11110000

00111100

Pattern from FPGA to PIC

1111 1111

0000 0000

In all cases, except for [PIC 0xFF -> FPGA], errors occur. In case of [PIC 0x00 <-> 0x00 FPGA] Errors occur too.

The cable has 10cm soldered direct in hosing for PIC chip. A picture is worth a thousand words. dl dot dropbox dot com/u/68170/DSC00273.JPG

After all tests, I believe that FPGA is the problem. Yes, I tried use other 4 wires for connection in different pins of I/O Port of my DE2-70. Same error behavior.

After this detailed description of my problems,

if someone can give-me some light of problem, I'll thanks a lot

So let's to the codes:

PIC18F4550 first. Pic running using 3.3V of FPGA


char SPIMasterBruteForce(char data)
{
//Phase 1
//Polarity/Enable 0
# define DELAY_SPI Delay10KTCYx(240); // about 200-300 milliseconds 	
	typedef volatile near union {
		struct{
			unsigned DT0:1;
			unsigned DT1:1;
			unsigned DT2:1;
			unsigned DT3:1;
			unsigned DT4:1;
			unsigned DT5:1;
			unsigned DT6:1;
			unsigned DT7:1;
		};
	    unsigned data;
	} DATA;
	
	DATA DATA_OUT;
	DATA DATA_IN;
	
	DATA_OUT.data = 0; // Clean for clean 
	DATA_IN.data  = 0; // 
	
	DATA_OUT.data = data;
	
	PORTAbits.RA5=1; // SS Inactive. 
	DELAY_SPI;
	PORTDbits.RD1=1; // LED ON 	
	
	// Not necessary clock cycle before transfer. 
	
	DELAY_SPI;
	PORTBbits.RB1=1;            // SCK
	DELAY_SPI;
	PORTBbits.RB1=0;            // SCK
	DELAY_SPI;
	
	//
	
	PORTBbits.RB1=0; // SCK (LOW)
	PORTAbits.RA5=0; // SS Active (LOW);
	DELAY_SPI;
	DELAY_SPI;
	DELAY_SPI;
	
	// 7//////////////////////////////
	PORTBbits.RB1=1;            // SCK  Propagate Bit 
	PORTCbits.RC7=DATA_OUT.DT7; // SDO 
	DELAY_SPI;
	DATA_IN.DT7=PORTBbits.RB0;  // SDI  Capture Bit
	PORTBbits.RB1=0;            // SCK  
	DELAY_SPI;
	// 6//////////////////////////////
	PORTBbits.RB1=1;            // SCK (HIGH)
	PORTCbits.RC7=DATA_OUT.DT6; // SDO
	DELAY_SPI;
	DATA_IN.DT6=PORTBbits.RB0;  // SDI
	PORTBbits.RB1=0;            // SCK (LOW)
	DELAY_SPI;	
	// 5//////////////////////////////
	PORTBbits.RB1=1;            // SCK
	PORTCbits.RC7=DATA_OUT.DT5; // SDO
	DELAY_SPI;
	DATA_IN.DT5=PORTBbits.RB0;  // SDI
	PORTBbits.RB1=0;            // SCK
	DELAY_SPI;	
	// 4//////////////////////////////
	PORTBbits.RB1=1;            // SCK
	PORTCbits.RC7=DATA_OUT.DT4; // SDO
	DELAY_SPI;
	DATA_IN.DT4=PORTBbits.RB0;  // SDI
	PORTBbits.RB1=0;            // SCK
	DELAY_SPI;
	// 3//////////////////////////////
	PORTBbits.RB1=1;            // SCK
	PORTCbits.RC7=DATA_OUT.DT3; // SDO
	DELAY_SPI;
	DATA_IN.DT3=PORTBbits.RB0;  // SDI
	PORTBbits.RB1=0;            // SCK
	DELAY_SPI;
	// 2//////////////////////////////
	PORTBbits.RB1=1;            // SCK
	PORTCbits.RC7=DATA_OUT.DT2; // SDO
	DELAY_SPI;
	DATA_IN.DT2=PORTBbits.RB0;  // SDI
	PORTBbits.RB1=0;            // SCK
	DELAY_SPI;
	// 1//////////////////////////////
	PORTBbits.RB1=1;            // SCK
	PORTCbits.RC7=DATA_OUT.DT1; // SDO
	DELAY_SPI;
	DATA_IN.DT1=PORTBbits.RB0;  // SDI
	PORTBbits.RB1=0;            // SCK
	DELAY_SPI;
	// 0 /////////////////////////////
	PORTBbits.RB1=1;            // SCK
	PORTCbits.RC7=DATA_OUT.DT0; // SDO
	DELAY_SPI;
    	DATA_IN.DT0=PORTBbits.RB0;  // SDI
    	PORTBbits.RB1=0;            // SCK
    	DELAY_SPI;
	//////////////////////////////////
	
	DELAY_SPI;
	DELAY_SPI;
	DELAY_SPI;
	PORTAbits.RA5=1; // SS inactive (HIGH) ;
	
	// Not necessary clock cycle after transfer. 
	
	DELAY_SPI;
	PORTBbits.RB1=1;     
	DELAY_SPI;
	PORTBbits.RB1=0;       
	DELAY_SPI;
	
	PORTDbits.RD1=0; // LED OFF
	
	return DATA_IN.data;
}	
void SPIMasterMySPITest(void)
{
	// Setup IO Pins in PIC
		
	TRISCbits.TRISC0 = 0; //LED Green  - Output 
	TRISDbits.TRISD1 = 0; //LED Yellow - Output
	TRISDbits.TRISD0 = 0; //LED Red    - Output
	
	PORTCbits.RC0    = 0; // LED Green - OFF
	PORTDbits.RD1    = 0; // LED Yellow- OFF
	PORTDbits.RD0    = 0; // LED Red   - OFF
	
	TRISBbits.TRISB1 = 0; // SCK - Output
	PORTBbits.RB1    = 0; // SCK - (LOW)
		
	TRISBbits.TRISB0 = 1; // SDI - Input  (MISO)
	PORTBbits.RB0    = 0; // Not necessary - Force cleaning of bit register
	
	TRISCbits.TRISC7 = 0; // SDO - Output (MOSI)
	PORTCbits.RC7    = 0; // SDO - (LOW)
	
	TRISAbits.TRISA5 = 0; // SS  - Output
	PORTAbits.RA5    = 1; // SS  - (LOW)
	
	
	while (1) 
		{ 
			PORTDbits.RD1=1;            // Yellow LED ON
			Delay10KTCYx(240);          // BIG Delay between transfers 
			SPIMasterBruteForce(0b10101010); // Sending the number 170 for test
			PORTDbits.RD1=0;            // Yellow LED ON
			Delay10KTCYx(240);	        // BIG Delay between transfers
	    }
}	
void main(void)
{
	ADCON0 = 0x00;   // ADC OFF 
	ADCON1 = 0x0F;   // ALL I/O PINS DIGITAL
	CMCON  = 0x07;   // COMPARATOR DISCONNECTED FROM PORT(A) 
	while (1)
	{
		SPIMasterMySPITest();
	}  
}

NOW FPGA CODE


void SPIPolling(void)
{
	if (IORD_ALTERA_AVALON_SPI_STATUS(SPI_BASE) & ALTERA_AVALON_SPI_STATUS_RRDY_MSK )
	    {
	    	printf(": %d \n", (char)IORD_ALTERA_AVALON_SPI_RXDATA(SPI_BASE));
	    }
	if (IORD_ALTERA_AVALON_SPI_STATUS(SPI_BASE) & ALTERA_AVALON_SPI_STATUS_TRDY_MSK )
	    {
	    	IOWR_ALTERA_AVALON_SPI_TXDATA(SPI_BASE, 0); //255 );
	    }
}
int main()
{
	unsigned char count  = 0;
	unsigned int  count2 = 25000;
	printf("Hello from Nios II!\n");
  while(1)
  {
	  SPIPolling();
	  // Some lights to indicate that my NIOS is alive. 
	  IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE, count ) ;
	  count++;
	  if (count==255) count = 0;
	  while (count2) count2--;
	  if (!count2) count2 = 25000;
  }
  return 0;
}

2 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Are you sure that the clock on the FPGA's SPI interface isn't too fast for the PIC controller?

    Try to put a signaltap probe on the SPI interface to see what the signals look like.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I notice, that are writing SDO and reading SDI after SCK rising edge, which correspondends to no usual SPI mode. I don't see, which SPI mode is implemented in the FPGA, but I guess that it doesn't match the master's behaviour, which would explain well the erratic result.

    P.S.: If you intend SPI mode 0, you have to set SDO before the rising clock edge.