- 2024-12-09
-
回复了主题帖:
【Follow me第二季第3期】扩展任务---EK_RA6M5函数信号发生器
御坂10032号 发表于 2024-12-7 21:57
我想看一下这个保存历史波形到Flash里的相关代码,但是似乎你这个工程文件中并没有这一部分, 而你这个帖子 ...
你参考这篇帖子https://bbs.eeworld.com.cn/thread-1299584-1-1.html
可以进行SPI Flash外设初始化和数据写入与读取。完成SPI Flash驱动后就可以将波形数据存入Flash保存下来
- 2024-12-04
-
加入了学习《【Follow me第二季第3期】扩展任务---EK_RA6M5函数信号发生器》,观看 【Follow me第二季第3期】扩展任务---EK_RA6M5函数信号发生器
- 2024-12-02
-
回复了主题帖:
【Follow me第二季第3期】扩展任务---EK_RA6M5函数信号发生器
quansirx 发表于 2024-11-30 21:29
可以,源程序后面会上传 后续更新下文件链接
工程链接:https://download.eeworld.com.cn/detail/quansirx/635164
- 2024-11-30
-
回复了主题帖:
【Follow me第二季第3期】扩展任务---EK_RA6M5函数信号发生器
beyond_笑谈 发表于 2024-11-30 17:37
请问有没有这个任务完整的工程代码?或者细一点的分享,这个任务的功能试了几次搞不定,谢谢
文件资源正在审核
-
上传了资料:
【Follow me第二季第3期】扩展任务 源代码工程
-
回复了主题帖:
【Follow me第二季第3期】扩展任务---EK_RA6M5函数信号发生器
beyond_笑谈 发表于 2024-11-30 17:37
请问有没有这个任务完整的工程代码?或者细一点的分享,这个任务的功能试了几次搞不定,谢谢
可以,源程序后面会上传 后续更新下文件链接
-
回复了主题帖:
【Follow me第二季第3期】扩展任务---EK_RA6M5函数信号发生器
wangerxian 发表于 2024-11-30 16:22
8KHz频率这么高吗?输出个方波看看频率
可以的 但是DAC转换点数需要适当减少
- 2024-11-29
-
回复了主题帖:
【Follow me第二季第3期】任务汇总
beyond_笑谈 发表于 2024-11-29 16:16
第五个任务能打开,而且楼主速度挺快的,这就已经做好了。
勉强做好
-
回复了主题帖:
【Follow me第二季第3期】任务汇总
Jacktang 发表于 2024-11-29 07:31
第五个任务链接打不开吧
我看下,可能是帖子还没通过审核
-
回复了主题帖:
【Follow me第二季第3期】扩展任务---EK_RA6M5函数信号发生器
qwqwqw2088 发表于 2024-11-29 11:17
做的这个函数发生器的频率能做到大概在多少范围
没有使用DMA,目前是8KHz左右
- 2024-11-28
-
发表了主题帖:
【Follow me第二季第3期】任务汇总
一、EK-RA6M5开箱帖
【Follow me第二季第3期】EK-RA6M5开箱帖 - DigiKey得捷技术专区 - 电子工程世界-论坛
二、入门任务---调试程序、Blink及按键测试
【Follow me第二季第3期】入门任务---调试程序、Blink及按键测试 - DigiKey得捷技术专区 - 电子工程世界-论坛
三、基础任务---QSPI、OSPI Flash及DAC测试
【Follow me第二季第3期】基础任务---QSPI、OSPI Flash及DAC测试 - DigiKey得捷技术专区 - 电子工程世界-论坛
四、进阶任务---示例程序新增命令打印信息
【Follow me第二季第3期】进阶任务---示例程序新增命令打印信息 - DigiKey得捷技术专区 - 电子工程世界-论坛
五、扩展任务---EK_RA6M5函数信号发生器
【Follow me第二季第3期】扩展任务---EK_RA6M5函数信号发生器 - DigiKey得捷技术专区 - 电子工程世界-论坛
-
发表了主题帖:
【Follow me第二季第3期】扩展任务---EK_RA6M5函数信号发生器
本帖最后由 quansirx 于 2024-11-28 21:17 编辑
一、任务介绍
该项目使用EK_RA6M5评估板完成一简易函数信号发生器的制作,涉及EK_RA6M5主控芯片的片内资源有定时器GPT,数模转换器DAC;片外QSPI Flash用于存储历史DAC波形数据
DAC最大模拟输出电压为3.3V,最小输出电压为0V,如果使用外部电压偏置电路可以实现更大电压或负压输出。
二、原理说明
函数信号发生器最基本的功能是生成一定幅度、频率(周期)、波形类型的信号,那么如何通过MCU主控来控制波形的类型、幅度以及频率?这个思路是比较简单的,只需使用到定时器与DAC这两个外设就能够实现以上功能。对于一个12位的DAC,能转换的离散电压范围为2^12=4096档,这4096个电压档位将DAC的输出电压范围3.3V均分为4096份。
2.1、幅度调节
因此波形的幅度大小通过控制DAC的输出档位来实现,将DAC_Array波形查找表内数据归一化,设幅度调节因子为A,A∈[0,1]。因此DAC最终输出的电压等于
DAC_Arrat*4095*A
2.2、频率调节
使用定时器实现,设定时器溢出频率为F,设DAC在一个信号周期的采样点数为N,于是DAC输出信号频率
f=F/N;
2.3、波形类型
将不同信号的波形数据存储到片内Flash,通过设置标记变量的方式来输出不同类型的波形
2.4 软件流程图
三、程序设计
3.1 定时器外设设置
在FSP工具内新增定时器外设,用于定时触发DAC进行转换
3.2 DAC外设设置
FSP内新增DAC外设
3.3
波形设置代码
//add***
#include "bsp_adc.h"
#include "math.h"
#define M_PI 3.14159265358979323846
#define ND 128
float frac=0.8;
volatile float dac_array[ND];
volatile uint16_t dac_value;
volatile uint8_t wave_type=0;
static uint32_t n1=0;
static uint32_t n2=0;
static uint32_t n3=0;
//add***
//add2***
#define ND2 12800
volatile float history_dac_array[ND2];
volatile uint8_t show_history_wave=0;
//add2***
void init_dac_array(uint8_t cmd);
void init_dac_array(uint8_t cmd){
switch(cmd){
case 1://锯齿波
for(uint16_t i=0;i<ND;i++){
dac_array[i]=(float)1.0*i/(ND-1);
}
break;
case 2://正弦波
double w=0.0;
for(uint16_t i=0;i<ND;i++){
dac_array[i]=(float)(sin(w)+1)/2;
w+=(2*M_PI/(ND-1));
}
break;
case 3://方波
for(uint16_t i=0;i<ND;i++){
if(i<ND/2){
dac_array[i]=1.0;
}
else{
dac_array[i]=0;
}
}
break;
case 4://历史波形删除方波
n3=0;
n2=0;
// for(uint32_t i=0;i<ND2;i++){
// history_dac_array[i]=0;
// }
break;
}
}
DAC定时输出设置、信号幅度测试
//add***
void g_timer0_callback(timer_callback_args_t * p_args)
{
FSP_PARAMETER_NOT_USED(p_args);
if(show_history_wave==0){
dac_value=(uint16_t)(frac*4095*dac_array[n1++]);
R_DAC_Write(&g_dac0_ctrl,dac_value);
//add2**
history_dac_array[n2++]=dac_array[n1-1];
QSPI_Flash_BufferWrite(history_dac_array, FLASH_WriteAddress, ND2);//存储历史DAC波形
//add2**
if(n1==ND)
n1=0;
if(n2==ND2)
n2=0;
}
else{
QSPI_Flash_BufferRead(history_dac_array2, FLASH_WriteAddress, ND2);//读取历史DAC波形
dac_value=(uint16_t)(frac*4095*history_dac_array2[n3++]);
R_DAC_Write(&g_dac0_ctrl,dac_value);
if(n3==n2)
n3=0;
}
}
四、实验结果
我这里通过在调试状态更改标记变量的方式,更改DAC输出波形类型,信号幅度、频率,默认DAC历史波形存储深度为12800,超过存储深度后历史波形数据将被新的波形数据覆盖
另外提供了清除历史存储波形的选项。使用e2 studio内置real-time chart来观察DAC信号波形
4.1 GIF演示
4.2 视频演示
- 2024-11-24
-
加入了学习《Follow me第二季第4期 任务完成视频》,观看 【Follow me第二季第4期】最终视频
- 2024-11-19
-
发表了主题帖:
【Follow me第二季第3期】进阶任务---示例程序新增命令打印信息
本帖最后由 quansirx 于 2024-11-19 23:01 编辑
一、任务说明
使用EK_RA6M5的示例程序,新增一个菜单命令行,新增命令用于打印开发板信息或其他程序处理。
E2 studio打开quickstart_ek_ra6m5_ep工程
在main.c处找到关于menu的线程创建
打开menu线程的声明,是在menu_thread.c文件内
进行往下查找
menu_main.c文件
命令菜单列表定义在变量s_menu_items内
在s_menu_items数组新增命令“Show kit Information”
并打开kis_display_menu函数定义处
kis_display_menu函数定义
show_display_menu函数内容与kis_display_menu一致
新添加的菜单命令函数未做声明,找到kis_display_menu函数声明所在文件,添加
show_display_menu的外部声明
extern test_fn show_display_menu(void);
编译无误后开始调试目标板
二、实验结果
打开串口终端工具
菜单列表出现了新增的命令序列
按下数字键2,新增命令执行正常
-
发表了主题帖:
【Follow me第二季第3期】基础任务---QSPI、OSPI Flash及DAC测试
本帖最后由 quansirx 于 2024-11-19 23:00 编辑
一、QSPI Flash配置
1.1
使用e2 studio新建MCU自定义工程,MCU型号为R7FA6M5BH3CFC
打开开发板原理图文件,找到QSPI Flash的原理图
在FSP配置界面找到Pins栏,引脚配置与原理图一致,注意引脚组选项为_B only
操作模式为Quad
在stacks栏新增qspi flash
Qspi flash stack属性设置保持默认
FSP设置完成后点击右上角的Generate Project Content
1.2
在工程目录src下新建bsp文件夹,并新建qspi的两个c/h驱动文件
bsp_qspi_flash.h头文件内容如下
#ifndef QSPI_FLASH_BSP_QSPI_FLASH_H_
#define QSPI_FLASH_BSP_QSPI_FLASH_H_
#include "hal_data.h"
#include "r_qspi.h"
#define FLASH_ID_W25Q32JV 0xEF4016 // W25Q32JV
#define FLASH_ID_AT25SF321B 0x1F8701 // AT25SF321B
#define SPI_FLASH_PageSize 256
#define SPI_FLASH_PerWritePageSize 256
#define RESET_VALUE (0x00)
/*命令定义-开头*******************************/
#define WriteEnable 0x06
#define WriteDisable 0x04
#define ReadStatusReg 0x05
#define WriteStatusReg 0x01
#define ReadData 0x03
#define FastReadData 0x0B
#define FastReadDual 0x3B
#define PageProgram 0x02
#define BlockErase 0xD8
#define SectorErase 0x20
#define ChipErase 0xC7
#define PowerDown 0xB9
#define ReleasePowerDown 0xAB
#define DeviceID 0xAB
#define ManufactDeviceID 0x90
#define JedecDeviceID 0x9F
/* WIP(busy)标志,FLASH内部正在写入 */
#define WIP_Flag 0x01
#define Dummy_Byte 0xFF
/*命令定义-结尾*******************************/
void QSPI_Flash_Init(void);
uint32_t QSPI_Flash_ReadID(void);
uint32_t QSPI_Flash_ReadDeviceID(void);
void QSPI_Flash_PowerDown(void);
void QSPI_Flash_WakeUp(void);
void QSPI_Flash_WriteEnable(void);
fsp_err_t QSPI_Flash_WaitForWriteEnd(void);
void QSPI_Flash_SectorErase(uint32_t adress);
void QSPI_Flash_PageWrite(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite); //页写入
void QSPI_Flash_BufferWrite(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
void QSPI_Flash_BufferRead(uint8_t *pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead);
//static void qspi_d0_byte_write_standard (uint8_t 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);
#endif /* QSPI_FLASH_BSP_QSPI_FLASH_H_ */
bsp_qspi_flash.c文件内容如下
#include "bsp_qspi_flash.h"
void QSPI_Flash_Init(void)
{
R_QSPI_Open(&g_qspi0_flash_ctrl, &g_qspi0_flash_cfg);
R_BSP_SoftwareDelay(10u, BSP_DELAY_UNITS_MILLISECONDS);
}
/**
* @brief 读取FLASH ID
* @param 无
* @retval FLASH ID
*/
uint32_t QSPI_Flash_ReadID(void)
{
unsigned char data[6] = {};
uint32_t back;
data[0] = JedecDeviceID;
R_QSPI_DirectWrite(&g_qspi0_flash_ctrl, &data[0], 1, true); //false: close the spi true: go go go
R_QSPI_DirectRead(&g_qspi0_flash_ctrl, &data[0], 3);
/*把数据组合起来,作为函数的返回值*/
back = (data[0] << 16) | (data[1] << 8) | (data[2]);
return back;
}
/**
* @brief 读取FLASH 设备ID
* @param 无
* @retval FLASH ID
*/
uint32_t QSPI_Flash_ReadDeviceID(void)
{
unsigned char data[6] = {};
uint32_t back;
data[0] = DeviceID;
data[1] = 0xff;
data[2] = 0xff;
data[3] = 0xff;
R_QSPI_DirectWrite(&g_qspi0_flash_ctrl, &data[0], 4, true); //false: close the spi true: go go go
R_QSPI_DirectRead(&g_qspi0_flash_ctrl, &data[0], 3);
/*把数据组合起来,作为函数的返回值*/
back = (data[0] << 16) | (data[1] << 8) | (data[2]);
return back;
}
/**
* @brief 等待WIP(BUSY)标志被置0,即等待FLASH内部数据写入完毕
* @param 无
*/
fsp_err_t QSPI_Flash_WaitForWriteEnd(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_flash_ctrl, &status);
if (FSP_SUCCESS != err)
{
//printf("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)
{
//printf("\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 擦除FLASH扇区
* @param SectorAddr:要擦除的扇区地址
* @retval 无
*/
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_flash_ctrl, &data[1], 4, false);
QSPI_Flash_WaitForWriteEnd();
}
/**
* @brief 对FLASH写入数据,调用本函数写入数据前需要先擦除扇区
* @param pBuffer,要写入数据的指针
* @param WriteAddr,写入地址
* @param NumByteToWrite,写入数据长度
* @retval 无
*/
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_flash_ctrl, pBuffer, WriteAddr, NumByteToWrite);
QSPI_Flash_WaitForWriteEnd();
}
else /* NumByteToWrite > SPI_FLASH_PageSize */
{
/*先把整数页都写了*/
while (NumOfPage--)
{
R_QSPI_Write(&g_qspi0_flash_ctrl, pBuffer, WriteAddr, SPI_FLASH_PageSize);
QSPI_Flash_WaitForWriteEnd();
WriteAddr += SPI_FLASH_PageSize;
pBuffer += SPI_FLASH_PageSize;
}
/*若有多余的不满一页的数据,把它写完*/
R_QSPI_Write(&g_qspi0_flash_ctrl, pBuffer, 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_flash_ctrl, pBuffer, WriteAddr, count);
QSPI_Flash_WaitForWriteEnd();
WriteAddr += count;
pBuffer += count;
/*再写剩余的数据*/
R_QSPI_Write(&g_qspi0_flash_ctrl, pBuffer, WriteAddr, temp);
QSPI_Flash_WaitForWriteEnd();
}
else /*当前页剩余的count个位置能写完NumOfSingle个数据*/
{
R_QSPI_Write(&g_qspi0_flash_ctrl, pBuffer, 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_flash_ctrl, pBuffer, WriteAddr, count);
QSPI_Flash_WaitForWriteEnd();
/* 接下来就重复地址对齐的情况 */
WriteAddr += count;
pBuffer += count;
/*把整数页都写了*/
while (NumOfPage--)
{
R_QSPI_Write(&g_qspi0_flash_ctrl, pBuffer, WriteAddr, SPI_FLASH_PageSize);
QSPI_Flash_WaitForWriteEnd();
WriteAddr += SPI_FLASH_PageSize;
pBuffer += SPI_FLASH_PageSize;
}
/*若有多余的不满一页的数据,把它写完*/
if (NumOfSingle != 0)
{
R_QSPI_Write(&g_qspi0_flash_ctrl, pBuffer, WriteAddr, NumOfSingle);
QSPI_Flash_WaitForWriteEnd();
}
}
}
}
/**
* @brief 读取FLASH数据,减少ctrl这个标志
* @param pBuffer,存储读出数据的指针
* @param ReadAddr,读取地址
* @param NumByteToRead,读取数据长度
* @retval 无
*/
void QSPI_Flash_BufferRead(uint8_t *pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
R_QSPI_Read(&g_qspi0_flash_ctrl, pBuffer, ReadAddr, NumByteToRead);
}
/**
* @brief 读取flash数据
* @param p_ctrl
* @param p_src 需要传回的数据
* @param p_dest 数据地址
* @param byte_count 数据长度
*/
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;
}
1.3 hal_entry.c代码编写
hal_entry.c添加内容
//add***
uint32_t flag=0;
uint32_t id;
uint32_t id1;
#define FLASH_WriteAddress 0x00000
#define FLASH_ReadAddress FLASH_WriteAddress
#define FLASH_SectorToErase FLASH_WriteAddress
/* 发送缓冲区初始化 */
uint8_t Tx_Buffer[] = "Hello Digikey&EEWorld!\n";
uint8_t Rx_Buffer[sizeof(Tx_Buffer)];
int Buffercmp(uint8_t *pBuffer1, uint8_t *pBuffer2, uint16_t BufferLength)
{
while (BufferLength--)
{
if (*pBuffer1 != *pBuffer2)
{
return 1;
}
pBuffer1++;
pBuffer2++;
}
return 0;
}
//add***
hal_entry函数添加如下内容
//add***
/*******************************************************************************************************************//**
* main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used. This function
* is called by main() when no RTOS is used.
**********************************************************************************************************************/
void hal_entry(void)
{
/* TODO: add your own code here */
//add***
// uint32_t FlashID = 0;
// uint32_t FlashDeviceID = 0;
QSPI_Flash_Init(); // 串行FLASH初始化
// FlashID = QSPI_Flash_ReadID();
// FlashDeviceID = QSPI_Flash_ReadDeviceID();
QSPI_Flash_SectorErase(FLASH_SectorToErase);
/* 将发送缓冲区的数据写到flash中 */
// 这里写一页,一页的大小为256个字节
QSPI_Flash_BufferWrite(Tx_Buffer, FLASH_WriteAddress, sizeof(Tx_Buffer));
//printf("写入的数据为:%s \r\n", Tx_Buffer);
/* 将刚刚写入的数据读出来放到接收缓冲区中 */
QSPI_Flash_BufferRead(Rx_Buffer, FLASH_ReadAddress, sizeof(Tx_Buffer));
//printf("读出的数据为:%s \r\n", Rx_Buffer);
if (Buffercmp(Tx_Buffer, Rx_Buffer, sizeof(Tx_Buffer)) == 0)
{
flag=1;
//printf("\r\n32Mbit串行Flash测试成功!\r\n");
//LED3_ON;
}
else
{
flag=0;
//printf("\r\n32Mbit串行Flash测试失败!\r\n");
//LED1_ON;
}
//add***
编译工程后进入调试模式
打开Jlink RTT查看日志输出
这里往QSPI Flash的起始地址写入一行字符串,并读出该地址的字符数据,如果写入的数据与读出的数据一致,说明QSPI Flash读写测试成功
二、OSPI配置
2.1
使用e2 studio新建MCU自定义工程
打开开发板原理图文件,找到OSPI Flash的原理图
在FSP配置界面找到Pins栏,引脚配置与原理图一致,注意引脚组选项为Mixed
操作模式为Custom
在stacks栏新增ospi flash
ospi flash stack属性设置保持默认,由于OPSI外设使用独立的OCTASPICLK时钟信号,需要在Clocks配置OSPI的时钟信号,时钟树配置如下
2.2
在工程目录src下新建bsp文件夹,并新建ospi的两个c/h驱动文件
bsp_ospi_flash.h头文件内容如下
bsp_ospi_flash.h头文件内容如下
/*
* bsp_ospi_flash.h
*
* Created on: 2024年11月17日
* Author: quansirx
*/
#ifndef OSPI_FLASH_BSP_OSPI_FLASH_H_
#define OSPI_FLASH_BSP_OSPI_FLASH_H_
#include "hal_data.h"
#include "r_ospi.h"
#define RESET_VALUE (0x00)
void QSPI_Flash_Init(void);
fsp_err_t ospi_init(void);
#endif /* OSPI_FLASH_BSP_OSPI_FLASH_H_ */
bsp_ospi_flash.c文件内容如下
/*
* bsp_ospi_flash.c
*
* Created on: 2024年11月17日
* Author: quansirx
*/
#include "bsp_ospi_flash.h"
void QSPI_Flash_Init(void){
// bsp_octaclk_settings_t octaclk = {RESET_VALUE};
// octaclk.source_clock = BSP_CFG_OCTA_SOURCE; /* 200MHz */
// octaclk.divider = BSP_CLOCKS_OCTA_CLOCK_DIV_2;
// R_BSP_OctaclkUpdate(&octaclk);//更新OSI 时钟频率
//
// fsp_err_t err = FSP_SUCCESS;
// err = ospi_init();
R_OSPI_Open(&g_ospi_ctrl, &g_ospi_cfg);
}
spi_flash_cfg_t g_loc_ospi_cfg;
ospi_extended_cfg_t g_loc_ospi_extnd_cfg;
#define DEVICE_SECTOR_SIZE (4096U)
#define DEVICE_BLOCK_SIZE (65536U)
#define INITIAL_INDEX (0U)
#define OSPI_OPI_CMD_ERASE_SECTOR (0x21DEU)
#define OSPI_OPI_CMD_ERASE_BLOCK (0xDC23U)
#define OSPI_OPI_CMD_ERASE_CHIP (0xC738U)
static const spi_flash_erase_command_t opi_erase_command_list[] =
{
{ .command = OSPI_OPI_CMD_ERASE_SECTOR, .size = DEVICE_SECTOR_SIZE },
{ .command = OSPI_OPI_CMD_ERASE_BLOCK, .size = DEVICE_BLOCK_SIZE },
{ .command = OSPI_OPI_CMD_ERASE_CHIP, .size = SPI_FLASH_ERASE_SIZE_CHIP_ERASE },
};
fsp_err_t ospi_init(void)
{
fsp_err_t err = FSP_SUCCESS;
/*Configuration setup of Extended SPI configuration into local config*/
ospi_extended_cfg_t* textd = NULL;
textd = (void *)g_ospi_cfg.p_extend;
g_loc_ospi_extnd_cfg = *textd;
g_loc_ospi_cfg = g_ospi_cfg;
g_loc_ospi_cfg.p_erase_command_list = &opi_erase_command_list[INITIAL_INDEX];
g_loc_ospi_cfg.p_extend = &g_loc_ospi_extnd_cfg;
/* In the current OSPI device model, the default status of the device is set to SPI mode.
* Therefore, it is necessary to initialize the OSPI driver module in SPI mode
* to ensure compatibility with the device's default SPI protocol.
*/
g_loc_ospi_cfg.spi_protocol = SPI_FLASH_PROTOCOL_EXTENDED_SPI;
/*Open Octa Flash device in Extended SPI Mode */
err = R_OSPI_Open(&g_ospi_ctrl, &g_loc_ospi_cfg);
if (FSP_SUCCESS != err)
{
//APP_ERR_PRINT ("\r\n** R_OSPI_Open API FAILED **\r\n");
}
return err;
}
三、DAC波形测试
以快速向导工程为模版,驱动DAC产生正弦波波形
3.1
打开quickstart_ek_ra6m5_ep工程下FSP配置文件
在stack栏新增DAC外设
pins栏配置DAC输出引脚为P014
DAC波形产生需要使用定时器,这里使用示例工程中g_gpt_blue这一定时器
g_gpt_blue定时器已经使能定时器溢出中断,中断回调函数为gpt_blue_callback
使用全局搜索gpt_blue_callback,找到gpt_blue_callback的函数定义
gpt_blue_callback定义在common_init.c文件
在gpt_blue_callback添加以下内容
#include "math.h"
#define M_PI 3.141592
/**********************************************************************************************************************
* Function Name: gpt_blue_callback
* Description : Callback function for driver g_gpt_blue.
* Argument : p_args
* Return Value : .
*********************************************************************************************************************/
void gpt_blue_callback(timer_callback_args_t * p_args)
{
/* Void the unused params */
uint16_t dacvalue=0;
static double w=0.0;
w+=M_PI/90;
if(w>=2*M_PI){
w=0.0;
}
dacvalue=4095*(cos(w)+1)/2;
R_DAC_Write(&g_dac0_ctrl, dacvalue);
FSP_PARAMETER_NOT_USED(p_args);
switch (s_blueled_flashing)
{
case ON:
{
if ((s_intense++ ) < s_duty)
{
TURN_BLUE_ON
}
else
{
TURN_BLUE_OFF
}
if (s_intense >= 100)
{
s_intense = 0;
s_duty = g_pwm_dcs[g_board_status.led_intensity];
}
break;
}
default:
{
TURN_BLUE_OFF
s_intense = 0;
s_duty = g_pwm_dcs[g_board_status.led_intensity];
}
}
}
进行程序调试
我这里没有示波器观察DAC波形,使用e2 studio内置的real-time chart观察dacvalue的变化情况
因为real-time chart的刷新速率慢,所以波形会有些失真
- 2024-11-16
-
发表了主题帖:
【Follow me第二季第3期】入门任务---调试程序、Blink及按键测试
本帖最后由 quansirx 于 2024-11-16 14:28 编辑
一、
瑞萨EK-RA6M5开发板支持e2 studio、IAR、Keil MDK等IDE工具进行编程开发,我使用官方基于Eclipse开源IDE制作的e2 studio,由于是官方IDE工具因此开发支持力度相对好一些。
e2 studio的安装可以参考老师的讲解视频,以下来进行调试示例程序,LED等Blink,按键操作等内容
二、e2 studio调试示例程序
下载Renesas官方FSP例程,网址链接为https://github.com/renesas/ra-fsp-examples
以上为解压的文件内容,打开e2 studio工具并导入开发板quickstart例程
鼠标右击构建项目,编译通常后开始项目调试
调试选项选第3个
打开插件终端工具,设置参数如上图所示,串口通信波特率为115200
终端菜单选项:
键盘按下数字键1,开发板基本信息一览
QSPI、OSPI Flash读写速度测试
三、Blink、按键测试
3.1 LED Blink
新建e2 studio 基本FSP工程
TrustZone设置
屏幕剪辑的捕获时间: 2024-11-16 12:38
不使用RTOS
点击创建最小基本工程
基本工程结构一览
板载LED原理图
在原理图找到板载LED的引脚连接情况,LED1连接在P006引脚
打开配置xml文件
选中Pins这一栏,输入引脚编号P006以自动定位到该引脚配置界面
板载LED1为共阴极接法,于是设P006默认输出高电平
P001引脚配置的初始化代码
烧录固件至开发板
LED1成功点亮
添加循环点亮LED代码,在hal_entry函数处
void hal_entry(void)
{
/* TODO: add your own code here */
while(1){
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_06, BSP_IO_LEVEL_HIGH); //LED1亮
R_BSP_SoftwareDelay(500, BSP_DELAY_UNITS_MILLISECONDS); //延时500ms
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_06, BSP_IO_LEVEL_LOW); //LED1灭亮
R_BSP_SoftwareDelay(500, BSP_DELAY_UNITS_MILLISECONDS); //延时500ms
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
实验效果
3.2 按键测试
查看按键原理图
按键2连接至P004引脚,引脚状态默认为上拉,按键按下后引脚电平为低电平
xml配置
示例代码
void hal_entry(void)
{
/* TODO: add your own code here */
uint8_t t=150;
while(1){
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_06, BSP_IO_LEVEL_HIGH); //LED3亮
R_BSP_SoftwareDelay(t, BSP_DELAY_UNITS_MILLISECONDS); //延时500ms
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_06, BSP_IO_LEVEL_LOW); //LED1灭亮
R_BSP_SoftwareDelay(t, BSP_DELAY_UNITS_MILLISECONDS); //延时500ms
KeyScan(BSP_IO_PORT_00_PIN_04);
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
void KeyScan(bsp_io_port_pin_t key);
void KeyScan(bsp_io_port_pin_t key){
bsp_io_level_t key_state;
R_IOPORT_PinRead(&g_ioport_ctrl, key, &key_state);
if(key_state==BSP_IO_LEVEL_LOW){
//软件消抖
R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);
//点亮LED2
R_IOPORT_PinWrite(&g_ioport_ctrl, LED2, BSP_IO_LEVEL_HIGH); //LED2亮
//等待按键松开
while(key_state==BSP_IO_LEVEL_LOW){
R_IOPORT_PinRead(&g_ioport_ctrl, key, &key_state);
}
//熄灭LED2
R_IOPORT_PinWrite(&g_ioport_ctrl, LED2, BSP_IO_LEVEL_LOW); //LED2灭
}
}
按键实验结果
- 2024-11-15
-
发表了主题帖:
【Follow me第二季第3期】EK-RA6M5开箱帖
本帖最后由 quansirx 于 2024-11-15 23:48 编辑
一、
很幸运能够参加本次得捷&EEWorld举办的第二季3期开发板学习活动,申请通过之后马上到得捷官网购买了EK-RA6M5开发板,不得不说从得捷官网下单也是一次愉快的购物体验,主要是元器件品质的可靠性得到保证,经过两周多终于交付手上。这也是本人首次使用瑞萨的MCU产品,非常期待本次的瑞萨开发之旅
二、EK-RA6M5简介
EK-RA6M5 是瑞萨电子(Renesas Electronics)推出的一款基于 ARM Cortex-M33 核心的微控制器(MCU)。它是瑞萨 RA 系列的一部分,专为高性能、低功耗应用设计,具有广泛的外设和强大的处理能力。下面是该微控制器的一些关键特点和简介:
1. 处理器核心
核心架构:ARM Cortex-M33,支持 TrustZone技术,用于增强安全性。
主频:高达 200 MHz,适用于对性能要求较高的嵌入式应用。
2. 内存配置
闪存(Flash):最多 2 MB。
RAM:最大 512 KB。
3. 外设支持
提供丰富的外设接口,如 UART、I2C、SPI、CAN、ADC、DAC 等,支持多种通信和控制需求。
具备多通道的 PWM(脉宽调制)和 定时器,适合各种嵌入式应用。
内建硬件加速的加密引擎(AES、RSA等),使得加密和解密操作更加高效,增强了数据安全性。
4. 低功耗特性
EK-RA6M5 采用了低功耗设计,支持多种省电模式,适用于对电池寿命要求较长的设备。
5. 开发和调试支持
EK-RA6M5 提供了完整的开发套件和工具支持,用户可以通过 E2Studio IDE 或 IAR Embedded Workbench 等开发环境进行开发。
支持标准的调试接口,如 J-Link,方便开发和调试。
6. 应用领域
EK-RA6M5 适用于各种嵌入式应用,如智能家居、工业控制、物联网设备、医疗设备等。
由于其高效的性能和低功耗特点,它也适合于电池驱动设备和需要处理加密数据的应用场景
图1 EK-RA6M5板载资源一览
三、EK-RA6M5开箱
得捷包装快递箱
EK-RA6M5开发板包装盒,看着非常简约大气
内附物品有:
EK-RA6M5开发板 1块
MicroUSB数据线 1根
RJ45接头网线 1根
MicroUSB OTG接头 1个
四、通电测试
开发板出厂出厂固件测试:
1.使用按键S1、S2更改LED1、LED2的显示亮度,刷新速率;
2.USB连接PC进行USB 模拟串口通信;
3.Web服务器等
五、结语
总的来说,这款EK-RA6M5开发板板载资源丰富,e2 studio是初次接触感觉操作也很不错。FSP提供的例程涵盖了大部分板载的外设驱动,有以上工具和内容丰富的例程以及社区论坛的支持,学习这款MCU的编程开发相信会非常便捷的
-
加入了学习《FollowMe 第二季:3 - EK_RA6M5 开发板入门》,观看 EK-RA6M5 开发板入门
- 2024-11-12
-
加入了学习《TI MSPM0 MCU》,观看 视频3
-
加入了学习《TI MSPM0 MCU》,观看 视频2