【黑金原創教程】【FPGA那些事兒-驅動篇I 】實驗十七:IIC儲存模塊 - FIFO讀寫


1. int main()

2. {

3. int A;

4. A = 165. }

代碼17.1

話題為進入之前,首先讓我們來聊聊一些題外話。那些學過軟核NIOS的朋友可曾記得,軟核NIOS可利用片上內存作為儲存資源,而且它也能利用SDRAM作為儲存資源,然而問題是在這里 ... 如代碼17.1所示,筆者先建立變量A,然后變量A賦值16。如果站在高級語言上的角度去思考,無論是建立變量A還是為變量A賦值,我們沒有必要去理解變量A利用什么儲存資源,然后賦值變量A又是利用怎樣的儲存功能去實現。

我們只要負責輕松的表層工作,然而那些辛苦的底層工作統統交由編譯器處理。讀者也許會認為那是高級語言的溫柔,不過這股溫柔卻不適合描述語言,還不如說那是一種抹殺性的傷害。這種感覺好比父母親過度溺愛自己的孩子,嬌生慣養的孩子最終只會失去可能性而已。

筆者曾在前面說過,儲存模塊基本上可以分為“儲存資源”還有“儲存方式”。默認下,描述語言可用的儲存資源有寄存器還有片上內存,然而兩者都是內在資源。換之,實驗十六卻利用外在的儲存資源,IIC儲存器。

clip_image002

圖17.1 IIC儲存模塊與RAM儲存模塊。

如圖17.1所示,那是實驗十六的IIC儲存模塊,然而圖17.1也表示IIC儲存模塊的調用方法也不僅近似 RAM儲存模塊,而且只有一方調用它而已。這種感覺好比順序語言的主函數調用某個儲存函數一樣,結果如代碼17.2所示:

1. int ram_func( int Addr, int WrData ) { ... }

2.

3. int main()

4. {

5. ram_func( 020 );

6. ...

7. }

代碼17.2

如代碼17.2所示,第1行聲明函數 ram_func,然后主函數在第5行將其調用,並且傳遞地址參數0,數據參數 20。高級語言是一位順序又寂寞的家伙,函數永遠只能被一方調用而已 ... 換之,描述語言是一位並行又多愁的家伙,模塊有可能同時被兩方以上調用,情況宛如兩位男生同時追求一位少女,對此少女會煩惱選擇誰。哎~這是奢侈的少女憂愁。

clip_image004

圖17.2 雙口RAM儲存模塊。

如圖17.2所示,RAM儲存模塊同時被兩方調用,周邊操作為它寫入數據,核心操作則為它讀出數據。圖17.2也是俗稱的雙口RAM。對此,我們也可以說雙口RAM儲存模是RAM儲存模塊的亞種。

clip_image006

圖17.3 基於雙口RAM儲存模塊的FIFO儲存模塊。

此外,雙口RAM儲存模塊只要稍微更換一下馬甲,然后加入一些先進先出的機制,隨之基於雙口RAM儲存模塊的FIFO儲存模塊便完成,結果如圖17.3所示。對此,我們可以說FIFO儲存模塊是雙口RAM儲存模塊的亞種。

那么問題來了:

“請問,實驗十六的IIC儲存模塊是否也能成為雙口IIC儲存模塊?”,筆者問道。

“再請問,它還可以成為有FIFO機制的儲存模塊呢?”,筆者再問道。

沒錯,上述問題就是實驗十七的主要目的。如果這些要求可以成真,我們便可以斷定描述語言不僅不遜色與順序語言,描述語言也充滿許多可能性,而且儲存類作為一個模塊類有着舉足輕重的地位。廢話少說,我們還是開始實驗吧,因為筆者已經壓抑不了蛋蛋的沖動!

首先我們要明白,片上內存是效率又優秀的儲存資源,基本上只要1個時鍾就可完成讀寫操作,而且讀寫也可以同時進行,兩方也可以同時調用,不過就是不能隨意擴充。反之,IIC儲存器雖然可以隨意擴充,但是又笨又麻煩的它,讀寫操作不僅用時很長,而且不能也同時進行,對此造就兩方不能同時調用的問題。為此,我們必須先解決這個問題。

clip_image008

圖17.4 寫操作與讀操作。

實驗十六告訴我們,IIC儲存模塊有兩位 Call 信號,其中 Call[1] 表示寫操作,Call[0]表示讀操作。不過不管是寫操作還是讀操作,IIC儲存模塊都必須調用IIC儲存器,而且讀寫操作一次也只能進行其中一項。如圖17.4,假設左邊的周邊操作負責寫操作,右邊的核心操作負責讀操作 ... 如果兩者同時拉高 Call 信號就會發生多義性的問題,對此筆者該如何協調呢?

clip_image010

圖17.5 輪流協調。

為了公平起見,筆者采取輪流的方式來協調多義性的問題。圖17.5所是輪流協調的概念圖,一般Call兼職“提問與使能“,即Call一拉高操作便執行。如今Call信號作為第一層提問,isDo則作為第二層使能 ... 換句話說,不管 Call 拉不拉高,只要isDo不拉高,操作也不會執行。如圖17.5所示,isDo位寬有3表示模塊有3種操作,或者說3個操作共享一個模塊資源。至於右邊是稱為使能指針的箭頭,它的作用是給予使能權。

clip_image012

圖17.6 輪流協調例子①。

如圖17.6所示,假設 Call[2] 拉高以示提問,但是指針並沒有指向它,所以它沒有使能權也不能執行操作。這種情況好比舉手的學生沒被老師點名,這位學生就不能隨意開口。當然,使能指針也不是靜止不動,只要遇見有人舉手提問,它便會按照順序檢測各個對象。

clip_image014

圖17.7 輪流協調例子②。

如圖17.7所示,當指針來到Call[2]的面前並且給予使能權,isDo[2]立即拉高使能操作,直至操作完成之前,該操作都享有模塊的使用權。(灰度指針為過去,黑色指針為現在)

clip_image016

圖17.8 輪流協調例子③。

如圖17.8所示,操作執行完畢之際,模塊便會反饋完成信號以示結束操作,isDo[2] 還有Call[2] 都會經由完成信號拉低內容。此外,指針也會立即指向下一個對象。

clip_image018

圖17.9 輪流協調例子④。

如圖17.9所示,假設 Call[2] 還有 Call[1] 同時提問,由於指針沒有指向它們,所以Call[2] 與 Call[1] 都沒有使能權。此刻,指針開始一動。

clip_image020

圖17.10 輪流協調例子⑤。

首先,Call[1] 會得到使能權,isDo[1]因此拉高並且開始執行操作,直至操作結束之前,isDo[1]都獨占模塊,結果如圖17.10所示。

clip_image022

圖17.11 輪流協調例子⑥。

如圖17.11所示,當操作執行完畢,模塊便會反饋完成信號,隨之isDo[1] 還有 Call[1]都會拉低內容,而且指針也會指向下一個對象。對此,isDo[2] 得到使能權,並且開始執行操作 ... 直至操作結束之前,它都獨占模塊。

clip_image024

圖17.12 輪流協調例子⑦。

操作結束之際,模塊便會反饋完成信號,isDo[2] 還有 Call[2] 隨之也會拉低內容,然后指針指向另一個對象,結果如圖17.12所示。輪流協調的概念基本上就是這樣而已,即單純也非常邏輯。接下來,讓我們來看看Verilog 如何描述輪流協調,結果如代碼17.3所示:

1. module iic_savemod

2. (

3. input [1:0]iCall,

4. output [1:0]oDone,

5. );

6. reg [1:0]C7;

7. reg [1:0]isDo;

8.

9. always @ ( posedge CLOCK or negedge RESET )

10. if( !RESET ) 

11. begin 

12. C7 <= 2’b10;

13. isDo <= 2’b00;

14. end

15. else 

16. begin

17. if( iCall[1] & C7[1] ) isDo[1] <= 1’b1;

18. else if( iCall[0] & C7[0] ) isDo[0] <= 1’b1;

19.

20. if( isDo[1] & isDone[1] ) isDo[1] <= 1’b0;

21. else if( isDo[0] & isDone[0] ) isDo[0] <= 1’b0;

22.

23. if( isDone ) C7 <= { isDo[0], isDo[1] };

24. else if( iCall ) C7 <= { C7[0], C7[1] };

25. end

26.

代碼17.3

第3~4行是相關的出入端聲明, 其中 Call 還有 Done 均為兩位。第6~7行是輪流協調作用的寄存器isDo與C7,C7為使能指針。第10~14行則是這些寄存器的初始化,注意C7默認下指向 Call[1]。第16~25行則是輪流協調的主要操作,第17~18行是提問與使能,其中 iCall[N] & C7[N] 表示提問並且被指針指向,isDo[N] 表示給予使能權。

第20~21行是消除提問和使能,其中 isDo[N] & isDone[N] 表示相關的完成信號對應相關的操作,然后 isDo[N] 表示消除使能。第24行的表示有提問,指針就立即移動。第23行表示結束操作,指針便指向下一個對象。

27. reg [4:0]i;

28. reg [1:0]isDone;

29.

30. always @ ( posedge CLOCK or negedge RESET )

31. if( !RESET )

32. begin

33. ...

34. i <= 5’d0;

35. isDone <= 2’b00;

36. end

37. else if( isDo[1] )

38. case( i )

39. ...

40. 5: begin isDone[1] <= 1’b1; i <= i + 1’b1; end

41. 6: begin isDone[1] <= 1’b0; i <= 5’d0; end

42. endcase

43. else if( isDo[0] )

44. case( i )

45. ...

46. 7: begin isDone[0] <= 1’b1; i <= i + 1’b1; end

47. 8: begin isDone[0] <= 1’b0; i <= 5’d0; end

48. endcase

49.

50. endmodule

代碼17.3

第27~28行只核心操作相關的寄存器,第31~36行則是這些寄存器的復位操作。第37行表示 isDo[1] 拉高才執行操作1。第40~41行表示操作1反饋完成信號。第43行表示 isDo[0] 拉高才指向操作0。第46~47行表示操作0反饋完成信號。如此一來,問答信號便有輪流協調,接下來就是為IIC儲存模塊加入FIFO機制。

clip_image026

圖17.13 有FIFO機制的IIC儲存模塊。

如圖17.13所示,那是擁有FIFO機制的IIC儲存模塊,它那畸形的儲存功能,可謂是IIC儲存模塊的亞種。其中 Call/Done[1] 表示寫入調用,Tag[1] 表示寫滿狀態,反之既然。由於目前的IIC儲存模塊是FIFO的關系,所以寫入地址還有讀出地址都是在里邊建立。為此,Verilog可以這樣描述,結果如代碼17.4所示:

1. module iic_savemod

2. (

3. input [1:0]iCall,

4. output [1:0]oDone,

5. input [7:0]iData,

6. output [7:0]oData,

7. output [1:0]oTag

8. );

9. always @ ( posedge CLOCK or negedge RESET ) // 輪流協調的周邊操作

10. ...

11.

12. reg [8:0]C2,C3; // C2 Write Pointer, C3 Read Pointer;

13.

14. always @ ( posedge CLOCK or negedge RESET )

15. if( !RESET )

16. begin

17. C2 <= 9’d0;

18. C3 <= 9’d0;

19. end

20. else if( isDo[1] )

21. case( i )

22. ...

23. 2: // Wirte Word Addr

24. begin D1 <= C2[7:0]; i <= FF_Write1; Go <= i + 1'b1; end

25. ...

26. 5:

27. begin C2 <= C2 + 1'b1; isDone[1] <= 1'b1; i <= i + 1'b1; end

28. ...

29. endcase

30. else if( isDo[0] )

31. case( i )

32. ...

33. 2: // Wirte Word Addr

34. begin D1 <= C3[7:0]; i <= FF_Write2; Go <= i + 1'b1; end

35. ...

36. 7:

37. begin C3 <= C3 + 1'b1; isDone[0] <= 1'b1; i <= i + 1'b1; end

38. ...

39. endcase

40.

41. ...

42. assign oTag[1] = ( (C2[8]^C3[8]) && (C2[7:0] == C3[7:0]) );

43. assign oTag[0] = ( C2 == C3 );

44.

45. endmodule

代碼17.4

如代碼17.4所示,第3~7行是相關的出入端聲明。第12行建立相關的寄存器,C2為寫指針,C3為讀指針,位寬為 N + 1。第23~24行表示C2[7:0]為寫數據地址。第26~27行表示C2遞增。第33~34行表示C3[7:0]為讀數據地址。第36~37行表示C3遞增。第42行表示寫滿狀態,第43行則表示讀空狀態。完后,我們便可以開始建模了。

clip_image028

圖17.14 實驗十七的建模圖。

圖17.14是實驗十七的建模圖,周邊操作為 IIC 儲存模塊寫入數據,核心操作則從哪里讀取數據,並且將讀出的數據驅動數碼管基礎模塊。

iic_savemod.v

clip_image030

圖17.15 IIC儲存模塊。

圖17.15是IIC儲存模塊的建模圖,左方是寫入操作,右邊是讀出操作,上方則是鏈接至頂層信號 SCL 與 SDA。

1. module iic_savemod

2. (

3. input CLOCK, RESET,

4. output SCL,

5. inout SDA,

6. input [1:0]iCall,

7. output [1:0]oDone,

8. input [7:0]iData,

9. output [7:0]oData,

10. output [1:0]oTag

11. );

12. parameter FCLK = 10'd125, FHALF = 10'd62, FQUARTER = 10'd31; //(1/400E+3)/(1/50E+6)

13. parameter THIGH = 10'd30, TLOW = 10'd65, TR = 10'd15, TF = 10'd15;

14. parameter THD_STA = 10'd30, TSU_STA = 10'd30, TSU_STO = 10'd30;

15. parameter FF_Write1 = 5'd7;

16. parameter FF_Write2 = 5'd9, FF_Read = 5'd19;

17.

18. /***************/

19.

20. reg [1:0]C7;

21. reg [1:0]isDo;

22.

23. always @ ( posedge CLOCK or negedge RESET )

24. if( !RESET )

25. begin

26. C7 <= 2'b10;

27. isDo <= 2'b00;

28. end

29. else

30. begin

31.

32. if( iCall[1] & C7[1] ) isDo[1] <= 1'b1;

33. else if( iCall[0] & C7[0] ) isDo[0] <= 1'b1;

34.

35. if( isDo[1] & isDone[1] ) isDo[1] <= 1'b0;

36. else if( isDo[0] & isDone[0] ) isDo[0] <= 1'b0;

37.

38. if( isDone ) C7 <= {isDo[0],isDo[1]};

39. else if( iCall ) C7 <= { C7[0], C7[1] };

40.

41. end

42.

43.

44. /***************/

45.

46. reg [4:0]i;

47. reg [4:0]Go;

48. reg [9:0]C1;

49. reg [7:0]D1;

50. reg [1:0]isDone;

51. reg [8:0]C2,C3; // C2 Write Pointer, C3 Read Pointer

52. reg rSCL,rSDA;

53. reg isAck,isQ;

54.

55. always @ ( posedge CLOCK or negedge RESET )

56. if( !RESET )

57. begin

58. { i,Go } <= { 5'd0,5'd0 };

59. C1 <= 10'd0;

60. D1 <= 8'd0;

61. isDone <= 2'd0;

62. { C2, C3 } <= 18'd0;

63. { rSCL,rSDA,isAck,isQ } <= 4'b1111;

64. end

65. else if( isDo[1] )

66. case( i )

67.

68. 0: // Call

69. begin

70. isQ = 1;

71. rSCL <= 1'b1;

72.

73. if( C1 == 0 ) rSDA <= 1'b1; 

74. else if( C1 == (TR + THIGH) ) rSDA <= 1'b0;

75.

76. if( C1 == (FCLK) -1) begin C1 <= 10'd0; i <= i + 1'b1; end

77. else C1 <= C1 + 1'b1;

78. end

79.

80. 1: // Write Device Addr

