реклама на сайте
подробности

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> FSM (КА) в VHDL
justontime
сообщение Jun 10 2017, 16:38
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 221
Регистрация: 6-12-14
Из: СПб
Пользователь №: 84 003



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

Процентов 10% - 20% всех передач байта не отрабатывает, как положено - сбрасывается после еще до передачи первого бита... Буду очень благодарен, если кто-то очень умный sm.gif сможет подсказать, что в стиле написания FSM у меня неправильно. Мне кажется, что проблема именно в стиле (а не в конкретной логике - тогда бы, наверное, все работало бы пускай неправильно, но стабильно) - очевидно, я попросил компилятор сделать что-то такое, от чего у него крыша поехала.
Именно из-за подозрения на неправильный стиль (т.е. принципиально неправильный подход) я решился спросить - если бы считал, что ошибка просто в логике, то разбирался бы сам в своих каракулях...

Quartus 16.1 и Cyclone IV

Код
process (clk, rst) begin

if rst = '1' then
    
    state    <= Init;
    
elsif rising_edge(clk) then

    case state is
    
        when Init =>
        
            state    <= WaitStart;
            modeRst    <= '1';
            SPIready    <= '0';
        
        when WaitStart =>
        
            modeRst    <= '0';
        
            if StartCmd = '1' then
        
                state    <= ClkUp;
                MainCnt        <= "111";
                SPIready        <= '0';
                ShiftRegTX     <= BYTEo;
            
                else
                    SPIready    <= '1';
            
            end if;
        
        when ClkUp =>
    
            state        <= ClkDwn;
            SD_CLKi    <= '1';
    
        when ClkDwn =>
        
            SD_CLKi    <= '0';
    
            if MainCnt > 0 then
            
                state                            <= ClkUp;
                MainCnt                        <= MainCnt - 1;
                ShiftRegTX(7 downto 1)    <= ShiftRegTX(6 downto 0);
                ShiftRegRX                     <= ShiftRegRX(5 downto 0) & MISO;
                
                else
                    state        <= WaitStart;
                    DO         <= ShiftRegRX & MISO;
                    SPIready    <= '1';
                    modeRst    <= '1';
            end if;
            
    end case;

end if;

end process;


Еще смущает картинка в FSM viewer - почему-то не показывает переход от ClkDwn до WaitStart - возможно, именно здесь собака порылась...

Прикрепленное изображение


Заранее всем огромное спасибо !

P.S. Небольшое замечание - понятно, что базовых вещей не знаю, но для меня это всего лишь хобби, одно из многих... Еще раз спасибо !
Go to the top of the page
 
+Quote Post
Flip-fl0p
сообщение Jun 10 2017, 17:22
Сообщение #2


Местный
***

Группа: Участник
Сообщений: 391
Регистрация: 11-06-13
Пользователь №: 77 140



Лично я считаю что автомат надо описывать в 3 или 4 процессах.
Так меньше шансов допустить ошибку.
1 Процесс - условие смены состояния автомата.
2 Процесс - Логика выбора следующего состояния автомата
3 Процесс - Комбинаторная часть работы автомата в текущем состоянии
4 Процесс - Синхронная часть работы автомата в текущем состоянии
Ну и не забывайте в CASE описывать все состояния.
У вас ещё осталось огромное количество неописанных состояний автомата.
P.S А перехода в состояние WaitStart может не быть, если счетчик не считает, и оптимизатор выбросил этот переход, как невозможный.
Не претендую на правильность, но вот как я обычно описываю:
CODE

----------------- СБРОС АВТОМАТА, ПЕРЕКЛЮЧЕНИЕ В СЛЕДУЮЩЕЕ СОСТОЯНИЕ -----------------
-- Здесь описывается условие смены состояний автомата
-- И что будет происходить при сигнале сброса
RESET_AND_NEXT_STATE : PROCESS
(
CLKx16
)
BEGIN
IF (RISING_EDGE(CLKx16)) THEN -- По каждому переднему фронту
PRESS_STATE <= NEXT_STATE; -- Меняем состояние автомата на NEXT_STATE
IF (SYNC_RESET = '1') THEN -- Когда сброс в активном уровне
PRESS_STATE <= IDLE; -- Сбрасываем автомат в состояние ожидания
END IF;
END IF;
END PROCESS RESET_AND_NEXT_STATE;

