Following my previous blog on the continuing saga of my attempt to create an SPI (serial peripheral interface) in my Spartan 6 LX9 FPGA development board, I received an incredible amount of fantastic feedback in the form of comments on this project. The first thing I'm going to do is take advantage of some of this knowledge.
The first order of business, based on Hamster's advice, is to get rid of the second clock resource that I generated with the DCM. What I had done was use the DCM to buffer the system clock and to generate a second clock for the SPI. The DCM on my chip won't create a clock any slower than 400KHz, but I need a 100KHz clock for the SPI. To do this, I fed the slowed clock into a divide-by-four counter. Now I'm going to replace that with a single buffered 100 MHz system clock and a divide-by-1,000 (10-bit) counter to generate my 100KHz SPI clock.
With the above clock gone, I use a 9-bit counter and roll it over on the binary value 0b1111101000. This results in an even 100KHz SPI clock that doesn't consume a second clock resource. Then Devel@latke.net reminded me that I really need double clock speed, because I'm toggling my SPI clock value on each counter rollover. If my counter runs at the desired frequency, I'll only get half a wave for each counter rollover. That means I really need a divide by 500, or a rollover value of 0b111110100.
Next, I took some advice from Paul Clark about getting the lines set up and clocking that data out. Paul suggested a counter with four steps more than the number of data bits. In his example, he had 32 bits of data with a 36-step count. I have 8 bits of data so I'll have a 12-step counter.
The "SS"/"Slave Select" (a.k.a. "CS"/"Chip Select") signal for SPI is active low, so I need to get my "SS" signal to a logic 1 value as soon as possible upon system power-up. I've been digging, but I haven't yet found a way to set the power up default state of an output pin, so I have to set this first thing, however... Is this thinking like a software person? In the FPGA hardware world, if I put in the command "SS = 1;", or better yet, just declare it with a default value "reg SS = 1;", doesn't this happen instantly at power up, not even waiting for a clock? Maybe I've been overthinking this one.
I'm only worrying about outputting data at the moment. I'll deal with receiving data from the slave another time. To get 12 steps, I need a 4-bit register that counts from 0000 to 1011 in binary:
The "always" block needs to clock on the SPI clock and not on the system clock:
This should only cause things to happen when there is data to send. At the moment, I'm just going to clock a byte out if I push the SW5 switch on the board. I'll have that set the "data_ready_flag" and I'll surround the following code with an "if" statement as follows:
Next, I want to do different things based on where I am in the shift counter. At zero, I'll set the chip select low; at 0001, I'll send the SPI clock out the "SCLK" line. I have an enable ("SPIclkEn") and, elsewhere, I AND this with the SPI clock ("assign SCLKio = SCLK & SPIclkEn;"), thereby allowing me to control when the clock is going out to the slave. I also need to have the MSB (most significant bit) ready for when the clock next goes high:
I now need to clock the data out until the LSB (least-significant bit) has been transmitted. The above two "ifs" have performed slightly different actions, while the next seven will perform the same action as follows:
At this point the data byte has been transmitted. Now I need to shut off the clock, set the slave select high again, and reset the "shiftCount" register as follows:
All of this ended up being only a 10-step process. Maybe I'll need a few more when I receive data as well. The next step is to use the ChipScope virtual logic analyzer to take a look at the signals and see what I'm missing and where. I've included all of my source code, in this ZIP file on the off-chance you'd like to take a look at it and provide more before I get to that step.