- 2025-01-18
-
回复了主题帖:
游戏玩家征集
这个不就是支持宏的键盘一类吗
-
回复了主题帖:
EEWorld 2024年度人物:感恩相伴,共赴新程,携手努力!
希望新的一年里EEWrold做大做强,再创辉煌!
- 2025-01-17
-
回复了主题帖:
【新年新挑战,任务打卡赢好礼!】第一批获奖名单公布
已确认
-
回复了主题帖:
回帖赢好礼 | 关于无线技术的那些事儿
-
回复了主题帖:
EEWorld 2024年度人物:感恩相伴,共赴新程,携手努力!
感谢佬,感谢EEworld论坛,感谢各位工作人员。 一定再接再厉在今年继续分享高质量的内容!
- 2025-01-14
-
回复了主题帖:
新年新挑战,任务打卡赢好礼!
本帖最后由 御坂10032号 于 2025-1-14 22:48 编辑
1- 2- 回复帖子
3- 大学堂学习
4 - 报名活动,得捷电子投票活动
5 - 资料下载
-
回复了主题帖:
【瓜分2500元红包】票选2024 DigiKey “感知万物,乐享生活”创意大赛人气作品TOP3!
手机扫码已经投票!
-
加入了学习《直播回放: 中星联华 - 高速信号完整性分析与测试》,观看 高速信号完整性分析与测试
-
加入了学习《自己动手写嵌入式操作系统》,观看 时间片轮转和上下文切换
-
加入了学习《自己动手写嵌入式操作系统》,观看 高级操作系统特性
-
回复了主题帖:
【STM32H7S78-DK测评】3.转轮动效菜单的实现
真流畅啊
-
回复了主题帖:
关于TL431的使用问题
不是太懂TL431不就是一个电压基准芯片吗? 好像就是输出2.5的参考电压
-
回复了主题帖:
DIY 耳机盒爆改随身音响(一)
0.8元爆炸了我都夸它炸的响
- 2025-01-13
-
回复了主题帖:
EEWORLD陪你过大年,新年积分兑换专场来啦~好物多多还有幸运盲盒!
兑换了一个开发板盲盒,求中大奖!
- 2025-01-11
-
回复了主题帖:
【测评入围名单(第一批)】年终回炉:FPGA、AI、高性能MCU、书籍等65个测品邀你来~
已经收到单号,感谢各位工作人员!
- 2025-01-10
-
回复了主题帖:
【回顾2024,展望2025】新年抢楼活动来啦!
⑴遇到过什么技术问题: 今年一直在尝试着入门学习机器学习和深度学习, 感谢论坛的动手学pytorch 读书活动,使我受益匪浅
⑵实现了哪些目标,达成了什么成就?: 今年最主要的收获在嵌入式方面上就是学习到了各种的软件知识, 和入门了PCB设计
在崭新的2025年
⑶最想关注什么技术? :AI
⑷最想要什么支持?比如更多的某方面教程、资料、活动? : 希望论坛多举办一些AI方面的活动和测评学习机会。
⑸立一个新年Flag : 希望,大家身体健健康康。家庭幸福美满!
- 2025-01-08
-
回复了主题帖:
【测评入围名单(第一批)】年终回炉:FPGA、AI、高性能MCU、书籍等65个测品邀你来~
个人信息无误, 确认可以完成测评计划
- 2024-12-25
-
回复了主题帖:
2025年测评中心,DigiKey得捷赞助继续,欢迎跟帖推你期待的上线的测品啦~
希望多出一些AI系列难度中等的开发板测评或者活动
- 2024-12-13
-
加入了学习《Follow me 第二季第3期成果视频》,观看 成果展示
-
发表了主题帖:
[Follow me第二季第3期] 作品提交
本帖最后由 御坂10032号 于 2024-12-13 00:12 编辑
简介
大家好,接下来我将对项目的所有任务进行整合和汇总,并且介绍每个任务功能的核心代代码。
任务/项目介绍
本次项目采用的开发板是来自瑞萨电子的EK-RA6M5开发板, 它基于Arm®Cortex®-M33内核, 最高主频可以跑到200MHZ. 它一共有176个引脚。它不仅本身性能强悍,同时预留了很多其他生态的接口。 比如说 2个Seeed Grove®系统(I2C/模拟)连接器 ,SparkFun®Qwiic®连接器, 2个Digilent PmodTM(SPI和UART)连接器,ArduinoTM(Uno R3)连接器,和MikroElektronikaTM mikroBUS连接器。
本期一共有四个任务, 分别是下述。
入门任务:搭建环境,下载调试示例程序,Blink,按键;
基础任务:quad-spi flash和octo-spi flash配置及读写速度测试;DAC配置生成波形及性能测试;
进阶任务:示例程序中新增命令打印信息;
扩展任务:设计一个类似信号发生器功能的例程。可在示例程序上修改。通过命令或按键,设置DAC输出波形,可通过flash存储历史波形等信息。
实现思路:
入门任务:入门任务的主要实现思路是学习如何搭建环境信息, 以及如何使用E2studio创建工程,并且将示例程序使用debug接口下载到开发板上。 同时学习如何调整Demo的代码信息, 比如说增加额外的LED频率和占空比等等,以及如何读取IO输入。
基础任务:基础任务的Q-SPI falsh 和O-SPI flash的配置和读写速度测试,我们可以参照官方提供的函数进行实现。 对于DAC的配置如果不想在原本的项目上改的话, 可以在configuration.yml 中来快速配置, 并且快速的生成stack。然后使用Developer Assistance 来辅助我们快速完成。
进阶任务:进阶任务需要我们自己来创建一个菜单选项,并且集成在主菜单界面中。使其打印自定义的数据信息。
扩展任务:拓展任务实现起来相对复杂一点,但是其功能则是整合了上述所有的功能在一起。通过命令或者按键来生成不同的波形,同时可以将波形数据保存到Flash里,进行历史数据的保存或者直接输出。
软件流程图
由于上述的程序主要是在RTOS中运行的, 现在我来简单的解释一下上面的流程图。 首先在程序的初始化完成之后。 显示程序的菜单界面。 之后根据用户的输入进入到不同的子菜单选项。比如说板载的信息显示。 自定义命令。 或者QSPI操作DAC输出等。 而对于某些非本次任务的子菜单选项这次并没有额外的画出。 比如说Webserver的子菜单。 USB相关的等以便于理解。
主要功能、核心代码展示
入门任务核心代码及其功能演示:
入门任务的核心在于如何来追踪已经有的LED的频率和占空比信息等。我们可以非常方便的使用e2 studio 对 menu_kit.c 中相关的变量进行追踪和修改。
修改LED的相关信息
效果演示
基础任务核心代码及其功能演示:
基础任务的核心在于读懂如何使用官方的SPI-flash的读写测试部分, 虽然测试代码我们并不需要自己直接写,但是在后续的SPI flash 数据保存环节我们还需要继续使用。 所以能够看懂官方的代码也是至关重要的一项。 对于DAC的测试的重点有两个 ,1 如何使用FSP结合stack快速生成对应的库文件和初始化文件。 2 - 如何使用DAC相关的函数输出。
SPI-Flash 测试核心代码
static uint32_t qspi_write_test(uint32_t block_size)
{
fsp_err_t fsp_err;
uint32_t qspi_write_result = 0;
timer_status_t status = {};
fsp_err_t err = FSP_SUCCESS;
spi_flash_protocol_t current_spi_mode;
/* Convert from kB */
block_size *= 1024;
/* The comms mode is EXTENDED_SPI by default */
current_spi_mode = SPI_FLASH_PROTOCOL_EXTENDED_SPI;
/* initialise the QSPI, and change mode to that set in FSP */
err = qpi_init();
if (FSP_SUCCESS == err)
{
/* The comms mode has changed. So if recovering, this new mode required */
current_spi_mode = g_qspi_cfg.spi_protocol;
}
uint32_t page_write_count = 0;
uint8_t * p_mem_addr;
/* Cast to req type */
p_mem_addr = (uint8_t *)QSPI_DEVICE_START_ADDRESS;
while (((page_write_count * SECTOR_SIZE) < block_size)
&& ( FSP_SUCCESS == err ) )
{
/* Erase Flash for one sector */
err = R_QSPI_Erase(&g_qspi_ctrl, p_mem_addr, SECTOR_SIZE);
if (FSP_SUCCESS != err)
{
sprintf(s_print_buffer, "R_QSPI_Erase Failed\r\n");
}
else
{
err = get_flash_status();
if (FSP_SUCCESS != err)
{
sprintf(s_print_buffer, "Failed to get status for QSPI operation\r\n");
}
/* Verify the erased block data */
uint32_t count;
for (count = 0; count < SECTOR_SIZE; count++ )
{
if (DEFAULT_MEM_VAL != p_mem_addr[count])
{
/* Verification failed, perhaps the ERASE failed */
err = FSP_ERR_NOT_ERASED;
}
}
}
p_mem_addr += SECTOR_SIZE;
page_write_count++;
}
/* Start the test timer */
fsp_err = R_GPT_Start(g_memory_performance.p_ctrl);
/* Handle error */
if (FSP_SUCCESS != fsp_err)
{
/* Fatal error */
SYSTEM_ERROR
}
/* Cast to req type */
p_mem_addr = (uint8_t *)QSPI_DEVICE_START_ADDRESS;
page_write_count = 0;
while (((page_write_count * PAGE_WRITE_SIZE) < block_size)
&& (FSP_SUCCESS == err))
{
if (FSP_SUCCESS == err)
{
/* Write data to QSPI Flash */
/* Each block begins one character shifted along the source text. To avoid regular striping in memory */
err = R_QSPI_Write(&g_qspi_ctrl, &(sp_source[page_write_count]), p_mem_addr, PAGE_WRITE_SIZE);
if (FSP_SUCCESS != err)
{
sprintf(s_print_buffer, "R_QSPI_Write Failed\r\n");
}
else
{
err = get_flash_status();
if (FSP_SUCCESS != err)
{
sprintf(s_print_buffer, "Failed to get status for QSPI operation\r\n");
}
}
}
p_mem_addr += PAGE_WRITE_SIZE;
page_write_count++;
}
/* close QSPI module */
deinit_qspi(current_spi_mode);
fsp_err = R_GPT_Stop(g_memory_performance.p_ctrl);
/* Handle error */
if (FSP_SUCCESS != fsp_err)
{
/* Fatal error */
SYSTEM_ERROR
}
fsp_err = R_GPT_StatusGet(g_memory_performance.p_ctrl, &status);
/* Handle error */
if (FSP_SUCCESS != fsp_err)
{
/* Fatal error */
SYSTEM_ERROR
}
fsp_err = R_GPT_Reset(g_memory_performance.p_ctrl);
/* Handle error */
if (FSP_SUCCESS != fsp_err)
{
/* Fatal error */
SYSTEM_ERROR
}
qspi_write_result = status.counter;
return (qspi_write_result);
}
相关的DAC配置信息
效果如下所示:
DAC输出的效果
进阶任务核心代码及其功能演示
进阶任务的核心在于如何读懂原本的命令菜单方面的代码。 如果读懂了的话,我们可以非常方便的在原本的功能上面进行拓展。
主菜单核心代码
/* Table of menu functions */
static st_menu_fn_tbl_t s_menu_items[] =
{
{"Kit Information" , kis_display_menu},
{"Hello world" , ns_display_hello_world},
{"QSPI Operation" , ns_display_qspi_write},
{"Web Server" , eth_emb_display_menu},
{"Network Name Lookup" , eth_www_display_menu},
{"Quad-SPI and Octo-SPI Speed Comparison" , ext_display_menu},
{"Cryptography and USB High speed (MSC)" , enc_display_menu},
{"Next Steps", ns_display_menu },
{"", NULL }
};
子菜单核心代码
/*
* menu_text.c
*
* Created on: 2024年12月1日
* Author: 23391
*/
#include "FreeRTOS.h"
#include "FreeRTOSConfig.h"
#include "semphr.h"
#include "queue.h"
#include "task.h"
#include "common_init.h"
#include "common_utils.h"
#include "menu_text.h"
#define CONNECTION_ABORT_CRTL (0x00)
#define MENU_EXIT_CRTL (0x20)
static char_t s_print_buffer[BUFFER_LINE_LENGTH] = {};
#define MODULE_NAME "\r\n%d. Hello world!\r\n"
test_fn ns_display_hello_world (void)
{
int8_t c = -1;
print_to_console((void*)s_print_buffer);
sprintf (s_print_buffer, MODULE_NAME, g_selected_menu);
print_to_console((void*)s_print_buffer);
sprintf (s_print_buffer, MENU_RETURN_INFO);
while ((CONNECTION_ABORT_CRTL != c))
{
c = input_from_console ();
if ((MENU_EXIT_CRTL == c) || (CONNECTION_ABORT_CRTL == c))
{
break;
}
}
return (0);
}
效果演示
拓展任务核心代码及其功能演示
拓展任务实际上是将上述的所有任务整合在了一起,通过将上述的所有任务进行整合,从而来达到我们任务的目的。 拓展任务中我们需要将历史波形信息保存到Flash, 然后根据从Flash里读取的波形来驱动DAC输出不同的波形(正弦波和三角波等)
生成正弦波代码
void generate_sine_wave(uint16_t *sine_wave_array, size_t size)
{
for (size_t i = 0; i < size; i++)
{
// Generate sine wave: scale to 0 - MAX_AMPLITUDE
sine_wave_array[i] = (uint16_t) ((sin ((double) i * 2.0 * 3.1415926 / size) + 1.0) * (MAX_AMPLITUDE / 2.0));
}
}
生成三角波代码
void generate_triangle_wave(uint16_t *triangle_wave_array, size_t size)
{
size_t half_period = size / 2; // Half period of the triangle wave
for (size_t i = 0; i < size; i++)
{
if (i < half_period)
{
// Rising edge: 0 to MAX_AMPLITUDE
triangle_wave_array[i] = (uint16_t) ((double) i / (half_period - 1) * MAX_AMPLITUDE);
}
else
{
// Falling edge: MAX_AMPLITUDE to 0
triangle_wave_array[i] = (uint16_t) ((double) (size - i - 1) / (half_period - 1) * MAX_AMPLITUDE);
}
}
}
SPI Flash 的保存和读取
void saveToFlash(uint8_t *buffer)
{
fsp_err_t err = FSP_SUCCESS;
uint32_t page_write_count = 0;
uint8_t *p_mem_addr = (uint8_t*) QSPI_DEVICE_START_ADDRESS;
spi_flash_protocol_t current_spi_mode;
p_mem_addr = (uint8_t*) QSPI_DEVICE_START_ADDRESS;
err = qpi_init ();
if (FSP_SUCCESS == err)
{
/* The comms mode has changed. So if recovering, this new mode required */
current_spi_mode = g_qspi_cfg.spi_protocol;
}
/* 擦除 QSPI 的指定扇区 */
err = R_QSPI_Erase (&g_qspi_ctrl, p_mem_addr, 4096U);
if (FSP_SUCCESS != err)
{
sprintf (s_print_buffer, "Failed to erase QSPI flash\r\n");
print_to_console ((void*) s_print_buffer);
return;
}
/* 等待擦除完成 */
err = get_flash_status ();
if (FSP_SUCCESS != err)
{
sprintf (s_print_buffer, "Failed to get flash status after erase\r\n");
print_to_console ((void*) s_print_buffer);
return;
}
err = R_QSPI_Write (&g_qspi_ctrl, &buffer[0], p_mem_addr, 1);
if (FSP_SUCCESS != err)
{
sprintf (s_print_buffer, "Failed to write data to QSPI flash\r\n");
print_to_console ((void*) s_print_buffer);
}
else
{
err = get_flash_status ();
if (FSP_SUCCESS != err)
{
sprintf (s_print_buffer, "Failed to get flash status after write\r\n");
print_to_console ((void*) s_print_buffer);
}
}
deinit_qspi (current_spi_mode);
}
void readFromFlash(uint8_t *buffer)
{
fsp_err_t err = FSP_SUCCESS;
uint32_t page_read_count = 0;
uint8_t *p_mem_addr = (uint8_t*) QSPI_DEVICE_START_ADDRESS;
spi_flash_protocol_t current_spi_mode;
/* The comms mode of the FLASH device is EXTENDED_SPI by default */
current_spi_mode = SPI_FLASH_PROTOCOL_EXTENDED_SPI;
/* initialise the QSPI, and change mode to that set in FSP */
err = qpi_init ();
if (FSP_SUCCESS == err)
{
/* The comms mode has changed. So if recovering, this new mode required */
current_spi_mode = g_qspi_cfg.spi_protocol;
}
memcpy (&buffer[0], p_mem_addr, 1);
deinit_qspi (current_spi_mode);
}
效果展示
所有功能的实现思路和效果演示请查看每个帖子,或者是总结视频,总结视频中详细讲解了每个任务的实现步骤。
总结和建议
非常感谢得捷电子和电子工程世界提供的这次来之不易的活动机会。 我个人觉得本次的活动安排的非常好, 每个任务和衔接非常严谨。最后又通过一个完成的demo设计将上述所有的任务整合在了一起, 让我在本次活动中所学到的知识都联系了起来。 希望得捷电子和电子工程世界越办越好。再次感谢!
成功视频展示
代码附件信息
代码下载链接(点击跳转, 已经包含了每个部分的完整代码实现)