81. begin D1 <= {4'b1010, 3'b000, 1'b0}; i <= 5'd7; Go <= i + 1'b1; end

82.

83. 2: // Wirte Word Addr

84. begin D1 <= C2[7:0]; i <= FF_Write1; Go <= i + 1'b1; end

85.

86. 3: // Write Data

87. begin D1 <= iData; i <= FF_Write1; Go <= i + 1'b1; end

88.

89. /*************************/

90.

91. 4: // Stop

92. begin

93. isQ = 1'b1;

94.

95. if( C1 == 0 ) rSCL <= 1'b0;

96. else if( C1 == FQUARTER ) rSCL <= 1'b1; 

97.

98. if( C1 == 0 ) rSDA <= 1'b0;

99. else if( C1 == (FQUARTER + TR + TSU_STO ) ) rSDA <= 1'b1;

100.

101. if( C1 == (FQUARTER + FCLK) -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

102. else C1 <= C1 + 1'b1; 

103. end

104.

105. 5:

106. begin C2 <= C2 + 1'b1; isDone[1] <= 1'b1; i <= i + 1'b1; end

107.

108. 6: 

109. begin isDone[1] <= 1'b0; i <= 5'd0; end

110.

111. /*******************************/ //function

112.

113. 7,8,9,10,11,12,13,14:

114. begin

115. isQ = 1'b1;

116. rSDA <= D1[14-i];

117.

118. if( C1 == 0 ) rSCL <= 1'b0;

119. else if( C1 == (TF + TLOW) ) rSCL <= 1'b1; 

120.

121. if( C1 == FCLK -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

122. else C1 <= C1 + 1'b1;

123. end

124.

125. 15: // waiting for acknowledge

126. begin

127. isQ = 1'b0;

128. if( C1 == FHALF ) isAck <= SDA;

129.

130. if( C1 == 0 ) rSCL <= 1'b0;

131. else if( C1 == FHALF ) rSCL <= 1'b1;

132.

133. if( C1 == FCLK -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

134. else C1 <= C1 + 1'b1; 

135. end

136.

137. 16:

138. if( isAck != 0 ) i <= 5'd0;

139. else i <= Go; 

140.

141. /*******************************/ // end function

142.

143. endcase

144.

145. else if( isDo[0] ) 

146. case( i )

147.

148. 0: // Call

149. begin

150. isQ = 1; 

151. rSCL <= 1'b1;

152.

153. if( C1 == 0 ) rSDA <= 1'b1; 

154. else if( C1 == (TR + THIGH) ) rSDA <= 1'b0;

155.

156. if( C1 == FCLK -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

157. else C1 <= C1 + 1'b1;

158. end

159.

160. 1: // Write Device Addr

161. begin D1 <= {4'b1010, 3'b000, 1'b0}; i <= 5'd9; Go <= i + 1'b1; end

162.

163. 2: // Wirte Word Addr

164. begin D1 <= C3[7:0]; i <= FF_Write2; Go <= i + 1'b1; end

165.

166. 3: // Start again

167. begin

168. isQ = 1'b1;

169.

170. if( C1 == 0 ) rSCL <= 1'b0;

171. else if( C1 == FQUARTER ) rSCL <= 1'b1;

172. else if( C1 == (FQUARTER + TR + TSU_STA + THD_STA + TF) ) rSCL <= 1'b0;

173.

174. if( C1 == 0 ) rSDA <= 1'b0; 

175. else if( C1 == FQUARTER ) rSDA <= 1'b1;

176. else if( C1 == ( FQUARTER + TR + THIGH) ) rSDA <= 1'b0;

177.

178. if( C1 == (FQUARTER + FCLK + FQUARTER) -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

179. else C1 <= C1 + 1'b1;

180. end

181.

182. 4: // Write Device Addr ( Read )

183. begin D1 <= {4'b1010, 3'b000, 1'b1}; i <= 5'd9; Go <= i + 1'b1; end

184.

185. 5: // Read Data

186. begin D1 <= 8'd0; i <= FF_Read; Go <= i + 1'b1; end

187.

188. 6: // Stop

189. begin

190. isQ = 1'b1;

191.

192. if( C1 == 0 ) rSCL <= 1'b0;

193. else if( C1 == FQUARTER ) rSCL <= 1'b1; 

194.

195. if( C1 == 0 ) rSDA <= 1'b0;

196. else if( C1 == (FQUARTER + TR + TSU_STO) ) rSDA <= 1'b1;

197.

198. if( C1 == (FCLK + FQUARTER) -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

199. else C1 <= C1 + 1'b1; 

200. end

201.

202. 7:

203. begin C3 <= C3 + 1'b1; isDone[0] <= 1'b1; i <= i + 1'b1; end

204.

205. 8: 

206. begin isDone[0] <= 1'b0; i <= 5'd0; end

207.

208. /*******************************/ //function

209.

210. 9,10,11,12,13,14,15,16:

211. begin

212. isQ = 1'b1;

213.

214. rSDA <= D1[16-i];

215.

216. if( C1 == 0 ) rSCL <= 1'b0;

217. else if( C1 == (TF + TLOW) ) rSCL <= 1'b1; 

218.

219. if( C1 == FCLK -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

220. else C1 <= C1 + 1'b1;

221. end

222.

223. 17: // waiting for acknowledge

224. begin

225. isQ = 1'b0;

226.

227. if( C1 == FHALF ) isAck <= SDA;

228.

229. if( C1 == 0 ) rSCL <= 1'b0;

230. else if( C1 == FHALF ) rSCL <= 1'b1;

231.

232. if( C1 == FCLK -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

233. else C1 <= C1 + 1'b1; 

234. end

235.

236. 18:

237. if( isAck != 0 ) i <= 5'd0;

238. else i <= Go;

239.

240. /*****************************/

241.

242. 19,20,21,22,23,24,25,26: // Read

243. begin

244. isQ = 1'b0;

245. if( C1 == FHALF ) D1[26-i] <= SDA;

246.

247. if( C1 == 0 ) rSCL <= 1'b0;

248. else if( C1 == FHALF ) rSCL <= 1'b1; 

249.

250. if( C1 == FCLK -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

251. else C1 <= C1 + 1'b1;

252. end

253.

254. 27: // no acknowledge

255. begin

256. isQ = 1'b1;

257. //if( C1 == 100 ) isAck <= SDA;

258.

259. if( C1 == 0 ) rSCL <= 1'b0;

260. else if( C1 == FHALF ) rSCL <= 1'b1;

261.

262. if( C1 == FCLK -1 ) begin C1 <= 10'd0; i <= Go; end

263. else C1 <= C1 + 1'b1; 

264. end

265.

266. /*************************************/ // end fucntion

267.

268. endcase

269.

270. /***************************************/

271.

272. assign SCL = rSCL;

273. assign SDA = isQ ? rSDA : 1'bz;

274. assign oDone = isDone;

275. assign oData = D1;

276. assign oTag[1] = ( (C2[8]^C3[8]) && (C2[7:0] == C3[7:0]) );

277. assign oTag[0] = ( C2 == C3 );

278.

279. /***************************************/

280.

281. endmodule

具體內容筆者也懶得解釋了,讀者自己看着辦吧。

iic_demo.v

連線部署請參考圖17.14。

1. module iic_demo

2. (

3. input CLOCK, RESET,

4. output SCL,

5. inout SDA,

6. output [7:0]DIG,

7. output [5:0]SEL

8. );

以上內容為相關的出入端聲明。

9. reg [3:0]j;

10. reg [7:0]D1;

11. reg isWR;

12.

13. always @ ( posedge CLOCK or negedge RESET )

14. if( !RESET )

15. begin 

16. j <= 4'd0;

17. D1 <= 8'd0;

18. isWR <= 1'b0;

19. end

20. else

21. case( j )

22.

23. 0:

24. if( !TagU1[1] ) j <= j + 1'b1;

25.

26. 1:

27. if( DoneU1[1] ) begin isWR <= 1'b0; j <= j + 1'b1; end

28. else begin isWR <= 1'b1; D1 <= 8'hAB; end

29.

30. 2:

31. if( !TagU1[1] ) j <= j + 1'b1;

32.

33. 3:

34. if( DoneU1[1] ) begin isWR <= 1'b0; j <= j + 1'b1; end

35. else begin isWR <= 1'b1; D1 <= 8'hCD; end

36.

37. 4:

38. if( !TagU1[1] ) j <= j + 1'b1;

39.

40. 5:

41. if( DoneU1[1] ) begin isWR <= 1'b0; j <= j + 1'b1; end

42. else begin isWR <= 1'b1; D1 <= 8'hEF; end

43.

44. 6:

45. i <= i;

46.

47. endcase

48.

以上內容為寫入作用的周邊操作,操作過程如下:

步驟0,判斷是否寫滿狀態。

步驟1,寫入數據 8’hAB;

步驟2,判斷是否寫滿狀態。

步驟3,寫入數據 8’hCD;

步驟4,判斷是否寫滿狀態。

步驟5,寫入數據 8’hEF;

步驟6,發呆。

49. wire [7:0]DataU1;

50. wire [1:0]DoneU1;

51. wire [1:0]TagU1;

52.

53. iic_savemod U1

54. (

55. .CLOCK( CLOCK ),

56. .RESET( RESET ),

57. .SCL( SCL ), // > top

58. .SDA( SDA ), // <> top

59. .iCall( { isWR, isRD } ), // < sub & core

60. .oDone( DoneU1 ), // > core

61. .iData( D1 ), // < core

62. .oData( DataU1 ), // > core

63. .oTag( TagU1 )

64. );

65.

以上內容為IIC儲存模塊的實例化。第59行表示 isWR 為 Call[1],isRD 為 Call[0]。第61行表示 D1 驅動該輸入。

66. reg [3:0]i;

67. reg [23:0]D2;

68. reg isRD;

69.

70. always @ ( posedge CLOCK or negedge RESET ) // core

71. if( !RESET )

72. begin

73. i <= 4'd0;

74. D2 <= 24'd0;

75. isRD <= 1'b0;

76. end

77. else

78. case( i )

79.

80. 0:

81. if( !TagU1[0] ) i <= i + 1'b1;

82.

83. 1:

84. if( DoneU1[0] ) begin D2[23:16] <= DataU1; isRD <= 1'b0; i <= i + 1'b1; end

85. else isRD <= 1'b1;

86.

87. 2:

88. if( !TagU1[0] ) i <= i + 1'b1;

89.

90. 3:

91. if( DoneU1[0] ) begin D2[15:8] <= DataU1; isRD <= 1'b0; i <= i + 1'b1; end

92. else isRD <= 1'b1;

93.

94. 4:

95. if( !TagU1[0] ) i <= i + 1'b1;

96.

97. 5:

98. if( DoneU1[0] ) begin D2[7:0] <= DataU1; isRD <= 1'b0; i <= i + 1'b1; end

99. else isRD <= 1'b1;

100.

101. 6:

102. i <= i;

103.

104. endcase

105.

以上內容為讀出數據並且驅動數碼管基礎模塊的核心操作,操作過程如下:

步驟0,判斷是否為讀空狀態。

步驟1,讀出數據 8’hAB,並且暫存至 D2[23:16]。

步驟2,判斷是否為讀空狀態。

步驟3,讀出數據 8’hCD,並且暫存至 D2[15:8]。

步驟4,判斷是否為讀空狀態。

步驟5,讀出數據 8’hEF,並且暫存至 D2[7:0]。

步驟6,發呆。

106. smg_basemod U2

107. (

108. .CLOCK( CLOCK ),

109. .RESET( RESET ),

110. .DIG( DIG ), // > top

111. .SEL( SEL ), // > top

112. .iData( D2 ) // < core

113. );

114.

115. endmodule

第106~113行是數碼管基礎模塊的實例化,第112行表示D2驅動該輸入。編譯完畢並且下載程序,如果數碼管自左向右顯示“ABCDEF”表示實驗成功。

細節一: 完整的個體模塊

實驗十七的IIC儲存模塊隨時可以使用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM