色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

CKS32F4xx系列產(chǎn)品SPI通信

中科芯MCU ? 來(lái)源:中科芯MCU ? 2023-04-21 09:36 ? 次閱讀

SPI協(xié)議是由摩托羅拉公司提出的通訊協(xié)議(Serial Peripheral Interface),即串行外圍設(shè)備接口,是一種高速全雙工的通信總線。它在芯片的管腳上只占用四根線,節(jié)約了芯片的管腳,同時(shí)為PCB在布局上節(jié)省了空間,提供方便,正是出于這種簡(jiǎn)單易用的特性,現(xiàn)在越來(lái)越多的芯片集成了這種通信協(xié)議,它被廣泛地使用在ADC、LCD、FLASH等設(shè)備與MCU之間的通信。

CKS32F4xx系列產(chǎn)品SPI介紹

CKS32F4xx系列的SPI外設(shè)可用作通訊的主機(jī)及從機(jī),支持最高的SCK時(shí)鐘頻率為fpclk/2(CKS32F407型號(hào)的芯片默認(rèn)fpclk為142MHz,fpclk2為84MHz),完全支持SPI協(xié)議的4種模式。SPI協(xié)議根據(jù)CPOL及CPHA的不同狀態(tài)分成的四種工作模式如下表所示:

71895c76-dfb8-11ed-bfe3-dac502259ad0.jpg

CKS32F4xx系列的SPI架構(gòu)如下圖所示:

71a38bc8-dfb8-11ed-bfe3-dac502259ad0.png

圖中的1處是SPI的引腳MOSI、MISO、SCK、NSS。CKS32F4xx芯片有多個(gè) SPI外設(shè),它們的SPI通訊信號(hào)引出到不同GPIO引腳上,使用時(shí)必須配置到這些指定的引腳。關(guān)于GPIO引腳的復(fù)用功能可以查閱芯片數(shù)據(jù)手冊(cè)。各個(gè)引腳的作用介紹如下:

(1)NSS:從設(shè)備選擇信號(hào)線,常稱為片選信號(hào)線。當(dāng)有多個(gè)SPI從設(shè)備與 SPI主機(jī)相連時(shí),設(shè)備的其它信號(hào)線SCK、MOSI及MISO同時(shí)并聯(lián)到相同的SPI 總線上,即無(wú)論有多少個(gè)從設(shè)備,都共同只使用這3條總線;而每個(gè)從設(shè)備都有獨(dú)立的一條NSS信號(hào)線,當(dāng)主機(jī)要選擇從設(shè)備時(shí),把該從設(shè)備的NSS信號(hào)線設(shè)置為低電平,該從設(shè)備即被選中,即片選有效,接著主機(jī)開(kāi)始與被選中的從設(shè)備進(jìn)行SPI通訊。所以SPI通訊以NSS線置低電平為開(kāi)始信號(hào),以NSS線被拉高作為結(jié)束信號(hào)。

(2)SCK:時(shí)鐘信號(hào)線,用于通訊數(shù)據(jù)同步。它由通訊主機(jī)產(chǎn)生,決定了通訊的速率,不同的設(shè)備支持的最高時(shí)鐘頻率不一樣,兩個(gè)設(shè)備之間通訊時(shí),通訊速率受限于低速設(shè)備。

(3)MOSI:主設(shè)備輸出/從設(shè)備輸入引腳。主機(jī)的數(shù)據(jù)從這條信號(hào)線輸出,從機(jī)由這條信號(hào)線讀入主機(jī)發(fā)送的數(shù)據(jù),即這條線上數(shù)據(jù)的方向?yàn)橹鳈C(jī)到從機(jī)。

(4)MISO:主設(shè)備輸入/從設(shè)備輸出引腳。主機(jī)從這條信號(hào)線讀入數(shù)據(jù),從機(jī)的數(shù)據(jù)由這條信號(hào)線輸出到主機(jī),即在這條線上數(shù)據(jù)的方向?yàn)閺臋C(jī)到主機(jī)。

圖中的2處是SCK線的時(shí)鐘信號(hào),由波特率發(fā)生器根據(jù)“控制寄存器CR1”中的BR[0:2]位控制,該位是對(duì)fpclk時(shí)鐘的分頻因子,對(duì)fpclk的分頻結(jié)果就是SCK引腳的輸出時(shí)鐘頻率。

圖中的3處是SPI的數(shù)據(jù)控制邏輯。SPI的MOSI及MISO都連接到數(shù)據(jù)移位寄存器上,數(shù)據(jù)移位寄存器的內(nèi)容來(lái)源于接收緩沖區(qū)及發(fā)送緩沖區(qū)以及MISO、MOSI線。當(dāng)向外發(fā)送數(shù)據(jù)的時(shí)候,數(shù)據(jù)移位寄存器以“發(fā)送緩沖區(qū)”為數(shù)據(jù)源,把數(shù)據(jù)一位一位地通過(guò)數(shù)據(jù)線發(fā)送出去;當(dāng)從外部接收數(shù)據(jù)的時(shí)候,數(shù)據(jù)移位寄存器把數(shù)據(jù)線采樣到的數(shù)據(jù)一位一位地存儲(chǔ)到“接收緩沖區(qū)”中。通過(guò)寫(xiě)SPI 的“數(shù)據(jù)寄存器DR”把數(shù)據(jù)填充到發(fā)送緩沖區(qū)中,通過(guò)“數(shù)據(jù)寄存器DR”,可以獲取接收緩沖區(qū)中的內(nèi)容。其中數(shù)據(jù)幀的長(zhǎng)度可以通過(guò)“控制寄存器CR1”的“DFF位”配置成8位及16位模式;配置“LSBFIRST位”可選擇MSB先行還是 LSB先行。

圖中的4處是SPI的整體控制邏輯。整體控制邏輯負(fù)責(zé)協(xié)調(diào)整個(gè)SPI外設(shè),控制邏輯的工作模式根據(jù)我們配置的“控制寄存器(CR1/CR2)”的參數(shù)而改變,基本的控制參數(shù)包括SPI模式、波特率、LSB先行、主從模式、單雙向模式等等。在外設(shè)工作時(shí),控制邏輯會(huì)根據(jù)外設(shè)的工作狀態(tài)修改“狀態(tài)寄存器(SR)”,我們只要讀取狀態(tài)寄存器相關(guān)的寄存器位,就可以了解SPI的工作狀態(tài)了。除此之外,控制邏輯還根據(jù)要求,負(fù)責(zé)控制產(chǎn)生SPI中斷信號(hào)、DMA請(qǐng)求及控制NSS信號(hào)線。實(shí)際應(yīng)用中,我們一般不使用CKS32 SPI外設(shè)的標(biāo)準(zhǔn)NSS信號(hào)線,而是更簡(jiǎn)單地使用普通的GPIO,軟件控制它的電平輸出,從而產(chǎn)生通訊起始和停止信號(hào)。

CKS32F4xx系列的SPI作為通訊主機(jī)端時(shí)收發(fā)數(shù)據(jù)的過(guò)程如下:

(1) 控制NSS信號(hào)線,產(chǎn)生起始信號(hào);

(2) 把要發(fā)送的數(shù)據(jù)寫(xiě)入到“數(shù)據(jù)寄存器DR”中,該數(shù)據(jù)會(huì)被存儲(chǔ)到發(fā)送緩沖區(qū);

(3) 通訊開(kāi)始,SCK時(shí)鐘開(kāi)始運(yùn)行。MOSI把發(fā)送緩沖區(qū)中的數(shù)據(jù)一位一位地傳輸出去;MISO則把數(shù)據(jù)一位一位地存儲(chǔ)進(jìn)接收緩沖區(qū)中;

(4) 當(dāng)發(fā)送完一幀數(shù)據(jù)的時(shí)候,“狀態(tài)寄存器SR”中的“TXE標(biāo)志位”會(huì)被置1,表示傳輸完一幀,發(fā)送緩沖區(qū)已空;類似地,當(dāng)接收完一幀數(shù)據(jù)的時(shí)候,“RXNE標(biāo)志位”會(huì)被置1,表示傳輸完一幀,接收緩沖區(qū)非空;

(5) 等待到“TXE標(biāo)志位”為1時(shí),若還要繼續(xù)發(fā)送數(shù)據(jù),則再次往“數(shù)據(jù)寄存器DR”寫(xiě)入數(shù)據(jù)即可;等待到“RXNE標(biāo)志位”為1時(shí),通過(guò)讀取“數(shù)據(jù)寄存器DR”可以獲取接收緩沖區(qū)中的內(nèi)容。

假如我們使能了TXE或RXNE中斷,TXE或RXNE置1時(shí)會(huì)產(chǎn)生SPI中斷信號(hào),進(jìn)入同一個(gè)中斷服務(wù)函數(shù),到SPI中斷服務(wù)程序后,可通過(guò)檢查寄存器位來(lái)了解是哪一個(gè)事件,再分別進(jìn)行處理。也可以使用DMA方式來(lái)收發(fā)“數(shù)據(jù)寄存器 DR”中的數(shù)據(jù)。

CKS32F4xx系列產(chǎn)品SPI的配置

接下來(lái)我們講解如何利用CKS32F4xx系列固件庫(kù)來(lái)完成對(duì)SPI的配置使用。跟其它外設(shè)一樣,CKS32標(biāo)準(zhǔn)庫(kù)提供了SPI初始化結(jié)構(gòu)體及初始化函數(shù)來(lái)配置 SPI外設(shè)。了解初始化結(jié)構(gòu)體后我們就能對(duì)SPI外設(shè)運(yùn)用自如了,代碼如下:

typedef struct
{
  uint16_t SPI_Direction;          
  uint16_t SPI_Mode;              
  uint16_t SPI_DataSize;          
  uint16_t SPI_CPOL;             
  uint16_t SPI_CPHA;               
  uint16_t SPI_NSS;               
  uint16_t SPI_BaudRatePrescaler;  
  uint16_t SPI_FirstBit;           
  uint16_t SPI_CRCPolynomial;       
}SPI_InitTypeDef;

結(jié)構(gòu)體中各個(gè)成員變量的介紹及初始化時(shí)可被賦的值如下:

1) SPI_Direction:本成員設(shè)置SPI的通訊方向,可設(shè)置為雙線全雙工 (SPI_Direction_2Lines_FullDuplex),雙線只接收 (SPI_Direction_2Lines_RxOnly),單線只接收(SPI_Direction_1Line_Rx)、單線只發(fā)送模式(SPI_Direction_1Line_Tx)。

2) SPI_Mode:本成員設(shè)置SPI工作在主機(jī)模式(SPI_Mode_Master)或從機(jī)模式(SPI_Mode_Slave ),這兩個(gè)模式的最大區(qū)別為SPI的SCK信號(hào)線的時(shí)序,SCK的時(shí)序是由通訊中的主機(jī)產(chǎn)生的。若被配置為從機(jī)模式,CKS32的SPI外設(shè)將接受外來(lái)的SCK信號(hào):

3) SPI_DataSize: 本成員可以選擇SPI通訊的數(shù)據(jù)幀大小是為8位 (SPI_DataSize_8b)還是16位(SPI_DataSize_16b)。

4) SPI_CPOL和SPI_CPHA: 這兩個(gè)成員配置SPI的時(shí)鐘極性CPOL和時(shí)鐘相位CPHA,前面講過(guò)這兩個(gè)配置影響到SPI的通訊模式。時(shí)鐘極性CPOL成員可設(shè)置為高電平(SPI_CPOL_High)或低電平(SPI_CPOL_Low )。時(shí)鐘相位CPHA則 可以設(shè)置為SPI_CPHA_1Edge(在SCK的奇數(shù)邊沿采集數(shù)據(jù))或 SPI_CPHA_2Edge(在SCK的偶數(shù)邊沿采集數(shù)據(jù))。

5) SPI_NSS: 本成員配置NSS引腳的使用模式,可以選擇為硬件模式 (SPI_NSS_Hard )與軟件模式(SPI_NSS_Soft ),在硬件模式中的SPI片選信號(hào)由 SPI硬件自動(dòng)產(chǎn)生,而軟件模式則需要我們自己把相應(yīng)的GPIO端口拉高或置低產(chǎn)生非片選和片選信號(hào)。實(shí)際中軟件模式應(yīng)用比較多。

6) SPI_BaudRatePrescaler: 本成員設(shè)置波特率分頻因子,分頻后的時(shí)鐘即為SPI的SCK信號(hào)線的時(shí)鐘頻率。這個(gè)成員參數(shù)可設(shè)置為fpclk的2、4、6、8、16、32、64、128、256分頻。可選的值如下所示:

SPI_BaudRatePrescaler_2    //2分頻
SPI_BaudRatePrescaler_4    //4分頻
SPI_BaudRatePrescaler_6    //6分頻
SPI_BaudRatePrescaler_8    //8分頻
SPI_BaudRatePrescaler_16   //16分頻
SPI_BaudRatePrescaler_32   //32分頻
SPI_BaudRatePrescaler_64   //64分頻
SPI_BaudRatePrescaler_128  //128分頻
SPI_BaudRatePrescaler_256  //256分頻
?

7) SPI_FirstBit:所有串行的通訊協(xié)議都會(huì)有MSB先行(高位數(shù)據(jù)在前)還是 LSB先行(低位數(shù)據(jù)在前)的問(wèn)題,而CKS32F4xx系列的SPI模塊可以通過(guò)這個(gè)結(jié)構(gòu)體成員,對(duì)這個(gè)特性編程控制。

SPI_FirstBit_MSB    //高位數(shù)據(jù)在前
SPI_FirstBit_LSB     //低位數(shù)據(jù)在前

8) SPI_CRCPolynomial:這是SPI的CRC校驗(yàn)中的多項(xiàng)式,若我們使用CRC 校驗(yàn)時(shí),就使用這個(gè)成員的參數(shù)(多項(xiàng)式),來(lái)計(jì)算CRC的值。

配置完這些結(jié)構(gòu)體成員的值,調(diào)用庫(kù)函數(shù)SPI_Init即可把結(jié)構(gòu)體的配置寫(xiě)入到寄存器中。

CKS32F4xx讀寫(xiě)SPI FLASH實(shí)驗(yàn)

串口的DMA接發(fā)通信實(shí)驗(yàn)是存儲(chǔ)器到外設(shè)和外設(shè)到存儲(chǔ)器的數(shù)據(jù)傳輸。在第24

本小節(jié)以一種使用SPI通訊的串行FLASH存儲(chǔ)芯片的讀寫(xiě)實(shí)驗(yàn)為大家講解 CKS32F4xx系列的SPI使用方法。實(shí)驗(yàn)中的FLASH芯片(型號(hào):W25Q32)是一種使用SPI通訊協(xié)議的NORFLASH存儲(chǔ)器,它的CS/CLK/DIO/DO引腳分別連接到了CKS32F4xx對(duì)應(yīng)的SPI引腳NSS/SCK/MOSI/MISO上,其中CKS32F4xx的NSS引腳是一個(gè)普通的GPIO,不是SPI的專用NSS引腳,所以程序中我們要使用軟件控制的方式。

1.編程要點(diǎn)

(1) 初始化通訊使用的目標(biāo)引腳及端口時(shí)鐘;

(2) 使能SPI外設(shè)的時(shí)鐘;

(3) 配置SPI外設(shè)的模式、地址、速率等參數(shù)并使能SPI外設(shè);

(4) 編寫(xiě)基本SPI按字節(jié)收發(fā)的函數(shù);

(5) 編寫(xiě)對(duì)FLASH擦除及讀寫(xiě)操作的的函數(shù);

(6) 編寫(xiě)測(cè)試程序,對(duì)讀寫(xiě)數(shù)據(jù)進(jìn)行校驗(yàn)。

2.代碼分析

代碼清單1:W25Q32初始化配置

void W25QXX_Init(void)
{ 
  GPIO_InitTypeDef  GPIO_InitStructure;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); 
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE); 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; 
  GPIO_Init(GPIOD, &GPIO_InitStructure); 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_SetBits(GPIOG,GPIO_Pin_3); 
  W25QXX_CS=1;                        //SPI FLASH不選中
  SPI1_Init();                               //初始化SPI
  SPI1_SetSpeed(SPI_BaudRatePrescaler_4);    //設(shè)置為21M時(shí)鐘
  W25QXX_TYPE=W25QXX_ReadID();         //讀取FLASH ID.
}  

上面的代碼主要是完成對(duì)W25Q32片選引腳的初始化,SPI初始化。SPI通信速率設(shè)置和讀取W25Q32的ID。

代碼清單2:SPI初始化函數(shù)

void SPI1_Init(void)
{   
  GPIO_InitTypeDef  GPIO_InitStructure;
  SPI_InitTypeDef  SPI_InitStructure;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; 
  GPIO_Init(GPIOB, &GPIO_InitStructure); 
GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_SPI1); 
GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_SPI1); 
  RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);
  RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; 
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;    
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;  
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;    
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; 
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;    
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;  
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;  
  SPI_InitStructure.SPI_CRCPolynomial = 7;  
  SPI_Init(SPI1, &SPI_InitStructure);  
  SPI_Cmd(SPI1, ENABLE); 
  SPI1_ReadWriteByte(0xff);   
}   

上面這段代碼主要是完成對(duì)SPI1的初始化,首先是配置了SPI1使用的引腳SPI1_SCK、SPI1_MOSI和SPI1_MISO。然后是根據(jù)第2小節(jié)的內(nèi)容完成對(duì)SPI1外設(shè)模式的配置。根據(jù)FLASH芯片W25Q32的說(shuō)明,它支持SPI模式0及模式3,支持雙線全雙工,使用MSB先行模式,支持最高通訊時(shí)鐘為104MHz,數(shù)據(jù)幀長(zhǎng)度為8位。我們要把CKS32F4的SPI外設(shè)中的這些參數(shù)配置一致。

代碼清單3:SPI1單字節(jié)收發(fā)函數(shù)

u8 SPI1_ReadWriteByte(u8 TxData)
{            
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){} 
  SPI_I2S_SendData(SPI1, TxData); 
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){} 
  return SPI_I2S_ReceiveData(SPI1); 
}

本函數(shù)中不包含SPI起始和停止信號(hào),只是收發(fā)的主要過(guò)程,所以在調(diào)用本函數(shù)前后要做好起始和停止信號(hào)的操作。通過(guò)檢測(cè)TXE標(biāo)志,獲取發(fā)送緩沖區(qū)的狀態(tài),若發(fā)送緩沖區(qū)為空,則表示可能存在的上一個(gè)數(shù)據(jù)已經(jīng)發(fā)送完畢;等待至發(fā)送緩沖區(qū)為空后,調(diào)用庫(kù)函數(shù)SPI_I2S_SendData把要發(fā)送的數(shù)據(jù)“TxData”寫(xiě)入到SPI的數(shù)據(jù)寄存器DR,寫(xiě)入SPI數(shù)據(jù)寄存器的數(shù)據(jù)會(huì)存儲(chǔ)到發(fā)送緩沖區(qū),由SPI外設(shè)發(fā)送出去;寫(xiě)入完畢后等待RXNE事件,即接收緩沖區(qū)非空事件。由于SPI雙線全雙工模式下MOSI與MISO數(shù)據(jù)傳輸是同步的,當(dāng)接收緩沖區(qū)非空時(shí),表示上面的數(shù)據(jù)發(fā)送完畢,且接收緩沖區(qū)也收到新的數(shù)據(jù);等待至接收緩沖區(qū)非空時(shí),通過(guò)調(diào)用庫(kù)函數(shù)SPI_I2S_ReceiveData讀取SPI的數(shù)據(jù)寄存器DR,就可以獲取接收緩沖區(qū)中的新數(shù)據(jù)了。代碼中使用關(guān)鍵字“return”把接收到的這個(gè)數(shù)據(jù)作為SPI1_ReadWriteByte函數(shù)的返回值。

搞定了SPI的基本收發(fā)單元后,還需要了解如何對(duì)FLASH芯片進(jìn)行讀寫(xiě)。FLASH 芯片自定義了很多指令,我們通過(guò)控制CKS32F4利用SPI總線向FLASH 芯片發(fā)送指令,F(xiàn)LASH芯片收到后就會(huì)執(zhí)行相應(yīng)的操作。具體的指令代碼可以查看W25Q32芯片的數(shù)據(jù)手冊(cè)。

代碼清單4:讀取FLASH芯片ID函數(shù)

u16 W25QXX_ReadID(void)
{
  u16 Temp = 0;    
  W25QXX_CS=0;            
  SPI1_ReadWriteByte(0x90);      
  SPI1_ReadWriteByte(0x00);       
  SPI1_ReadWriteByte(0x00);       
  SPI1_ReadWriteByte(0x00);             
  Temp|=SPI1_ReadWriteByte(0xFF)<<8;  
  Temp|=SPI1_ReadWriteByte(0xFF);   
  W25QXX_CS=1;            
  return Temp;
}     

這段代碼利用控制CS引腳電平的宏“W25QXX_CS”以及前面編寫(xiě)的單字節(jié)收發(fā)函數(shù)SPI1_ReadWriteByte,很清晰地實(shí)現(xiàn)了讀ID指令的時(shí)序,最后把讀 取到的這3個(gè)數(shù)據(jù)合并到一個(gè)變量Temp中,然后作為函數(shù)返回值,把該返回值與我們定義的芯片ID對(duì)比,即可知道FLASH芯片是否正常。

代碼清單5:W25Q32寫(xiě)使能和寫(xiě)禁止函數(shù)

void W25QXX_Write_Enable(void)   
{
  W25QXX_CS=0;                              
  SPI1_ReadWriteByte(W25X_WriteEnable);     
  W25QXX_CS=1;                                    
}
void W25QXX_Write_Disable(void)   
{  
  W25QXX_CS=0;                            
  SPI1_ReadWriteByte(W25X_WriteDisable);        
  W25QXX_CS=1;                                      
}   

由于FLASH存儲(chǔ)器的特性決定了它只能把原來(lái)為“1”的數(shù)據(jù)位改寫(xiě)成“0”,而原來(lái)為“0”的數(shù)據(jù)位不能直接改寫(xiě)為“1”。所以在寫(xiě)入前,必須要對(duì)目標(biāo)存儲(chǔ)矩陣進(jìn)行擦除操作,把矩陣中的數(shù)據(jù)位擦除為“1”,在數(shù)據(jù)寫(xiě)入的時(shí)候,如果要存儲(chǔ)數(shù)據(jù)“1”, 那就不修改存儲(chǔ)矩陣,在要存儲(chǔ)數(shù)據(jù)“0”時(shí),需要更改該位。W25Q32支持“扇區(qū)擦除”、“塊擦除”以及“整片擦除”。扇區(qū)擦除指令的第一個(gè)字節(jié)為指令編碼,緊接著發(fā)送的3個(gè)字節(jié)用于表示要擦除的存儲(chǔ)矩陣地址。要注意的是在扇區(qū)擦除指令前,還需要先發(fā)送“寫(xiě)使能”指令,發(fā)送扇區(qū)擦除指令后,通過(guò)讀取寄存器狀態(tài)等待扇區(qū)擦除操作完畢。

代碼清單6:W25Q32扇區(qū)擦除函數(shù)

void W25QXX_Erase_Sector(u32 Dst_Addr)   
{      
   Dst_Addr*=4096;
    W25QXX_Write_Enable();                    
    W25QXX_Wait_Busy();   
    W25QXX_CS=0;                              
    SPI1_ReadWriteByte(W25X_SectorErase);      
    SPI1_ReadWriteByte((u8)((Dst_Addr)>>16));     
    SPI1_ReadWriteByte((u8)((Dst_Addr)>>8));   
    SPI1_ReadWriteByte((u8)Dst_Addr);  
  W25QXX_CS=1;                                   
    W25QXX_Wait_Busy();             
}  

目標(biāo)扇區(qū)被擦除完畢后,就可以向它寫(xiě)入數(shù)據(jù)了。與EEPROM類似,F(xiàn)LASH芯片也有頁(yè)寫(xiě)入命令,使用頁(yè)寫(xiě)入命令最多可以一次向FLASH傳輸256個(gè)字節(jié)的數(shù)據(jù),我們把這個(gè)單位稱為頁(yè)大小。在進(jìn)行頁(yè)寫(xiě)入時(shí)第1個(gè)字節(jié)為“頁(yè)寫(xiě)入指令”編碼,2-4字節(jié)為要寫(xiě)入的“地址A”,接著的是要寫(xiě)入的內(nèi)容,最多可以發(fā)送 256字節(jié)數(shù)據(jù),這些數(shù)據(jù)將會(huì)從“地址A”開(kāi)始,按順序?qū)懭氲紽LASH的存儲(chǔ)矩陣。若發(fā)送的數(shù)據(jù)超出256個(gè),則會(huì)覆蓋前面發(fā)送的數(shù)據(jù)。

代碼清單7:W25Q32頁(yè)寫(xiě)入函數(shù)

void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
   u16 i;  
    W25QXX_Write_Enable();                 
  W25QXX_CS=0;                               
    SPI1_ReadWriteByte(W25X_PageProgram);         
    SPI1_ReadWriteByte((u8)((WriteAddr)>>16));   
    SPI1_ReadWriteByte((u8)((WriteAddr)>>8));   
    SPI1_ReadWriteByte((u8)WriteAddr);   
    for(i=0;i

應(yīng)用的時(shí)候我們常常要寫(xiě)入不定量的數(shù)據(jù),直接調(diào)用“頁(yè)寫(xiě)入”函數(shù)并不是特別方便,所以我們頁(yè)寫(xiě)入函數(shù)的基礎(chǔ)上編寫(xiě)了“不定量數(shù)據(jù)寫(xiě)入”的函數(shù)。在實(shí)際調(diào)用這個(gè)“不定量數(shù)據(jù)寫(xiě)入”函數(shù)時(shí),還要注意確保目標(biāo)扇區(qū)處于擦除狀態(tài)

代碼清單8:W25Q32不定量數(shù)據(jù)寫(xiě)入函數(shù)

void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
{ 
  u32 secpos;
  u16 secoff;
  u16 secremain;     
   u16 i;    
  u8 * W25QXX_BUF;    
     W25QXX_BUF=W25QXX_BUFFER;       
   secpos=WriteAddr/4096; 
  secoff=WriteAddr%4096; 
  secremain=4096-secoff;  
   if(NumByteToWrite<=secremain)secremain=NumByteToWrite;
  while(1) 
  {  
    W25QXX_Read(W25QXX_BUF,secpos*4096,4096); 
    for(i=0;i4096)secremain=4096;  
      else secremain=NumByteToWrite;      
    }   
  };   
}

函數(shù)的入口參數(shù)pBuffer是數(shù)據(jù)存儲(chǔ)區(qū)、WriteAd是開(kāi)始寫(xiě)入的地址(24bit)、NumByteToWrite是要寫(xiě)入的字節(jié)數(shù)(最大65535)gaojp。

相對(duì)于寫(xiě)入,F(xiàn)LASH芯片W25Q32的數(shù)據(jù)讀取要簡(jiǎn)單的多,發(fā)送了指令編碼及要讀的起始地址和要讀取的字節(jié)數(shù)之后,F(xiàn)LASH 芯片W25Q32就會(huì)按地址遞增的方式返回存儲(chǔ)矩陣中一定字節(jié)數(shù)量的數(shù)據(jù)。

代碼清單9:W25Q32讀取數(shù)據(jù)函數(shù)

void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)   
{ 
   u16 i;                           
  W25QXX_CS=0;                              
    SPI1_ReadWriteByte(W25X_ReadData);          
    SPI1_ReadWriteByte((u8)((ReadAddr)>>16));     
    SPI1_ReadWriteByte((u8)((ReadAddr)>>8));   
    SPI1_ReadWriteByte((u8)ReadAddr);   
    for(i=0;i

函數(shù)的入口參數(shù)pBuffer是數(shù)據(jù)存儲(chǔ)區(qū)、ReadAddr是開(kāi)始讀取的地址(24bit)、NumByteToRead是要讀取的字節(jié)數(shù)(最大65535)。

完成基本的讀寫(xiě)函數(shù)后,接下來(lái)我們編寫(xiě)一個(gè)讀寫(xiě)測(cè)試函數(shù)來(lái)檢驗(yàn)驅(qū)動(dòng)程。

代碼清單10:W25Q32讀寫(xiě)測(cè)試函數(shù)

uint8_t w25q32_Test(void)
{
  u16 i;
   printf("寫(xiě)入的數(shù)據(jù):
");
  for ( i=0; i<=10; i++ ) 
  {   
    spi_Buf_Write[i] = i;
    printf("0x%02X ", spi_Buf_Write[i]);
   }
   W25QXX_Write((u8*)spi_Buf_Write,FLASH_SIZE-100,11);     
     printf("寫(xiě)成功,");
     printf("讀出的數(shù)據(jù):
");
    W25QXX_Read(datatemp,FLASH_SIZE-100,11);          
  for (i=0; i<11; i++)
  {  
    if(datatemp[i] != spi_Buf_Write[i])
    {
      printf("0x%02X ", datatemp[i]);
      printf("錯(cuò)誤:I2C EEPROM寫(xiě)入與讀出的數(shù)據(jù)不一致");
      return 0;
    }
    printf("0x%02X ", datatemp[i]);
  }
  printf("
");
    printf("spi(w25q32)讀寫(xiě)測(cè)試成功");
  return 1;
}

代碼中先填充一個(gè)數(shù)組,數(shù)組的內(nèi)容為0,1至10,接著把這個(gè)數(shù)組的內(nèi)容寫(xiě)入到SPI FLASH中,并將寫(xiě)入的數(shù)據(jù)打印輸出到串口調(diào)試助手。寫(xiě)入完畢后再?gòu)腟PI FLASH的地址中讀取數(shù)據(jù),把讀取到的數(shù)據(jù)與寫(xiě)入的數(shù)據(jù)進(jìn)行校驗(yàn),若一致說(shuō)明讀寫(xiě)正常,否則讀寫(xiě)過(guò)程有問(wèn)題或者SPI FLASH芯片不正常,然后再將讀取到的數(shù)據(jù)打印輸出到串口調(diào)試助手。

代碼清單11:主函數(shù)

int main(void)
{ 
    u16 id = 0;  
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  delay_init(168);    
   USART_Configuration();
  W25QXX_Init();      
  while(1)
  {
    id = W25QXX_ReadID();
    if (id == W25Q32 || id == NM25Q32)
      break;
      printf("W25Q32 init failed
");
    delay_ms(500);
    delay_ms(500);
  }
   printf("W25Q32 init success
");
   w25q32_Test();
  while(1)
  {
      
  }       
}

主函數(shù)代碼比較簡(jiǎn)單,主要是完成串口初始化和W25Q32的初始化,初始化完成之后會(huì)執(zhí)行W25QXX_ReadID函數(shù),讀取W25Q32的ID,同時(shí)對(duì)ID進(jìn)行判斷,并將結(jié)果通過(guò)串口調(diào)試助手打印輸出。然后會(huì)執(zhí)行一次W25Q32測(cè)試函數(shù),并將一些測(cè)試結(jié)果通過(guò)串口調(diào)試助手打印輸出。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • mcu
    mcu
    +關(guān)注

    關(guān)注

    146

    文章

    17123

    瀏覽量

    350992
  • 接口
    +關(guān)注

    關(guān)注

    33

    文章

    8575

    瀏覽量

    151019
  • 通信
    +關(guān)注

    關(guān)注

    18

    文章

    6024

    瀏覽量

    135950
  • SPI
    SPI
    +關(guān)注

    關(guān)注

    17

    文章

    1706

    瀏覽量

    91507
  • 通訊協(xié)議
    +關(guān)注

    關(guān)注

    10

    文章

    273

    瀏覽量

    20351

原文標(biāo)題:MCU微課堂 | CKS32F4xx系列產(chǎn)品SPI通信

文章出處:【微信號(hào):中科芯MCU,微信公眾號(hào):中科芯MCU】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    MCU微課堂|CKS32F4xx系列產(chǎn)品時(shí)鐘配置

    作為MCU運(yùn)行的基礎(chǔ),時(shí)鐘是單片機(jī)各個(gè)模塊工作時(shí)序的最小時(shí)間單位,推動(dòng)單片機(jī)的各指令執(zhí)行,是MCU選型的一個(gè)重要指標(biāo)。CKS32F4xx系列產(chǎn)品具有眾多的外設(shè),但并非所有的外設(shè)均需要系統(tǒng)時(shí)鐘的高頻率
    發(fā)表于 12-12 10:17 ?831次閱讀

    CKS32F4xx系列ETH通信詳解

    CKS32F4xx系列芯片自帶以太網(wǎng)模塊,該模塊包括帶專用DMA控制器的MAC 802.3(介質(zhì)訪問(wèn)控制)控制器
    的頭像 發(fā)表于 11-10 11:13 ?992次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>ETH<b class='flag-5'>通信</b>詳解

    CKS32F4xx系列產(chǎn)品NVIC中斷優(yōu)先級(jí)管理單元講解

    本課將為大家講解CKS32F4xx系列產(chǎn)品的中斷優(yōu)先級(jí)管理單元NVIC。CM4內(nèi)核共支持256個(gè)中斷,其中包含了16個(gè)內(nèi)核中斷和240個(gè)外部中斷,具有256級(jí)可編程中斷設(shè)置。但CKS32F4x
    的頭像 發(fā)表于 02-06 14:52 ?1169次閱讀

    CKS32F4xx系列產(chǎn)品串口DMA傳輸

    在上一講,我們講過(guò)CKS32F4xx系列的6個(gè)串口都支持DMA傳輸。因此本節(jié)我們對(duì)CKS32F4xx系列的DMA進(jìn)行介紹,同時(shí)利用DMA對(duì)串口數(shù)據(jù)進(jìn)行傳輸。
    的頭像 發(fā)表于 04-10 11:18 ?1033次閱讀

    CKS32F4xx系列產(chǎn)品的定時(shí)器使用-基本特征和定時(shí)操作

    這一課我們將介紹CKS32F4XX系列產(chǎn)品的定時(shí)器使用,CKS32F4XX的定時(shí)器功能十分強(qiáng)大,包含2個(gè)高級(jí)控制定時(shí)器,8個(gè)普通定時(shí)器,2個(gè)基礎(chǔ)定時(shí)器,以及兩個(gè)看門狗定時(shí)器和一個(gè)系統(tǒng)定時(shí)器,總共15個(gè)定時(shí)器之多。關(guān)于定時(shí)器部分內(nèi)
    的頭像 發(fā)表于 05-19 09:18 ?892次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列產(chǎn)品</b>的定時(shí)器使用-基本特征和定時(shí)操作

    CKS32F4xx系列RNG功能設(shè)置

    ? MCU 微課堂 CKS32F4xx 系 列RNG功能 隨機(jī)數(shù)發(fā)生器簡(jiǎn)介 ? ? CKS32F4xx系列自帶了硬件隨機(jī)數(shù)發(fā)生器(RNG),RNG處理器是一個(gè)以連續(xù)模擬噪聲為基礎(chǔ)的隨機(jī)數(shù)發(fā)生器,在
    的頭像 發(fā)表于 09-08 10:01 ?603次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>RNG功能設(shè)置

    CKS32F4xx系列DAC功能

    CKS32F4xx系列DAC功能
    的頭像 發(fā)表于 11-06 16:56 ?847次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>DAC功能

    CKS32F4xx系列ADC多通道DMA電壓采集

    CKS32F4xx系列ADC多通道DMA電壓采集
    的頭像 發(fā)表于 11-06 16:53 ?1096次閱讀

    CKS32F4xx系列低功耗模式STOP模式

    CKS32F4xx系列低功耗模式STOP模式
    的頭像 發(fā)表于 11-06 17:08 ?621次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>低功耗模式STOP模式

    CKS32F4xx系列產(chǎn)品Timer的基本使用方法-定時(shí)器脈沖計(jì)數(shù)

    CKS32F4xx系列產(chǎn)品Timer的基本使用方法-定時(shí)器脈沖計(jì)數(shù)
    的頭像 發(fā)表于 11-09 17:38 ?1066次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列產(chǎn)品</b>Timer的基本使用方法-定時(shí)器脈沖計(jì)數(shù)

    CKS32F4xx系列產(chǎn)品Timer的基本使用方法-比較輸出

    CKS32F4xx系列產(chǎn)品Timer的基本使用方法-比較輸出
    的頭像 發(fā)表于 11-09 17:39 ?848次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列產(chǎn)品</b>Timer的基本使用方法-比較輸出

    CKS32F4xx系列產(chǎn)品Timer的基本使用方法-定時(shí)操作

    CKS32F4xx系列產(chǎn)品Timer的基本使用方法-定時(shí)操作
    的頭像 發(fā)表于 11-09 17:41 ?616次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列產(chǎn)品</b>Timer的基本使用方法-定時(shí)操作

    MCU微課堂 | CKS32F4xx系列產(chǎn)品SPI通信

    MCU微課堂 | CKS32F4xx系列產(chǎn)品SPI通信
    的頭像 發(fā)表于 10-24 17:12 ?699次閱讀
    MCU微課堂 | <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列產(chǎn)品</b><b class='flag-5'>SPI</b><b class='flag-5'>通信</b>

    MCU微課堂 | CKS32F4xx系列產(chǎn)品GPIO口配置

    MCU微課堂 | CKS32F4xx系列產(chǎn)品GPIO口配置
    的頭像 發(fā)表于 10-24 15:14 ?777次閱讀
    MCU微課堂 | <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列產(chǎn)品</b>GPIO口配置

    CKS32F4xx系列FSMC功能簡(jiǎn)介

    本課講為大家講解CKS32F4xx系列產(chǎn)品的FSMC應(yīng)用實(shí)例,F(xiàn)SMC全稱是Flexible Static Memory Controller,讀作靈活的靜態(tài)存儲(chǔ)控制器,顧名思義,MCU可以通過(guò)FSMC擴(kuò)展靜態(tài)內(nèi)存
    的頭像 發(fā)表于 04-14 15:06 ?933次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>FSMC功能簡(jiǎn)介
    主站蜘蛛池模板: 在线观看免费av网| 熟女人妻水多爽中文字幕| 超碰公开在线caopon| 月夜直播免费观看全集| 色姣姣狠狠撩综合网| 永久免费精品影视网站| 欧美日韩国产码在线| 国产扒开美女双腿屁股流白浆| 亚洲免费福利在线视频| 美女露出逼| 国产VA精品午夜福利视频| 亚洲综合香蕉在线视频| 暖暖直播免费观看韩国| 国产精品免费大片| 在线 无码 中文 强 乱| 日本久久久WWW成人免费毛片丨| 国产一区亚洲| 99久久免费热在线精品| 香蕉免费高清完整| 免费韩伦影院在线观看| 国产精品久久国产三级国不卡顿| 印度性hd18| 色迷迷电影| 看了n遍舍不得删的黄文| 丰满人妻无码AV系列| 伊人情涩网| 肉肉描写很细致的黄文| 久久精品一区二区免费看| 超碰视频在线观看| 夜色爽爽爽久久精品日韩| 热久久视久久精品18| 九九99热久久精品在线6| 成人免费观看www视频| 伊人精品影院| 色偷偷成人网免费视频男人的天堂| 久久操热在线视频精品| 国产 有码 无码 电影| 最新男同鸭子ktv| 香蕉久久日日躁夜夜嗓| 男人到天堂a线牛叉在线| 国内精品伊人久久久久|