CLK -- PB13(SPI2_SCK)
DO -- PB14(SPI2_MISO)
DI -- PB15(SPI2_MOSI)


Page Program 02h

//SPI2 初始化 void spi_flash_init(void) { GPIO_Config_T gpioConfig; SPI_Config_T spiConfig; /* Enable related Clock */ RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_SPI2); RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOB); /* config MISO*/ gpioConfig.pin = GPIO_PIN_14 ; gpioConfig.mode = GPIO_MODE_AF_PP; gpioConfig.speed = GPIO_SPEED_50MHz; GPIO_Config(GPIOB, &gpioConfig); /** config SCK,MOSI*/ gpioConfig.pin = GPIO_PIN_13 | GPIO_PIN_15; gpioConfig.mode = GPIO_MODE_AF_PP; gpioConfig.speed = GPIO_SPEED_50MHz; GPIO_Config(GPIOB, &gpioConfig); /** config CS */ gpioConfig.pin = GPIO_PIN_12; gpioConfig.mode = GPIO_MODE_OUT_PP; gpioConfig.speed = GPIO_SPEED_50MHz; GPIO_Config(GPIOB, &gpioConfig); GPIO_SetBit(GPIOB, GPIO_PIN_12); GPIO_SetBit(GPIOB, GPIO_PIN_13); GPIO_SetBit(GPIOB, GPIO_PIN_14); GPIO_SetBit(GPIOB, GPIO_PIN_15); SPI_ConfigStructInit(&spiConfig); spiConfig.length = SPI_DATA_LENGTH_8B; spiConfig.baudrateDiv = SPI_BAUDRATE_DIV_64; /* 2 line full duplex */ spiConfig.direction = SPI_DIRECTION_2LINES_FULLDUPLEX; /* LSB first */ spiConfig.firstBit = SPI_FIRSTBIT_MSB; /* Slave mode */ spiConfig.mode = SPI_MODE_MASTER; /* Polarity is low */ spiConfig.polarity = SPI_CLKPOL_HIGH; /* Software select slave enable */ spiConfig.nss = SPI_NSS_SOFT; /* Phase is 1 edge */ spiConfig.phase = SPI_CLKPHA_2EDGE; spiConfig.crcPolynomial = 7; /* SPI config */ SPI_Config(SPI2, &spiConfig); SPI_ConfigDataSize(SPI2, SPI_DATA_LENGTH_8B); SPI_Enable(SPI2); }2.2 DMA的初始化
内存地址和传输长度可以先不配,等后面真正要传输时再配置,两个DMA通道都先不要使能。
DMA_Config_T DMA_ConfigStruct; void spi_fullduplex_dma_init(void) { RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_DMA1); DMA_ConfigStruct.peripheralBaseAddr = (uint32_t)(SPI2_BASE + 0x0C) ; DMA_ConfigStruct.peripheralInc = DMA_PERIPHERAL_INC_DISABLE; DMA_ConfigStruct.memoryInc = DMA_MEMORY_INC_ENABLE; DMA_ConfigStruct.peripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_BYTE; DMA_ConfigStruct.memoryDataSize = DMA_MEMORY_DATA_SIZE_BYTE; DMA_ConfigStruct.loopMode = DMA_MODE_NORMAL; DMA_ConfigStruct.priority = DMA_PRIORITY_HIGH; DMA_ConfigStruct.M2M = DMA_M2MEN_DISABLE; //SPI2_TX DMA_CH5 DMA_Reset(DMA1_Channel5); DMA_ConfigStruct.memoryBaseAddr = (uint32_t) AddressBuffer; DMA_ConfigStruct.dir = DMA_DIR_PERIPHERAL_DST; DMA_ConfigStruct.bufferSize = 0; DMA_Config(DMA1_Channel5, &DMA_ConfigStruct); SPI_I2S_EnableDMA(SPI2, SPI_I2S_DMA_REQ_TX); //SPI2_RX DMA_CH4 DMA_Reset(DMA1_Channel4); DMA_ConfigStruct.memoryBaseAddr = (uint32_t) AddressBuffer; DMA_ConfigStruct.dir = DMA_DIR_PERIPHERAL_SRC; DMA_ConfigStruct.bufferSize = 0; DMA_Config(DMA1_Channel4, &DMA_ConfigStruct); SPI_I2S_EnableDMA(SPI2, SPI_I2S_DMA_REQ_RX); //DMA_Enable(DMA1_Channel4); //DMA_Enable(DMA1_Channel5; }2.3 SPI的DMA发送
void spi_dam_transmit_buffer(unsigned char *buffer, unsigned int length) { DMA1_Channel4->CHCFG_B.MIMODE = DISABLE; DMA1_Channel4->CHMADDR = (uint32_t)AddressBuffer; DMA1_Channel4->CHNDATA = length; DMA1_Channel5->CHCFG_B.MIMODE = ENABLE ; DMA1_Channel5->CHMADDR = (uint32_t)buffer; DMA1_Channel5->CHNDATA = length; DMA1_Channel4->CHCFG_B.CHEN = ENABLE; DMA1_Channel5->CHCFG_B.CHEN = ENABLE; while (DMA_ReadStatusFlag(DMA1_FLAG_TC5) == RESET); DMA_ClearStatusFlag(DMA1_FLAG_TC5); while (DMA_ReadStatusFlag(DMA1_FLAG_TC4) == RESET); DMA_ClearStatusFlag(DMA1_FLAG_TC4); DMA1_Channel5->CHCFG_B.CHEN = DISABLE; DMA1_Channel4->CHCFG_B.CHEN = DISABLE; }2.4 SPI的DMA接收
void spi_dam_receive_buffer(unsigned char *buffer, unsigned int length) { DMA1_Channel5->CHCFG_B.MIMODE = DISABLE; DMA1_Channel5->CHMADDR = (uint32_t)AddressBuffer; DMA1_Channel5->CHNDATA = length; DMA1_Channel4->CHCFG_B.MIMODE = ENABLE ; DMA1_Channel4->CHMADDR = (uint32_t)buffer; DMA1_Channel4->CHNDATA = length; DMA1_Channel4->CHCFG_B.CHEN = ENABLE; DMA1_Channel5->CHCFG_B.CHEN = ENABLE; while (DMA_ReadStatusFlag(DMA1_FLAG_TC5) == RESET); DMA_ClearStatusFlag(DMA1_FLAG_TC5); while (DMA_ReadStatusFlag(DMA1_FLAG_TC4) == RESET); DMA_ClearStatusFlag(DMA1_FLAG_TC4); DMA1_Channel5->CHCFG_B.CHEN = DISABLE; DMA1_Channel4->CHCFG_B.CHEN = DISABLE; }三、NorFlash的驱动
#define W25XXX_PageProgram 0x02
3.1 NorFlash的数据读取
读取多个数据的流程与不用DMA的方式类似,只是原来用for循环读数据的部分用spi_dam_receive_buffer()替换。。
//SPI FLASH的数据读取 void w25qxxx_read(unsigned char *buf, unsigned int addr, unsigned short num) { unsigned short i; w25qxxx_cs_set(0); //使能器件 w25qxxx_wr_byte(W25XXX_ReadData); //发送读取命令 w25qxxx_wr_byte((unsigned char)((addr) >> 16)); //发送24bit地址 w25qxxx_wr_byte((unsigned char)((addr) >> 8)); w25qxxx_wr_byte((unsigned char)addr); spi_dam_receive_buffer(buf,num); w25qxxx_cs_set(1); }3.2 NorFlash的页编程
//SPI FLASH的页编程 void w25qxxx_write_page(unsigned char *buf, unsigned int addr, unsigned short num) { unsigned short i; w25qxxx_write_enable(); // SET WEL w25qxxx_cs_set(0); //使能器件 w25qxxx_wr_byte(W25XXX_PageProgram); //发送写页命令 w25qxxx_wr_byte((unsigned char)((addr) >> 16)); //发送24bit地址 w25qxxx_wr_byte((unsigned char)((addr) >> 8)); w25qxxx_wr_byte((unsigned char)addr); spi_dam_transmit_buffer(buf, num); w25qxxx_cs_set(1); //取消片选 w25qxxx_wait_busy(); //等待写入结束 }四、测试验证
//初始化 void w25qxxx_init() { spi_flash_init(); spi_fullduplex_dma_init(); }
然后读一下芯片的ID,这步主要是确认一下硬件是否正常。
FlashChipID = w25qxxx_read_id();
接下来就往任意一个扇区写入从0x00-0xFF的数据,擦除扇区后,写入该扇区,再读出该扇区的数据,把读出的数据和写入的原始数据作对比。
//flash测试 unsigned short FlashChipID; unsigned char flash_test_write_buffer[4096]; unsigned char flash_test_read_buffer[4096]; unsigned int AddrSector=0; void w25qxxx_test() { unsigned int i; for(i=0;i<4096;i++) { flash_test_write_buffer[i]=i%256; } w25qxxx_erase_sector(AddrSector); w25qxxx_write_sector(flash_test_write_buffer,AddrSector); w25qxxx_read(flash_test_read_buffer,AddrSector*4096,4096); if(memcmp(flash_test_read_buffer,flash_test_write_buffer,4096)==0) { printf("flash write success."); } else { printf("flash write fail!!!"); } }下载程序并执行,查看输出的日志,可以看到芯片的DeviceID=0xEF16,说明硬件正常;写入数据和读出数据完全一致,读写正常。