HardRock 0 18 апреля, 2020 Опубликовано 18 апреля, 2020 · Жалоба Значит так, есть модуль SPI Slave, который работает непосредственно с физическим интерфейсом. Для взаимодействия с другими модулями есть клиенты, rx_buffer и tx_buffer размером 1 байт каждый. Когда в модуле происходит некое событие, например SS подняли извне, происходит разовый наезд на клиента IRQ_IO_START. В этом случае основной модуль сбрасывает номер отдаваемого байта в ноль и всё, клиент дозрел. Когда в модуле SPI принят извне 1 байт, происходит разовый наезд на IRQ_IO_BYTE. Основной модуль увеличивает номер отправляемого байта и говорит что клиент дозрел. Как-то так Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Plain 220 18 апреля, 2020 Опубликовано 18 апреля, 2020 · Жалоба Не видно, кого прерывают. Скорее речь о флагах готовности данных, или ещё о FIFO. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
HardRock 0 18 апреля, 2020 Опубликовано 18 апреля, 2020 (изменено) · Жалоба Ну да скорее флаг, но пока не подкинул новый буфер задумке работать не должно. Но это мелочи. Выглядит так: //! SPI Slave wire [7:0] spi_rx_buffer; wire [7:0] spi_tx_buffer; wire [3:0] spi_ivt_status_link; reg [1:0] spi_ivt_status[4]; reg [3:0] spi_ivt_reset; SPISlave spi_port(clk, in_SPI_SS, in_SPI_SCLK, in_SPI_MOSI, out_SPI_MISO, spi_rx_buffer, spi_tx_buffer, spi_ivt_status_link, spi_ivt_reset); reg [7:0] memory[5]; integer id; initial begin memory[0] <= 8'hDE; memory[1] <= 8'hAD; memory[2] <= 8'hBE; memory[3] <= 8'hEF; memory[4] <= 8'hAA; id <= 0; end assign spi_tx_buffer = memory[id]; reg debug; always @(posedge clk) begin // - Drop interrupt set requests spi_ivt_reset <= 0; // - Detect interrupts edges spi_ivt_status[0] <= { spi_ivt_status[0][0], spi_ivt_status_link[0] }; spi_ivt_status[1] <= { spi_ivt_status[1][0], spi_ivt_status_link[1] }; spi_ivt_status[2] <= { spi_ivt_status[2][0], spi_ivt_status_link[2] }; spi_ivt_status[3] <= { spi_ivt_status[3][0], spi_ivt_status_link[3] }; // - IRQ_IO_START if (spi_ivt_status[0] == 2'b01) begin // - Reset byte index id <= 0; // - Reset interrupt spi_ivt_reset[0] <= 1'b1; end // - Wait IRQ_IO_BYTE if (spi_ivt_status[1] == 2'b01) begin // - Move to next byte id <= id + 1; debug <= debug == 0 ? 1 : 0; // - Reset interrupt spi_ivt_reset[1] <= 1'b1; end // - IRQ_IO_STOP if (spi_ivt_status[2] == 2'b01) begin // - Reset interrupt spi_ivt_reset[2] <= 1'b1; end end Проблемы такие: 1. Первый байт оправляется 2 раза 2. Последний байт соответственно не отправляется Изменено 18 апреля, 2020 пользователем HardRock Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RobFPGA 34 18 апреля, 2020 Опубликовано 18 апреля, 2020 · Жалоба Приветствую! Ну теперь расклад понятнее стал - хотя получается клиент у вас мелковат - можно без наездов обойтись - просто пинать его в нужный момент с уверенностью что он (клиент) сразу засуетится и ждать его созревания не надо. module abrupt_uncle (input wire clk, SS, output logic pnut_clienta, ...); logic [2:0] ss_cdc; always @(posedge clk) begin ss_cdc <= (ss_cdc<<1) | SS; pnut_clienta <= (ss_cdc[2:1]==2'b01); end ... endmodule module skinny_client (input wire clk, pnut_clienta, ...); ... always @(posedge clk) begin if (pnut_clienta) begin count_of_sent_out_mahy <= '0; ... end end ... endmodule Удачи! Rob. P.S. Словарь : пинать - импульсный сигнал в один такт ждать созревания - ожидание сигнала об окончании обработки прерывания. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 18 апреля, 2020 Опубликовано 18 апреля, 2020 · Жалоба Возьмите напишите тестбенч и в симуляции все увидите как Ваш модуль работает... В симуляции будут видны все сигналы, а RTL viewer поможет понять как Вас понимает синтезатор... В симуляции сделайте мастер SPI (судя по тому что Вы сейчас делайте, обратитевнимание на циклограмму микросхемы с которой Вы планируете работать)... Не пытайтесь пропустить данный этап... Только после того как в симуляции будет все хорошо то можно приступать к работе с платой... У Вас клок заведен на плату я думаю намного больше чем клок приходящий от SPI - нужна синхронизация Рекомендую Вашу схему разбить на модули, например модуль синхронизации, модуль приема данных (сдвигающий регистр), модуль отправки данных (сдвигающий регистр), модуль управления (управляющий автомат - управляет всеми модулями) и т.д. Тогда будете видеть их в RTL viewer и поможет понять как Вас понимает синтезатор Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
HardRock 0 18 апреля, 2020 Опубликовано 18 апреля, 2020 · Жалоба 1 час назад, Maverick_ сказал: У Вас клок заведен на плату я думаю намного больше чем клок приходящий от SPI - нужна синхронизация Да, 50МГц против 5 на SPI. Реализован вариант с детектом фронтов SPI. 2 часа назад, RobFPGA сказал: Ну теперь расклад понятнее стал - хотя получается клиент у вас мелковат - можно без наездов обойтись - просто пинать его в нужный момент с уверенностью что он (клиент) сразу засуетится и ждать его созревания не надо. Пинать или ждать пока созреет тут работает одинаково. Если пинать то получается проще, но работает к сожалению также. Проблема не в модуле SPI он работает отлично, а в основном модуле который отдает данные в модуль SPI, код привел выше. Почему-то первый байт отправляется два раза. Нужно отправить последовательность: DE AD BE EF, а отправляется DE DE AD BE. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RobFPGA 34 18 апреля, 2020 Опубликовано 18 апреля, 2020 · Жалоба Приветствую! 10 minutes ago, HardRock said: Нужно отправить последовательность: DE AD BE EF, а отправляется DE DE AD BE. Наверное потому что вы в SPISlave сначала защелкиваете текущие данные от spi_tx_buffer а затем формируете прерывание spi_ivt_status[1] для изменения индекса. Вам правильно советуют - запустите код на симуляторе - сразу многое станет ясно. Удачи! Rob. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
HardRock 0 18 апреля, 2020 Опубликовано 18 апреля, 2020 (изменено) · Жалоба Подозревал это по симптомам, только было не очевидно для новичка почему :) Вобщем, заработало, можно двигаться дальше. Поменял прерывание с ожидания на пинок, в модуле SPI сделал защелкивание tx_buffer по заднему фронту пинков начала сессии и следующего байта. always @(posedge clk) begin // - Drop interrupt set requests for (ix = 0; ix < ENV_IRQ_COUNT; ix = ix + 1) begin : Interrupts_Drop_SET IVT_SET[ix] <= 0; IVT_STATUS_EDGE[ix] <= { IVT_STATUS_EDGE[ix][0], IVT_STATUS[ix] }; end // - if (IVT_STATUS_EDGE[IRQ_IO_START] == 2'b10 || IVT_STATUS_EDGE[IRQ_IO_BYTE] == 2'b10) begin // - Copy TX buffer into IO buffer io_buffer <= tx_buffer; end ... Можно ли как-то вытащить из модуля параметры? Например чтобы использовать IRQ_IO_START и тп., объявленные в модуле, но снаружи модуля? Изменено 18 апреля, 2020 пользователем HardRock Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RobFPGA 34 18 апреля, 2020 Опубликовано 18 апреля, 2020 · Жалоба Приветствую! 12 minutes ago, HardRock said: Например чтобы использовать IRQ_IO_START и тп., объявленные в модуле, но снаружи модуля? Для синтеза - нельзя. Но можно сделать наоборот - объявить их в модуле как parameter и при установке такого модуля задавать нужные значения снаружи. Ну или задавать общие константы как макросы define или как localparam во внешнем файле конфигурации и включать это файл как include во все нужные модули. А если вы на SystemVerilog пишете то можно еще и в package все засунуть и делать import в нужном месте. Удачи! Rob. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
HardRock 0 18 апреля, 2020 Опубликовано 18 апреля, 2020 (изменено) · Жалоба Пока на обычном верилоге. Доделаю первый проект, а там посмотрю в сторону System Verilog. На первый взгляд выглядит интересно в первую очередь за счет структур и в целом похож на С немного. А вот VHDL как-то совсем не понравился на первый взгляд. А пока нужно сделать протокол общения через SPI. То что делаю - это PWM контроллер с SPI интерфейсом. Нужно задавать / читать значения ШИМ для каждого канала. Потом сделать коммутацию байпас ШИМа с внешней ножки или выдавать от внтуреннего генератора. Соответственно настраиваемо по SPI. Всем спасибо за помощь! Впервые начал писать под FPGA в день когда зарегистрировался на форуме, тоесть пару дней назад :) До этого давно хотел начать, но как-то микроконтроллеров хватало. FPGA это прям новое измерение в создании цифровых схем))) очень интересно. Изменено 18 апреля, 2020 пользователем HardRock Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 18 апреля, 2020 Опубликовано 18 апреля, 2020 · Жалоба 4 минуты назад, HardRock сказал: Пока на обычном верилоге. Доделаю первый проект, а там посмотрю в сторону System Verilog. На первый взгляд выглядит интересно в первую очередь за счет структур и в целом похож на С немного. А вот VHDL как-то совсем не понравился на первый взгляд. А пока нужно сделать протокол общения через SPI. То что делаю - это PWM контроллер с SPI интерфейсом. Нужно задавать / читать значения ШИМ для каждого канала. Потом сделать коммутацию байпас ШИМа с внешней ножки или выдавать от внтуреннего генератора. Соответственно настраиваемо по SPI. Потому-что VHDL строго типизированный язык. Однако на нем проще выявлять ошикби. Лично мне verilog не нравится из-за вечных begin-end. Хотя по работе приходится и на verilog писать... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
HardRock 0 18 апреля, 2020 Опубликовано 18 апреля, 2020 · Жалоба Всетаки перешел на SystemVerilog :) Можно ли объявить таску со статичными переменными внутри, чтобы их состояние сохранялось между вызовами? Пробовал так: task static CMD_TEST(ref reset, input wire [7:0] rx_byte) ; begin reg [7:0] channel_id; if (reset) begin channel_id <= rx_byte; reset <= 0; end else begin __MEMORY__[channel_id] = rx_byte; end end endtask Но не работает, а если channel_id вытащить наружу - то работает. Хочется реализацию отдельных команд протокола обмена данными сделать в виде отдельных блоков т.к. у них может быть своя логика (стейт машина) и не хочется устраивать помойку в основном модуле + чтобы легко добавлять новые команды. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
one_eight_seven 6 18 апреля, 2020 Опубликовано 18 апреля, 2020 · Жалоба 15 minutes ago, HardRock said: Но не работает, а если channel_id вытащить наружу - то работает. Ну всё правильно. Если вы хотите статическую переменную, то зачем вы объявляете статическим таск? Переменную и объявляйте. 24 minutes ago, HardRock said: очется реализацию отдельных команд протокола обмена данными сделать в виде отдельных блоков т.к. у них может быть своя логика (стейт машина) и не хочется устраивать помойку в основном модуле + чтобы легко добавлять новые команды. Тогда выносите это в интерфейс. Поищите в гугле Bus Functional Model, чтобы получше узнать, что это и зачем. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
HardRock 0 18 апреля, 2020 Опубликовано 18 апреля, 2020 (изменено) · Жалоба Как объявить? Это нужно в коде под железку, не в тестах. static reg [7:0] channel_id; компилится но эффект тот же, при этом ругается если есть параллельное присваивание, Цитата Error (10959): SystemVerilog error at pwm.v(104): illegal assignment - automatic variables can't have non-blocking assignments хотя причем тут автоматик если написал статик. Без слова статик не ругается, но и не работает. А так не компилится) reg static [7:0] channel_id; Изменено 18 апреля, 2020 пользователем HardRock Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
one_eight_seven 6 19 апреля, 2020 Опубликовано 19 апреля, 2020 · Жалоба 1. В интерфейсе эта переменная может быть за пределами таска. (В модуле тоже) 2. Зачем вам неблокирующее присваивание? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться