用PWM的方法實(shí)現(xiàn)熒火蟲燈
上次提到要用Timer的PWM功能來實(shí)現(xiàn)熒火蟲燈。當(dāng)然還是找一個(gè)現(xiàn)成的例子來作個(gè)修改,這回要用到的例子在這里。
復(fù)制一份到自己練習(xí)用的文件夾中,建立工程。
從程序中可以知道:
?。?) 使用TIM3
?。?) PWM信號(hào)的頻率是36KHz,這是通過TIM3的ARR來設(shè)置的。ARR的值是999,因此PWM的頻率是36MHz/(999+1)=36KHz。
?。?) 四個(gè)通道的占空比分別由TIM3_CCR1~TIM3_CCR4來確定,算式是:
?。═IM3_CCR1/ TIM3_ARR)* 100
由此,當(dāng)PWM的頻率是36K時(shí),占空比分辨率接近0.1%。降低頻率,可以獲得更高的分辨率。
要完成燈的漸亮和漸滅控制,只要定時(shí)改變TIM3_CCR1的值就行了。
如何改變呢?這里用到STM32提供的系統(tǒng)定時(shí)器(SysTick)
數(shù)據(jù)手冊中關(guān)于這個(gè)定時(shí)器的描述如下:
-------------------------------------------------------------
系統(tǒng)時(shí)基定時(shí)器
這個(gè)定時(shí)器是專用于實(shí)時(shí)操作系統(tǒng),也可當(dāng)成一個(gè)標(biāo)準(zhǔn)的遞減計(jì)數(shù)器。它具有下述特性:
● 24位的遞減計(jì)數(shù)器
● 自動(dòng)重加載功能
● 當(dāng)計(jì)數(shù)器為0時(shí)能產(chǎn)生一個(gè)可屏蔽系統(tǒng)中斷
● 可編程時(shí)鐘源
而它的使用方法可以在庫提供的例子中找到。
有一個(gè)初始化函數(shù):
void SysTick_Configuration(void)
{
if (SysTick_Config((SystemFrequency) / 10)) //經(jīng)實(shí)際測試發(fā)現(xiàn),除以10是100ms,除以100是10ms,依此類推
{
/* Capture error */
while (1);
}
NVIC_SetPriority(SysTick_IRQn, 0x0);
}
這里將其初始化為每100ms產(chǎn)生一次中斷。
將這個(gè)函數(shù)放在main.c中,在main函數(shù)中調(diào)用它,即完成初始化工作。在system32_it.c中有中斷處理函數(shù)。
void SysTick_Handler(void)
{}
原例子中這里沒有寫代碼,可以根據(jù)需要自行增加相關(guān)代碼來處理每100ms時(shí)間到的事件。
代碼如下:
extern uint16_t dutyRatio;
extern uint8_t ChangDuty;
void SysTick_Handler(void)
{ static uint8_t Counter;
if(Counter》16)
dutyRatio-=62;
else
{ dutyRatio+=62;
if(dutyRatio》999)
dutyRatio=999;
}
if(++Counter》=32)
Counter=0;
ChangDuty=1;
}
這里定義了兩個(gè)變量,一個(gè)是dutyRatio,用來控制占空比的變化。它在main.c中定義,并初始化為6。初始化TIM3_CH1通道時(shí)使用該變量。
每次中斷則視情況增加或者減少,每次變化的量是62。在SysTick_Handler函數(shù)中,定義了一個(gè)static型的變量Counter,它的值在 0~31之間變化。當(dāng)其值在0~15之間時(shí),dutyRatio每次加1,這樣一共是加16次,即其最終的值是:6+16*62=998,正好比ARR的值小1。當(dāng)Counter的值在16~31之間變化時(shí),dutyRatio每次減62。這樣,dutyRatio的值始終在6~998之間變化,對應(yīng)的是占空比在:
6/999*100%=0.6% ~ 998/999*100%=99.89% 之間變化。
ChangDuty是一個(gè)標(biāo)志,用途是通知main函數(shù),占空比已發(fā)生變化,要求更新CCR1。Mina函數(shù)的處理如下:
while (1)
{ if(ChangDuty==1)
{
TIM3-》CCR1=dutyRatio;
ChangDuty=0;
}
}
在用軟件仿真時(shí),執(zhí)行到TIM3-》CCR1=dutyRatio;時(shí),外圍部件中的相應(yīng)值并沒有立即變化。目前還沒有弄清楚是調(diào)試器的問題還是確實(shí)不立即發(fā)生變化。
使用硬件來測試,由于我手邊的板子TIM3_CH1上沒有接LED,所以就看不出燈亮的效果了,不過,不要緊,還有示波器。將程序下載入FLASH后運(yùn)行,觀察GPIOA.6,可以看到非常漂亮的波形。用萬用表電壓檔測該引腳的電壓,可以看到電壓平穩(wěn)地上升和下降。所以,我有些懷疑上面提到的那個(gè)CCR1沒有立即變化僅僅只是調(diào)試器的問題。//藍(lán)色的字這個(gè)不對,下面有說明。
??? 用PWM生成正弦波
有了PWM,自然就可以用PWM的方法生成正弦波了。下面生成500Hz正弦波的方法參考自張明峰的《PIC單片機(jī)入門與實(shí)踐》
每個(gè)正弦波分成四個(gè)像限,每個(gè)像限16點(diǎn),共64點(diǎn),每點(diǎn)出現(xiàn)2個(gè)PWM周期,故PWM的周期為:2ms/128=156.25us,頻率為64KHz。
TIM3 Frequency = TIM3 counter clock/(ARR + 1)
倒過來:
ARR=TIM3 Counter Clock/TIM3 Frequenc - 1 =562.5-1 =561
如果取ARR的值是561的話,那么實(shí)際的頻率是64.056KHz,即最終生成為的正弦波頻率是:500.4Hz
有了ARR,占空比就取決于CCR1的值了,使用EXCEL可以方便地計(jì)算出第一象限的16個(gè)點(diǎn)的數(shù)據(jù):
280,307,335,361,387,412,436,458,478,496,513,527,539,548,555,559
有了第一象限,其他象限都可以鏡像生成了。具體方法請看源程序。
要用上面的例子修改,還需要做一些工作。
前面是在SysTick中做出標(biāo)志,然后在主程序中修改CCR1的值,現(xiàn)在不行了,肯定會(huì)有時(shí)間的誤差,不能這做么,要在PWM輸出后修正,這樣就要在PWM波形輸出時(shí)產(chǎn)生中斷。因此,需要在main函數(shù)中增加以下這個(gè)函數(shù)。
這個(gè)函數(shù)哪里來的呢,很簡單,從timebase工程中中抄來的然后將TIM2改成TIM3就行了^_^。然后在main函數(shù)中調(diào)用它。
注意,還需要打開stm32f10x_conf.h文件,將下面:
藍(lán)色框里面的包含文件給“解放”出來。當(dāng)然,同時(shí)要把庫中的misc.c源程序文件加入工程中來。否則,編譯是通不過的。
為了讓通道1可以產(chǎn)生中斷,還需要做一件事,就是下面藍(lán)色的部分。
/* TIM IT enable */
TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE);
//也是從TIMEBASE工程中抄來,再將TIM2改成TIM3的。
/* TIM3 enable counter */
TIM_Cmd(TIM3, ENABLE);
現(xiàn)在該到stm32f10x_it.c中去了,增加一個(gè)中斷處理函數(shù):
uint16_t sinTab[]={280,307,335,361,387,412,436,458,478,496,513,527,539,548,555,559};
uint8_t Count1,Count2; //1.像限計(jì)數(shù)器,其值在0~3之間變化 2.其值在0~31之間變化
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
if(Count2%2==0) //準(zhǔn)備更新,新的值會(huì)在下一次更新
{ switch(Count1)
{ case 0: //象限1
{
TIM3-》CCR1= sinTab[Count2/2];
break;
}
case 1: //象限2
{ TIM3-》CCR1=sinTab[15-Count2/2];
break;
}
case 2: //象限3
{ TIM3-》CCR1=560-sinTab[Count2/2];
break;
}
case 3: //象限4
{ TIM3-》CCR1=560-sinTab[15-Count2/2];
break;
}
default:break;
}
}
}
if(++Count2==32)
{ Count2=0;
if(++Count1==4)
Count1=0;
}
}
也就是在這里,搞清楚了,所謂的“我有些懷疑上面提到的那個(gè)CCR1沒有立即變化僅僅只是調(diào)試器的問題”不對,這是CCR1更新方法的問題,
注意上圖中紅色框中的描述。
這里就是不用立即更新的方法。因?yàn)槊總€(gè)點(diǎn)的PWM波形會(huì)出現(xiàn)2次,因此,用
if(Count2%2==0) 來判斷是第一次產(chǎn)生PWM波形,更新CCR1,但是這個(gè)CCR1不會(huì)立即更新,而會(huì)在下一次產(chǎn)生PWM事件時(shí)更新。
STM32的SDIO控制SD卡
一、STM32的SDIO適配器的結(jié)構(gòu)
STM32的SDIO適配器包括與AHB總線接口和SD卡接口兩個(gè)大塊兒。如下面圖中兩個(gè)灰色陰影區(qū)域。
左側(cè)的陰影部分又細(xì)分兩個(gè)子單無,適配器寄存器組和FIFO。適配器寄存器組包含了所有SDIO所有的寄存器,這些寄存器用于配置一些參數(shù),以實(shí)現(xiàn)一些SD協(xié)議中的時(shí)序,最終于實(shí)現(xiàn)SD卡的命令傳輸。FIFO則是為了實(shí)現(xiàn)數(shù)據(jù)的傳輸,這兩者部分分別代表者對SD卡的兩種傳輸操作,即命令的傳輸和數(shù)據(jù)的傳輸。
右側(cè)的陰影部分,即SDIO適配器的SD卡接口大塊兒,又細(xì)分為三個(gè)子單元??刂茊卧–ontrol Unit),命令通道和數(shù)據(jù)通道(Command Path and Data Path)。控制單元主要實(shí)現(xiàn)電源和時(shí)鐘的控制。它根據(jù)適配器寄存器組中寄存器的配置,開啟和關(guān)閉SDIO適配器模塊的電源,改變工作的時(shí)鐘源(直接使用 SDIO_CLK還是其分頻后的時(shí)鐘等)。命令通道連接CMD線,控制命令的傳輸。數(shù)據(jù)通道連接數(shù)據(jù)線(DAT0~DAT7),控制數(shù)據(jù)的傳輸。
二、分單元詳述
下面按照上面一章提到的五個(gè)子單元的劃分,對各子單元進(jìn)行詳細(xì)的描述。
1、適配器寄存器組
The adapter register block contains all system registers. This block also generates the signals that clear the static flags in the multimedia card. The clear signals are generated when 1 is written into the corresponding bit location in the SDIO Clear register.
這個(gè)STM32數(shù)據(jù)手冊上關(guān)于這一部分的全部描述,大體上就是說:適配器寄存器組包含了所有的系統(tǒng)寄存器。它還產(chǎn)生用于清除MMC卡的靜態(tài)標(biāo)志位的信號(hào)。當(dāng)向SDIO Clear register(清除寄存器)的對應(yīng)位寫1,即產(chǎn)生這個(gè)信號(hào)。
2、控制單元
這一單元又在內(nèi)部分為電源管理和時(shí)鐘管理兩個(gè)子單元,他們都受控制適配器寄存器組。時(shí)鐘管理子單元產(chǎn)生和控制時(shí)鐘信號(hào)SDIO_CK,也就是SD卡最絡(luò)接收到的SCK。時(shí)鐘管理子單元工作于兩種模式時(shí)鐘分頻模式和時(shí)鐘直通模式(Bypass,標(biāo)準(zhǔn)的翻譯不知是什么,似乎可以是“旁路”,但“直通”更容易理解些)。當(dāng)工作在直通模式進(jìn),SDIO_CK==SDIO_CLK.工作于分頻模塊時(shí),SDIO_CK==SDIO_CLK/div.
在如下情形下,時(shí)鐘是不輸出時(shí)鐘信號(hào)的:
復(fù)位后
上電和掉電期間
省電模式下總線處于空閑模式時(shí)
電源管理子單元在上電和掉電時(shí)關(guān)繼時(shí)適配器的輸出信號(hào)。
3、命令通道
命令通道向卡發(fā)送命令和接收回應(yīng)。
如圖所示,圖上左側(cè)陰影部分是屬于適配器寄存器組子單元里的兩個(gè)寄存器,分別為SDIO_ARG和SDIO_CMD,后者用于添加想要發(fā)送的命令,前者用于添加所要發(fā)送的命令的參數(shù),將兩個(gè)添好之后使能命令發(fā)送,命令就會(huì)自動(dòng)發(fā)送出去。適配器上述兩個(gè)寄存器的內(nèi)容進(jìn)行組合,并最終形成48位長的命令,這48 位首先進(jìn)入移位寄存器,即圖中的Shift register,在這里由并轉(zhuǎn)串一位一位的發(fā)送,由圖可見,這些位要經(jīng)過CRC后,才發(fā)送出去。實(shí)際上,前面講的總位數(shù)并非48,在這里經(jīng)過CRC,生成那些位的CRC較驗(yàn)值,并追加到其尾部,最絡(luò)才是48位。命令分為有回應(yīng)的和沒有回應(yīng)的兩種。如果發(fā)送的是沒有回應(yīng)的命令,發(fā)送之后會(huì)對標(biāo)志位中的相送位置位,通知系統(tǒng),命令發(fā)送正常,然后進(jìn)入空閉狀態(tài)。如果發(fā)送的命令是有回應(yīng)的命令,則要等待回應(yīng)。接收到回應(yīng)之后,會(huì)對回應(yīng)進(jìn)行CRC校驗(yàn),并設(shè)定相關(guān)位。下面是命令通道的狀態(tài)機(jī):
進(jìn)入等待狀態(tài)后,命令時(shí)鐘(command timer)開始計(jì)時(shí),如果到達(dá)超時(shí)時(shí)間CPSM狀態(tài)機(jī)還沒移動(dòng)到接收狀態(tài),則置位超時(shí)標(biāo)志并進(jìn)入空閑狀態(tài)。
注意:命令超時(shí)時(shí)間是固定值,為64個(gè)SDIO_CK。
如果在命令寄存器中設(shè)置了中斷位(interrupt bit),就不會(huì)啟用上面講到的超時(shí)時(shí)鐘,CPSM狀態(tài)機(jī)會(huì)一直等待來自卡的中斷請求。如果在命令寄存器中置位了懸停位(pending bit),CPSM狀態(tài)機(jī)會(huì)進(jìn)入懸停狀態(tài)(所謂的掛起狀態(tài)),并等待來自數(shù)據(jù)通道子單元的CmdPend信號(hào)。檢測到CmdPend位以為,CPSM狀態(tài)機(jī)會(huì)移動(dòng)到發(fā)送狀態(tài)(Send state),這將使數(shù)據(jù)計(jì)數(shù)器停止命令的傳輸。
注意:CPSM會(huì)在空閑模式停留至少8個(gè)SDIO_CK時(shí)間,以滿足Ncc和Nrc的時(shí)間要求。Ncc時(shí)兩次主機(jī)命令傳輸?shù)淖钚⊙舆t,而Nrc時(shí)主機(jī)命令與卡的回應(yīng)之間的最小延遲。如下圖:
命令的格式:
命令即是開始傳輸?shù)囊粋€(gè)標(biāo)記。命令由主機(jī)發(fā)送給單個(gè)卡(尋址性命令)或是所有的卡(廣播性命令,MMC V3.31及更早的MMC卡標(biāo)準(zhǔn)中支持)。命令通過CMD信號(hào)線串行傳輸,所有的命令都有一個(gè)固定的長度,即48位。命令的格式如下圖:
命令通道工作于半雙工模式,所以可以發(fā)送,也可以接收命令或回應(yīng)。如果CPSM狀態(tài)機(jī)不在發(fā)送狀態(tài)(Send State),SDIO_CMD為高阻狀態(tài)(Hi-Z state),如下圖:
SDIO_CMD在SDIO_CK的上升沿進(jìn)行同步。
回應(yīng):
回應(yīng)是由被尋址的卡發(fā)出的一個(gè)標(biāo)記(或是在MMC V3.31及以前標(biāo)準(zhǔn)中,所有連接在適配器上的卡同步發(fā)送),此標(biāo)記由卡發(fā)給主機(jī),是對剛剛接收到的命令的回答?;貞?yīng)是在CMD信號(hào)線上串行傳輸?shù)摹?/p>
SDIO支持兩種回應(yīng)類型,都是進(jìn)行CRC校驗(yàn)的:
48位的短回應(yīng)(short response)
136位的長回應(yīng)(long response)
注意:如果回應(yīng)不包含CRC校驗(yàn)信息(如CMD1的回應(yīng)),設(shè)備驅(qū)動(dòng)就必須忽略CRC錯(cuò)誤的狀態(tài)。
下面兩張表是兩種回應(yīng)的格式:
前面講到,SDIO適配器包含兩個(gè)大塊兒,詳見本帖開頭,這里只拿出圖來:
其中,與AHB接口相連的有兩個(gè)塊兒,就是上圖中左側(cè)陰影部分,Adapter registers 和FIFO,即適配器寄存器組和數(shù)據(jù)FIFO。前者包含了適配器所有的寄存器,用于配置相應(yīng)時(shí)序,產(chǎn)生相應(yīng)的信號(hào)。
這里面,用于控制命令通道產(chǎn)生命令時(shí)序的就有兩個(gè)寄存器,名為SDIO_ARG和SDIO_CMD,SDIO_ARG的三十二位全部用來存儲(chǔ)命令參數(shù),也就沒什么好講的了。SDIO_CMD則不同,它有六個(gè)位,用來識(shí)別不同的命令,總共可以區(qū)別64個(gè),但實(shí)際上SD卡的命令集沒有那么多。 SDIO_CMD還有一些位,用來表示些命令時(shí)否有回應(yīng),是長回應(yīng)還是短回應(yīng),命令的類型是什么等等。適配器最終根據(jù)這些,加上CRC組合成一個(gè)48位的命令。
另外,我們還提到過命令發(fā)送之后,如果這是一個(gè)沒有回應(yīng)的命令,那么就很簡單,命令通道直接置位CMDSENT標(biāo)志,或進(jìn)入空閑狀態(tài)。如果是有回應(yīng)的,則要等待回應(yīng),并設(shè)定相關(guān)的標(biāo)志位。命令通道的相關(guān)標(biāo)志位如下:
CRC 產(chǎn)生器計(jì)算的是CRC碼前面的所有位的校驗(yàn)和。這包括開始位,傳輸位,命令索引(command index)和命令參數(shù)(和卡狀態(tài))。對長回應(yīng)格式來說,CRC校驗(yàn)和計(jì)算的是CID或CSD的前120位。這里不包括開始位,傳輸位和六個(gè)保留位。 CRC是一個(gè)7位的值,其計(jì)算方法如下:
?
補(bǔ)充一些硬件知識(shí)
SEGGER 給出的Jlink引腳圖
開發(fā)板上的連接圖
標(biāo)準(zhǔn)的JTAG連接圖,供對照參考。
調(diào)試方式既可以用JTAG,也可以用SW。
以下是轉(zhuǎn)載:
SWD 仿真模式概念簡述
先所說 SWD 和傳統(tǒng)的調(diào)試方式有什么不一樣:
首先給大家介紹下經(jīng)驗(yàn)之談:
?。ㄒ唬?SWD 模式比 JTAG 在高速模式下面更加可靠。 在大數(shù)據(jù)量的情況下面 JTAG 下載程序會(huì)失敗, 但是 SWD 發(fā)生的幾率會(huì)小很多。 基本使用 JTAG 仿真模式的情況下是可以直接使用 SWD 模式的, 只要你的仿真器支持。 所以推薦大家使用這個(gè)模式。
?。ǘ?在大家 GPIO 剛好缺一個(gè)的時(shí)候, 可以使用 SWD 仿真, 這種模式支持更少的引腳。
(三): 在大家板子的體積有限的時(shí)候推薦使用 SWD 模式, 他需要的引腳少, 當(dāng)然需要的 PCB 空間就小啦。 比如: 你可以選擇一個(gè)很小的 2.54 間距的 5 芯端子做仿真接口。
?。?) 仿真器對 SWD 模式支持情況
再說說市面上的常用仿真器對 SWD 仿真的支持情況。
?。?) JLINKV6 支持 SWD 仿真模式。 速度較慢。
(2) JLINKV7 比較好的支持 SWD 仿真模式, 速度有了明顯的提高。 速度是 JLINKV6 的 6 倍。
(3) JLINKV8 非常好的支持 SWD 仿真模式, 速度可以到 10M.
?。?) ULINK1 不支持 SWD 模式
(5) 盜版 ULINK2 非常好的支持 SWD 模式。 速度可以達(dá)到 10M.
?。?) 正版 ULINK2 非常好的支持 SWD 模式。 速度可以達(dá)到 10M.
再所說硬件上的不同:
?。?) JLINKV6 需要的硬件接口為: GND, RST, SWDIO, SWDCLK
?。?) JLINKV7 需要的硬件接口為: GND, RST, SWDIO, SWDCLK
?。?) JLINKV8 需要的硬件接口為: VCC, GND, RST, SWDIO, SWDCLK
注:下面有我自己實(shí)驗(yàn)的結(jié)果
?。?) ULINK1 不支持 SWD 模式
?。?) 盜版 ULINK2 需要的硬件接口為: GND, RST, SWDIO, SWDCLK
?。?) 正版 ULINK2 需要的硬件接口為: GND, RST, SWDIO, SWDCLK
由此可以看到只有 JLINKV8 需要 5 個(gè)引腳。 那么給大家介紹下為什么有了 VCC 這個(gè)引腳時(shí)候有好處, 我的個(gè)人理解: 我認(rèn)為有這個(gè)引腳是最合適的, 仿真器對目標(biāo)板子的仿真需要用到 RST 引腳, 其實(shí)使用仿真器內(nèi)部的 VCC 做這個(gè)功能其實(shí)并不是非常美妙。 因此 JLINKV8 選擇了只和目標(biāo)板共 GND, 但是不共 VCC. 因此我覺得這種模式最合理, 當(dāng)然通常情況下仿真器和目標(biāo)板共 GND 和 VCC 是沒有錯(cuò)的。
?。?) 在 MDK 中SWD 模式設(shè)置
接下來告訴大家怎么使用 SWD 設(shè)置:
打開工程 Option 設(shè)置:
在設(shè)置中按照上圖設(shè)置成 SWD 模式, 速度你可以按照你的實(shí)際需求來設(shè)置, 如果你的板子供電系統(tǒng)不是特別穩(wěn)定, 紋波比較大或者仿真線比較長可以設(shè)置成 500K 或者 1M , 如果環(huán)境很好當(dāng)然可以選擇 10M , 當(dāng)然速度會(huì)飛起來。 記得不要忽略了左下方的那個(gè)USB 還是 TCP 模式, 當(dāng)然我們是 USB 模式, 因?yàn)橛械臅r(shí)候默認(rèn)是 TCP 模式, 這個(gè)時(shí)候我們忽略這個(gè)設(shè)置后會(huì)仿真常常連接不上的。
JTAG引腳可以被復(fù)用為IO口,但是這樣一來,JLINK就不能夠連上芯片了。解決的方法有兩種:
?。?) 另寫一段程序,不要將JTAG復(fù)用為I/O口,然后將這段程序用串口工具寫入芯片中;
?。?) 將BOOT0/BOOT1設(shè)置成為內(nèi)部RAM啟動(dòng),那么上電后就不會(huì)執(zhí)行FLASH中的程序,這樣JLINK就能順利“接管”JTAG引腳。
按SW方式來調(diào)試
1腳不接時(shí)出現(xiàn)的畫面
DMA初步
DMA有什么用?
直接存儲(chǔ)器存取用來提供在外設(shè)和存儲(chǔ)器之間或者存儲(chǔ)器和存儲(chǔ)器之間的高速數(shù)據(jù)傳輸。無須CPU的干預(yù),通過DMA數(shù)據(jù)可以快速地移動(dòng)。這就節(jié)省了CPU的資源來做其他操作。
有多少個(gè)DMA資源
有兩個(gè)DMA控制器,DMA1有7個(gè)通道,DMA2有5個(gè)通道。
數(shù)據(jù)從什么地方送到什么地方?
外設(shè)到SRAM(I2C/UART等獲取數(shù)據(jù)并送入SRAM);
SRAM的兩個(gè)區(qū)域之間;
外設(shè)到外設(shè)(ADC讀取數(shù)據(jù)后送到TIM1控制其產(chǎn)生不同的PWM占空比);
SRAM到外設(shè)(SRAM中預(yù)先保存的數(shù)據(jù)送入DAC產(chǎn)生各種波形);
……還有一些目前還搞不清楚的。
DMA可以傳遞多少數(shù)據(jù)?
傳統(tǒng)的DMA的概念是用于大批量數(shù)據(jù)的傳輸,但是我理解,在STM32中,它的概念被擴(kuò)展了,也許更多的時(shí)候快速是其應(yīng)用的重點(diǎn)。數(shù)據(jù)可以從1~65535個(gè)。
通道是如何分配的?
見下面的這個(gè)表:
如何來用DMA?
確定數(shù)據(jù)來源,確定數(shù)據(jù)目的地,選擇使用哪個(gè)通道,設(shè)定傳輸多少個(gè)數(shù)據(jù),設(shè)定數(shù)據(jù)傳遞模式等等就可以了。且讀一下STM32提供給我們的例子。
//////////////////////////////////////////
……
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)TIM1_CCR3_Address;
//設(shè)定外圍設(shè)備的地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SRC_Buffer;
//設(shè)定內(nèi)存地址,SRC_Buffer是前面定義的一個(gè)數(shù)組
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //方向控制
DMA_InitStructure.DMA_BufferSize = 3; //緩沖區(qū)大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外圍地址增量控制
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //內(nèi)存地址增量控制
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
//DMA_PeripheralDataSize_HalfWord的值為0x100,后一個(gè)為0x400,在在stm32f10x_dma.h中定義,用于決定存儲(chǔ)器數(shù)據(jù)寬度
*/
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
以下是stm32f10x_dma.c中有關(guān)DMA的初始化設(shè)置代碼
tmpreg |= DMA_InitStruct-》DMA_DIR | DMA_InitStruct-》DMA_Mode |
DMA_InitStruct-》DMA_PeripheralInc | DMA_InitStruct-》DMA_MemoryInc |
DMA_InitStruct-》DMA_PeripheralDataSize | DMA_InitStruct-》DMA_MemoryDataSize |
DMA_InitStruct-》DMA_Priority | DMA_InitStruct-》DMA_M2M;
/* Write to DMAy Channelx CCR */
DMAy_Channelx-》CCR = tmpreg;
/*--------------------------- DMAy Channelx CNDTR Configuration ---------------*/
/* Write to DMAy Channelx CNDTR */
DMAy_Channelx-》CNDTR = DMA_InitStruct-》DMA_BufferSize;
/*--------------------------- DMAy Channelx CPAR Configuration ----------------*/
/* Write to DMAy Channelx CPAR */
DMAy_Channelx-》CPAR = DMA_InitStruct-》DMA_PeripheralBaseAddr;
/*--------------------------- DMAy Channelx CMAR Configuration ----------------*/
/* Write to DMAy Channelx CMAR */
DMAy_Channelx-》CMAR = DMA_InitStruct-》DMA_MemoryBaseAddr;
//內(nèi)存地址送入CMAR寄存器
說明:這個(gè)圖從PDF截下來,圖中那個(gè)DMA_CPARx寫錯(cuò)了,應(yīng)該是DMA_CMARx
------------------------------------------------------------------------------------------
再來看一個(gè)DMA的例子
/* DMA1 Channel5 configuration ----------------------------------------------*/
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)TIM1_CCR1_Address;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC1_DR_Address;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
/* Enable DMA1 Channel5 */
DMA_Cmd(DMA1_Channel5, ENABLE);
還有一些目前暫時(shí)還沒有去搞清楚的,比如中斷處理等,等到需要時(shí)再看吧。
——下次將討論學(xué)習(xí)用認(rèn)識(shí)ADC兼進(jìn)一步看懂STM的庫,敬請繼續(xù)關(guān)注。
?
評論