從一張示波器截圖談FIFO
概要:SPI外設(shè)具有協(xié)議通用性強(qiáng),高速串行通訊,操作簡便等優(yōu)點(diǎn)。本文講述了在使用SPI外設(shè)驅(qū)動(dòng)LCD屏?xí)r,由于FIFO功能遇到的“異步”發(fā)送數(shù)據(jù),導(dǎo)致LCD屏驅(qū)動(dòng)異常,從而屏幕顯示失敗的問題。借助示波器觀察引腳信號(hào),分析信號(hào)時(shí)序等方法的解決過程,并最終實(shí)現(xiàn)SPI外設(shè)驅(qū)動(dòng)LCD屏。
本文引用地址:http://m.butianyuan.cn/article/202104/424757.htm本人的一個(gè)項(xiàng)目,項(xiàng)目使用NXP公司的LPC11U68微處理器作為主控芯片,其設(shè)計(jì)功能之一是驅(qū)動(dòng)TFT LCD屏。TFT LCD屏為SPI接口,于是使用LPC11U68芯片的SSP0外設(shè)接口來驅(qū)動(dòng)。
很簡單的三兩行字,卻讓我在調(diào)試的時(shí)候一度深陷困境。先上一張示波器截圖,我們慢慢道來。
這張示波器截圖對應(yīng)的是下面這段代碼實(shí)現(xiàn):
void ssp0_send_byte(uint8_t data)
{
uint16_t tmp = data;
LCD_DESELECT();
LCD_CMD();
while((Chip_SSP_GetStatus(LPC_SSP0, SSP_STAT_TNF) == RESET));
Chip_SSP_SendFrame(LPC_SSP0, tmp);
while((Chip_SSP_GetStatus(LPC_SSP0, SSP_STAT_TFE) != SET));
LCD_SELECT();
}
LCD驅(qū)動(dòng)對于寄存器或數(shù)據(jù)的寫入流程還是比較清晰、簡單。如上述源代碼所示:
step1:將片選CS信號(hào)拉低
step2:配置本條發(fā)送數(shù)據(jù)是命令or數(shù)據(jù)
step3:發(fā)送8位串行數(shù)據(jù)
step4:將片選CS信號(hào)拉高
上圖為TFT LCD驅(qū)動(dòng)datasheet中的引腳時(shí)序參考圖。代碼的編寫也是完全符號(hào)時(shí)序的要求??墒蔷褪沁@么簡單的6行代碼出現(xiàn)了問題!
我將代碼編譯后燒錄入LPC11U68芯片后開始運(yùn)行,發(fā)現(xiàn)LCD屏驅(qū)動(dòng)異常,屏幕沒有任何顯示。
考慮到代碼是從示例程序移植過來,也不排除出現(xiàn)問題——也許原例程亦無法實(shí)現(xiàn)呢!我將代碼更換為GPIO模擬SPI方式實(shí)現(xiàn)驅(qū)動(dòng)LCD屏——這次顯示成功了,只是頁面刷新要慢好多了。再次換回SPI外設(shè)方式,故障依舊——這也充分說明了硬件是完好的,而問題就出在了軟件設(shè)計(jì)上面了。
剛剛開始以為配置LPC11U68芯片的SSP0外設(shè)出現(xiàn)了問題,經(jīng)過反復(fù)驗(yàn)證后,也未能定位原因所在。在軟件分析無果后,請出來了示波器,便有了文章開頭的那一張截圖。
截圖中,藍(lán)線CH1為SPI外設(shè)的SCK引腳,黃線CH2為LCD的片選CS信號(hào)。從示波器上面可以清晰看到片選CS信號(hào)并沒有在發(fā)送一幀數(shù)據(jù)后才拉高,而是提前拉高了。當(dāng)片選CS引腳為高時(shí),LCD屏忽略SDA上面?zhèn)鬏數(shù)臄?shù)據(jù),自然LCD屏不會(huì)有正確的顯示。
通過示波器的 介入,我們觀察到了控制信號(hào)與數(shù)據(jù)信號(hào)的傳輸過程,并發(fā)現(xiàn)了LCD屏未能正確的顯示的癥結(jié)所在。下面我們就分析一下其中的原因。
示例的例程是基于STM32系列單片機(jī),閱讀兩者的datasheet,對比所使用的微處理器LPC11U68的SPI外設(shè),可以看到STM32系列單片機(jī)沒有發(fā)送FIFO。那發(fā)送FIFO為何物呢?
“FIFO是先進(jìn)先出的意思,隊(duì)列的方式?!?/span>
“FIFO是一個(gè)硬件環(huán)形的緩沖隊(duì)列,物理上不可尋址,不可見,僅SSPDR這個(gè)FIFO出口可見?!?/span>
“SSP接口向SPI總線發(fā)送數(shù)據(jù)時(shí),數(shù)據(jù)先存到SSPDR當(dāng)中,由Tx FIFO的狀態(tài)及總線是否空閑決定已經(jīng)存入到SSPDR當(dāng)中的數(shù)據(jù)何時(shí)進(jìn)行發(fā)送?!?/span>
“因?yàn)門x FIFO的深度是有限的,每次發(fā)送過程中都是將現(xiàn)有FIFO中所有數(shù)據(jù)一起發(fā)送,所以SSPDR可以理解為發(fā)送過程當(dāng)中的數(shù)據(jù)緩沖寄存器。”
以上我從網(wǎng)絡(luò)上面摘錄下來的。通過FIFO的介紹可以得出,當(dāng)程序執(zhí)行到Chip_SSP_SendFrame()時(shí),僅將數(shù)據(jù)“塞入”FIFO,并在成功“塞入”后即返回。而此時(shí)數(shù)據(jù)并未成功發(fā)送,但片選CS信號(hào) 卻在Chip_SSP_SendFrame()返回后,誤認(rèn)為其成功執(zhí)行而對片選CS信號(hào)進(jìn)行了釋放拉高操作,待SPI外設(shè)真正發(fā)送數(shù)據(jù)時(shí),此時(shí)片選CS信號(hào)已經(jīng)釋放,LCD驅(qū)動(dòng)芯片也就不會(huì)再接收其數(shù)據(jù)了。沒有了正確的輸入數(shù)據(jù),屏幕也就“漆黑一片”了。
分析問題已經(jīng)完成,那么下面我們就著手解決問題。
通過閱讀官方技術(shù)手冊,可以查詢到BUSY標(biāo)志位代表SPI外設(shè)正在發(fā)送操作,所以我們僅需要在此標(biāo)志位清零后再執(zhí)行片選CS釋放即可。源代碼如下:
void ssp0_send_byte(uint8_t data)
{
uint16_t tmp = data;
LCD_DESELECT();
LCD_CMD();
while((Chip_SSP_GetStatus(LPC_SSP0, SSP_STAT_TNF) == RESET));
Chip_SSP_SendFrame(LPC_SSP0, tmp);
while((Chip_SSP_GetStatus(LPC_SSP0, SSP_STAT_TFE) != SET));
while((Chip_SSP_GetStatus(LPC_SSP0, SSP_STAT_BSY) == SET));
LCD_SELECT();
}
NXP公司旗下LPC系列微處理器對外設(shè)增加FIFO可以減少數(shù)據(jù)中斷的調(diào)用,提高整體通訊效率,而這也恰恰營造了一種“異步”指令處理的環(huán)境。這時(shí),也就出現(xiàn)了我們的微處理器在代碼執(zhí)行順序上面出現(xiàn)了沒有按“順序”執(zhí)行的問題。
在增加了等待指令后,軟件的操作順序與期望順序一致,TFT LCD驅(qū)動(dòng)顯示正常。我們在軟件設(shè)計(jì)時(shí),合理使用硬件外設(shè)提供的FIFO功能,充分利用其優(yōu)勢,規(guī)避其使用過程中的副作用。雖然本次FIFO帶來了一些困擾,但從整體的系統(tǒng)角度來講,仍然提升了我們的系統(tǒng)效率。
評論