首页 > 行业资讯 > 正文

(2)创建w25q128.c并输入以下代码。

复制/********************************************************************************************************* FLASH 驱 动 程 序 *********************************************************************************************************/ #include “w25q128.h” #include “delay.h” /*************************************************** Name :SPI2_SetSpeed Function :SPI2速度设置函数 Paramater : SpeedSet:0~7 Return :None ***************************************************/ void SPI2_SetSpeed( u8 SpeedSet ) { SpeedSet &= 0x07 ; //限制范围 SPI2->CR1 &= 0xFFC7 ; SPI2->CR1 |= SpeedSet<<3 ; //设置SPI2速度 SPI2->CR1 |= 1<<6 ; //SPI设备使能 } /*************************************************** Name :SPI2_ReadWriteByte Function :SPI2读写一个字节 Paramater : TxData:要写入的字节 Return :读取到的字节 ***************************************************/ u8 SPI2_ReadWriteByte( u8 TxData ) { u16 retry=0; //等待发送区空 while( ( SPI2->SR&0x02 )==0 ) { retry ++ ; //超时退出 if( retry>=0xFFFE ) return 0 ; } SPI2->DR = TxData ; //发送一个byte //等待接收完一个byte retry = 0 ; while( ( SPI2->SR&0x01 )==0 ) { retry ++ ; //超时退出 if( retry>=0xFFFE ) return 0 ; } return SPI2->DR ; //返回收到的数据 } /*************************************************** Name :W25QXX_Init Function :初始化W25Q128芯片 Paramater :None Return :None ***************************************************/ void W25QXX_Init() { RCC->APB2ENR |= 1<<3 ; //PORTB时钟使能 GPIOB->CRH &= 0x0000FFFF ; GPIOB->CRH |= 0xBBB30000 ; //PB12推挽输出+PB13/14/15复用 GPIOB->ODR |= 0x7<<13 ; //PB13/14/15上拉 W25QXX_CS = 1 ; //SPI FLASH不选中 //初始化SPI RCC->APB1ENR |= 1<<14 ; //SPI2时钟使能 SPI2->CR1 |= 0<<10 ; //全双工模式 SPI2->CR1 |= 1<<9 ; //软件nss管理 SPI2->CR1 |= 1<<8 ; SPI2->CR1 |= 1<<2 ; //SPI主机 SPI2->CR1 |= 0<<11 ; //8bit数据格式 SPI2->CR1 |= 1<<1 ; //空闲模式下SCK为1 CPOL=1 SPI2->CR1 |= 1<<0 ; //数据采样从第二个时间边沿开始,CPHA=1 //对SPI2属于APB1的外设.时钟频率最大为36M SPI2->CR1 |= 3<<3 ; //Fsck=Fpclk1/256 SPI2->CR1 |= 0<<7 ; //MSBfirst SPI2->CR1 |= 1<<6 ; //SPI设备使能 SPI2_ReadWriteByte( 0xFF ) ; //启动传输 SPI2_SetSpeed( SPI_SPEED_2 ) ; //设置为18M时钟,高速模式 } /*************************************************** Name :W25QXX_Wait_Busy Function :等待空闲 Paramater :None Return :None ***************************************************/ void W25QXX_Wait_Busy() { u8 byte=0 ; // 等待BUSY位清空 do { W25QXX_CS = 0 ; //使能器件 SPI2_ReadWriteByte( W25X_ReadStatusReg ) ; //发送读取状态寄存器命令 byte = SPI2_ReadWriteByte( 0xFF ) ; //读取一个字节 W25QXX_CS = 1 ; //取消片选 }while( ( byte&0x01 )==0x01 ) ; } /*************************************************** Name :W25QXX_Erase_Chip Function :擦除整个芯片 Paramater :None Return :None ***************************************************/ void W25QXX_Erase_Chip() { W25QXX_CS = 0 ; //使能器件 SPI2_ReadWriteByte( W25X_WriteEnable ) ; //发送写使能 W25QXX_CS = 1 ; //取消片选 W25QXX_Wait_Busy() ; W25QXX_CS=0 ; //使能器件 SPI2_ReadWriteByte( W25X_ChipErase ) ; //发送片擦除命令 W25QXX_CS = 1 ; //取消片选 W25QXX_Wait_Busy() ; //等待芯片擦除结束 } /*************************************************** Name :W25QXX_Erase_Sector Function :擦除一个扇区 Paramater : Address:扇区地址 Return :None ***************************************************/ void W25QXX_Erase_Sector( u32 Address ) { Address *= 4096 ; W25QXX_CS = 0 ; //使能器件 SPI2_ReadWriteByte( W25X_WriteEnable ) ; //发送写使能 W25QXX_CS = 1 ; //取消片选 W25QXX_Wait_Busy(); W25QXX_CS = 0 ; //使能器件 SPI2_ReadWriteByte( W25X_SectorErase ) ; //发送扇区擦除指令 SPI2_ReadWriteByte( ( u8 )( Address>>16 ) ) ; //发送24bit地址 SPI2_ReadWriteByte( ( u8 )( Address>>8 ) ) ; SPI2_ReadWriteByte( ( u8 )Address ) ; W25QXX_CS = 1 ; //取消片选 W25QXX_Wait_Busy() ; //等待擦除完成 } /*************************************************** Name :W25QXX_Read Function :在指定地址开始读取指定长度的数据 Paramater : pBuffer:数据存储区 Address:开始读取的地址 Len:要读取的字节数 Return :None ***************************************************/ void W25QXX_Read( u8 *pBuffer, u32 Address, u16 Len ) { u16 i ; W25QXX_CS = 0 ; //使能器件 SPI2_ReadWriteByte( W25X_ReadData ) ; //发送读取命令 SPI2_ReadWriteByte( ( u8 )( Address>>16 ) ) ; //发送24bit地址 SPI2_ReadWriteByte( ( u8 )( Address>>8 ) ) ; SPI2_ReadWriteByte( ( u8 )Address ); for( i=0; i>16 ) ) ; //发送24bit地址 SPI2_ReadWriteByte( ( u8 )( Address>>8 ) ) ; SPI2_ReadWriteByte( ( u8 )Address ) ; for( i=0; ipageremain else { pBuffer += pageremain ; Address += pageremain ; Len -= pageremain ; //减去已经写入了的字节数 //一次可以写入256个字节 if( Len>256 ) pageremain = 256 ; //不够256个字节了 else pageremain = Len ; } } } /*************************************************** Name :W25QXX_Write_NoCheck Function :在指定地址开始写入指定长度的数据 Paramater : pBuffer:数据存储区 Address:开始写入的地址 Len:要写入的字节数 Return :None ***************************************************/ u8 W25QXX_BUFFER[ 4096 ] ; void W25QXX_Write( u8 *pBuffer, u32 Address, u16 Len ) { u32 secpos ; u16 secoff ; u16 secremain ; u16 i ; u8 *W25QXX_BUF ; W25QXX_BUF = W25QXX_BUFFER ; secpos = Address/4096 ; //扇区地址 secoff = Address%4096 ; //在扇区内的偏移 secremain = 4096-secoff ; //扇区剩余空间大小 //不大于4096个字节 if( Len<=secremain ) secremain = Len ; while( 1 ) { W25QXX_Read( W25QXX_BUF, secpos*4096, 4096 ) ; //读出整个扇区的内容 //校验数据 for( i=0; i secremain ) { W25QXX_Erase_Sector( secpos ) ; //擦除这个扇区 //复制 for( i=0; i<secremain; i++ ) W25QXX_BUF[ i+secoff ] = pBuffer[ i ] ; W25QXX_Write_NoCheck( W25QXX_BUF, secpos*4096, 4096 ) ; //写入整个扇区 } else W25QXX_Write_NoCheck( pBuffer, Address, secremain ) ; //写已经擦除了的,直接写入扇区剩余区间 //写入结束了 if( Len==secremain ) break ; //写入未结束 else { secpos ++ ; //扇区地址增1 secoff = 0 ; //偏移位置为0 pBuffer += secremain ; //指针偏移 Address += secremain ; //写地址偏移 Len = secremain ; //字节数递减 //下一个扇区还是写不完 if( Len>4096 ) secremain = 4096 ; //下一个扇区可以写完了 else secremain = Len ; } } }

(3)在1.c文件中输入以下代码。

复制#include “sys.h” #include “delay.h” #include “usart1.h” #include “lcd.h” #include “w25q128.h” const u8 TEXT_Buffer[] = { “WarShip STM32F1 SPI TEST” } ; #define SIZE sizeof( TEXT_Buffer ) int main() { u8 datatemp[ SIZE ] ; u32 FLASH_SIZE ; STM32_Clock_Init( 9 ) ; //STM32时钟初始化 SysTick_Init( 72 ) ; //SysTick初始化 USART1_Init( 72, 115200 ) ; //初始化串口1波特率115200 LCD_Init() ; //LCD初始化 W25QXX_Init() ; //W25QXX初始化 POINT_COLOR = RED ; //设置字体为红色 FLASH_SIZE = 128*1024*1024 ; //FLASH 大小为16M字节 W25QXX_Write( (u8*)TEXT_Buffer, FLASH_SIZE-100, SIZE ) ; //从倒数第100个地址处开始,写入SIZE长度的数据 W25QXX_Read( datatemp, FLASH_SIZE-100, SIZE ) ; //从倒数第100个地址处开始,读出SIZE个字节 LCD_ShowString( 0, 0, datatemp ) ; //显示读到的字符串 while( 1 ) { } }

猜你喜欢