大家在開發(fā)過程中遇到BUG?
真正的目的是給自己一個糾錯記錄,最近老是忘事,遇到的bug,過幾天再次遇到,就會忘了之前如何處理,遂留筆記一篇,也給后面可能遇到該問題的小伙伴一個借鑒。
問題匯總:最近沒得更新,主要是我們搞到了一批芯片,之前的項(xiàng)目可以重新提上日程,于是保留了之前的開發(fā)思路,在其他MCU平臺上進(jìn)行重新開發(fā),遇到的問題是一件接著一件。首先產(chǎn)品端最初是STM32F030,現(xiàn)在的情況大家都了解,這顆料肯定是無法再用了,雖然手里還有幾千片存貨,可能一周都堅(jiān)持不住,于是主控?fù)Q成了GD32E230F4,主頻更高,但是flash太小,我的代碼編譯之后會超出內(nèi)存空間,此為所遇問題之一。我們有一個用于給產(chǎn)品配合的小玩意,一般一個客戶有幾個就行,小客戶一個便可。之前為了開發(fā)快捷迅速,選擇了STM32F103作為主控,所有功能開發(fā)完畢。
但是因?yàn)檫@個小玩意是免費(fèi)贈送,而且現(xiàn)在STM32F103也買不到,這個問題只有換芯片才能解決,于是換了GD32E230F4,同樣面臨代碼空間不夠的問題,而且還附帶其他問題,此為其二。還有一個是用STM32F030遇到發(fā)送數(shù)據(jù)也會進(jìn)入USART的空閑中斷,無論代碼如何處理。此為其三。
問題詳情及解決之道:
問題一:flash空間不足的問題我算是解決了一半,只能算解決了問題,而解決問題后所帶來的其他問題,本人暫時無法追蹤原因。因?yàn)橹癝TM32F030的flash足夠大,所以沒遇到這個問題,在資源緊張的GD32E230中遇到了。但是在缺貨的情況下,能找到一顆供應(yīng)滿足的MCU實(shí)屬不易,想方設(shè)法也得用起來。在代碼編寫完之后遇到如下問題:
我第一次遇到這種問題,去搜索發(fā)現(xiàn)是代碼太大,無法燒錄進(jìn)MCU的FLASH。檢查發(fā)現(xiàn)code的確超出容量了。
于是借鑒網(wǎng)絡(luò)上的方法提高優(yōu)化等級。
可以發(fā)現(xiàn)明顯變小,燒錄也沒問題,但是代碼不正常運(yùn)行,沒有卡死在任何地方,但是確實(shí)功能異常,在debug后發(fā)現(xiàn)問題出在SPI通信,我使用DMA+SPI0,發(fā)送一個數(shù)組給傳感器例如tx[3] = {0x01,0x02,0x03};然后接受數(shù)組可以正常接收到傳感器數(shù)據(jù)rx[3] = {0x01,0x02,0x03},將優(yōu)化等級提高到1,此時SPI收到的數(shù)據(jù)rx[3] = {0x03,0x01,0x02}。這就導(dǎo)致了我后面處理SPI數(shù)據(jù)的時候數(shù)據(jù)出錯。于是我將發(fā)送的數(shù)據(jù)改為4個,也就是多發(fā)一個字節(jié),此時接收到的數(shù)據(jù)是rx[4] = {0x00,0x01,0x02,0x03}。我在取數(shù)據(jù)的時候取后三個便可,這是一個治標(biāo)不治本的辦法,至今我沒找到解決之道。其實(shí)這個問題的根源就是硬件IIC的驅(qū)動太大了,我沒能簡化掉。但是發(fā)現(xiàn)提高優(yōu)化等級可以將代碼空間壓縮,那FLASH不就有閑置空間了嗎?為何還要用外置EEPROM呢?于是舍棄外置EEPROM,更換片內(nèi)FLAH。因?yàn)橐豁揻lash足夠我用了,這里只寫一頁,下面的代碼是參考官方例程自己簡化的一個寫FLASH的驅(qū)動,灰常好用。
void fmc_program(uint8_t* p_buffer,uint32_t Start_Address,uint16_t number_of_byte)
{
uint32_t u32data;//fmc解鎖
fmc_unlock();
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGERR);
fmc_page_erase(ERASE_PAGE_START_ADDR);
address = PROGRAM_ADDRESS;
for(uint16_t i = 0;i<number_of_byte;i++)
{
u32data = (uint32_t)p_buffer[i];
fmc_word_program(address, u32data);
address+= 4U;
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGERR);
}
fmc_lock(); //fmc上鎖
}
GD的FLASH例程叫FMC,一開始都沒找到,以為例程沒有。
過程很簡單:
1.使用庫函數(shù)fmc_unlock();函數(shù)將FLAH解鎖,
2.使用庫函數(shù)清標(biāo)志位fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGERR);
3.使用庫函數(shù)fmc_page_erase(ERASE_PAGE_START_ADDR);擦除一頁,寫之前必須先擦除,而且一擦就是整頁,這里我有個內(nèi)容沒寫,是需要先將原來的數(shù)據(jù)讀出來的,否則會造成不需要改的數(shù)據(jù)擦掉。讀數(shù)據(jù)直接取地址就行,將數(shù)據(jù)全讀到一個數(shù)組中,然后在數(shù)組中將需要改的數(shù)據(jù)修改,調(diào)用這個驅(qū)動進(jìn)行寫便可。ERASE_PAGE_START_ADDR為該頁的首地址。4.調(diào)用函數(shù)fmc_word_program(address, u32data);循環(huán)寫入,我是從頁首開始寫,這個參數(shù)address就是上面的ERASE_PAGE_START_ADDR。5.寫完重新置位標(biāo)志位并上鎖。
uint32_t data;
address = PROGRAM_ADDRESS;
for(uint16_t j=0;j<256;j++)//取出所有FLASH里面的數(shù)據(jù)
{
data = *(uint32_t*)address;
i2c_rxbuff[j] = (uint8_t)data;
address += 4U;
}
上面是將整頁數(shù)據(jù)讀出放在數(shù)組i2c_rxbuff中。
這里忽然想到還有一個問題,這里得說一下:我的工程用到了IIC,目的是像24C04里面寫數(shù)據(jù),但是我的項(xiàng)目要求沒有足夠的時間給我寫,每個上位機(jī)的指令過來我必須及時回復(fù),間隔時間只有幾十微秒,而寫24c04需要的是ms級別的時間,而且GD32E230沒有足夠的DMA通道給我使用,會和URAT以及SPI的DMA沖突。于是擠壓了一點(diǎn)時間出來,在主循環(huán)執(zhí)行IIC寫操作,其他應(yīng)用用DMA處理,這樣每個指令之間都可以空出一點(diǎn)點(diǎn)時間來寫,慢慢寫唄,不影響正常通信就行。但是在調(diào)試的時候發(fā)現(xiàn)了一個問題,這個問題很嚴(yán)重,但是不會影響我之前的應(yīng)用,前提是我不在主循環(huán)進(jìn)行IIC的讀寫。問題很簡單,我退出不了串口接收中斷,這個問題在一般應(yīng)用中很常見,但是因?yàn)轫?xiàng)目需求的原因,我所有的應(yīng)用都在中斷內(nèi)完成,沒有中斷外的應(yīng)用,都是一個中斷打斷另一個中斷。最后還是在論壇里找到了答案。這一點(diǎn)在GD的例程中是沒有體現(xiàn)的,
問題二:代碼空間不足的問題上文已經(jīng)處理,這里不贅述。這里說一下其他問題。我們的產(chǎn)品為例節(jié)省成本,基本都是使用MCU內(nèi)部時鐘,之前ST是,現(xiàn)在GD也是,所用外設(shè)為:USRAT,SPI,IIC。均無任何問題。但是在芯片荒之前用STM32F103做這個小玩意時加上了外部晶振,而這次改用GD32E230再次取消外部晶振,于是遇到了大問題。我通過定時器觸發(fā)SPI采集若干個數(shù)據(jù),在MCU內(nèi)部進(jìn)行算法處理,得到的值有問題,我懷疑是MCU計(jì)算出錯,畢竟里面包括了浮點(diǎn)運(yùn)算,三角函數(shù)等等。于是我將數(shù)據(jù)導(dǎo)入到EXCLE中,發(fā)現(xiàn)計(jì)算并無問題。最后問題定位在定時器不準(zhǔn),在使用內(nèi)部時鐘時,其他通信外設(shè)沒有問題,我就覺得內(nèi)部時鐘是可靠的,但是遇到定時器他就歇菜了。于是重新打板,問題得以解決。還有個問題就是很容易出現(xiàn)的SPI通信問題,在產(chǎn)品上,MCU和傳感器是在同一個PCB上,距離很近,用100Khz的通信速率可以讀寫傳感器內(nèi)部EEPROM,但是用這個小玩意和產(chǎn)品通信時通過排線連接,100K的通信速率會導(dǎo)致通信失敗,降低通信速率,將速率降低到50K便可。
問題三:發(fā)送數(shù)據(jù)進(jìn)入串口接收中斷直到寫這篇帖子之前才找到原因,在網(wǎng)上沒找到這個問題的解決之道,也懷疑過時清標(biāo)志位的問題,但是無論我如何操作,都無法解決這個問題。然后用示波器點(diǎn)了一下rx
明明在發(fā)送數(shù)據(jù),但是卻有一個下降沿,然后再看空閑中斷的定義:空閑中斷是接收數(shù)據(jù)后出現(xiàn)一個byte的高電平(空閑)狀態(tài),就會觸發(fā)空閑中斷.并不是空閑就會一直中斷,準(zhǔn)確的說應(yīng)該是上升沿(停止位)后一個byte,如果一直是低電平是不會觸發(fā)空閑中斷的。因?yàn)檫@一個電平的下拉,導(dǎo)致電平回拉的時候產(chǎn)生了一個上升沿,導(dǎo)致誤判為空閑狀態(tài)。查看電路圖,發(fā)現(xiàn)了一顆礙事的下拉電阻。
于是將該電阻拆掉便可,這個問題之所以一直未發(fā)現(xiàn),其實(shí)是之前所有的應(yīng)用都用不到空閑中斷,電路一直這么設(shè)計(jì)并無問題,但是在空閑中斷應(yīng)用中就會導(dǎo)致出錯。ps:硬件不是我設(shè)計(jì),所以這個問題發(fā)現(xiàn)的比較晚,而且我之前發(fā)現(xiàn)這個問題后在軟件上做處理給抵消了。不影響使用。