Monday, April 4, 2011

Building an SPI controller... (part 4)

To pump data onto the bus we are going to use the master/slave mode and the logical signals from the previous module to pump data from an internal buffer onto the correct line (MISO or MOSI).  Since we are not restricted to a given number of bits but most of the devices tend to need transfers of less than 64 bits I am making the buffer 64 bits wide. 

This buffer size is completely arbitrary and could be any size and still function correctly.  The number of bits to transfer from the buffer is passed as well as a pair of lines to indicate when transfers should begin and when all the needed bits have been sent.  By making this buffer larger, there is less overhead on the flag pairs (and by making it smaller there is more overhead)...

For a fixed application this type of module isn't needed but it makes the other modules easier to maintain.  Since I am controlling the MISO and MOSI lines here (tristated) it made sense to include a buffer.


  always @ (posedge clock) begin  
      if (reset) begin
         xmt_busy            <= 1'b0;  
         xmt_ack             <= 1'b0;
         xmt_counter         <= 6'b000000; 
      end      
      else if (!reset) begin
         if (send_intent && !xmt_ack && !xmt_busy) begin
            // setup initial transmit counter and sig
            xmt_busy           <= 1'b1;
            xmt_counter        <= transferbits;  
         end
         else if (!send_intent & xmt_ack) begin
            // clear signal
            xmt_busy <= 1'b0;      
            xmt_ack  <= 1'b0;
         end
         if (send_intent && busdetect_writenow && xmt_busy) begin
            if (!slave) begin
               spi_mosi_write <= xmt_buffer[xmt_counter];              
            end                                            
            else if (slave) begin
               spi_miso_write <= xmt_buffer[xmt_counter];    
            end 
            if (xmt_counter == 6'b000000) begin
               // sent last we need to so finish
               xmt_busy <= 1'b0;     
               xmt_ack  <= 1'b1;       
            end
            else if (xmt_counter > 0) begin
               xmt_counter <= xmt_counter - 1;
            end
         end // conditions to write
      end // not in reset
   end // write handler
 As usual, all of the full verilog files can be found here.