Перейти к содержанию
    

Реализация SPI на VHDL.

Привет Всем!

Есть модуль SPI со входным CLK = 40 МГц и шинами данных, запросов записи-чтения и прочим. Тактовая SPI не больше 1.5 МГц. Данные идут по

16 бит. Т.е. за один цикл обмена я, и получаю адрес внутреннего регистра и записываю/читаю данные 8-битного регистра. Поэтому у меня в машине состояния

есть обращения в регистры по середине обмена (естественно на 40 МГц) и для этого есть подсчет сколько бит получено/ отправлено.

Собственно, синтезатор ругается/информирует на сигналы выделения фронтов, спадов - он их посчитал тактовыми

+---------------------+--------------+------+------+------------+-------------+
|        Clock Net    |   Resource   |Locked|Fanout|Net Skew(ns)|Max Delay(ns)|
+---------------------+--------------+------+------+------------+-------------+
|               s_CLK |         Local|      |  275 |  0.047     |  0.117      |
+---------------------+--------------+------+------+------------+-------------+
|Inst_SPI_7v0/fall_ed |              |      |      |            |             |
|                  ge |         Local|      |   19 |  0.010     |  1.699      |
+---------------------+--------------+------+------+------------+-------------+
|Inst_SPI_7v0/rise_ed |              |      |      |            |             |
|                  ge |         Local|      |    6 |  0.098     |  1.842      |
+---------------------+--------------+------+------+------------+-------------+

s_sck1 <= SCK;
process(CLK, RESET)
    begin    
        if (rising_edge (CLK)) then 
            if RESET = '1' then 
                s_sck2 <= '1';
                s_sck3 <= '1';                
                state <= IDLE;
            else
                s_sck2 <= s_sck1;
                s_sck3 <= s_sck2;                
                state <= state_next;        
                -- .......
                fall_edge <= (not s_sck2) and s_sck3;
                rise_edge <= s_sck2 and (not s_sck3);    
            end if;
        end if;
    end process;

    process (fall_edge, rise_edge, state)
    begin
        if state /= IDLE then
            if rising_edge (rise_edge) then
                rise_counter <= rise_counter + 1;
            end if;    
            if rising_edge (fall_edge) then
                fall_counter <= fall_counter + 1;
            end if;
        else
            fall_counter <= (others => '0');
            rise_counter <= (others => '0');
        end if;
    end process;

Регистры fall_counter и rise_counter сбрасываются в машине состояния по IDLE.

Вопрос - что здесь не правильно?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

второй процесс, вы как раз от них и тактируетесь

if rising_edge (rise_edge) then
               rise_counter <= rise_counter + 1;
           end if;    
           if rising_edge (fall_edge) then
               fall_counter <= fall_counter + 1;
           end if;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо за ответ. Тогда проистекает вопрос, если приращение счетчиков "загнать" в один процесс - будет ли эквивалентно? Т.e.

        s_sck1 <= SCK;
    process(CLK, RESET)
    begin    
        if (rising_edge (CLK)) then 
            if RESET = '1' then 
                s_sck2 <= '1';
                s_sck3 <= '1';                
                state <= IDLE;
            else
                s_sck2 <= s_sck1;
                s_sck3 <= s_sck2;                
                state <= state_next;                        
                if (not s_sck2) and s_sck3 then
                                            fall_counter <= fall_counter + 1;
                                end if;
                if s_sck2 and (not s_sck3) then
                                            rise_counter <= rise_counter + 1;    
                                end if;
            end if;
        end if;
    end process;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Привет Всем!

Есть модуль SPI со входным CLK = 40 МГц и шинами данных, запросов записи-чтения и прочим. Тактовая SPI не больше 1.5 МГц. Вопрос - что здесь не правильно?

 

Вообще, все контроллеры связи, как то SPI, UART и пр. удобно делать из нескольких автоматов.

На самом нижнем уровне автомат оперирует только с битами: выделяет фронты под системную тактовую, убирает дребезг и пр.

Потом, "над ним" делается автомат, который оперирует уже байтами или словами или кадрами. Этот автомат от нижнего получает сигнал готовности бита и сам бит, а наверх отдает свою готовность и принятое слово, кадр данных и т.д...

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

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

А вообще SPI - где только не описывался. И а аппликухах, и на открытых проектах, и в учебных программмах..

Если будут проблемы, то посмотрите у меня на сайте в статьях, "Краткий Курс", там я об этом писал подробно...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

  process (fall_edge, rise_edge, state)
    begin
        if state /= IDLE then
            if rising_edge (rise_edge) then

 

- В список чувствительности включайте клок и резет, если юзаете асинхронный резет

- Для автоматов удобно использовать case

- Сигналы фронтов считывайте тем же клоком, которым их формируете.

 

Всякий раз, когда вы пишите новый if rising_edge() от нового сигнала, то вводите новый клоковый домен (сам страдал этим). В данной ситуации это совершенно лишнее.

 

Лучше писать так

process (clk) begin
        if rising_edge(clk) then
                      case (state) is
                     when idle => if (rising_edge='1') then....

 

Про разделение протокола на иерархии сказали совершенно правильно. Сам делал SPI следующим образом

 

- Один блок ловит фронты и спады SCK и выдает тычки. И все.

- Другой блок задвигается данные из MOSI в регистр и выдвигает данные в MISO из другого (другой был нужен да) принимая тычки предыдущего блока. Он не смотрит на сигнал SCK и на содержание данных в шине.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо. Я ориентировался на образец проектирования у Pong Chu - там он делит на два модуля , автомат состояния и выходная логика. Буду читать про иерархические модули.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...