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

Verilog SPI slave, асинхронный

Здравствуйте.

Для связи между CPLD epm570 и MCU atsam3u задумано использовать SPI, проц - мастер, плис - слейв.

 

Микроконтроллер должен управлять светодиодами посредством ПЛИС и считывать состояние входов ПЛИС.

Регистров в ПЛИС несколько, поэтому в дополнение к сигналам SPI (mosi/miso/sck/ncs), используются три линии адреса, управляемые микроконтроллером в режиме PIO.

 

Обмен происходит изредка и не быстрее мегагерца, поэтому мне показалось неоптимальным постоянно тактовать модуль SPI от быстрого системного клока ПЛИС.

 

Та же шина должна использоваться для контроля внешнего ЦАП, поэтому формат SPI выбран самый обычный (CPHA=0, CPOL=0), когда данные на mosi/miso появляются сразу после падения NCS, а сигнальный клок SCK появляется позже.

MCU не генерит SCK, когда NCS в единице, и эти сигналы не меняют своё состояние одновременно.

 

Код модуля и тестбенча - ниже.

Основная идея - клочить приёмопередатчик сигналом ck, получаемый объединением логическим ИЛИ сигналов SCK и NCS шины.

Что нужно защелкивать в сдвиговый регистр интерфейса - выходные данные MOSI или параллельные данные состояния ПЛИС, держится в регистре state.

Если по фронту объединенного клока видим положительный NCS - будем загружать данные ПЛИС. Если был SCK - значит будем загружать побитно MOSI.

 

В итоге, проц нормально управляет регистрами ПЛИС - лампочки загораются как надо,

но, хотя в симуляторе всё работает, в реальном устройстве ПЛИС не выдаёт на MISO своё состояние, а лишь повторяет прошлые пришедшие в MOSI данные.

 

Подскажите пожалуйста, в чем я мог тут ошибиться.

Или я уже готов плюнуть и сделать синхронный дизайн на мастерклоке в 20МГц с детекторами фронтов клоков шины, как во всех примерах гугла, но это не то, что хотелось.

 

module spislave( spcki,ncsi,mosi,miso,addri, pdati, pdat1o,pdat2o);
//spi IO
input spcki,ncsi,mosi; output miso;
input [2:0]addri;

//parallel IO
input [7:0]pdati; output [7:0]pdat1o; output [7:0]pdat2o;

parameter PDATI=0,MOSI=1; //что защелкивать в spishiftreg
reg state=PDATI;
wire ck = spcki | ncsi;
always@(posedge ck)
begin
	if(ncsi)
		state <= PDATI;
	else //(ncs==0 && spcki==1)
		state <= MOSI;
end

reg mosi_prelatch=0;
always@(posedge spcki)
	mosi_prelatch<=mosi;

reg [7:0]spishiftreg=0;
always@(negedge ck)
begin
	if(state == PDATI)
		spishiftreg<=pdati;
	else//(state == MOSI)
		spishiftreg<={spishiftreg[6:0],mosi_prelatch};
end

assign miso=spishiftreg[7]&(~ncsi);

reg [7:0]pdat1o;
reg [7:0]pdat2o;
always@(posedge ncsi)
begin
	if(addri==0)
		pdat1o<=spishiftreg;
	else if(addri==1)
		pdat2o<=spishiftreg;
end
endmodule

 

`timescale 1ps/1ps
parameter ps=1;parameter ns=1000*ps;

module tbspi();
integer bitnum=0;
reg [2:0]addr=7;
reg ncs=1;
reg spck=0;
wire mosi;

reg [7:0]spi_reg=0;
assign mosi=spi_reg[7];

initial begin
	#(50*ns)ncs=1;
	for(addr=0;addr<4;addr=addr+1)
	begin
		spi_reg<=8'b01010101;
		#(50*ns)ncs=0;
		for(bitnum=0; bitnum<8; bitnum=bitnum+1)
		begin
			#(10*ns) spck=1;
			#(10*ns) spck=0;
			spi_reg<={spi_reg[6:0],1'b0};
		end
		#(50*ns)ncs=1;
		#(50*ns)ncs=1;
	end
end

wire miso;

wire [7:0]pdati=8'b11100111; 
wire [7:0]pdat1o;
wire [7:0]pdat2o;

spislave DUT(.spcki(spck),.ncsi(ncs),.mosi(mosi),.miso(miso),.addri(addr),
		.pdati(pdati), .pdat1o(pdat1o),.pdat2o(pdat2o));

endmodule

post-10546-1434703994_thumb.png

 

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


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

Или я уже готов плюнуть и сделать синхронный дизайн на мастерклоке в 20МГц с детекторами фронтов клоков шины, как во всех примерах гугла, но это не то, что хотелось.

Именно это и нужно сделать!

Потому что то, что у Вас сейчас это тихий ужас.

 

И еще не мешайте в testbench блокирующее и не блокирующее присваивание, а то на race condition напоритесь

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


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

у вас в проекте используется 3 разных клока - это уже занимает хилые ресурсы CPLD заметно. я делал такие дизайны, их надо очень подробно отлаживать чтоб заработало, но всеравно их скорость будет уступать синхронным просто потому что она не может быть адекватна посчитана симуляторами. ваш проект скорее всего заработает если вы сведете количество доменов клоков к 2м, и это потребует довольно серьезных размышлений над междоменной синхронизацией. проще всего конечно сделать чисто синхронный дизайн с одним клоком.

 

 

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


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

Спасибо большое за ответы.

сейчас это тихий ужас.

Как, по вашему, будет смотреться дизайн с мастерклоком модуля, разрешаемым декодером адреса (трех входных пинов плис)?

Просто не хотелось бы "шевелить" эту часть вхолостую, если фактически работа с нею происходит раз в сутки.

 

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

 

Да в том и дело, что скорость высокая совсем не требуется. Клоки в реале - не более чем 1МГц. Т.е времена - микросекундные. Рассинхронизация тут, по идее, влиять на должна.

Я грешил на ошибки в алгоритме, которые почему-то не могу увидеть сам.

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


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

Как, по вашему, будет смотреться дизайн с мастерклоком модуля, разрешаемым декодером адреса (трех входных пинов плис)?

Так и будет смотреться, пересадите все асинхронные входные сигналы на системный клок, далее спокойно работайте в одном домене

и будет у вас синхронный дизайн без состояний когда работает, но не совсем.

 

А ужас это вот это

wire ck = spcki | ncsi;
always@(posedge ck)

Вы берете по или два сигнала и используете как клок.

 

А что синтехатор сделает из этого, вообще сложно представить

always@(posedge ncsi)
begin

 

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


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

Так и будет смотреться, пересадите все асинхронные входные сигналы на системный клок, далее спокойно работайте в одном домене

и будет у вас синхронный дизайн без состояний когда работает, но не совсем.

Вы правы, так написать проще всего. Но появятся дополнительные цепочки реклока трех входных сигналов и детекта фронтов, это дополнительные 8..12 LE, которых и так маловато. Поэтому, для начала, хотелось бы попробовать асинхронный дизайн.

 

А ужас это вот это

wire ck = spcki | ncsi;
always@(posedge ck)

Вы берете по или два сигнала и используете как клок.

Возможно, глупый вопрос, но почему это ужас?

Ведь на этом клоке работает единственный регистр, выход которого используется гарантированно больше, чем 500ns, по другому фронту этого же клока.

 

А что синтехатор сделает из этого, вообще сложно представить

always@(posedge ncsi)
begin

Я надеялся, что сделает параллельные регистры, берущие данные с шины из сдвигового регистра приёма mosi, работающие по клоку ncsi, и с энейблами, декодированными из трехбитного адреса. И судя по post-fitting map квартуса, пока синтезируется так.

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

Нужно переписать конструкцию if-else-if как switch-case?

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


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

Вот что-то такое можно оформить в виде таска, и потом при отладке менять адреса и данные...

Ну а "адреса и данные" сделать входами для таска...

 

#(50*ns)ncs=1;

for(addr=0;addr<4;addr=addr+1)

begin

spi_reg<=8'b01010101;

#(50*ns)ncs=0;

for(bitnum=0; bitnum<8; bitnum=bitnum+1)

begin

#(10*ns) spck=1;

#(10*ns) spck=0;

spi_reg<={spi_reg[6:0],1'b0};

end

#(50*ns)ncs=1;

#(50*ns)ncs=1;

end

 

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


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

Подскажите пожалуйста, в чем я мог тут ошибиться.

Или я уже готов плюнуть и сделать синхронный дизайн на мастерклоке в 20МГц с детекторами фронтов клоков шины, как во всех примерах гугла, но это не то, что хотелось.

Можно сделать и асинхронный (т.е. на клоке от spi) если четко понимаете что вам нужно. В вашем коде мне показалось странным вот что :

1. По хорошему MISO при неактивном CS должен быть в Z состоянии.

2. Т.к. у вас читается только регистр состояния, так и сделайте что бы он читался на каждой транзакции. Т.е. берете компонент dffeas (а ваш макс это сыклон 2 по сути), на сигнал aload вешаете CS, по спаду загружаете свой регистр ну и дальше банальная транзакция записи/чтения, т.е. сдвиговый регистр). А отличать запись от чтения, судя по вашему коду, вы будете по адресам (маскируя "лишную" запись). Логика упростится и будет надежно работать (пока наводочки с левыми фронтами на сигналах не появятся ;))

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


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

Обмен происходит изредка и не быстрее мегагерца, поэтому мне показалось неоптимальным постоянно тактовать модуль SPI от быстрого системного клока ПЛИС.

А чем по Вашему такое решение неоптимально в этом случае если есть такая возможность?

Делать SPI от внешнего клока имеет смысл только если нет возможности привязатть к внутреннему клоку (напр. он сравним по скорости с SPI, или его нет )

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


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

А чем по Вашему такое решение неоптимально

Характер потребления плис по питанию будет мягче для асинхронного дизайна за счёт разновременности переключения отдельных логических элементов.

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

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

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

 

dffeas на сигнал aload вешаете CS

Элемент dffeas не решает задачу, потому что он работает не по фронту, а по уровню aload. Ему необходим детектор фронта.

 

Суть задачи именно в этом и состоит: нужен D-триггер с двумя защелкивающими входами (и с двумя входами данных, соответствующих им).

Возможен ли такой элемент вообще?

И чтобы

а)без явных детекторов фронтов на элементах задержки(на Д-триггерах синхронных мастерклоку, либо на цепочках lcell)

б)без дополнительной внутренней памяти некоего автоматного состояния

в)без использования аппаратно-специфичных примитивов (на синтезируемом Верилоге, например)

 

Можете ли посоветовать литературу на эту тему?

 

 

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


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

Элемент dffeas не решает задачу, потому что он работает не по фронту, а по уровню aload. Ему необходим детектор фронта.

Вашу задачу решает прекрасно. Вы читаете один регистр статуса.

 

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


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

Вашу задачу решает прекрасно. Вы читаете один регистр статуса.

 

Простите, я не понимаю, как.

(Сколько регистров передаём - не суть, пусть даже всего один читаем, и всего один пишем, я согласен на это)

Но Dffeas, судя по таблице истинности описания примитива в /modelsim_ase/.../maxii_atoms.v при установленном Aload становится в режим прозрачности, повторяя Adata на выходе. И не реагирует на D и Clk, пока Aload не снимется.

Если подать CS на Aload, то регистр проигнорирует любое остальное шевеление на шине SPI, хотя именно тогда идут нужные данные.

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


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

Простите, я не понимаю, как.

Может быть я вашу задачу не понял, но сами смотрите :

`timescale 1ns/1ns

