aramy 发表于 2024-11-28 13:48

【Follow me第二季第3期】EK-RA6M5任务提交

本帖最后由 aramy 于 2024-12-3 20:32 编辑

<p>很开心参加&ldquo;Follow me第二季第3期&rdquo;活动,这次板子是瑞萨的EK-RA6M5 。这款开发板超级大的。还配了网线、usb转接线和microUSB数据线。</p>

<p style="text-align: center;"><iframe allowfullscreen="true" border="0" frameborder="no" framespacing="0" height="450px" scrolling="no" src="//player.bilibili.com/player.html?bvid=BV1bNzmYpEi8&amp;page=1" width="700px"></iframe><br />
&nbsp;</p>

<p style="text-align: center;"> &nbsp;</p>

<p style="text-align: center;"> &nbsp;</p>

<hr />
<p><strong>入门任务:搭建环境,下载调试示例程序,Blink,按键</strong></p>

<p>开发软件,我是使用官方的IDE,内核应该是eclipse。参考着<a href="https://training.eeworld.com.cn/video/41666" target="_blank">老师的视频</a>安装IDE环境,我这里安装的是&ldquo;setup_fsp_v5_5_0_e2s_v2024-07.exe&rdquo;。然后下载例程包&ldquo;ra-fsp-examples-5.6.0.example.1.zip&rdquo;,导入例程包中的&ldquo;_quickstart&rdquo;例程。</p>

<p style="text-align: center;"> &nbsp;&nbsp;&nbsp;</p>

<p style="text-align: center;">&nbsp;</p>

<p style="text-align: center;">&nbsp;</p>

<p>点击图标栏里边的&ldquo;锤子&rdquo;图标,或者在项目上右键鼠标选择构建,即可编译项目,有一些警告,不用管它。然后通过microUSB线,插到板子的&ldquo;usb full&rdquo;口。官方例程中提供了按键和LED的控制。蓝色LED闪烁。左边的按钮控制蓝色LED灯的亮度:10%、50%、90%;右边的按键控制闪烁频率1Hz、5Hz、10Hz。查看例程的源码,可以找到控制LED灯亮度的方法:</p>

<pre>
<code>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++ ) &lt; s_duty)
            {
                TURN_BLUE_ON
            }
            else
            {
                TURN_BLUE_OFF
            }

            if (s_intense &gt;= 100)
            {
                s_intense = 0;
                s_duty = g_pwm_dcs;
            }
            break;
      }
      default:
      {
            TURN_BLUE_OFF
            s_intense = 0;
            s_duty = g_pwm_dcs;
      }
    }
}</code></pre>

<p style="text-align: center;">&nbsp;两个按键使用了中断的处理方法。</p>

<pre>
<code>/* SW 1 */
/**********************************************************************************************************************
* Function Name: button_irq10_callback
* Description: SW1 Interrupt handler.
* Argument   : p_args
* Return Value : None
*********************************************************************************************************************/
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 &amp; (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,
                                          &amp;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);
      }
    }
}
/**********************************************************************************************************************
End of function button_irq10_callback
*********************************************************************************************************************/

/* SW 2 */
/**********************************************************************************************************************
* Function Name: button_irq9_callback
* Description: SW2 interrupt handler.
* Argument   : p_args
* Return Value : None
*********************************************************************************************************************/
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 &amp; (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, &amp;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);
      }
    }
}</code></pre>

<p style="text-align: center;">&nbsp;&nbsp; &nbsp;</p>

<hr />
<p><strong>基础任务</strong>:quad-spi flash和octo-spi flash配置及读写速度测试;DAC配置生成波形及性能测试。这里使用两根microUSB数据线连接到开发板。一根线连接到&ldquo;USB FULL&rdquo;口,用来烧写调试程序,一根线连接到板子下方的&ldquo;DEBUG&rdquo;口,用来通过串口与板子通讯。</p>

<p style="text-align: center;">&nbsp;&nbsp; &nbsp;</p>

<p>依然是使用例程中的测试代码,具体代码在ospi_test.c中实现。</p>

<p style="text-align: center;"> &nbsp;</p>

<p>&nbsp;</p>

<p style="text-align: center;"> &nbsp;</p>

<p>DAC输出。依然使用&ldquo;_quickstart&rdquo;例程。</p>

<p>1、添加DAC功能,这里DAC输出使用P014管脚,直接设置会报错,原因是P014管脚已经被ADC0使用了,找到ADC0的设置,取消P014的使用,就可以了。</p>

<p style="text-align: center;"></p>

<p style="text-align: center;">&nbsp;</p>

<p style="text-align: center;">&nbsp;</p>

<p>参考着老师的视频讲解,初始化DAC的使用。</p>

<p style="text-align: center;"> &nbsp; &nbsp;</p>

<p>在gpt_blue_callback方法中,添加DAC的调用,这里创建了一个锯齿波。设置一个变量,变量累加。因为&ldquo;R_DAC_Write&rdquo;最大输入值为4095.所以将变量自加,当值大于等于4095时就归零。使用示波器观察波形输出。</p>

<p style="text-align: center;"> &nbsp;</p>

<p style="text-align: center;"> &nbsp;</p>

<hr />
<p><strong>进阶任务</strong>:示例程序中新增命令打印信息。在&ldquo;menu_main.c &rdquo;文件中找到例程的菜单,添加一行自定义菜单。</p>

<p style="text-align: center;"></p>

<p>&nbsp;编写自定义菜单对应方法。</p>

<pre>
<code>test_fn follow_me(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, "%s", "Follow me Season 2 Issue 3");
    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);
}</code></pre>

<p>然后调试运行,就可以看见自己增加的菜单了。</p>

<p style="text-align: center;"> &nbsp;</p>

<p style="text-align: center;"> &nbsp;</p>

<hr />
<p><strong>扩展任务:</strong>设计一个类似信号发生器功能的例程。可在示例程序上修改。通过命令或按键,设置DAC输出波形,可通过flash存储历史波形等信息。</p>

<p>这里简单地设计了两个波形:锯齿波、方波。通过DAC输出。使用外接示波器来做观察。模仿着例程设计一个菜单,显示用户可以选择的选项。选择1,显示锯齿波;选择2,显示方波。还有&ldquo;w&rdquo;、&ldquo;r&rdquo;两个选项,用户选择&ldquo;w&rdquo;则将当前显示的波形类型写入flash中。选择&ldquo;r&rdquo;则从flash中读取已经保存了的波形类型,并且通过DAC输出。</p>

<p style="text-align: center;"> &nbsp;</p>

<p>首先,在例程的基础上添加一个DAC输出波形的方法。通过一个全局变量来判断,输出的波形是锯齿波还是方波。</p>

<pre>
<code class="language-cpp">void DAC_Wave(char wavetype)
{
      static int value=0;
      if(wavetype==1)      R_DAC_Write(&amp;g_dac0_ctrl, value);//锯齿波
      if(wavetype==2)      R_DAC_Write(&amp;g_dac0_ctrl, value &gt; 2050 ? 4095 : 0);//方波
      value=value+20;
      if(value&gt;=4095) value=0;
}</code></pre>

<p>然后启动一个新菜单,通过键盘与用户交互,可以选择熟人波形类型,或者读写flash。这里使用了汉字输出,但在串口终端上实际输出的效果不太好,汉字的最后部分总是显示不全。</p>

<pre>
<code>
test_fn follow_me(void)
{
    int8_t c = -1;
    uint16_t buffer;
    sprintf (s_print_buffer, "%s%s", gp_clear_screen, gp_cursor_home);
    print_to_console ((void*) s_print_buffer);            //清屏

    sprintf (s_print_buffer, "%s", "波形控制:\r\n1:三角波\r\n2:方波\r\nr: 从flash存储读取\r\nw: 写入到flash存储\r\n");
    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;
      }
      if (0 != c)
      {
            /* Cast, as compiler will assume calc is int */
            sprintf (s_print_buffer, "select %c \r\n", c);
            print_to_console ((void*) s_print_buffer);
            if ('1' == c)
                wavetype = 1;          //输入1 选择三角波
            if ('2' == c)
                wavetype = 2;          //输入2 选择方波
            if ('r' == c)         //输入r 读取保存的参数
            {
                readFromFlash (buffer);
                sprintf (s_print_buffer, "read from buf %d \r\n", buffer);
                print_to_console ((void*) s_print_buffer);
//                if (buffer == '1' || buffer == '2')
                wavetype = buffer;
            }
            if ('w' == c)             //输入w 保存方波类型参数
            {
                buffer = wavetype;
                saveToFlash (buffer);
            }
      }
    }

    xEventGroupClearBits (g_update_console_event, STATUS_DISPLAY_MENU_KIS);
    return (0);
}</code></pre>

<p>最后添加两个函数,用来读写flash。因为需要写入和读取的数据只有一个波形类型的数据,只需要一个整形数据即可。</p>

<pre>
<code>
void saveToFlash(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;
//    err = R_QSPI_Open(&amp;g_qspi_ctrl, &amp;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 (&amp;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;
    }

    err = R_QSPI_Write (&amp;g_qspi_ctrl, &amp;buffer, p_mem_addr, 1);
    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");
      }
    }

//    err = R_QSPI_Close(&amp;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);
}
void readFromFlash(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;
    /* 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 (&amp;buffer, p_mem_addr, 1);
    deinit_qspi (current_spi_mode);
}</code></pre>

<p style="text-align: center;"> &nbsp;</p>

<p style="text-align: center;"> &nbsp;</p>

<p style="text-align: center;"> &nbsp;</p>

<div><br />
<br />
<br />
<br />
&nbsp;</div>

<hr />
<p><strong>心得体会:</strong>非常开心参加Follow me活动,这次活动推出的瑞萨的EK-RA6M5开发板功能超级强悍。但与此同时,掌握开发板的开发方法也相当的困难。好在有老师在视频课中事无巨细地耐心讲解,通过反复观看老师的视频,总算是入门了这块开发板,但是远远没有能发挥出这块开发板的能力,期待着后续看到各位老师优秀的作品。</p>
页: [1]
查看完整版本: 【Follow me第二季第3期】EK-RA6M5任务提交