alex1985 0 24 июля, 2018 Опубликовано 24 июля, 2018 · Жалоба Доброго дня всем! Есть модуль ПИ-регулятора, проект собирается на cyclone III, таймквест ругается, выдает слаки. Код: module pid ( input clk, input use_pid, //Если 1 - включается ПИД-регулятор, иначе выдаем pwm_cur = pwm_fixed input [24:0] pwm_fixed, //Фиксированное значение ШИМ (используется при use_pid=0) input start_pulse, //Импульс начала вычислений input [11:0] ADC_REF, //АЦП уставки, max: 4096 (12 bit) input [11:0] ADC_FAKT, //АЦП фактическое, max: 4096 (12 bit) input [15:0] Ki, //Интегральный коэффициент input [15:0] Kp, //Пропорциональный коэффициент input [24:0] pwm_min, //Минимальная граница ШИМ input [24:0] pwm_max, //Макчимальная граница ШИМ output reg [24:0] pwm_cur, //Выходное значение ШИМ output reg is_pwm_max, //Если 1 - то ШИМ максимальный output end_pulse //Импульс окончания вычислений ); reg signed [25:0] I_reg; reg signed [26:0] F_reg; reg signed [24:0] I_prev_reg; reg [24:0] pwm_fixed_reg; reg [1:0] F_limits_reg; reg [1:0] I_limits_reg; reg [11:0] adc_ref_reg; reg [11:0] adc_fakt_reg; reg signed [12:0] err_reg; reg [9:0] Kp_reg; reg [9:0] Ki_reg; initial begin I_prev_reg = 25'd1000; is_pwm_max = 0; pwm_cur = 0; end wire [1:0] w_F_limits; wire [1:0] w_I_limits; wire signed [25:0] w_I; wire signed [23:0] w_P; wire signed [26:0] w_F; wire signed [12:0] w_err; wire w_start_pulse2; wire w_start_pulse3; wire w_start_pulse4; wire w_start_pulse5; wire w_start_pulse6; //--------------------------------- // PID-calculating //--------------------------------- assign w_err =$signed({1'b0, ADC_REF}) - $signed({1'b0, ADC_FAKT}); //max: 13 bit assign w_I = use_pid? ($signed({1'b0, Ki_reg}) * err_reg + I_prev_reg) : ($signed({1'b0, pwm_fixed_reg})); //max: (10+1) * 13 + 25 = 26 bit assign w_P = $signed({1'b0, Kp_reg}) * err_reg; //max: (10+1) * 13 = 24 bit assign w_F = use_pid? (w_I + w_P) : ($signed({1'b0, pwm_fixed_reg})); //max: 26 + 24 = 27 bit; assign w_F_limits[0] = (w_F < $signed({1'b0, pwm_min}))? 1'b1 : 1'b0; assign w_F_limits[1] = (w_F > $signed({1'b0, pwm_max}))? 1'b1 : 1'b0; assign w_I_limits[0] = (w_I < $signed({1'b0, pwm_min}))? 1'b1 : 1'b0; assign w_I_limits[1] = (w_I > $signed({1'b0, pwm_max}))? 1'b1 : 1'b0; //============================================ delay delay1(.in(start_pulse), .clk(clk), .out(w_start_pulse2)); delay delay2(.in(w_start_pulse2), .clk(clk), .out(w_start_pulse3)); delay delay3(.in(w_start_pulse3), .clk(clk), .out(w_start_pulse4)); delay delay4(.in(w_start_pulse4), .clk(clk), .out(w_start_pulse5)); delay delay5(.in(w_start_pulse5), .clk(clk), .out(w_start_pulse6)); delay delay6(.in(w_start_pulse6), .clk(clk), .out(end_pulse)); //============================================ always @ (posedge clk) begin //======================================== // Начало вычислений, захватываем входные данные //======================================== if (start_pulse) begin Ki_reg = Ki[9:0]; Kp_reg = Kp[9:0]; err_reg <= w_err; pwm_fixed_reg <= pwm_fixed; end //======================================== // Даем 3 такта на вычисления, помещаем результат в регистры //======================================== else if (w_start_pulse4) begin I_reg <= w_I; F_reg <= w_F; I_limits_reg <= w_I_limits; F_limits_reg <= w_F_limits; end //======================================== // Выдаем результат, учитывая ограничения //======================================== else if (w_start_pulse5) begin //Ограничиваем выходное воздействие case (F_limits_reg) 2'b01: begin pwm_cur <= pwm_min; is_pwm_max <= 0; end 2'b10: begin pwm_cur <= pwm_max; is_pwm_max <= 1; end default: begin pwm_cur <= F_reg[24:0]; is_pwm_max <= 0; end endcase //Ограничиваем интегральную составляющую case (I_limits_reg) 2'b01: I_prev_reg <= pwm_min; 2'b10: I_prev_reg <= pwm_max; default: I_prev_reg <= I_reg[24:0]; endcase end end //============================================ endmodule Модуль delay: module delay #(parameter WIDTH = 1) ( input [WIDTH-1:0] in, input clk, output reg [WIDTH-1:0] out ); always @(posedge clk) out <= in; endmodule Идея такова: в момент прихода стартового импульса (start_pulse) происходит захват входных значений в регистры, цепочка из элементов delay производит задержку входного сигнала на 6 тактов для того, чтобы вся эта "колбаса" успела посчитаться к моменту выдачи импульса завершения (end_pulse). Таймквест выдает ошибки: Но регистр err_reg захватывается на 3 такта раньше чем производится вычисление F_reg, неужели 3 такта недостаточно для умножения? Файл констрейнов: derive_clock_uncertainty create_clock -name clk -period 36.1MHz [get_ports {clk}] create_generated_clock -name clk_216MHz -source [get_ports {clk}] -multiply_by 6 [get_nets {pll_ena_inst1|pll1|altpll_component|auto_generated|wire_pll1_clk[0]}] create_generated_clock -name clk_adc -source [get_ports {clk}] -divide_by 17 -multiply_by 15 [get_nets {pll_ena_inst1|pll1|altpll_component|auto_generated|wire_pll1_clk[1]}] set_false_path -from pll_ena_inst1|pll1|altpll_component|auto_generated|pll1|clk[1] -to adc_inst:adc_inst1|sync:sync_adc|sync[0] Какие констрейны прописать для устранения ошибок? Заранее спасибо! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
nice_vladi 1 24 июля, 2018 Опубликовано 24 июля, 2018 · Жалоба delay delay1(.in(start_pulse), .clk(clk), .out(w_start_pulse2)); delay delay2(.in(w_start_pulse2), .clk(clk), .out(w_start_pulse3)); delay delay3(.in(w_start_pulse3), .clk(clk), .out(w_start_pulse4)); delay delay4(.in(w_start_pulse4), .clk(clk), .out(w_start_pulse5)); delay delay5(.in(w_start_pulse5), .clk(clk), .out(w_start_pulse6)); delay delay6(.in(w_start_pulse6), .clk(clk), .out(end_pulse)); Вот это прям сильно) Зачем на такую простую операцию столько модулей? На мой взгляд - лишняя писанина... все это можно заменить парой строк: reg [4:0] shft_reg; shft_reg <= shft_reg << 1 | start_pulse; // либо shft_reg <= {shft_reg[3:0], start_pulse}; /*мне так больше нравится*/ И, если сильно хочется, можно этот сдвиговый регистр утащить в отдельный модуль. При таком описании в качестве сигналов разрешения (w_start_pulsе...) будут использоваться биты сдвигового регистра (shft_reg[...]). Но регистр err_reg захватывается на 3 такта раньше чем производится вычисление F_reg, неужели 3 такта недостаточно для умножения? Не понятно, как компилятор развел умножители - возможно, и не хватает. Я бы попробовал утащить в симуляцию и там посмотреть-отладить. А так же для умножения пользовал бы корки от производителя. Их использование хотя бы гарантирует, что компилятор разведет блоки так, как вы зададите в настройках этой корки (пайплайны и все такое). derive_clock_uncertainty create_clock -name clk -period 36.1MHz [get_ports {clk}] create_generated_clock -name clk_216MHz -source [get_ports {clk}] -multiply_by 6 [get_nets {pll_ena_inst1|pll1|altpll_component|auto_generated|wire_pll1_clk[0]}] create_generated_clock -name clk_adc -source [get_ports {clk}] -divide_by 17 -multiply_by 15 [get_nets {pll_ena_inst1|pll1|altpll_component|auto_generated|wire_pll1_clk[1]}] set_false_path -from pll_ena_inst1|pll1|altpll_component|auto_generated|pll1|clk[1] -to adc_inst:adc_inst1|sync:sync_adc|sync[0] Я бы описал входные клоки (опорные): create_clock -name clk -period 36.1MHz [get_ports {clk}] И потом командой создаются все клоки PLL: derive_pll_clocks Для удобства и красоты им можно присвоить имена: set clk_216MHz pll_ena_inst1|pll1|altpll_component|auto_generated|pll1|clk[0] set clk_adc pll_ena_inst1|pll1|altpll_component|auto_generated|pll1|clk[1] А еще стоит открыть handbook на вашу модель циклона и посмотреть, сколько максимальная частота работы умножителей. Может быть, они не умеют в 216 МГц. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 24 июля, 2018 Опубликовано 24 июля, 2018 · Жалоба Особо в код не вникал, но если у вас данные меняются каждые 3 такта - то для того, чтобы подсказать это синтезатору обычно применяют мультициклы: set_multicycle_path Ибо по-умолчанию анализатор считает что данные меняются каждый такт. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 25 июля, 2018 Опубликовано 25 июля, 2018 · Жалоба TC, если интересно може посмотреть описание на vhdl, правда Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 26 июля, 2018 Опубликовано 26 июля, 2018 · Жалоба Еще чуть добавлю. Очень неплохо было бы если бы автор темы сообщал решил ли он проблему или нет. И как он решил возникшую проблему. Ведь форум - это не только место где могут помочь, подсказать и дать пинка в верном направлении, но также это хорошая база знаний, где можно найти решение проблемы, если она встречалась ранее ;) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alex1985 0 27 июля, 2018 Опубликовано 27 июля, 2018 · Жалоба Спасибо за оперативные ответы! Извиняюсь, что пишу так поздно. Проблема была в невыставленном set_multicycle_path. Я почему то полагал, что TimeQuest чуть умнее и сам додумается, т.к. вычисления разнесены по цепочке D-триггеров, но как выяснилось - нужно все прописывать самому. Пришлось добавить целую портянку кода: set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|F_reg[*]} -setup -end 4 set_multicycle_path -from {pid:pid1|Ki_reg[*]} -to {pid:pid1|F_reg[*]} -setup -end 4 set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|F_limits_reg[0]_OTERM3} -setup -end 4 set_multicycle_path -from {pid:pid1|Ki_reg[*]} -to {pid:pid1|F_limits_reg[0]_OTERM3} -setup -end 4 set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|F_limits_reg[0]_OTERM5} -setup -end 4 set_multicycle_path -from {pid:pid1|Ki_reg[*]} -to {pid:pid1|F_limits_reg[0]_OTERM5} -setup -end 4 set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|F_reg[24]_OTERM217} -setup -end 4 set_multicycle_path -from {pid:pid1|Ki_reg[*]} -to {pid:pid1|F_reg[24]_OTERM217} -setup -end 4 set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|F_reg[*]_OTERM235} -setup -end 4 set_multicycle_path -from {pid:pid1|Ki_reg[*]} -to {pid:pid1|F_reg[*]_OTERM235} -setup -end 4 set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|F_limits_reg[0]_OTERM7_OTERM153_OTERM223_OTERM251} -setup -end 4 set_multicycle_path -from {pid:pid1|Ki_reg[*]} -to {pid:pid1|F_limits_reg[0]_OTERM7_OTERM153_OTERM223_OTERM251} -setup -end 4 set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|F_limits_reg[0]_OTERM7_OTERM155_OTERM221_OTERM239_OTERM299} -setup -end 4 set_multicycle_path -from {pid:pid1|Ki_reg[*]} -to {pid:pid1|F_limits_reg[0]_OTERM7_OTERM155_OTERM221_OTERM239_OTERM299} -setup -end 4 set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|F_reg[*]_OTERM281} -setup -end 4 set_multicycle_path -from {pid:pid1|Ki_reg[*]} -to {pid:pid1|F_reg[*]_OTERM281} -setup -end 4 set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|F_reg[*]_OTERM287} -setup -end 4 set_multicycle_path -from {pid:pid1|Ki_reg[*]} -to {pid:pid1|F_reg[*]_OTERM287} -setup -end 4 set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|F_reg[*]_OTERM291} -setup -end 4 set_multicycle_path -from {pid:pid1|Ki_reg[*]} -to {pid:pid1|F_reg[*]_OTERM291} -setup -end 4 set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|F_reg[*]_OTERM295} -setup -end 4 set_multicycle_path -from {pid:pid1|Ki_reg[*]} -to {pid:pid1|F_reg[*]_OTERM295} -setup -end 4 set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|I_limits_reg[0]_OTERM13_OTERM215_OTERM233_OTERM275} -setup -end 4 set_multicycle_path -from {pid:pid1|Ki_reg[*]} -to {pid:pid1|I_limits_reg[0]_OTERM13_OTERM215_OTERM233_OTERM275} -setup -end 4 set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|F_limits_reg[0]_OTERM7_OTERM149_OTERM227_OTERM247_OTERM307} -setup -end 4 set_multicycle_path -from {pid:pid1|Ki_reg[*]} -to {pid:pid1|F_limits_reg[0]_OTERM7_OTERM149_OTERM227_OTERM247_OTERM307} -setup -end 4 set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|F_limits_reg[0]_OTERM7_OTERM149_OTERM227_OTERM245_OTERM303} -setup -end 4 set_multicycle_path -from {pid:pid1|Ki_reg[*]} -to {pid:pid1|F_limits_reg[0]_OTERM7_OTERM149_OTERM227_OTERM245_OTERM303} -setup -end 4 set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|F_reg[12]_OTERM325} -setup -end 4 set_multicycle_path -from {pid:pid1|Ki_reg[*]} -to {pid:pid1|F_reg[12]_OTERM325} -setup -end 4 set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|I_limits_reg[0]_OTERM13_OTERM215_OTERM233_OTERM273} -setup -end 4 set_multicycle_path -from {pid:pid1|Ki_reg[*]} -to {pid:pid1|I_limits_reg[0]_OTERM13_OTERM215_OTERM233_OTERM273} -setup -end 4 Ситуация выправилась, но осталась куча слаков по Hold, вот один из них: Если я правильно понимаю, то Hold time (th) - это время, которое сигнал должен удерживаться после фронта clk приёмника. Как понимать эту диаграмму? Данные (Data Arrival) пришли раньше фронта Latch clock, что не так? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alex1985 0 30 июля, 2018 Опубликовано 30 июля, 2018 · Жалоба Задам вопрос по другому. Есть 1 общий клок и цепочка D-триггеров: В момент прихода импульса на первый триггер (1) в регистры заносятся некоторые данные, например err_reg[]. Далее с ними проводятся манипуляции (сложение/умножение/сравнение) и к моменту поступления импульса на шестой триггер (6) берется результат (F_limits_reg[]). Периодичность поступления импульсов на цепочку триггеров намного больше 6. Как правильно описать данный констрейн с помощью set_multicycle_path? Делаю так: set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|F_limits_reg[*]*} -setup -end 6 На картинке снизу изображения временного отчета по setup(слева) и hold(справа). По setup все более-менее понятно: мы указываем когда защелкиваются данные, соответственно сами данные должны прибыть ДО Latch-фронта. А вот с hold не знаю что делать, смысл его для меня пока загадка. Из каких соображений определяется констрейн для hold? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alex1985 0 30 июля, 2018 Опубликовано 30 июля, 2018 · Жалоба Вобщем посмотрел Time-report простейшей цепи и сделал вывод: setup и hold отстают друг от друга на один такт. В моем случае - та же простейшая цепь с одним клоком, просто данные захватываются с задержкой в 6 тактов. Поставил hold-time на 1 меньше setup и варнинги пропали. Осталось легкое недопонимание относительно hold( set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|I_limits_reg[*]*} -hold -end 6 set_multicycle_path -from {pid:pid1|err_reg[*]} -to {pid:pid1|I_limits_reg[*]*} -setup -end 7 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_sda 0 30 июля, 2018 Опубликовано 30 июля, 2018 · Жалоба Всё правильно, разница в один такт должна быть.Здесь смотрели? Multicycles_explained_v1.0.pdf Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alex1985 0 31 июля, 2018 Опубликовано 31 июля, 2018 · Жалоба _Anatoliy, спасибо большое! :beer: Посмотрю обязательно! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alex1985 0 3 августа, 2018 Опубликовано 3 августа, 2018 · Жалоба Спасибо всем, кто принимал участие в обсуждении! Все получилось, остался один вопрос: при компиляции проекта выдается ограничение по частоте в 200Мгц: Где именно ограничивается минимальный период и можно ли это поправить? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 3 августа, 2018 Опубликовано 3 августа, 2018 · Жалоба Спасибо всем, кто принимал участие в обсуждении! Все получилось, остался один вопрос: при компиляции проекта выдается ограничение по частоте в 200Мгц: Где именно ограничивается минимальный период и можно ли это поправить? Лучше читать описание к микросхеме. Тут у Вас либо ограничение клокового дерева, либо применяется какой-то блок, который имеет ограничение в 200 Mhz. Например, очень частым блоком, ограничивающим максимальную частоту является блок памяти. Первая цифра максимальной частоты в проекте (Fmax) - это максимальная теоретическая частота для конкретного проекта на конкретной FPGA без учёта ограничений на спец блоки, и клоковое дерево. Вторая цифра (restricted Fmax - максимальная частота с учетом ограничения на спец блоки и клоковое дерево). Приведу простой пример: если создать небольшой сдвиговый регистр на триггерах, у него Fmax может показать под 800 Mhz. Но restricted Fmax будет например 400 Мгц. Т.е триггеры могли бы и на 800 Мгц щелкать. Но клоковое дерево выше 400 Мгц через себя не пропустит. Иными словами: максимальная частота проекта - это меньшее из этих значений (Fmax и restricted Fmax). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alex1985 0 3 августа, 2018 Опубликовано 3 августа, 2018 · Жалоба Лучше читать описание к микросхеме. Тут у Вас либо ограничение клокового дерева, либо применяется какой-то блок, который имеет ограничение в 200 Mhz. Например, очень частым блоком, ограничивающим максимальную частоту является блок памяти. Первая цифра максимальной частоты в проекте (Fmax) - это максимальная теоретическая частота для конкретного проекта на конкретной FPGA без учёта ограничений на спец блоки, и клоковое дерево. Вторая цифра (restricted Fmax - максимальная частота с учетом ограничения на спец блоки и клоковое дерево). Иосиф Григорьевич, спасибо! Все ясно и понятно! Тему можно считать закрытой. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 4 августа, 2018 Опубликовано 4 августа, 2018 · Жалоба Иосиф Григорьевич, спасибо! Все ясно и понятно! Тему можно считать закрытой. Вы меня перепутали с многоуважаемым iosifk :biggrin: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alex1985 0 5 августа, 2018 Опубликовано 5 августа, 2018 · Жалоба Вы меня перепутали с многоуважаемым iosifk :biggrin:Прошу прощения :laughing: Но за советы все равно спасибо! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться