【Follow me第二季第3期】基础任务:2、Qflash和Oflash测试及Uart输出
[复制链接]
1、任务介绍
本次的任务是完成EK-RA6M5开发板的Qflash的测试,开发板的上面集成了QFlash和Oflash两个flash芯片。本次测试Qflash接口的MX25L25645G芯片
RA6M5内置了完善的QSPI接口,参考qspi_ek_ra6m5_ep例程完成本次测试。
2、项目配置
(1) 使用FSP建立CMAKE项目
使用GCC作为编译工具。
(2)修改heap尺寸
修改为0x200大小,根据软件库的使用情况。本次使用了#include <stdarg.h>中的函数。
(3) 增加QSPI软件栈
New Stack->Storage->QSPI 软件包
注意全局变量名称g_qspi,不要使用默认的变量名。这在使用参考程序时较麻烦。其它引脚等默认配置。
(4) 配置uart设置
New Stack->connectivity->UART软件包
使用sci通道7,引脚默认,设置callback函数user_uart_callback()
配置完成后生成代码。
3、程序代码
(1) 使用VSCode打卡项目
(2)将参考程序qspi_ep.h拷贝到项目路径SRC,加入到hal_entry.c
/*
* Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "hal_data.h"
#include "qspi_ep.h"
#include "app_print.h"
#define RESET_VALUE (0x00)
/*
* private functions
*/
static fsp_err_t get_flash_status(void);
static void deinit_qspi(const spi_flash_protocol_t spi_protocol_mode);
static fsp_err_t qpi_mode_set(void);
void R_BSP_WarmStart(bsp_warm_start_event_t event);
extern bsp_leds_t g_bsp_leds;
/*******************************************************************************************************************//**
* [url=home.php?mod=space&uid=159083]@brief[/url] Blinky example application
*
* Blinks all leds at a rate of 1 second using the software delay function provided by the BSP.
*
**********************************************************************************************************************/
void hal_entry (void)
{
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
fsp_err_t err = FSP_SUCCESS;
uint8_t data_write[PAGE_WRITE_SIZE] = {RESET_VALUE,};
uint8_t verify_written_data[PAGE_WRITE_SIZE] = {RESET_VALUE,};
uint8_t data_sreg[SREG_SIZE] = STATUS_REG_PAYLOAD;
// fsp_pack_version_t version = {RESET_VALUE};
uint8_t *p_mem_addr = (uint8_t *)QSPI_DEVICE_START_ADDRESS;
/* Define the units to be used with the software delay function */
const bsp_delay_units_t bsp_delay_units = BSP_DELAY_UNITS_MILLISECONDS;
/* Set the blink frequency (must be <= bsp_delay_units */
const uint32_t freq_in_hz = 2;
/* Calculate the delay in terms of bsp_delay_units */
const uint32_t delay = bsp_delay_units / freq_in_hz;
/* LED type structure */
bsp_leds_t leds = g_bsp_leds;
/* If this board has no LEDs then trap here */
if (0 == leds.led_count)
{
while (1)
{
; // There are no LEDs on this board
}
}
err = R_SCI_UART_Open(&g_uart7_ctrl, &g_uart7_cfg);
if(FSP_SUCCESS != err) __BKPT();
/* Holds level to set for pins */
bsp_io_level_t pin_level = BSP_IO_LEVEL_LOW;
if (SPI_FLASH_PROTOCOL_QPI == g_qspi_cfg.spi_protocol)
{
/*
* this needs to be done since QPI is set by user in configuration
* and it sets QPI only in MCU but not in flash device
* so as a system (MCU + QSPI flash device) QPI mode does not get set by
* simply calling only R_QSPI_Open in QPI mode.
* Rather QPI mode enabling has to be done in Flash device as well
* So opening the driver in extended SPI mode only
* and QPI mode is enabled when qpi_mode_set sub-function is called
*/
spi_flash_cfg_t l_qspi_cfg;
memcpy((spi_flash_cfg_t *)&l_qspi_cfg, (spi_flash_cfg_t *)&g_qspi_cfg, sizeof (spi_flash_cfg_t));
l_qspi_cfg.spi_protocol = SPI_FLASH_PROTOCOL_EXTENDED_SPI;
APP_PRINT ("\r\n ** user selected QPI Mode in RA configuration tool ** \r\n");
/* open QSPI with local configuration */
err = R_QSPI_Open(&g_qspi_ctrl, &l_qspi_cfg);
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT("R_QSPI_Open Failed\r\n");
APP_ERR_TRAP(err);
}
}
else
{
APP_PRINT ("\r\n ** user selected extended SPI Mode in RA Configuration tool ** \r\n");
/* open QSPI in extended SPI mode */
err = R_QSPI_Open(&g_qspi_ctrl, &g_qspi_cfg);
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT("R_QSPI_Open Failed\r\n");
APP_ERR_TRAP(err);
}
}
/* write enable for further operations */
err = R_QSPI_DirectWrite(&g_qspi_ctrl, &(g_qspi_cfg.write_enable_command), ONE_BYTE, false);
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT("R_QSPI_DirectWrite Failed\r\n");
/* close QSPI module which is currently in extended SPI mode only */
deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);
APP_ERR_TRAP(err);
}
else
{
err = get_flash_status();
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT("Failed to get status for QSPI operation\r\n");
/* close QSPI module which is currently in extended SPI mode only */
deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);
APP_ERR_TRAP(err);
}
}
/*
* write QSPI flash status register
* This is required to make sure the device is ready for general
* read write operation,
* This performs settings such as physical reset,WP hardware pin disable,
* block protection lock bits clearing.
* for more details please refer Mx25L data sheet.
*/
err = R_QSPI_DirectWrite(&g_qspi_ctrl, data_sreg, SREG_SIZE, false);
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT("R_QSPI_DirectWrite Failed\r\n");
/* close QSPI module which is currently in extended SPI mode only */
deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);
APP_ERR_TRAP(err);
}
else
{
err = get_flash_status();
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT("Failed to get status for QSPI operation\r\n");
/* close QSPI module which is currently in extended SPI mode only */
deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);
APP_ERR_TRAP(err);
}
}
/*
* Verifying data written to QSPI flash status register
* Step 1: - send command byte - 0x05
* through R_QSPI_DirectWrite with last argument set as true
* Step 2 - read data through R_QSPI_DirectRead
*/
uint8_t sreg_data = RESET_VALUE;
err = R_QSPI_DirectWrite(&g_qspi_ctrl, &(g_qspi_cfg.status_command), ONE_BYTE, true);
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT("R_QSPI_DirectWrite Failed\r\n");
/* close QSPI module which is currently in extended SPI mode only */
deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);
APP_ERR_TRAP(err);
}
/*
* we should not call function get_flash_status here
* because the CS line should not get interrupted between write read
*
* Also MCU <SFMCD register> is set as 0 when status register is read
* to resume in ROM access mode hence API direct read returns error as part
* of parameter check itself
*/
err = R_QSPI_DirectRead(&g_qspi_ctrl, &sreg_data, ONE_BYTE);
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT("R_QSPI_DirectRead Failed\r\n");
/* close QSPI module which is currently in extended SPI mode only */
deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);
APP_ERR_TRAP(err);
}
else
{
/* check for status check operation here */
err = get_flash_status();
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT("Failed to get status for QSPI operation\r\n");
/* close QSPI module which is currently in extended SPI mode only */
deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);
APP_ERR_TRAP(err);
}
}
/* verify read status register data */
if (SET_SREG_VALUE != sreg_data)
{
APP_ERR_PRINT("Failed to get value set in the status register \r\n");
/* close QSPI module which is currently in extended SPI mode only */
deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);
APP_ERR_TRAP(err);
}
if (SPI_FLASH_PROTOCOL_QPI == g_qspi_cfg.spi_protocol)
{
/* set QPI mode in flash and MCU device */
err = qpi_mode_set();
if (FSP_SUCCESS!=err)
{
APP_ERR_PRINT ("qpi_mode_set failed\r\n");
/* close QSPI module which is currently in extended SPI mode only */
deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);
APP_ERR_TRAP(err);
}
}
/* Erase Flash for one sector */
err = R_QSPI_Erase(&g_qspi_ctrl, p_mem_addr, SECTOR_SIZE);
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT("R_QSPI_Erase Failed\r\n");
deinit_qspi(g_qspi_cfg.spi_protocol);
APP_ERR_TRAP(err);
}
else
{
err = get_flash_status();
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT("Failed to get status for QSPI operation\r\n");
deinit_qspi(g_qspi_cfg.spi_protocol);
APP_ERR_TRAP(err);
}
/* validating erase */
for (uint16_t mem_index = RESET_VALUE; mem_index < SECTOR_SIZE; mem_index++)
{
if (DEFAULT_MEM_VAL != p_mem_addr[mem_index])
{
APP_ERR_PRINT ("\r\n Verification for erase Failed \r\n");
deinit_qspi(g_qspi_cfg.spi_protocol);
APP_ERR_TRAP(err);
}
}
}
/* Fill the data write buffer further to be written in QSPI flash device */
for (uint16_t write_index = RESET_VALUE; write_index < PAGE_WRITE_SIZE ; write_index++)
{
data_write[write_index] = (uint8_t)write_index;
}
/* Write data to QSPI Flash */
err = R_QSPI_Write(&g_qspi_ctrl, data_write, (uint8_t *)QSPI_FLASH_ADDRESS(PAGE_FIRST), PAGE_WRITE_SIZE);
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT("R_QSPI_Write Failed\r\n");
deinit_qspi(g_qspi_cfg.spi_protocol);
APP_ERR_TRAP(err);
}
else
{
err = get_flash_status();
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT("Failed to get status for QSPI operation\r\n");
deinit_qspi(g_qspi_cfg.spi_protocol);
APP_ERR_TRAP(err);
}
}
/* Read data from QSPI memory region */
memcpy(verify_written_data, (uint8_t *)QSPI_FLASH_ADDRESS(PAGE_FIRST), PAGE_WRITE_SIZE);
/* Verify the written data */
if ( FSP_SUCCESS == (fsp_err_t)(memcmp(verify_written_data, data_write, PAGE_WRITE_SIZE)) )
{
APP_PRINT ("\r\n ** QSPI operation successful -> Data read matches with written data ** \r\n");
}
else
{
APP_ERR_PRINT ("\r\nQSPI operation Failed -> Data read does not match with written data\r\n");
}
/* close QSPI module */
deinit_qspi(g_qspi_cfg.spi_protocol);
while (1)
{
/* Enable access to the PFS registers. If using r_ioport module then register protection is automatically
* handled. This code uses BSP IO functions to show how it is used.
*/
R_BSP_PinAccessEnable();
/* Update all board LEDs */
for (uint32_t i = 0; i < leds.led_count; i++)
{
/* Get pin to toggle */
uint32_t pin = leds.p_leds[i];
/* Write to this pin */
R_BSP_PinWrite((bsp_io_port_pin_t) pin, pin_level);
}
/* Protect PFS registers */
R_BSP_PinAccessDisable();
/* Toggle level for next write */
if (BSP_IO_LEVEL_LOW == pin_level)
{
pin_level = BSP_IO_LEVEL_HIGH;
}
else
{
pin_level = BSP_IO_LEVEL_LOW;
}
/* Delay */
R_BSP_SoftwareDelay(delay, bsp_delay_units);
}
}
/*******************************************************************************************************************//**
* This function is called at various points during the startup process. This implementation uses the event that is
* called right before main() to set up the pins.
*
* @param[in] event Where at in the start up process the code is currently at
**********************************************************************************************************************/
void R_BSP_WarmStart (bsp_warm_start_event_t event)
{
if (BSP_WARM_START_RESET == event)
{
#if BSP_FEATURE_FLASH_LP_VERSION != 0
/* Enable reading from data flash. */
R_FACI_LP->DFLCTL = 1U;
/* Would normally have to wait tDSTOP(6us) for data flash recovery. Placing the enable here, before clock and
* C runtime initialization, should negate the need for a delay since the initialization will typically take more than 6us. */
#endif
}
if (BSP_WARM_START_POST_C == event)
{
/* C runtime environment and system clocks are setup. */
/* Configure pins. */
R_IOPORT_Open(&IOPORT_CFG_CTRL, &IOPORT_CFG_NAME);
}
}
/*******************************************************************************************************************//**
* @brief wait for QSPI flash device status register to get idle till operation is in progress
* @param[IN] None
* @retval FSP_SUCCESS or any other possible error codes
**********************************************************************************************************************/
static fsp_err_t get_flash_status(void)
{
spi_flash_status_t status = {.write_in_progress = true};
int32_t time_out = (INT32_MAX);
fsp_err_t err = FSP_SUCCESS;
do
{
/* Get status from QSPI flash device */
err = R_QSPI_StatusGet(&g_qspi_ctrl, &status);
if (FSP_SUCCESS!= err)
{
APP_ERR_PRINT("R_QSPI_StatusGet Failed\r\n");
return err;
}
/* Decrement time out to avoid infinite loop in case of consistent failure */
--time_out;
if ( RESET_VALUE >= time_out)
{
APP_PRINT("\r\n ** Timeout : No result from QSPI flash status register ** \r\n");
return FSP_ERR_TIMEOUT;
}
}while (false != status.write_in_progress);
return err;
}
/*******************************************************************************************************************//**
* @brief Close QSPI module
* @param[IN] spi_protocol mode
* @retval None
**********************************************************************************************************************/
static void deinit_qspi(const spi_flash_protocol_t spi_protocol_mode)
{
fsp_err_t error = FSP_SUCCESS;
/* if QPI is active mode then Exit QPI mode from flash device before QSPI close */
if (SPI_FLASH_PROTOCOL_QPI == spi_protocol_mode)
{
uint8_t data_exit_qpi = QSPI_MX25L_CMD_EXIT_QPI_MODE;
APP_PRINT ("\r\n ** Exit QPI mode before Closing QSPI module ** \r\n");
error = R_QSPI_DirectWrite(&g_qspi_ctrl, &data_exit_qpi, ONE_BYTE, false);
if (FSP_SUCCESS != error)
{
APP_ERR_PRINT("R_QSPI_DirectWrite Failed\r\n");
}
}
APP_PRINT ("\r\n ** Closing QSPI module ** \r\n");
/* close QSPI module */
error = R_QSPI_Close(&g_qspi_ctrl);
if (FSP_SUCCESS != error)
{
APP_ERR_PRINT("R_QSPI_Close Failed\r\n");
}
//APP_PRINT("\r\n\r\n *****############## demo ends here ########## *******\r\n\r\n");
}
/*******************************************************************************************************************//**
* @brief set QPI Mode in flash device and MCU
* @param[IN] none
* @retval FSP_SUCCESS or any other possible error codes
**********************************************************************************************************************/
static fsp_err_t qpi_mode_set(void)
{
fsp_err_t err = FSP_SUCCESS;
uint8_t data_qpi_en = QSPI_MX25L_CMD_ENTER_QPI_MODE;
//APP_PRINT ("\r\n ** setting QPI mode: sending QPI enabling command byte to flash ** \r\n");
/* write enable once again section 9-1 states that
* we should do it before sending 0x35 to flash device
*/
err = R_QSPI_DirectWrite(&g_qspi_ctrl, &(g_qspi_cfg.write_enable_command), ONE_BYTE, false);
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT("R_QSPI_DirectWrite Failed\r\n");
return err;
}
else
{
err = get_flash_status();
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT("Failed to get status for QSPI operation\r\n");
return err;
}
}
/* send QPI mode enable command in flash device
* Note - no status register read after this operation
* because flash device has gone in QPI mode
* and MCU at this point is in extended SPI mode only.
* vice versa same is applicable while exiting QPI mode too.
*/
err = R_QSPI_DirectWrite(&g_qspi_ctrl, &data_qpi_en, ONE_BYTE, false);
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT("R_QSPI_DirectWrite Failed\r\n");
return err;
}
APP_PRINT ("\r\n ** setting QPI mode: setting QPI mode in MCU ** \r\n");
/* Command byte transferred to flash-> NOW set the QPI protocol in MCU run time */
err = R_QSPI_SpiProtocolSet(&g_qspi_ctrl, SPI_FLASH_PROTOCOL_QPI);
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT("R_QSPI_SpiProtocolSet Failed\r\n");
}
return err;
}
参考代码加入其中。默认项目使用RTT输出log,本项目使用uart输出。需要在hal_entry当中打开uart
err = R_SCI_UART_Open(&g_uart7_ctrl, &g_uart7_cfg);
if(FSP_SUCCESS != err) __BKPT();
显示程序APP_PRINT,APP_ERR_PRINT,APP_ERR_TRAP三个函数在app_print.c实现。
#include "hal_data.h"
#include <stdio.h>
#include "app_print.h"
#include <stdarg.h>
#include <string.h>
/* Macro definition */
#define CARRIAGE_ASCII (13u) /* Carriage return */
#define ZERO_ASCII (48u) /* ASCII value of zero */
#define NINE_ASCII (57u) /* ASCII value for nine */
#define DATA_LENGTH (4u) /* Expected Input Data length */
#define UART_ERROR_EVENTS (UART_EVENT_BREAK_DETECT | UART_EVENT_ERR_OVERFLOW | UART_EVENT_ERR_FRAMING | \
UART_EVENT_ERR_PARITY) /* UART Error event bits mapped in registers */
#define RESET_VALUE (0x00)
/* Flag for user callback */
static volatile uint8_t g_uart_event = RESET_VALUE;
static uint8_t g_temp_buffer[DATA_LENGTH] = {RESET_VALUE};
/* Counter to update g_temp_buffer index */
static volatile uint8_t g_counter_var = RESET_VALUE;
/* Flag to check whether data is received or not */
static volatile uint8_t g_data_received_flag = false;
int v_uart( const char * sFormat, va_list * pParamList);
int APP_PRINT( const char * sFormat, ... )
{
va_list ParamList;
va_start(ParamList, sFormat);
v_uart(sFormat,&ParamList);
va_end(ParamList);
return 0;
}
int APP_ERR_PRINT( const char * sFormat, ... )
{
va_list ParamList;
va_start(ParamList, sFormat);
v_uart(sFormat,&ParamList);
va_end(ParamList);
return 0;
}
int APP_ERR_TRAP(int err)
{
char* errStr="Err No %d";
va_list ParamList;
v_uart(errStr,&ParamList);
va_end(ParamList);
return 0;
}
int v_uart( const char * sFormat, va_list * pParamList)
{
char send_buff[128]="";
strcpy(send_buff , sFormat);
size_t buff_len = strlen((char *)send_buff);
fsp_err_t err = FSP_SUCCESS;
uint32_t local_timeout = (DATA_LENGTH * UINT16_MAX);
err = R_SCI_UART_Write(&g_uart7_ctrl, send_buff, buff_len);
if(FSP_SUCCESS != err) __BKPT();
while ((UART_EVENT_TX_COMPLETE != g_uart_event) && (--local_timeout))
{
/* Check if any error event occurred */
if (UART_ERROR_EVENTS == g_uart_event)
{
break;
}
}
}
/*****************************************************************************************************************
* @brief UART user callback
* @param[in] p_args
* @retval None
****************************************************************************************************************/
void user_uart_callback(uart_callback_args_t *p_args)
{
/* Logged the event in global variable */
g_uart_event = (uint8_t)p_args->event;
/* Reset g_temp_buffer index if it exceeds than buffer size */
if(DATA_LENGTH == g_counter_var)
{
g_counter_var = RESET_VALUE;
}
if(UART_EVENT_RX_CHAR == p_args->event)
{
switch (p_args->data)
{
/* If Enter is pressed by user, set flag to process the data */
case CARRIAGE_ASCII:
{
g_counter_var = RESET_VALUE;
g_data_received_flag = true;
break;
}
/* Read all data provided by user until enter button is pressed */
default:
{
g_temp_buffer[g_counter_var++] = (uint8_t ) p_args->data;
break;
}
}
}
}
编写完成后,需要重新建立cmake configuer ,
如果不重新构建configure可能无法加入编译项目。
(4) 测试
编译项目测试。
通过调试,过程顺利完成。
Oflash的过程与Qflash的过程相似。
|