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

Не работает модуль на verilog

Добрый день всем и спасибо за конструктивную критику!

 

Вернул свой первоначальный вариант, немного доработав его (добавил сигнал data_ready)

module spi_slave
(
    input CLK,
    input CS,
    input MOSI,
    input SCK,
    input [15:0] DATA_IN,
    
    output MISO,
    output reg [15:0] DATA_OUT,
    output reg data_ready
);

    reg [15:0]         data_receive_reg;
    reg [15:0]         data_send_reg;
    reg [4:0]          bit_counter;
    reg               miso_reg;

    //============================
    // По спаду CS заносим данные в
    // data_send_reg
    //============================
    always @(negedge CS) 
    begin
        data_send_reg <= DATA_IN;
   end
    
    //============================
    // Если CS=1 - обнуляем bitcounter
    // По фронту SCK заносим данные
    // в регистр data_receive_reg
    //============================
    always @(negedge SCK, posedge CS) 
        if (CS)
            bit_counter <= 4'b00000;
        else    
        begin
            data_receive_reg <= { data_receive_reg[14:0], MOSI };
            bit_counter <= bit_counter + 5'b00001;
        end
            
    //============================        
    // Если CS=1 - обнуляем MISO
    // По фронту SCK выводим данные
    //============================
    always @(posedge SCK, posedge CS, posedge bit_counter[4]) 
        if (CS)
            miso_reg <= 1'b0;
        else if (bit_counter[4])
            miso_reg <= 1'b0;
        else
            miso_reg <= data_send_reg[15-bit_counter];
    assign MISO = miso_reg;        
            
    //============================
    // Синхронизация данных
    //============================
    always @(posedge CLK) 
    begin
        DATA_OUT = data_receive_reg;
        data_ready = (bit_counter[4])? 1'b1 : 1'b0;
    end
    //============================
endmodule

 

Жду конструктивной критики по коду!

 

Теперь немного вопросов:

 

Flip-fl0p советовал работать только от одного клока: у Вас это, как понимаю, clk.

И в списке чувствительности, помимо него, имеет право быть (для проекта комильфо) только, если, конечно, он Вам нужен, ещё асинхронный глобальный сброс.

А у Вас в этих списках зоопарк.

Кстати, боюсь предложить Вам ещё включить (если я правильно помню называние) Design Assistant )))

И пока перестаньте нас радовать Вашим RTL: давайте сначала код вылизывать.

Лучше выкладывайте экран функционального моделирования для этого модуля.

 

1. По фронту clk работать можно, но как быть если частота clk = 36 МГц, а SPI CLK = 21МГц? Останется ли время на выделение фронтов? и обработку state-машин, как советовали Flip-fl0p и iosifk?

2. Для чего вводить сигнал асинхронного глобального сброса? Не совсем понимаю. Для установки триггеров в начальные значения? Каких именно?

3. Не совсем понял фразу "Какой может быть интерес к "RTL-схема", если она потом оптимизируется и от нее мало что останется?". Т.е. при добавлении в проект нового кода RTL-схема уже созданных блоков может быть изменена? Если это так, то как можно это предотвратить? И вообще как можно тогда быть уверенным, что любой идеальный код будет работать так, как это планировалось?

4. По совету AnatolySh поменял настройки вместо временного на функциональное моделирование.

 

Функциональная симуляция:

 

functional.png

 

И RTL:

 

functional.png

 

 

Проект с этим кодом прошил и поставил вчера на тест: с МК отправляю запись данных по адресу 2, затем считываю данные по этому адресу и сверяю с отправленным значением. Далее повторяю процедуру, но по этому же адресу пишу считываю и сверяю уже другие данные. Если данные отправленные и принятые не совпадают - то выставляю флаг ошибки. Пришел сегодня посмотреть результаты - отправлено принято всего 5 300 000 посылок, кол-во ошибок - 0. Результат вполне устраивает.

Но есть узкое место: Т.к. адрес и данные поступают двумя разными SPI-передачами по 16 бит, то в случае помехи по сигналу CS может произойти рассинхронизация в приеме дынных, проще говоря ПЛИС не поймет что пришло данные или адрес. Можно конечно ввести дополнительный сигнал синхронизации, но я думаю поступить по другому - держать CS в нуле на все 32 бита, пропуская последовательно адрес и данные.

Изменено пользователем Sprite

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


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

Добрый день всем и спасибо за конструктивную критику!

 

Вернул свой первоначальный вариант, немного доработав его (добавил сигнал data_ready)

...

 

Я бы постарался отвязаться от работы на внешней тактовой частоте и завел бы внутри ПЛИС свою, с хорошим перетактированием, допустим, 100 МГц. Работать внутри ПЛИС на внешней частоте, асинхронной внутренним частотам ПЛИС - головная боль. Тем более, когда частоты невысокие и не составляет труда с помощью перетактирования затащить данные под внутреннюю частоту ПЛИС.

 

Тогда можно было бы очень просто продетектировать фронты тактовой частоты SPI и по ним (при условии опущенного CS) укладывать данные с шины данных в сдвиговый регистр. А окончание одной посылки отсчитывать флагом заполнения 3битного счетчика (он как раз 8 тактов насчитает).

 