module pipa (input clk, input cs_n, sclk, mosi, output miso, input [1 : 0] addr, output logic [1 : 0] leds [2]);

 logic [7 : 0] sreg, sreg_next;
 logic [7 : 0] status_cnt;

 //------------------------------------------------------------------------------------------------------
 // spi
 //------------------------------------------------------------------------------------------------------
/*
 always_ff @(posedge sclk or posedge cs_n) begin // not correctly dffeas (!!!!)
   if (cs_n)
     sreg <= status_cnt;
   else
     sreg <= (sreg << 1) | mosi;
 end
*/

 assign sreg_next = {sreg[6:0], mosi};

 generate
   genvar i;
   for (i = 0; i < 8; i++) begin : popa_inst
     dffeas
     popa
     (
       .clk    ( sclk           ) ,
       .d      ( sreg_next [i]  ) ,
       .ena    ( 1'b1           ) ,
       .asdata ( status_cnt [i] ) ,
       .aload  ( cs_n           ) ,
       .q      ( sreg       [i] )
     );
   end
 endgenerate

 assign miso = !cs_n ? sreg[7] : 1'bz;

 //------------------------------------------------------------------------------------------------------
 // spi decode
 //------------------------------------------------------------------------------------------------------

 always_ff @(posedge cs_n) begin
   leds[addr] <= sreg[1:0];
 end

 //------------------------------------------------------------------------------------------------------
 // status cnt
 //------------------------------------------------------------------------------------------------------

 always_ff @(posedge clk) begin
   status_cnt <= status_cnt + 1'b1;
 end

endmodule

// synthesis translate_off
module tb ;

 bit         clk, cs_n, sclk, mosi, miso;
 bit [1 : 0] addr;
 logic [1 : 0] leds [2];

 pipa popa (.*);

 initial begin
   forever #50ns clk = ~clk;
 end

 const int N = 5;

 initial begin
   bit [7 : 0] rtmp;
   init_spi(100ns);
   for (int i = 0; i < N; i++) begin
     do_spi(10+i, i, rtmp, 50ns);
     $display("%0d write %0d read %0d", i, 10+i, rtmp);
   end
   $stop;
 end

 //------------------------------------------------------------------------------------------------------
 //
 //------------------------------------------------------------------------------------------------------

 time T = 10ns;

 task init_spi (time delay = T);
   cs_n <= 1'b1;
   sclk <= 1'b0;
   mosi <= 1'b0;
   #delay;
 endtask

 task do_spi (bit [7 :0] wdat = 0, addr = 0, output bit [7:0] rdat, input time delay = T);
   cs_n <= 1'b0;
   addr <= addr;
   #(T/2);
   for (int i = 0; i < 8; i++) begin
     sclk <= 1'b0;
     mosi <= wdat[7-i];
     rdat <= (rdat << 1) | miso;
     #(T/2);
     sclk <= 1'b1;
     #(T/2);
   end
   #(T/2);
   sclk <= 1'b0;
   cs_n <= 1'b1;
   #delay;
 endtask

endmodule
// synthesis translate_on

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


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

смотрите :

 

Сразу стало ясно. Прозрачность рабочего регистра spi для выходных данных слейва по ald=nCS=1 в покое и сдвигание данных по slck при транзакции.

Просто блестящая в своей простоте идея.

Спасибо.

 

Моя проблема в том, что я хотел описать на верилоге, чтобы тот же код использовать ещё и для max3000/7000.

но теперь стало ясно, для начала надо вдумчиво изучить Алтеровский "Coding Guidelines"

 

Вот было интересное обсуждение около года назад на тему "dffea -- verilog"

http://electronix.ru/forum/index.php?s=&am...t&p=1276608

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


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

Товарищи, подскажите, у меня есть проект SPI синхронного от внутреннего генератора. Регитр состояния и регистр значения (4 байта) сделан на verilog обычным reg [7:0]. На MAX II работает нормально. А вот при портирования проекта на Lattice дурят значения регистров, если вставляю в CASE четыре альтернативы все плывет, а если две то работате нормально...

 

В симуляции смотрел все отлично, да и до этого на MAX II все проверял... в чем может быть загвоздка? Такое ощущение, что разводке что-то оптимизируется или усекается...

 

под словои "дурит" понимается, что когда в коде написано data_sent <= 32'hDEADBEEF; на порт выходит что-то не понятное, а когда работает, то нормально на порту выходит это значение

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


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

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

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

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

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

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

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

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

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

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