【GD32E503评测】05: 测评spi之Flash驱动
[复制链接]
1. SPI Falsh 采用了GD自家的芯片:GD25Q16,参数如下:
2MB的容量,存个字库已经戳戳有余了呢!
接下来就是利用历程的代码驱动它,这里做了稍许修改,写了一个测试小函数。
void SPI_Flash_Test(void)
{
uint8_t tx_buffer[BUFFER_SIZE];
uint8_t rx_buffer[BUFFER_SIZE];
printf("\r\nWrite to tx_buffer:\r\n");
for(int i = 0; i < BUFFER_SIZE; i ++)
{
tx_buffer[i] = i;
printf("0x%02X ",tx_buffer[i]);
if(31 == i%32)
printf("\n\r");
}
/* erases the specified flash sector */
spi_flash_sector_erase(FLASH_WRITE_ADDRESS);
/* write tx_buffer data to the flash */
spi_flash_buffer_write(tx_buffer,FLASH_WRITE_ADDRESS,BUFFER_SIZE);
printf("\n\r\n\rRead from rx_buffer:\n\r\n\r");
/* read a block of data from the flash to rx_buffer */
spi_flash_buffer_read(rx_buffer,FLASH_READ_ADDRESS,BUFFER_SIZE);
/* printf rx_buffer value */
for(int i = 0; i < BUFFER_SIZE; i ++)
{
printf("0x%02X ", rx_buffer[i]);
if(31 == i%32)
printf("\n\r");
}
}
/*!
\file gd25qxx.c
\brief SPI flash gd25qxx driver
\version 2020-09-04, V1.0.0, demo for GD32E50x
*/
#include "bsp_gd25qxx.h"
/*!
\brief initialize SPI0 GPIO and parameter
\param[in] none
\param[out] none
\retval none
*/
void spi_flash_init(void)
{
spi_parameter_struct spi_init_struct;
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOE);
rcu_periph_clock_enable(RCU_SPI0);
/* SPI0_SCK(PA5), SPI0_MISO(PA6) and SPI0_MOSI(PA7) GPIO pin configuration */
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
/* SPI0_CS(PE3) GPIO pin configuration */
gpio_init(GPIOE, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
/* chip select invalid*/
SPI_FLASH_CS_HIGH();
/* SPI0 parameter config */
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_init_struct.device_mode = SPI_MASTER;;
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
spi_init_struct.nss = SPI_NSS_SOFT;
spi_init_struct.prescale = SPI_PSC_8 ;
spi_init_struct.endian = SPI_ENDIAN_MSB;;
spi_init(SPI0, &spi_init_struct);
/* set crc polynomial */
spi_crc_polynomial_set(SPI0,7);
/* enable SPI0 */
spi_enable(SPI0);
}
/*!
\brief erase the specified flash sector
\param[in] sector_addr: address of the sector to erase
\param[out] none
\retval none
*/
void spi_flash_sector_erase(uint32_t sector_addr)
{
/* send write enable instruction */
spi_flash_write_enable();
/* sector erase */
/* select the flash: chip select low */
SPI_FLASH_CS_LOW();
/* send sector erase instruction */
spi_flash_send_byte(SE);
/* send sector_addr high nibble address byte */
spi_flash_send_byte((sector_addr & 0xFF0000) >> 16);
/* send sector_addr medium nibble address byte */
spi_flash_send_byte((sector_addr & 0xFF00) >> 8);
/* send sector_addr low nibble address byte */
spi_flash_send_byte(sector_addr & 0xFF);
/* deselect the flash: chip select high */
SPI_FLASH_CS_HIGH();
/* wait the end of flash writing */
spi_flash_wait_for_write_end();
}
/*!
\brief erase the entire flash
\param[in] none
\param[out] none
\retval none
*/
void spi_flash_bulk_erase(void)
{
/* send write enable instruction */
spi_flash_write_enable();
/* bulk erase */
/* select the flash: chip select low */
SPI_FLASH_CS_LOW();
/* send bulk erase instruction */
spi_flash_send_byte(BE);
/* deselect the flash: chip select high */
SPI_FLASH_CS_HIGH();
/* wait the end of flash writing */
spi_flash_wait_for_write_end();
}
/*!
\brief write more than one byte to the flash
\param[in] pbuffer: pointer to the buffer
\param[in] write_addr: flash's internal address to write
\param[in] num_byte_to_write: number of bytes to write to the flash
\param[out] none
\retval none
*/
void spi_flash_page_write(uint8_t* pbuffer, uint32_t write_addr, uint16_t num_byte_to_write)
{
/* enable the write access to the flash */
spi_flash_write_enable();
/* select the flash: chip select low */
SPI_FLASH_CS_LOW();
/* send "write to memory" instruction */
spi_flash_send_byte(WRITE);
/* send write_addr high nibble address byte to write to */
spi_flash_send_byte((write_addr & 0xFF0000) >> 16);
/* send write_addr medium nibble address byte to write to */
spi_flash_send_byte((write_addr & 0xFF00) >> 8);
/* send write_addr low nibble address byte to write to */
spi_flash_send_byte(write_addr & 0xFF);
/* while there is data to be written on the flash */
while(num_byte_to_write--){
/* send the current byte */
spi_flash_send_byte(*pbuffer);
/* point on the next byte to be written */
pbuffer++;
}
/* deselect the flash: chip select high */
SPI_FLASH_CS_HIGH();
/* wait the end of flash writing */
spi_flash_wait_for_write_end();
}
/*!
\brief write block of data to the flash
\param[in] pbuffer: pointer to the buffer
\param[in] write_addr: flash's internal address to write
\param[in] num_byte_to_write: number of bytes to write to the flash
\param[out] none
\retval none
*/
void spi_flash_buffer_write(uint8_t* pbuffer, uint32_t write_addr, uint16_t num_byte_to_write)
{
uint8_t num_of_page = 0, num_of_single = 0, addr = 0, count = 0, temp = 0;
addr = write_addr % SPI_FLASH_PAGE_SIZE;
count = SPI_FLASH_PAGE_SIZE - addr;
num_of_page = num_byte_to_write / SPI_FLASH_PAGE_SIZE;
num_of_single = num_byte_to_write % SPI_FLASH_PAGE_SIZE;
/* write_addr is SPI_FLASH_PAGE_SIZE aligned */
if(0 == addr){
/* num_byte_to_write < SPI_FLASH_PAGE_SIZE */
if(0 == num_of_page)
spi_flash_page_write(pbuffer,write_addr,num_byte_to_write);
/* num_byte_to_write > SPI_FLASH_PAGE_SIZE */
else{
while(num_of_page--){
spi_flash_page_write(pbuffer,write_addr,SPI_FLASH_PAGE_SIZE);
write_addr += SPI_FLASH_PAGE_SIZE;
pbuffer += SPI_FLASH_PAGE_SIZE;
}
spi_flash_page_write(pbuffer,write_addr,num_of_single);
}
}else{
/* write_addr is not SPI_FLASH_PAGE_SIZE aligned */
if(0 == num_of_page){
/* (num_byte_to_write + write_addr) > SPI_FLASH_PAGE_SIZE */
if(num_of_single > count){
temp = num_of_single - count;
spi_flash_page_write(pbuffer,write_addr,count);
write_addr += count;
pbuffer += count;
spi_flash_page_write(pbuffer,write_addr,temp);
}else
spi_flash_page_write(pbuffer,write_addr,num_byte_to_write);
}else{
/* num_byte_to_write > SPI_FLASH_PAGE_SIZE */
num_byte_to_write -= count;
num_of_page = num_byte_to_write / SPI_FLASH_PAGE_SIZE;
num_of_single = num_byte_to_write % SPI_FLASH_PAGE_SIZE;
spi_flash_page_write(pbuffer,write_addr, count);
write_addr += count;
pbuffer += count;
while(num_of_page--){
spi_flash_page_write(pbuffer,write_addr,SPI_FLASH_PAGE_SIZE);
write_addr += SPI_FLASH_PAGE_SIZE;
pbuffer += SPI_FLASH_PAGE_SIZE;
}
if(0 != num_of_single)
spi_flash_page_write(pbuffer,write_addr,num_of_single);
}
}
}
/*!
\brief read a block of data from the flash
\param[in] pbuffer: pointer to the buffer that receives the data read from the flash
\param[in] read_addr: flash's internal address to read from
\param[in] num_byte_to_read: number of bytes to read from the flash
\param[out] none
\retval none
*/
void spi_flash_buffer_read(uint8_t* pbuffer, uint32_t read_addr, uint16_t num_byte_to_read)
{
/* select the flash: chip select low */
SPI_FLASH_CS_LOW();
/* send "read from memory " instruction */
spi_flash_send_byte(READ);
/* send read_addr high nibble address byte to read from */
spi_flash_send_byte((read_addr & 0xFF0000) >> 16);
/* send read_addr medium nibble address byte to read from */
spi_flash_send_byte((read_addr& 0xFF00) >> 8);
/* send read_addr low nibble address byte to read from */
spi_flash_send_byte(read_addr & 0xFF);
/* while there is data to be read */
while(num_byte_to_read--){
/* read a byte from the flash */
*pbuffer = spi_flash_send_byte(DUMMY_BYTE);
/* point to the next location where the byte read will be saved */
pbuffer++;
}
/* deselect the flash: chip select high */
SPI_FLASH_CS_HIGH();
}
/*!
\brief read flash identification
\param[in] none
\param[out] none
\retval flash identification
*/
uint32_t spi_flash_read_id(void)
{
uint32_t temp = 0, temp0 = 0, temp1 = 0, temp2 = 0;
/* select the flash: chip select low */
SPI_FLASH_CS_LOW();
/* send "RDID " instruction */
spi_flash_send_byte(0x9F);
/* read a byte from the flash */
temp0 = spi_flash_send_byte(DUMMY_BYTE);
/* read a byte from the flash */
temp1 = spi_flash_send_byte(DUMMY_BYTE);
/* read a byte from the flash */
temp2 = spi_flash_send_byte(DUMMY_BYTE);
/* deselect the flash: chip select high */
SPI_FLASH_CS_HIGH();
temp = (temp0 << 16) | (temp1 << 8) | temp2;
return temp;
}
/*!
\brief initiate a read data byte (read) sequence from the flash
\param[in] read_addr: flash's internal address to read from
\param[out] none
\retval none
*/
void spi_flash_start_read_sequence(uint32_t read_addr)
{
/* select the flash: chip select low */
SPI_FLASH_CS_LOW();
/* send "read from memory " instruction */
spi_flash_send_byte(READ);
/* send the 24-bit address of the address to read from */
/* send read_addr high nibble address byte */
spi_flash_send_byte((read_addr & 0xFF0000) >> 16);
/* send read_addr medium nibble address byte */
spi_flash_send_byte((read_addr& 0xFF00) >> 8);
/* send read_addr low nibble address byte */
spi_flash_send_byte(read_addr & 0xFF);
}
/*!
\brief read a byte from the SPI flash
\param[in] none
\param[out] none
\retval byte read from the SPI flash
*/
uint8_t spi_flash_read_byte(void)
{
return(spi_flash_send_byte(DUMMY_BYTE));
}
/*!
\brief send a byte through the SPI interface and return the byte received from the SPI bus
\param[in] byte: byte to send
\param[out] none
\retval the value of the received byte
*/
uint8_t spi_flash_send_byte(uint8_t byte)
{
/* loop while data register in not empty */
while (RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_TBE));
/* send byte through the SPI0 peripheral */
spi_i2s_data_transmit(SPI0,byte);
/* wait to receive a byte */
while(RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_RBNE));
/* return the byte read from the SPI bus */
return(spi_i2s_data_receive(SPI0));
}
/*!
\brief send a half word through the SPI interface and return the half word received from the SPI bus
\param[in] half_word: half word to send
\param[out] none
\retval the value of the received byte
*/
uint16_t spi_flash_send_halfword(uint16_t half_word)
{
/* loop while data register in not empty */
while(RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_TBE));
/* send half word through the SPI0 peripheral */
spi_i2s_data_transmit(SPI0,half_word);
/* wait to receive a half word */
while(RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_RBNE));
/* return the half word read from the SPI bus */
return spi_i2s_data_receive(SPI0);
}
/*!
\brief enable the write access to the flash
\param[in] none
\param[out] none
\retval none
*/
void spi_flash_write_enable(void)
{
/* select the flash: chip select low */
SPI_FLASH_CS_LOW();
/* send "write enable" instruction */
spi_flash_send_byte(WREN);
/* deselect the flash: chip select high */
SPI_FLASH_CS_HIGH();
}
/*!
\brief poll the status of the write in progress(wip) flag in the flash's status register
\param[in] none
\param[out] none
\retval none
*/
void spi_flash_wait_for_write_end(void)
{
uint8_t flash_status = 0;
/* select the flash: chip select low */
SPI_FLASH_CS_LOW();
/* send "read status register" instruction */
spi_flash_send_byte(RDSR);
/* loop as long as the memory is busy with a write cycle */
do{
/* send a dummy byte to generate the clock needed by the flash
and put the value of the status register in flash_status variable */
flash_status = spi_flash_send_byte(DUMMY_BYTE);
}while((flash_status & WIP_FLAG) == SET);
/* deselect the flash: chip select high */
SPI_FLASH_CS_HIGH();
}
void SPI_Flash_Test(void)
{
uint8_t tx_buffer[BUFFER_SIZE];
uint8_t rx_buffer[BUFFER_SIZE];
printf("\r\nWrite to tx_buffer:\r\n");
for(int i = 0; i < BUFFER_SIZE; i ++)
{
tx_buffer[i] = i;
printf("0x%02X ",tx_buffer[i]);
if(31 == i%32)
printf("\n\r");
}
/* erases the specified flash sector */
spi_flash_sector_erase(FLASH_WRITE_ADDRESS);
/* write tx_buffer data to the flash */
spi_flash_buffer_write(tx_buffer,FLASH_WRITE_ADDRESS,BUFFER_SIZE);
printf("\n\r\n\rRead from rx_buffer:\n\r\n\r");
/* read a block of data from the flash to rx_buffer */
spi_flash_buffer_read(rx_buffer,FLASH_READ_ADDRESS,BUFFER_SIZE);
/* printf rx_buffer value */
for(int i = 0; i < BUFFER_SIZE; i ++)
{
printf("0x%02X ", rx_buffer[i]);
if(31 == i%32)
printf("\n\r");
}
}
且看头文件:
#ifndef GD25QXX_H
#define GD25QXX_H
#include "gd32e50x.h"
#include <string.h>
#include <stdio.h>
#define BUFFER_SIZE SPI_FLASH_PAGE_SIZE // 256
#define VERSION_ID "1.0.0"
#define SFLASH_ID 0xC84015
#define FLASH_WRITE_ADDRESS 0x000000
#define FLASH_READ_ADDRESS FLASH_WRITE_ADDRESS
#define WRITE 0x02 /* write to memory instruction */
#define WRSR 0x01 /* write status register instruction */
#define WREN 0x06 /* write enable instruction */
#define READ 0x03 /* read from memory instruction */
#define RDSR 0x05 /* read status register instruction */
#define RDID 0x9F /* read identification */
#define SE 0x20 /* sector erase instruction */
#define BE 0xC7 /* bulk erase instruction */
#define WIP_FLAG 0x01 /* write in progress(wip)flag */
#define DUMMY_BYTE 0xA5
#define SPI_FLASH_PAGE_SIZE 0x100
#define SPI_FLASH_CS_LOW() gpio_bit_reset(GPIOE, GPIO_PIN_3)
#define SPI_FLASH_CS_HIGH() gpio_bit_set(GPIOE, GPIO_PIN_3)
/* initialize SPI0 GPIO and parameter */
void spi_flash_init(void);
/* erase the specified flash sector */
void spi_flash_sector_erase(uint32_t sector_addr);
/* erase the entire flash */
void spi_flash_bulk_erase(void);
/* write more than one byte to the flash */
void spi_flash_page_write(uint8_t* pbuffer,uint32_t write_addr,uint16_t num_byte_to_write);
/* write block of data to the flash */
void spi_flash_buffer_write(uint8_t* pbuffer,uint32_t write_addr,uint16_t num_byte_to_write);
/* read a block of data from the flash */
void spi_flash_buffer_read(uint8_t* pbuffer,uint32_t read_addr,uint16_t num_byte_to_read);
/* read flash identification */
uint32_t spi_flash_read_id(void);
/* initiate a read data byte (read) sequence from the flash */
void spi_flash_start_read_sequence(uint32_t read_addr);
/* read a byte from the SPI flash */
uint8_t spi_flash_read_byte(void);
/* send a byte through the SPI interface and return the byte received from the SPI bus */
uint8_t spi_flash_send_byte(uint8_t byte);
/* send a half word through the SPI interface and return the half word received from the SPI bus */
uint16_t spi_flash_send_halfword(uint16_t half_word);
/* enable the write access to the flash */
void spi_flash_write_enable(void);
/* poll the status of the write in progress (wip) flag in the flash's status register */
void spi_flash_wait_for_write_end(void);
void SPI_Flash_Test(void);
#endif /* GD25QXX_H */
最后看测试效果吧,嘿嘿:
|