EmbDev.net

Forum: FPGA, VHDL & Verilog Addressing many registers


von SparkyT (Guest)


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

von Lothar M. (lkmiller) (Moderator)


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"...

von berndl (Guest)


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?

von SparkyT (Guest)


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";      

von SparkyT (Guest)


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

von Lothar M. (lkmiller) (Moderator)


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"?

von SparkyT (Guest)


Rate this post
0 useful
not useful

von SparkyT (Guest)


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?

von Lothar M. (lkmiller) (Moderator)


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.

von SparkyT (Guest)


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?

von Legacy M. (Company: my) (legacy)


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!

von SparkyT (Guest)


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?

von Lothar M. (lkmiller) (Moderator)


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

von SparkyT (Guest)


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.