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,说明硬件正常;写入数据和读出数据完全一致,读写正常。![]()
我要赚赏金
