加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 一、MCU和CPLD直接交互
    • 二、mcu通過ahb轉(zhuǎn)apb后的數(shù)據(jù)交互
    • 三、DMA在CPLD中的使用
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

AG32:MCU和CPLD交互實操指南

09/26 14:49
996
閱讀需 20 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

本文檔介紹了AG32開發(fā)中,MCU與CPLD交互的具體方式以及例子。

如需了解AG32更多資料可發(fā)郵件:sales@agm-micro.com,或直接掃碼加我本人微信。

一、MCU和CPLD直接交互

cpld工程創(chuàng)建及編譯的操作流程,參考文檔《AG32下fpga和cpld的使用入門》

在工程中,用戶邏輯部分編寫是從analog_ip.v的接口下開始的。

mcu和cpld之間的交互,可以分為:

1. mcu傳遞信號給cpld;(如mcu的gpio傳遞高低信號到cpld)

2. cpld傳遞信號給mcu;(如:對mcu產(chǎn)生中斷信號)

3. mcu讀寫數(shù)據(jù)到cpld;

4. 不建議,cpld做為主設(shè)備對mcu寫。

也就是說,在mcu和cpld交互中,cpld更像一個外設(shè)。

其中,前兩種較為簡單。后兩種要使用AHB總線來操作。

下邊針對四種情況分別說明:

1. mcu傳遞信號給cpld;

這種使用較簡單。步驟如下:

在ve中定義信號:

GPIO4_1
iocvt_chn:OUTPUT

表示,用mcu的gpio(gpio4_1)來輸入信號到cpld。

然后,prepare LOGIC工程后,可以看到analog_ip.v接口中的信號:

input?????????????iocvt_chn_out_data,

input?????????????iocvt_chn_out_en,

這里的iocvt_chn_out_data,就是對接到mcu的gpio4_1的信號。

當(dāng)控制mcu的gpio4_1高低切換時,cpld中的iocvt_chn_out_data,會對應(yīng)來變化。

具體樣例,可以參考網(wǎng)盤“l(fā)ogic樣例3.mcu信號到cpld到pin”的樣例,該樣例中,展示了mcu控制cpld繼續(xù)控制led的過程。

除了gpio信號輸出到cpld,其他比如pwm輸出信號等,都可以輸入到cpld。

2. cpld傳遞信號給mcu

這種方式和1相近,只不過是反向。

可以在mcu中定義gpio4_2為輸入并使能中斷,則cpld中設(shè)置信號高低時,將觸發(fā)?mcu的中斷。

在VE中定義信號:

GPIO4_2
iocvt_chn:INPUT

表示,用mcu的gpio(gpio4_2)信號來源于cpld的iocvt_chn。

然后,prepare LOGIC工程后,可以看到analog_ip.v接口中的信號:

output?????????????iocvt_chn_in_data,

這里的iocvt_chn_in_data,就是對接到mcu的gpio4_2的信號。

當(dāng)cpld中控制iocvt_chn_in_data信號高低時,mcu中的gpio4_2對應(yīng)變化。

這里不再舉例。

3. mcu讀寫數(shù)據(jù)到cpld

在地址設(shè)計中,cpld的地址區(qū)間是:0x60000000 ~
0x7FFFFFFF

當(dāng)mcu對這個區(qū)間內(nèi)的地址訪問時,相當(dāng)于訪問了cpld的“寄存器”。

mcu是全局尋址,對這個空間的訪問和對ram(0x20000000起)空間的訪問是一樣的方式,在C代碼中,可以這樣寫:

讀cpld:int cpRdReg = *((int *)0x60000000);

寫cpld:*((int *)0x60000004) = cpWtReg;

Mcu端讀寫cpld較為簡單,直接通過上述語句就可以了。

當(dāng)mcu讀寫動作發(fā)生時,cpld端是如何反應(yīng)的?

當(dāng)上述mcu讀寫動作發(fā)生時,AHB總線會把動作拆解為讀寫信號,傳遞到analog_ip.v的接口,用戶cpld程序需要響應(yīng)該信號。

以下,以寫動作 *((int *)0x60000004) = cpWtReg 為例,描述cpld端會發(fā)生的事情。

回顧下analog_ip.v中的接口部分:

其中slave_ahb_開頭的一組信號,是cpld作為主端時用的,暫時不用理會。

Mem_ahb_開頭的一組信號,是cpld作為從端使用的。

當(dāng)mcu有讀寫操作時,mem_ahb_這組信號將發(fā)生變化。

這部分是遵循標(biāo)準(zhǔn)的AHB總線協(xié)議的。如果對AHB總線印象不深,請自行百度。

可參考的講解:https://blog.csdn.net/weixin_46022434/article/details/104987905

幾個信號的概述(更詳細(xì)的講解請自行百度):

Ahb_htrans: 當(dāng)前傳輸類型(00: IDLE、01: BUSY、10: NONSEQ、11: SEQ)

Ahb_ready:mcu讀時要mcu要準(zhǔn)備好cpld才會寫

Ahb_hwrite: 要讀還是要寫(1為寫,0為讀)

Ahb_haddr[32]: 要操作的地址

Ahb_hsize:transfer的大小,以字節(jié)為單位

Ahb_hburst:批量傳輸

Ahb_hwdata[32]:寫的數(shù)據(jù),32位

Ahb_hreadyout:輸出信號,mcu寫時cpld是否準(zhǔn)備好

Ahb_hresp:輸出信號,響應(yīng)信號(OK、retry、error、split)

Ahb_hrdata[32]:讀的數(shù)據(jù),32位

根據(jù)AHB時序,在一次傳輸中,cpld(slave端)會先拿到addr地址,讀或?qū)懙臉?biāo)記,然后交互ready信號后,開始數(shù)據(jù)傳輸。

大致如下圖(無等待類型的圖):

比如,mcu要讀0x60000004的寄存器:

mcu端直接C語言這樣調(diào)用:int cpRdReg = *((int
*)0x60000004);

cpld端,可以根據(jù)以上信號做如下處理:

----------------------------------------------

//mcu的讀操作響應(yīng)

//mcu端用C語言:int value = *((int *)0x60000004);

reg [31:0] hrdata_reg; ?????? //定義32位的hrdata_reg

always @(posedge sys_clock) begin??????? //clk上升沿觸發(fā)

if (mem_ahb_htrans ==
2'b10 &&? ???????? //NONSEQ
狀態(tài),第一次傳輸

? mem_ahb_hready && ??????????????? ????????? //master已ready,可以給數(shù)據(jù)線寫入了

? !mem_ahb_hwrite &&??????? ???????? //(0 讀,1 寫)

? mem_ahb_haddr[23:0] == 'h04) ??????? //讀地址為0x60000004(cpld用相對偏移)

begin

hrdata_reg <=
hwdata_reg;????????????? //
把另一準(zhǔn)備好的數(shù)據(jù)給到hrdata_reg

end

end

assign mem_ahb_hrdata = hrdata_reg; //綁定hrdata_reg到讀的數(shù)據(jù)線上

-----------------------------------------------

以上代碼,加入到analog_ip.v的module下,就可以完成cpld對mcu讀動作的響應(yīng)。

比如,mcu要寫0x60000000的寄存器:

mcu端直接C語言這樣調(diào)用:*((int *)0x60000000)
= value;

cpld端,可以根據(jù)以上信號做如下處理:

----------------------------------------------

//mcu的寫操作響應(yīng)

//mcu端用C語言:*((int *)0x60000000) = value;

reg [31:0] hwdata_reg; ?????? //定義32位的hwdata_reg

always @(posedge sys_clock) begin??????? //clk上升沿觸發(fā)

if (mem_ahb_htrans ==
2'b00 &&? ?????? //IDLE
狀態(tài)

? mem_ahb_hreadyout && ????????? ???????? //cpld已ready狀態(tài),ahb上數(shù)據(jù)可以寫過來

? mem_ahb_hwrite &&??????? ????????? //(0 讀,1 寫)

? mem_ahb_haddr[23:0] == 'h00) ??????? //寫地址為0x60000000(cpld用相對偏移)

begin

hwdata_reg <=
mem_ahb_hwdata;???????? //
把收到的數(shù)據(jù)給到hwdata_reg

end

end

//這個過程,是把mcu寫進(jìn)來的數(shù)據(jù)收到hwdata_reg

-----------------------------------------------

這部分的實例代碼,請參考網(wǎng)盤上cpld樣例工程《5.mcu讀寫cpld寄存器》。

注意:這里展示的,僅僅是基于AHB總線上的數(shù)據(jù)交互。

在實際應(yīng)用中,比如要實現(xiàn)一個串口之類的,往往是慢速設(shè)備,這些是要掛載到apb ? 上的。慢速設(shè)備要經(jīng)過ahb到apb的bridge,才能最終使用。請繼續(xù)往下看。

二、mcu通過ahb轉(zhuǎn)apb后的數(shù)據(jù)交互

上節(jié)講述了mcu和cpld之間交互數(shù)據(jù)的實現(xiàn)方式。

但數(shù)據(jù)是在ahb層面的響應(yīng),慢速設(shè)備不能直接使用。

慢速設(shè)備需要ahb轉(zhuǎn)為apb后,使用apb的信號來交互。這種情況,轉(zhuǎn)變?yōu)閙cu和apb? 之間的交互。

mcu和apb之間的交互,相比mcu和aph之間的交互,多了一層ahb到apb的轉(zhuǎn)換。這個轉(zhuǎn)換是借助于ahb2apb.v模塊來實現(xiàn)的(在example/analog下找該.v文件)。

該模塊:輸入是ahb的一組信號,輸出是apb的一組信號。使用如下圖:

如果實現(xiàn)mcu和apb的交互,則需要操作的是轉(zhuǎn)換后的這組apb信號。

關(guān)于apb總線的使用,更多信息請自行百度。

這里只是簡述下apb信號列表(與ahb略有不同):

apb_psel:片選

apb_penable:表示傳輸進(jìn)入第二周期(準(zhǔn)備好了讀/寫)

apb_pwrite:傳輸方向(1-寫;0-讀)

apb_paddr[32]:地址總線,要操作的地址

apb_pwdata[32]:寫的數(shù)據(jù),32位

apb_prdata[32]:讀的數(shù)據(jù),32位

以下展示在apb下如何實現(xiàn)跟mcu的交互,仍以ahb的兩個寄存器為例。

1. 首先需要增加ahb轉(zhuǎn)apb的信號關(guān)聯(lián);

如上圖。

Ahb2apb模塊會把a(bǔ)hb信號轉(zhuǎn)換為apb信號。接下來操作apb信號即可。

2. 在轉(zhuǎn)換后的apb信號中,實現(xiàn)寫和讀的操作。

mcu讀操作時:

比如,mcu要讀0x60000004的寄存器:

mcu端直接C語言這樣調(diào)用:int cpRdReg = *((int
*)0x60000004);

cpld端,可以根據(jù)以上信號做如下處理:

----------------------------------------------

//mcu的讀操作響應(yīng)

//mcu端用C語言:int value = *((int *)0x60000004);

reg [31:0] ardata_reg; ?????? //定義32位的hrdata_reg

always @(posedge apb_clock) begin????? //clk上升沿觸發(fā)

if (!apb_pwrite
&&??????? ???????????????????? //
(0 讀,1 寫)

apb_penable
&&???????????????????????????????? //
是否準(zhǔn)備好

apb_paddr[11:0]
== ‘h04)??? //
讀地址為0x60000004(cpld內(nèi)部用相對偏移)

begin

ardata_reg <=
awdata_reg;????????????? //
把另一準(zhǔn)備好的數(shù)據(jù)給到hrdata_reg

end

end

assign apb_prdata = ardata_reg; //綁定hrdata_reg到讀的數(shù)據(jù)線上

-----------------------------------------------

mcu寫操作時:

比如,mcu要寫0x60000000的寄存器:

mcu端直接C語言這樣調(diào)用:*((int *)0x60000000)
= value;

cpld端,可以根據(jù)以上信號做如下處理:

----------------------------------------------

//mcu的寫操作響應(yīng)

//mcu端用C語言:*((int *)0x60000000) = value;

reg [31:0] awdata_reg; ?????? //定義32位的hwdata_reg

always @(posedge apb_clock) begin????? //clk上升沿觸發(fā)

if (apb_pwrite
&&??????? ????????????????????? //
(0 讀,1 寫)

apb_penable
&&???????????????????????????????? //
是否準(zhǔn)備好

apb_paddr[11:0]
== ‘h00)? //
寫地址為0x60000000(cpld內(nèi)部用相對偏移)

begin

awdata_reg <=
apb_pwdata;?????????? //
把收到的數(shù)據(jù)給到hwdata_reg

end

end

//這個過程,是把mcu寫進(jìn)來的數(shù)據(jù)收到hwdata_reg

-----------------------------------------------

這個功能實現(xiàn)后,其實是個簡單的“空外設(shè)”??梢杂盟鰹閷崿F(xiàn)復(fù)雜功能外設(shè)的基礎(chǔ)。

這部分的實例代碼,請參考網(wǎng)盤上cpld樣例工程《5.mcu讀寫cpld寄存器》。

樣例展示到這里,mcu和cpld的交互上:交互信號、跟ahb交互數(shù)據(jù)、跟apb交互數(shù)據(jù),基本的交互通路已經(jīng)建立。

接下來,用戶根據(jù)自己的需求,在cpld中交互到數(shù)據(jù)后,編寫自己需要的功能即可。

三、DMA在CPLD中的使用

cpld中實現(xiàn)DMA的邏輯:

1. MCU為master,cpld為slave,mcu對cpld的交互方式為存取寄存器的方式;

2. mcu中配置好DMA(讀取cpld中準(zhǔn)備好的數(shù)據(jù));

3. cpld中準(zhǔn)備好數(shù)據(jù)后,觸發(fā)dma信號,dma自動搬運(yùn)到mcu指定的ram;

4. 搬運(yùn)一次后,dma給cpld一個clear信號,完成一次dma搬運(yùn);

5. 等到cpld中再次準(zhǔn)備好數(shù)據(jù),將再次觸發(fā)dma信號,重復(fù)3和4;

對于cpld來說,mcu來讀取數(shù)據(jù)和dma來讀取數(shù)據(jù),是一致的。

dma來讀取時,只是每次讀完后會多給cpld一個clear信號。

更多細(xì)節(jié),請參考網(wǎng)盤上《7.cpld中配合實現(xiàn)mcu的dma讀取》部分的樣例。

在這個樣例中,展示了兩部分代碼:

1. mcu中,配置dma讀取;為了測試,mcu會在另一地址給cpld寫數(shù)據(jù);

2. cpld中,會對mcu寫進(jìn)來的數(shù)據(jù)緩存,緩存后觸發(fā)dma的信號,讓dma來讀取數(shù)據(jù)。而dma從cpld里讀取數(shù)據(jù)后會給cpld一個clear信號,標(biāo)志一次dma交互完成。

相關(guān)推薦

電子產(chǎn)業(yè)圖譜