- 2025-01-12
-
加入了学习《【Follow me第二季第1期】全部任务演示》,观看 全部任务演示2.0
-
发表了主题帖:
【Follow me第二季第3期】任务总汇
本帖最后由 linyu0395 于 2025-1-20 22:28 编辑
开发板到手已经有一段时间了,瑞萨的这款EK-RA6M5虽然是首次尝试,但是入门和开发流程个人感觉比ST还快捷。开发环境我综合考虑了一下,相对于e2studio,还是通过RASC开发更方便,毕竟MDK也用的熟练。大家可以通过https://github.com/renesas进行下载。除了IDE安装文件,还有很多历程可以参考,特别是上手前期,通过丰富的例子可以加快对这块开发板的调试和使用。以下链接大家也可以参考。
FSP Webpage: www.renesas.com/ra/fsp
FSP GitHub: https://github.com/renesas/fsp
FSP Releases: https://github.com/renesas/fsp/releases
FSP Documentation: https://renesas.github.io/fsp
RA Product Information: www.renesas.com/ra
RA/FSP Knowledge Base: https://en-support.renesas.com/knowledgeBase/category/31087
Support: www.renesas.com/support
[localvideo]4cfa391f3856d0f81b244b97bb666c51[/localvideo]
任务软件流程图如下:
任务成果展示
入门任务:搭建环境,下载调试示例程序,Blink,按键
安装Renesas RA Smart Configurator 5.7.0后,打开界面如下:
选择了EK-RA6M5,里面包含了和开发板资源相关外设的IO、功能模块的初始化,接下来只要实例化就可以了。
本次任务需要实例化的外设,QSPI、OSPI、DAC等,通过下载的example里的实例就可以快速配置。
然后点击右上角的“Generate Project Content”生成MDK的项目工程
根据任务需求,我加入了qspi、ospi、dac_wave、rtt、按键、led的代码。
2、基础任务:quad-spi flash和octo-spi flash配置及读写速度测试;DAC配置生成波形及性能测试
QSPI的配置如下:
#include "qspi.h"
#include "hal_data.h"
#include "common_utils.h"
#include "qspi_ep.h"
/*******************************************************************************************************************//**
* @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_qspi0_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_qspi0_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_qspi0_cfg);
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_qspi0_ctrl, &(g_qspi0_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_qspi0_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_qspi0_ctrl, SPI_FLASH_PROTOCOL_QPI);
if(FSP_SUCCESS != err)
{
APP_ERR_PRINT("R_QSPI_SpiProtocolSet Failed\r\n");
}
return err;
}
void qspi_init(void)
{
fsp_err_t err;
uint8_t data_sreg[SREG_SIZE] = STATUS_REG_PAYLOAD;
if(SPI_FLASH_PROTOCOL_QPI == g_qspi0_cfg.spi_protocol)
{
spi_flash_cfg_t l_qspi_cfg;
memcpy((spi_flash_cfg_t *)&l_qspi_cfg, (spi_flash_cfg_t *)&g_qspi0_cfg, sizeof(spi_flash_cfg_t));
l_qspi_cfg.spi_protocol = SPI_FLASH_PROTOCOL_EXTENDED_SPI;
err = R_QSPI_Open(&g_qspi0_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_qspi0_ctrl, &g_qspi0_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_qspi0_ctrl, &(g_qspi0_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_qspi0_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_qspi0_ctrl, &(g_qspi0_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_qspi0_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_qspi0_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);
}
}
}
void qspi_erase_sector(uint32_t sector_index, uint32_t sector_nums)
{
uint8_t *p_mem_addr = (uint8_t *)QSPI_DEVICE_START_ADDRESS;
fsp_err_t err;
/* Erase Flash for one sector */
err = R_QSPI_Erase(&g_qspi0_ctrl, p_mem_addr + sector_index * SECTOR_SIZE, sector_nums * SECTOR_SIZE);
if(FSP_SUCCESS != err)
{
APP_ERR_PRINT("R_QSPI_Erase Failed\r\n");
deinit_qspi(g_qspi0_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_qspi0_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_qspi0_cfg.spi_protocol);
APP_ERR_TRAP(err);
}
}
}
}
void qspi_read(uint32_t addr, uint8_t *data, uint32_t size)
{
memcpy(data, (uint8_t *)QSPI_DEVICE_START_ADDRESS, size);
}
void qspi_write(uint32_t addr, uint8_t *data, uint32_t size)
{
uint32_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
/*mod 运算求余,若 writeAddr 是 SPI_FLASH_PageSize 整数倍,运算结果 Addr 值为
0*/
Addr = addr % PAGE_WRITE_SIZE;
/* 差 count 个数据值,刚好可以对齐到页地址 */
count = PAGE_WRITE_SIZE - Addr;
/* 计算出要写多少整数页 */
NumOfPage = size / PAGE_WRITE_SIZE;
/*mod 运算求余,计算出剩余不满一页的字节数 */
NumOfSingle = size % PAGE_WRITE_SIZE;
/* Addr=0, 则 WriteAddr 刚好按页对齐 aligned
*/
if(Addr == 0)
{
/* NumByteToWrite < SPI_FLASH_PageSize */
if(NumOfPage == 0)
{
R_QSPI_Write(&g_qspi0_ctrl, data, addr, size);
get_flash_status();
}
else /* NumByteToWrite > SPI_FLASH_PageSize */
{
/* 先把整数页都写了 */
while(NumOfPage--)
{
R_QSPI_Write(&g_qspi0_ctrl, data, addr, PAGE_WRITE_SIZE);
get_flash_status();
addr += PAGE_WRITE_SIZE;
data += PAGE_WRITE_SIZE;
}
/* 若有多余的不满一页的数据,把它写完 */
R_QSPI_Write(&g_qspi0_ctrl, data, addr, NumOfSingle);
get_flash_status();
}
}
/* 若地址与 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, data, addr, count);
get_flash_status();
addr += count;
data += count;
/* 再写剩余的数据 */
R_QSPI_Write(&g_qspi0_ctrl, data, addr, temp);
get_flash_status();
}
else /* 当前页剩余的 count 个位置能写完 NumOfSingle 个数据 */
{
R_QSPI_Write(&g_qspi0_ctrl, data, addr, size);
get_flash_status();
}
}
else /* NumByteToWrite > SPI_FLASH_PageSize */
{
/* 地址不对齐多出的 count 分开处理,不加入这个运算 */
size -= count;
NumOfPage = size / PAGE_WRITE_SIZE;
NumOfSingle = size % PAGE_WRITE_SIZE;
/* 先写完 count 个数据,为的是让下一次要写的地址对齐 */
R_QSPI_Write(&g_qspi0_ctrl, data, addr, count);
get_flash_status();
/* 接下来就重复地址对齐的情况 */
addr += count;
data += count;
/* 把整数页都写了 */
while(NumOfPage--)
{
R_QSPI_Write(&g_qspi0_ctrl, data, addr, PAGE_WRITE_SIZE);
get_flash_status();
addr += PAGE_WRITE_SIZE;
data += PAGE_WRITE_SIZE;
}
/* 若有多余的不满一页的数据,把它写完 */
if(NumOfSingle != 0)
{
R_QSPI_Write(&g_qspi0_ctrl, data, addr, NumOfSingle);
get_flash_status();
}
}
}
}
OSPI的配置如下:
#include "ospi_test.h"
#include "ospi_commands.h"
#include "ospi_ep.h"
#include "common_utils.h"
#include "dac_wave.h"
#include "qspi.h"
void reset_device()
{
/* OSPI Memory reset Pin */
R_IOPORT_PinWrite(&g_ioport_ctrl, RESET_PIN, BSP_IO_LEVEL_LOW);
R_BSP_SoftwareDelay(DELAY_TIME, BSP_DELAY_UNITS_MICROSECONDS);
R_IOPORT_PinWrite(&g_ioport_ctrl, RESET_PIN, BSP_IO_LEVEL_HIGH);
R_BSP_SoftwareDelay(DELAY_TIME, BSP_DELAY_UNITS_MICROSECONDS);
}
uint8_t write_data[4096] = { 0 };
uint8_t read_data[4096] = { 0 };
uint32_t qspi_tick;
uint32_t qspi_period_tick;
void ospi_test(void)
{
fsp_pack_version_t version = { RESET_VALUE };
fsp_err_t err = FSP_SUCCESS;
uint8_t read_data = RESET_VALUE;
uint32_t dev_id = RESET_VALUE;
bsp_octaclk_settings_t octaclk = { RESET_VALUE };
/* Reset device */
// reset_device();
/* Upon power-on or reset, the device defaults to SPI mode.
* To ensure proper operation, the OCTACLK clock should be configured to 100 MHz in SPI mode.
* Because OM_SCLK (OM_SCLK = OCTACLK/2) only support 50MHz as max.
*/
octaclk.source_clock = BSP_CFG_OCTA_SOURCE; /* 200MHz */
octaclk.divider = BSP_CLOCKS_OCTA_CLOCK_DIV_2;
R_BSP_OctaclkUpdate(&octaclk);
/* Initialize the OSPI driver module.*/
err = ospi_init();
if(FSP_SUCCESS != err)
{
APP_ERR_PRINT("\r\n** OSPI INIT FAILED **\r\n");
APP_ERR_TRAP(err);
}
/*Enable Write */
err = ospi_write_enable_and_verify(&g_ospi_ctrl, SPI_FLASH_PROTOCOL_EXTENDED_SPI);
if(FSP_SUCCESS != err)
{
/*handle error*/
handle_error(err, "\r\n** OSPI Write Enable and Verify failed **\r\n");
}
/* configure ospi in extended spi mode */
err = reconfigure_device();
if(FSP_SUCCESS != err)
{
/*handle error*/
handle_error(err, "\r\n** Reconfiguring OSPI device failed **\r\n");
}
/*Read the device id*/
err = read_device_id(&dev_id);
if(FSP_SUCCESS != err)
{
/*handle error*/
handle_error(err, "\r\n** Device_ID read operation failed **\r\n");
}
/* Reset the OCTACLK clock to 200 MHz, as specified by the default configuration.*/
octaclk.source_clock = BSP_CFG_OCTA_SOURCE; /* 200MHz */
octaclk.divider = BSP_CFG_OCTA_DIV;
R_BSP_OctaclkUpdate(&octaclk);
/*Print device id and main menu*/
APP_PRINT("\nDevice ID read successfully and Device id : 0x%X\r\n", dev_id);
APP_PRINT(OSPI_MENU);
while(true)
{
/* read user input */
read_data = process_input_data();
switch(read_data)
{
case QSPI_MODE:
qspi_tick = get_tick();
qspi_erase_sector(0, 1);
APP_PRINT("\nQSPI operation erase sector successfully\r\n");
qspi_write(0, write_data, sizeof(write_data));
APP_PRINT("\nQSPI operation write successfully\r\n");
qspi_read(0, read_data, sizeof(read_data));
APP_PRINT("\nQSPI operation read successfully\r\n");
qspi_period_tick = get_tick() - qspi_tick;
APP_PRINT("\nQSPI operation completed in %d ms\r\n", qspi_period_tick);
break;
case DAC_RECT_MODE:
generate_square_wave(buffer, BUFFER_SIZE, 500);
// generate_triangle_wave(buffer, BUFFER_SIZE, 100);
// generate_sine_wave(buffer, BUFFER_SIZE, 10);
break;
case DAC_SIN_MODE:
generate_sine_wave(buffer, BUFFER_SIZE, 10);
break;
/*Perform Extended SPI Operation*/
case SPI_MODE:
{
err = spi_operation();
/*handle error*/
handle_error(err, "\r\n** SPI Operation failed **\r\n");
break;
}
/*Perform SOPI operation*/
case SOPI_MODE:
{
err = opi_operation(SOPI_OPERATION_MODE);
/*handle error*/
handle_error(err, "\r\n** SOPI Operation failed **\r\n");
break;
}
/*Perform DOPI operation*/
case DOPI_MODE:
{
err = opi_operation(DOPI_OPERATION_MODE);
/*handle error*/
handle_error(err, "\r\n** DOPI Operation failed **\r\n");
break;
}
default:
{
APP_PRINT("\r\n Invalid input. Provide a valid input\r\n");
break;
}
}
/*reset data */
read_data = RESET_VALUE;
/* Print Main Menu option of OSPI operation.*/
APP_PRINT(OSPI_MENU);
}
}
DAC的配置如下:
DAC通过P014输出
按键、LED
#include "key.h"
uint8_t led_state;
void LED_ON() //LED1 亮
{
R_IOPORT_PinWrite(&g_ioport_ctrl, LED1_PIN, BSP_IO_LEVEL_HIGH);
}
uint32_t Key_Scan(bsp_io_port_pin_t key)
{
bsp_io_level_t state;
// 读取按键引脚电平
R_IOPORT_PinRead(&g_ioport_ctrl, key, &state);
if(BSP_IO_LEVEL_HIGH == state)
{
return KEY_OFF; //按键没有被按下
}
else
{
do
//等待按键释放
{
R_IOPORT_PinRead(&g_ioport_ctrl, key, &state);
}
while(BSP_IO_LEVEL_LOW == state);
}
return KEY_ON; //按键被按下了
}
void Key_Poll(void)
{
static uint8_t key_status[2];
if(Key_Scan(KEY1_PIN) == KEY_ON)
//扫描按键 1
{
if(key_status[0])
{
LED1_ON();
key_status[0] = 0;
}
else
{
LED1_OFF();
key_status[0] = 1;
}
}
if(Key_Scan(KEY2_PIN) == KEY_ON)
//扫描按键 2
{
if(key_status[1])
{
LED2_ON();
key_status[1] = 0;
}
else
{
LED2_OFF();
key_status[1] = 1;
}
}
}
#ifndef _KEY_H_
#define _KEY_H_
#include <stdint.h>
#include "hal_data.h"
/* 定义宏 KEY_ON 表示按键按下
定义宏 KEY_OFF 表示按键没有按下
*/
#define KEY_ON 1
#define KEY_OFF 0
#define KEY1_PIN BSP_IO_PORT_00_PIN_04
#define KEY2_PIN BSP_IO_PORT_00_PIN_05
#define LED1_PIN BSP_IO_PORT_00_PIN_07
#define LED2_PIN BSP_IO_PORT_00_PIN_08
#define LED1_ON() R_IOPORT_PinWrite(&g_ioport_ctrl, LED1_PIN, BSP_IO_LEVEL_HIGH)
#define LED1_OFF() R_IOPORT_PinWrite(&g_ioport_ctrl, LED1_PIN, BSP_IO_LEVEL_LOW)
// #define LED1_TOGGLE() R_IOPORT_PinWrite(&g_ioport_ctrl, LED1_PIN, !R_IOPORT_PinRead(&g_ioport_ctrl, LED1_PIN, &led_state))
#define LED2_ON() R_IOPORT_PinWrite(&g_ioport_ctrl, LED2_PIN, BSP_IO_LEVEL_HIGH)
#define LED2_OFF() R_IOPORT_PinWrite(&g_ioport_ctrl, LED2_PIN, BSP_IO_LEVEL_LOW)
// #define LED2_TOGGLE() R_IOPORT_PinWrite(&g_ioport_ctrl, LED2_PIN, !R_IOPORT_PinRead(&g_ioport_ctrl, LED2_PIN, &led_state))
extern uint8_t led_state;
uint32_t Key_Scan(bsp_io_port_pin_t key);
void Key_Poll(void);
#endif
3、进阶任务:示例程序中新增命令打印信息
4、扩展任务:设计一个类似信号发生器功能的例程。可在示例程序上修改。通过命令或按键,设置DAC输出波形,可通过flash存储历史波形等信息
此任务已经通过视频演示输出方波和正弦波。
#include "dac_wave.h"
#include "hal_data.h"
#include <math.h>
#include <stdint.h>
#include "r_dac.h"
uint8_t dac_init_flag = 0;
uint16_t buffer[BUFFER_SIZE];
uint32_t buffer_index;
void dac_output(uint16_t value);
void generate_square_wave(uint16_t *buf, uint32_t length, uint32_t frequency)
{
uint32_t period = (uint32_t)(SAMPLE_RATE / frequency);
for(uint32_t i = 0; i < length; i++)
{
buf[i] = (uint16_t)((i % period < period / 2) ? AMPLITUDE : 0);
}
}
void generate_triangle_wave(uint16_t *buf, uint32_t length, uint32_t frequency)
{
uint32_t period = (uint32_t)(SAMPLE_RATE / frequency);
for(uint32_t i = 0; i < length; i++)
{
uint32_t pos = i % period;
if(pos < period / 2)
{
buf[i] = (uint16_t)((2 * AMPLITUDE * pos) / (period / 2));
}
else
{
buf[i] = (uint16_t)(2 * AMPLITUDE - (2 * AMPLITUDE * (pos - period / 2)) / (period / 2));
}
}
}
void generate_sine_wave(uint16_t *buf, uint32_t length, uint32_t frequency)
{
float increment = 2 * PI * frequency / SAMPLE_RATE;
for(uint32_t i = 0; i < length; i++)
{
buf[i] = (uint16_t)(AMPLITUDE * (1 + sin(increment * i)) / 2);
}
}
// 定时器中断服务程序
void dac_timer_isr(void)
{
if(dac_init_flag)
{
/* Write value to DAC module */
R_DAC_Write(&g_dac_ctrl, buffer[buffer_index]);
/* handle error */
/* Start DAC conversion */
R_DAC_Start(&g_dac_ctrl);
/* handle error */
//dac_output(buffer[buffer_index]);
buffer_index = (buffer_index + 1) % BUFFER_SIZE;
}
}
void start_waveform_output(float frequency, void (*generate_wave)(uint16_t *, uint32_t, float))
{
generate_wave(buffer, BUFFER_SIZE, frequency);
buffer_index = 0;
// 启动定时器,配置定时器中断频率为 SAMPLE_RATE
//start_timer(SAMPLE_RATE);
}
//void start_timer(uint32_t sample_rate)
//{
// 配置并启动定时器,使其以 sample_rate 频率触发中断
// 具体实现取决于你的硬件平台
//}
void dav_wave_init(void)
{
fsp_err_t err = FSP_SUCCESS;
err = R_DAC_Open(&g_dac_ctrl, &g_dac_cfg);
// generate_square_wave(buffer, BUFFER_SIZE, 1000);
dac_init_flag = 1;
}
#ifndef _DAC_WAVE_H_
#define _DAC_WAVE_H_
#include <stdint.h>
#define PI 3.14159265
#define SAMPLE_RATE 1000
#define AMPLITUDE 2048
#define BUFFER_SIZE 1000
extern uint16_t buffer[BUFFER_SIZE];
extern uint32_t buffer_index;
void dac_timer_isr(void);
void dav_wave_init(void);
void generate_square_wave(uint16_t *buf, uint32_t length, uint32_t frequency);
void generate_triangle_wave(uint16_t *buf, uint32_t length, uint32_t frequency);
void generate_sine_wave(uint16_t *buf, uint32_t length, uint32_t frequency);
#endif
总结:瑞萨的EK-RA6M5的上手非常快,开发有大量丰富的历程参考,无论对于新手还是老手,都是非常适合的。资源丰富,带网络、LCD驱动、多路FDCAN等还需要细细研究。后续有更新的话再和大家一起分享,谢谢!
代码附件:
- 2024-12-15
-
发表了主题帖:
【Follow me第二季第3期】+ 瑞萨开发环境
本帖最后由 linyu0395 于 2024-12-16 00:02 编辑
首先有幸得到瑞萨的RA6M5开发板并进行测试。
开发环境的下载、安装,大家可以通过官网直接下载,安装后如图
这里不得不夸一下瑞萨的开发环境,我从入手到熟悉,基本上就花了不到一个小时。我个人觉得瑞萨的开发环境比ST的还优秀,包括各种硬件模块、功能模块的可视化配置以及丰富的代码集成,非常适合新手入门。一旦熟悉了,就能快速地搭建测试环境和代码编写,摒弃各种繁杂的底层驱动的测试,这应该是广大工程师梦寐以求的便捷式开发模式吧。
这里也推荐一下[野火]瑞萨RA系列FSP库开发实战指南——基于野火启明开发板 — [野火]瑞萨RA系列FSP库开发实战指南——基于野火启明开发板 文档这个网站,里面也提供了瑞萨RA系列的开发教程,非常适合入门的工程师们参考!
renesas/ra-fsp-examples: Example projects for Renesas RA MCU family 这是github的内容,里面可以下载最新的官方example,我也是借助这些教程和参考快速进行开发板功能的验证。
好了,长话短说。测试过程中我首先测试了RA6M5的QSPI模块的功能。
以下是每个 SPI 闪存协议模式的区别:
SPI_FLASH_PROTOCOL_EXTENDED_SPI (0x000):
标准的 SPI 模式,命令、地址和数据通过单条线(MOSI)传输。
SPI_FLASH_PROTOCOL_QPI (0x002):
QPI(四线接口)模式使用四条线传输命令、地址和数据。相比标准 SPI 模式,QPI 模式每个时钟周期传输四位数据,从而提高数据吞吐量。
SPI_FLASH_PROTOCOL_SOPI (0x003):
SOPI(串行八线接口)模式使用八条线传输命令和数据。此模式需要设备设置为 SOPI 模式,并且可以显著提高数据传输速率。
SPI_FLASH_PROTOCOL_DOPI (0x004):
DOPI(双八线接口)模式也使用八条线,但它在双数据速率(DDR)模式下运行,即在时钟的上升沿和下降沿都传输数据,相比 SOPI 模式,数据速率加倍。
SPI_FLASH_PROTOCOL_1S_1S_1S (0x000):
使用一条线传输命令、地址和数据的协议,与标准 SPI 模式类似。
SPI_FLASH_PROTOCOL_4S_4D_4D (0x3B2):
使用四条线传输命令,并以双数据速率传输地址和数据。
SPI_FLASH_PROTOCOL_8D_8D_8D (0x3FF):
使用八条线以双数据速率传输命令、地址和数据。
SPI_FLASH_PROTOCOL_1S_2S_2S (0x048):
使用一条线传输命令,使用两条线传输地址和数据。
SPI_FLASH_PROTOCOL_2S_2S_2S (0x049):
使用两条线传输命令、地址和数据。
SPI_FLASH_PROTOCOL_1S_4S_4S (0x090):
使用一条线传输命令,使用四条线传输地址和数据
SPI_FLASH_PROTOCOL_4S_4S_4S (0x092):
使用四条线传输命令、地址和数据
这些协议模式的选择通常取决于设备的支持和所需的数据传输速率
QSPI和OPI的代码我参考了github上下载的
我用了SEGGER_RTT进行数据打印,过程中加入了速度测试。这里提一下,
用Auto 无法输出打印的数据,这个时候可以根据编译生成的map文件定位到 .bss._SEGGER_RTT 就可以看到RTT的内存地址
RTT选择 Adress ,然后填入就OK了。
回到瑞萨的IDE,正如开始所说,配置非常的人性化,熟悉后,基本通过菜单和功能选择就能生成一个完整的代码框架,里面包含了底层的驱动和部分应用。
熟悉代码框架后,我加入了Systick的初始化配置、OSPI、QSPI的初始化以及进行读写的测速代码,具体内容我会附上代码供大家参考
这次调试的时间比较仓促,板子寄到了老家,而且最近一直在疯狂加班,板子今天才拿回来开始测试,花了半天的时间熟悉了代码并尝试测试了一下,有点捉紧。希望后续能抽时间继续完善其他外设包括液晶、can、网络等。最后不得不说瑞萨的开发环境做的做不错,我第一次入门就花了半天时间就基本熟悉IDE和功能配置等,除了e2studio,还支持MDK,非常棒!希望瑞萨能加强国内的推荐力度!
-
加入了学习《Follow me第二季第3期演示视频》,观看 Follow me第二季第3期演示视频
- 2024-03-16
-
加入了学习《BQ76952 & BQ76942, 3-16S & 3-10S 电池监控器系列讲座 (2)》,观看 2.2 bq76942/bq76952 器件概述