----------------- ЛОГИКА ПЕРЕКЛЮЧЕНИЯ АВТОМАТА -----------------
UART_NEXT_STATE_LOGIC:PROCESS
(
PRESS_STATE,
RX_SYNC,
MAJ_DATA,
BIT_PRD_CNT,
RX_BIT_CNT
)
BEGIN
CASE PRESS_STATE IS -- Анализируем текущее состояние автомата
WHEN IDLE => -- Когда состояние ожидания
NEXT_STATE <= IDLE; -- Зацикливаемся в этом состояниии
IF (RX_SYNC = '0') THEN -- Если на линии найнен лог. 0
NEXT_STATE <= START_BIT; -- Перейдем в состояние проверки старт бита
END IF;

WHEN START_BIT => -- Когда мы в состоянии проверки старт-бита
NEXT_STATE <= START_BIT; -- Зацикливаемся в этом состояниии
CASE BIT_PRD_CNT IS -- Анализиурем счетчик периода бита
WHEN 9 => -- Когда у нас середина битового интервала
IF (MAJ_DATA = '1') THEN -- Если мажоритарная выборка показала что пришла лог. 1
NEXT_STATE <= IDLE; -- Значит скоре всего пришла помеха и вернёмся в состояние ожидания
END IF;
WHEN 14 => -- Если счётчик успел досчитать 15 тактов
NEXT_STATE <= RECEIVE_BIT; -- Значит действительно был старт бит и можно принимать данные от передатчика

WHEN OTHERS => NULL; -- В остальных случаях ничего не делаем
END CASE;

WHEN RECEIVE_BIT => -- Когда автомат в состояние приёма битов
NEXT_STATE <= RECEIVE_BIT; -- Зацикливаемся в этом состояниии
IF (RX_BIT_CNT >= SDB-1) THEN -- Если счётчик приемя битов равен 7 (приинимаем 8 биит)
IF (BIT_PRD_CNT >= 15) THEN -- Если счётчик битового интервала досчитал до конца
NEXT_STATE <= STOP_BIT; -- Значит дальше должен быть стоп бит -> перейдем в состоение приёма стоп бита
END IF;
END IF;

WHEN STOP_BIT => -- Когда мы в состоянии проверки стоп-бита
NEXT_STATE <= STOP_BIT; -- Зацикливаемся в этом состояниии в
IF (BIT_PRD_CNT >= 9) THEN -- Можно сразу после мажорирования
NEXT_STATE <= IDLE; -- Перейти в состояние ожидания
END IF;

WHEN OTHERS =>
NEXT_STATE <= IDLE; -- В остальных случаях ждем старт бита
END CASE;
END PROCESS UART_NEXT_STATE_LOGIC;

------------------- Работа атомата -----------------------------------------------------
RECEIVE_BIT_FROM_UART : PROCESS
(
PRESS_STATE,
BIT_PRD_CNT,
MAJ_DATA
)
BEGIN
------------------- Значения флагов по умолчанию -------------------------------------
DATA_VALID <= '0'; -- Постоянно сбрасываем флаг валидности данных
DATA_ERROR <= '0'; -- Постоянно сбрасываем флаг ошибки приёма данных
RX_BIT_CNT_ENA <= '0';
SHIFT_DATA_ENA <= '0';
BIT_PRD_CNT_SCLR <= '0';
RX_BIT_CNT_SCLR <= '0';
-------------------- Работа автомата --------------------------------------
CASE PRESS_STATE IS -- Анализируем текущее состояние автомата
WHEN IDLE => -- Если у нас состояние ожидания
BIT_PRD_CNT_SCLR <= '1'; -- Счётчики периода бита сбрасывается
RX_BIT_CNT_SCLR <= '1'; -- Счётчики количества принятых бит сбрасывается

WHEN START_BIT => -- Когда проверяем старт бит
IF (BIT_PRD_CNT >= 14) THEN -- Поскольку на 14 такте сбрасыаем счётчик периода бита
BIT_PRD_CNT_SCLR <= '1';
END IF;

WHEN RECEIVE_BIT => -- Когда автомат в состоянии приёма битов
CASE BIT_PRD_CNT IS -- Анализируем состояние счетчика 16 битных интервалов
WHEN 10 => -- Когда счетчик сделал все 3 выборки
SHIFT_DATA_ENA <= '1'; -- Разрешим сдвинем данные в регистре на 1 разряд
WHEN 15 => -- Когда счётчик досчитал до конца битового интервала
RX_BIT_CNT_ENA <= '1'; -- Разрешим счётчику считать
WHEN OTHERS => NULL; -- В остальных случаях ничего не делаем
END CASE;

WHEN STOP_BIT => -- Когда автомат в состоянии проверки стоп бита
CASE BIT_PRD_CNT IS -- Анализируем состояние счетчика 16 битных интервалова
WHEN 10 => -- В середине битового интервала
IF (MAJ_DATA = '0') THEN
DATA_ERROR <= '1';
ELSE
DATA_VALID <= '1';
END IF;
WHEN OTHERS => NULL; -- В остальных случая ничего не делаем
END CASE;
WHEN OTHERS => NULL;
END CASE;
END PROCESS RECEIVE_BIT_FROM_UART;


Сообщение отредактировал Flip-fl0p - Jun 10 2017, 17:34
Go to the top of the page
 
+Quote Post
justontime
сообщение Jun 10 2017, 17:49
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 221
Регистрация: 6-12-14
Из: СПб
Пользователь №: 84 003



Цитата(Flip-fl0p @ Jun 10 2017, 20:22) *
Лично я считаю что автомат надо описывать в 3 или 4 процессах.

Я читал умные книжки и пробовал по разному. В процессе получился вариант "Single process, Single decoder" - от остальных вариантов ум за разум заехал...

Цитата(Flip-fl0p @ Jun 10 2017, 20:22) *
У вас ещё осталось огромное количество неописанных состояний автомата.

Не могли бы указать хотя бы на одно неописанное состояние ? А то я как раз читал об этом, но запутался, что нужно обязательно описывать, а что - нет...

Цитата(Flip-fl0p @ Jun 10 2017, 20:22) *
P.S А перехода в состояние WaitStart может не быть, если счетчик не считает, и оптимизатор выбросил этот переход, как невозможный.

Так вот с толку сбивает, что в большинстве случаев все работает правильно - не просто счетчик считает, а еще у в нужные места переходит, в т.ч. и в WaitStart. Именно это и поставило меня в полный тупик...
Go to the top of the page
 
+Quote Post
Flip-fl0p
сообщение Jun 10 2017, 18:03
Сообщение #4


Местный
***

Группа: Участник
Сообщений: 391
Регистрация: 11-06-13
Пользователь №: 77 140



Применение перечисляемого типа позволяет более удобно описывать состояния автомата. То как он будет кодироваться ONE-HOT, GRAY или пр зависит от синтезатора.
Но в любом варианте существует вероятность свалиться в то, состояние которое у Вас не описано.
Например у вас есть 3 состояния S1, S2, S3. Кодирование ONE-HOT. Физически каждое состояние - это отдельный триггер.
Существует вероятность того, что 2 триггера будут включены в результате ошибки или сбоя. И как следствие автомат зависнет.
Используйте директивы синтезатору, для создания автомата, который сам выходит из невозможных состояний.
Go to the top of the page
 
+Quote Post
justontime
сообщение Jun 10 2017, 18:33
Сообщение #5


Местный
***

Группа: Свой
Сообщений: 221
Регистрация: 6-12-14
Из: СПб
Пользователь №: 84 003



Блин, ну ничего не понимаю... Попробовал переделать на "Two processes, single decoder" - вообще получил миллион предупреждений (Latches, Unsafe behavior и т.д.).
Такой вопрос - а вообще можно счетчик в FSM вставлять так, как я сделал (в самом первом сообщении) ?
Go to the top of the page
 
+Quote Post
Flip-fl0p
сообщение Jun 10 2017, 18:51
Сообщение #6


Местный
***

Группа: Участник
Сообщений: 391
Регистрация: 11-06-13
Пользователь №: 77 140



Цитата(justontime @ Jun 10 2017, 21:33) *
Блин, ну ничего не понимаю... Попробовал переделать на "Two processes, single decoder" - вообще получил миллион предупреждений (Latches, Unsafe behavior и т.д.).
Такой вопрос - а вообще можно счетчик в FSM вставлять так, как я сделал (в самом первом сообщении) ?

При описании FSM LATCH - это частая проблема когда неправильно указана логика переключения состояний. Где-то ошибка.
Go to the top of the page
 
+Quote Post
iosifk
сообщение Jun 10 2017, 19:19
Сообщение #7


Гуру
******

