Jump to content
    

Начинаю изучать 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.

Share this post


Link to post
Share on other sites

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

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

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

Share this post


Link to post
Share on other sites

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

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

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

Share this post


Link to post
Share on other sites

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

32 minutes ago, Plain said:

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

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

Удачи! Rob.

Share this post


Link to post
Share on other sites

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

 

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

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

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.

Share this post


Link to post
Share on other sites

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

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

Edited by HardRock

Share this post


Link to post
Share on other sites

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

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.

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

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

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.

Share this post


Link to post
Share on other sites

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

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

  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

Edited by HardRock

Share this post


Link to post
Share on other sites

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

6 minutes ago, HardRock said:

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

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

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

Удачи Rob.

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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...