64|1

1

帖子

1

TA的资源

一粒金砂(中级)

楼主
 

【Follow me第二季第3期】EK-RA6M5所有任务汇总 [复制链接]

  本帖最后由 fastjs 于 2024-11-20 15:35 编辑

很荣幸参与【Follow me第二季第3期】,这期活动的开发板为EK-RA6M5,是一款由瑞萨官方开发的评估套件。

一、演示视频


Follow me第二季第3期演示视频-Follow me第二季第3期演示视频-EEWORLD大学堂

二、任务介绍

任务简介

入门任务:搭建环境,下载调试示例程序,Blink,按键;

基础任务:quad-spi flash和octo-spi flash配置及读写速度测试;DAC配置生成波形及性能测试;

进阶任务:示例程序中新增命令打印信息;

扩展任务:设计一个类似信号发生器功能的例程。通过命令或按键,设置DAC输出波形,可通过flash存储历史波形等信息。

物料清单

物料为EK-RA6M5开发板和MicroUSB线缆。

 

设计思路

通过USB虚拟串口传输指令,从而实现各个功能,比如调整DAC输出电压的值,以生成波形;存储波形数据,读取波形数据。通过接收命令,可以调整DAC的输出参数,例如增大或减小波形参数的值(范围为0-4095),从而动态生成所需的波形。指令 a 和 s 用于实时增减波形参数,便于快速调整输出。存储功能使用 Quad-SPI 闪存,指令 w 将当前波形数据写入闪存以便保存历史记录,指令r 则从闪存中加载存储的波形数据到内存缓冲区,实现快速回放。启动功能通过 g 指令激活波形发生器,开始输出设定的波形数据。

 

三、软件流程图

 

四、实现细节

示例程序为ek_ra6m5/_quickstart下的quickstart_ek_ra6m5_ep工程。

任务一 入门任务

开发环境搭建e2 studio

打开示例程序编译后,右键工程,选择Debug As -> Renesas GDB Hardware Debugging下载程序

 

编译项目时,由于示例代码所使用的FSP版本问题,可能会报错,修改BSP_CLOCKS_PLL_MUL_10_0为BSP_CLOCKS_PLL_MUL(10, 0)即可。

 

下载好示例程序后,会发现LED初始设置为

  • LED1 (蓝色):以1 Hz频率闪烁,亮度为10%。
  • LED2 (绿色):常亮且亮度最大。
  • LED3 (红色):关闭。
  • LED5 (调试LED):忽略其橙色闪烁或点亮状态。

此时按下用户按钮S1,会改变LED1的亮度,每次按下依次切换为10%、50%和90%循环;按下用户按钮S2:改变LED1的闪烁频率,每次按下依次切换为1 Hz、5Hz和10 Hz循环。

点灯代码,其中代码中的GPT 是指 General Purpose Timer(通用定时器)

// 更改LED亮度
void gpt_blue_callback(timer_callback_args_t * p_args)
{
    /* Void the unused params */
    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];
        }
    }
}

// 更改LED闪烁频率
{
if ((s_ux_bits & (STATUS_UPDATE_FREQ_INFO)) == (STATUS_UPDATE_FREQ_INFO))
        {
            R_GPT_PeriodSet (g_blinker.p_ctrl, g_pwm_rates[g_board_status.led_frequency]);

            /* Clear Event */
            xEventGroupClearBits (g_update_console_event, (STATUS_UPDATE_FREQ_INFO));
        }
}

 

按键控制灯代码,按键由外部中断实现

/* SW 1 */
void button_irq10_callback(external_irq_callback_args_t *p_args)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    BaseType_t xResult = pdFAIL;
    EventBits_t uxBits;

    /* Void the unused args */
    FSP_PARAMETER_NOT_USED(p_args);

    uxBits = xEventGroupGetBitsFromISR (g_update_console_event);

    if ((uxBits & (STATUS_UPDATE_INTENSE_INFO)) != (STATUS_UPDATE_INTENSE_INFO))
    {
        /* Cast, as compiler will assume calc is int */
        g_board_status.led_intensity = (uint16_t) ((g_board_status.led_intensity + 1) % 3);
        xResult = xEventGroupSetBitsFromISR(g_update_console_event, STATUS_UPDATE_INTENSE_INFO,
                                            &xHigherPriorityTaskWoken);

        /* Was the message posted successfully? */
        if (pdFAIL != xResult)
        {
            /* If xHigherPriorityTaskWoken is now set to pdTRUE then a context
             switch should be requested.  The macro used is port specific and will
             be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() - refer to
             the documentation page for the port being used. */
            portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
        }
    }
}
/* SW 2 */
void button_irq9_callback(external_irq_callback_args_t *p_args)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    BaseType_t xResult = pdFAIL;
    EventBits_t uxBits;

    /* Void the unused args */
    FSP_PARAMETER_NOT_USED(p_args);

    uxBits = xEventGroupGetBitsFromISR (g_update_console_event);

    if ((uxBits & (STATUS_UPDATE_FREQ_INFO)) != (STATUS_UPDATE_FREQ_INFO))
    {
        /* Cast, as compiler will assume calc is int */
        g_board_status.led_frequency = (uint16_t) ((g_board_status.led_frequency + 1) % 3);
        xResult = xEventGroupSetBitsFromISR(g_update_console_event, STATUS_UPDATE_FREQ_INFO, &xHigherPriorityTaskWoken);

        /* Was the message posted successfully? */
        if (pdFAIL != xResult)
        {
            /* If xHigherPriorityTaskWoken is now set to pdTRUE then a context
             switch should be requested.  The macro used is port specific and will
             be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() - refer to
             the documentation page for the port being used. */
            portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
        }
    }
}

 

 

任务二 基础任务

任务2的flash测试功能已经在示例代码中实现了,这里展示配置及测试的核心代码,测试效果如下

quad-spi flash配置代码为示例代码menu.ext.c中的qpi_init(void)函数

octo-spi flash配置代码为示例代码ospi_test.c中configure_dopi_ospi()函数

quad-spi flash和octo-spi flash读写速度测试代码

print_to_console((uint8_t *)
                "\r\nWriting the text block to external Quad-SPI and Octo-SPI flash memories...\r\n");
uint32_t ospi_performance_write_result = 0;
uint32_t ospi_performance_read_result = 0;
uint32_t timer_frequency;
R_GPT_InfoGet(g_memory_performance.p_ctrl, &timer_info);
timer_frequency = timer_info.clock_frequency;
ospi_performance_test (block_size_actual, &ospi_performance_write_result, &ospi_performance_read_result);
ospi_write_result = ((100000000 / timer_frequency) * ospi_performance_write_result) / 100;
qspi_write_result  = ((100000000 / timer_frequency) * qspi_write_test(block_size_actual)) / 100;
print_to_console((uint8_t *)"Writing to flash completed\r\n");
        
print_to_console((uint8_t *)"\r\nReading the text block from external Quad-SPI and Octo-SPI flash memories...\r\n");
ospi_read_result  = ((100000000 / timer_frequency) * ospi_performance_read_result) / 100;
qspi_read_result  = ((100000000 / timer_frequency) * qspi_read_test(block_size_actual)) / 100;
print_to_console((uint8_t *)"Reading from flash completed\r\n");
R_GPT_Close(g_memory_performance.p_ctrl);

 

 

 

对于DAC波形生成,使用DAC的示例文件

DAC输出端口P014,对应Arduino_A4

ADC输入端口P000,对应MIKROBUS_AN_ARDUINO_A0

用杜邦线连接P014和P000,下载代码后运行效果如下

观察到ADC通道一读取的值随着设定的DAC的增加而增加。

DAC配置生成波形及性能测试代码

static fsp_err_t dac_adc_operations(int32_t * input)
{
    fsp_err_t err = FSP_SUCCESS;     // Error status
    /* Write value to DAC module */
    err = R_DAC_Write (&g_dac_ctrl, (uint16_t) (* input));
    /* handle error */
    if (FSP_SUCCESS != err)
    {
        /* dac Write Failure message */
        APP_ERR_PRINT("** DAC Write API failed ** \r\n");
        return err;
    }
    /* Start DAC conversion */
    err = R_DAC_Start (&g_dac_ctrl);
    /* handle error */
    if (FSP_SUCCESS != err)
    {
        /* dac start failure message */
        APP_ERR_PRINT("** DAC Start API failed ** \r\n");
        return err;
    }
    /* Start the ADC scan in Single scan mode*/
    err = R_ADC_ScanStart (&g_adc_ctrl);
    /* handle error */
    if (FSP_SUCCESS != err)
    {
        /* ADC Scan Failure message */
        APP_ERR_PRINT("** ADC ScanStart API failed ** \r\n");
        return err;
    }
    /* Stop and start DAC conversion for consecutive user input values*/
    err = R_DAC_Stop(&g_dac_ctrl);
    /* Handle Error */
    if (FSP_SUCCESS != err)
    {
        /* DAC stop failure message */
        APP_ERR_PRINT("** DAC Stop API failed ** \r\n");
    }
    return err;
}

 

任务三 进阶任务

新增命令打印信息

初始打印信息为

 

添加打印信息后,删除了暂时用不到的打印命令,显示效果如下,

 

按4,进入新增的第四个选项,输入一个字符串回车后将打印该字符串。

此部分核心代码如下。

	block_sz_ndx = 0;
    memset(&s_block_sz_str, 0, INPUT_BUFFER);
    while (false == valid_block_size)
    {
        print_to_console("input: ");
        while ((CONNECTION_ABORT_CRTL != c))
        {
            c = input_from_console ();

            if (block_sz_ndx < block_sz_limit)
            {
                s_block_sz_str[block_sz_ndx] = (char_t)c;
                block_sz_ndx++;
            }
            else
            {
                s_block_sz_str[block_sz_ndx] = MENU_ENTER_RESPONSE_CRTL;
                c = MENU_ENTER_RESPONSE_CRTL;

            }
            if (MENU_ENTER_RESPONSE_CRTL == c)
            {
                print_to_console("\r\noutput: ");
                s_block_sz_str[block_sz_ndx - 1] = '\r';
                s_block_sz_str[block_sz_ndx] = '\n';
                print_to_console((void*)s_block_sz_str);
                block_sz_ndx = 0;
                memset(&s_block_sz_str, 0, INPUT_BUFFER);
                break;
            }

            if (MENU_EXIT_CRTL == c)
            {
                valid_block_size = true;
                block_size_actual = 0;
                break;
            }

            if (CARRAGE_RETURN != c)
            {
                sprintf(s_print_buffer, "%c", (char_t)c);
                print_to_console((void*)s_print_buffer);
            }

        }
        if ((MENU_EXIT_CRTL == c) || (CONNECTION_ABORT_CRTL == c))
        {
            break;
        }
    }

 

任务四 扩展任务

QSPI FLASH型号为MX25L25645G,OSPI FLASH型号为MX25LM51245GM,本次任务将波形信息存储到QSPI FLASH中。QSPI 使用6 个信号连接Flash,分别是四个数据线QIO0~QIO3,一个时钟输出SCLK,一个片选输出(低电平有效)CS#。

设置默认dac输出值为{ 2048, 2460, 2856, 3218, 3532, 3786, 3969, 4072, 4093, 4031, 3887, 3668, 3382, 3042, 2661, 2255, 1841, 1435, 1054, 714, 428, 209, 65, 3, 24, 127, 310, 564, 878, 1240, 1636, 2048 };

这将输出一个正弦波,当输入指令时,其中的值发生增大或减小固定的值,但每个值范围在0-4095间,指令设计为

  • 'a' - 增加波形参数
  • 's' - 减少波形参数
  • 'r' - 从 Quad-SPI 闪存读取波形数据到内存缓冲区
  • 'w' - 将当前波形数据写入 Quad-SPI 闪存存储
  • 'g' - 启动波形发生器

键入指令后,输入Tab键即可执行对应功能。

波形发生器界面

设置DAC输出波形

void DAC_Init()
{
    R_DAC_Open(&g_dac0_ctrl, &g_dac0_cfg);
    R_DAC_Start(&g_dac0_ctrl);
}

void DAC_SinWave_Cycle(uint32_t time_interval)
{
    for(uint32_t i = 0 ; i < (sizeof(custom_var)/sizeof(custom_var[0])); i++)
    {
        R_DAC_Write(&g_dac0_ctrl, custom_var[i]);
        R_BSP_SoftwareDelay(time_interval, BSP_DELAY_UNITS_MILLISECONDS);
    }
}

在flash存储历史波形


/**
 * @brief 将波形数据存储到 Quad Flash
 * @param buffer 需要存储的波形
 * @retval 无
 */
void Write_Waveform_To_Flash(uint16_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;

    /* Cast to req type */
    p_mem_addr = (uint8_t *)QSPI_DEVICE_START_ADDRESS;
    /* 打开 QSPI 模块 */
//    err = R_QSPI_Open(&g_qspi_ctrl, &g_qspi_cfg);
//    if (FSP_SUCCESS != err)
//    {
//        sprintf(s_print_buffer, "Failed to open QSPI module\r\n");
//        return;
//    }
    /* 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;
    }
    /* 擦除 QSPI 的指定扇区 */
    err = R_QSPI_Erase(&g_qspi_ctrl, p_mem_addr, SECTOR_SIZE);
    if (FSP_SUCCESS != err)
    {
        sprintf(s_print_buffer, "Failed to erase QSPI flash\r\n");
        return;
    }
    /* 等待擦除完成 */
    err = get_flash_status();
    if (FSP_SUCCESS != err)
    {
        sprintf(s_print_buffer, "Failed to get flash status after erase\r\n");
        return;
    }

    /* 逐页写入波形数据 */
    while (((page_write_count * PAGE_WRITE_SIZE) < sizeof(custom_var)) && (FSP_SUCCESS == err))
    {
        err = R_QSPI_Write(&g_qspi_ctrl, &buffer[page_write_count * PAGE_WRITE_SIZE / sizeof(uint16_t)], p_mem_addr, PAGE_WRITE_SIZE);
        if (FSP_SUCCESS != err)
        {
            sprintf(s_print_buffer, "Failed to write data to QSPI flash\r\n");
        }
        else
        {
            err = get_flash_status();
            if (FSP_SUCCESS != err)
            {
                sprintf(s_print_buffer, "Failed to get flash status after write\r\n");
            }
        }
        p_mem_addr += PAGE_WRITE_SIZE;
        page_write_count++;
    }
    /* 关闭 QSPI 模块 */
//    err = R_QSPI_Close(&g_qspi_ctrl);
//    if (FSP_SUCCESS != err)
//    {
//        sprintf(s_print_buffer, "Failed to close QSPI module\r\n");
//    }

    /* close QSPI module */
    deinit_qspi(current_spi_mode);
}

读取上一次存储的波形

/**
 * @brief 从 Quad Flash 读取波形数据
 * @param buffer 存储波形的缓冲区
 * @retval 无
 */
void Read_Waveform_From_Flash(uint16_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;
    /* 打开 QSPI 模块 */
//    err = R_QSPI_Open(&g_qspi_ctrl, &g_qspi_cfg);
//    if (FSP_SUCCESS != err)
//    {
//        sprintf(s_print_buffer, "Failed to open QSPI module\r\n");
//        return;
//    }
    /* 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;
    }

    /* 逐页读取波形数据 */
    while ((page_read_count * PAGE_WRITE_SIZE) < sizeof(custom_var))
    {
        memcpy(&buffer[page_read_count * PAGE_WRITE_SIZE / sizeof(uint16_t)], p_mem_addr, PAGE_WRITE_SIZE);
        p_mem_addr += PAGE_WRITE_SIZE;
        page_read_count++;
    }
//    /* 关闭 QSPI 模块 */
//    err = R_QSPI_Close(&g_qspi_ctrl);
//    if (FSP_SUCCESS != err)
//    {
//        sprintf(s_print_buffer, "Failed to close QSPI module\r\n");
//    }
    /* close QSPI module */
    deinit_qspi(current_spi_mode);
}

调整DAC参数

void Adjust_Waveform(int32_t step)
{
    for (uint32_t i = 0; i < sizeof(custom_var) / sizeof(custom_var[0]); i++)
    {
        // 调整值,限制范围在 MIN_VALUE 和 MAX_VALUE 之间
        if (custom_var[i] + step > MAX_VALUE)
        {
            custom_var[i] = MAX_VALUE;
        }
        else if (custom_var[i] + step < MIN_VALUE)
        {
            custom_var[i] = MIN_VALUE;
        }
        else
        {
            custom_var[i] += step;
        }
    }
}

指令输入解析

block_sz_ndx = 0;
    memset(&s_block_sz_str, 0, INPUT_BUFFER);
    while (false == response_flag)
    {
        print_to_console("input: ");

        while ((CONNECTION_ABORT_CRTL != c))
        {
            c = input_from_console();
            if (block_sz_ndx < block_sz_limit)
            {
                s_block_sz_str[block_sz_ndx] = (char_t)c;
                block_sz_ndx++;
            }
            else
            {
                s_block_sz_str[block_sz_ndx] = MENU_ENTER_RESPONSE_CRTL;
                c = MENU_ENTER_RESPONSE_CRTL;

            }
            if (MENU_ENTER_RESPONSE_CRTL == c)
            {
                if (s_block_sz_str[block_sz_ndx - 2] == 'a')
                {
                    sprintf(s_print_buffer, "\r\nIncrease waveform parameters\r\n");
                    print_to_console((void*)s_print_buffer);
                    Adjust_Waveform(STEP_SIZE); // 增加波形值
                    sprintf(s_print_buffer, "custom_var contains:\r\n");
                    print_to_console((void *)s_print_buffer);
                    for (uint32_t i = 0; i < 32; i++)
                    {
                        sprintf(s_print_buffer, "custom_var[%u] = %u\r\n", i, custom_var[i]);
                        print_to_console((void *)s_print_buffer);
                    }
                }
                if (s_block_sz_str[block_sz_ndx - 2] == 's')
                {
                    sprintf(s_print_buffer, "\r\nDecrease waveform parameters\r\n");
                    print_to_console((void*)s_print_buffer);
                    Adjust_Waveform(-STEP_SIZE); // 减少波形值
                    sprintf(s_print_buffer, "custom_var contains:\r\n");
                    print_to_console((void *)s_print_buffer);
                    for (uint32_t i = 0; i < 32; i++)
                    {
                        sprintf(s_print_buffer, "custom_var[%u] = %u\r\n", i, custom_var[i]);
                        print_to_console((void *)s_print_buffer);
                    }
                }
                if (s_block_sz_str[block_sz_ndx - 2] == 'r') // 读取波形数据
                {
                    sprintf(s_print_buffer, "\r\nRead the waveform data from Quad-SPI flash into memory buffer\r\n");
                    print_to_console((void*)s_print_buffer);
                    Read_Waveform_From_Flash(custom_var);
                    is_custom_wave = true;
                    sprintf(s_print_buffer, "After Reading, custom_var contains:\r\n");
                    print_to_console((void *)s_print_buffer);
                    for (uint32_t i = 0; i < 32; i++)
                    {
                        sprintf(s_print_buffer, "custom_var[%u] = %u\r\n", i, custom_var[i]);
                        print_to_console((void *)s_print_buffer);
                    }

                }
                else if (s_block_sz_str[block_sz_ndx - 2] == 'w') // 写入波形数据
                {
                    sprintf(s_print_buffer, "\r\nWrite the current waveform data to Quad-SPI flash storage\r\n");
                    print_to_console((void*)s_print_buffer);
                    sprintf(s_print_buffer, "Before Writing, var contains:\r\n");
                    print_to_console((void *)s_print_buffer);
                    for (uint32_t i = 0; i < 32; i++)
                    {
                        sprintf(s_print_buffer, "var[%u] = %u\r\n", i, custom_var[i]);
                        print_to_console((void *)s_print_buffer);
                    }
                    Write_Waveform_To_Flash(custom_var);
                }
                else if (s_block_sz_str[block_sz_ndx - 2] == 'g') // 写入波形数据
                {
                    sprintf(s_print_buffer, "\r\nStart Generator...\r\n");
                    print_to_console((void *)s_print_buffer);
                    while(1)
                    {
                        DAC_SinWave_Cycle(10);
                    }
                }

                block_sz_ndx = 0;
                memset(&s_block_sz_str, 0, INPUT_BUFFER);
                break;
            }
            if (MENU_EXIT_CRTL == c)
            {
                response_flag = true;
                block_size_actual = 0;
                break;
            }

            if (CARRAGE_RETURN != c)
            {
                sprintf(s_print_buffer, "%c", (char_t)c);
                print_to_console((void*)s_print_buffer);
            }
            // 输出波形
            DAC_SinWave_Cycle(1);
        }
        if ((MENU_EXIT_CRTL == c) || (0x00 == c))
        {
            break;
        }
    }

向flash写入一个周期的波形数据

 

从flash读取一个周期的波形数据,可以看到读取的波形数据和写入的是一致的。

默认输出波形:

修改DAC输出后波形:

五、心得体会

本次活动非常棒,通过本次活动,我对在瑞萨平台上的开发有了更加深入的了解。整个任务过程设计合理,循序渐进,从环境搭建到功能扩展,不仅让我熟悉了开发流程,还提升了实际动手能力。在扩展任务中,熟悉了spi接口操作flash和dac波形生成。此外,EEworld工作人员的全程答疑提供了很大的帮助,解决了活动中的疑问。再次感谢活动组织方和工作人员的精心安排!

 

六、代码下载

Follow me第二季第3期任务代码-嵌入式开发相关资料下载-EEWORLD下载中心

最新回复

恭喜完成任务,这还用了一个12指,挺不错的     详情 回复 发表于 3 小时前
点赞 关注
 
 

回复
举报

6061

帖子

6

TA的资源

版主

沙发
 

恭喜完成任务,这还用了一个12指,挺不错的  

个人签名

在爱好的道路上不断前进,在生活的迷雾中播撒光引

 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

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

 
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
快速回复 返回顶部 返回列表