Что-то вроде:

 


if (~CS)             cnt <= cnt + 1'b1;
else                 cnt <= '0;

if (front & ~CS)   shft_reg <= shft_reg << 1 | dat ;

if (&cnt)          rdy_dat <= shft_reg;

 

И писанины меньше, и нагляднее. Ну и да: Questa/ModelSim - маст хев. Без них - никуда. Встроенный симулятор Квартуса - боль.

 

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


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

1. По фронту clk работать можно, но как быть если частота clk = 36 МГц, а SPI CLK = 21МГц? Останется ли время на выделение фронтов? и обработку state-машин, как советовали Flip-fl0p и iosifk?

У вас Cyclone III. Примените один блок PLL...

 

2. Для чего вводить сигнал асинхронного глобального сброса? Не совсем понимаю. Для установки триггеров в начальные значения? Каких именно?

Для Cyclone III можно и без асинхронного глабального сброса. На данном чипе регистры можно принудительно инициализировать нужными значениями. Сделайте правильно без асинхронного сброса сначала...

 

3. Не совсем понял фразу "Какой может быть интерес к "RTL-схема", если она потом оптимизируется и от нее мало что останется?". Т.е. при добавлении в проект нового кода RTL-схема уже созданных блоков может быть изменена? Если это так, то как можно это предотвратить? И вообще как можно тогда быть уверенным, что любой идеальный код будет работать так, как это планировалось?

RTL нужен только для того, чтобы посмотреть иерархию блоков, посмотреть какие блоки куда подключены. Ну и оценить приблизительно соответствует ли схема Вашему ожиданию. Но потом данная схема ложится на логические ячейки FPGA и от того RTL представления практически ничего не остается, т.к САПР всё это добро оптимизирует. Поэтому с точки зрения схемотехники - смотреть на RTL смысла нет.

 

4. По совету AnatolySh поменял настройки вместо временного на функциональное моделирование.

Изучайте Modelsim. Это стандарт де-факто.

 

А вообще Вам уже говорили.

Сначала делайте автомат который принимает биты.

Он занимается только приемом битов.

Потом этот автомат переедает данные другому автомату, который уже обрабатывает слова. И.т.д. Сейчас Вы вернулись к неправильному варианту.

 

Вот есть сигнал SCK.

Вы его для начала пропускаете через цепочку синхронизаторов для подавления метастабильного состояния.

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

Потом выделяете детектором фронта - нужный вам фронт.

И все это работает на системном клоке, который Вы формируете на PLL.

В итоге все синхронные always блоки будут содержать только @(posedge CLK)

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


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

Проект с этим кодом прошил и поставил вчера на тест: с МК отправляю запись данных по адресу 2, затем считываю данные по этому адресу и сверяю с отправленным значением. Далее повторяю процедуру, но по этому же адресу пишу считываю и сверяю уже другие данные. Если данные отправленные и принятые не совпадают - то выставляю флаг ошибки. Пришел сегодня посмотреть результаты - отправлено принято всего 5 300 000 посылок, кол-во ошибок - 0. Результат вполне устраивает.

Про все дела уже написали, но вот есть еще и небольшенькая такая тонкость...

Если дело поставлено именно так: " отправляю запись данных по адресу 2, затем считываю данные по этому адресу и сверяю с отправленным значением", причем без паузы и без выдачи на шину данных другого кода, то вполне возможно, что читаете Вы не содержимое ячеек памяти, а паразитный емкостной заряд на шине... А он конечно всегда будет таким, какой Вы и выставляли на этой шине... :)

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

А если делать по хорошему, то в блок, который открывает шинники ПЛИС по 3-му состоянию, надо сделать задержку на время разряда емкости на линиях. Так хоть будет немного дольше, но ПЛИС будет греться значительно меньше...

 

 

 

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


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

Добрый день всем!

 

Еще одна редакция модуля с учетом исправлений и замечаний:

 

