Jump to content
  • 0

SPI - Arduino to Basys 3


Tickstart

Question

Arduino is the SPI Master and therefore provides the clock, SPICLK through a PMOD. How do I receive the clock in a good way on the FPGA?

Vivado does not approve of checking rising_edge(SPICLK) so I though I'd put a clock buffer or something in between (not that I know why or what they do but it sounds like a good idea). At some point Vivado told me to add "set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets {SPICLK_IBUF}]" to the constraints file, but I still got warnings and it didn't recommend I proceed.

 

If I have the top level SPICLK connected to an IBUF_IBUFDISABLE with the disable line connected to the slave select (SS) line, I get this warning:

[DRC 23-20] Rule violation (CKLD-2) Clock Net has IO Driver, not a Clock Buf, and/or non-Clock loads - Clock net spi_buf is directly driven by an IO rather than a Clock Buffer or may be an IO driving a mix of Clock Buffer and non-Clock loads. This connectivity should be reviewed and corrected as appropriate. Driver(s): IBUF_IBUFDISABLE_inst/O
 

If I have the top level SPICLK connected to an IBUF_IBUFDISABLE and that into a BUFGCE, with the disable line connected to the slave select (SS) line and the inverse of SS into the CE, I get this warning:

[Place 30-574] Poor placement for routing between an IO pin and BUFG. This is normally an ERROR but the CLOCK_DEDICATED_ROUTE constraint is set to FALSE allowing your design to continue. The use of this override is highly discouraged as it may lead to very poor timing results. It is recommended that this error condition be corrected in the design.

    IBUF_IBUFDISABLE_inst (IBUF_IBUFDISABLE.O) is locked to IOB_X0Y25
     and BUFGCE_inst (BUFGCTRL.I0) is provisionally placed by clockplacer on BUFGCTRL_X0Y1

Roughly the same warning was issued with just the BUFGCE.

 

I know there are other ways of polling the input clock from the arduino and treating it as normal signal but I want to do it the "proper" way.

Link to comment
Share on other sites

Recommended Posts

It does look a little odd. It looks as though it will move bits into data_reg every cycle that "spi_clk" is high,

TRANSCIEVE: process(clk)
   begin
      if rising_edge(clk) 
         if slave_select = '0' then  
           -- slave is selected
           if spi_clk_tick = '1' and  spi_clk_tick_last = '0' then
              -- seen the rising edge on spi_clk, so grab the data
              data_reg <= data_reg(6 downto 0) & mosi_sync;
           end if;
         end if;
         -- remember the current spi_clk_tick signal so we can detect if it 
         -- changes from '0' to '1' in the next cycle
         spi_clk_tick_last <= spi_clk_tick;
      end if;
    end process;
Link to comment
Share on other sites

17 hours ago, hamster said:

It does look a little odd. It looks as though it will move bits into data_reg every cycle that "spi_clk" is high,


TRANSCIEVE: process(clk)
   begin
      if rising_edge(clk) 
         if slave_select = '0' then  
           -- slave is selected
           if spi_clk_tick = '1' and  spi_clk_tick_last = '0' then
              -- seen the rising edge on spi_clk, so grab the data
              data_reg <= data_reg(6 downto 0) & mosi_sync;
           end if;
         end if;
         -- remember the current spi_clk_tick signal so we can detect if it 
         -- changes from '0' to '1' in the next cycle
         spi_clk_tick_last <= spi_clk_tick;
      end if;
    end process;

Thanks for your input. The spi_clk_tick is only one cycle long, FPGA clock-wise. At least that's the idea. Anyway, my previous code was all wrong so it behaved very weird.

Link to comment
Share on other sites

53 minutes ago, D@n said:

@Tickstart,

Does this mean you now have things working?

Dan

Well as always, they're evolving.. The rising_edge-thing seems to be working, the Arduino is supposed to transmit a byte every second and the incrementer I've connected it to shows a multiple of 8 in hex every second on the 7-seg display. 00 -> 08 -> 10 -> 18 -> 20 etc. So it's progressing, but the "data_reg <= data_reg(6 downto 0) & mosi_sync;"-code does not want to do anything, don't know if it's because of the MOSI-line not actually responding or something else. The chase continues.. (:

Link to comment
Share on other sites

@Tickstart,

Making progress?  Good ...

Ok, so ... if it works in simulation, but not in real life ... do you have the right pin identified in your XDC file?

Since you are coming from the arduino, are you properly toggling the right pin?

Just some things to think about.

Dan

Link to comment
Share on other sites

8 minutes ago, D@n said:

@Tickstart,

Making progress?  Good ...

Ok, so ... if it works in simulation, but not in real life ... do you have the right pin identified in your XDC file?

Since you are coming from the arduino, are you properly toggling the right pin?

Just some things to think about.

Dan

The simulation works and so does the real life thing, at least that's what I think. It (the synchronizer that is, which is what I've spent most time on thus far trying to fix) seems to work with the SPI clock at least. But whether the Arduino actually does what I want it to do is a whole other question..

This is my Arduno code:

#include <avr/io.h>
#include <util/delay.h>

//Initialize SPI Master Device
void spi_init_master (void)
{
	PRR |= (1 << PRTWI) | (1 << PRTIM2) | (1 << PRTIM0) | (1 << PRTIM1) | (1 << PRUSART0) | (1 << PRADC); // power save
	PRR &= ~(1 << PRSPI);
	DDRB |= (1 << DDB5) | (1 << DDB3) | (1 << DDB2);		//Set SS, MOSI, SCK as Output
	SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR0);			//Enable SPI, Set as Master, divide by 16
	SPSR;
	SPDR;
}

//Function to send and receive data
unsigned char spi_tranceiver (unsigned char data)
{
	PORTB &= ~(1 << DDB2);			   // SS low
	SPDR = data;                       //Load data into the buffer
	while(!(SPSR & (1 << SPIF)));      //Wait until transmission complete
	PORTB |= (1 << DDB2);			   // SS high
	return(SPDR);                      //Return received data
}

//Main
int main(void)
{
	spi_init_master();                  //Initialize SPI Master

	unsigned char data = 0;

	while(1)
	{
		spi_tranceiver(data++);
		_delay_ms(1000);
	}
}

Not that it necessarily tells you very much, I asked on AVRFreaks and they thought it was fine.

Link to comment
Share on other sites

@Tickstart,

There's still a test you can do with the arduino ... send a whole bunch of zeros, like in a tight loop, and use a voltmeter to make sure you are getting the right value.  Repeat using all ones.  Then you know you are toggling the right wire.

Dan

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...