Группа: Модераторы
Сообщений: 3 601
Регистрация: 8-09-05
Из: спб
Пользователь №: 8 369



Цитата(justontime @ Jun 10 2017, 19:38) *
Буду очень благодарен, если кто-то очень умный sm.gif сможет подсказать, что в стиле написания FSM у меня неправильно.
P.S. Небольшое замечание - понятно, что базовых вещей не знаю, но для меня это всего лишь хобби, одно из многих... Еще раз спасибо !


Могу рассказать как надо...
голосом по скайпу...
И еще... Почитайте в "Кратком Курсе" дополнительный раздел про автоматы.


--------------------
www.iosifk.narod.ru
Go to the top of the page
 
+Quote Post
justontime
сообщение Jun 10 2017, 19:31
Сообщение #8


Местный
***

Группа: Свой
Сообщений: 221
Регистрация: 6-12-14
Из: СПб
Пользователь №: 84 003



Цитата(iosifk @ Jun 10 2017, 22:19) *
И еще... Почитайте в "Кратком Курсе" дополнительный раздел про автоматы.

Я столько всего перечитал... И вроде бы, исходя из прочитанного, должно работать. Но при этом также понимаю, что у меня там есть какая-то грубая системная ошибка...
Просто очень тяжело в самом начале, когда нормальной точки опоры еще нет...
Go to the top of the page
 
+Quote Post
iosifk
сообщение Jun 10 2017, 19:38
Сообщение #9


Гуру
******

Группа: Модераторы
Сообщений: 3 601
Регистрация: 8-09-05
Из: спб
Пользователь №: 8 369



Цитата(justontime @ Jun 10 2017, 22:31) *
Я столько всего перечитал... И вроде бы, исходя из прочитанного, должно работать. Но при этом также понимаю, что у меня там есть какая-то грубая системная ошибка...
Просто очень тяжело в самом начале, когда нормальной точки опоры еще нет...

Понятно, что много... Вот только из множества возможных вариантов описания Вы выбрали самый, самый тяжелый. Предложение было сделано, дальше дело Ваше...


--------------------
www.iosifk.narod.ru
Go to the top of the page
 
+Quote Post
dm.pogrebnoy
сообщение Jun 10 2017, 20:09
Сообщение #10


Знающий
****

Группа: Свой
Сообщений: 714
Регистрация: 11-04-07
Пользователь №: 26 933



justontime
Как показывает практика, все сигналы которые входят в синхронный автомат, должны быть синхронными. Иначе возникает метастибальность в абсолютно не очевидных местах. Поэтому проверьте, везде ли есть сихронизаторы. Сигнал MISO, например, также должен быть синхронизированным.


--------------------
Go to the top of the page
 
+Quote Post
justontime
сообщение Jun 10 2017, 20:16
Сообщение #11


Местный
***

Группа: Свой
Сообщений: 221
Регистрация: 6-12-14
Из: СПб
Пользователь №: 84 003



Думаю (скорее, даже уверен), что в данном случае проблема точно не в не-синхронности входных сигналов...
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Jun 13 2017, 06:33
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 4 204
Регистрация: 17-02-06
Пользователь №: 14 454



Цитата
Сигнал MISO, например, также должен быть синхронизированным.

Он должен быть синхронизированн только в очень плохо написанных SPI, в которых работа идет в слейве по основному клоку, а не по клоку SPI. В противном случае гарантированные сетапы и холды выдерживаются протоколом (ну и схемотехникой, конечно).

Если что-то работает стабильно, а временами ломается - проблема не в стиле описания, а в мета-стабильнтости или гонках сигналов.

Как я вижу из описания у вас вроде как SPI мастер на половинной частоте основного клока. Вопросы вызывает сигнал StartCmd - откуда он берется? Если он внешний или с кнопочки то его надо синхронизовать, а то и защитить от дребезга. Потому что огромный шанс что у вас пол автомата переходит в передачу-прием, а половина остается в старом состоянии. Так же имеет смысл проверить разрядности счетчика. Ну и попробовать снизить частоту, может просто реально слишком быстро для вышей платы.

В целом описание популярное, не очень хорошее, но для маленьких автоматов вполне годное.
Go to the top of the page
 
+Quote Post
Flip-fl0p
сообщение Jun 13 2017, 06:49
Сообщение #13


Местный
***

Группа: Участник
Сообщений: 391
Регистрация: 11-06-13
Пользователь №: 77 140



Вот Вам в помощь очень неплохое руководство по написанию FSM : https://electronix.ru/forum/index.php?act=a...st&id=92974
А вот пример совсем кратенький, но от этого не менее информативный https://habrahabr.ru/post/254885/
Go to the top of the page
 
+Quote Post
sqrt(2)
сообщение Jun 13 2017, 09:07
Сообщение #14


Участник
*

Группа: Участник
Сообщений: 65
Регистрация: 20-07-16
Пользователь №: 92 633



В Харрис-Харрис по моему более чем исчерпывающее описание (и словами, и на VHDL - Verilog) как делать КА. Книжка есть даже на русском.

На английском есть хорошая книжка (даже несколько) от некого Pong Chu - там вообще объяснена тема чуть ли для самых маленьких.

http://academic.csuohio.edu/chu_p/rtl/index.html
Go to the top of the page
 
+Quote Post
justontime
сообщение Jun 13 2017, 15:09
Сообщение #15


Местный
***

Группа: Свой
Сообщений: 221
Регистрация: 6-12-14
Из: СПб
Пользователь №: 84 003



Во-первых, как всегда - большое спасибо всем откликнувшимся !

К сожалению, все еще мучаюсь с проблемой...

Насчет чтения книг - проблема в том, что я действительно много прочитал (например, одна из книг упомянутого выше Pong Chu вообще является одной из моих "любимых" по теме). Дело не в том, что я что чувствую общее непонимание темы.
Ровно наоборот - мне кажется, что я все понял (в рамках необходимого), и все сделал правильно, но устройство почему-то не работает... Поэтому мне важно понять, в чем я допустил ошибку именно в этой моей конструкции, а не вообще углублять освоение FSMов/FSMDэмов и т.д.

Исходя из того, что я увидел в SignalTap - такое впечатление, что иногда не загружается счетчик (почему-то с самого начала у меня было подозрение в ту сторону - просто даже в голове сложно представить, как это все синтезируется в "железе").
Понятно, что я буду сейчас смотреть, что там Quartus насинтезировал, но вряд ли это даст мне понимание того, что именно я неправильно сделал в описании этой FSM. Мне ведь важно не просто запустить узел (тем более, в другом виде он у меня давно работает), а понять, что там не правильно, и как сделать правильно.

Насчет сигнала StartCmd - верное предположение, что от него могут быть проблемы. Как минимум, я знаю, что он асинхронный, и приходит без синхронизатора, что уже неправильно. Только, честно говоря, не думаю, что именно в нем проблема:
1. В таком виде это все работает без сбоев в старом узле (согласен, не совсем показательно, схема другая, но вроде именно в том месте очень похожая)
2. Крайне сомневаюсь, что при моих частотах метастабильность может проявляться приблизительно в 10% случаев...

Насчет частоты - ну, для моей платы (DE2-115) 14 МГц для такого узла вряд ли вообще можно назвать частотой... К сожалению, я на некоторое время остался без платы, поэтому сейчас проверить более правильную обработку StartCmd не могу sad.gif

Все-таки мне продолжает казаться, что есть именно системная ошибка - данная FSM в принципе где-то описана в корне неверно. Как уже с самого начала показывал - FSM viewer неправильно показывает диаграмму, что не может не настораживать.
Мало того, когда я вроде бы непринципиально поменял местами два кусочка в районе счетчика (естественно, с изменением проверки его состояния):

Код
if MainCnt = 0 then
                
        state        <= WaitStart;
               DO        <= ShiftRegRX & MISO;
               SPIready    <= '1';
               modeRst    <= '1';
                
                else
                    
                        state            <= ClkUp;
                        MainCnt            <= MainCnt - 1;
                        ShiftRegTX(7 downto 1)    <= ShiftRegTX(6 downto 0);
                        ShiftRegRX            <= ShiftRegRX(5 downto 0) & MISO;
                  
            end if;


Quartus стал понимать мой замысл вроде бы правильно:

Прикрепленное изображение


Тем не менее, работа узла от этого не изменилась вообще...
Go to the top of the page
 
+Quote Post

3 страниц V   1 2 3 >
Reply to this topicStart new topic
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th September 2017 - 14:57
Рейтинг@Mail.ru


Страница сгенерированна за 0.01952 секунд с 7
ELECTRONIX ©2004-2016