ZYNQ上的簡單 FSK 基帶發(fā)射器
掃描二維碼
隨時隨地手機看文章
緒論
由于某種需求需要生成正弦波,因此使用 C 應(yīng)用程序中的sin()函數(shù)來計算單位圓的幅度值,然后將該幅度值轉(zhuǎn)換為 AD9717 的適當 DAC 代碼(當然將每個角度值轉(zhuǎn)換為弧度)。

能夠使用DAC生成簡單的正弦波,下一個想法就是在 SDR(軟件定義無線電)中使用頻率調(diào)制。
大多數(shù) SDR 設(shè)計都有 3 個不同的內(nèi)部運行頻率:一個低基帶頻率,用于處理來自 ADC/DAC 的數(shù)據(jù);一個或多個中間頻率,最終基帶數(shù)據(jù)流作為中間步驟提升到該頻率;以及最終的 RF 將輸入/輸出天線的輸出頻率。顯然,最簡單的起點是基帶,因為它是最低頻率,并且是實際模擬數(shù)據(jù)流從各個數(shù)字數(shù)據(jù)位組合在一起/提取的地方。為了進一步縮小范圍,1 和 0 的數(shù)字位與某些相關(guān)模擬波形相關(guān)的確切點被稱為符號映射器,它是前面提到的 SDR 基本構(gòu)建塊。
因此,本項目將是一個非常簡化的基帶符號映射器,用于 FSK 數(shù)字調(diào)制方案的鏈(數(shù)字到模擬)的發(fā)送端。
數(shù)字調(diào)制
頻移鍵控 (FSK) 是一種數(shù)字調(diào)制,通過更改頻率來表示數(shù)據(jù)流中的不同位/符號。在其最基本的形式中,一個頻率用于表示二進制 1,另一個頻率用于表示二進制 0。這種形式的 FSK 被稱為二進制 FSK 或 2-FSK。

從上面可以看出,1比特由大約是表示0比特的頻率的兩倍的頻率來表示。對于 ZYNQ+SDR 來說,這意味著它需要能夠分別以連續(xù)相位輸出兩個不同的頻率。換句話說:定時在這里很重要,可以確保一個頻率的相位恰好在最后一個頻率的相位停止的地方出現(xiàn)。每個頻率的一個完整周期也是每一位完成的。
Vivado 中的邏輯設(shè)計
由于本演示中只關(guān)注發(fā)送器端,為了處理符號映射器邏輯可能在 MM2S 讀取中對來自 DDR 內(nèi)存的數(shù)據(jù)流施加的背壓,將帶有 FSK 符號映射器的 sin LUT 放置在 AXIS 數(shù)據(jù) FIFO 和 DAC 控制器 IP 之間。這樣,F(xiàn)IFO 可以完成從內(nèi)存的 MM2S 傳輸,當符號映射器邏輯每比特輸出一個周期的相應(yīng)頻率值時,AXI DMA 不會被鎖定tdata。

