EmbDev.net

Forum: FPGA, VHDL & Verilog Addressing many registers


Author: SparkyT (Guest)
Posted on:

Rate this post
0 useful
not useful
Hi,

i have a question for whoever has the time.
I am writing a vhdl module to interface an IC through SPI.
The main functionality of the module is a FSM, using a few counters and 
looping whenever is needed.
The IC to interface, requires a lot of writing to registers for 
configuration, and then some writing and reading for normal operation, 
all through SPI.

For example, i need to configure 30 something internal IC registers, to 
get the IC ready for operation. So my FSM will loop 30 something times, 
while incrementing a counter to keep track.

I am using a combinational proccess, where the counter above, selects 
the correct SPI instruction, address and data to either read or write.

I am wondering if there is a better way for selecting SPI instruction, 
address and data, because the combinational process becomes very quickly 
too long.

Thank you in advance

Author: Lothar Miller (lkmiller) (Moderator)
Posted on:

Rate this post
0 useful
not useful
SparkyT wrote:
> I am wondering if there is a better way for selecting SPI instruction,
> address and data, because the combinational process becomes very quickly
> too long.
Use a RAM(ROM) and initialize it with the intitializing sequence...
Look at this LCD controller: 
http://www.mikrocontroller.net/attachment/90798/LCD_CTRL.vhd
In it is a RAM which is used in double way: first it contains the 
sequence to initialize the display, after initialisation it contains the 
characters to be displayed...

> So my FSM will loop 30 something times, while incrementing a counter to
> keep track.
You do not have to jump back to the very beginning of your "loop"...

Author: berndl (Guest)
Posted on:

Rate this post
0 useful
not useful
SparkyT wrote:
> I am writing a vhdl module to interface an IC through SPI.
> The main functionality of the module is a FSM, using a few counters and
> looping whenever is needed.

oops, what do you mean with 'looping'?

> The IC to interface, requires a lot of writing to registers for
> configuration,

so, you have an SPI interface (most likely an SPI slave?) which receives 
data via SPI, collects all bits together, and then presents you a e.g. 
32bit register with a 'write-strobe' to your logic? If the cycletime of 
the solution is too slow, you could easily pipeline this write operation 
into your config-registers...

> and then some writing

same as above

> and reading for normal operation,
> all through SPI.

now it gets interesting! Do you have a in-frame SPI protocoll or a 
out-of-frame SPI protocoll? And what's the cycletime of the SPI, how is 
the address to be read passed via SPI to your logic?

>
> For example, i need to configure 30 something internal IC registers, to
> get the IC ready for operation. So my FSM will loop 30 something times,
> while incrementing a counter to keep track.

i simply have no idea what you are stating above... Without the .vhdl 
files i can't even grasp what you are doing...

>
> I am using a combinational proccess, where the counter above, selects
> the correct SPI instruction, address and data to either read or write.
>
> I am wondering if there is a better way for selecting SPI instruction,
> address and data, because the combinational process becomes very quickly
> too long.

without having a clear description what you want to do (not based on 
your non-working solution, just the problem!) and the requirements in 
case of timing, latency, ... i think no one can give you an idea...

Lothar already mentioned embedded RAMs for data storage. Is this an 
option for you? At least for some of the registers?

Author: SparkyT (Guest)
Posted on:

Rate this post
0 useful
not useful
Hi again,
very interesting points, and i agree my description is not the best.
The FPGA will be the SPI master, and the IC is the SPI slave.

Let me just say that speed is not critical, i am way over some limits.
I just want to make my code simpler and more readable.

About looping, my fsm has about 30-35 states (so far). The first 5 are 
the config loop, where each loop iteration configures a single register 
on the SPI slave. After 30 times (configuring 29 registers, and 
inquiring the state of the slave) i enter on the 6th state where i am in 
normal operation.
But,
the combinational process is already too long, and i haven't even 
started  enquiring the slave in normal operation.

I will also look into ROM (the fpga has embedded), as i need data to be 
there even after power-down.

here is the begining on the combinational process.
obviously the "config_count" is the counter incremented by the fsm, to 
give appropriate data to the SPI link.

decode:process (config_count, norm_count, send_can, sel_heart,CAN_DATA_TX,node_count) 
begin
  -- default value
  instruction <= (others => '0');                
  addr_byte  <= (others => '0');                
  data_byte  <= (others => '0');
  data_byte1  <= (others => '0');

  case config_count is      
      
    when "000000" =>             
      instruction <= reset_inst;  
         
    when "000001" =>             
      instruction <= write_inst;               
      addr_byte  <= x"2A";  
      data_byte  <= "01001100";  -- TODO    

    when "000010" =>
      instruction <= write_inst;               
      addr_byte  <= x"29";    
      data_byte  <= "11001100";  -- TODO       

    when "000011" =>
      instruction <= write_inst;               
      addr_byte  <= x"28";
      data_byte  <= "10101010";  -- TODO          
 
    when "000100" =>
      instruction <= write_inst;               
      addr_byte  <= x"20";    
      data_byte  <= x"FF";          

    when "000101" =>
      instruction <= write_inst;               
      addr_byte  <= x"21";    
      data_byte  <= x"FF";    

    when "000110" =>
      instruction <= write_inst;               
      addr_byte  <= x"00";  
      data_byte  <= x"FF";   

    when "000111" =>
      instruction <= write_inst;               
      addr_byte  <= x"01";  
      data_byte  <= x"FF";    

    when "001000" =>
      instruction <= write_inst;               
      addr_byte  <= x"04";  
      data_byte  <= x"FF";   

    when "001001" =>
      instruction <= write_inst;               
      addr_byte  <= x"05";  
      data_byte  <= x"FF";    --   (TODO)

    when "001010" =>
      instruction <= write_inst;               
      addr_byte  <= x"24";    
      data_byte  <= x"FF";      

Author: SparkyT (Guest)
Posted on:

Rate this post
0 useful
not useful
By the way, i am using the SPI master from this website, very nice....

Author: Lothar Miller (lkmiller) (Moderator)
Posted on:

Rate this post
0 useful
not useful
SparkyT wrote:
> About looping, my fsm has about 30-35 states (so far).
This is the ideal use for a RAM. Make config_count as an integer and 
use it as the adress to read the addr_byte and data_byte from the 
RAM in a way like that:
-- define the RAM
type ram_t is array (0 to 31) of std_logic_vector(15 downto 0); -- addr_byte + data_byte  
-- init the RAM
signal ram : ram_t := ( x"2A4C",
                        x"29CC",
                        ...
                        others => x"00000"
                       );

-- access the RAM
   addr_byte <= ram(config_count)(15 downto 8);
   data_byte <= ram(config_count)(7 downto 0);


SparkyT wrote:
> By the way, i am using the SPI master from this website
Where is "this"?

Author: SparkyT (Guest)
Posted on:

Rate this post
0 useful
not useful

Author: SparkyT (Guest)
Posted on:

Rate this post
0 useful
not useful
Hi again,
thanks for the pointers, i am using your ram.

I have a question for the SPI-master above.
Is this the right place to ask?

Author: Lothar Miller (lkmiller) (Moderator)
Posted on:

Rate this post
0 useful
not useful
SparkyT wrote:
> I have a question for the SPI-master above. Is this the right place to
> ask?
Why not? Go on.

Author: SparkyT (Guest)
Posted on:

Rate this post
0 useful
not useful
i was wondering how to adjust the SPI-master to a variable length SPI 
tranfer. I need to interface an IC where i have SPI instructions that 
are 1 byte long, 3 bytes long and 4 bytes long. The IC will always reply 
on the third byte of the SPI variable transfer.

I have managed to change (well, trying) the example above, but keeping 
the exact same logic. (repeating the sequence of the states, but 
spi_bitcounter is not a generic. Its set every time according to need)
I have one Receive shift register (8bits), that registers MISO, and my 
FSM knows when its the third byte, to read.
I have 3  Transmit shift registers used as follows,
-- 'tx_reg1' is 8 bits,  used for 1 Byte SPI TRANSFER
-- 'tx_reg3' is 24 bits, used for 3 Bytes SPI TRANSFER
-- 'tx_reg4' is 32 bits, used for 4 Bytes SPI TRANSFER
The FSM knows what SPI length is needed for communication, and uses the 
apropriate tx_regx.

So far, so good. Simulations look ok, waiting for the hardware to start 
testing. But the FSM  has 49 states. I can already see some redudant 
ones, that i will try to remove.
I guess the SPI-master example is your work. Very nice VHDL coding. So, 
my question is how would you go about changing it to a variable length?

Author: Legacy My (Company: my) (legacy)
Posted on:

Rate this post
0 useful
not useful
SparkyT wrote:
> http://www.lothar-miller.de/s9y/categories/45-SPI-Master

pretty code, very useful for me, too
thank you for it!

Author: SparkyT (Guest)
Posted on:

Rate this post
0 useful
not useful
I was thinking something like this.

need this input
SEL_SPI  : in  STD_LOGIC_VECTOR (2 downto 0); 

make the spi count up to the max possible size (remove generic)
signal bitcounter    : integer range 0 to 32;   

then the fsm state is like this
  case spitxstate is
       when spi_stx =>
             SS          <= '1';             -- slave select disabled
             TX_Done     <= '0';
             spiclk      <= '0';             -- SPI-Mode 0
    case SEL_SPI is
      when "001" =>
        bitcounter  <= 8;
      when "010" =>
        bitcounter  <= 16;
      when "011" =>
        bitcounter  <= 24;
      when "100" =>
        bitcounter  <= 32;
      when others =>
        bitcounter  <= 0;
    end case;
             if(TX_Start = '1') then 
                spitxstate <= spi_txactive; 
                SS         <= '0';
                delay      <= clock_delay; 
             end if;

and finally use the multiple txreg
    case SEL_SPI is
-- ONE BYTE SPI TRANSFER -------------------------------------------------------
      when "001" =>
             if (spitxstate=spi_stx) then             -- Reset if the SS inactive
                tx_reg1 <= TX_Data(7 downto 0);
             end if;
            if (spiclk='0' and  spiclklast='1') then         -- SPI-Mode 0
                tx_reg1 <= tx_reg1(tx_reg1'left-1 downto 0) & tx_reg1(0);
             end if;
      MOSI    <= tx_reg1(tx_reg1'left);
      tx_reg2 <= (others => '0');
      tx_reg3 <= (others => '0');
      tx_reg4 <= (others => '0');
-- TWO BYTES SPI TRANSFER -------------------------------------------------------
      when "010" =>
             if (spitxstate=spi_stx) then             -- Reset if the SS inactive
                tx_reg2 <= TX_Data(15 downto 0);
             end if;
            if (spiclk='0' and  spiclklast='1') then         -- SPI-Mode 0
                tx_reg2 <= tx_reg2(tx_reg2'left-1 downto 0) & tx_reg2(0);
             end if;
      MOSI    <= tx_reg2(tx_reg2'left);
      tx_reg1 <= (others => '0');
      tx_reg3 <= (others => '0');
      tx_reg4 <= (others => '0');
-- THREE BYTES SPI TRANSFER -------------------------------------------------------
      when "011" =>
             if (spitxstate=spi_stx) then             -- Reset if the SS inactive
                tx_reg3 <= TX_Data(23 downto 0);
             end if;
            if (spiclk='0' and  spiclklast='1') then         -- SPI-Mode 0
                tx_reg3 <= tx_reg3(tx_reg3'left-1 downto 0) & tx_reg3(0);
             end if;
      MOSI    <= tx_reg3(tx_reg3'left);
      tx_reg1 <= (others => '0');
      tx_reg2 <= (others => '0');
      tx_reg4 <= (others => '0');
-- FOUR BYTES SPI TRANSFER -------------------------------------------------------
      when "100" =>
             if (spitxstate=spi_stx) then             -- Reset if the SS inactive
                tx_reg4 <= TX_Data;
             end if;
            if (spiclk='0' and  spiclklast='1') then         -- SPI-Mode 0
                tx_reg4 <= tx_reg4(tx_reg4'left-1 downto 0) & tx_reg4(0);
             end if;
      MOSI    <= tx_reg4(tx_reg4'left);
      tx_reg1 <= (others => '0');
      tx_reg2 <= (others => '0');
      tx_reg3 <= (others => '0');
--------------------------------------------------------------------------------
      when others =>
        tx_reg1 <= (others => '0');
        tx_reg3 <= (others => '0');
        tx_reg4 <= (others => '0');
        MOSI <= '0';
    end case;

What about this?

Author: Lothar Miller (lkmiller) (Moderator)
Posted on:

Rate this post
0 useful
not useful
SparkyT wrote:
> What about this?
Seems far to difficult. There is no need to have one 8 bit, one 16 bit 
and one 32 bit SPI. I would configure only one SPI engine as an 32 bit 
SPI (as you did). In that 32 bit register I would place the shorter 8 
and 16 bit words to the correct place and then start a transmission with 
the length of the bitcounter.

Michael Fischer did this already. You can find his adaption at the 
bottom of the page: http://www.emb4fun.de/fpga/components/index.html

Author: SparkyT (Guest)
Posted on:

Rate this post
0 useful
not useful
thanks for the tips

Reply

Entering an e-mail address is optional. If you want to receive reply notifications by e-mail, please log in.

Rules — please read before posting

  • Post long source code as attachment, not in the text
  • Posting advertisements is forbidden.

Formatting options

  • [c]C code[/c]
  • [avrasm]AVR assembler code[/avrasm]
  • [vhdl]VHDL code[/vhdl]
  • [code]code in other languages, ASCII drawings[/code]
  • [math]formula (LaTeX syntax)[/math]




Bild automatisch verkleinern, falls nötig
Note: the original post is older than 6 months. Please don't ask any new questions in this thread, but start a new one.