Plain 321 April 18, 2020 Posted April 18, 2020 · Report post 14 часов назад, HardRock сказал: if (io_bits_count == 7) begin // - Copy IO buffer into RX buffer rx_buffer <= io_buffer; Это противоречит стандарту SPI — устройства могут соединяться последовательно, т.е. один сеанс обмена и один SS для всех, образуя один сдвиговый регистр произвольной разрядности и тактуемый одним общим SCLK, либо устройства могут соединяться параллельно, для индивидуальных сеансов обмена, т.е. SS у каждого свой собственный, SCLK по-прежнему общий, а все MISO и MOSI соединены параллельно, для этого MOSI и потребовалось третье состояние (но его может и не быть, т.е. не каждое устройство поддерживает шинный обмен) — в любом случае, всё, что двигалось сдвиговыми регистрами, переписывается в параллельные только по завершении сеанса, т.е. по снятии SS. Quote Share this post Link to post Share on other sites More sharing options...
andrew_b 23 April 18, 2020 Posted April 18, 2020 · Report post 16 часов назад, Flip-fl0p сказал: Где Вы в SPI нашли двунаправленные шины ? Трёхпроводной SPI. Там провод данных один, и он может переключаться со входа на выход прямо по ходу дела. Мастер, например, в четырёх битах выдал адрес регистра, в пятом -- чтение, а слейв должен начиная с шестого бита выдавать данные. Quote Share this post Link to post Share on other sites More sharing options...
Flip-fl0p 4 April 18, 2020 Posted April 18, 2020 · Report post 1 минуту назад, andrew_b сказал: Трёхпроводной SPI. Там провод данных один, и он может переключаться со входа на выход прямо по ходу дела. Мастер, например, в четырёх битах выдал адрес регистра, в пятом -- чтение, а слейв должен начиная с шестого бита выдавать данные. Так я знаю, что существуют SPI с двунаправленными шинами . У меня сейчас такой в проекте применяется . Но всё-же такой spi - это слегка нестандатрная реализация. Я просто задавал наводящий вопрос Автору темы, чтобы он задумался над своей реализацией. Quote Share this post Link to post Share on other sites More sharing options...
RobFPGA 58 April 18, 2020 Posted April 18, 2020 · Report post Приветствую! 32 minutes ago, Plain said: в любом случае, всё, что двигалось сдвиговыми регистрами, переписывается в параллельные только по завершении сеанса, т.е. по снятии SS. Это уж внутренне дело устройства - когда и с какой регулярностью принятые биты записывать - я могу потоком (в одном сеансе) гнать через SPI и 64 KB данных что-ж мне потом все эти биты разом переписывать из приемного регистра? Удачи! Rob. Quote Share this post Link to post Share on other sites More sharing options...
HardRock 0 April 18, 2020 Posted April 18, 2020 · Report post Да это всё нестандартные вариации по мотивам SPI. Мне нужен SPI без последовательных соединений и т.п. Тоесть общий SCLK, а MOSI / MISO параллельно, SS у каждого свой. При этом протокол передачи хочу сделать похожий на SPI FLASH. Тоесть включаем SS, отправляем первый байт команды (например записать регистр), затем адер регистра и затем данные которые записываются. Аналогично с чтением. Поэтому нужно передавать несколько байт в рамках одной сессии (SS == 1). Quote Share this post Link to post Share on other sites More sharing options...
HardRock 0 April 18, 2020 Posted April 18, 2020 (edited) · Report post Подскажите пожалуйста, реализация условно "контроллера прерывания" сделана нормально? //! Interrupt module module Interrupt ( input wire in_clk, // - System clock input wire in_set, // - Set command input wire in_reset, // - Reset command output wire out_state // - Current state ); reg state; reg [1:0] setpulse; reg [1:0] resetpulse; assign out_state = state; always @(posedge in_clk) begin // - Update pulses setpulse <= { setpulse[0], in_set }; resetpulse <= { resetpulse[0], in_reset }; // - Detect set if (setpulse == 2'b01) state <= 1'b1; // - Detect reset if (resetpulse == 2'b01) state <= 1'b0; end endmodule Ожидаемое поведение: Выполняется на каждом системном клоке. Текущее состояние хранится в state. Когда на in_set приходит 1, а предыдущее значение там 0, то состояние переходит в 1. Аналогично с in_reset. Если нужно скинуть состояние в 0, то нужно на in_reset послать 1 когда там был 0. Результат смены текущего состояния out_state будет доступен во внешнем коде на следующем системном клоке. При использовании внешним кодом, прежде чем использовать например in_set, нужно убедиться что он выставлен в 0. Псевдокод always @(posedge clk) if (irq.in_set == 1) irq.in_set <= 0; ... irq.in_set <= 1; end ожидаемое поведение - хз. Как оно будет работать если так написать? Edited April 18, 2020 by HardRock Quote Share this post Link to post Share on other sites More sharing options...
RobFPGA 58 April 18, 2020 Posted April 18, 2020 · Report post Приветствую! 27 minutes ago, HardRock said: ожидаемое поведение - хз. Как оно будет работать если так написать? Никак - первая строчка "if (irq.in_set == 0) irq.in_set <= 0; " бессмысленна - зачем ставить irq.in_set в 0 если уже она == 0 ? Может хотели так always @(posedge clk) irq.in_set <= 0; ... irq.in_set <= ~irq.in_set && (some_irq_request == 1); end Вы для начала разрисуйте стейт-диаграму вашей схемы - чтобы было понятно что и как управляет им (внешние сигналы) и как и куда переключается автомат (внутренние сигналы и состояния). Тогда многие вопросы станут значительно понятнее. Удачи! Rob. Quote Share this post Link to post Share on other sites More sharing options...
HardRock 0 April 18, 2020 Posted April 18, 2020 (edited) · Report post А почему она в нуле если в предыдущем цикле или в другом месте программы в неё записали 1? Wire от прерывания подключается к регистру в вызывающем коде (в псевдокоде не написал), соответственно кто сбросит регистр в ноль? Edited April 18, 2020 by HardRock Quote Share this post Link to post Share on other sites More sharing options...
RobFPGA 58 April 18, 2020 Posted April 18, 2020 · Report post Приветствую! 27 minutes ago, HardRock said: А почему она в нуле если в предыдущем цикле или в другом месте программы в неё записали 1? В том то и дело - раз записали и irq.in_set станет ==1 - значит первая строчка никогда не выполнится. Так и будет стоять одинокой единицей P.S. А вот с исправленным условием if (irq.in_set == 1) irq.in_set <= 0; будет сбрасываться но тогда можно и просто написать irq.in_set <= 0; без всякого условия. Еще раз - тяжело оценивать форму облаков в тумане ночью. Делите ваш дизайн на законченные функциональные кусочки. Фиксируйте назначение, функционал и параметры входов/входов. И реализовывайте их как бы независимо. Удачи! Rob. Quote Share this post Link to post Share on other sites More sharing options...
HardRock 0 April 18, 2020 Posted April 18, 2020 · Report post Ну тоесть предлагается в каждом клоке принудительно занулять регистр in_set, а дальше записывать в него 1 если нужно. Почему проверка в на 1 в начале клока не будет выполняться? Кстати, проверил отправку массива байт в самом модуле SPI - все отлично работает. Итого проблема в коммуникации модуля с внешним кодом. Quote Share this post Link to post Share on other sites More sharing options...
RobFPGA 58 April 18, 2020 Posted April 18, 2020 · Report post Приветствую! 9 minutes ago, HardRock said: Ну тоесть предлагается в каждом клоке принудительно занулять регистр in_set, а дальше записывать в него 1 если нужно. Почему проверка в на 1 в начале клока не будет выполняться? Потому что вначале вы написали if (irq.in_set == 0) irq.in_set <= 0; А вот исправленный вариант "if (irq.in_set == 1) irq.in_set <= 0;" и вариант "irq.in_set <= 0;" для синтеза (но не для симуляции) функционально одинаковы. Удачи! Rob. Quote Share this post Link to post Share on other sites More sharing options...
HardRock 0 April 18, 2020 Posted April 18, 2020 · Report post А ну это опечатка была, я её поправил секунд через 30 :) Quote Share this post Link to post Share on other sites More sharing options...
HardRock 0 April 18, 2020 Posted April 18, 2020 (edited) · Report post Разобрался почему не работает отправка нескольких байт. Дело действительно было в обработке прерываний, она занимает некоторое время, в течении которого системный клок успевает сделать несколько проходов. Изначально написал так: always @(posedge clk) begin // - Drop interrupt set requests spi_ivt_reset <= 0; // - IRQ_IO_START if (spi_ivt_status[0]) begin // - Reset byte index id <= 0; // - Reset interrupt spi_ivt_reset[0] <= 1'b1; end // - Wait IRQ_IO_BYTE if (spi_ivt_status[1]) 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]) begin // - Reset interrupt spi_ivt_reset[2] <= 1'b1; end end Осцилограмма во вложении. Желтым - состояние IRQ_IO_BYTE, синим состояние debug. Видно что дебаг успевает несколько раз сменить состояние, значит id плюсуется больше чем нужно. Если ввести буфер и ловить только передний фронт прерывания, то всё работает. always @(posedge clk) begin // - Drop interrupt set requests spi_ivt_reset <= 0; ivt_buffer <= { ivt_buffer[0], spi_ivt_status[1] }; // - IRQ_IO_START if (spi_ivt_status[0]) begin // - Reset byte index id <= 0; // - Reset interrupt spi_ivt_reset[0] <= 1'b1; end // - Wait IRQ_IO_BYTE if (ivt_buffer == 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]) begin // - Reset interrupt spi_ivt_reset[2] <= 1'b1; end end Вопрос: это нормальная практика - ловить передний фронт, или можно сделать более эффективно (без дополнительных регистров)? Как серьезные дядьки решают подобную задачу с прерываниями? PS: осцил ломаный до 100МГц, так что 50МГц тактовую показывает хорошо) Edited April 18, 2020 by HardRock Quote Share this post Link to post Share on other sites More sharing options...
HardRock 0 April 18, 2020 Posted April 18, 2020 · Report post И всёравно немного залипает. Первый байт отправляется два раза. Quote Share this post Link to post Share on other sites More sharing options...
RobFPGA 58 April 18, 2020 Posted April 18, 2020 · Report post Приветствую! 6 minutes ago, HardRock said: Вопрос: это нормальная практика - ловить передний фронт, или можно сделать более эффективно (без дополнительных регистров)? Как серьезные дядьки решают подобную задачу с прерываниями? Вы бы сначала объяснили серьезным дядькам какие бабло сигналы у вас есть и как вы хотите их обрабатывать. А то расклад на пальцах мутный какой-то и мы (серьезные дядьки) ни как в тему не вникнем Так что разложите все по полочкам - кто клиента обрабатывать должен - по какому событию - разовый наезд или постоянный прессинг - как сигналить что клиент дозрел? Удачи Rob. P.S. Словарь серьезных дядек клиент - прерывание разовый наезд - сигнал прерывания импульсом постоянный прессинг - сигнал прерывания уровнем клиент дозрел - подтверждение обработки прерывания Quote Share this post Link to post Share on other sites More sharing options...