180|0

178

帖子

4

TA的资源

纯净的硅(初级)

楼主
 

[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连接器。

 

 

本期一共有四个任务, 分别是下述。

  1. 入门任务:搭建环境,下载调试示例程序,Blink,按键;
  2. 基础任务:quad-spi flash和octo-spi flash配置及读写速度测试;DAC配置生成波形及性能测试;
  3. 进阶任务:示例程序中新增命令打印信息;
  4. 扩展任务:设计一个类似信号发生器功能的例程。可在示例程序上修改。通过命令或按键,设置DAC输出波形,可通过flash存储历史波形等信息。

实现思路

  1. 入门任务:入门任务的主要实现思路是学习如何搭建环境信息, 以及如何使用E2studio创建工程,并且将示例程序使用debug接口下载到开发板上。 同时学习如何调整Demo的代码信息, 比如说增加额外的LED频率和占空比等等,以及如何读取IO输入。
  2. 基础任务:基础任务的Q-SPI falsh 和O-SPI flash的配置和读写速度测试,我们可以参照官方提供的函数进行实现。 对于DAC的配置如果不想在原本的项目上改的话, 可以在configuration.yml 中来快速配置, 并且快速的生成stack。然后使用Developer Assistance 来辅助我们快速完成。
  3. 进阶任务:进阶任务需要我们自己来创建一个菜单选项,并且集成在主菜单界面中。使其打印自定义的数据信息。
  4. 扩展任务:拓展任务实现起来相对复杂一点,但是其功能则是整合了上述所有的功能在一起。通过命令或者按键来生成不同的波形,同时可以将波形数据保存到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设计将上述所有的任务整合在了一起, 让我在本次活动中所学到的知识都联系了起来。 希望得捷电子和电子工程世界越办越好。再次感谢!

 


 

成功视频展示

 


 

代码附件信息

 

代码下载链接(点击跳转, 已经包含了每个部分的完整代码实现)

 

点赞 关注
 
 

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表