|
|
|
Cyclone III, констрейны |
|
|
|
Jul 24 2018, 03:52
|
Частый гость
Группа: Участник
Сообщений: 173
Регистрация: 11-05-08
Пользователь №: 37 414
|
Доброго дня всем! Есть модуль ПИ-регулятора, проект собирается на 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] Какие констрейны прописать для устранения ошибок? Заранее спасибо!
|
|
|
|
|
Jul 24 2018, 04:21
|
Участник
Группа: Участник
Сообщений: 53
Регистрация: 7-09-16
Из: Томск
Пользователь №: 93 239
|
Цитата(Sprite @ Jul 24 2018, 04:52) Код 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 МГц.
|
|
|
|
|
Jul 24 2018, 04:22
|
В поисках себя...
Группа: Свой
Сообщений: 729
Регистрация: 11-06-13
Из: Санкт-Петербург
Пользователь №: 77 140
|
Особо в код не вникал, но если у вас данные меняются каждые 3 такта - то для того, чтобы подсказать это синтезатору обычно применяют мультициклы: Код set_multicycle_path Ибо по-умолчанию анализатор считает что данные меняются каждый такт.
|
|
|
|
|
Jul 27 2018, 03:56
|
Частый гость
Группа: Участник
Сообщений: 173
Регистрация: 11-05-08
Пользователь №: 37 414
|
Спасибо за оперативные ответы! Извиняюсь, что пишу так поздно. Проблема была в невыставленном 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, что не так?
|
|
|
|
|
Jul 30 2018, 10:33
|
Частый гость
Группа: Участник
Сообщений: 173
Регистрация: 11-05-08
Пользователь №: 37 414
|
Задам вопрос по другому. Есть 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?
|
|
|
|
|
Jul 30 2018, 12:19
|
Частый гость
Группа: Участник
Сообщений: 173
Регистрация: 11-05-08
Пользователь №: 37 414
|
Вобщем посмотрел 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
|
|
|
|
|
Aug 3 2018, 03:32
|
Частый гость
Группа: Участник
Сообщений: 173
Регистрация: 11-05-08
Пользователь №: 37 414
|
Спасибо всем, кто принимал участие в обсуждении! Все получилось, остался один вопрос: при компиляции проекта выдается ограничение по частоте в 200Мгц: Где именно ограничивается минимальный период и можно ли это поправить?
|
|
|
|
|
Aug 3 2018, 03:57
|
В поисках себя...
Группа: Свой
Сообщений: 729
Регистрация: 11-06-13
Из: Санкт-Петербург
Пользователь №: 77 140
|
Цитата(Sprite @ Aug 3 2018, 06:32) Спасибо всем, кто принимал участие в обсуждении! Все получилось, остался один вопрос: при компиляции проекта выдается ограничение по частоте в 200Мгц: Где именно ограничивается минимальный период и можно ли это поправить? Лучше читать описание к микросхеме. Тут у Вас либо ограничение клокового дерева, либо применяется какой-то блок, который имеет ограничение в 200 Mhz. Например, очень частым блоком, ограничивающим максимальную частоту является блок памяти. Первая цифра максимальной частоты в проекте (Fmax) - это максимальная теоретическая частота для конкретного проекта на конкретной FPGA без учёта ограничений на спец блоки, и клоковое дерево. Вторая цифра (restricted Fmax - максимальная частота с учетом ограничения на спец блоки и клоковое дерево). Приведу простой пример: если создать небольшой сдвиговый регистр на триггерах, у него Fmax может показать под 800 Mhz. Но restricted Fmax будет например 400 Мгц. Т.е триггеры могли бы и на 800 Мгц щелкать. Но клоковое дерево выше 400 Мгц через себя не пропустит. Иными словами: максимальная частота проекта - это меньшее из этих значений (Fmax и restricted Fmax).
|
|
|
|
|
Aug 3 2018, 12:19
|
Частый гость
Группа: Участник
Сообщений: 173
Регистрация: 11-05-08
Пользователь №: 37 414
|
Цитата(Flip-fl0p @ Aug 3 2018, 10:57) Лучше читать описание к микросхеме. Тут у Вас либо ограничение клокового дерева, либо применяется какой-то блок, который имеет ограничение в 200 Mhz. Например, очень частым блоком, ограничивающим максимальную частоту является блок памяти. Первая цифра максимальной частоты в проекте (Fmax) - это максимальная теоретическая частота для конкретного проекта на конкретной FPGA без учёта ограничений на спец блоки, и клоковое дерево. Вторая цифра (restricted Fmax - максимальная частота с учетом ограничения на спец блоки и клоковое дерево). Иосиф Григорьевич, спасибо! Все ясно и понятно! Тему можно считать закрытой.
|
|
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|