On 5/27/06, Timothy Miller <[EMAIL PROTECTED]> wrote:
For my part, I downloaded the docs for the SPI PROM, read them, drew
some diagrams, etc. Now that I have it pretty much figured out, I'd
like to code it up.
Well, I guess since no one else wants to take the lead on some of
this, I'll get started.
The SPI protocol is quite simple. You control a clock signal SCK.
You stream out some bits on the falling edge of SCK (so that the prom
can take them on the rising edge), and then, if you're going to get
anything back, you stream them back in on the rising edge of SCK
(because the prom puts them out on the falling edge).
So, for a chip erase, you stream out 32 bits and then stop. For a
byte write, you stream out 40 bits.
Reads create a slight complication in that the last address bit is
sampled by the prom on the rising edge of a particular cycle of SCK,
and then it puts out the first data bit in the falling edge of the
SAME CLOCK CYCLE.
You may have noticed that the protocol is byte-oriented. Everything
is done in 8-bit chunks. So, I first though about designing one state
machine (with associated shift registers) that would handle 8-bit
chunks. On top of that, I would put another state machine that would
control the high-level byte stuff. The problem with two-level
machines like this is that they're impossible to debug--it's very hard
to keep track of causality in the waveform viewer, at least for me.
Besides, we're dealing with something that doesn't have to run that
fast, so I figure we'll shoot for something rather flat. Also, I
think we can play fast and loose with the protocol a bit, simplifying
the machine.
So, first thing's first. When a write is requested, we load a shift
register with the 40 bits of data and then start clocking it out:
reg [39:0] ck_out_data;
reg [6:0] bit_counter;
always @(posedge clock or negedge reset_) begin
if (reset_ == 0) begin
// reset stuff
end else begin
if (!busy) begin
if (do_write) begin
ck_out_data <= {write_cmd, write_addr, write_byte};
bit_counter <= 40;
busy <= 1;
end
end else begin
{SI, ck_out_data[39:1]} <= ck_out_data;
bit_counter <= bit_counter - 1;
if (bit_counter == 2) busy <= 0;
end
end
end
What's missing is getting the SCK and CE_ timings right. We'll use a
DDR output buffer for the SCK. For writes, the timing of CE_ isn't
critical, but SCK is. For reads, the timing of CE_ is more critical.
We're going to play a trick with reads. For the shift-in buffer, it
doesn't matter if we shift in garbage before the right time (as long
as we stop at the right time), and it probably doesn't matter if we
shift out garbage when the command address are done. So, here's the
basic idea:
reg [39:0] ck_out_data;
reg [31:0] ck_in_data;
reg [6:0] bit_counter;
always @(posedge clock or negedge reset_) begin
if (reset_ == 0) begin
// reset stuff
end else begin
if (!busy) begin
if (do_read) begin
ck_out_data <= {write_cmd, write_addr, 8'b0};
bit_counter <= 32+32; // It might be 32+31
busy <= 1;
CE_ <= 0; // right time or one cycle later??
end
end else begin
{SI, ck_out_data[39:1]} <= ck_out_data;
ck_in_data <= {SO, ck_in_data[31:1]};
bit_counter <= bit_counter - 1;
if (bit_counter == 2) busy <= 0;
if (bit_counter == 1) CE_ <= 1; // Is this the right time?
end
end
end
A few other things we have to work out:
The idea behind (bit_counter == 2) is that on the next cycle (when the
counter is 1), the machine will accept another command. So the
counter never reaches zero. Zero means that it's idle. Otherwise, it
goes from 1 straight to 40 or whatever. Check me on that. Also, that
means that my else arrangement isn't right. It should be more like:
if (counter != 0) begin
// shifting stuff
end
if (!busy) begin
// accept command
end
The other thing is when CE_ goes away for reads. We need to figure
that out. And also how many clock cycles. It's like the last address
cycle and the first data cycle are shared (maybe), so we'd need one
less cycle. I'd have to draw it out to be sure.
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)