CoderX9527

个性签名:

点个灯吧

  • 2025-01-18
  • 回复了主题帖: EEWORLD陪你过大年,新年积分兑换专场来啦~好物多多还有幸运盲盒!

    已兑换盲盒,啥时候发快递呢?

  • 2025-01-17
  • 回复了主题帖: 新年新挑战,任务打卡赢好礼!

      任务1:完善个人信息 任务2:回复3个帖子 帖子1: 帖子2: 帖子3: 任务3:认真学完一个大学堂视频 任务4:报名参加活动中心的一个活动 任务5:下载一份资源站资料

  • 评论了课程: EEWORLD大学堂----Digikey KOL系列:欢迎进入MicroPython的奇妙世界

    非常感谢分享。 会一点Python皮毛,只会嵌入式MCU开发,看了这个视频,感觉可以把Python捡起来,在MCU开发小项目可以加快速度。

  • 加入了学习《2020_Digikey KOL系列:欢迎进入MicroPython的奇妙世界》,观看 欢迎进入MicroPython的奇妙世界

  • 2025-01-16
  • 加入了学习《Arduino和树莓派之间的比较》,观看 Arduino和树莓派之间的比较

  • 回复了主题帖: 【英飞凌PSOC™ 4100S Max】③Capsense触摸按钮初体验

    谢谢分享。 不仅分享了基础用例,还分享了触控调教,点赞。

  • 回复了主题帖: 【Raspberry Pi 5测评】树莓派5学习笔记02(GPIO口应用)

    学习了,python 开发MCU应用真的是太方便了,几行代码的事情。

  • 回复了主题帖: 【MCXA156开发板测评】-3-LPTMR体验

    谢谢分享,MUCXPressoIDE 配置外设还是非常方便的。

  • 加入了学习《乐鑫EV_Board变色龙UI框架与LVGL游戏移植实践》,观看 乐鑫EV_Board变色龙UI框架与LVGL游戏移植实践

  • 2025-01-15
  • 加入了学习《键鼠统一管家》,观看 键鼠统一管家

  • 2025-01-13
  • 回复了主题帖: EEWORLD陪你过大年,新年积分兑换专场来啦~好物多多还有幸运盲盒!

    已兑换一个盲盒

  • 2025-01-10
  • 加入了学习《【2024 DigiKey 创意大赛】AI全功能环境监测站作品功能演示视频》,观看 【2024 DigiKey 创意大赛】AI全功能环境监测站作品功能演示视频

  • 加入了学习《2024 DigiKey “感知万物,乐享生活”创意大赛》,观看 “感知万物,乐享生活”AI赋能的智能家居系统

  • 2025-01-08
  • 回复了主题帖: 【Raspberry Pi 5测评】树莓派5学习笔记01(开发环境搭建)

    详细的分享

  • 回复了主题帖: 【Raspberry Pi 5测评】0.测评计划及前瞻

    期待大佬的作品

  • 2025-01-02
  • 回复了主题帖: 【2024 DigiKey 创意大赛】+基于Teensy4.1环境温湿度和气压监测

    为大佬点赞

  • 2024-12-24
  • 加入了学习《FollowMe第二季第三期-任务提交》,观看 任务提交视频

  • 2024-12-17
  • 加入了学习《【Follow me第二季第4期】ARDUINO NANO RP2040 CONNECT》,观看 PDM功能演示-ARDUINO NANO RP2040 CONNECT

  • 2024-12-15
  • 发表了主题帖: 【Follow me第二季第3期】作品提交

    本帖最后由 CoderX9527 于 2024-12-15 16:56 编辑   致谢 非常感谢 EEWORLD && DigiKey 联合举办的 FollowMe 活动,我非常幸运地参与了此次活动,学到了不少东西。以前没接触过 Renesas MCU,也没有接触过 Renesas 的开发环境,经过这次的学习,我学会了 DAC 输出波形,通过 QSPI 读写 Flash。受益良多。   视频     https://training.eeworld.com.cn/video/41969     代码   https://download.eeworld.com.cn/detail/CoderX9527/635246     任务简介 此次活动总共有4个任务: 入门任务:搭建环境,下载调试例程,Blink,按键; 基础任务:quid-spi flash 和 octo-spi flash 配置以及读写速度测试;DAC配置生成波形以及性能测试; 进阶任务:示例程序中新增命令打印信息; 扩展任务:设计一个类似信号发生器功能的例程。通过命令或者按键,设置 DAC 输出波形,可通过 flash 存储历史波形等信息。   物料 此次活动仅使用一个物料,即 EK-RA6M5 板卡。   1. 入门任务 其中入门任务,已经在如下帖子中分享我的实践: https://bbs.eeworld.com.cn/thread-1301289-1-1.html 此次作品提交贴分三个部分,分别介绍基础任务、进阶任务和扩展任务。   2. 基础任务:QSPI-Flash 和 OSPI-Flash 速度测试,以及 DAC 配置生成波形和性能测试   QSPI-Flash 和 OSPI-Flash 速度测试 QSPI-Flash和OSPI-Flash 速度测试在 quick_start 工程中已经有了,这里理清楚它们的实现思路并实测演示。   实现思路 从下面的菜单项可以看到QSPI-Flash和OSPI-Flash速度测试的入口函数是 ext_display_menu() 串口打印输出如下,用户输入整数为2的倍数,最大值为64,指定文本块大小,然后开始测试。   主流程 OSPI-Flash 读写测试流程   QSPI-Flash 写测试流程   QSPI-Flash 读测试流程   速度测试   块大小 2KB 块大小 4KB 块大小 8KB 块大小 16KB 块大小 32KB 块大小 64KB   总结   从上图可知: 无论QSPI还是OSPI,块大小翻倍,读写耗时都会翻倍,大约是2倍; 同样的块大小写操作,OSPI耗时基本是 QSPI 的一半,即速度大约是 QSPI 的2倍,符合预期; 同样的块大小读操作,OSPI耗时基本是 QSPI 的1/6,即速度大约是 QSPI的6倍。   DAC配置生成波形和性能测试 RA6M5 提供了一个带输出放大器的 12bit DAC,有两个输出通道。DA0 管脚是 DAC的通道0输出管脚,DA1 是 DAC 的通道1输出管脚。   三角波 由于 DAC 位宽是12位,数值范围是[0, 4095],因此三角波一个周期内的数值变化趋势是 0逐步增加到 4095,然后又逐步减少到0,周期循环。 这里为此单独写了一个生成三角波的模块,每次调用函数 triangle_wave_get_next() 都会获取三角波中的下一个点。 C++ typedef struct { int16_t step; /**< 斜率 */ int32_t val; } triangle_wave_t; static triangle_wave_t m_triangle_wave = { .step = 1 // 默认斜率为1 }; /** * @brief 设置三角波斜率,可选值 [-2048, 2048] * * @param step */ void triangle_wave_cfg(int16_t step) { if ((step < -2048) || (step > 2048)) { return; } m_triangle_wave.step = step; } /** * @brief 获取三角波中的下一个点 * * @return int32_t */ int32_t triangle_wave_get_next(void) { int32_t temp = 0; temp = m_triangle_wave.val + m_triangle_wave.step; if (m_triangle_wave.step >= 0) { if (temp > 4095) { m_triangle_wave.step = 0 - m_triangle_wave.step; // step 变负数 } } else { if (temp < 0) { m_triangle_wave.step = 0 - m_triangle_wave.step; // step 变正数 } } m_triangle_wave.val += m_triangle_wave.step; return m_triangle_wave.val; }   DAC 配置   新增Stack--DAC 双击工程的配置文件 configuration.xml 文件,打开配置工具; New Stack 展开子菜单,选择 DAC   g_dac0 属性 打开 Properties 窗口,点击 HAL/Common Stacks 窗口中的 g_dac0 DAC (r_dac) ,然后就可以在下方属性窗口看到 g_dac0 的各个设置。 属性中可知 DAC 通道0对应的实例对象名字为 g_dac0,数据格式:Right Justifed,即数据右对齐,其他选项都是默认值; 从 Pins 可以看到 DA0 没有对应管脚,即(3)是 None,我们单击(4)处的箭头就可以跳转到 Pin Configuration 窗口,配置 DA0 管脚。 展开的 Pin Configuration 窗口中,可以看到 DAC0 的 管脚还是 None,我们修改为 P014,然而还是红色标注,说明配置有错误。   DA0 配置 P014 为输出管脚,红色表示管脚有错误或冲突。   找到 ADC 中的 ADC0,可知通道 AN012 占用了 P014 管脚,修改它为 None,即可解决 DAC0 配置 P014 管脚冲突问题。   确认 DAC0 的 P014 管脚配置没有问题之后,还需要点击 Generate Project Content 重新生成工程。   DAC 输出三角波 在函数 common_init() 中添加如下代码,初始化 DAC 在 gpt_blue_callback() 中添加一行 R_DAC_Write(&g_dac0_ctrl, triangle_wave_get()) 即可输出三角波。   示波器测量     心得体会 熟悉了定时器操作; 熟悉了QSPI-Flash, OSPI-Flash 的操作,实测对比读写速度,对于两者的性能有更深的认识; 熟悉了DAC模块,如何在 e2studio 中添加并配置 DAC 模块,示波器测试 DAC 输出,加深了对 DAC 的认识; DAC输出波形如此简单,以前以为很难,其实就是往 DAC 输出一个数值即可。   3. 进阶任务目标:示例程序中新增命令打印信息   显示命令的代码 从 main() 开始,一路找到显示菜单的函数,流程图如下:   菜单数组 s_menu_items 菜单数组如下,每一个成员都是一个结构体 st_menu_fn_tbl_t,成员 p_name 表示显示的菜单名字,成员 p_func 表示此菜单的执行函数。 C++ typedef struct menu_fn_tbl { char_t * p_name; /*<! Name of Test */ test_fn ( * p_func)(void); /*<! Pointer to Test Function */ } st_menu_fn_tbl_t; /* Table of menu functions */ static st_menu_fn_tbl_t s_menu_items[] = { {"Kit Information" , kis_display_menu}, {"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 } }; 如第一个菜单项,菜单名字为 "Kit Information",菜单的执行函数为 kis_display_menu()。这个菜单执行函数打印开发板的基本信息,包括板卡名字,part number,128-比他UID,芯片温度,蓝色LED闪烁频率、亮度等级等。 我新增一个命令,菜单名字为 "Welcome",菜单执行函数为 kit_welcome(),此菜单打印MCU的温度信息。   菜单数组更新 C++ /* Table of menu functions */ static st_menu_fn_tbl_t s_menu_items[] = { {"Welcome" , kit_welcome}, // 新增命令 {"Kit Information" , kis_display_menu}, {"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 } };   kit_welcome() 实现 此函数实现如下,最关键的就是第10行代码,把字符串输出到 s_print_buffer,然后调用函数 print_to_console((void *)s_print_buffer) 输出到终端。 C++ test_fn kit_welcome(void) { int8_t c = -1; sprintf (s_print_buffer, "%s%s", gp_clear_screen, gp_cursor_home); /* ignoring -Wpointer-sign is OK when treating signed char_t array as as unsigned */ print_to_console((void*)s_print_buffer); sprintf (s_print_buffer, "\r\nWelcome, EEWORLD & DigiKey FollowMe 2-3 by CoderX9527\r\n"); /* ignoring -Wpointer-sign is OK when treating signed char_t array as as unsigned */ print_to_console((void*)s_print_buffer); /* ignoring -Wpointer-sign is OK when treating signed char_t array as as unsigned */ sprintf (s_print_buffer, MENU_RETURN_INFO); print_to_console((void*)s_print_buffer); while (CONNECTION_ABORT_CRTL != c) { c = input_from_console (); if ((MENU_EXIT_CRTL == c) || (CONNECTION_ABORT_CRTL == c)) { break; } } xEventGroupClearBits (g_update_console_event, STATUS_DISPLAY_MENU_KIS); return (0); }   运行演示 按下1进入 Welcome 命令界面,如下图所示: 按下空格键返回到主菜单。   心得体会 通过串口输出打印信息也可以玩的很花,在打印的字符串中加入特殊的控制字符,例如 \x1b[2m 等可以控制输出的格式,以及输出文字的颜色,但是需要串口中断支持;   4. 扩展任务:设计一个类似信号发生器功能的历程。可以在示例程序上修改。通过命令或者按键,设置DAC输出波形,可以通过 Flash 存储历史波形等信息。   设计思路 信号发生器,支持输出三角波、正弦波。 命令界面,t -- 三角波,s -- 正弦波,w -- 保存波形类型到Flash,r -- 从 Flash 读取波形类型。   实现步骤 设计2种波形,分别是三角波、正弦波,能输出对应的波形; 菜单中增加命令,进入信号发生器菜单界面,可选择子菜单项,总共4个选项; 分别实现4个子菜单项; 分别验证4个子菜单项;   菜单设计 在主菜单中新增一个菜单项,名字为 Signal Generator,执行函数为 kit_signal_generator()。 C /* Table of menu functions */ static st_menu_fn_tbl_t s_menu_items[] = { {"Welcome" , kit_welcome}, {"Signal Generator" , kit_signal_generator}, // 信号发生器 {"Kit Information" , kis_display_menu}, {"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 } };   函数 kit_signal_generator() 执行函数在串口打印如下信息,用户输入 t 输出三角波 s 输出正弦波 w 保存当前的波形类型到 Flash r 从 Flash 读取波形类型,并立刻输出波形 空格键,返回主菜单 C test_fn kit_signal_generator(void) { int8_t c = -1; sprintf(s_print_buffer, "%s%s", gp_clear_screen, gp_cursor_home); 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, OPT_HELP); print_to_console(s_print_buffer); sprintf(s_print_buffer, OPT_TRIANGLE); print_to_console(s_print_buffer); sprintf(s_print_buffer, OPT_SINE); print_to_console(s_print_buffer); sprintf(s_print_buffer, OPT_WRITE); print_to_console(s_print_buffer); sprintf(s_print_buffer, OPT_READ); print_to_console(s_print_buffer); sprintf(s_print_buffer, MENU_RETURN_INFO); print_to_console((void*)s_print_buffer); while (CONNECTION_ABORT_CRTL != c) { c = input_from_console(); if (c == 't') { triangle_wave_cfg(20); wave_type_set(WAVE_TYPE_TRIANGLE); print_to_console("t --> Force wave type: Triangle\r\n"); continue; } if (c == 's') { wave_type_set(WAVE_TYPE_SINE); print_to_console("s --> Force wave type: Sine\r\n"); continue; } if (c == 'w') { sprintf(s_print_buffer, "w --> Save wave type: %u \r\n", (uint32_t)wave_type_get()); print_to_console(s_print_buffer); save_wave_type(wave_type_get()); continue; } if (c == 'r') { uint32_t wt = 0; if (restore_wave_type(&wt) == FSP_SUCCESS) { wave_type_set(wt); } sprintf(s_print_buffer, "r --> Restore wave type: %u \r\n", (uint32_t)wave_type_get()); print_to_console(s_print_buffer); continue; } if ((MENU_EXIT_CRTL == c) || (CONNECTION_ABORT_CRTL == c)) { break; } } xEventGroupClearBits(g_update_console_event, STATUS_DISPLAY_MENU_KIS); return (0); }   产生三角波 产生三角波的代码见入门任务,这里仅粘贴代码。重点在函数 triangle_wave_get_next(),每调用一次即可得到下一个点。 C typedef struct { int16_t step; /**< 斜率 */ int32_t val; } triangle_wave_t; static triangle_wave_t m_triangle_wave = { .step = 1 // 默认斜率为1 }; /** * @brief 设置三角波斜率,可选值 [-2048, 2048] * * @param step */ void triangle_wave_cfg(int16_t step) { if ((step < -2048) || (step > 2048)) { return; } m_triangle_wave.step = step; } /** * @brief 获取三角波中的下一个点 * * @return int32_t */ int32_t triangle_wave_get_next(void) { int32_t temp = 0; temp = m_triangle_wave.val + m_triangle_wave.step; if (m_triangle_wave.step >= 0) { if (temp > 4095) { m_triangle_wave.step = 0 - m_triangle_wave.step; // step 变负数 } } else { if (temp < 0) { m_triangle_wave.step = 0 - m_triangle_wave.step; // step 变正数 } } m_triangle_wave.val += m_triangle_wave.step; return m_triangle_wave.val; }   产生正弦波 产生正弦波的代码也很简单,只需要调用 sine_wave_get_next() 即可获取下一个点。 C #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #define SAMPLE_N (500) // sin 周期 500 个点 #define X_FACT ((2 * M_PI) / SAMPLE_N) // X系数 static int sine_t = 0; // 时间变量 double sine_wave_get_next(void) { double y = (sin(X_FACT * sine_t) + 1) / 2 * 4095; sine_t++; return y; }   保存波形、读取波形 QSPI-Flash 的读写操作参见 QSPI-Flash 读写速度测试,修改 qspi_write_test() 和 qspi_read_test() 函数即可分别实现写 Flash 和读 Flash 的操作。   保存波形 save_wave_type() 入口参数 wt 表示波形类型,参见 wave_type_e。 先调用 qpi_init() 初始化 QSPI ; R_QSPI_Erase() 擦除一个扇区; R_QSPI_Write() 把 wt 写入到第一个扇区首地址上; deinit_qspi() 反初始化 QSPI C /** * @brief 保存波形类型到 Flash 上。 * * @param wt 参见 wave_type_e * @return */ static fsp_err_t save_wave_type(uint32_t wt) { fsp_err_t fsp_err = FSP_SUCCESS; fsp_err_t err = FSP_SUCCESS; spi_flash_protocol_t current_spi_mode; uint32_t block_size = 4; // 4KB /* 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; // NOTE: Erase Sector 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"); print_to_console(s_print_buffer); } else { err = get_flash_status(); if (FSP_SUCCESS != err) { sprintf(s_print_buffer, "Failed to get status for QSPI operation\r\n"); print_to_console(s_print_buffer); } /* Verify the erased block data */ for (uint32_t 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++; } /* 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; // NOTE: Write fsp_err = R_QSPI_Write(&g_qspi_ctrl, &wt, p_mem_addr, sizeof(wt)); /* close QSPI module */ deinit_qspi(current_spi_mode); /* Handle error */ if (FSP_SUCCESS != fsp_err) { /* Fatal error */ SYSTEM_ERROR } return (fsp_err); }   读取波形 restore_wave_type() 从 Flash 读取波形类型保存到入口参数 wt 中。 qpi_init() 初始化 QSPI; memcpy() 读取 QSPI_DEVICE_START_ADDRESS 前1个word 并保存到 wt 地址上; deinit_qspi() 反初始化 QSPI; C /** * @brief 从 Flash 读取 wave_type * * @param wt * @return 0 表示成功,其他值表示失败 */ static fsp_err_t restore_wave_type(uint32_t* wt) { fsp_err_t err = FSP_SUCCESS; spi_flash_protocol_t current_spi_mode; uint8_t* p_mem_addr; /* 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; } // NOTE: Read wave type from Flash p_mem_addr = (uint8_t*)QSPI_DEVICE_START_ADDRESS; memcpy((void*)wt, p_mem_addr, sizeof(wt)); /* close QSPI module */ deinit_qspi(current_spi_mode); return (err); } 视频演示   心得体会 学会了如何生成三角波、正弦波; 模块化编程,有利于分解各个功能,减少串联出错的风险; 学习 QSPI-Flash 的读写操作;  

  • 上传了资料: FollowMe2-3 提交代码 - CoderX9527

最近访客

< 1/2 >

统计信息

已有29人来访过

  • 芯积分:158
  • 好友:--
  • 主题:12
  • 回复:56

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言