91|0

3

帖子

1

TA的资源

一粒金砂(中级)

楼主
 

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

  本帖最后由 鱼豆腐车仔面 于 2024-12-15 15:53 编辑

从收到开发板到完成任务已经一个月了,终于完成了所有的任务,这次是我第一次参加Follow me的活动,我觉得这真是个很好的活动,为我这种想学习嵌入式的人提供了一个机会。这一期的开发板是瑞萨的RA6M5系列的开发板,版上集成度相当高,各种接口、存储器都有,相信以后还能用在其他的地方。另外,还要感谢论坛和得捷电子提供的机会,让我可以有机会参加这样的项目

 

 

项目任务汇总视频


这个项目的任务主要有七个,分别是:

(1)例程的演示

(2)Blink与按键的演示

(3)QSPI的配置与Quad Flash的测速

(4)OSPI的配置与Octa Flash的测速

(5)DAC的配置与性能测试

(6)命令接收与菜单打印

(7)信号发生器的实现

 

所有的项目都在视频里进行展示:

 

 

 

物料展示


这次能够购买的物料仅有开发板本体,任务所需的全部功能均使用开发板上的器件完成

 
 

 

 

 

任务成果展示


 

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


开发环境

RA6M5使用瑞萨的e2studio进行开发,使用官方的IDE,可以很方便地通过图形化的界面完成时钟树、引脚功能、中断、ELC事件、各种模块栈的配置,类似于CubeMX。而且借助于FSP库,通过调用API接口,能快速完成任务的需求。

    

 

1.新建项目时,选择对应的开发板编号或MCU编号,是否使用RTOS,是否打开TrustZone等选项,完成项目的建立

2.在FSP Configuration图形化配置界面,根据所需的功能,添加对应的模块

3.在编写程序时调用对应的FSP库API接口,快速完成程序的编写

 

下载调试示例程序

官方的示例程序可以在Github上面下载到,

链接已隐藏,如需查看请登录或者注册

打开实例程序项目后,首先在FSP Configuration界面点击生成项目文件,IDE会根据所选择的配置生成对应的源文件和头文件,然后点击编译与烧录,即可将程序烧录到片上

 

写入程序后,打开IDE的终端,使用附带的USB将开发板与电脑连接,通过串口完成交互

 

通过串口发送命令,可以做到:

(1)查看开发板状态

(2)打开Web服务器,使用网线连接到路由器之后,可以在浏览器打开对应的页面

(3)获取开发板的IP地址,并Ping“www.renesas.com"

(4)Flash读写时间对比

 

并且在开发板上,通过两个用户按键,可以切换板载LED的亮度以及闪烁频率

 

 

Blink与按键

通过按键控制板载LED的开关,这个任务非常简单,只需要查看电路图找到LED和开关对应的引脚就可以了,查看图纸可知用户按键1对应P005,LED对应P006

 

 

创建一个空白工程,在图形化配置页面完成IO口的配置

 

 

程序代码如下:

void hal_entry(void)
{
    /* TODO: add your own code here */

    bsp_io_level_t state;

    while (1)
    {
        R_IOPORT_PinRead (&g_ioport_ctrl, BSP_IO_PORT_00_PIN_06, &state); //读取LED1端口状态
        if (Key_Scan (BSP_IO_PORT_00_PIN_05) == 1) //扫描按键
        {
            if (state == BSP_IO_LEVEL_HIGH) //电平翻转
            {
                R_IOPORT_PinWrite (&g_ioport_ctrl, BSP_IO_PORT_00_PIN_06, BSP_IO_LEVEL_LOW);
            }
            else
            {
                R_IOPORT_PinWrite (&g_ioport_ctrl, BSP_IO_PORT_00_PIN_06, BSP_IO_LEVEL_HIGH);
            }

        }
    }

}

//按键扫描函数
uint32_t Key_Scan(bsp_io_port_pin_t pin)
{
    bsp_io_level_t state;

    R_IOPORT_PinRead(&g_ioport_ctrl, pin, &state);

    if(state == BSP_IO_LEVEL_HIGH)
    {
        return NG;//按键没有被按下
    }
    else
    {
        do//直到没有按下按键后才跳出循环
        {
            R_IOPORT_PinRead(&g_ioport_ctrl, pin, &state);
        }while(state == BSP_IO_LEVEL_LOW);
    }
    return EN;//按键被按下
}

 

基础任务一:Quad-SPI Flash配置与读写测速


任务中使用到的Flash是来自MACRONIX的MX25L25645G Quad-SPI Flash,芯片容量32MB,Flash的手册也一并附上。
MX25L25645G, 3V, 256Mb, v2.0.pdf (1.84 MB, 下载次数: 0)

 

QSPI使用六线与Flash连接,分别是片选线、时钟线以及四条数据线。SPI一个时钟周期只能发送接收1位的数据,发送1字节数据需要8个时钟周期,QSPI可以在1个时钟周期发送4位数据,2个时钟周期就可以发送1字节的数据,提高了传输的速度。
 
QSPI能够工作在多种模式下,在不同模式下的命令阶段、地址阶段和数据阶段传输的位数不一样,需要根据实际情况进行调整。
而且QSPI的工作模式要与Flash芯片的模式相对应,如果QSPI处于QPI模式时,则无法与处于extended-SPI模式的Flash芯片进行通讯。
注意,Flash在重新上电后是处于extended-SPI模式的,需要将QSPI的工作模式改为extended-SPI模式后,对Flash的寄存器进行配置,将Flash设置为QPI模式,才能在QPI模式下进行读写。

 

这个任务的大致思路是:

(1)将Flash设置为QPI模式,因为Flash在重新上电后是处于extended-SPI模式的,需要先改变QSPI的协议,完成Flash的设置后,再将QSPI的协议改回来;

(2)准备好256字节的数据,写入到Flash芯片中;

(3)使用定时器计算Flash读写时所需的时间,然后根据读写的数据量与时间,计算出Quad-SPI Flash读写的速度。

 

流程图:

 
代码:
void qspi_test(void)
{
    /* TODO: add your own code here */

    //写入与读取缓存
    uint8_t data_write[PAGE_SIZE_QSPI] = {0};
    uint8_t data_read[PAGE_SIZE_QSPI] = {0};

    //写入flash的status与configuration寄存器的数值,以及读写的地址
    uint8_t data_sreg[3] = {WRSR, STATUS_REGISTER_CONTENT, CONFIG_REGISTER_CONTENT};
    uint8_t *p_mem_addr = (uint8_t*)FLASH_START_ADDRESS;

    //计时器状态结构体
    timer_status_t timer_status_write;
    timer_status_t timer_status_read;

    fsp_err_t err = FSP_SUCCESS;

    APP_PRINT("This is a QSPI test program\r\n");

    R_GPT_Open(&g_timer_performance_ctrl, &g_timer_performance_cfg);//开启计数器

    //若qspi设置为QPI模式,则改为extend qspi模式
    if(SPI_FLASH_PROTOCOL_QPI == g_qspi0_cfg.spi_protocol)
    {
        spi_flash_cfg_t temp_qspi0_cfg;
        memcpy((spi_flash_cfg_t *)&temp_qspi0_cfg, (spi_flash_cfg_t *)&g_qspi0_cfg, sizeof(spi_flash_cfg_t));
        temp_qspi0_cfg.spi_protocol = SPI_FLASH_PROTOCOL_EXTENDED_SPI;

        APP_PRINT("The default set of QSPI is QPI mode\r\n");
        err = R_QSPI_Open(&g_qspi0_ctrl, &temp_qspi0_cfg);
        if(FSP_SUCCESS != err)
        {
            APP_ERR_PRINT("QSPI open failed.\r\n");
            APP_ERR_TRAP(err);
        }
    }
    else//如qspi设置为extend qspi模式,则直接启动
    {
        APP_PRINT("The default set of QSPI is extended-SPI mode\r\n\r\n");
        err = R_QSPI_Open(&g_qspi0_ctrl, &g_qspi0_cfg);
        if(FSP_SUCCESS != err)
        {
            APP_ERR_PRINT("QSPI open failed.\r\n");
            APP_ERR_TRAP(err);
        }
    }

    //设置Flash的状态寄存器(status register)与配置寄存器(configuration register)
    err = R_QSPI_DirectWrite(&g_qspi0_ctrl, &g_qspi0_cfg.write_enable_command, 1, false);
    if(FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Flash write enable failed\r\n");
        APP_ERR_TRAP(err);
    }
    err = get_flash_status();
    if(FSP_SUCCESS != err)
    {
        APP_PRINT("Can't get flash status\r\n");
    }

    //将设定值写入status寄存器
    err = R_QSPI_DirectWrite(&g_qspi0_ctrl, data_sreg, 3, false);
    if(FSP_SUCCESS != err)
       {
           APP_ERR_PRINT("Flash write register failed\r\n");
           APP_ERR_TRAP(err);
       }
    get_flash_status();

    //检查寄存器的值(status register)
    uint8_t _register_data = 0;
    err = R_QSPI_DirectWrite(&g_qspi0_ctrl, &g_qspi0_cfg.status_command, 1, true);

    err = R_QSPI_DirectRead(&g_qspi0_ctrl, &_register_data, 1);
    if(FSP_SUCCESS != err)
           {
               APP_ERR_PRINT("Flash write register failed\r\n");
               APP_ERR_TRAP(err);
           }
    get_flash_status();

    if(_register_data !=0x40)
    {
        APP_ERR_PRINT("The status register can't be set correctly.\r\n");
        APP_ERR_TRAP(err);
    }

    //如果一开始设置为QPI模式,现在将MCU与Flash恢复成QPI
    if(g_qspi0_cfg.spi_protocol == SPI_FLASH_PROTOCOL_QPI)
    {
        uint8_t data = OPEN_FLASH_QPI;
        err = R_QSPI_DirectWrite(&g_qspi0_ctrl, &g_qspi0_cfg.write_enable_command, 1, false);
        if(FSP_SUCCESS != err)
            {
                APP_ERR_PRINT("Flash write enable failed\r\n");
                APP_ERR_TRAP(err);
            }
        get_flash_status();

        //设置Flash为QPI模式
        err = R_QSPI_DirectWrite(&g_qspi0_ctrl, &data, 1, false);
        if(FSP_SUCCESS != err)
            {
                APP_ERR_PRINT("Flash set qpi mode failed\r\n");
                APP_ERR_TRAP(err);
            }

        err = R_QSPI_SpiProtocolSet(&g_qspi0_ctrl, SPI_FLASH_PROTOCOL_QPI);
        if(FSP_SUCCESS != err)
            {
                APP_ERR_PRINT("QSPI protocol change failed\r\n");
                APP_ERR_TRAP(err);
            }
    }

    //准备写入数据
    for (uint16_t index = 0; index < PAGE_SIZE_QSPI; index++)
    {
        data_write[index] = (uint8_t) index;
    }

    //开始计时
    err = R_GPT_Start(&g_timer_performance_ctrl);
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Timer start failed\r\n");
        flash_quit_qpi ();
        APP_ERR_TRAP(err);
    }

    //擦除一个扇区
    err = R_QSPI_Erase(&g_qspi0_ctrl, p_mem_addr, 4096U);
    if(FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Flash erase failed\r\n");
        flash_quit_qpi();
        APP_ERR_TRAP(err);
    }
    get_flash_status();


    //写入数据
    err = R_QSPI_Write(&g_qspi0_ctrl, data_write, p_mem_addr, PAGE_SIZE_QSPI);

    if(FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Flash program failed\r\n");
        flash_quit_qpi();
        APP_ERR_TRAP(err);
    }
    get_flash_status();

    err = R_GPT_Stop(&g_timer_performance_ctrl);//结束计时
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Timer stop failed\r\n");
        flash_quit_qpi ();
        APP_ERR_TRAP(err);
    }
    R_GPT_StatusGet (&g_timer_performance_ctrl, &timer_status_write);
    R_GPT_Reset (&g_timer_performance_ctrl);

    err = R_GPT_Start(&g_timer_performance_ctrl);
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Timer start failed\r\n");
        flash_quit_qpi ();
        APP_ERR_TRAP(err);
    }

    //读取Flash数据,地址为0x60000000
    memcpy(data_read,p_mem_addr,PAGE_SIZE_QSPI);

    err = R_GPT_Stop (&g_timer_performance_ctrl); //结束计时
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Timer stop failed\r\n");
        flash_quit_qpi ();
        APP_ERR_TRAP(err);
    }

    R_GPT_StatusGet (&g_timer_performance_ctrl, &timer_status_read);
    R_GPT_Reset (&g_timer_performance_ctrl);

    flash_quit_qpi (); //Flash退出QPI模式
    R_QSPI_Close (&g_qspi0_ctrl); //关闭qspi

    //打印从flash读取的内容
    APP_PRINT("The data written to the flash is:\r\n");

   for(uint16_t column = 0; column<16;column++)
    {
        for(uint16_t row = 0; row<16;row++)
        {
            APP_PRINT("%4d",data_read[row+16*column]);
            R_BSP_SoftwareDelay(50, BSP_DELAY_UNITS_MICROSECONDS);
        }
        APP_PRINT("\r\n");
    }
   APP_PRINT("\r\n");


   //因RTT_viewer不能打印浮点类型数据,所以将浮点型用两个整型分别表示整数与小数点后部分
   uint16_t WR_int;
   uint16_t WR_dec;
   uint16_t RE_int;
   uint16_t RE_dec;

   float temp_speed;

   temp_speed = 250000000 / (10 * (float)timer_status_write.counter);
   WR_int = (uint16_t) temp_speed;
   WR_dec = (uint16_t) ((temp_speed - WR_int) * 100);

   temp_speed = 250000000 / (10 * (float)timer_status_read.counter);
   RE_int = (uint16_t) temp_speed;
   RE_dec = (uint16_t) ((temp_speed - RE_int) * 100);

   APP_PRINT("Write speed: %d.%d KB/s.\r\n", WR_int, WR_dec);
   APP_PRINT("Read speed: %d.%d KB/s.\r\n", RE_int, RE_dec);
   APP_PRINT("\r\n\r\n");
}





/*Flash退出QPI模式*/
void flash_quit_qpi(void)
{
    uint8_t data = CLOSE_FLASH_QPI;
    R_QSPI_DirectWrite(&g_qspi0_ctrl, &data, 1, false);
}


//获取Flash读写状态
fsp_err_t get_flash_status(void)
{
    spi_flash_status_t status = {.write_in_progress = true};
    volatile uint16_t time_out          = (0xFFFF);
    fsp_err_t err             = FSP_SUCCESS;

    do
    {
        /* Get status from QSPI flash device */
        err = R_QSPI_StatusGet(&g_qspi0_ctrl, &status);
        if (FSP_SUCCESS!= err)
        {
            return err;
        }

        /* Decrement time out to avoid infinite loop in case of consistent failure */
        --time_out;

        if ( 0 >= time_out)
        {
            return FSP_ERR_TIMEOUT;
        }

    }while (false != status.write_in_progress);

    return err;
}

 

读写速度测试结果:

 
 
基础任务二:Octa-SPI Flash配置与读写测速

任务中使用到的Octa-SPI Flash如下图,型号为MX25LM51245G,该Flash容量为64MB。

MX25LM51245G, 3V, 512Mb, v1.1.pdf (1.22 MB, 下载次数: 0)

 

 

程序思路大致与Quad-SPI Flash的一样,只是Octa-SPI的配置相对复杂,需要使用一个结构体去写入和读取数据,如下:

spi_flash_direct_transfer_t g_ospi_direct_transfer [OSPI_COMMAND_MAX] =
{
    [OSPI_COMMAND_WRITE_ENABLE_SPI_MODE] =
    {
    .command        = OSPI_WRITE_ENABLE_COMMAND_SPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_ONE,
    .address_length = LENGTH_ZERO,
    .data_length    = LENGTH_ZERO,
    .dummy_cycles   = LENGTH_ZERO
    },
    [OSPI_COMMAND_WRITE_DISABLE_SPI_MODE] =
    {
    .command        = OSPI_WRITE_DISABLE_COMMAND_SPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_ONE,
    .address_length = LENGTH_ZERO,
    .data_length    = LENGTH_ZERO,
    .dummy_cycles   = LENGTH_ZERO
    },
    [OSPI_COMMAND_READ_STATUS_SPI_MODE] =
    {
    .command        = OSPI_READ_STATUS_COMMAND_SPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_ONE,
    .address_length = LENGTH_ZERO,
    .data_length    = LENGTH_ONE,
    .dummy_cycles   = LENGTH_ZERO
    },
    [OSPI_COMMAND_SECTOR_ERASE_SPI_MODE] =
    {
    .command        = OSPI_ERASE_COMMAND_SECTOR_SPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_ONE,
    .address_length = LENGTH_FOUR,
    .data_length    = LENGTH_ZERO,
    .dummy_cycles   = LENGTH_ZERO
    },
    [OSPI_COMMAND_SECTOR_ERASE_3SPI_MODE] =
    {
    .command        = OSPI_ERASE_COMMAND_SECTOR_3SPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_ONE,
    .address_length = LENGTH_THREE,
    .data_length    = LENGTH_ZERO,
    .dummy_cycles   = LENGTH_ZERO
    },
    [OSPI_COMMAND_BLOCK_ERASE_SPI_MODE] =
    {
    .command        = OSPI_ERASE_COMMAND_BLOCK_SPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_ONE,
    .address_length = LENGTH_FOUR,
    .data_length    = LENGTH_ZERO,
    .dummy_cycles   = LENGTH_ZERO
    },
    [OSPI_COMMAND_BLOCK_ERASE_3SPI_MODE] =
    {
    .command        = OSPI_ERASE_COMMAND_BLOCK_3SPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_ONE,
    .address_length = LENGTH_THREE,
    .data_length    = LENGTH_ZERO,
    .dummy_cycles   = LENGTH_ZERO
    },
    [OSPI_COMMAND_WRITE_CR2_SPI_MODE] =
    {
    .command        = OSPI_COMMAND_WCR2_SPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_ONE,
    .address_length = LENGTH_FOUR,
    .data_length    = LENGTH_ONE,
    .dummy_cycles   = LENGTH_ZERO
    },
    [OSPI_COMMAND_WRITE_CR2_3SPI_MODE] =
    {
    .command        = OSPI_COMMAND_WCR2_SPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_ONE,
    .address_length = LENGTH_FOUR,
    .data_length    = LENGTH_ONE,
    .dummy_cycles   = LENGTH_ZERO
    },
    [OSPI_COMMAND_WRITE_CR2_OPI_MODE] =
    {
    .command        = OSPI_COMMAND_WCR2_OPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_TWO,
    .address_length = LENGTH_FOUR,
    .data_length    = LENGTH_ONE,
    .dummy_cycles   = LENGTH_ZERO
    },

    [OSPI_COMMAND_READ_CR2_SPI_MODE] =
    {
    .command        = OSPI_COMMAND_RCR2_SPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_ONE,
    .address_length = LENGTH_FOUR,
    .data_length    = LENGTH_ONE,
    .dummy_cycles   = LENGTH_ZERO
    },
    [OSPI_COMMAND_READ_CR2_3SPI_MODE] =
    {
    .command        = OSPI_COMMAND_RCR2_SPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_ONE,
    .address_length = LENGTH_FOUR,
    .data_length    = LENGTH_ONE,
    .dummy_cycles   = LENGTH_ZERO
    },
    [OSPI_COMMAND_READ_CR2_OPI_MODE] =
    {
    .command        = OSPI_COMMAND_RCR2_OPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_TWO,
    .address_length = LENGTH_FOUR,
    .data_length    = LENGTH_ONE,
    .dummy_cycles   = LENGTH_FOUR
    },
    [OSPI_COMMAND_WRITE_ENABLE_OPI_MODE] =
    {
    .command        = OSPI_WRITE_ENABLE_COMMAND_OPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_TWO,
    .address_length = LENGTH_ZERO,
    .data_length    = LENGTH_ZERO,
    .dummy_cycles   = LENGTH_ZERO
    },
    [OSPI_COMMAND_WRITE_DISABLE_OPI_MODE] =
    {
    .command        = OSPI_WRITE_DISABLE_COMMAND_OPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_TWO,
    .address_length = LENGTH_ZERO,
    .data_length    = LENGTH_ZERO,
    .dummy_cycles   = LENGTH_ZERO
    },
    [OSPI_COMMAND_SECTOR_ERASE_OPI_MODE] =
    {
    .command        = OSPI_ERASE_COMMAND_SECTOR_OPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_TWO,
    .address_length = LENGTH_FOUR,
    .data_length    = LENGTH_ZERO,
    .dummy_cycles   = LENGTH_ZERO
    },
    [OSPI_COMMAND_BLOCK_ERASE_OPI_MODE] =
    {
    .command        = OSPI_ERASE_COMMAND_BLOCK_OPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_TWO,
    .address_length = LENGTH_FOUR,
    .data_length    = LENGTH_ZERO,
    .dummy_cycles   = LENGTH_ZERO
    },
    [OSPI_COMMAND_READ_STATUS_OPI_MODE] =
    {
    .command        = OSPI_READ_STATUS_COMMAND_OPI_MODE,
    .address        = OSPI_CR2_ADDRESS_HEX_0,
    .data           = OSPI_CR2_DATA_HEX_00,
    .command_length = LENGTH_TWO,
    .address_length = LENGTH_FOUR,
    .data_length    = LENGTH_ONE,
    .dummy_cycles   = LENGTH_FOUR
    }
};

每当要对Flash芯片的寄存器进行读写操作时,就要用到上面这个结构体数组,通过调用数组中的不同元素,完成Flash芯片寄存器的读写操作。

另外,OSPI在extended-SPI模式与OSPI模式下,所用到外设时钟频率和dummy cycles也不一样,具体需要查看用户手册对应章节。

 

代码:

#include "common_utils.h"
#include "ospi_commands.h"
#include "ospi.h"

spi_flash_cfg_t local_ospi0_cfg = {RESET_VALUE};
ospi_extended_cfg_t local_ospi0_extend_cfg = {RESET_VALUE};

extern spi_flash_direct_transfer_t        g_ospi_direct_transfer[OSPI_COMMAND_MAX];

void ospi_dopi_test(void)
{

    APP_PRINT("This is an OSPI test program\r\n");
    APP_PRINT("OSPI will be set from extended-SPI mode to DOPI mode\r\n");

    fsp_err_t err = FSP_SUCCESS;

    uint8_t data_write[PAGE_SIZE] = { RESET_VALUE };
    uint8_t data_read[PAGE_SIZE] = { RESET_VALUE };

    bsp_octaclk_settings_t octaclk = { RESET_VALUE };

    uint8_t *p_mem_addr = (uint8_t*) 0x70000000;

    timer_status_t write_status = { RESET_VALUE };
    timer_status_t read_status = { RESET_VALUE };

    R_GPT_Open (&g_timer_performance_ctrl, &g_timer_performance_cfg);

	//重置Flash芯片
    flash_reset ();

    //设置OSPI外设时钟为50MHz,对应extended spi模式
    octaclk.source_clock = BSP_CFG_OCTA_SOURCE; /* 200MHz */
    octaclk.divider = BSP_CLOCKS_OCTA_CLOCK_DIV_2;
    R_BSP_OctaclkUpdate (&octaclk);

    //打开OSPI及协议调整
    err = ospi_init ();
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("OSPI init failed\r\n");
        APP_ERR_TRAP(err);
    }
    
	//Flash芯片寄存器配置
    err = flash_configure ();

    //设置OSPI外设时钟为100MHz,对应DOPI模式
    octaclk.source_clock = BSP_CFG_OCTA_SOURCE; /* 200MHz */
    octaclk.divider = BSP_CLOCKS_OCTA_CLOCK_DIV_1;
    R_BSP_OctaclkUpdate (&octaclk);

    err = ospi_spi_to_dopi ();
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Setting extended-SPI mode to DOPI mode failed\r\n");
        APP_ERR_TRAP(err);
    }

    //准备写入的数据
    for (uint16_t index = 0; index < PAGE_SIZE; index++)
    {
        data_write[index] = (uint8_t) index;
    }

    //开始计时
    err = R_GPT_Start (&g_timer_performance_ctrl);
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Start counting failed\r\n");
        APP_ERR_TRAP(err);
    }
    //擦除一个扇区
    err = R_OSPI_Erase (&g_ospi0_ctrl, p_mem_addr, 4096U);
    wait_operation ();

    //写入数据
    err = R_OSPI_Write (&g_ospi0_ctrl, data_write, p_mem_addr, PAGE_SIZE);
    wait_operation ();
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Flash writing failed\r\n");
        APP_ERR_TRAP(err);
    }

    //结束计时并读出写入时间
    R_GPT_Stop (&g_timer_performance_ctrl);
    R_GPT_StatusGet (&g_timer_performance_ctrl, &write_status);
    R_GPT_Reset (&g_timer_performance_ctrl);

    /****************************************************************************/

    err = R_GPT_Start (&g_timer_performance_ctrl); //开始计时
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Start counting failed\r\n");
        APP_ERR_TRAP(err);
    }

    //从闪存芯片读取
    memcpy (data_read, p_mem_addr, PAGE_SIZE);

    //结束计时
    R_GPT_Stop (&g_timer_performance_ctrl);
    R_GPT_StatusGet (&g_timer_performance_ctrl, &read_status);
    R_GPT_Reset (&g_timer_performance_ctrl);

    R_OSPI_Close(&g_ospi0_ctrl);//关闭ospi

    //打印读取内容
    APP_PRINT("The data written to the flash is:\r\n");
    for (uint16_t column = 0; column < 16; column++)
    {
        for (uint16_t row = 0; row < 16; row++)
        {
            APP_PRINT("%4d", data_read[row + 16 * column]);
            R_BSP_SoftwareDelay (50, BSP_DELAY_UNITS_MICROSECONDS);
        }
        APP_PRINT("\r\n");
    }
    APP_PRINT("\r\n");

    //因RTT_viewer不能打印浮点类型数据,所以将浮点型用两个整型分别表示整数与小数点后部分
       uint16_t WR_int;
       uint16_t WR_dec;
       uint16_t RE_int;
       uint16_t RE_dec;

       float temp_speed;

       temp_speed = 250000000 / (10 * (float)write_status.counter);
       WR_int = (uint16_t) temp_speed;
       WR_dec = (uint16_t) ((temp_speed - WR_int) * 100);

       temp_speed = 250000000 / (10 * (float)read_status.counter);
       RE_int = (uint16_t) temp_speed;
       RE_dec = (uint16_t) ((temp_speed - RE_int) * 100);

       APP_PRINT("Write speed: %d.%d KB/s.\r\n", WR_int, WR_dec);
       APP_PRINT("Read speed: %d.%d KB/s.\r\n", RE_int, RE_dec);
       APP_PRINT("\r\n\r\n");
}

//Flash芯片重置
void flash_reset(void)
{
    R_IOPORT_PinWrite (&g_ioport_ctrl, RESET_PIN, BSP_IO_LEVEL_LOW);
    R_BSP_SoftwareDelay (DELAY_TIME, BSP_DELAY_UNITS_MICROSECONDS);
    R_IOPORT_PinWrite (&g_ioport_ctrl, RESET_PIN, BSP_IO_LEVEL_HIGH);
    R_BSP_SoftwareDelay (DELAY_TIME, BSP_DELAY_UNITS_MICROSECONDS);
}

//打开OSPI以及协议配置调整
fsp_err_t ospi_init(void)
{
    fsp_err_t err = FSP_SUCCESS;

    ospi_extended_cfg_t *p_temp = NULL;

    p_temp = (void *)g_ospi0_cfg.p_extend;
    local_ospi0_extend_cfg = *p_temp;

    //修改local_ospi0_cfg的配置
    local_ospi0_cfg = g_ospi0_cfg;

    local_ospi0_cfg.p_extend = &local_ospi0_extend_cfg;
    local_ospi0_cfg.p_erase_command_list = &spi_erase_command_list[INITIAL_INDEX];
    local_ospi0_cfg.spi_protocol = SPI_FLASH_PROTOCOL_EXTENDED_SPI;

    err = R_OSPI_Open(&g_ospi0_ctrl, &local_ospi0_cfg);
    if(FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Open ospi failed\r\n");
        APP_ERR_TRAP(err);
    }


    return err;
}

//设置flash芯片,对应extended-spi模式
fsp_err_t flash_configure(void)
{
    fsp_err_t err = FSP_SUCCESS;

    spi_flash_direct_transfer_t ospi_transfer_struct =
    {
      .command = OSPI_COMMAND_WCR2_SPI_MODE,
      .address = OSPI_CR2_ADDRESS_HEX_0,
      .data = OSPI_CR2_DATA_HEX_00,
      .command_length = LENGTH_ONE,
      .address_length = LENGTH_FOUR,
      .data_length = LENGTH_ONE,
      .dummy_cycles = LENGTH_ZERO
    };

    err = flash_write_enable();
    //打开flash的extended spi 模式
    err = R_OSPI_DirectTransfer(&g_ospi0_ctrl, &ospi_transfer_struct, SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE);
    if(FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Open extended spi mode failed\r\n");
        APP_ERR_TRAP(err);
    }

    //设置dummy cycles
    ospi_transfer_struct.address = OSPI_CR2_ADDRESS_HEX_300;
    ospi_transfer_struct.data = OSPI_CR2_DATA_HEX_07;

    err = flash_write_enable();
    err = R_OSPI_DirectTransfer(&g_ospi0_ctrl, &ospi_transfer_struct, SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE);
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Changing Flash's dummy cycles in spi mode failed\r\n");
        APP_ERR_TRAP(err);
    }

    return err;
}

//将外设与flash芯片都设置为DOPI模式
fsp_err_t ospi_spi_to_dopi(void)
{
    fsp_err_t err = FSP_SUCCESS;

    //修改ospi配置变量
    local_ospi0_cfg.p_erase_command_list = &opi_erase_command_list[INITIAL_INDEX];
    local_ospi0_cfg.spi_protocol = SPI_FLASH_PROTOCOL_DOPI;

    err = flash_write_enable();
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Write enable failed\r\n");
        APP_ERR_TRAP(err);
    }
    //修改DQS
    g_ospi_direct_transfer[OSPI_COMMAND_WRITE_CR2_SPI_MODE].address = OSPI_CR2_ADDRESS_HEX_200;
    g_ospi_direct_transfer[OSPI_COMMAND_WRITE_CR2_SPI_MODE].data = OSPI_CR2_DATA_HEX_00;
    err = R_OSPI_DirectTransfer (&g_ospi0_ctrl, &g_ospi_direct_transfer[OSPI_COMMAND_WRITE_CR2_SPI_MODE],
                                 SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE);
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Setting DQS failed\r\n");
        APP_ERR_TRAP(err);
    }
/***************************************************************************/
    err = flash_write_enable ();
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Write enable failed\r\n");
        APP_ERR_TRAP(err);
    }
    //修改dummy cycles
    g_ospi_direct_transfer[OSPI_COMMAND_WRITE_CR2_SPI_MODE].address = OSPI_CR2_ADDRESS_HEX_300;
    g_ospi_direct_transfer[OSPI_COMMAND_WRITE_CR2_SPI_MODE].data = OSPI_CR2_DATA_HEX_05;

    err = R_OSPI_DirectTransfer (&g_ospi0_ctrl, &g_ospi_direct_transfer[OSPI_COMMAND_WRITE_CR2_SPI_MODE],
                                 SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE);
    if (FSP_SUCCESS != err)
        {
            APP_ERR_PRINT("Setting dummy cycles failed\r\n");
            APP_ERR_TRAP(err);
        }

/*****************************************************************************/
    err = flash_write_enable ();
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Write enable failed\r\n");
        APP_ERR_TRAP(err);
    }
    //打开DOPI模式
    g_ospi_direct_transfer[OSPI_COMMAND_WRITE_CR2_SPI_MODE].address = OSPI_CR2_ADDRESS_HEX_0;
    g_ospi_direct_transfer[OSPI_COMMAND_WRITE_CR2_SPI_MODE].data = OSPI_CR2_DATA_HEX_02;

    err = R_OSPI_DirectTransfer (&g_ospi0_ctrl, &g_ospi_direct_transfer[OSPI_COMMAND_WRITE_CR2_SPI_MODE],
                                     SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE);
    if (FSP_SUCCESS != err)
        {
            APP_ERR_PRINT("Setting DOPI mode failed\r\n");
            APP_ERR_TRAP(err);
        }

    err = R_OSPI_SpiProtocolSet(&g_ospi0_ctrl, SPI_FLASH_PROTOCOL_DOPI);

    err = R_OSPI_Close(&g_ospi0_ctrl);

    err = R_OSPI_Open(&g_ospi0_ctrl, &local_ospi0_cfg);

    err = R_OSPI_SpiProtocolSet(&g_ospi0_ctrl, SPI_FLASH_PROTOCOL_DOPI);


    return err;
}



fsp_err_t flash_write_enable(void)
{
    fsp_err_t err = FSP_SUCCESS;

    if(SPI_FLASH_PROTOCOL_EXTENDED_SPI == g_ospi0_ctrl.spi_protocol)
    {
        err = R_OSPI_DirectTransfer(&g_ospi0_ctrl, &g_ospi_direct_transfer[OSPI_COMMAND_WRITE_ENABLE_SPI_MODE], SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE);
        return err;
    }
    else
    {
        err = R_OSPI_DirectTransfer(&g_ospi0_ctrl, &g_ospi_direct_transfer[OSPI_COMMAND_WRITE_ENABLE_OPI_MODE], SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE);
        return err;
    }

}

void wait_operation(void)
{
    uint32_t timeout         = UINT32_MAX;
    spi_flash_status_t status;
    status.write_in_progress = true;

    while ((status.write_in_progress) && (--timeout > RESET_VALUE))
    {
        R_OSPI_StatusGet(&g_ospi0_ctrl, &status);
    }
    /*check if timeout occured*/
    if(timeout == RESET_VALUE)
    {
        APP_PRINT("Timeout Occurred");
    }
}

 

读写速度测试结果:

 
 
基础任务三:DAC配置生成波形与性能测试

RA6M5配备了一个双通道的12位DA模块,通过该模块,可以输出0-3.3V的电压信号。

 

程序思路:

(1)通过定时器溢出中断触发DAC输出值更新,保证DAC有精确的采样频率

(2)由于没有示波器,需要用ADC去测量DAC的输出电压值,所以也使用定时器溢出中断去触发ADC采样,保证ADC的采样率

(3)配置输出波形的频率、幅值、偏置,以及DAC的采样频率(通过调整定时器周期实现),去测试DAC的性能

(4)由于没有示波器,使用SEGGER J-Scope去查看ADC采集的波形

 

所需的模块:

(1)GPT定时器

(2)DAC

(3)ADC

 

流程图:

 
为了固定ADC和DAC的采样频率,要用到定时器的溢出中断,需要事先配置好定时器的通道、周期、对应的中断回调函数和中断优先等级

 

代码:

#include "ad_da.h"
#include "qspi.h"

#define M_PI        3.14159265358979323846

uint16_t wave;

//波形生成参数
uint32_t index=0;
uint16_t frequency = 1;
uint16_t amplitude = 0;
uint16_t offset = 0;
uint32_t sample_rate = DAFAULT_SAMPLE_RATE;
uint32_t sample_num = 0;

//切换波形
uint8_t waveform_change = 0;

//ADC完成转换标志
volatile bool adc_complete_flag = false;

void dac_test(void)
{
    uint16_t data = 0;
    bsp_io_level_t state;

    //计算一个周期采样点数
    sample_num = sample_rate / frequency;

    //打开DAC
    R_DAC_Open(&g_dac0_ctrl, &g_dac0_cfg);
    R_DAC_Start(&g_dac0_ctrl);

    //打开DAC采样定时器
    R_GPT_Open (&g_timer_dac_ctrl, &g_timer_dac_cfg);
    R_GPT_Start (&g_timer_dac_ctrl);

    //打开ADC
    R_ADC_Open (&g_adc0_ctrl, &g_adc0_cfg);
    R_ADC_ScanCfg (&g_adc0_ctrl, &g_adc0_channel_cfg);

    //打开ADC采样定时器
    R_GPT_Open (&g_timer_adc_ctrl, &g_timer_adc_cfg);
    R_GPT_Start (&g_timer_adc_ctrl);

    APP_PRINT("\r\nInput the frequency, or input 0 to quit\r\n");
    while(1)
    {
        //输入生成的波形的参数
        data = process_input_data();
        if(data != 0)
        {
            frequency = data;
            APP_PRINT("\r\nThe frequency of sine wave is %d\r\n",frequency);

            APP_PRINT("\r\nInput the amplitude\r\n");
            amplitude = process_input_data();
            APP_PRINT("\r\nThe amplitude of sine wave is %d\r\n",amplitude);

            APP_PRINT("\r\nInput the offset\r\n");
            offset = process_input_data();
            APP_PRINT("\r\nThe offset of sine wave is %d\r\n",offset);

            APP_PRINT("\r\nInput the sample rate\r\n");
            sample_rate = process_input_data ();
            APP_PRINT("\r\nThe sample rate of sine wave is %d\r\n", sample_rate);

            sample_num = sample_rate / frequency;
            R_GPT_PeriodSet(&g_timer_dac_ctrl, (uint32_t)(100000000/sample_rate));


            APP_PRINT("\r\nNow the DAC is running\r\n");
            APP_PRINT("\r\nPress user sw1 to stop DAC\r\n");
            while(1)
            {
                //等待ADC采样完成
                while (!adc_complete_flag)
                {

                }
                R_ADC_Read (&g_adc0_ctrl, ADC_CHANNEL_0, &wave);
                adc_complete_flag = false;

                //按下SW1退出循环
                R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_05, &state);
                if(state == 0)
                {
                    APP_PRINT("\r\nInput the frequency, or input 0 to quit\r\n");
                    break;
                }
            }

        }
        else if(data == 0)
        {
            break;
        }
    }

    //关闭外设
    R_DAC_Close (&g_dac0_ctrl);
    R_ADC_Close (&g_adc0_ctrl);

    R_GPT_Close (&g_timer_dac_ctrl);
    R_GPT_Close (&g_timer_adc_ctrl);

    wave = 0;

}


//DAC更新波形值的中断函数
void timer_dac_callback(timer_callback_args_t *p_args)
{
    FSP_PARAMETER_NOT_USED(p_args);
    index++;
    if(index > sample_num)
    {
        index = 0;
    }
    switch(waveform_change)
    {
        case 0://正弦波
        {
            R_DAC_Write (&g_dac0_ctrl, (uint16_t) (amplitude * sin (2 * M_PI * frequency * index / sample_rate) + offset));
            break;
        }
        case 1://三角波
        {
            R_DAC_Write (&g_dac0_ctrl, (uint16_t) (2*amplitude * asin(sin (2 * M_PI * frequency * index / sample_rate))/M_PI + offset));
            break;
        }
        case 2:
        {
            if(index <= (sample_num/2))
            {
                R_DAC_Write (&g_dac0_ctrl,amplitude+offset);
            }
            else
            {
                R_DAC_Write (&g_dac0_ctrl,-amplitude+offset);
            }
        }
    }


}

//触发ADC开始采样的中断
void timer_adc_callback(timer_callback_args_t *p_args)
{
    FSP_PARAMETER_NOT_USED(p_args);
    R_ADC_ScanStart(&g_adc0_ctrl);

}

//ADC采样完成中断
void adc_callback(adc_callback_args_t *p_args)
{
    FSP_PARAMETER_NOT_USED(p_args);
    adc_complete_flag = true;
}

 

DAC测试结果:

为了使用ADC测量DAC输出电压信号,需要使用到一根杜邦线,将P000引脚与P014引脚相连

调整了波形的参数和DAC的采样率之后,可以看到波形有明显的变化

 
 
进阶任务:命令打印信息

实现了使用菜单进行交互的功能,将QSPI测试、OSPI测试、DAC测试以及信号发生器功能集成到一个菜单里,使用菜单选择不同的功能,进入下一级菜单后,又能选择其他的选项。

主菜单页面
信号发生器菜单页面

程序思路:

在while循环中嵌套多层switch函数,检测输入来进入不同的功能模块,功能模块中也有对应的菜单。功能模块里设置有相应的退出条件,达到退出条件后,就可以返回主菜单并进行下一次的循环。

 

流程图:

 

代码:

主菜单

void hal_entry(void)
{
    /* TODO: add your own code here */

    APP_PRINT("Select the function:\r\n"
            "\r\n"
            "1.QSPI speed test\r\n"
            "2.OSPI speed test\r\n"
            "3.DAC test\r\n"
            "4.signal generator\r\n\r\n\r\n");

    while (1)
    {
        switch (process_input_data ())
        {
            case QSPI_TEST:
            {
                qspi_test ();
                break;
            }

            case OSPI_TEST:
            {
                ospi_dopi_test ();
                break;
            }

            case DAC_TEST:
            {
                dac_test();
                break;
            }

            case SIGNAL_GENERATOR:
            {
                signal_generator();
                break;
            }

            default:
            {
                APP_PRINT("\r\n Invalid input. Provide a valid input\r\n\r\n");
                break;
            }
        }

        APP_PRINT("Select the function:\r\n"
                "\r\n"
                   "1.QSPI speed test\r\n"
                   "2.OSPI speed test\r\n"
                   "3.DAC test\r\n"
                   "4.signal generator\r\n\r\n\r\n");
    }

}

 

DAC测试菜单:

//忽略了前后段的外设配置程序,只展示了菜单的实现部分
DAC_test_menu(void)
{
	while(1)
    {
        data = process_input_data();
        if(data != 0)
        {
			//逐个输入参数
            frequency = data;
            APP_PRINT("\r\nThe frequency of sine wave is %d\r\n",frequency);

            APP_PRINT("\r\nInput the amplitude\r\n");
            amplitude = process_input_data();
            APP_PRINT("\r\nThe amplitude of sine wave is %d\r\n",amplitude);

            APP_PRINT("\r\nInput the offset\r\n");
            offset = process_input_data();
            APP_PRINT("\r\nThe offset of sine wave is %d\r\n",offset);

            APP_PRINT("\r\nInput the sample rate\r\n");
            sample_rate = process_input_data ();
            APP_PRINT("\r\nThe sample rate of sine wave is %d\r\n", sample_rate);

            sample_num = sample_rate / frequency;
            R_GPT_PeriodSet(&g_timer_dac_ctrl, (uint32_t)(100000000/sample_rate));


            APP_PRINT("\r\nNow the DAC is running\r\n");
            APP_PRINT("\r\nPress user sw1 to stop DAC\r\n");
            while(1)
            {
                //等待ADC采样完成
                while (!adc_complete_flag)
                {

                }
                R_ADC_Read (&g_adc0_ctrl, ADC_CHANNEL_0, &wave);
                adc_complete_flag = false;

                //按下SW1退出循环
                R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_05, &state);
                if(state == 0)
                {
                    APP_PRINT("\r\nInput the frequency, or input 0 to quit\r\n");
                    break;
                }
            }

        }
        else if(data == 0)//返回上一级菜单
        {
            break;
        }
    }
}

 

信号发生器菜单:

APP_PRINT("\r\nChoose the mode\r\n"
              "\r\n1.Write parameter to flash\r\n"
              "2.Read parameter from flash\r\n"
              "3.Input the parameter and turn on DAC directly\r\n");

    switch (process_input_data ())
    {
        case WRITE_TO_FLASH://写入参数到flash
        {
            
			//写入参数的代码
            break;
        }
        case READ_FROM_FLASH://从flash读取参数
        {
            //读取参数的代码
            break;
        }
        case DIRECT_INPUT://直接使用输入参数启动DAC
        {
            //直接输入参数的代码
            break;
        }
    }


    APP_PRINT("\r\nOpen DAC or go back to main menu\r\n"
            "\r\n1.Open DAC"
            "\r\n2.Back to main menu\r\n");

    switch(process_input_data())
    {
        case 1://打开DAC
        {
            
			//配置DAC与ADC的代码
            break;
        }

        case 2://返回主菜单
        {
            break;
        }
    }

 

 

扩展任务:信号发生器,通过命令或按键设置DAC波形,通过Flash存储波形信息


实现了正弦波、三角波、方波的生成,并且可以将波形参数存到Flash中。

 

程序思路:

(1)通过DAC生成波形,ADC采样波形并在电脑屏幕显示(由于没有示波器)

(2)DAC与ADC通过GPT定时器溢出触发,以固定的频率进行波形生成与采样

(3)通过按键外部中断,切换DAC生成波形的种类,实现在波形生成中的波形切换

(4)使用QSPI-Flash存储波形信息,在启动DAC之前可以选择提前将参数写入到Flash中,并在以后进行读取

 

流程图:

 

代码:

信号发生器主程序

void signal_generator(void)
{

    fsp_err_t err = FSP_SUCCESS;

    bsp_io_level_t state;//io口状态

    uint8_t data_buffer[2] = {0};//缓冲

    uint8_t data_sreg[3] = { WRSR, STATUS_REGISTER_CONTENT, CONFIG_REGISTER_CONTENT };//flash设置
    uint8_t *p_mem_addr = NULL;//写入地址指针

    sample_rate = DAFAULT_SAMPLE_RATE;//重置采样率


    //初始化QSPI和flash
    if (SPI_FLASH_PROTOCOL_QPI == g_qspi0_cfg.spi_protocol)
    {
        spi_flash_cfg_t temp_qspi0_cfg;
        memcpy ((spi_flash_cfg_t*) &temp_qspi0_cfg, (spi_flash_cfg_t*) &g_qspi0_cfg, sizeof(spi_flash_cfg_t));
        temp_qspi0_cfg.spi_protocol = SPI_FLASH_PROTOCOL_EXTENDED_SPI;

        err = R_QSPI_Open (&g_qspi0_ctrl, &temp_qspi0_cfg);
        if (FSP_SUCCESS != err)
        {
            APP_ERR_PRINT("QSPI open failed.\r\n");
            APP_ERR_TRAP(err);
        }
    }
    else //如qspi设置为extend qspi模式,则直接启动
    {
        err = R_QSPI_Open (&g_qspi0_ctrl, &g_qspi0_cfg);
        if (FSP_SUCCESS != err)
        {
            APP_ERR_PRINT("QSPI open failed.\r\n");
            APP_ERR_TRAP(err);
        }
    }

    //设置Flash的状态寄存器(status register)与配置寄存器(configuration register)
    err = R_QSPI_DirectWrite (&g_qspi0_ctrl, &g_qspi0_cfg.write_enable_command, 1, false);
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Flash write enable failed\r\n");
        APP_ERR_TRAP(err);
    }
    err = get_flash_status ();
    if (FSP_SUCCESS != err)
    {
        APP_PRINT("Can't get flash status\r\n");
    }

    //将设定值写入status寄存器
    err = R_QSPI_DirectWrite (&g_qspi0_ctrl, data_sreg, 3, false);
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Flash write register failed\r\n");
        APP_ERR_TRAP(err);
    }
    get_flash_status ();

    //检查寄存器的值(status register)
    uint8_t _register_data = 0;
    err = R_QSPI_DirectWrite (&g_qspi0_ctrl, &g_qspi0_cfg.status_command, 1, true);

    err = R_QSPI_DirectRead (&g_qspi0_ctrl, &_register_data, 1);
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("Flash write register failed\r\n");
        APP_ERR_TRAP(err);
    }
    get_flash_status ();

    if (_register_data != 0x40)
    {
        APP_ERR_PRINT("The status register can't be set correctly.\r\n");
        APP_ERR_TRAP(err);
    }

    //如果一开始设置为QPI模式,现在将MCU与Flash恢复成QPI
    if (g_qspi0_cfg.spi_protocol == SPI_FLASH_PROTOCOL_QPI)
    {
        uint8_t data = OPEN_FLASH_QPI;
        err = R_QSPI_DirectWrite (&g_qspi0_ctrl, &g_qspi0_cfg.write_enable_command, 1, false);
        if (FSP_SUCCESS != err)
        {
            APP_ERR_PRINT("Flash write enable failed\r\n");
            APP_ERR_TRAP(err);
        }
        get_flash_status ();

        //设置Flash为QPI模式
        err = R_QSPI_DirectWrite (&g_qspi0_ctrl, &data, 1, false);
        if (FSP_SUCCESS != err)
        {
            APP_ERR_PRINT("Flash set qpi mode failed\r\n");
            APP_ERR_TRAP(err);
        }

        err = R_QSPI_SpiProtocolSet (&g_qspi0_ctrl, SPI_FLASH_PROTOCOL_QPI);
        if (FSP_SUCCESS != err)
        {
            APP_ERR_PRINT("QSPI protocol change failed\r\n");
            APP_ERR_TRAP(err);
        }
    }

    APP_PRINT("\r\nChoose the mode\r\n"
              "\r\n1.Write parameter to flash\r\n"
              "2.Read parameter from flash\r\n"
              "3.Input the parameter and turn on DAC directly\r\n");

    //菜单与功能选择
    switch (process_input_data ())
    {
        case WRITE_TO_FLASH://写入参数到flash
        {
            APP_PRINT("\r\nInput the frequency:\r\n");
            frequency = process_input_data ();

            APP_PRINT("\r\nInput the amplitude:\r\n");
            amplitude = process_input_data ();

            APP_PRINT("\r\nInput the offset:\r\n");
            offset = process_input_data ();


            //擦除扇区
            p_mem_addr = (uint8_t*) 0x60001000;
            err = R_QSPI_Erase (&g_qspi0_ctrl, p_mem_addr, 4096U);
            if (FSP_SUCCESS != err)
            {
                flash_quit_qpi ();
                APP_ERR_PRINT("DAC-QSPI erase failed\r\n");
                APP_ERR_TRAP(err);
            }
            get_flash_status();

            //写入频率
            p_mem_addr = (uint8_t*) FREQUENCY_ADDRESS;
            data_buffer[0] = (uint8_t) (frequency & 0xff); //取低字节
            data_buffer[1] = (uint8_t) ((frequency >> 8) & 0xff); //取高字节
            err = R_QSPI_Write (&g_qspi0_ctrl, data_buffer, p_mem_addr, 2);
            if (FSP_SUCCESS != err)
            {
                flash_quit_qpi ();
                APP_ERR_PRINT("DAC-QSPI write frequency failed\r\n");
                APP_ERR_TRAP(err);
            }
            get_flash_status();

            //写入幅值
            p_mem_addr = (uint8_t*) AMPLITUDE_ADDRESS;
            data_buffer[0] = (uint8_t) (amplitude & 0xff); //取低字节
            data_buffer[1] = (uint8_t) ((amplitude >> 8) & 0xff); //取高字节
            err = R_QSPI_Write (&g_qspi0_ctrl, data_buffer, p_mem_addr, 2);
            if (FSP_SUCCESS != err)
            {
                flash_quit_qpi ();
                APP_ERR_PRINT("DAC-QSPI write amplitude failed\r\n");
                APP_ERR_TRAP(err);
            }
            get_flash_status();

            //写入偏置
            p_mem_addr = (uint8_t*) OFFSET_ADDRESS;
            data_buffer[0] = (uint8_t) (offset & 0xff); //取低字节
            data_buffer[1] = (uint8_t) ((offset >> 8) & 0xff); //取高字节
            err = R_QSPI_Write (&g_qspi0_ctrl, data_buffer, p_mem_addr, 2);
            if (FSP_SUCCESS != err)
            {
                flash_quit_qpi ();
                APP_ERR_PRINT("DAC-QSPI write offset failed\r\n");
                APP_ERR_TRAP(err);
            }
            get_flash_status();

            flash_quit_qpi ();
            R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS);
            err = R_QSPI_Close(&g_qspi0_ctrl);

            break;
        }
        case READ_FROM_FLASH://从flash读取参数
        {
            p_mem_addr = (uint8_t*) FREQUENCY_ADDRESS;
            memcpy (data_buffer, p_mem_addr, 2);
            frequency = (data_buffer[0] | (data_buffer[1] << 8));

            p_mem_addr = (uint8_t*) AMPLITUDE_ADDRESS;
            memcpy (data_buffer, p_mem_addr, 2);
            amplitude = (data_buffer[0] | (data_buffer[1] << 8));

            p_mem_addr = (uint8_t*) OFFSET_ADDRESS;
            memcpy (data_buffer, p_mem_addr, 2);
            offset = (data_buffer[0] | (data_buffer[1] << 8));

            flash_quit_qpi ();
            R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS);
            R_QSPI_Close(&g_qspi0_ctrl);

            APP_PRINT("\r\nfrequency = %d\r\n"
                    "amplitude = %d\r\n"
                    "offset = %d\r\n",frequency ,amplitude ,offset);

            break;
        }
        case DIRECT_INPUT://直接使用输入参数启动DAC
        {
            flash_quit_qpi ();
            R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS);
            R_QSPI_Close (&g_qspi0_ctrl);

            APP_PRINT("\r\nInput the frequency:\r\n");
            frequency = process_input_data ();

            APP_PRINT("\r\nInput the amplitude:\r\n");
            amplitude = process_input_data ();

            APP_PRINT("\r\nInput the offset:\r\n");
            offset = process_input_data ();

            break;
        }
    }


    APP_PRINT("\r\nOpen DAC or go back to main menu\r\n"
            "\r\n1.Open DAC"
            "\r\n2.Back to main menu\r\n");

    switch(process_input_data())
    {
        case 1://打开DAC
        {
            sample_num = sample_rate / frequency;

            //打开P004外部中断,用于切换波形
            R_ICU_ExternalIrqOpen(&g_external_irq0_ctrl, &g_external_irq0_cfg);
            R_ICU_ExternalIrqEnable(&g_external_irq0_ctrl);

            //打开DAC
            R_DAC_Open (&g_dac0_ctrl, &g_dac0_cfg);
            R_DAC_Start (&g_dac0_ctrl);

            //打开DAC采样定时器
            R_GPT_Open (&g_timer_dac_ctrl, &g_timer_dac_cfg);
            R_GPT_PeriodSet(&g_timer_dac_ctrl, (uint32_t)(100000000/sample_rate));
            R_GPT_Start (&g_timer_dac_ctrl);

            //打开ADC
            R_ADC_Open (&g_adc0_ctrl, &g_adc0_cfg);
            R_ADC_ScanCfg (&g_adc0_ctrl, &g_adc0_channel_cfg);

            //打开ADC采样定时器
            R_GPT_Open (&g_timer_adc_ctrl, &g_timer_adc_cfg);
            R_GPT_Start (&g_timer_adc_ctrl);

            APP_PRINT("\r\nDAC is running.\r\n"
                    "\r\nPress SW2 to switch waveform\r\n"
                    "Press SW1 to quit\r\n");

            while (1)
            {
                //等待ADC采样完成
                while (!adc_complete_flag)
                {

                }
                R_ADC_Read (&g_adc0_ctrl, ADC_CHANNEL_0, &wave);
                adc_complete_flag = false;

                //按下SW1退出循环
                R_IOPORT_PinRead (&g_ioport_ctrl, BSP_IO_PORT_00_PIN_05, &state);
                if (state == 0)
                {
                    break;
                }
            }


            R_DAC_Close (&g_dac0_ctrl);
            R_ADC_Close (&g_adc0_ctrl);

            R_GPT_Close (&g_timer_dac_ctrl);
            R_GPT_Close (&g_timer_adc_ctrl);

            wave = 0;

            break;
        }

        case 2://返回主菜单
        {
            break;
        }
    }

}

 

DAC波形更新(定时器溢出中断回调)

void timer_dac_callback(timer_callback_args_t *p_args)
{
    FSP_PARAMETER_NOT_USED(p_args);
    index++;
    if(index > sample_num)
    {
        index = 0;
    }
    switch(waveform_change)
    {
        case 0://正弦波
        {
            R_DAC_Write (&g_dac0_ctrl, (uint16_t) (amplitude * sin (2 * M_PI * frequency * index / sample_rate) + offset));
            break;
        }
        case 1://三角波
        {
            R_DAC_Write (&g_dac0_ctrl, (uint16_t) (2*amplitude * asin(sin (2 * M_PI * frequency * index / sample_rate))/M_PI + offset));
            break;
        }
        case 2://方波
        {
            if(index <= (sample_num/2))
            {
                R_DAC_Write (&g_dac0_ctrl,amplitude+offset);
            }
            else
            {
                R_DAC_Write (&g_dac0_ctrl,-amplitude+offset);
            }
        }
    }


}

 

ADC开始转换(定时器溢出中断回调函数) 以及 ADC采样转换完成回调函数

//ADC定时开始采样
void timer_adc_callback(timer_callback_args_t *p_args)
{
    FSP_PARAMETER_NOT_USED(p_args);
    R_ADC_ScanStart(&g_adc0_ctrl);

}

//ADC采样转换完成
void adc_callback(adc_callback_args_t *p_args)
{
    FSP_PARAMETER_NOT_USED(p_args);
    adc_complete_flag = true;
}

 

波形切换,通过外部中断实现

void irq_waveform_callback(external_irq_callback_args_t *p_args)
{
    FSP_PARAMETER_NOT_USED(p_args);
    waveform_change++;
    if(waveform_change > 2)
    {
        waveform_change = 0;
    }
}

 

演示:

为了采集DAC输出电压信号,与DAC测试一样,需要将P000与P014相连

波形生成:

生成正弦波

 
生成三角波
 
生成方波

在DAC生成波形中,按下用户按键2,触发中断,就可以完成波形的转换

 

 

总结


    在这次活动里面,我学习到了EK-RA6M5这块开发板上各种外设功能的配置和使用方法,然后又将这些外设应用到不同的项目任务中。在实现这些任务的过程中,我了解到了QSPI、OSPI Flash的工作原理,了解到DAC、ADC的配置方法,了解到了定时器配置以及中断回调函数的使用方法等。这次的项目不仅让我学习到开发板外设的使用方法,更重要的是让我获得了在项目中的思路和实际解决问题的技巧。

    再次感谢论坛和得捷电子提供这样的机会,让我能够获得学习的机会,希望未来能够继续参与这样的活动,继续提高自己的技术水平。

 

 

项目的源码


项目的源码打包上传到了下载中心


 

eeworld_mission.zip

1.87 MB, 下载次数: 3

【Follow me第二季第3期】EK-RA6M5任务汇总

点赞 关注
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

关闭
站长推荐上一条 1/7 下一条

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