verilog - SPI slave doesn't work when I follow the spec, does when I don't? -


i wrote spi slave in verilog. there implementations out there, still learning verilog , digital logic in general, , decided i'd try write on own.

my implementation works. had make change work, , making change (i think) puts implementation @ odds motorola spi spec. i'm wondering: right in thinking strange, or not understand how works?

the spi signals come in on 4 wires called sck, ss, mosi, , miso. no surprise there. fpga running @ 12mhz , spi bus running @ 1mhz. strategy sample bus spi bus on every fpga clock posedge , keep track of both current , last value sck , ss can detect edges. pass each signal through buffer reg. logic operating 2 fpga clocks behind actual events: on clock 1, latch signal in buffer; on clock 2, copy reg use logic, , on clock 3, act upon it.

i'm using spi mode 0. according spi spec, in mode 0, slave should sample mosi line on posedge of sck , transmit on negedge of sck.

so wrote way:

reg [511:0] data; // exchange 512-bit messages master.  reg [2:0] sck_buffer = 0; @(posedge clock) begin // clock fpga clock     sck_buffer <= {sck_buffer[1:0], sck}; end  wire sck_posedge = sck_buffer[2:1] == 2'b01; wire sck_negedge = sck_buffer[2:1] == 2'b10;  reg [2:0] ss_buffer = 0; @(posedge clock) begin     ss_buffer <= {ss_buffer[1:0], ss}; end wire ss_posedge = ss_buffer[2:1] == 2'b01; wire ss_negedge = ss_buffer[2:1] == 2'b10; wire ss_active = ~ss_buffer[1];  reg [1:0] mosi_buffer = 0; @(posedge clock) begin     mosi_buffer = {mosi_buffer[0], mosi}; end wire mosi_in = mosi_buffer[1];       assign miso = data[511];  @(posedge clock) begin      if (ss_active) begin         if (sck_posedge) begin             // clock goes high: capture 1 bit mosi.             mosi_capture <= mosi_in;         end         else if (sck_negedge) begin             // shift captured mosi bit lsb of data , output              // msb data.  note: miso wire outputs data[511].             data <= {data[510:0], mosi_capture};         end     end end 

the code should work this:

  1. when ss goes active (low), data[511] output on miso virtue of wire. (no tristate here because i'm thing on bus.)
  2. on posedge of sck, slave samples mosi, , master gets data[511] on miso.
  3. on negedge of sck, slave shifts bit sampled mosi data, causing new bit shift miso output position.

when ran version, dropped bits on place. literally half of 512-bit messages sent master slave wound corrupted.

i looked @ open-source spi slave implementation , noticed didn't use negedge of sck. changed code this:

always @(posedge clock) begin      if (ss_active) begin         if (sck_posedge) begin             // skip "capture" business , shift mosi right             // data reg.             data <= {data[510:0], mosi_in};         end     end end 

after making change, worked perfectly. totally bulletproof.

but i'm thinking, huh?

i okay. miso gets new value after posedge of sck, , it's still there on next posedge, when master samples it. wrong changing miso on negedge? though i'm running 2 fpga cycles behind spi bus due buffering, still have 12 fpga clocks every 1 tick of sck, means have 6 fpga cycles between sck negedge , next posedge. should able bit out there on miso in time, right?

in practice (in spi mode 0) update miso right after sck posedge , not worry negedge?

thanks!

i think may confused master doing. mosi gets new value after posedge of sck, , it's still there on next posedge, when master samples it. presumably mean when slave samples it, general idea reader samples on other clock edge 1 generated data, maximise setup , hold. think, in case, master should producing data on falling edge of sck, not rising edge.

in case, first thing have datasheet master device , find out it's meant doing. ideally, should scope on sclk, mosi, , ss, , find out actual master timing is. find out when master changes mosi, , mosi setup , hold sclk edge (either pos or neg) is.

your code doesn't sample mosi on sck rising edge, , second version doesn't sample on falling edge. samples somewhere near edge. problem you've got separate synchronisers on sck , mosi (and ss). generally, recipe failure, might or might not work in case, depending on specific timings. think way. if you're right, , "mosi gets new value after posedge of sck", there's long setup , short hold on mosi, , sampling fail because, time you've seen high value on sck (up 84ns after happened), mosi has changed , invalid.

the right way sample mosi (and possibly ss) on f/f clocked sck, , use small digital pll lock sck, know when read sampler output. if understand timing, , you've got huge setup , hold on you're sampling, can instead sample sck you're doing. in case, don't need synchros on mosi , ss; create enable signal sample them when they're known stable.


Comments

Popular posts from this blog

ios - UICollectionView Self Sizing Cells with Auto Layout -

node.js - ldapjs - write after end error -

DOM Manipulation in Wordpress (and elsewhere) using php -