瑞萨RA6系列的大部分型号都带QSPI总线,不过在RA6E2和RA6M4上的Stack归类不同,RA6E2的QSPI总线归类到了通信类(Communication),而RA6M4和RA6M5则归类到了存储类(Storage):
14.jpg 13.jpg

但其实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全都占用了,按照野火给出的文档,接线示意如下:
15.jpg 微信图片_20230802152038.jpg
(注意,有其中两根线需要飞线到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]);
  • 复制代码

           
    16.jpg

    然后把擦除和写入操作注释掉,只读:
            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]);
  • 复制代码


    17.jpg