module SPI_slave2
(
    input clk,
    input cs,
    input mosi,
    input sck,
    input [15:0] data_in,
    
    output reg miso = 1'b0,
    output reg [15:0] adr_out = 32'd0,
    output reg [15:0] data_out = 32'd0,
    output reg adr_ready = 1'b0,
    output reg data_ready = 1'b0,
    output wr,
    output [15:0] bitcnt
);

    reg[1:0] sck_reg;
    reg[1:0] mosi_reg;
    reg[5:0] bit_counter;
    reg[15:0] data_send_reg;

    wire sck_risingEdge;
    wire sck_fallingEdge;
    wire mosi_data;

    //---------------------------------
    // Выделяем фронт и спад сигнала sck
    //---------------------------------
    always @(posedge clk) 
    begin
        if(cs)
            sck_reg <= 2'b00;
        else
            sck_reg <= {sck_reg[0], sck};
    end
    assign sck_risingEdge = (sck_reg == 2'b01);
    assign sck_fallingEdge = (sck_reg == 2'b10);

    //---------------------------------
    // Выделяем сигнал mosi
    //---------------------------------
    always @(posedge clk) 
    begin
        if(cs)
            mosi_reg <= 2'b00;
        else
            mosi_reg <= {mosi_reg[0], mosi};
    end
    assign mosi_data = mosi_reg[1];

    //---------------------------------
    // Если cs==1 - очищаем приемный регистр
    // и обнуляем счетчик.
    // Иначе по спаду sck принимаем данные
    // и инкрементируем счетчик.
    //---------------------------------
    always @(posedge clk) 
    begin
        if(cs) 
        begin
            adr_out <= 16'd0;
            data_out <= 16'd0;
            bit_counter <= 6'b000000;
        end
        else if (sck_fallingEdge)
        begin
            if (bit_counter[4])
                data_out <= {data_out[14:0], mosi_data};
            else
                adr_out <= {adr_out[14:0], mosi_data};
            bit_counter <= bit_counter + 6'b000001;
        end
    end

    //---------------------------------
    // Выделяем сигналы готовности адреса и данных
    //---------------------------------
    always @(posedge clk)
    begin
        adr_ready <= (~cs) && (bit_counter[4]);
        data_ready <= (~cs) && (bit_counter[5]);
    end
    //---------------------------------
    // Если cs==1 - заносим в регистр данные для посылки
    // Иначе сдвигаем данные и отправляем побитно
    //---------------------------------
    always @(posedge clk) 
    begin
        if(cs)
        begin
            miso <= 1'b0;
            data_send_reg <= data_in;
        end    
        else if (sck_risingEdge)
        begin
            if (bit_counter[4])
            begin
                miso <= data_send_reg[15];
                data_send_reg <= {data_send_reg[14:0], 1'b0};
            end
        end
    end
    
    assign wr = adr_out[15];
    assign bitcnt = bit_counter;
    
endmodule

По совету nice_vladi и Flip-fl0p поставил pll, умножил частоту на 3 - получил 108Мгц. Провел функциональную симуляцию - все ОК. Частота SPI - 5 МГц, пока выше не поднимал. Итоговый Waveform:

 

functional_6.png

 

В результате появились "слаки"(

 

modelsim.png

 

Насколько это криминально - не знаю.

 

Файл констрейна:

derive_clock_uncertainty
create_clock -name clk -period 36.1MHz [get_ports {clk}]
create_clock -name sck -period 5MHz [get_ports {SCK}]
create_generated_clock -name CLK_108MHz -source [get_ports {clk}] -multiply_by 3 -duty_cycle 50 [get_nets {inst19|altpll_component|auto_generated|wire_pll1_clk[0]}]

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


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

Вы как-то очень избирательно читаете :rolleyes:

PLL поставили - уже хорошо. Работаете только по одному CLK - отлично !

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

Да и простейший фильтр дребезга не мешало бы поставить. Сигналы Вашего SPI относительно FPGA имеют очень пологие фронты. Это надо фильтровать. А то задолбаетесь искать сбои в работе, когда они будут. А они будут будьте уверены :rolleyes:

И да. Я бы не считал линию SCK полноценным клоком. Соответственно из констрейнов его убрать нафиг.

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


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

Смотрите как я делаю:

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

2. У меня отдельный модуль детектора фронтов, где я параметрами задаю тип детектируемого фронта.

Самое главное, что это у меня отдельные модули, которые отлажены и гарантированно работают. И если что-то у меня не работает, то я знаю, что 100% проблема не в них. Тем более, эти модули присутствуют в большинстве проектов. Зачем по 100 раз описывать одно и то же. Да ещё и тестировать их потом ?

 

 

image.png

 

PS. Не претендую на правильность. Но практика показала, что так быстрее и удобнее.

Сначала на бумаге набросал всю схему и все алгоритмы, потом перенес на HDL - более 50% проекта собрал из готовых библиотечных блоков собственной разработки

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


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

Вы как-то очень избирательно читаете :rolleyes:

PLL поставили - уже хорошо. Работаете только по одному CLK - отлично !

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

Да и простейший фильтр дребезга не мешало бы поставить. Сигналы Вашего SPI относительно FPGA имеют очень пологие фронты. Это надо фильтровать. А то задолбаетесь искать сбои в работе, когда они будут. А они будут будьте уверены :rolleyes:

И да. Я бы не считал линию SCK полноценным клоком. Соответственно из констрейнов его убрать нафиг.

 

Синхронизаторы - это хорошо) Подумаю над этим. Если у Вас есть готовый пример фильтра антидребезга - может поделитесь? Насчет SCK - согласен, только я его потому и описывал в констрейне, т.к. надоели всякие варнинги типа "found dedicated clock...".

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


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

Синхронизаторы - это хорошо) Подумаю над этим. Если у Вас есть готовый пример фильтра антидребезга - может поделитесь? Насчет SCK - согласен, только я его потому и описывал в констрейне, т.к. надоели всякие варнинги типа "found dedicated clock...".

Над синхронизаторами не думать надо, а ставить их !

Вот пример фильтра.

http://allaboutfpga.com/wp-content/uploads...gic_circuit.jpg

Можно описать в виде FSM, но мне в виде схемы он понятней. Легко сделать параметризируемым

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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