代碼如下:
`timescale 1ns / 1ps module sin_lut( input clk, input rst, input [8:0] sel, output [15:0] DAC_code ); reg [15:0] DAC_code; always @ (posedge clk) begin if (rst == 1'b0) begin end else begin case (sel) 9'd0 : DAC_code = 16'h0000; 9'd1 : DAC_code = 16'h01C8; 9'd2 : DAC_code = 16'h0390; 9'd3 : DAC_code = 16'h0558; 9'd4 : DAC_code = 16'h0724; 9'd5 : DAC_code = 16'h08EC; 9'd6 : DAC_code = 16'h0AB0; 9'd7 : DAC_code = 16'h0C78; 9'd8 : DAC_code = 16'h0E3C; 9'd9 : DAC_code = 16'h1004; 9'd10 : DAC_code = 16'h11C4; 9'd11 : DAC_code = 16'h1388; 9'd12 : DAC_code = 16'h1548; 9'd13 : DAC_code = 16'h1708; 9'd14 : DAC_code = 16'h18C4; 9'd15 : DAC_code = 16'h1A7C; 9'd16 : DAC_code = 16'h1C38; 9'd17 : DAC_code = 16'h1DEC; 9'd18 : DAC_code = 16'h1FA0; 9'd19 : DAC_code = 16'h2154; 9'd20 : DAC_code = 16'h2304; 9'd21 : DAC_code = 16'h24B0; 9'd22 : DAC_code = 16'h2658; 9'd23 : DAC_code = 16'h2800; 9'd24 : DAC_code = 16'h29A4; 9'd25 : DAC_code = 16'h2B44; 9'd26 : DAC_code = 16'h2CE0; 9'd27 : DAC_code = 16'h2E78; 9'd28 : DAC_code = 16'h3010; 9'd29 : DAC_code = 16'h31A0; 9'd30 : DAC_code = 16'h3330; 9'd31 : DAC_code = 16'h34B8; 9'd32 : DAC_code = 16'h3640; 9'd33 : DAC_code = 16'h37C0; 9'd34 : DAC_code = 16'h3940; 9'd35 : DAC_code = 16'h3AB8; 9'd36 : DAC_code = 16'h3C2C; 9'd37 : DAC_code = 16'h3D9C; 9'd38 : DAC_code = 16'h3F08; 9'd39 : DAC_code = 16'h406C; 9'd40 : DAC_code = 16'h41D0; 9'd41 : DAC_code = 16'h432C; 9'd42 : DAC_code = 16'h4480; 9'd43 : DAC_code = 16'h45D0; 9'd44 : DAC_code = 16'h471C; 9'd45 : DAC_code = 16'h4864; 9'd46 : DAC_code = 16'h49A4; 9'd47 : DAC_code = 16'h4AE0; 9'd48 : DAC_code = 16'h4C14; 9'd49 : DAC_code = 16'h4D44; 9'd50 : DAC_code = 16'h4E6C; 9'd51 : DAC_code = 16'h4F90; 9'd52 : DAC_code = 16'h50AC; 9'd53 : DAC_code = 16'h51C4; 9'd54 : DAC_code = 16'h52D4; 9'd55 : DAC_code = 16'h53DC; 9'd56 : DAC_code = 16'h54E0; 9'd57 : DAC_code = 16'h55DC; 9'd58 : DAC_code = 16'h56D4; 9'd59 : DAC_code = 16'h57C0; 9'd60 : DAC_code = 16'h58A8; 9'd61 : DAC_code = 16'h598C; 9'd62 : DAC_code = 16'h5A64; 9'd63 : DAC_code = 16'h5B38; 9'd64 : DAC_code = 16'h5C04; 9'd65 : DAC_code = 16'h5CC8; 9'd66 : DAC_code = 16'h5D88; 9'd67 : DAC_code = 16'h5E3C; 9'd68 : DAC_code = 16'h5EEC; 9'd69 : DAC_code = 16'h5F94; 9'd70 : DAC_code = 16'h6034; 9'd71 : DAC_code = 16'h60CC; 9'd72 : DAC_code = 16'h6160; 9'd73 : DAC_code = 16'h61E8; 9'd74 : DAC_code = 16'h6268; 9'd75 : DAC_code = 16'h62E4; 9'd76 : DAC_code = 16'h6358; 9'd77 : DAC_code = 16'h63C0; 9'd78 : DAC_code = 16'h6424; 9'd79 : DAC_code = 16'h6480; 9'd80 : DAC_code = 16'h64D4; 9'd81 : DAC_code = 16'h6520; 9'd82 : DAC_code = 16'h6564; 9'd83 : DAC_code = 16'h659C; 9'd84 : DAC_code = 16'h65D0; 9'd85 : DAC_code = 16'h65FC; 9'd86 : DAC_code = 16'h6620; 9'd87 : DAC_code = 16'h663C; 9'd88 : DAC_code = 16'h6650; 9'd89 : DAC_code = 16'h665C; 9'd90 : DAC_code = 16'h6660; 9'd91 : DAC_code = 16'h665C; 9'd92 : DAC_code = 16'h6650; 9'd93 : DAC_code = 16'h663C; 9'd94 : DAC_code = 16'h6620; 9'd95 : DAC_code = 16'h65FC; 9'd96 : DAC_code = 16'h65D0; 9'd97 : DAC_code = 16'h659C; 9'd98 : DAC_code = 16'h6564; 9'd99 : DAC_code = 16'h6520; 9'd100 : DAC_code = 16'h64D4; 9'd101 : DAC_code = 16'h6480; 9'd102 : DAC_code = 16'h6424; 9'd103 : DAC_code = 16'h63C0; 9'd104 : DAC_code = 16'h6358; 9'd105 : DAC_code = 16'h62E4; 9'd106 : DAC_code = 16'h6268; 9'd107 : DAC_code = 16'h61E8; 9'd108 : DAC_code = 16'h6160; 9'd109 : DAC_code = 16'h60CC; 9'd110 : DAC_code = 16'h6034; 9'd111 : DAC_code = 16'h5F94; 9'd112 : DAC_code = 16'h5EEC; 9'd113 : DAC_code = 16'h5E3C; 9'd114 : DAC_code = 16'h5D88; 9'd115 : DAC_code = 16'h5CC8; 9'd116 : DAC_code = 16'h5C04; 9'd117 : DAC_code = 16'h5B38; 9'd118 : DAC_code = 16'h5A64; 9'd119 : DAC_code = 16'h598C; 9'd120 : DAC_code = 16'h58A8; 9'd121 : DAC_code = 16'h57C0; 9'd122 : DAC_code = 16'h56D4; 9'd123 : DAC_code = 16'h55DC; 9'd124 : DAC_code = 16'h54E0; 9'd125 : DAC_code = 16'h53DC; 9'd126 : DAC_code = 16'h52D4; 9'd127 : DAC_code = 16'h51C4; 9'd128 : DAC_code = 16'h50AC; 9'd129 : DAC_code = 16'h4F90; 9'd130 : DAC_code = 16'h4E6C; 9'd131 : DAC_code = 16'h4D44; 9'd132 : DAC_code = 16'h4C14; 9'd133 : DAC_code = 16'h4AE0; 9'd134 : DAC_code = 16'h49A4; 9'd135 : DAC_code = 16'h4864; 9'd136 : DAC_code = 16'h471C; 9'd137 : DAC_code = 16'h45D0; 9'd138 : DAC_code = 16'h4480; 9'd139 : DAC_code = 16'h432C; 9'd140 : DAC_code = 16'h41D0; 9'd141 : DAC_code = 16'h406C; 9'd142 : DAC_code = 16'h3F08; 9'd143 : DAC_code = 16'h3D9C; 9'd144 : DAC_code = 16'h3C2C; 9'd145 : DAC_code = 16'h3AB8; 9'd146 : DAC_code = 16'h3940; 9'd147 : DAC_code = 16'h37C0; 9'd148 : DAC_code = 16'h3640; 9'd149 : DAC_code = 16'h34B8; 9'd150 : DAC_code = 16'h3330; 9'd151 : DAC_code = 16'h31A0; 9'd152 : DAC_code = 16'h3010; 9'd153 : DAC_code = 16'h2E78; 9'd154 : DAC_code = 16'h2CE0; 9'd155 : DAC_code = 16'h2B44; 9'd156 : DAC_code = 16'h29A4; 9'd157 : DAC_code = 16'h2800; 9'd158 : DAC_code = 16'h2658; 9'd159 : DAC_code = 16'h24B0; 9'd160 : DAC_code = 16'h2304; 9'd161 : DAC_code = 16'h2154; 9'd162 : DAC_code = 16'h1FA0; 9'd163 : DAC_code = 16'h1DEC; 9'd164 : DAC_code = 16'h1C38; 9'd165 : DAC_code = 16'h1A7C; 9'd166 : DAC_code = 16'h18C4; 9'd167 : DAC_code = 16'h1708; 9'd168 : DAC_code = 16'h1548; 9'd169 : DAC_code = 16'h1388; 9'd170 : DAC_code = 16'h11C4; 9'd171 : DAC_code = 16'h1004; 9'd172 : DAC_code = 16'h0E3C; 9'd173 : DAC_code = 16'h0C78; 9'd174 : DAC_code = 16'h0AB0; 9'd175 : DAC_code = 16'h08EC; 9'd176 : DAC_code = 16'h0724; 9'd177 : DAC_code = 16'h0558; 9'd178 : DAC_code = 16'h0390; 9'd179 : DAC_code = 16'h01C8; 9'd180 : DAC_code = 16'h0000; 9'd181 : DAC_code = 16'hFE37; 9'd182 : DAC_code = 16'hFC6F; 9'd183 : DAC_code = 16'hFAA7; 9'd184 : DAC_code = 16'hF8DB; 9'd185 : DAC_code = 16'hF713; 9'd186 : DAC_code = 16'hF54F; 9'd187 : DAC_code = 16'hF387; 9'd188 : DAC_code = 16'hF1C3; 9'd189 : DAC_code = 16'hEFFB; 9'd190 : DAC_code = 16'hEE3B; 9'd191 : DAC_code = 16'hEC77; 9'd192 : DAC_code = 16'hEAB7; 9'd193 : DAC_code = 16'hE8F7; 9'd194 : DAC_code = 16'hE73B; 9'd195 : DAC_code = 16'hE583; 9'd196 : DAC_code = 16'hE3C7; 9'd197 : DAC_code = 16'hE213; 9'd198 : DAC_code = 16'hE05F; 9'd199 : DAC_code = 16'hDEAB; 9'd200 : DAC_code = 16'hDCFB; 9'd201 : DAC_code = 16'hDB4F; 9'd202 : DAC_code = 16'hD9A7; 9'd203 : DAC_code = 16'hD7FF; 9'd204 : DAC_code = 16'hD65B; 9'd205 : DAC_code = 16'hD4BB; 9'd206 : DAC_code = 16'hD31F; 9'd207 : DAC_code = 16'hD187; 9'd208 : DAC_code = 16'hCFEF; 9'd209 : DAC_code = 16'hCE5F; 9'd210 : DAC_code = 16'hCCCF; 9'd211 : DAC_code = 16'hCB47; 9'd212 : DAC_code = 16'hC9BF; 9'd213 : DAC_code = 16'hC83F; 9'd214 : DAC_code = 16'hC6BF; 9'd215 : DAC_code = 16'hC547; 9'd216 : DAC_code = 16'hC3D3; 9'd217 : DAC_code = 16'hC263; 9'd218 : DAC_code = 16'hC0F7; 9'd219 : DAC_code = 16'hBF93; 9'd220 : DAC_code = 16'hBE2F; 9'd221 : DAC_code = 16'hBCD3; 9'd222 : DAC_code = 16'hBB7F; 9'd223 : DAC_code = 16'hBA2F; 9'd224 : DAC_code = 16'hB8E3; 9'd225 : DAC_code = 16'hB79B; 9'd226 : DAC_code = 16'hB65B; 9'd227 : DAC_code = 16'hB51F; 9'd228 : DAC_code = 16'hB3EB; 9'd229 : DAC_code = 16'hB2BB; 9'd230 : DAC_code = 16'hB193; 9'd231 : DAC_code = 16'hB06F; 9'd232 : DAC_code = 16'hAF53; 9'd233 : DAC_code = 16'hAE3B; 9'd234 : DAC_code = 16'hAD2B; 9'd235 : DAC_code = 16'hAC23; 9'd236 : DAC_code = 16'hAB1F; 9'd237 : DAC_code = 16'hAA23; 9'd238 : DAC_code = 16'hA92B; 9'd239 : DAC_code = 16'hA83F; 9'd240 : DAC_code = 16'hA757; 9'd241 : DAC_code = 16'hA673; 9'd242 : DAC_code = 16'hA59B; 9'd243 : DAC_code = 16'hA4C7; 9'd244 : DAC_code = 16'hA3FB; 9'd245 : DAC_code = 16'hA337; 9'd246 : DAC_code = 16'hA277; 9'd247 : DAC_code = 16'hA1C3; 9'd248 : DAC_code = 16'hA113; 9'd249 : DAC_code = 16'hA06B; 9'd250 : DAC_code = 16'h9FCB; 9'd251 : DAC_code = 16'h9F33; 9'd252 : DAC_code = 16'h9E9F; 9'd253 : DAC_code = 16'h9E17; 9'd254 : DAC_code = 16'h9D97; 9'd255 : DAC_code = 16'h9D1B; 9'd256 : DAC_code = 16'h9CA7; 9'd257 : DAC_code = 16'h9C3F; 9'd258 : DAC_code = 16'h9BDB; 9'd259 : DAC_code = 16'h9B7F; 9'd260 : DAC_code = 16'h9B2B; 9'd261 : DAC_code = 16'h9ADF; 9'd262 : DAC_code = 16'h9A9B; 9'd263 : DAC_code = 16'h9A63; 9'd264 : DAC_code = 16'h9A2F; 9'd265 : DAC_code = 16'h9A03; 9'd266 : DAC_code = 16'h99DF; 9'd267 : DAC_code = 16'h99C3; 9'd268 : DAC_code = 16'h99AF; 9'd269 : DAC_code = 16'h99A3; 9'd270 : DAC_code = 16'h999F; 9'd271 : DAC_code = 16'h99A3; 9'd272 : DAC_code = 16'h99AF; 9'd273 : DAC_code = 16'h99C3; 9'd274 : DAC_code = 16'h99DF; 9'd275 : DAC_code = 16'h9A03; 9'd276 : DAC_code = 16'h9A2F; 9'd277 : DAC_code = 16'h9A63; 9'd278 : DAC_code = 16'h9A9B; 9'd279 : DAC_code = 16'h9ADF; 9'd280 : DAC_code = 16'h9B2B; 9'd281 : DAC_code = 16'h9B7F; 9'd282 : DAC_code = 16'h9BDB; 9'd283 : DAC_code = 16'h9C3F; 9'd284 : DAC_code = 16'h9CA7; 9'd285 : DAC_code = 16'h9D1B; 9'd286 : DAC_code = 16'h9D97; 9'd287 : DAC_code = 16'h9E17; 9'd288 : DAC_code = 16'h9E9F; 9'd289 : DAC_code = 16'h9F33; 9'd290 : DAC_code = 16'h9FCB; 9'd291 : DAC_code = 16'hA06B; 9'd292 : DAC_code = 16'hA113; 9'd293 : DAC_code = 16'hA1C3; 9'd294 : DAC_code = 16'hA277; 9'd295 : DAC_code = 16'hA337; 9'd296 : DAC_code = 16'hA3FB; 9'd297 : DAC_code = 16'hA4C7; 9'd298 : DAC_code = 16'hA59B; 9'd299 : DAC_code = 16'hA673; 9'd300 : DAC_code = 16'hA757; 9'd301 : DAC_code = 16'hA83F; 9'd302 : DAC_code = 16'hA92B; 9'd303 : DAC_code = 16'hAA23; 9'd304 : DAC_code = 16'hAB1F; 9'd305 : DAC_code = 16'hAC23; 9'd306 : DAC_code = 16'hAD2B; 9'd307 : DAC_code = 16'hAE3B; 9'd308 : DAC_code = 16'hAF53; 9'd309 : DAC_code = 16'hB06F; 9'd310 : DAC_code = 16'hB193; 9'd311 : DAC_code = 16'hB2BB; 9'd312 : DAC_code = 16'hB3EB; 9'd313 : DAC_code = 16'hB51F; 9'd314 : DAC_code = 16'hB65B; 9'd315 : DAC_code = 16'hB79B; 9'd316 : DAC_code = 16'hB8E3; 9'd317 : DAC_code = 16'hBA2F; 9'd318 : DAC_code = 16'hBB7F; 9'd319 : DAC_code = 16'hBCD3; 9'd320 : DAC_code = 16'hBE2F; 9'd321 : DAC_code = 16'hBF93; 9'd322 : DAC_code = 16'hC0F7; 9'd323 : DAC_code = 16'hC263; 9'd324 : DAC_code = 16'hC3D3; 9'd325 : DAC_code = 16'hC547; 9'd326 : DAC_code = 16'hC6BF; 9'd327 : DAC_code = 16'hC83F; 9'd328 : DAC_code = 16'hC9BF; 9'd329 : DAC_code = 16'hCB47; 9'd330 : DAC_code = 16'hCCCF; 9'd331 : DAC_code = 16'hCE5F; 9'd332 : DAC_code = 16'hCFEF; 9'd333 : DAC_code = 16'hD187; 9'd334 : DAC_code = 16'hD31F; 9'd335 : DAC_code = 16'hD4BB; 9'd336 : DAC_code = 16'hD65B; 9'd337 : DAC_code = 16'hD7FF; 9'd338 : DAC_code = 16'hD9A7; 9'd339 : DAC_code = 16'hDB4F; 9'd340 : DAC_code = 16'hDCFB; 9'd341 : DAC_code = 16'hDEAB; 9'd342 : DAC_code = 16'hE05F; 9'd343 : DAC_code = 16'hE213; 9'd344 : DAC_code = 16'hE3C7; 9'd345 : DAC_code = 16'hE583; 9'd346 : DAC_code = 16'hE73B; 9'd347 : DAC_code = 16'hE8F7; 9'd348 : DAC_code = 16'hEAB7; 9'd349 : DAC_code = 16'hEC77; 9'd350 : DAC_code = 16'hEE3B; 9'd351 : DAC_code = 16'hEFFB; 9'd352 : DAC_code = 16'hF1C3; 9'd353 : DAC_code = 16'hF387; 9'd354 : DAC_code = 16'hF54F; 9'd355 : DAC_code = 16'hF713; 9'd356 : DAC_code = 16'hF8DB; 9'd357 : DAC_code = 16'hFAA7; 9'd358 : DAC_code = 16'hFC6F; 9'd359 : DAC_code = 16'hFE37; 9'd360 : DAC_code = 16'h0000; default : DAC_code = 16'h0000; endcase end end endmodule
由于 sin LUT 的 case 語句中的選擇值是正弦波單位圓的每個 360 度值,因此計數(shù)器從 0 到 360 遞增的速度最終設(shè)置了輸出正弦波的頻率。
sin LUT 上方的邏輯中需要三個計數(shù)器:一個計數(shù)器用于對 sin LUT 選擇從 0 到 359 的度數(shù)進行計數(shù),一個計數(shù)器用于計算頻率 0 的增量之間的延遲,以及一個計數(shù)器用于計算頻率 0 的增量之間的延遲。頻率 1.
always @ (posedge clk) begin if (rst == 1'b0) begin degree_cntr <= 9'd0; degree_cntr_done <= 1'b0; end else if (incr_degree_cntr == 1'b1) begin if (degree_cntr < unit_circle_deg) begin degree_cntr <= degree_cntr + 1; degree_cntr_done <= 1'b0; end else begin degree_cntr <= 9'd0; degree_cntr_done <= 1'b1; end end else begin degree_cntr <= degree_cntr; end end always @ (posedge clk) begin if (rst == 1'b0) begin incr_degree_cntr = 1'b0; period_cntr <= 3'd0; end else begin if (period_cntr == period) begin incr_degree_cntr = 1'b1; period_cntr <= 3'd0; end else begin incr_degree_cntr = 1'b0; period_cntr <= period_cntr + 1; end end end always @ (posedge clk) begin if (rst == 1'b0) begin tdata_sel_cntr <= 5'd0; end else begin if (degree_cntr_done == 1'b1) begin tdata_sel_cntr <= tdata_sel_cntr + 1; end else begin tdata_sel_cntr <= tdata_sel_cntr; end end end
還需要一個并行到串行轉(zhuǎn)換器,通過 MM2S 傳輸從 DDR 發(fā)出的數(shù)據(jù)包的 AXI Stream 接口獲取 32 位數(shù)據(jù),并將其串行化,可以通過 MM2S 傳輸輸出該位各自頻率的一個周期。 DAC一次。這就是 2-FSK 的局限性暴露出來的地方:一次只能傳輸一位。
always @ (tdata_sel_cntr) begin case (tdata_sel_cntr) 32'd0 : begin current_tx_bit <= tdata[0]; tx_pkt_done <= 1'b0; end 32'd1 : begin current_tx_bit <= tdata[1]; tx_pkt_done <= 1'b0; end 32'd2 : begin current_tx_bit <= tdata[2]; tx_pkt_done <= 1'b0; end 32'd3 : begin current_tx_bit <= tdata[3]; tx_pkt_done <= 1'b0; end 32'd4 : begin current_tx_bit <= tdata[4]; tx_pkt_done <= 1'b0; end 32'd5 : begin current_tx_bit <= tdata[5]; tx_pkt_done <= 1'b0; end 32'd6 : begin current_tx_bit <= tdata[6]; tx_pkt_done <= 1'b0; end 32'd7 : begin current_tx_bit <= tdata[7]; tx_pkt_done <= 1'b0; end 32'd8 : begin current_tx_bit <= tdata[8]; tx_pkt_done <= 1'b0; end 32'd9 : begin current_tx_bit <= tdata[9]; tx_pkt_done <= 1'b0; end 32'd10 : begin current_tx_bit <= tdata[10]; tx_pkt_done <= 1'b0; end 32'd11 : begin current_tx_bit <= tdata[11]; tx_pkt_done <= 1'b0; end 32'd12 : begin current_tx_bit <= tdata[12]; tx_pkt_done <= 1'b0; end 32'd13 : begin current_tx_bit <= tdata[13]; tx_pkt_done <= 1'b0; end 32'd14 : begin current_tx_bit <= tdata[14]; tx_pkt_done <= 1'b0; end 32'd15 : begin current_tx_bit <= tdata[15]; tx_pkt_done <= 1'b0; end 32'd16 : begin current_tx_bit <= tdata[16]; tx_pkt_done <= 1'b0; end 32'd17 : begin current_tx_bit <= tdata[17]; tx_pkt_done <= 1'b0; end 32'd18 : begin current_tx_bit <= tdata[18]; tx_pkt_done <= 1'b0; end 32'd19 : begin current_tx_bit <= tdata[19]; tx_pkt_done <= 1'b0; end 32'd20 : begin current_tx_bit <= tdata[20]; tx_pkt_done <= 1'b0; end 32'd21 : begin current_tx_bit <= tdata[21]; tx_pkt_done <= 1'b0; end 32'd22 : begin current_tx_bit <= tdata[22]; tx_pkt_done <= 1'b0; end 32'd23 : begin current_tx_bit <= tdata[23]; tx_pkt_done <= 1'b0; end 32'd24 : begin current_tx_bit <= tdata[24]; tx_pkt_done <= 1'b0; end 32'd25 : begin current_tx_bit <= tdata[25]; tx_pkt_done <= 1'b0; end 32'd26 : begin current_tx_bit <= tdata[26]; tx_pkt_done <= 1'b0; end 32'd27 : begin current_tx_bit <= tdata[27]; tx_pkt_done <= 1'b0; end 32'd28 : begin current_tx_bit <= tdata[28]; tx_pkt_done <= 1'b0; end 32'd29 : begin current_tx_bit <= tdata[29]; tx_pkt_done <= 1'b0; end 32'd30 : begin current_tx_bit <= tdata[30]; tx_pkt_done <= 1'b0; end 32'd31 : begin current_tx_bit <= tdata[31]; tx_pkt_done <= 1'b1; end default : begin current_tx_bit <= 1'b0; tx_pkt_done <= 1'b0; end endcase end always @ (posedge clk) begin if (current_tx_bit == 1'b1) period <= T1_period; else period <= T0_period; end
最后,AXI Stream 接口只需要圍繞上述邏輯,使用從接口接收來自 AXIS FIFO 的數(shù)據(jù),并使用主接口將數(shù)據(jù)輸出到 DAC 控制器。
`timescale 1ns / 1ps module sin_axis( input clk, input reset, input [31:0] s_axis_tdata, input [3:0] s_axis_tkeep, input s_axis_tlast, output reg s_axis_tready, input s_axis_tvalid, output reg [31:0] m_axis_tdata, output reg [3:0] m_axis_tkeep, output reg m_axis_tlast, input m_axis_tready, output reg m_axis_tvalid, output [2:0] state_reg ); sin_sm sin_sm_i( .clk(clk), .rst(reset), .tdata_slave(tdata_slave), .tdata_master(tdata_master), .tx_pkt_done(tx_pkt_done) ); reg tlast; reg [2:0] state_reg; wire tx_pkt_done; wire [31:0] tdata_master; reg [31:0] tdata_slave; parameter init = 3'd0; parameter SetSlaveTready = 3'd1; parameter CheckSlaveTvalid = 3'd2; parameter ProcessTdata = 3'd3; parameter CheckTlast = 3'd4; always @ (posedge clk) begin // Default outputs m_axis_tvalid <= 1'b0; if (reset == 1'b0) begin tlast <= 1'b0; tdata_slave[31:0] <= 32'd0; s_axis_tready <= 1'b0; m_axis_tdata[31:0] <= 32'd0; m_axis_tkeep <= 4'h0; m_axis_tlast <= 1'b0; state_reg <= init; end else begin case(state_reg) init : // 0 begin tlast <= 1'b0; tdata_slave[31:0] <= 32'd0; s_axis_tready <= 1'b0; m_axis_tdata[31:0] <= 32'd0; m_axis_tkeep <= 4'h0; m_axis_tlast <= 1'b0; state_reg <= SetSlaveTready; end SetSlaveTready : // 1 begin s_axis_tready <= 1'b1; state_reg <= CheckSlaveTvalid; end CheckSlaveTvalid : // 2 begin if (s_axis_tkeep == 4'hf && s_axis_tvalid == 1'b1) begin s_axis_tready <= 1'b0; tlast <= s_axis_tlast; tdata_slave[31:0] <= s_axis_tdata[31:0]; state_reg <= ProcessTdata; end else begin tdata_slave[31:0] <= 32'd0; state_reg <= CheckSlaveTvalid; end end ProcessTdata : // 3 begin m_axis_tkeep <= 4'hf; m_axis_tlast <= tlast; m_axis_tvalid <= 1'b1; m_axis_tdata[31:0] <= tdata_master[31:0]; if (m_axis_tready == 1'b1 && tx_pkt_done == 1'b1) begin state_reg <= CheckTlast; end else begin state_reg <= ProcessTdata; end end CheckTlast : // 4 begin if (m_axis_tlast == 1'b1) begin state_reg <= init; end else if (m_axis_tready == 1'b1) begin state_reg <= SetSlaveTready; end else begin state_reg <= CheckTlast; end end endcase end end endmodule
完整的代碼見最后。
Vitis 軟件
由于生成正弦波的所有邏輯都是在 Verilog 的 HDL 中處理的,因此 C 代碼中唯一剩下的就是控制 MM2S 傳輸(源文件也附在下面):
int main() { init_platform(); XAxiDma_Config *CfgPtr; //DMA configuration pointer int Status, Index; u8 *TxBufferPtr; TxBufferPtr = (u8 *)TX_BUFFER_BASE; for(Index = 0; Index < MAX_PKT_LEN; Index ++){ TxBufferPtr[Index] = 0x00; } CfgPtr = XAxiDma_LookupConfig(DMA_DEV_ID); if (!CfgPtr) { xil_printf("No config found for %d\r\n", DMA_DEV_ID); return XST_FAILURE; } Status = XAxiDma_CfgInitialize(&AxiDma, CfgPtr); if (Status != XST_SUCCESS) { xil_printf("Initialization failed %d\r\n", Status); return XST_FAILURE; } XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE); TxBufferPtr[0] = 0xef; Xil_DCacheFlushRange((UINTPTR)TxBufferPtr, MAX_PKT_LEN); XAxiDma_Reset(&AxiDma); Status = XAxiDma_MM2Stransfer(&AxiDma,(UINTPTR) TxBufferPtr, MAX_PKT_LEN); if (Status != XST_SUCCESS){ xil_printf("XAXIDMA_DMA_TO_DEVICE transfer failed...\r\n"); return XST_FAILURE; } cleanup_platform(); return 0; }

測試設(shè)備
為了驗證模擬輸出,將其通道 1 連接到示波器通道 1,并在主機 PC 上啟動 WaveForms 來查看它。
然后,在 Vitis 中啟動 C 應(yīng)用程序的調(diào)試,并在 MM2S 傳輸開始之前設(shè)置了斷點:

由于將DAC設(shè)置為低增益模式,因此峰值輸出值約為 1.0v。在 WaveForms 的 Scope 選項卡中,為超過 100mV 的上升沿設(shè)置電平觸發(fā)器,然后單擊Run 。
得到 1 和 0 兩個不同頻率值的清晰輸出:

正如我上面提到的,這只是符號映射器的一個非常簡化的版本,目的是為了以更實用、更實際的方式克服 SDR 設(shè)計入門的困難。兩個不同頻率的周期計數(shù)器是查看輸出結(jié)果的良好起點。
代碼
?https://github.com/Digilent/vivado-boards
?
?https://github.com/suisuisi/FPGATechnologyGroup/tree/main/simple_2_fsk
?