Verilog SPI slave ontwerp

Beste,

Ik ben weer eens wat aan het spelen met FPGA's. Nu heb ik hier bijzonder weinig ervaring mee, maar met wat simuleren en veel zoeken online lukt het aardig. Nu ben ik een SPI slave interface aan het maken, puur ter leering en vermaak. Ik heb 2 verschillende implementaties en ik vraag me af of hier doorgewinterde specialisten zitten die eens willen kijken of het een beetje oke is zo.

Ik gebruik trouwens dit om te testen: http://digitaljs.tilk.eu/

Ontwerp 1.
Wat ik hier zelf een nadeel aan vind, is het ophogen van de 'cnt' en het vergelijken in dezelfde edge. Ik weet niet of het verstandig is om op de propagatie delay van het systeem te vertrouwen.

verilog code:


module Spi (
    input clk,
    input cs,
    input sck,
    input mosi,
    output reg miso,
    input [7:0] dataIn,
    output reg [7:0] dataOut,
    output reg dataClk
);


reg sSCK, sCS, sMOSI;
always @(posedge clk) begin
    sSCK <= sck;
    sCS <= cs;
    sMOSI <= mosi;
end

reg [2:0] cnt;
reg [7:0] dataBuf;
always @(posedge sSCK or posedge sCS) begin
    if(sCS) begin
        cnt <= 3'b000;
        dataClk <= 0;
    end else begin
        cnt <= cnt + 1;
        dataOut <= {dataOut[6:0], sMOSI};
        dataClk <= (cnt==3'b111);
        if(cnt == 3'b000) begin
            dataBuf <= dataIn;
        end else begin 
            dataBuf <= {dataBuf[6:0], 1'b1};
        end
    end
end

always @(negedge sSCK) begin
    miso <= dataBuf[7];
end

endmodule

In de tweede implementatie los ik dit zo op:

verilog code:


always @(posedge sSCK) begin
  	if(~sCS) begin
		dataOut <= {dataOut[6:0], sMOSI};
        dataClk <= (cnt==3'b111);
        if(cnt == 3'b000) begin
            dataBuf <= dataIn;
        end else begin 
            dataBuf <= {dataBuf[6:0], 1'b1};
        end
    end
end

always @(negedge sSCK or posedge sCS) begin
  	if(sCS) begin
        cnt <= 3'b000;
    end else begin
        cnt <= cnt + 1;
        miso <= dataBuf[7];
    end
end

Kan iemand hier wat tips geven wat hier goed of fout aan zou zijn?

PE2BAS

Ik weet niks van verilog. :)

Maar een SPI doet normaal data update na de opgaande flank van de klok, en inlezen op de neergaande flank (of net andersom). Dan heb je dus altijd een halve klok as propagation delay en zit je altijd safe.

Arco

Special Member

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com

Ik lees de data hier ook ik op de opkomende flank van SCK. Mode 0 dus. En ik schrijf data op de neergaande flank van SCK. Dat zit wel goed, ik doelde meer op dit stukje. Hier wordt cnt opgehoogd en ook vergeleken. Het lijkt me dat dit gevoelig is voor race condities.

vhdl code:


cnt <= cnt + 1;
if(cnt == 3'b000) begin
    dataBuf <= dataIn;
end else begin 
    dataBuf <= {dataBuf[6:0], 1'b1};
end

Wellicht nog even afwachten op iemand die veel met hdl werkt. :)

PE2BAS

Ik denk dat het werkt.

Gebruikelijk is dat je buffer register vanuit de input (vanaf de rest van je ontwerp) gevuld wordt en dat ie aangevuld wordt met de MOSI bitjes. Niet zoals bij jou met "1". Vervolgens kan je het output register (naar de rest van je ontwerp) op cnt == 7 updaten.

Ik zou zelf kiezen voor @posedge CS cnt <= 0; Klaar!

Los daarvan een @posedge ssck blok. Hmm. heb ik nu een bug gevonden? Er gaan denk ik dingen gebeuren als je met CS gaat lopen wiebelen. Misschien valt het mee. Het tellen lukt natuurlijk niet als je de count steeds reset op de positieve edges.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Ik denk dat ik het, maar gewoon ga proberen. Ook kan ik me goed voorstellen dat er meerdere wegen naar Romé zijn die niet per se fout of goed zijn.

Ik heb wat moeite om je reactie goed te begrijpen.

"Gebruikelijk is dat je buffer register vanuit de input ..."
Dit gebeurt toch ook? Die vullen met 1 is enkel bij het uitklokken.

"@posedge CS cnt <= 0;"
Dit mag denk ik niet, aangezien ik dan naar CNT schrijf vanaf 2 verschillende triggers. Namelijk CS voor resetten en sSCK voor het optellen.

"Los daarvan een @posedge ssck blok."
Het idee is dat de sXXX signalen synchroon zijn met de systeem clock. Dus ik gebruik de sSCK voor het in en uit klokken van de mosi en miso.

PE2BAS

Je hebt nu 16 "register" bits. 8 aan de input kant 8 aan de output kant. Van ieder van deze twee is een deel "don't care" gedurende de transfer. Je kan de helft van de resgister bits besparen door de ongebruikte van de ene voor de andere te gebruiken.

verilog code:


reg [7:0] dataBuf;
reg tmp;
always @(posedge sSCK) begin
   dataBuf <= {dataBuf[6:0], MOSI};
   tmp <= dataBuf[7];
end
always @(negedge sSCK) begin
    miso <= tmp;
end

Plus dan nog de stuff voor de IO naar "intern"

Had ik al gezegd dat ik 30 en 20 jaar geleden wat met die andere HDL heb gewerkt... "arbitraire keuze" tussen verilog en die andere.

Tien jaar terug heb ik even wat in verilog geprobeerd en heb besloten dat als ik het ooit weer ga doen, dan blijf ik bij verilog. Wat een verademing vergeleken bij die andere. Maar ik heb er dus nooit veel mee gedaan, en minstens tien jaar al niets.

In bovenstaande code had ik eerst miso <= dataBuf[7]; staan. (zonder tmp). Toen dacht ik: Dat gaat natuurlijk nooit werken, die is overschreven voordat je hem nodig hebt. Maar als de posedge en negedge in andere volgorde komen dan werkt het juist eerst wel en nu niet meer. Het zou kunnen dat het te maken heeft met de verschillende SPI modes....

[Bericht gewijzigd door rew op donderdag 27 juli 2023 12:30:50 (16%)

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Die andere mag je gerust bj naam noemen: VHDL :)

VHDL hadden wij op school, dat was ook zomaar een vak van een paar uur 1 kwartaal lang. In mijn opinie veel te kort om echt wat te leren. Het doel was ook meer "dan heb je gezien dat het bestaat" i.p.v. echt leren hardware ontwerpen.

Mijn keuze voor Verilog is heel simpel: de examples van het bordje zijn in Verilog. Ook vind ik dat je in VHDL veel dingen dubbel moet uitschrijven. Dat vind ik dan alleen maar onhandig.

Ik zie ook veel andere dingen voorbij komen zoals scala en Amarant. Maar daar durf ik me nu nog niet te veel aan te wagen. Eerst maar eens de basis begrijpen.

Verder denk ik dat ik het wel begrijp. Het ontbreekt een beetje aan tijd, maar ik wil het wel beter kunnen. Eigenlijk moet ik de baas eens overtuigen dat wij FPGA's absoluut nodig hebben. :+

PE2BAS

VHDL is niet echt veel lastiger om te leren. Een voordeel van Verilog is dat het minder abstract is en korter bij de hardware staat.
Als je eenmaal door hebt hoe je in VHDL registers, buffers, etc, en state machines beschrijft en dat alles synchroon met een of meerdere clock signalen doet dan is VHDL best gemakkelijk. VHDL wordt door velen als moeilijk ervaren omdat de taal abstracter is dan Verilog en dat de leercurve van VHDL langer is.

Ik begrijp je keuze voor Verilog.

Op 27 juli 2023 12:50:10 schreef Bobosje:
Die andere mag je gerust bj naam noemen: VHDL :)

Ohja , zo heet dat. Kon even niet op de naam komen.

Op 27 juli 2023 13:22:01 schreef hardbass:
Ook vind ik dat je in VHDL veel dingen dubbel moet uitschrijven. Dat vind ik dan alleen maar onhandig.

Precies. Dat was ook mijn bezwaar tegen VHDL. Gewoon echt dingen waarvan je denkt: Heeft het NUT dat ik het driekeer uit moet schrijven (in een header ergens, en dan in iedere module weer twee keer, dacht ik.

[Bericht gewijzigd door rew op donderdag 27 juli 2023 15:03:05 (52%)

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Op 25 juli 2023 16:03:31 schreef hardbass:
...Hier wordt cnt opgehoogd en ook vergeleken. Het lijkt me dat dit gevoelig is voor race condities.

vhdl code:


cnt <= cnt + 1;
if(cnt == 3'b000) begin
    dataBuf <= dataIn;
end else begin 
    dataBuf <= {dataBuf[6:0], 1'b1};
end

Dit is een volledig normale en legale constructie die 0.0 foutgevoelig is. Je beschrijft een rijtje FFs (flipflops) waar de volgende state steeds de huidige waarde +1 is. Tegelijkertijd vergelijk je de huidige stand met een constante. Teken het maar uit, dan zie je dat het niet kan.
Misschien maak je deze vergissing: het is dus niet dat eerst cnt verhoogd wordt en vervolgens je de vergelijking doet. Het gebeurt tegelijk, op dezelfde clk flank.
(dit mechanisme heet scheduling in hdl, zelfde in VHDL)

"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein

Kijk top, dan is dat ook duidelijk. Ik weet dat ze tegelijk gebeuren, maar ik dacht, als de logica van de count ophogen net iets sneller is dan de logica van het vergelijken dan gaat het dus fout.

Maar daar hoef ik me dan geen zorgen over te maken.

PE2BAS

code:


  register cnt output ---- A-adder adder output register cnt input
                    1 ---- B-adder 

  register cnt output ---- A isgelijk isgelijk output --->
                    0 ---- B isgelijk

   isgelijk output -- SELinput selector
   datain          -- in indien1 selector  selector out -> datbuf input
   databuf[6:0], 1 -- in indien0 selector 

Dat is de logica die hij bouwt.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Op 28 juli 2023 08:05:58 schreef hardbass:
..ik dacht, als de logica van de count ophogen net iets sneller is dan de logica van het vergelijken dan gaat het dus fout.

Daar zorgt de synthese tool voor dat dat nooit zal gebeuren. Alles wat op 1 clk loopt wordt als een berg synchrone logica gezien, en dan wordt voorkomen waar je bang voor bent.

"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein

Wat je beschrijft in Verilog of VHDL dat komt ook uit je synthese tool. Een synchrone beschrijving wordt een synchroon circuit en een asynchrone beschrijving een asynchroon circuit na synthese. Het synthese tool maakt van een Verilog of VHDL beschrijving niet automatisch een synchroon circuit / design.

Op 28 juli 2023 18:49:03 schreef Bobosje:
..Het synthese tool maakt van een Verilog of VHDL beschrijving niet automatisch een synchroon circuit / design.

Ik weet niet of je specifiek op mijn antwoord reageert, maar ik had het over "alles wat op 1 clk loopt". Daarbij krijg je synchrone logica. Althans, ik kan me zo niet bedenken dat je iets asynchroons krijgt bij 1 clk.

"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein

Het was geen specifieke reactie maar een algemene.
Door foutieve constructies in de Verilog of VHDL beschrijving kun je na synthese iets asynchroons krijgen terwijl je het synchroon had bedoeld.

Dan heb ik ook nog een algemene: geen fouten maken :-)

"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein

Op 28 juli 2023 19:43:24 schreef flipflop:
[...]
Ik weet niet of je specifiek op mijn antwoord reageert, maar ik had het over "alles wat op 1 clk loopt". Daarbij krijg je synchrone logica. Althans, ik kan me zo niet bedenken dat je iets asynchroons krijgt bij 1 clk.

Er is natuurlijk een stukje asynchroon van de "isgelijk" naar de selector

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Die snap ik niet. Selector? wasda?

Ik had verder niet naar de code gekeken. Op zich vind ik dat wat vreemd in elkaar zitten. Op clk wordt eerst de input interface signalen ingeclocked. Die registers gebruik je dan om de eigenlijke slave functie te doen. Ik zou dat gewoon direct op de inkomende sclk doen. En dan synchroniseren naar een interne fpga clock.
De sclk krijg je binnen waar de data aan de master kant ook mee verstuurd is, dus daar kun je het ook weer mee inklokken aan de slave kant.

PS, simuleren in Modelsim oid moet je gewoon doen. Dan zie je veel meer dan in de code staren.

"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein

Selector/multiplexer.

Voor iedere data-input van de "databuf" flipflops zit een multiplexer die OFWEL het bitje van databuf 1 verschoven, ofwel "datain" aanbiedt.

@flipflop: Aan de specs van de SPI en I2C modules van Atmel (nu microchip) kan je zien dat zij het ook precies zo doen. Het heeft voordelen. Maar het heeft ook zo z'n nadelen. Bij de Atmels bijvoorbeeld als je de interne klok zo configureerd dat ie het "niet doet" (b.v. externe klok configureren terwijl die er niet aanhangt), dan kan je ook niet meer via SPI de chip benaderen om de config te veranderen.....

[Bericht gewijzigd door rew op maandag 31 juli 2023 11:48:24 (32%)

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Ah, een mux. De term selector ben ik in m'n hele cariere nog niet tegengekomen voor een mux, maar goed, what's in a name. Er zitten meerderen muxen in trouwens. Ook nog eentje voor cnt.

Wb m'n opmerking in m'n vorige post, dat was over de 1e poging. Daar gaat ie eerst naar een intern domein clk. Da's niet goed. Dat rijtje FFs gaat metastabiel worden als je pech hebt. De 2e poging is wel goed wat dat betreft (had ik over het hoofd gezien). Uiteraard moet je nog wel naar een intern domein uiteindelijk.

"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein