Перейти к содержанию
    

Начинаю изучать FPGA (verilog)

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.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

16 часов назад, Flip-fl0p сказал:

Где Вы в SPI нашли двунаправленные шины ?

Трёхпроводной SPI. Там провод данных один, и он может переключаться со входа на выход прямо по ходу дела. Мастер, например, в четырёх битах выдал адрес регистра, в пятом -- чтение, а слейв должен начиная с шестого бита выдавать данные.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 минуту назад, andrew_b сказал:

Трёхпроводной SPI. Там провод данных один, и он может переключаться со входа на выход прямо по ходу дела. Мастер, например, в четырёх битах выдал адрес регистра, в пятом -- чтение, а слейв должен начиная с шестого бита выдавать данные.

Так я знаю, что существуют SPI с двунаправленными шинами . У меня сейчас такой в проекте применяется :biggrin:. Но всё-же такой spi - это слегка нестандатрная реализация.  Я просто задавал наводящий вопрос Автору темы, чтобы он задумался над своей реализацией. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

32 minutes ago, Plain said:

в любом случае, всё, что двигалось сдвиговыми регистрами, переписывается в параллельные только по завершении сеанса, т.е. по снятии SS.

Это уж внутренне  дело устройства - когда и с какой регулярностью принятые биты записывать -  я могу  потоком (в одном сеансе) гнать через SPI и 64 KB  данных  что-ж мне потом все эти биты разом переписывать из приемного регистра? :shok:

Удачи! Rob.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да это всё нестандартные вариации по мотивам SPI. Мне нужен SPI без последовательных соединений и т.п. Тоесть общий SCLK, а MOSI / MISO параллельно, SS у каждого свой. При этом протокол передачи хочу сделать похожий на SPI FLASH. Тоесть включаем SS, отправляем первый байт команды (например записать регистр), затем адер регистра и затем данные которые записываются. Аналогично с чтением. Поэтому нужно передавать несколько байт в рамках одной сессии (SS == 1). 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Подскажите пожалуйста, реализация условно "контроллера прерывания" сделана нормально?

//! 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

ожидаемое поведение - хз. Как оно будет работать если так написать? 

Изменено пользователем HardRock

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

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.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А почему она в нуле если в предыдущем цикле или в другом месте программы в неё записали 1? 

Wire от прерывания  подключается к регистру в вызывающем коде (в псевдокоде не написал), соответственно кто сбросит регистр в ноль?

Изменено пользователем HardRock

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

27 minutes ago, HardRock said:

А почему она в нуле если в предыдущем цикле или в другом месте программы в неё записали 1? 

В том то и дело - раз записали и irq.in_set станет ==1 - значит первая строчка никогда не выполнится. Так и будет стоять одинокой единицей :unknw:

P.S.  А вот с исправленным условием  if (irq.in_set == 1) irq.in_set <= 0; будет сбрасываться  но тогда можно и просто написать irq.in_set <= 0;  без всякого условия. 

Еще раз  - тяжело оценивать форму облаков  в тумане ночью.

Делите ваш дизайн  на  законченные функциональные кусочки.  Фиксируйте назначение, функционал и параметры входов/входов. И реализовывайте их как бы независимо.  

Удачи! Rob.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну тоесть  предлагается в каждом клоке принудительно занулять регистр in_set, а дальше записывать в него 1 если нужно. Почему проверка в на 1 в начале клока не будет выполняться? 

Кстати, проверил отправку массива байт в самом модуле SPI - все отлично работает. Итого проблема в коммуникации модуля с внешним кодом.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

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.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Разобрался почему не работает отправка нескольких байт. Дело действительно было в обработке прерываний, она занимает некоторое время, в течении которого системный клок успевает сделать несколько проходов.

Изначально написал так:

  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МГц тактовую показывает хорошо)

 

IMG_20200418_180121.jpg

IMG_20200418_181349.jpg

Изменено пользователем HardRock

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

6 minutes ago, HardRock said:

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

Вы бы сначала объяснили серьезным дядькам какие  бабло сигналы у вас есть и как вы хотите их обрабатывать. А то расклад на пальцах мутный какой-то и мы (серьезные дядьки)  ни как в тему не вникнем :biggrin:  

Так что разложите  все по полочкам - кто клиента обрабатывать должен - по какому событию   - разовый наезд или  постоянный прессинг - как сигналить что клиент дозрел?  :new_russian:

Удачи Rob.

P.S. Словарь  серьезных дядек 
клиент                              - прерывание
разовый наезд              - сигнал прерывания импульсом
постоянный прессинг - сигнал прерывания уровнем
клиент дозрел               - подтверждение обработки прерывания

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...