📄 i2cslave.tdf
字号:
% module I2CSLAVE --------------- version : 3.1 date : Nov 2, 2004 author : Frank Budzelaar Summary ------- This module implements an i2c slave with the following features: - 7-bit address support only - programmable I2C slave address - subaddressing support: - 1 to 16 bit subaddresses - autoincrement of the subaddress - no general call handling - clock stretching support By using this module together with the other i2c components in this package, i2c controlled systems can be implemented very rapidly, and with a minimum of hassle. Parameters ---------- SLAVEADDRESS NOSUBADRESS : 1 / 0 If set to 1, no subaddressing is done. As the original slave core makes heavy use of subaddressing, this is a bit of a cludge: SUBADDRESSBITS must be set to 1 (or higher), so there is still a subaddress bus, but the address on it will always be 0. the slave core will now pass all databytes directly to address 0. SUBADDRESSBITS : 1..16 The number of subaddress bits to use. If the number of subaddressbits is 8 or lower, one subaddress byte is expected as first data byte during a write operation. If the number is higher, two subaddress bytes are expected. The first byte holds the MSBs. DEBUGMODE As a bidirectional bus with pull-ups is very difficult to simulate, a debug mode helps in debugging an application. This debug mode is enabled by parameter DEBUGMODE=1. Non debug mode: scl, sda: bidirectional I2C pins sclout, sdaout: not used Debug mode: scl, sda: input sclOut, sdaOut: outputs, driven with the active bits generated by the slave itself. Interface --------- General interface ----------------- clk: INPUT A clock which is at least 5 times the i2c speed i2c interface ------------- sda: BIDIR standard bidirectional i2c SDA line scl: BIDIR standard bidirectional i2c SCL line internal i2c interface ---------------------- All signals are bundled into one bus for easy of use: this starts at the i2c slave, flows through each i2c subdevice, and returns to the i2cslave. The internal structure of this bus is of no concern to the user. [0] clk [1] wr [2] rd [3] wait [11..4] data in [19..12] data out [I2CBUSWIDTH-1..20] address i2cBusOut[I2CBUSWIDTH-1..0]: OUTPUT; The output bus i2cBusIn[I2CBUSWIDTH-1..0]: INPUT; The input bus%INCLUDE "medianFilter";PARAMETERS ( SUBADDRESSBITS=1, NOSUBADDRESS=1, WAITSTATES=4, DEBUGMODE=0 );CONSTANT SUBADDRESSBYTES = SUBADDRESSBITS > 8 ? 2 : 1;CONSTANT I2CBUSWIDTH = SUBADDRESSBITS+20; -- address, data in, data out, wait, read, write, clk -- order: -- [0] clk -- [1] wr -- [2] rd -- [3] wait -- [11..4] data in -- [19..12] data out -- [I2CBUSWIDTH-1..20] addressSUBDESIGN i2cSlave ( -- system clk: INPUT; -- i2c side sda: BIDIR; scl: BIDIR; slaveAddress[7..1]: INPUT; -- internal side i2cBusOut[I2CBUSWIDTH-1..0]: OUTPUT; i2cBusIn[I2CBUSWIDTH-1..0]: INPUT; -- debug sdaOut: OUTPUT; -- debugging only: ignore sclOut: OUTPUT; -- debugging only: ignore dummyOut: OUTPUT; -- just used to get rid of warnings: ignore )VARIABLE sdan,sdap,scln,sclp: DFF; start,stop,bitStart,bitStop: NODE; bitCounter[3..0]: DFF; byteCounter[1..0]: DFFE; shiftInReg[7..0]: DFFE; shiftOutReg: DFFE; addressed: DFF; address[SUBADDRESSBITS-1..0]: DFFE; wait: NODE; waitff: DFF; read: DFFE; wr: DFF; rd: DFF; prevAct: DFF; sdaMedian,sclMedian: medianFilter WITH (length=6); forceSclLow: NODE; forceSdaLow: NODE; IF (WAITSTATES!=0) GENERATE waitCounter[CEIL(LOG2(WAITSTATES+1))-1..0]: DFF; END GENERATE;BEGIN-- scl and sda clocking, edge detectionsdaMedian.clk=clk;sdaMedian.in=sda;sdan.clk=clk;sdan=sdaMedian.out;sdap.clk=clk;sdap=sdan;sclMedian.clk=clk;sclMedian.in=scl;scln.clk=clk;scln=sclMedian.out;sclp.clk=clk;sclp=scln;start=!sdan & sdap & scln;stop=sdan & !sdap & scln;bitstart=scln & !sclp;bitstop=!scln & sclp;-- data bit counter: 0..8-- the bit counter is set to 15 on a start condition-- and incremented on negative edge of scl-- this means that the bit counter indicates the bit nr during-- the preceding low and subsequent high scl period of the bit-- code 0 means data bit 7-- code 7 means data bit 0-- code 8 means ack bitbitCounter[].clk=clk;IF (start) THEN bitCounter[]=15;ELSIF (bitStop) THEN IF (bitCounter[]==8) THEN bitCounter[]=0; ELSE bitCounter[]=bitCounter[]+1; END IF;ELSE bitCounter[]=bitCounter[];END IF;-- data byte counter: 0..3 (3 means 3 or more)-- the byte counter is cleared on a start condition-- and incremented on negative edge of ackbyteCounter[].clk=clk;IF (start) THEN byteCounter[]=0;ELSE IF ((bitCounter[]==8) & bitStop & byteCounter[]!=3) THEN byteCounter[]=byteCounter[]+1; ELSE byteCounter[]=byteCounter[]; END IF;END IF;-- data input shift register-- data is shifted in on every bit start-- During a read, the shiftInReg is misused to-- shift out the data to the processor.shiftInReg[].clk=clk;shiftInReg[].ena=bitStart # rd;IF (rd) THEN shiftInReg[]=i2cBusIn[19..12];ELSE shiftInReg[]=(shiftInReg[6..0],sdan);END IF; shiftOutReg.clk=clk;shiftOutReg.ena=bitStop;shiftOutReg=shiftInReg[7];-- address recognition-- the addressed bit is cleared on every start and stop condition,-- and will be updated on reception of the last bit of the first byte-- of a transferaddressed.clk=clk;addressed=((addressed & !start & !stop) & -- not a read with no ack !(read & bitCounter[]==8 & bitStart & sdan)) # -- Address matches in first byte (bitStart & bitCounter[]==6 & byteCounter[]==0 & (shiftInReg[5..0],sdan)==slaveAddress[]);-- read/write mode logic-- the addressed bit will be updated on reception of the read bit -- in the first byte of the transferread.clk=clk;read.ena=bitStart & bitCounter[]==7 & byteCounter[]==0;read=sdan;-- subaddress logic-- the sub address will be loaded at the second and third byte of the write-- and it is incremented:-- during a write: -- during a read:address[].clk=clk;IF (addressed) THEN IF (NOSUBADDRESS==1) GENERATE address[]=0; -- address is always 0 ELSE GENERATE IF (SUBADDRESSBYTES==2) GENERATE IF (!read & byteCounter[]==1 & bitCounter[]==7 & bitStop) THEN address[SUBADDRESSBITS-1..8]=shiftInReg[SUBADDRESSBITS-1-8..0]; address[7..0]=address[7..0]; ELSIF (!read & byteCounter[]==2 & bitCounter[]==7 & bitStop) THEN address[7..0]=shiftInReg[]; address[SUBADDRESSBITS-1..8]=address[SUBADDRESSBITS-1..8]; ELSE -- increment on negative egdes of rd and write IF (prevAct & !(rd # wr)) THEN address[]=address[]+1; ELSE address[]=address[]; END IF; END IF; END GENERATE; IF (SUBADDRESSBYTES==1) GENERATE IF (!read & byteCounter[]==1 & bitCounter[]==7 & bitStop) THEN address[SUBADDRESSBITS-1..0]=shiftInReg[SUBADDRESSBITS-1..0]; ELSE -- increment on negative egdes of rd and write IF (prevAct & !(rd # wr)) THEN address[]=address[]+1; ELSE address[]=address[]; END IF; END IF; END GENERATE; END GENERATE;ELSE address[]=address[];END IF;-- write logic-- a write to the internal registers occurs at the negative edge of -- scl of the last data bit.-- as a wait will keep scl low, no new data can shift into the -- shift registerwr.clk=clk;IF (NOSUBADDRESS==1) GENERATE wr=addressed & ((!read & byteCounter[]>=1 & bitCounter[]==7 & bitStart) # (wr & wait));ELSE GENERATE IF (SUBADDRESSBYTES==1) GENERATE wr=addressed & ((!read & byteCounter[]>=2 & bitCounter[]==7 & bitStart) # (wr & wait)); END GENERATE; IF (SUBADDRESSBYTES==2) GENERATE wr=addressed & ((!read & byteCounter[]>=3 & bitCounter[]==7 & bitStart) # (wr & wait)); END GENERATE;END GENERATE;-- read logic-- a read occurs at each negative edge of a positive ack.-- this includes the positive ack on the first byte (!)rd.clk=clk;rd=addressed & ((read & bitCounter[]==8 & bitStart & !sdan) # (rd & wait));-- used to detect negative of wr or rd: will increment address counterprevAct.clk=Clk;prevAct=wr # rd;-- wait logicwaitff.clk=clk;waitff=(waitff # bitStop) & (addressed & (rd # wr));-- scl and sda out logicforceSclLow=waitff;forceSdaLow=addressed & -- ack bits ( (bitCounter[]==8 & (byteCounter[]==0 # !read)) # -- data bits during read (read & byteCounter[]!=0 & bitCounter[]!=8 & !shiftOutReg));IF (debugmode==0) GENERATEscl=tri(.in=gnd, .oe=forceSclLow);sda=tri(.in=gnd, .oe=forceSdaLow);sclOut=Gnd;sdaOut=Gnd;END GENERATE;IF (debugmode==1) GENERATEscl=tri(.in=gnd, .oe=gnd);sda=tri(.in=gnd, .oe=gnd);sclOut=!forceSclLow;sdaOut=!forceSdaLow;END GENERATE;-- wait state generatorIF (WAITSTATES!=0) GENERATE waitCounter[].clk=clk; IF (rd # wr) THEN IF (waitCounter[]>0) THEN waitCounter[]=waitCounter[]-1; ELSE waitCounter[]=waitCounter[]; END IF; ELSE waitCounter[]=WAITSTATES; END IF; wait=i2cBusIn[3] # waitCounter[]!=0;END GENERATE;IF (WAITSTATES==0) GENERATE wait=i2cBusIn[3];END GENERATE;-- interfacei2cBusOut[0]=clk;i2cBusOut[1]=wr;i2cBusOut[2]=rd;i2cBusOut[3]=Gnd; -- wait: ignore;i2cBusOut[11..4]=shiftInReg[7..0]; -- data outi2cBusOut[19..12]=h"FF"; -- data In: ignore;i2cBusOut[I2CBUSWIDTH-1..20]=address[];dummyOut=i2cBusIn[I2CBUSWIDTH-1..0]==0;END;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -