Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Счетчик не справляется
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Работаем с ПЛИС, области применения, выбор
torik
quartus7.2, циклон 2, скорость 7...

Мне необходимо состряпать счетчик адреса, для чтения данных из памяти. Частота - 133МГц. Предварительно на симуляторе проверяю, для чего пишем такой код:

Код
input                ddr_sdram_phy_clk_out;

output        [23:0]    address_0_r;
output        [22:0]    address_0_r_x;

input                read_n;
input                waitrequest;
input                HC_VD;

assign address_0_r[23:1] = address_0_r_x;

count_adr c1        (
                    .clock(ddr_sdram_phy_clk_out),
                    .cnt_en((~read_n)&(~waitrequest)),
                    .data(24'd0),
                    .sload(~HC_VD),
                    .q(address_0_r_x)
                    );


address_0_r просто для того чтобы считать по +2. count_adr - это обычный lpm_count из мегавизарда.

Так вот, когда частота ddr_sdram_phy_clk_out до 100 МГц - все кое-как работает. Это на первом рисунке видать. А вот если ставим частоту 133МГц - уже, судя по всему не справляется - рисунок 2.

Что делать, как по-другому, "правильно", сделать генератор адреса? Да и почему счетчику такая частота не дается?
mse
Может чего не понял, но постарайтесь быть проще
Код
module d22(inclock,ena,outdat);

input    inclock,ena;
output reg [21:0] outdat;


always @(posedge inclock or posedge ena)
    if (ena==1)
    outdat<=outdat;
    else
    outdat<=outdat+1`b1;

endmodule


для Ц2 -8 работает на 7нС цлоцке в симуляторе. Квартус для него пишет
"Info: Clock "inclock" has Internal fmax of 219.88 MHz between source register "outdat[0]~reg0" and destination register "outdat[21]~reg0" (period= 4.548 ns)"

Ежли проблему не так понял, извиняйте. ;О)
sazh
С ассигнованиями как то странно.
C lpm наверно лишнее. Посмотрите

module ct
(
input ddr_sdram_phy_clk_out,
output [23:0] address_0_r,
output [22:0] address_0_r_x,
input read_n,
input waitrequest,
input HC_VD
);


reg [22:0] ct_a;

always @(posedge ddr_sdram_phy_clk_out)
begin
if ((~read_n)&(~waitrequest))
begin
if (~HC_VD) ct_a <= 23'd0;
else ct_a <= ct_a + 1'b1;
end
end

assign address_0_r_x = ct_a;
assign address_0_r = {ct_a, 1'b0};

endmodule
torik
Да, этот LPM я попробовал потому что уже ничего не получалось. Вот сделал все так как сказано в предыдущих двух постах и...
Та же ситуевина, картинки не поменялись. Я сперва так и делал с той разницей, что не оформлял в виде отдельного модуля, теперь оформил.

Может я какие-то назначения не делаю, или что еще? У меня даже строки навроде
Цитата
"Info: Clock "inclock" has Internal fmax of 219.88 MHz between source register "outdat[0]~reg0" and destination register "outdat[21]~reg0" (period= 4.548 ns)"

не имеется

Извиняйте, был невнимателен - строка такая имеется...
mse
Цитата(torik @ Apr 15 2008, 13:15) *
Да, этот LPM я попробовал потому что уже ничего не получалось. Вот сделал все так как сказано в предыдущих двух постах и...

Смотрите внимательно в РТЛ-вьювере. Мож какую аномалию разглядите. В смысле, не ЛПМ-кода.
torik
Блин, выкладываю сам этот простейший проект. Если не лениво гляньте на диаграмки...
mse
Не понял хохмы, но вроде всё пучком...
Квартус(71) заявил, что до 245МГц могло бы работать.
torik
Ну во-первых смотрим - почему первый фронт пропускает? Этого не должно быть по логике, и на 10нс получается по-другому. Во-вторых, это же генератор адреса, и по фронту тактового должно быть установившееся значение адреса. А тут этого не наблюдается, ведь так?
mse
Цитата(torik @ Apr 15 2008, 14:42) *
Ну во-первых смотрим - почему первый фронт пропускает? ...

Дык, РТЛвьювер кажет, что на ЕНА триггеров, с выхода сумматора идёт через логику. А это время. Вот первый цлоцк и таво... Сдвиньте назад сигналы readn и waitrequest на одну-пару нан и счоччик чудесно сработает от "первого" фронта. Ну и время на распространение. ;О) Тут, есчо, надо понимать, что Квартус показывает состояние именно пинов. Физических. Т.е. ещё сколько-то нан плюсом ко всем времянкам.
torik
Хм... сейчас осмыслю все, попробую в железе - скажу что-нибудь)))
Вообще в железе просто инкремент счетчика адреса на 2 работает нормально. А задача стоит несколько более сложная - надо адрес формировать следующего образца:
0,2...8, 30,32...38, 10,12...18...
Вот, это навроде деинтерлейсера. И тут у меня и возникли проблемы, вопросы и прочее.

Да, в железе output/input заменяются на wire

Вот, отдельно разглядим wire и output в симуляторе:
Код
output        [23:0]    address_0_r;
wire        [23:0]    address_0_rx;

assign address_0_r = address_0_rx;
sdfgsdfg dddd1        (
                    .iclk(ddr_sdram_phy_clk_out),
                    .irst_n(HC_VD),
                    .ena((~read_n)&(~waitrequest)),
                    .iadr_add(/*adr_add*/2'd2),
                    .oadr(address_0_rx)
                    );


На картинке получаем задержку для wire намного меньше, все начинает проясняться но... какого там появляются некие X? Как это понимать?
sazh
Цитата(torik @ Apr 15 2008, 13:45) *
Блин, выкладываю сам этот простейший проект. Если не лениво гляньте на диаграмки...


А с чего Вы взяли, что он простейший. На простейшем столько предупреждений не получишь.
Ваш счетчик Квартусу не нравиться. Опмсание на lach смахивает.
На таких частотах Вы не можете себе позволить асинхронной загрузки. Она тоже в такт должна уложиться.
И счетчик для инкремента 2 можно на разряд меньше сделать. Это уже 275 мгц.
А моделирование не корректное. grid size надо коррекетно выставлять в пол периода клока и галочку setup выставлять для правильного анализа временного моделирования.
input iclk;
input irst_n;
input ena;
output [23:0] oadr_out;

reg [22:0] oadr;


assign oadr_out = {oadr, 1'b0};

always @(posedge iclk) begin
if (!irst_n)
oadr <= 23'd0;
else begin
if (ena)
oadr <= oadr + 1'd1;
end
end
torik
Грид поправил, но это же не принципиально. О какой галке "setup" идет речь не понял...

По-моему без разницы делать +1 и на 1 разряд меньше или +2 и на один разряд больше - результат будет один.

Вы мне главное поясните - откуда ХХХ беруться в симуляторе при наблюдении wire?)))
sazh
Цитата(torik @ Apr 15 2008, 15:44) *
Грид поправил, но это же не принципиально. О какой галке "setup" идет речь не понял...

По-моему без разницы делать +1 и на 1 разряд меньше или +2 и на один разряд больше - результат будет один.

Вы мне главное поясните - откуда ХХХ беруться в симуляторе при наблюдении wire?)))


Если Вам без разницы, на какой частоте счетчик работает, моделируйте функционально. И XXX тоже не будет.
Нет смысла рассматривать диаграмму с некорректным grid size.
В среде временного моделирования есть опция setup and hold time ........
для анализа времени установления и удержания данных относительно клока.
Если времена не корректны, будут xxxxxx.
В вашем частном случает, если входные управляющие сигналы через регистры пропустить, xxxx пропадут. Или корректно входные воздействия рисуйте.
Если в основном проекте при временном моделировании получаете xxxx, а при функциональном все хорошо, значит с проектом облом. (При наличии галочки и реально выставленном периоде клока)
torik
Цитата
Если Вам без разницы, на какой частоте счетчик работает, моделируйте функционально. И XXX тоже не будет.
Нет смысла рассматривать диаграмму с некорректным grid size.
В среде временного моделирования есть опция setup and hold time ........
для анализа времени установления и удержания данных относительно клока.
Если времена не корректны, будут xxxxxx.
В вашем частном случает, если входные управляющие сигналы через регистры пропустить, xxxx пропадут. Или корректно входные воздействия рисуйте.
Если в основном проекте при временном моделировании получаете xxxx, а при функциональном все хорошо, значит с проектом облом. (При наличии галочки и реально выставленном периоде клока)


Итак, на счет некорректного grid size - результат симуляции от него не зависит, но согласен - должен быть порядок, откорректировал...
Промоделировал функционально - все нормально. Теперь временной анализ. Тоже все впорядке! На самом деле "ХХХ" появились не из-за проблем с частотами, а из-за того что при синтезе и оптимизаци компилятор упростил схему и часть выходов регистра была заменена на "провода". "ХХХ" я убрал, т.к. стал прибавлять на 1, а не на 2...

Но все равно получаю облом. Задача в целом такая:
- все сделано на основе отладки "Nios II Embedded Evaluation Kit, Cyclone III Edition"
- с камеры картинка пишется в DDR память. Общее разрешение 576*800, по 16 бит на цвет (565). Т.к. развертка черезстрочная, в памяти получаем поле1 по адресам 0...(288*800*2-2), поле2 по адресам 288*800*2...(576*800*2-2). Запись происходит нормально, это точно.
- контроллер DDR памяти в SOPS Builder, для чтения/записи использую простейший мастер (выводы шины авалон на верхний уровень, уже обсуждал здесь на форуме, применяется успешно)
- для вывода на экран просто генерируем адрес чтения 0...(576*800*2-2). При этом на экране наблюдаем поле1 и поле2 раздельно, как бы два сжатых по вертикали кадра. Все стабильно работает, никаких сбоев...
- остается сделать деинтерлейсер. Для этого по идее надо читать в следующем порядке:
Код
(0*800*2)...(1*800*2-2), (288*800*2)...(289*800*2-2), (1*800*2)...(2*800*2-2)...

Вот тут-то и начинаются проблемы - второе поле вообще куда-то теряется, если два раза повторять каждую строчку одного поля - видим словно пропадание строк. Такое впечатление, что адрес некорректно задается, но на симуляторе (естественно при меньших цифрах) смотрел - все в норме вроде. Кроме того если вывод на монитор выполнять с помощью SGDMA и других приблкд в сопсбилдере, тоже все идет нормально (но этот вариант не подходит).

Поглядите, может я где-то принципиально, в алгоритме или коде делаю ошибку?
Код
wire        [23:0]    address_0_r;
wire        [22:0]    address_0_rx;
assign address_0_r[23:0] = {address_0_rx,1'b0};
sdfgsdfg dddd1        (
                    .iclk(ddr_sdram_phy_clk_out),
                    .irst_n(HC_VD),
                    .ena((~read_n)&(~waitrequest)),
                    .iadr_add(adr_add),
                    .oadr(address_0_rx)
                    );
wire        [22:0]    adr_add;
adr_add dddd2        (
                    .iclk(ddr_sdram_phy_clk_out),
                    .irst_n(HC_VD),
                    .ena((~read_n)&(~waitrequest)),
                    .oadr_add(adr_add)
                    );



module sdfgsdfg        (
                    iclk,
                    irst_n,
                    ena,
                    iadr_add,
                    oadr
                    );

input                iclk;
input                irst_n;
input                ena;
input        [22:0]    iadr_add;
output        [22:0]    oadr;
reg            [22:0]    oadrx;

assign oadr = oadrx;
always    @(posedge iclk or negedge irst_n) begin
    if (!irst_n) begin
        oadrx <= 23'd0;
    end else begin
        if (ena == 1'b0)
            oadrx <= oadrx;
        else
            oadrx <= oadrx + iadr_add;
    end
end

endmodule



module adr_add        (
                    iclk,
                    irst_n,
                    ena,
                    oadr_add
                    );
                    
input                iclk;
input                irst_n;
input                ena;
output    reg    [22:0]    oadr_add;

reg            [22:0]    sta_dop;
always    @(posedge iclk or negedge irst_n) begin
    if (!irst_n) begin
        sta_dop <= 23'd0;
    end else begin
        if (sta_dop < /*23'd9*/23'd1599) begin
            if (ena == 1'b1)    //4*pix-2 (4*800-2 = 3198)
                sta_dop <= sta_dop + 23'd1;
            else
                sta_dop <= sta_dop;
        end else
            sta_dop <= 0;
    end

end
                    
always    @(posedge iclk or negedge irst_n) begin
    if (!irst_n)
        oadr_add <= 23'd1;
    else begin
    oadr_add <= (sta_dop == 23'd798) ? 23'd229601 :
                ((sta_dop == 23'd1598) ? 23'h7c7c01 : 23'd1);
        end
end

endmodule



А то что-то застопорился на этом. Можно конечно сделать отдельные мастеры на чтение первого и второго поля и переключать строки уже после фифо, но это как-то коряво получается...
mse
Короче, разбираться лень, просто кину идею, шоб попроще:
Пишите в ОЗУ построчно. Т.е. на строку выделяйте 1024 слова. И 1024 строки, ессно.
Тогда, для перемешивания строк "верхнего" и нижнего" полукадров используйте бит "0" счоччика строк(т.е. циклицки сдвиньте адрес вправо). Счоччики получатся простые и переключение полукадров быстрым и понятным.
torik
Это неоптимальная растрата памяти. Да и суммирование не уходит никуда, лишь минимизируем счетчики.
Все-таки поглядел бы кто, а? Могу и проект выложить целиком, если у кого такая же отладка быть...
А вот выкладываю только часть с симулятором - надо только скомпилировать и просимулировать и... wink.gif
mse
Цитата(torik @ Apr 17 2008, 15:42) *
Это неоптимальная растрата памяти...

;О) ЗачОт!

И суммирование уходит. Конкатенаццыя остаётся.
А счоччики, они такие - чем короче, тем быстрее/устойчивее. Они-ж на сумматоре. 2 по 10р всегда лучше, чем один на 20.
Хотя...Хозяин - барин.
torik
Проблема решилась (еще в четверг), дело оказалось вовсе не в быстродействии, а том что сигнал разрешения записи не был синхронизирован...

mse, нас чет памяти, как я понял вы предложили записывать в память не заподряд, а в блоки по 1024 байта? При этом в таком блоке будет 800 байт полезной информации, а остальная не используется. Но ведь это неудобно да и требуется больший объем памяти, чему тут удивляться...
sazh
Цитата(torik @ Apr 20 2008, 17:32) *
Проблема решилась (еще в четверг), дело оказалось вовсе не в быстродействии, а том что сигнал разрешения записи не был синхронизирован...

mse, нас чет памяти, как я понял вы предложили записывать в память не заподряд, а в блоки по 1024 байта? При этом в таком блоке будет 800 байт полезной информации, а остальная не используется. Но ведь это неудобно да и требуется больший объем памяти, чему тут удивляться...


Он Вам предложил стандартное решение. Счетчик строк и счетчик отсчетов в строке. Естественно 800 отсчетов, но разрядность таже будет.
Если черезстрочная развертка, и есть понятие полукадра, то младший разряд счетчика строк и есть уровень этого полукадра. Зачем все адресное пространство, если манипуляциям подвержены только строки.
torik
А, ну простите, сразу не понял... Но та ошибка все равно бы сохраниалсь, кстати. Наверное, попробую сделать и так.
EvgenyNik
torik, идея насчёт строки из 1024 слов, да и вообще, из числа 2^n широко используется из-за простоты и скорости. Если режим чтения/записи не страничный, т.е. производится генерация адреса для каждого слова, Вы можете поступить так:
800 слов это 512 + 256 + 32;
выделяете область памяти для строчек по 512 пикселей, отдельную область для их продолжения по 256 и ещё одну по 32;
это позволяет не тратить память, но использовать предлагаемый для 1024 эффект переключения строк.
torik
Спасибо, буду иметь ввиду. К счастью пока не придется это делать, т.к. скорости хватает с запасом. Сейчас решаю другие проблемы (они похоже в геометрической прогрессии растут) ((
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.