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

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

Значит так, есть модуль SPI Slave, который работает непосредственно с физическим интерфейсом. Для взаимодействия с другими модулями есть клиенты, rx_buffer и tx_buffer размером 1 байт каждый.

Когда в модуле происходит некое событие, например SS подняли извне, происходит разовый наезд на клиента IRQ_IO_START. В этом случае основной модуль сбрасывает номер отдаваемого байта в ноль и всё, клиент дозрел.

Когда в модуле SPI принят извне 1 байт, происходит разовый наезд на IRQ_IO_BYTE. Основной модуль увеличивает номер отправляемого байта и говорит что клиент дозрел.

Как-то так :new_russian:

 

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


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

Не видно, кого прерывают. Скорее речь о флагах готовности данных, или ещё о FIFO.

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


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

Ну да скорее флаг, но пока не подкинул новый буфер задумке работать не должно. Но это мелочи.

Выглядит так:

	//! 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. Последний байт соответственно не отправляется

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

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


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

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

Ну теперь расклад понятнее стал  - хотя получается клиент у вас мелковат   -  можно без наездов  обойтись -  просто  пинать его  в нужный момент с уверенностью что он (клиент) сразу засуетится и ждать его созревания не надо.

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.  Словарь :

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

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


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

Возьмите напишите тестбенч и в симуляции все увидите как Ваш модуль работает...

В симуляции будут видны все сигналы, а RTL viewer поможет понять как Вас понимает синтезатор...

В симуляции сделайте мастер SPI  (судя по тому что Вы сейчас делайте, обратитевнимание на циклограмму  микросхемы с которой Вы планируете работать)...

Не пытайтесь пропустить данный этап...

Только после того как в симуляции будет все хорошо то можно приступать к работе с платой...

У Вас клок заведен на плату я думаю намного больше чем клок приходящий от SPI - нужна синхронизация

Рекомендую Вашу схему разбить на модули, например модуль синхронизации, модуль приема данных (сдвигающий регистр), модуль отправки данных (сдвигающий регистр), модуль управления (управляющий автомат - управляет всеми модулями) и т.д. Тогда будете видеть их в RTL viewer и поможет понять как Вас понимает синтезатор

 

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


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

1 час назад, Maverick_ сказал:

У Вас клок заведен на плату я думаю намного больше чем клок приходящий от SPI - нужна синхронизация

Да, 50МГц против 5 на SPI.

Реализован вариант с детектом фронтов SPI.

 

2 часа назад, RobFPGA сказал:

Ну теперь расклад понятнее стал  - хотя получается клиент у вас мелковат   -  можно без наездов  обойтись -  просто  пинать его  в нужный момент с уверенностью что он (клиент) сразу засуетится и ждать его созревания не надо.

Пинать или ждать пока созреет тут работает одинаково. Если пинать то получается проще, но работает к сожалению также.

Проблема не в модуле SPI он работает отлично, а в основном модуле который отдает данные в модуль SPI, код привел выше. Почему-то первый байт отправляется два раза.

Нужно отправить последовательность: DE AD BE EF, а  отправляется DE DE AD BE. 

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


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

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

10 minutes ago, HardRock said:

Нужно отправить последовательность: DE AD BE EF, а  отправляется DE DE AD BE. 

Наверное потому что вы  в SPISlave сначала  защелкиваете текущие данные от spi_tx_buffer а затем формируете прерывание spi_ivt_status[1] для изменения  индекса.  Вам правильно советуют -  запустите код на симуляторе - сразу  многое станет ясно.  

Удачи! Rob. 

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


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

Подозревал это по симптомам, только было не очевидно для новичка почему :)

Вобщем, заработало, можно двигаться дальше.

Поменял прерывание с ожидания на пинок, в модуле 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 и тп., объявленные в модуле, но снаружи модуля?

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

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


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

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

12 minutes ago, HardRock said:

Например чтобы использовать IRQ_IO_START и тп., объявленные в модуле, но снаружи модуля?

Для синтеза - нельзя.  
Но можно сделать  наоборот - объявить их в модуле как parameter и при установке такого модуля задавать нужные значения снаружи.
Ну или задавать общие константы как макросы define или как localparam во внешнем файле конфигурации и включать это файл как include во все нужные модули.
А если вы на SystemVerilog пишете  то можно еще и в package все засунуть и делать import в нужном месте. 

Удачи! Rob.

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


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

Пока на обычном верилоге. Доделаю первый проект, а там посмотрю в сторону System Verilog. На первый взгляд выглядит интересно в первую очередь за счет структур и в целом похож на С немного. А вот VHDL как-то совсем не понравился на первый взгляд.

А пока нужно сделать протокол общения через SPI.

То что делаю - это PWM контроллер с SPI интерфейсом. Нужно задавать / читать значения ШИМ для каждого канала. Потом сделать коммутацию байпас ШИМа с внешней ножки или выдавать от внтуреннего генератора. Соответственно настраиваемо по SPI.

Всем спасибо за помощь!

Впервые начал писать под FPGA в день когда зарегистрировался на форуме, тоесть пару дней назад :) До этого давно хотел начать, но как-то микроконтроллеров хватало. FPGA это прям новое измерение в создании цифровых схем))) очень интересно.

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

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


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

4 минуты назад, HardRock сказал:

Пока на обычном верилоге. Доделаю первый проект, а там посмотрю в сторону System Verilog. На первый взгляд выглядит интересно в первую очередь за счет структур и в целом похож на С немного. А вот VHDL как-то совсем не понравился на первый взгляд.

А пока нужно сделать протокол общения через SPI.

То что делаю - это PWM контроллер с SPI интерфейсом. Нужно задавать / читать значения ШИМ для каждого канала. Потом сделать коммутацию байпас ШИМа с внешней ножки или выдавать от внтуреннего генератора. Соответственно настраиваемо по SPI.

 

Потому-что VHDL строго типизированный язык. Однако на нем проще выявлять ошикби. Лично мне verilog не нравится из-за вечных begin-end. Хотя по работе приходится и на verilog писать...

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


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

Всетаки перешел на 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 вытащить наружу - то работает.

 

Хочется реализацию отдельных команд протокола обмена данными  сделать в виде отдельных блоков т.к. у них может быть своя логика (стейт машина) и не хочется устраивать помойку в основном модуле + чтобы легко добавлять новые команды.

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


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

15 minutes ago, HardRock said:

Но не работает, а если channel_id вытащить наружу - то работает.

Ну всё правильно.
Если вы хотите статическую переменную, то зачем вы объявляете статическим таск? Переменную и объявляйте.

24 minutes ago, HardRock said:

очется реализацию отдельных команд протокола обмена данными  сделать в виде отдельных блоков т.к. у них может быть своя логика (стейт машина) и не хочется устраивать помойку в основном модуле + чтобы легко добавлять новые команды.

Тогда выносите это в интерфейс. Поищите в гугле Bus Functional Model, чтобы получше узнать, что это и зачем.

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


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

Как объявить? Это нужно в коде под железку, не в тестах.

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;

 

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

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


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

1. В интерфейсе эта переменная может быть за пределами таска. (В модуле тоже)

2. Зачем вам неблокирующее присваивание?

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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