roboforum.ru

Технический форум по робототехнике.

FPGA - Vhdl

Программирование микроконтроллеров AVR, PIC, ARM.
Разработка и изготовление печатных плат для модулей.

FPGA - Vhdl

Сообщение milkpower » 20 дек 2011, 12:49

Отдельного раздела нет, кину сюда вдруг кому пригодится.
Понемногу изучаю vhdl, и выложу некоторые наработки, если вдруг есть знатоки, вносите коррективы, только рад.

Подключение PSX-контроллера в режиме digital или RED-mode

Код: Выделить всёРазвернуть
-- PSX_Ctrl.vhd
-- Play Station Controller  digital and analog Red Mode

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

Entity PSX_Ctrl is

port(
   Clk   : in  std_logic;   -- System Clock 50 MHz
   PSX_Data : in  std_logic;   -- Data from Pad
   PSX_cmd   : out std_logic;   -- Commands to Pad
   PSX_ATT   : out std_logic;   -- Signal Attention to Pad
   PSX_Clk   : out   std_logic;   -- Clock to pad
   PSX_ACK   : in  std_logic;   -- ACK
   PSX_OK   : out   std_logic;   -- Pad connected
   PSX_Red   : out   std_logic;   -- Pad in RED Mode
   
                        -- Bit0 Bit1 Bit2 Bit3 Bit4 Bit5 Bit6 Bit7
   Buttons1 : out std_logic_vector (7 downto 0); -- SLCT JOYR JOYL STRT UP   RGHT DOWN LEFT
   Buttons2 : out std_logic_vector (7 downto 0); -- L2   R2   L1   R1   /\   O    X    |_|
   Rjoy_X   : out std_logic_vector (7 downto 0);  -- Right Joy 0x00 = Left  0xFF = Right
   Rjoy_Y   : out std_logic_vector (7 downto 0);  -- Right Joy 0x00 = Up    0xFF = Down
   Ljoy_X   : out std_logic_vector (7 downto 0);  -- Left Joy  0x00 = Left  0xFF = Right
   Ljoy_Y   : out std_logic_vector (7 downto 0)   -- Left Joy  0x00 = Up    0xFF = Down
   
);
end PSX_Ctrl;

Architecture ARCH of PSX_Ctrl is
constant ClkDiv:       integer := 100; -- 250kHz      50000000/250000/2
constant int_div:      integer :=5000; -- 50Hz       250000/5000
constant Att_div01:   integer :=4;
constant Att_div02:   integer :=Att_div01+9;
constant Att_div03:   integer :=Att_div02+6;
constant Att_div04:   integer :=Att_div03+9;
constant Att_div05:   integer :=Att_div04+6;
constant Att_div06:   integer :=Att_div05+9;
constant Att_div07:   integer :=Att_div06+5;
constant Att_div08:   integer :=Att_div07+9;
constant Att_div09:   integer :=Att_div08+5;
constant Att_div10:   integer :=Att_div09+9;
constant Att_div11:   integer :=Att_div10+5;
constant Att_div12:   integer :=Att_div11+9;
constant Att_div13:   integer :=Att_div12+5;
constant Att_div14:   integer :=Att_div13+9;
constant Att_div15:   integer :=Att_div14+5;
constant Att_div16:   integer :=Att_div15+9;
constant Att_div17:   integer :=Att_div16+5;
constant Att_div18:   integer :=Att_div17+9;
constant Att_div:      integer :=Att_div18+4;

constant   Data_init:   std_logic_vector (7 downto 0) := "00000001";
constant   Data_secd:   std_logic_vector (7 downto 0) := "01000010";

signal    ClkCount:   std_logic_vector (7 downto 0) := (others => '0');
signal    intrCount:   std_logic_vector (15 downto 0) := (others => '0');
signal    ClkTick:    std_logic := '0';
signal    Clk_en:     std_logic :='1';
signal    Clk_s:        std_logic :='1';
signal    ATT_s:        std_logic :='1';
signal    CMD_s:        std_logic :='1';
signal    PSX_OK_s:        std_logic :='0';
signal    PSX_RED_s:        std_logic :='0';
signal    Att_count:   std_logic_vector (7 downto 0) := (others => '0');
signal   Data_in   :   std_logic_vector (7 downto 0) := "00000000";
signal   byte_1   :   std_logic_vector (7 downto 0) := "00000000";
signal   byte_2   :   std_logic_vector (7 downto 0) := "00000000";
signal   byte_3   :   std_logic_vector (7 downto 0) := "00000000";
signal   byte_4   :   std_logic_vector (7 downto 0) := "00000000";
signal   byte_5   :   std_logic_vector (7 downto 0) := "00000000";
signal   byte_6   :   std_logic_vector (7 downto 0) := "00000000";
signal   step_byte:   integer range 0 to 7 :=0;
signal   Dcount:      integer range 0 to 7 :=0;

begin

PSX_ATT<=ATT_s;
PSX_Clk<=not(Clk_s and Clktick);
PSX_cmd<=CMD_s;
PSX_OK<=PSX_OK_s;
PSX_RED<=PSX_RED_s;

a: process (Clk)
begin
   if Clk='1' and Clk'event then
      if ClkCount = ClkDiv then
         ClkTick <= Not Clktick;
         ClkCount <= (others => '0');
      else
         ClkCount <= ClkCount + 1;
      end if;
   end if;
end process;

b: process (clkTick)
begin
   if ClkTick='1' and ClkTick'event then
      if intrcount <=Att_div then
         Att_s <='0';
      else
         Att_s <='1';
      end if;
      if intrcount >att_div01 and intrcount <att_div02 then
         Clk_s <='1';
         Cmd_s <=data_init(Dcount);
         Dcount <=Dcount+1;
      else
      --1
         if intrcount >att_div03 and intrcount <att_div04 then
            Clk_s <='1';
            Cmd_s <=data_secd(Dcount);
            Dcount <=Dcount+1;
         else
         --2
            if intrcount >att_div05 and intrcount <att_div06 then
               Clk_s <='1';
               Cmd_s <='0';
            else
            --3
               if intrcount >att_div07 and intrcount <att_div08 then
                  Clk_s <='1';
                  Cmd_s <='0';
               else
               --4
                  if intrcount >att_div09 and intrcount <att_div10 then
                     Clk_s <='1';
                     Cmd_s <='0';
                  else
                  --5   
                     if intrcount >att_div11 and intrcount <att_div12 then
                        Clk_s <='1';
                        Cmd_s <='0';
                     else
                     --6
                        if intrcount >att_div13 and intrcount <att_div14 then
                           Clk_s <='1';
                           Cmd_s <='0';
                        else
                        --7                     
                           if intrcount >att_div15 and intrcount <att_div16 then
                              Clk_s <='1';
                              Cmd_s <='0';
                           else
                           --8
                              if intrcount >att_div17 and intrcount <att_div18 then
                                 Clk_s <='1';
                                 Cmd_s <='0';
                              else
                                 Cmd_s <='1';
                                 Clk_s <='0';                     
                              end if;
                           --8
                           end if;
                           
                        --7
                        end if;
                     --6   
                     end if;
                  --5   
                  end if;
               --4   
               end if;
            --3   
            end if;
         --2
         end if;
      --1
      end if;
      
      if intrcount =int_div then
         intrcount <=(others => '0');
      else
         intrcount <= intrcount+1;
      end if;
   end if;
end process;
   
         
C: process (clkTick)
begin
   if ClkTick='1' and ClkTick'event then
      --1         
         if intrcount >att_div03+1 and intrcount <att_div04+1 then
            data_in(step_byte)<=PSX_data;
            step_byte <=step_byte+1;
         else
         --2
            if intrcount >att_div05+1 and intrcount <att_div06+1 then
               step_byte <=step_byte+1;
            else
            --3
               if intrcount >att_div07+1 and intrcount <att_div08+1 then
                  byte_1(step_byte)<=not PSX_data;
                  step_byte <=step_byte+1;
               else
               --4
                  if intrcount >att_div09+1 and intrcount <att_div10+1 then
                     byte_2(step_byte)<=not PSX_data;
                     step_byte <=step_byte+1;
                  else
                  --5   
                     if intrcount >att_div11+1 and intrcount <att_div12+1 then
                        byte_3(step_byte)<=not PSX_data;
                        step_byte <=step_byte+1;
                     else
                     --6
                        if intrcount >att_div13+1 and intrcount <att_div14+1 then
                           byte_4(step_byte)<=not PSX_data;
                           step_byte <=step_byte+1;
                        else
                        --7
                           if intrcount >att_div15+1 and intrcount <att_div16+1 then
                              byte_5(step_byte)<=not PSX_data;
                              step_byte <=step_byte+1;
                           else
                           --8
                              if intrcount >att_div17+1 and intrcount <att_div17+1 then
                                 byte_6(step_byte)<=not PSX_data;
                                 step_byte <=step_byte+1;
                              else
                                 step_byte <=0;
                                 Buttons1   <=byte_1;
                                 Buttons2   <=byte_2;
                                 Rjoy_X   <=byte_3;
                                 Rjoy_Y   <=byte_4;
                                 Ljoy_X   <=byte_5;
                                 Ljoy_Y   <=byte_6;
                                 if Data_in="01000001" then
                                    PSX_OK_s  <='1';
                                    PSX_RED_s <='0';
                                 else
                                    if Data_in="01110011" then
                                       PSX_OK_s  <='1';
                                       PSX_RED_s <='1';
                                    else
                                       PSX_OK_s  <='0';
                                       PSX_RED_s <='0';
                                    end if;                           
                                 end if;
                              end if;
                           --8
                           end if;
                        --7
                        end if;
                     --6   
                     end if;
                  --5   
                  end if;
               --4   
               end if;
            --3   
            end if;
         --2
         end if;
      --1
      end if;
end process;
      
end ARCH;

Pcx_ctrl.JPG
Pcx_ctrl.JPG (18.52 КиБ) Просмотров: 2311


Сигнал PSX_ACK не используется ввиду особой ненадобности, поэтому можно удалить.

Добавлено спустя 8 минут 40 секунд:
Servo driver
входы
Clk - 50MHz
Enable - включение/выключение выхода
Position - 8 бит значение (128 середина соответственно)


Servo_drv.JPG
Servo_drv.JPG (10.87 КиБ) Просмотров: 2282


Код: Выделить всёРазвернуть
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ServoDriver is
    Port (
      Clk : in STD_LOGIC; -- 50MHz
      Enable: in STD_LOGIC;
      Position : in STD_LOGIC_VECTOR (7 downto 0);
      Servo : out STD_LOGIC
      );
end ServoDriver;

architecture Behavioral of ServoDriver is

constant ClockDiv: integer := 273;

signal ClockTick: std_logic := '0';
signal ClockCount: std_logic_vector (8 downto 0) := (others => '0');

signal PulseCount: std_logic_vector (11 downto 0) := (others => '0');

begin

a: process (Clk)
begin
   if Clk='1' and Clk'event then
      if ClockCount = ClockDiv-2 then
         ClockTick <= '1';
      else
         ClockTick <= '0';
      end if;
      if ClockTick='1' then
         ClockCount <= (others => '0');
      else
         ClockCount <= ClockCount + 1;
      end if;
   end if;
end process;

b: process (Clk)
begin
   if Clk='1' and Clk'event then
      if ClockTick='1' then
         PulseCount <= PulseCount + 1;
      end if;
      if PulseCount < ("0000" & Position+148) then
         Servo <= '1' and Enable;
      else
         Servo <= '0';
      end if;
   end if;
end process;

end Behavioral;


Добавлено спустя 4 минуты 55 секунд:
UART
Этот код позаимствовал где-то в открытом доступе.
Uart.JPG
Uart.JPG (14.16 КиБ) Просмотров: 2286


Код: Выделить всёРазвернуть
----------------------------------------------------------------------
-- UART
-- Ver. 1.0   - 18.06.2004
--           Initial release
--
--
-----------------------------------------------------------------------

library ieee;
   use ieee.Std_Logic_1164.all;   
   use IEEE.STD_LOGIC_UNSIGNED.all; 

entity UART1 is 
    port (   
         CLK            :   in      Std_Logic;                        -- system clk
         RST_N            :   in      Std_Logic;                        -- system reset#
         DataIN         :   in      Std_Logic_Vector(7 downto 0);      -- Data to transmit
         DataOUT         :   out      Std_Logic_Vector(7 downto 0);   -- Recieved data   
         RX_READY         :    out      Std_Logic;                     -- RX buffer data ready
         TX_INT         :   in      Std_Logic;                        -- Data for   TX avaible   
         TX_RD            :   out      Std_Logic;                     -- Data for   TX RD   
         RxD            :    in      Std_Logic;                        -- RX pin
         TxD            :    out    Std_Logic                        -- TX pin
      );
end UART1;
-----------------------------------------------------------------------
-- Architecture for UARTv1
-----------------------------------------------------------------------
architecture UARTArc of UART1 is   

-- UART signals
signal RxClk, TxClk: Std_Logic;   
signal TxBuf: Std_Logic_Vector(7 downto 0); -- transmit buffer
--signal TxBufLoad: Std_Logic;   
signal TxBufEmpty: Std_Logic;
signal Start: Std_Logic;                   -- syncro signal (start bit)       
signal RxBuf: Std_Logic_Vector(7 downto 0); -- recieve buffer
signal tmpRxD: Std_Logic;                  -- RxD buffer register
signal RxReady: Std_Logic;     
signal TXRead: Std_Logic;    
--signal FrameErr: Std_Logic; 
--signal DataErr: Std_Logic;

begin 
   
   ------------------------------------------------------------------
   -- UART implementation                                  
   -- parameters:
   --            format - 1 start bit, 8 data bit, 1 stop bit
   ------------------------------------------------------------------
   
   UART_clk: process(CLK, RST_N)
   variable CntRX: integer range 0 to 27;  -- RX: 115200 BOD Rx (50MHZ_CLK/Speed_BOD/16_Samples)     
   variable CntTX: integer range 0 to 434; -- TX: 115200 BOD Tx (50MHz_CLK/Speed_BOD)
   begin
      if  RST_N='0' then      
         RxClk<='0';
         TxClk<='0';      
         CntRX:=0;   
         CntTX:=0;
      else
         if CLK'event and CLK='1' then   
            CntRX:=CntRX+1; 
            case CntRX is
               when 27 =>   
                  RxClk<='1';
                  CntRX:=0;
               when others =>
                  RxClk<='0';
            end case;   
            CntTX:=CntTX+1;
            case CntTX is
               when 434 =>
                  TxClk<='1';
                  CntTX:=0;
               when others =>
                  TxClk<='0';
            end case;   
         end if;   
      end if;   
   end process UART_clk;        


   UART_Tx: process(CLK, RST_N, TxClk, TxBufEmpty, TX_INT, TXRead) 
   variable TxBitCnt: integer range 0 to 9;
   begin
        if RST_N='0' then
         TxD<='1';
           TxBitCnt:=0;
         TxBuf<=(others=>'0');   
         TxBufEmpty<='1';   
         TXRead<='0';
        else    
         if (CLK'event and CLK='1') then   
            if TXRead='1' then
               TXRead<='0';          
            end if;         
            if (TxBufEmpty='1' and TX_INT='1') then
               TXRead<='1';
               TxBuf(7 downto 0)<=DataIN(7 downto 0);
               TxBufEmpty<='0';
            end if;   
            if (TxClk='1' and TxBufEmpty='0') then
                 case TxBitCnt is
                  when 0 =>
                     TxD<='0';    -- start bit
                     TxBitCnt:=TxBitCnt+1;                         
                  when 1|2|3|4|5|6|7|8 =>
                     TxD<= TxBuf(0);      
                     TxBuf<='1' & TxBuf(7 downto 1);
                     TxBitCnt:=TxBitCnt+1;
                  when 9 =>
                     TxD<='1';   -- stop bit
                     TxBuf<='1' & TxBuf(7 downto 1);
                     TxBitCnt:=0;
                     TxBufEmpty<='1';
               end case;
            end if;   
         end if;   
      end if;
   end process UART_Tx;   
   
   UART_Rx: process(CLK, RST_N, RxClk, RxD)
   variable RxBitCnt: integer range 0 to 10;
   variable RxSampleCnt: integer range 0 to 15;
   begin
         if RST_N='0' then
         RxBitCnt:=0;
         RxSampleCnt:=0;
            Start<='0';
            RxBuf<=(others=>'1');
         RxReady<='0'; 
         tmpRxD<='1';      
         else 
         if (CLK'event and CLK='1') then
            if RxReady='1' then
               RxReady<='0';
            end if;   
                if RxClk='1' then
                   if Start='0' then
                      if RxD='0' then  -- Start bit,
                     RxSampleCnt:=1;
                     RxBitCnt:=0;
                         Start<='1';
                      end if;
                   else   
                  case RxSampleCnt is                   
                         when 8 =>  -- reads the RxD line
                            tmpRxD<=RxD;
                            RxSampleCnt:=RxSampleCnt+1;               
                         when 15 =>
                        RxSampleCnt:=0;
                            case RxBitCnt is
                                 when 0 =>
                              if tmpRxD='1' then -- start bit failed
                                           Start<='0';
                                     else
                                           RxBitCnt:=RxBitCnt+1;      
                                     end if;
                              RxSampleCnt:=RxSampleCnt+1;               
                                 when 1|2|3|4|5|6|7|8 =>
                                     RxBitCnt:=RxBitCnt+1;
                                     RxBuf<= tmpRxD & RxBuf(7 downto 1);   
                                 when 9 =>
                              if tmpRxD='0' then  -- stop bit expected   
                                 RxReady<='0';      
                                     else
                                 RxReady<='1';
                                     end if;
                                     Start<='0';   
                              RxBitCnt:=0;
                                 when others => null;
                            end case;
                         when others =>
                         RxSampleCnt:=RxSampleCnt+1;               
                  end case;   
               end if;
                end if;
          end if;
      end if;   
   end process UART_Rx;   
   
   
   DataOUT(7 downto 0)<=RxBuf(7 downto 0);
   RX_READY<=RxReady;
   TX_RD<=TXRead;
   
end UARTArc;

Аватара пользователя
milkpower
 
Сообщения: 217
Зарегистрирован: 25 мар 2009, 13:57
Откуда: Ростов-на-Дону
ФИО: Виктор

Re: FPGA - Vhdl

Сообщение Strijar » 21 дек 2011, 11:07

Инициализировать состояние регисторов плохой тон. Нужно делать через сигнал сброса - reset. А в UART RX нет защиты от метастабильности. Надо внешний rx пускать через два тригера.
Аватара пользователя
Strijar
 
Сообщения: 664
Зарегистрирован: 28 авг 2006, 17:09
Откуда: Всеволожск (СПб)
прог. языки: С, C++, Python, Lua, VHDL, Verilog, Forth
ФИО: Олег Белоусов

Re: FPGA - Vhdl

Сообщение toshas » 23 дек 2011, 10:13

Strijar писал(а):Инициализировать состояние регисторов плохой тон. Нужно делать через сигнал сброса - reset.

не совсем верно - при конфигурировании fpga прописываются не только связи, но и значения регистров.
если в процессе работы схемы сбрасывать регистр не нужно, только инициализации достаточно.

milkpower писал(а):PSX_Ctrl.vhd

есть два замечания по стилю кодирования -
1. в будущем старайтесь не использовать асинхронные схемы, они могут плохо работать или вообще не работать на частотах выше минимальных.

в часности, это правильно
a: process (Clk)
begin
if Clk='1' and Clk'event then
if ClkCount = ClkDiv then
ClkTick <= Not Clktick;

а вот так делать нельзя (ловить фронт сигнала не являющегося частотой)
b: process (clkTick)
begin
if ClkTick='1' and ClkTick'event then

2. использовать многократно вложенные if не рекомендуется, с каждым новым вложением вы добавляете зарержку в распространение сигнала и теряете в скорости работы,
посмотрите что такое конечные автоматы (FSM - finite state machine) они в данном случае помогут.
Аватара пользователя
toshas
 
Сообщения: 90
Зарегистрирован: 31 янв 2006, 14:37
Откуда: Москва

Re: FPGA - Vhdl

Сообщение milkpower » 23 дек 2011, 15:09

toshas писал(а):а вот так делать нельзя (ловить фронт сигнала не являющегося частотой)
b: process (clkTick)
begin
if ClkTick='1' and ClkTick'event then


дело в том, что это в общем-то и является выходной частотой для джойстика, и я не хотел ставить отдельный делитель перед модулем, а это единственное что пришло мне в голову.

toshas писал(а):2. использовать многократно вложенные if не рекомендуется, с каждым новым вложением вы добавляете зарержку в распространение сигнала и теряете в скорости работы,
посмотрите что такое конечные автоматы (FSM - finite state machine) они в данном случае помогут.

до них еще не дошел, пока темный лес. по хорошему, все собранное время изучения мной vhdl - это в неделю не наберется.
а что касается скорости работы, то в данном случае она совсем не нужна.
а FSM при компиляции займет меньше размер в кристале чем "if...."?
Аватара пользователя
milkpower
 
Сообщения: 217
Зарегистрирован: 25 мар 2009, 13:57
Откуда: Ростов-на-Дону
ФИО: Виктор

Re: FPGA - Vhdl

Сообщение toshas » 23 дек 2011, 15:34

это приводит к тому, что вход синхронизации триггеров внутри плис будет подключен не к клоковой сети, а к обычным трассировочным ресурсам.
это менее стабильно, т.к. сигналы по этим ресурсам распространяются медленнее.
кроме того вы лишаете софт возможности проверить задержки вашей схемы, потому что она перестает быть синхронной.

конечно особая скорость для такой схемы не нужна, но лучше сразу учиться писать правильно.
самое простое - при написании кода сразу спрашивать себя - "а как это ляжет внутри плис ?".
fsm разложиться в триггеры и логику переноса, многочисленные if в очень длиную цепочку таблиц истинности.
Аватара пользователя
toshas
 
Сообщения: 90
Зарегистрирован: 31 янв 2006, 14:37
Откуда: Москва

Re: FPGA - Vhdl

Сообщение Strijar » 23 дек 2011, 21:19

toshas писал(а):
Strijar писал(а):Инициализировать состояние регисторов плохой тон. Нужно делать через сигнал сброса - reset.

не совсем верно - при конфигурировании fpga прописываются не только связи, но и значения регистров.
если в процессе работы схемы сбрасывать регистр не нужно, только инициализации достаточно.


Поэтому я и написал плохой тон ;) Это может порождать ошибки - если одна часть схемы использует сброс, а другая надеется на инициализацию при загрузке
Аватара пользователя
Strijar
 
Сообщения: 664
Зарегистрирован: 28 авг 2006, 17:09
Откуда: Всеволожск (СПб)
прог. языки: С, C++, Python, Lua, VHDL, Verilog, Forth
ФИО: Олег Белоусов


Вернуться в Микроконтроллеры

Кто сейчас на конференции

Сейчас этот форум просматривают: Bing [Bot], GoGo.Ru [Bot] и гости: 0

cron