STM32學(xué)習(xí)筆記(串口、IAP)
串口:
一. USART_ITConfig(USART1, USART_IT_TXE, ENABLE):
只要發(fā)送寄存器為空,就會(huì)一直有中斷,因此,要是不發(fā)送數(shù)據(jù)時(shí),把發(fā)送中斷關(guān)閉,只在開(kāi)始發(fā)送時(shí),才打開(kāi)。
二.
以下是字符發(fā)送的配置過(guò)程,注意第6點(diǎn),在設(shè)置USART_CR1中的TE位時(shí),會(huì)發(fā)送一個(gè)空閑幀作為第一次數(shù)據(jù)發(fā)送,所以即便你執(zhí)行了USART_ClearFlag(USART1, USART_FLAG_TC); (這個(gè)函數(shù)肯定在空閑幀數(shù)據(jù)發(fā)送完成前執(zhí)行),所以當(dāng)空閑幀發(fā)送完后,就進(jìn)入發(fā)送完成中斷。
配置步驟:
1.通過(guò)在USART_CR1寄存器上置位UE位來(lái)激活USART
2.編程USART_CR1的M位來(lái)定義字長(zhǎng)。
3.在USART_CR2中編程停止位的位數(shù)。
4.如果采用多緩沖器通信,配置USART_CR3中的DMA使能位(DMAT)。按多緩沖器通信中
的描述配置DMA寄存器。
5.利用USART_BRR寄存器選擇要求的波特率。
6.設(shè)置USART_CR1中的TE位,發(fā)送一個(gè)空閑幀作為第一次數(shù)據(jù)發(fā)送。
7.把要發(fā)送的數(shù)據(jù)寫進(jìn)USART_DR寄存器(此動(dòng)作清除TXE位)。在只有一個(gè)緩沖器的情況
下,對(duì)每個(gè)待發(fā)送的數(shù)據(jù)重復(fù)步驟7。
8.在USART_DR寄存器中寫入最后一個(gè)數(shù)據(jù)字后,要等待TC=1,它表示最后一個(gè)數(shù)據(jù)幀的
傳輸結(jié)束。當(dāng)需要關(guān)閉USART或需要進(jìn)入停機(jī)模式之前,需要確認(rèn)傳輸結(jié)束,避免破壞
最后一次傳輸。
解決的辦法:
方法一
在執(zhí)行USART_ITConfig(USART1,USART_IT_TC, ENABLE); 之前,
先延時(shí)一段時(shí)間,基本上比一個(gè)字符發(fā)送的時(shí)間長(zhǎng)一點(diǎn)就可以了,然后再執(zhí)行
USART_ClearFlag(USART1, USART_FLAG_TC);
方法二:
在執(zhí)行USART_ITConfig(USART1,USART_IT_TC, ENABLE); 之前,
USART_ClearFlag(USART1, USART_FLAG_TC);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET)
{
; //等待空閑幀發(fā)送完成后再清零發(fā)送標(biāo)志
}
USART_ClearFlag(USART1,USART_FLAG_TC);
三.
TXE:發(fā)送緩沖器空閑標(biāo)志
RXNE:接收緩沖區(qū)非空
IAP:
一.
問(wèn):
這幾天在折騰STM32的IAP,參考了兩個(gè)例程,一個(gè)AN2557,然后一個(gè)就是標(biāo)準(zhǔn)外設(shè)庫(kù)內(nèi)的flash例程
總結(jié)IAP:
1.Flash解鎖FLASH_Unlock();
2.清除Flash所有的未完成的標(biāo)志位FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);
3.根據(jù)文件大小擦除Flash
for(EraseCounter=0;(EraseCounter
FLASHStatus=FLASH_ErasePage(StartAddr+(FLASH_PAGE_SIZE*EraseCounter));
}
4.編程Flash
while((Address
FLASHStatus=FLASH_ProgramWord(Address,Data);
Address=Address+4;
}
5.檢驗(yàn)編入數(shù)據(jù)的正確性
while((Address
if((*(__IOuint32_t*)Address)!=Data)
{
MemoryProgramStatus=FAILED;
}
Address+=4;
}
在以上幾步中,如果上面沒(méi)有問(wèn)題的話,提出下面幾個(gè)疑問(wèn)
1.假如我的應(yīng)用程序的地址應(yīng)該從0x8003000開(kāi)始,那么我把后面的頁(yè)全部擦除是否可以?雖然我的程序可能只占到0x8003000-0x8005000那么這之后的頁(yè)是否也可以一并擦除?
2.在編程的時(shí)候有個(gè)很小的問(wèn)題,因我的數(shù)據(jù)都是以字節(jié)(byte)的形式儲(chǔ)存的,在寫的時(shí)候因?yàn)橹荒芤园胱?16位)或一個(gè)字(32位)的方式編程,那么如果我的bin
文件的最后一個(gè)字節(jié)并不夠兩個(gè)字節(jié),怎么辦?舉例:我的bin文件的大小是501個(gè)字節(jié)(8位),我的寫入方法是這樣的:
data[501]={X,X,X...}//應(yīng)用程序bin文件內(nèi)容
temp=data[0];
temp=temp<<8;
temp|=data[1];
temp=temp<<8;
temp|=data[2];
teme=temp<<8;
teme|=data[3];//待寫入得數(shù)據(jù)
FLASHStatus=FLASH_ProgramWord(Address,temp);//寫入flash
如果像這樣的話,那么不能被4整除的那一個(gè)字節(jié)怎么辦?
3.IAP程序中有一處一直很迷惑,不能理解
/*Testifusercodeisprogrammedstartingfromaddress"ApplicationAddress"*/
if(((*(__IOuint32_t*)ApplicationAddress)&0x2FFE0000)==0x20000000)
{/*Jumptouserapplication*/
JumpAddress=*(__IOuint32_t*)(ApplicationAddress+4);
Jump_To_Application=(pFunction)JumpAddress;
/*Initializeuserapplication'sStackPointer*/
__set_MSP(*(__IOuint32_t*)ApplicationAddress);
Jump_To_Application();
}
程序的整體是要跳出IAP引導(dǎo)區(qū)跳到應(yīng)用程序區(qū).那么這句判斷的依據(jù)是什么?if(((*(__IOuint32_t*)ApplicationAddress)&0x2FFE0000)==0x20000000)
倘若我今天的程序是重0x8003000處開(kāi)始,那么明天我升級(jí)一個(gè)程序,他的開(kāi)始是0x80080000呢?這里需要改嗎?
0x2FFE00000x20000000這兩個(gè)數(shù)我在AN2557的例子代碼里反復(fù)尋找,并沒(méi)有哪里出現(xiàn),那么又是怎么跟用戶的應(yīng)用程序關(guān)聯(lián)的呢?
還有如果將上面的例子直接這樣更改,是否可以達(dá)到跳轉(zhuǎn)到應(yīng)用程序區(qū)的目的呢?
/*Jumptouserapplication*/
JumpAddress=*(__IOuint32_t*)(ApplicationAddress+4);//這里為何要+4?+了4不就跳過(guò)出應(yīng)用程序的入口了嗎?
Jump_To_Application=(pFunction)JumpAddress;
/*Initializeuserapplication'sStackPointer*/
__set_MSP(*(__IOuint32_t*)ApplicationAddress);
Jump_To_Application();
4.關(guān)于Flash的寫保護(hù)問(wèn)題,在3.0標(biāo)準(zhǔn)外設(shè)庫(kù)中Flash還有另外一個(gè)例子,就是關(guān)于保護(hù)的
無(wú)疑flash的保護(hù)是對(duì)程序的一個(gè)安全保障,但目前我買的新片子(未進(jìn)行過(guò)任何保護(hù)方面的操作)中,是否不需要考慮這些問(wèn)題,直接擦除,然后編程即可?
5.有什么理由要“今天的程序是重0x8003000處開(kāi)始,明天又升級(jí)一個(gè)程序,他的開(kāi)始是呢”?第1沒(méi)有必要,第2是自尋煩惱。開(kāi)始地址是你自己定的,為什么要自己為難自己?
這個(gè)問(wèn)題怪我沒(méi)說(shuō)清楚,其實(shí)我是想說(shuō),我現(xiàn)在的引導(dǎo)區(qū)這樣定義的#ApplicationAddress0x80030000我只能啟動(dòng)起始地址在0x08003000處的應(yīng)用程序,那么這段代碼是可以成功啟動(dòng)的(我驗(yàn)證過(guò)):
/*Testifusercodeisprogrammedstartingfromaddress"ApplicationAddress"*/
if(((*(__IOuint32_t*)ApplicationAddress)&0x2FFE0000)==0x20000000)
{/*Jumptouserapplication*/
JumpAddress=*(__IOuint32_t*)(ApplicationAddress+4);
Jump_To_Application=(pFunction)JumpAddress;
/*Initializeuserapplication'sStackPointer*/
__set_MSP(*(__IOuint32_t*)ApplicationAddress);
Jump_To_Application();
}
那如果我現(xiàn)在想引導(dǎo)啟動(dòng)地址在0x80080000的應(yīng)用程序,是否只要更改#ApplicationAddress0x80080000這句就好?上面那串代碼就不需要更改了吧?
我還是想理解了上面的那串代碼到底是為什么?希望香版能仔細(xì)幫我解釋下,(當(dāng)我白癡好了,呵呵)!
答:
1.可以,只要不影響功能就行
2.比較好的解決方法,先讀一頁(yè)出來(lái)到RAM,擦掉這一頁(yè)Flash,在RAM中修改相應(yīng)的Bytes,再將整頁(yè)寫回去?!∫话愕慕鉀Q方法,后面不足一個(gè)WORD/DWORD的補(bǔ)0xff或0x00,補(bǔ)齊一個(gè)WORD或DWORD
3.ApplicationAddress對(duì)應(yīng)著你的應(yīng)用程序"stm32f10x_vector.c"這個(gè)文件中的__vector_table
*(__IOuint32_t*)ApplicationAddress與__vector_table[0]是一樣的
*(__IOuint32_t*)(ApplicationAddress+4)與__vector_table[1]是一樣的
__vector_table[0]是應(yīng)用程序棧的頂
__vector_table[1]是應(yīng)用程序的啟動(dòng)地址
這里有討論過(guò)
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=1600156&bbs_page_no=3&bbs_id=3020
(X&0x2FFE0000)==0x20000000意思是說(shuō)X是不是在0x20000000與0x2001FFFF之間,即棧頂是不是在以0x20000000開(kāi)始的128K
的范圍內(nèi),這里便是STM32的RAM區(qū)域,雖然現(xiàn)在最大的只有64k
如果你的bootloader只能啟動(dòng)0x08003000的應(yīng)用程序,那么你寫一個(gè)起始地址在0x08008000的程序他將不能啟動(dòng)
你要寫一個(gè)在0x080003000的啟動(dòng)程序來(lái)啟動(dòng)0x08008000的應(yīng)用程序,或者把0x08008000前八字節(jié)的內(nèi)容放到0x08003000中
4.是的,買回來(lái)的可以直接寫,出廠時(shí)芯片的Flash都沒(méi)有設(shè)置保護(hù)。