Приемник RS232 в VHDL не хранит данные правильно, если вообще - PullRequest
0 голосов
/ 08 мая 2019

Я пытаюсь спроектировать приемник rs232 в VHDL: я посылаю числа с помощью скрипта на python, которые он должен перехватить и показать некоторым светодиодам.Я надеюсь, что понял, как работает RS232, и приступил к работе над этим проектом.Дизайн не ведет себя так, как я надеюсь, и мне интересно, может ли кто-нибудь помочь мне определить мои ошибки.

Конечно, я пошел посмотреть, как работает последовательный приемник.Но, как начинающий, я часто чувствую себя подавленным предложенным решением (пример: VHDL RS-232 Receiver"или даже хуже: https://www.nandland.com/vhdl/modules/module-uart-serial-port-rs232.html), мне не хватает словарного запаса и опыта, чтобы понять, что происходиттам.

Я сделал этот дизайн для веб-издания Quartus II: enter image description here

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

с этими двумя файлами: rs232_test

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity rs232_receiver is 
port (
    clock : in std_logic;
    r     : in std_logic;
    reset : in std_logic;
    data  : out std_logic_vector (7 downto 0)
);
end rs232_receiver;

architecture rs232_receiver_arch of rs232_receiver is
    signal data_buffer : std_logic_vector (12 downto 0); 
    signal state : integer; -- 1000 => idle;
begin

    process
    begin
    wait until rising_edge (clock);
        if (reset = '0') then
            if (state = 1000) then
                if (r = '0') then
                    state <= 0; -- startbit as been detected => time to READ !
                end if;
            elsif (state < 13 and state > -1) then
                data_buffer(state) <= r;
                state <= state + 1;
            else
                state <= 1000; -- go back to idle
                data <= data_buffer(7 downto 0);
                data_buffer <= (others => '0');
            end if;
        else
            data_buffer <= (others => '0');
            data <= (others => '0');
            state <= 1000;
        end if;
    end process;
end rs232_receiver_arch;

настройка часов (необработанные часы - 24 МГц, я надеюсь, что, как я сделал этот делитель, выходной сигнал составляет 1200 Гц, то есть яповерьте, скорость передачи 1200).

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity div1000 is 
port (
    clock : in std_logic;
    clockOut : out std_logic
);
end div1000;

architecture div1000_arch of div1000 is
    signal count : integer;
begin

    clockOut <= '1' when count < 10000 else '0';

    process begin
    wait until rising_edge (clock);
        if (count > 19999 or count < 0) then
            count <= 1;
        else
            count <= count + 1;
        end if;
    end process;
end div1000_arch;

Я загружаю число с помощью этого скрипта Python:

# -*- coding: utf-8 -*-
"""
Created on Thu May  2 14:52:12 2019

@author: nathan hj ragot
"""

import time
import serial
import serial.tools.list_ports

print ("hello world !")

#  initialisation des variables
port = ""                                                                      # port choisit
ports = []                                                                     # ports listes

#  recherche et choix du port
print ("merci de rentrer le nom d'un port :")
print ("ps : automatiquement, le script a detecte ces ports :")
print ("**************")

ports = serial.tools.list_ports.comports()
for i in range (len(ports)):
    print ("-> [" + str(i) + "] : " + str (ports[i]))

print ("**************")

port = input("? votre choix :")
print ("ok cool")

# open serial port
ser = serial.Serial(
    port=port,
    baudrate=1200,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_TWO,
    bytesize=serial.EIGHTBITS
)
print(ser.isOpen())

#start writing
ser.write(bytearray([255]))
for i in range(15):
    input("press enter to print " + str(i))
    ser.write (bytearray([i]))

#stop writing
ser.close()

print(ser.isOpen())
print ("bye")

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

1 Ответ

0 голосов
/ 10 мая 2019

Я спросил одного моего учителя, что может быть не так в моем дизайне.Он сказал мне, что: , даже если две тактовые частоты имеют одинаковую частоту, они могут не синхронизироваться , поскольку приемник может попытаться прочитать сигнал, когда передатчик находится слишком близко от его нарастающего или падающего фронта.Поэтому он рекомендовал мне добавить отдельный счетчик, который запускается, когда стартовый бит запускается .это будет действовать как делитель тактовых импульсов, который запускается, когда распадающийся фронт и r = '0' распознаются.

Я взял на себя обязательство переписать код VHDL получателя, чтобы получить это:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity serial_receiver is 
port (
    -- clock is 24 MHz
    clock : in std_logic;
    -- data in at 1200 baud rate
    -- two stop bit
    -- no parity check
    -- byte size at 8
    r     : in std_logic;
    -- packet received
    dataOut : out std_logic_vector (7 downto 0)
);
end serial_receiver;

architecture serial_receiver_arch of serial_receiver is
    -- state of the process :
    --  idle => waiting for start bit
    --      start => waiting THROUGH the start bit
    --      reading => index and storing bits in data buffer
    --      stop => update up data and go back to idle
    type states is (idle, start, reading, stop);
    signal state : states := idle;

    -- clock divider for bit reading, one bit is 16 cycle after first division
    signal counter: integer := 0;
    -- clock divider for process, 1250 divider => clock is now 16*1200 Hz
    signal waiter : integer := 0;
    -- index for incomming data to be store in buffer
    signal index  : integer := 0;
    -- data buffer
    signal data   : std_logic_vector (7 downto 0);
begin

    process begin
        wait until rising_edge(clock);

        --first divider
        if waiter < 1250 then
            waiter <= waiter + 1;
        else
            -- time to run process
            -- reset waiter to restart clock divider
            waiter <= 0;

            -- switch case for state
            case state is
                -- receiver is idle
                when idle =>
                    -- will become ready for start when bit start is received
                    if r = '0' then
                        state <= start;
                        counter <= 0;
                    end if;
                -- receiver is waiting through start bit, doing nothing
                when start =>
                    -- not done yet, counter max must be bigger than 16 to insure not too close from rising_edge
                    if counter < 18 then
                        counter <= counter + 1;
                    else
                    -- done, is getting ready for reading
                        state <= reading;
                        -- counter is set to 16 to immediatly read first bit
                        counter <= 16;
                        index <= 0;
                    end if;
                -- receiver store data inside buffer
                when reading =>
                    -- clock divider to wait until next bit.
                    if counter < 16 then
                        counter <= counter + 1;
                    else
                        -- store bit in buffer if we can
                        if index < 8 then
                            counter <= 0;
                            data(index) <= r;
                            index <= index + 1;
                        else
                        -- if we can't, time to stop
                            counter <= 0;
                            state <= stop;
                        end if;
                    end if;
                -- reading is finnished
                when stop =>
                    -- go back to idle.
                    dataOut <= data;
                    state <= idle;
                    counter <= 0;
            end case;
        end if;
    end process;
end serial_receiver_arch;

VHDL один в дизайне, все остальные объекты больше не присутствуют.

Кажется, сейчас это работает (проверено несколько чисел в диапазоне от 0 до 255) с использованием скрипта Python.Я попытался сделать что-то похожее на ответ @QuantumRipple: VHDL RS-232 Receiver .Поскольку мой код немного отличается, я все еще не уверен, что именно не работало в старом.Я просто предположу, что это вещь синхронизации.Если у кого-то еще есть идея, я открыт для новых знаний.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...