alex1985 0 13 мая, 2018 Опубликовано 13 мая, 2018 (изменено) · Жалоба Добрый день всем и спасибо за конструктивную критику! Вернул свой первоначальный вариант, немного доработав его (добавил сигнал 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 поменял настройки вместо временного на функциональное моделирование. Функциональная симуляция: И RTL: Проект с этим кодом прошил и поставил вчера на тест: с МК отправляю запись данных по адресу 2, затем считываю данные по этому адресу и сверяю с отправленным значением. Далее повторяю процедуру, но по этому же адресу пишу считываю и сверяю уже другие данные. Если данные отправленные и принятые не совпадают - то выставляю флаг ошибки. Пришел сегодня посмотреть результаты - отправлено принято всего 5 300 000 посылок, кол-во ошибок - 0. Результат вполне устраивает. Но есть узкое место: Т.к. адрес и данные поступают двумя разными SPI-передачами по 16 бит, то в случае помехи по сигналу CS может произойти рассинхронизация в приеме дынных, проще говоря ПЛИС не поймет что пришло данные или адрес. Можно конечно ввести дополнительный сигнал синхронизации, но я думаю поступить по другому - держать CS в нуле на все 32 бита, пропуская последовательно адрес и данные. Изменено 13 мая, 2018 пользователем Sprite Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
nice_vladi 1 13 мая, 2018 Опубликовано 13 мая, 2018 · Жалоба Добрый день всем и спасибо за конструктивную критику! Вернул свой первоначальный вариант, немного доработав его (добавил сигнал 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 - маст хев. Без них - никуда. Встроенный симулятор Квартуса - боль. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 13 мая, 2018 Опубликовано 13 мая, 2018 · Жалоба 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) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iosifk 3 13 мая, 2018 Опубликовано 13 мая, 2018 · Жалоба Проект с этим кодом прошил и поставил вчера на тест: с МК отправляю запись данных по адресу 2, затем считываю данные по этому адресу и сверяю с отправленным значением. Далее повторяю процедуру, но по этому же адресу пишу считываю и сверяю уже другие данные. Если данные отправленные и принятые не совпадают - то выставляю флаг ошибки. Пришел сегодня посмотреть результаты - отправлено принято всего 5 300 000 посылок, кол-во ошибок - 0. Результат вполне устраивает. Про все дела уже написали, но вот есть еще и небольшенькая такая тонкость... Если дело поставлено именно так: " отправляю запись данных по адресу 2, затем считываю данные по этому адресу и сверяю с отправленным значением", причем без паузы и без выдачи на шину данных другого кода, то вполне возможно, что читаете Вы не содержимое ячеек памяти, а паразитный емкостной заряд на шине... А он конечно всегда будет таким, какой Вы и выставляли на этой шине... :) Так что надо "записать по правильному адресу", потом выдать что-то по любому "пустому месту", лишь бы на шинах поменялись данные, а только потом читать... А если делать по хорошему, то в блок, который открывает шинники ПЛИС по 3-му состоянию, надо сделать задержку на время разряда емкости на линиях. Так хоть будет немного дольше, но ПЛИС будет греться значительно меньше... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alex1985 0 15 мая, 2018 Опубликовано 15 мая, 2018 · Жалоба Добрый день всем! Еще одна редакция модуля с учетом исправлений и замечаний: 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: В результате появились "слаки"( Насколько это криминально - не знаю. Файл констрейна: 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]}] Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 15 мая, 2018 Опубликовано 15 мая, 2018 · Жалоба Вы как-то очень избирательно читаете :rolleyes: PLL поставили - уже хорошо. Работаете только по одному CLK - отлично ! А вот про цепочку синхронизаторов для подавления метастабильного состояния забыли. Да и простейший фильтр дребезга не мешало бы поставить. Сигналы Вашего SPI относительно FPGA имеют очень пологие фронты. Это надо фильтровать. А то задолбаетесь искать сбои в работе, когда они будут. А они будут будьте уверены :rolleyes: И да. Я бы не считал линию SCK полноценным клоком. Соответственно из констрейнов его убрать нафиг. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 15 мая, 2018 Опубликовано 15 мая, 2018 · Жалоба Смотрите как я делаю: 1. У меня отдельный модуль антидребезга, где внутри есть цепочка синхронизации для подавления метастабильного состояния. Я параметрами задаю длину цепочки синхронизации и время фильтрации дребезга. 2. У меня отдельный модуль детектора фронтов, где я параметрами задаю тип детектируемого фронта. Самое главное, что это у меня отдельные модули, которые отлажены и гарантированно работают. И если что-то у меня не работает, то я знаю, что 100% проблема не в них. Тем более, эти модули присутствуют в большинстве проектов. Зачем по 100 раз описывать одно и то же. Да ещё и тестировать их потом ? PS. Не претендую на правильность. Но практика показала, что так быстрее и удобнее. Сначала на бумаге набросал всю схему и все алгоритмы, потом перенес на HDL - более 50% проекта собрал из готовых библиотечных блоков собственной разработки Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alex1985 0 15 мая, 2018 Опубликовано 15 мая, 2018 · Жалоба Вы как-то очень избирательно читаете :rolleyes: PLL поставили - уже хорошо. Работаете только по одному CLK - отлично ! А вот про цепочку синхронизаторов для подавления метастабильного состояния забыли. Да и простейший фильтр дребезга не мешало бы поставить. Сигналы Вашего SPI относительно FPGA имеют очень пологие фронты. Это надо фильтровать. А то задолбаетесь искать сбои в работе, когда они будут. А они будут будьте уверены :rolleyes: И да. Я бы не считал линию SCK полноценным клоком. Соответственно из констрейнов его убрать нафиг. Синхронизаторы - это хорошо) Подумаю над этим. Если у Вас есть готовый пример фильтра антидребезга - может поделитесь? Насчет SCK - согласен, только я его потому и описывал в констрейне, т.к. надоели всякие варнинги типа "found dedicated clock...". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 15 мая, 2018 Опубликовано 15 мая, 2018 · Жалоба Синхронизаторы - это хорошо) Подумаю над этим. Если у Вас есть готовый пример фильтра антидребезга - может поделитесь? Насчет SCK - согласен, только я его потому и описывал в констрейне, т.к. надоели всякие варнинги типа "found dedicated clock...". Над синхронизаторами не думать надо, а ставить их ! Вот пример фильтра. http://allaboutfpga.com/wp-content/uploads...gic_circuit.jpg Можно описать в виде FSM, но мне в виде схемы он понятней. Легко сделать параметризируемым Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться