但其实6E2跟6M4的QSPI接口对于QSPI FLASH的读写代码并没有区别,代码甚至可以相互复制来用,我这边参考了野火启明开发板对于6M5读写板上QSPI FLASH的代码,移植到6E2上。首先是接线方式,6E2上面的QSPI接口是连续的,占用了P100~P104,P112共计6根线,6根线包含了QIO0 QIO1 QIO2 QIO3 QCLK SSL六根线,加上3V3电源和地两根线,把八脚的SPI FLASH全都占用了,按照野火给出的文档,接线示意如下:
(注意,有其中两根线需要飞线到PMOD2上)
使用如下代码可以进行QSPI FLASH的擦除,写入,读出操作:
void QSPI_Flash_SectorErase(uint32_t adress)
{
unsigned char data[6] = {};
data[0] = 0x06; //write_enable_command
data[1] = 0x20; //erase_command
data[2] = (uint8_t)(adress >> 16);
data[3] = (uint8_t)(adress >> 8);
data[4] = (uint8_t)(adress);
R_QSPI->SFMCMD = 1U;
R_QSPI->SFMCOM = data[0];
R_QSPI_DirectWrite(&g_qspi0_ctrl, &data[1], 4, false);
QSPI_Flash_WaitForWriteEnd();
}
void QSPI_Flash_BufferWrite(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
/*mod运算求余,若writeAddr是SPI_FLASH_PageSize整数倍,运算结果Addr值为0*/
Addr = WriteAddr % SPI_FLASH_PageSize;
/*差count个数据值,刚好可以对齐到页地址*/
count = SPI_FLASH_PageSize - Addr;
/*计算出要写多少整数页*/
NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
/*mod运算求余,计算出剩余不满一页的字节数*/
NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
/* Addr=0,则WriteAddr 刚好按页对齐 aligned */
if (Addr == 0)
{
/* NumByteToWrite < SPI_FLASH_PageSize */
if (NumOfPage == 0)
{
R_QSPI_Write(&g_qspi0_ctrl, pBuffer, (uint8_t*)WriteAddr , NumByteToWrite);
QSPI_Flash_WaitForWriteEnd();
}
else /* NumByteToWrite > SPI_FLASH_PageSize */
{
/*先把整数页都写了*/
while (NumOfPage--)
{
R_QSPI_Write(&g_qspi0_ctrl, pBuffer, (uint8_t*)WriteAddr , SPI_FLASH_PageSize);
QSPI_Flash_WaitForWriteEnd();
WriteAddr += SPI_FLASH_PageSize;
pBuffer += SPI_FLASH_PageSize;
}
/*若有多余的不满一页的数据,把它写完*/
R_QSPI_Write(&g_qspi0_ctrl, pBuffer, (uint8_t*)WriteAddr , NumOfSingle);
QSPI_Flash_WaitForWriteEnd();
}
}
/* 若地址与 SPI_FLASH_PageSize 不对齐 */
else
{
/* NumByteToWrite < SPI_FLASH_PageSize */
if (NumOfPage == 0)
{
/*当前页剩余的count个位置比NumOfSingle小,一页写不完*/
if (NumOfSingle > count)
{
temp = NumOfSingle - count;
/*先写满当前页*/
R_QSPI_Write(&g_qspi0_ctrl, pBuffer, (uint8_t*)WriteAddr , count);
QSPI_Flash_WaitForWriteEnd();
WriteAddr += count;
pBuffer += count;
/*再写剩余的数据*/
R_QSPI_Write(&g_qspi0_ctrl, pBuffer, (uint8_t*)WriteAddr , temp);
QSPI_Flash_WaitForWriteEnd();
}
else /*当前页剩余的count个位置能写完NumOfSingle个数据*/
{
R_QSPI_Write(&g_qspi0_ctrl, pBuffer, (uint8_t*)WriteAddr , NumByteToWrite);
QSPI_Flash_WaitForWriteEnd();
}
}
else /* NumByteToWrite > SPI_FLASH_PageSize */
{
/*地址不对齐多出的count分开处理,不加入这个运算*/
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
/* 先写完count个数据,为的是让下一次要写的地址对齐 */
R_QSPI_Write(&g_qspi0_ctrl, pBuffer, (uint8_t*)WriteAddr , count);
QSPI_Flash_WaitForWriteEnd();
/* 接下来就重复地址对齐的情况 */
WriteAddr += count;
pBuffer += count;
/*把整数页都写了*/
while (NumOfPage--)
{
R_QSPI_Write(&g_qspi0_ctrl, pBuffer, (uint8_t*)WriteAddr , SPI_FLASH_PageSize);
QSPI_Flash_WaitForWriteEnd();
WriteAddr += SPI_FLASH_PageSize;
pBuffer += SPI_FLASH_PageSize;
}
/*若有多余的不满一页的数据,把它写完*/
if (NumOfSingle != 0)
{
R_QSPI_Write(&g_qspi0_ctrl, pBuffer, (uint8_t*)WriteAddr , NumOfSingle);
QSPI_Flash_WaitForWriteEnd();
}
}
}
}
void QSPI_Flash_BufferRead(uint8_t *pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
R_QSPI_Read(&g_qspi0_ctrl, pBuffer, (uint8_t*)ReadAddr, NumByteToRead);
}
static void qspi_d0_byte_write_standard(uint8_t byte)
{
R_QSPI->SFMCOM = byte;
}
fsp_err_t R_QSPI_Read(spi_flash_ctrl_t *p_ctrl,
uint8_t *p_src,
uint8_t *const p_dest,
uint32_t byte_count)
{
qspi_instance_ctrl_t *p_instance_ctrl = (qspi_instance_ctrl_t *) p_ctrl;
uint32_t chip_address = (uint32_t) p_dest - (uint32_t) QSPI_DEVICE_START_ADDRESS + R_QSPI->SFMCNT1;
bool restore_spi_mode = false;
void (* write_command)(uint8_t byte) = qspi_d0_byte_write_standard;
void (* write_address)(uint8_t byte) = qspi_d0_byte_write_standard;
#if QSPI_CFG_SUPPORT_EXTENDED_SPI_MULTI_LINE_PROGRAM
/* If the peripheral is in extended SPI mode, and the configuration provided in the BSP allows for programming on
* multiple data lines, and a unique command is provided for the required mode, update the SPI protocol to send
* data on multiple lines. */
if ((SPI_FLASH_DATA_LINES_1 != p_instance_ctrl->data_lines) &&
(SPI_FLASH_PROTOCOL_EXTENDED_SPI == R_QSPI->SFMSPC_b.SFMSPI))
{
R_QSPI->SFMSPC_b.SFMSPI = p_instance_ctrl->data_lines;
restore_spi_mode = true;
/* Write command in extended SPI mode on one line. */
write_command = gp_qspi_prv_byte_write[p_instance_ctrl->data_lines];
if (SPI_FLASH_DATA_LINES_1 == p_instance_ctrl->p_cfg->page_program_address_lines)
{
/* Write address in extended SPI mode on one line. */
write_address = gp_qspi_prv_byte_write[p_instance_ctrl->data_lines];
}
}
#endif
/* Enter Direct Communication mode */
R_QSPI->SFMCMD = 1;
/* Send command to enable writing */
write_command(0x03);
/* Write the address. */
if ((p_instance_ctrl->p_cfg->address_bytes & R_QSPI_SFMSAC_SFMAS_Msk) == SPI_FLASH_ADDRESS_BYTES_4)
{
/* Send the most significant byte of the address */
write_address((uint8_t)(chip_address >> 24));
}
/* Send the remaining bytes of the address */
write_address((uint8_t)(chip_address >> 16));
write_address((uint8_t)(chip_address >> 8));
write_address((uint8_t)(chip_address));
/* Write the data. */
uint32_t index = 0;
while (index < byte_count)
{
/* Read the device memory into the passed in buffer */
*(p_src + index) = (uint8_t) R_QSPI->SFMCOM;
index++;
}
/* Close the SPI bus cycle. Reference section 39.10.3 "Generating the SPI Bus Cycle during Direct Communication"
* in the RA6M3 manual R01UH0886EJ0100. */
R_QSPI->SFMCMD = 1;
/* Return to ROM access mode */
R_QSPI->SFMCMD = 0;
return FSP_SUCCESS;
}
复制代码调用代码运行,看看效果,先是擦除,写入,读出:
uint8_t buffer_write[] = "Interesting666666";
uint8_t buffer_read[sizeof(buffer_write)];
float double_buffer_write[7] = {1.2 , 3.4 , 5.5 , 7.9 , 9.8 , 9.9 , 10.0};
float double_buffer_read[sizeof(double_buffer_write)] = {0};
#define FLASH_WriteAddress1 0x00000
#define FLASH_WriteAddress2 0x00100
R_QSPI_Open(&g_qspi0_ctrl, &g_qspi0_cfg);
R_BSP_SoftwareDelay(10u, BSP_DELAY_UNITS_MILLISECONDS);
FlashID = QSPI_Flash_ReadID();
FlashDeviceID = QSPI_Flash_ReadDeviceID();
printf("FlashID = 0x%x FlashDeviceID = 0x%x\n" , FlashID , FlashDeviceID);
QSPI_Flash_SectorErase(FLASH_WriteAddress1);
QSPI_Flash_BufferWrite(buffer_write , FLASH_WriteAddress1 , sizeof(buffer_write));
printf("Tx_Buffer = %s \r\n", buffer_write);
QSPI_Flash_BufferRead(buffer_read , FLASH_WriteAddress1 , sizeof(buffer_read));
printf("Rx_Buffer = %s \r\n", buffer_read);
QSPI_Flash_SectorErase(FLASH_WriteAddress2);
QSPI_Flash_BufferWrite((void *)double_buffer_write , FLASH_WriteAddress2 , sizeof(double_buffer_write));
QSPI_Flash_BufferRead((void *)double_buffer_read , FLASH_WriteAddress2 , sizeof(double_buffer_read));
printf("%f %f %f %f %f %f %f\n" ,
double_buffer_read[0] , double_buffer_read[1] , double_buffer_read[2] ,
double_buffer_read[3] , double_buffer_read[4], double_buffer_read[5] ,
double_buffer_read[6]);
复制代码然后把擦除和写入操作注释掉,只读:
R_QSPI_Open(&g_qspi0_ctrl, &g_qspi0_cfg);
R_BSP_SoftwareDelay(10u, BSP_DELAY_UNITS_MILLISECONDS);
FlashID = QSPI_Flash_ReadID();
FlashDeviceID = QSPI_Flash_ReadDeviceID();
printf("FlashID = 0x%x FlashDeviceID = 0x%x\n" , FlashID , FlashDeviceID);
// QSPI_Flash_SectorErase(FLASH_WriteAddress1);
// QSPI_Flash_BufferWrite(buffer_write , FLASH_WriteAddress1 , sizeof(buffer_write));
// printf("Tx_Buffer = %s \r\n", buffer_write);
QSPI_Flash_BufferRead(buffer_read , FLASH_WriteAddress1 , sizeof(buffer_read));
printf("Rx_Buffer = %s \r\n", buffer_read);
// QSPI_Flash_SectorErase(FLASH_WriteAddress2);
// QSPI_Flash_BufferWrite((void *)double_buffer_write , FLASH_WriteAddress2 , sizeof(double_buffer_write));
QSPI_Flash_BufferRead((void *)double_buffer_read , FLASH_WriteAddress2 , sizeof(double_buffer_read));
printf("%f %f %f %f %f %f %f\n" ,
double_buffer_read[0] , double_buffer_read[1] , double_buffer_read[2] ,
double_buffer_read[3] , double_buffer_read[4], double_buffer_read[5] ,
double_buffer_read[6]);
复制代码