EPTmachine

  • 2024-12-15
  • 发表了主题帖: 【Follow me第二季第3期】EK-RA6M5简易信号发生器设计汇总

    本帖最后由 EPTmachine 于 2024-12-15 13:36 编辑 本次Follow Me活动使用的开发板为Renesas的EK_RA6M5开发板。主要实现以下几个任务。 入门任务:搭建环境,下载调试示例程序,Blink,按键; 基础任务:quad-spi flash和octo-spi flash配置及读写速度测试;DAC配置生成波形及性能测试; 进阶任务:示例程序中新增命令打印信息; 扩展任务:设计一个类似信号发生器功能的例程。可在示例程序上修改。通过命令或按键,设置DAC输出波形,可通过flash存储历史波形等信息。 [localvideo]da54068e218459c5756737773eb2c7b5[/localvideo] # 入门任务: 任务相关的内容[【Follow me第二季第3期】1入门任务:搭建环境,下载调试示例程序,Blink,按键](https://bbs.eeworld.com.cn/thread-1298133-1-1.html) e2studio的开发环境功能多样,在熟悉各部分功能的使用后,可以借助FSP工具、Deverlop Asssitant代码提示加快开发进度。 # 基础任务: 任务相关的内容[【Follow me第二季第三期】基础任务:quad spi、octo spi、dac和定时器使用]( https://bbs.eeworld.com.cn/thread-1301167-1-1.html) 板载的外设很多,quad spi flash和octo spi flash扩展了开发板的存储空间,可以存储更多的程序和数据,实现复杂的应用,同时FSP配置工具中可以快捷地设定相关外设的驱动代码,方便外设的使用减少开发人员的工作量。 # 进阶任务: 任务相关的内容[【Follow me第二季第三期】进阶任务:通过USB发送指令修改QSPI中的数据 ](https://bbs.eeworld.com.cn/thread-1301875-1-1.html) USB设备可以设定端点类型为CDC设备,从而实现与电脑的通讯,建立通讯后后,通过控制台向开发板发送数据,从而实现数据交互和指令控制。 根据接受到的数据的不同,提示用户输入相关的输入,从而实现对qspi flash中存储的数据的修改。 # 扩展任务: 任务相关的内容[【Follow me第二季第三期】扩展任务:设计一个类似信号发生器功能的例程](https://bbs.eeworld.com.cn/thread-1301877-1-1.html) 结合之前的qspi flash储存和usb 指令任务,添加dds模块后,即可以实现简易的DDS信号发生器。 # 总结 开发板的硬件资源和示例代码很多,方便开发者理解如何使用芯片的功能。同时e2studio的开发工具辅助开发者快速搭建应用程序,加快开发进度。 任务代码:

  • 上传了资料: FollowMeEK-RA6M5

  • 发表了主题帖: 【Follow me第二季第三期】扩展任务:设计一个类似信号发生器功能的例程

    本帖最后由 EPTmachine 于 2024-12-15 12:12 编辑 设计程序能发出不同的波形,频率范围1——1kHz,支持正弦波、方波和三角波。 ## 程序设计 在MCU上实现信号发生器的功能,参考以下两篇博客 [STM32片上DAC实现DDS](https://www.emoe.xyz/stm32-dac-direct-digital-synthesis/) [STM32口袋仪器设计](https://www.eetree.cn/project/546) 采用其中的DDS模块实现信号的输出。结合之前任务中使用到的USB、QSPI Flash外设即可实现类似信号发生器的功能。 ## 程序实现 在FSP中添加以下的模块 涉及到DDS功能的模块有dac、gpt和dma模块。其中dac模块的参数设置如下 gpt模块设置如下 dma模块设置如下 DMA的数据搬运由定时器的溢出事件驱动。瑞萨DMA模块的使用和STM32的类似,在dds.c的DDS_setWaveParams函数中,通过修改DMA的数据源,加载不同的DDS查找表,从而实现不同配置波形的产生。 类似于任务3的Flash存储数据示例,在任务3的基础上添加以下文件,其中的代码实现DDS相关外设的初始化、DDS信号数据计算以及用户选择DDS信号配置的菜单。 添加上述代码,编译完成即可实现DDS信号发生器的功能,同时用户可以编辑信号的类型和频率。 # 程序演示 产生正弦波 产生方波 ![alt text](figures/04/dds_squ.jpg) 产生三角波 相关示例代码

  • 发表了主题帖: 【Follow me第二季第三期】进阶任务:通过USB发送指令修改QSPI中的数据

    本帖最后由 EPTmachine 于 2024-12-15 12:07 编辑 查看开发资料中演示例程的流程图了解控制台指令是如何实现的。开发板通过USB接口连接到电脑后,通过对电脑端发送的字符串进行解析,从而执行不同的功能函数。 # USB传输字符串并解析 USB通讯中,客户端(这里为开发板)可以设定端点(endpoint)的类型,实现不同的功能,本任务中使用的CDC类型的端点,通过usb连接至电脑后,可以实现串口通讯功能,传输数据,实现人机交互。 实现上述功能需要用的到外设有qspi、usb。在FSP的配置界面中添加需要用到的组件、定义的RTOS线程以及信号量等。 USB模块使用USB_PCDC,FSP工具可以生成USB CDC类型端点的代码,简化开发流程。 属性界面中设置CallBack的函数名。 QSPI的配置参考基础任务中的qspi配置。 # 添加新指令 任务目标是添加一条新指令,指令的功能设定为查看和修改存储在QSPI Flash上的DDS数据。存储在QSPI Flash上的数据结构为dds_record,dds_record的定义如下。 ```c typedef struct dds_param{     uint8_t         waveType;     uint8_t         amp;     int8_t          offset;     uint32_t        freq; }dds_param_t; enum dds_wavetype{     SIN_WAVE=0,     SQU_WAVE=1,     TRI_WAVE=2 }; #define DDS_RECORD_TYPE     0xF5 typedef struct dds_record{     uint8_t type;     dds_param_t dds_items[10]; }dds_record_t; ``` # 程序设计 程序设计参考示例程序的框架,包含的文件中新的文件如图所示。dds_record.c、dds_record.h和dds_record_ctrl_entry.c实现在QSPI Flash中管理数据的功能。menu_dds_record.c、menu_dds_record.h实现指令解析部分。 新文件中的代码为实现新指令的代码。 Flash存储相关的代码会初始化qspi flash,并对需要存储的数据进行管理。 ```c #include "common_init.h" #include "common_utils.h" #include "qspi_drv.h" #define DDS_RECORD_SIZE     1024 static char_t s_print_buffer[BUFFER_LINE_LENGTH] = {}; extern dds_record_t dds_record_ins; /* DDS_record entry function */ /* pvParameters contains TaskHandle_t */ void dds_record_ctrl_entry(void *pvParameters) {     FSP_PARAMETER_NOT_USED (pvParameters);     fsp_err_t err;     uint8_t* p_src=(uint8_t *)QSPI_DEVICE_START_ADDRESS;;     uint8_t* p_dest=(uint8_t*)&dds_record_ins;     qpi_init();     memcpy (p_dest, p_src, sizeof(dds_record_t));     if(dds_record_ins.type!=DDS_RECORD_TYPE)     {         /* Erase Flash for one sector */         err = R_QSPI_Erase(&g_qspi_ctrl, p_src, SECTOR_SIZE);         if (FSP_SUCCESS != err)         {             sprintf(s_print_buffer, "R_QSPI_Erase Failed\r\n");             print_to_console((void*)s_print_buffer);         }     }     /* TODO: add your own code here */     while (1)     {         while (pdPASS != xSemaphoreTake(g_store_dds_semaphore, pdMS_TO_TICKS(500u)))         {             vTaskDelay(10);         }         dds_record_ins.type=DDS_RECORD_TYPE;         /* Erase Flash for one sector */         err = R_QSPI_Erase(&g_qspi_ctrl, p_src, SECTOR_SIZE);         if (FSP_SUCCESS != err)         {             sprintf(s_print_buffer, "R_QSPI_Erase Failed\r\n");             print_to_console((void*)s_print_buffer);         }         err = get_flash_status();         err = R_QSPI_Write(&g_qspi_ctrl, (uint8_t*)&dds_record_ins, p_src, sizeof(dds_record_t));         if (FSP_SUCCESS != err)         {             sprintf(s_print_buffer, "R_QSPI_Write Failed\r\n");             print_to_console((void*)s_print_buffer);         }         err = get_flash_status();         sprintf (s_print_buffer, "g_store_dds_semaphore recevied" );         print_to_console((void*)s_print_buffer);         memcpy (p_dest, p_src, sizeof(dds_record_t));         vTaskDelay (10);     } } ``` 上述代码在初始化QSPI Flash后,读取其中的数据,并等待g_store_dds_semaphore信号量,用于更新Flash中存储的内容。 USB CDC模块中,用户需要自定义相关的端点描述符用于设备的枚举。相关的代码参考示例程序在r_usb_pcdc_descriptor.c中。 usb的Callback中转发接受到的事件,用于后续的字符解析。 ```c void usb_console_callback(usb_event_info_t* p_event_info, usb_hdl_t hdl, usb_onoff_t state) {     /* Void unused args */     FSP_PARAMETER_NOT_USED(hdl);     FSP_PARAMETER_NOT_USED(state);     BaseType_t xHigherPriorityTaskWoken;     memcpy(&s_usb_event_list[s_usb_event_pindex], p_event_info, sizeof(usb_event_info_t));     if (xQueueIsQueueFullFromISR(g_usb_transaction_queue) == pdFALSE)     {         xQueueSendToBackFromISR(g_usb_transaction_queue, &s_usb_event_pindex, &xHigherPriorityTaskWoken);         /* set next available index, cast to maintain sign integrity */         s_usb_event_pindex = (uint8_t)((s_usb_event_pindex + 1) % USB_QUEUE_SIZE);     }     else     {         /* Fatal error - usb message queue is full, this should not occur unless there has been a fatal USB error */         //SYSTEM_ERROR     }     /* Switch context if necessary. */     if (xHigherPriorityTaskWoken)     {         taskYIELD ();     } } ``` 后续对字符串的处理参考示例代码中usb_console_main.c的实现。 USB交互相关的部分则对用户的输入进行解析,修改DDS_record中数据,数据修改完成后,向Flash存储任务发出信号量g_store_dds_semaphore,进行存储数据的更新。主要的代码menu_dds_record.c的dds_record_menu函数中。相关的代码在工程的dds_record_menu函数中。 # 实际测试 工程编译并下载后,效果运行的效果如下所示。能够对Flash中存储的数据进行读写管理。 相关工程代码

  • 2024-12-07
  • 发表了主题帖: 【Follow me第二季第三期】基础任务:quad spi、octo spi、dac和定时器使用

    本帖最后由 EPTmachine 于 2024-12-7 11:09 编辑 基础任务:quad-spi flash和octo-spi flash配置及读写速度测试;DAC配置生成波形及性能测试; 评估板上提供了很多外设可供测试。借助瑞萨提供FSP(Flexiable Software Package)工具,可以配置外设和引脚的参数,生成相应的驱动代码,用户在此基础上能快速开放相应的应用代码开发和调试。本帖对板上的FLASH芯片读写性能和芯片的DAC性能进行测试。 任务涉及的外设有: - RA6M5的quad spi - RA6M5的octo spi - 板载的Quand-SPI flash-MX25L25645G - 板载的Octo-SPI Flash-MX25LM51245GM - RA6M5的DAC - RA6M5的定时器 ## quad-spi flash配置及读写速度测试 在官方提供的ek-ra6m5-exampleprojects.zip中有很多例程可供参考,详情见附件。这里参考例程中的gpt和qspi来完成flahs的配置和读写速度测试。 在gpt的例程中,对通用定时器进行设置,配置为周期工作模式,同时配合Segger RTT组件实现上位机与开发板之间的交互。参考例程的设计, ### 添加Segger RTT模块实现上位机和开发板的交互 将gpt例程中的Segger RTT文件夹和common_utils.h头文件 添加到新建工程的src文件夹下, 在其他文件中包含common_utils.h头文件后,就可以使用Segger RTT的功能。 ### 使用定时器进行时间测量 使用定时器的周期性中断功能,在中断发生时,进行时间技术,从而实现时间测量功能,用于计算某段代码的执行时间,从而计算出flash的读写速度。 在FSP的Stacks界面中添加gpt组件 设置定时器的参数,包括定时器工作模式、中断函数名、中断使能和优先级(设定优先级后默认使能该中断) 点击生成代码后,在工程中添加gpt_timer.c和gpt_timer.h,其中的代码如下,实现定时器的初始化、启动、Segger_RTT交互功能、定时器回调函数处理。 gpt_timer.h代码如下 ```c #ifndef GPT_TIMER_H_ #define GPT_TIMER_H_ /* Macros definitions */ #define GPT_MAX_PERCENT          (100U)          /* Max Duty Cycle percentage */ #define BUF_SIZE                 (16U)           /* Size of buffer for RTT input data */ #define PERIODIC_MODE_TIMER      (1U)            /* To perform GPT Timer in Periodic mode */ #define INITIAL_VALUE            ('\0') #define TIMER_UNITS_MILLISECONDS  (1000U)        /* timer unit in millisecond */ #define CLOCK_TYPE_SPECIFIER      (1ULL)         /* type specifier */ /* GPT Timer Pin for boards */ #define TIMER_PIN           (GPT_IO_PIN_GTIOCB) #if defined (BOARD_RA2A1_EK) || defined (BOARD_RA4W1_EK) #define GPT_MAX_PERIOD_COUNT     (0XFFFF)        /* Max Period Count for 16-bit Timer*/ #else #define GPT_MAX_PERIOD_COUNT     (0XFFFFFFFF)    /* Max Period Count for 32-bit Timer*/ #endif #define START_GPT          (1U)                  /* To Set the period of GPT */ #define CLOSE_GPT          (2U)                  /* To stop of GPT Timer  */ #define QSPIWRITE_MODE     (3U)                  /* To test the qspi flash write function*/ #define QSPIREAD_MODE      (4U)                  /* To test the qspi flash read function*/ /* Function declaration */ fsp_err_t init_gpt_timer(timer_ctrl_t * const p_timer_ctl, timer_cfg_t const * const p_timer_cfg, uint8_t timer_mode); fsp_err_t start_gpt_timer (timer_ctrl_t * const p_timer_ctl); uint32_t  process_input_data(void); void deinit_gpt_timer(timer_ctrl_t * const p_timer_ctl); void print_timer_menu(void); uint32_t timer_GetRunTime(void); #endif /* GPT_TIMER_H_ */ ``` gpt_timer.c代码如下 ```c __IO uint32_t g_iRunTime = 0; /* Store Timer open state*/ uint8_t g_timer_open_state = RESET_VALUE; extern bsp_leds_t g_bsp_leds; /* Holds level to set for pins */ bsp_io_level_t pin_level = BSP_IO_LEVEL_LOW; /*******************************************************************************************************************//** * @addtogroup r_gpt_ep * @{ **********************************************************************************************************************/ /***************************************************************************************************************** * @brief       Initialize GPT timer. * @param[in]   p_timer_ctl     Timer instance control structure * @param[in]   p_timer_cfg     Timer instance Configuration structure * @param[in]   timer_mode      Mode of GPT Timer * @retval      FSP_SUCCESS     Upon successful open of timer. * @retval      Any Other Error code apart from FSP_SUCCES on Unsuccessful open . ****************************************************************************************************************/ fsp_err_t init_gpt_timer(timer_ctrl_t * const p_timer_ctl, timer_cfg_t const * const p_timer_cfg, uint8_t timer_mode) {     fsp_err_t err = FSP_SUCCESS;     /* Initialize GPT Timer */     err = R_GPT_Open(p_timer_ctl, p_timer_cfg);     if (FSP_SUCCESS != err)     {         APP_ERR_PRINT ("\r\n ** R_GPT_TimerOpen FAILED ** \r\n");         return err;     }     if(PERIODIC_MODE_TIMER == timer_mode)     {         g_timer_open_state = START_GPT;     }     return err; } /***************************************************************************************************************** * @brief       Start GPT timers in periodic, one shot, PWM mode. * @param[in]   p_timer_ctl     Timer instance control structure * @retval      FSP_SUCCESS     Upon successful start of timer. * @retval      Any Other Error code apart from FSP_SUCCES on Unsuccessful start . ****************************************************************************************************************/ fsp_err_t start_gpt_timer (timer_ctrl_t * const p_timer_ctl) {     fsp_err_t err = FSP_SUCCESS;     /* Starts GPT timer */     err = R_GPT_Start(p_timer_ctl);     if (FSP_SUCCESS != err)     {         /* In case of GPT_open is successful and start fails, requires a immediate cleanup.          * Since, cleanup for GPT open is done in start_gpt_timer,Hence cleanup is not required */         APP_ERR_PRINT ("\r\n ** R_GPT_Start API failed ** \r\n");     }     return err; } /***************************************************************************************************************** *  @brief      Process input string to integer value *  @param[in]  None *  @retval     integer value of input string. ****************************************************************************************************************/ uint32_t process_input_data(void) {     unsigned char buf[BUF_SIZE] = {INITIAL_VALUE};     uint32_t num_bytes          = RESET_VALUE;     uint32_t value              = RESET_VALUE;     while (RESET_VALUE == num_bytes)     {         if (APP_CHECK_DATA)         {             num_bytes = APP_READ(buf);             if (RESET_VALUE == num_bytes)             {                 APP_PRINT("\r\nInvalid Input\r\n");             }         }     }     /* Conversion from input string to integer value */     value =  (uint32_t) (atoi((char *)buf));     return value; } /***************************************************************************************************************** * @brief      Close the GPT HAL driver. * @param[in]  p_timer_ctl     Timer instance control structure * @retval     None ****************************************************************************************************************/ void deinit_gpt_timer(timer_ctrl_t * const p_timer_ctl) {     fsp_err_t err = FSP_SUCCESS;     /* Timer Close API call*/     err = R_GPT_Close(p_timer_ctl);     if (FSP_SUCCESS != err)     {         /* GPT Close failure message */         APP_ERR_PRINT ("\r\n ** R_GPT_Close FAILED ** \r\n");     } } /***************************************************************************************************************** * @brief      Print GPT Timer menu option. * @param[in]  None * @retval     None ****************************************************************************************************************/ void print_timer_menu(void) {     APP_PRINT ("\r\nMenu Options");     APP_PRINT ("\r\nEnter 1 for Start and Set the GPT timer");     APP_PRINT ("\r\nEnter 2 for Stop the GPT timer");     APP_PRINT ("\r\nEnter 3 for Writing Data to QSPI Flash test");     APP_PRINT ("\r\nEnter 4 for Reading Data from QSPI Flash test");     APP_PRINT ("\r\nUser Input:  "); } uint32_t timer_GetRunTime(void) {     uint32_t runtime;     DISABLE_INT();      /*  */     runtime = g_iRunTime;   /*  */     ENABLE_INT();       /*  */     return runtime; } void timer_tick(timer_callback_args_t *p_args) {     /* TODO: add your own code here */     if(NULL != p_args)     {         if (TIMER_EVENT_CYCLE_END  == p_args->event)         {             R_IOPORT_PinWrite(&g_ioport_ctrl, (bsp_io_port_pin_t)g_bsp_leds.p_leds[1], pin_level);             if (BSP_IO_LEVEL_LOW == pin_level)             {                 pin_level = BSP_IO_LEVEL_HIGH;                       }             else             {                 pin_level = BSP_IO_LEVEL_LOW;                        }             g_iRunTime++;             if (g_iRunTime == 0x7FFFFFFF)   /* the variable g_iRunTime expire 0x7FFFFFFF ,set it to 0*/             {                 g_iRunTime = 0;             }         }     } } ``` 编译并烧写后完成后,在上位机打开J-Link RTT Viewer。在File->Connect界面设定参数如下所示: 其中RTT Control Block中地址需要在工程的Debug目录中的xxxx.map文件中寻找`_SEGGER_RTT`字段。 点击连接后可以在J-Link RTT Viewer的界面中看到提示用户输入的信息。 在菜单栏中设定输入的发送方式为按下Enter后发送 根据提示输入,即可调用不同的程序 ### Quad Flash设置 在开发板上通过qspi接口连接了QSPI Flash。 在FSP的Stacks中添加qspi模块。 qspi模块的参数设置如下所示 通过查看芯片的用户手册可知,读模式设置为"Fast Read Quad I/O"后,QSPI控制器会自动生成相应的控制指令。这样节省了用户编程工作量,可以直接使用内存操作函数,memcpy、memcmp等,提高读写性能。 ! 参考例程中的qspi flash初始化和数据操作,添加qspi flash的驱动代码如下。实现对Flash的初始化、存储块数据擦除、数据写入和读出操作。 qspi_drv.h代码如下: ```c #ifndef QSPI_DRV_H_ #define QSPI_DRV_H_ #include "common_utils.h" #include "hal_data.h" /* QSPI flash page number to be written */ #define PAGE_FIRST                      (0U) /* QSPI flash page Size */ #define PAGE_WRITE_SIZE                 (256U) #define TEST_WRITE_SIZE                 (256U) /* QSPI flash address through page*/ #define QSPI_FLASH_ADDRESS(page_no)     ((uint8_t *) (QSPI_DEVICE_START_ADDRESS + ((page_no) * PAGE_WRITE_SIZE))) /* Status register pay-load */ #define STATUS_REG_PAYLOAD              {0x01,0x40,0x00} /* data written to status register */ #define SET_SREG_VALUE                  (0x40) /* sector size of QSPI flash device */ #define SECTOR_SIZE                     (4096U) /* one byte data transfer */ #define ONE_BYTE                        (0x01) /* SREG pay-load size */ #define SREG_SIZE                       (0x03) /* default memory value */ #define DEFAULT_MEM_VAL                 (0xFF) /* QPI mode exit command */ #define QSPI_MX25L_CMD_EXIT_QPI_MODE    (0xF5) /* QPI mode entry command */ #define QSPI_MX25L_CMD_ENTER_QPI_MODE   (0x35) // #define RDID                      (0x9F) #define MX_MANUFACTURER_ID        (0xC2) #define DEVICE_ID                 (0x18) #define MEMORY_TYPE               (0x20) #define MEMORY_DENSITY            (0x19) //function declaration void QSPI_FlashInit(void); void QSPI_EraseSector(uint8_t * address); fsp_err_t QSPI_WritePage(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize); void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize); uint32_t QSPI_ReadID(void); #endif /* QSPI_DRV_H_ */ ``` qspi_drv.c的代码如下 ```c #include "qspi_drv.h" /*******************************************************************************************************************//** *  @brief       wait for QSPI flash device status register to get idle till operation is in progress *  @param[IN]   None *  @retval      FSP_SUCCESS or any other possible error codes **********************************************************************************************************************/ static fsp_err_t get_flash_status(void) {     spi_flash_status_t status = {.write_in_progress = true};     int32_t time_out          = (INT32_MAX);     fsp_err_t err             = FSP_SUCCESS;     do     {         /* Get status from QSPI flash device */         err = R_QSPI_StatusGet(&g_qspi_ctrl, &status);         if (FSP_SUCCESS!= err)         {             APP_ERR_PRINT("R_QSPI_StatusGet Failed\r\n");             return err;         }         /* Decrement time out to avoid infinite loop in case of consistent failure */         --time_out;         if ( RESET_VALUE >= time_out)         {             APP_PRINT("\r\n ** Timeout : No result from QSPI flash status register ** \r\n");             return FSP_ERR_TIMEOUT;         }     }while (false != status.write_in_progress);     return err; } /*******************************************************************************************************************//** *  @brief       set QPI Mode in flash device and MCU *  @param[IN]   none *  @retval      FSP_SUCCESS or any other possible error codes **********************************************************************************************************************/ static fsp_err_t qpi_mode_set(void) {     fsp_err_t err = FSP_SUCCESS;     uint8_t data_qpi_en = QSPI_MX25L_CMD_ENTER_QPI_MODE;     APP_PRINT ("\r\n ** setting QPI mode: sending QPI enabling command byte to flash ** \r\n");     /* write enable once again section 9-1 states that      * we should do it before sending 0x35 to flash device      */     err = R_QSPI_DirectWrite(&g_qspi_ctrl, &(g_qspi_cfg.write_enable_command), ONE_BYTE, false);     if (FSP_SUCCESS != err)     {         APP_ERR_PRINT("R_QSPI_DirectWrite Failed\r\n");         return err;     }     else     {         err = get_flash_status();         if (FSP_SUCCESS != err)         {             APP_ERR_PRINT("Failed to get status for QSPI operation\r\n");             return err;         }     }     /* send QPI mode enable command in flash device      * Note - no status register read after this operation      * because flash device has gone in QPI mode      * and MCU at this point is in extended SPI mode only.      * vice versa same is applicable while exiting QPI mode too.      */     err = R_QSPI_DirectWrite(&g_qspi_ctrl, &data_qpi_en, ONE_BYTE, false);     if (FSP_SUCCESS != err)     {         APP_ERR_PRINT("R_QSPI_DirectWrite Failed\r\n");         return err;     }     APP_PRINT ("\r\n ** setting QPI mode:  setting QPI mode in MCU  ** \r\n");     /* Command byte transferred to flash-> NOW  set the QPI protocol in MCU run time */     err = R_QSPI_SpiProtocolSet(&g_qspi_ctrl, SPI_FLASH_PROTOCOL_QPI);     if (FSP_SUCCESS != err)     {         APP_ERR_PRINT("R_QSPI_SpiProtocolSet Failed\r\n");     }     return err; } /*******************************************************************************************************************//** *  @brief       Close QSPI module *  @param[IN]   spi_protocol mode *  @retval      None **********************************************************************************************************************/ static void deinit_qspi(const spi_flash_protocol_t spi_protocol_mode) {     fsp_err_t error = FSP_SUCCESS;     /* if QPI is active mode then Exit QPI mode from flash device before QSPI close */     if (SPI_FLASH_PROTOCOL_QPI == spi_protocol_mode)     {         uint8_t data_exit_qpi = QSPI_MX25L_CMD_EXIT_QPI_MODE;         APP_PRINT ("\r\n ** Exit QPI mode before Closing QSPI module ** \r\n");         error = R_QSPI_DirectWrite(&g_qspi_ctrl, &data_exit_qpi, ONE_BYTE, false);         if (FSP_SUCCESS != error)         {             APP_ERR_PRINT("R_QSPI_DirectWrite Failed\r\n");         }     }     APP_PRINT ("\r\n ** Closing QSPI module ** \r\n");     /* close QSPI module */     error = R_QSPI_Close(&g_qspi_ctrl);     if (FSP_SUCCESS != error)     {         APP_ERR_PRINT("R_QSPI_Close Failed\r\n");     }     APP_PRINT("\r\n\r\n *****############## demo ends here ########## *******\r\n\r\n"); } void QSPI_FlashInit(void) {     fsp_err_t err= FSP_SUCCESS;     uint8_t   data_sreg[SREG_SIZE]                 = STATUS_REG_PAYLOAD;     if (SPI_FLASH_PROTOCOL_QPI == g_qspi_cfg.spi_protocol)     {         /*          * this needs to be done since QPI is set by user in configuration          * and it sets QPI only in MCU but not in flash device          * so as a system (MCU + QSPI flash device) QPI mode does not get set by          * simply calling only R_QSPI_Open in QPI mode.          * Rather QPI mode enabling has to be done in Flash device as well          * So opening the driver in extended SPI mode only          * and QPI mode is enabled when qpi_mode_set sub-function is called          */         spi_flash_cfg_t l_qspi_cfg;         memcpy((spi_flash_cfg_t *)&l_qspi_cfg, (spi_flash_cfg_t *)&g_qspi_cfg, sizeof (spi_flash_cfg_t));         l_qspi_cfg.spi_protocol = SPI_FLASH_PROTOCOL_EXTENDED_SPI;         APP_PRINT ("\r\n ** user selected QPI Mode in RA configuration tool ** \r\n");         /* open QSPI with local configuration  */         err = R_QSPI_Open(&g_qspi_ctrl, &l_qspi_cfg);         if (FSP_SUCCESS != err)         {             APP_ERR_PRINT("R_QSPI_Open Failed\r\n");             APP_ERR_TRAP(err);         }     }     else     {         APP_PRINT ("\r\n ** user selected extended SPI Mode in RA Configuration tool ** \r\n");         /* open QSPI in extended SPI mode */         err = R_QSPI_Open(&g_qspi_ctrl, &g_qspi_cfg);         if (FSP_SUCCESS != err)         {             APP_ERR_PRINT("R_QSPI_Open Failed\r\n");             APP_ERR_TRAP(err);         }     }     /* write enable for further operations */     err = R_QSPI_DirectWrite(&g_qspi_ctrl, &(g_qspi_cfg.write_enable_command), ONE_BYTE, false);     if (FSP_SUCCESS != err)     {         APP_ERR_PRINT("R_QSPI_DirectWrite Failed\r\n");         /* close QSPI module which is currently in extended SPI mode only */         deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);         APP_ERR_TRAP(err);     }     else     {         err = get_flash_status();         if (FSP_SUCCESS != err)         {             APP_ERR_PRINT("Failed to get status for QSPI operation\r\n");             /* close QSPI module which is currently in extended SPI mode only */             deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);             APP_ERR_TRAP(err);         }     }     /*      * write QSPI flash status register      * This is required to make sure the device is ready for general      * read write operation,      * This performs settings such as physical reset,WP hardware pin disable,      * block protection lock bits clearing.      * for more details please refer Mx25L data sheet.      */     err = R_QSPI_DirectWrite(&g_qspi_ctrl, data_sreg, SREG_SIZE, false);     if (FSP_SUCCESS != err)     {         APP_ERR_PRINT("R_QSPI_DirectWrite Failed\r\n");         /* close QSPI module which is currently in extended SPI mode only */         deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);         APP_ERR_TRAP(err);     }     else     {         err = get_flash_status();         if (FSP_SUCCESS != err)         {             APP_ERR_PRINT("Failed to get status for QSPI operation\r\n");             /* close QSPI module which is currently in extended SPI mode only */             deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);             APP_ERR_TRAP(err);         }     }     /*      * Verifying data written to QSPI flash status register      * Step 1: - send command byte - 0x05      * through R_QSPI_DirectWrite with last argument set as true      * Step 2 - read data through R_QSPI_DirectRead      */     uint8_t sreg_data = RESET_VALUE;     err = R_QSPI_DirectWrite(&g_qspi_ctrl, &(g_qspi_cfg.status_command), ONE_BYTE, true);     if (FSP_SUCCESS != err)     {         APP_ERR_PRINT("R_QSPI_DirectWrite Failed\r\n");         /* close QSPI module which is currently in extended SPI mode only */         deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);         APP_ERR_TRAP(err);     }     /*      *  we should not call function get_flash_status here      * because the CS line should not get interrupted between write read      *      * Also MCU is set as 0 when status register is read      * to resume in ROM access mode hence API direct read returns error as part      * of parameter check itself      */     err = R_QSPI_DirectRead(&g_qspi_ctrl, &sreg_data, ONE_BYTE);     if (FSP_SUCCESS != err)     {         APP_ERR_PRINT("R_QSPI_DirectRead Failed\r\n");         /* close QSPI module which is currently in extended SPI mode only */         deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);         APP_ERR_TRAP(err);     }     else     {         /* check for status check operation here */         err = get_flash_status();         if (FSP_SUCCESS != err)         {             APP_ERR_PRINT("Failed to get status for QSPI operation\r\n");             /* close QSPI module which is currently in extended SPI mode only */             deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);             APP_ERR_TRAP(err);         }     }     /* verify read status register data */     if (SET_SREG_VALUE != sreg_data)     {         APP_ERR_PRINT("Failed to get value set in the status register \r\n");         /* close QSPI module which is currently in extended SPI mode only */         deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);         APP_ERR_TRAP(err);     }     if (SPI_FLASH_PROTOCOL_QPI == g_qspi_cfg.spi_protocol)     {         /* set QPI mode in flash and MCU device */         err = qpi_mode_set();         if (FSP_SUCCESS!=err)         {             APP_ERR_PRINT ("qpi_mode_set failed\r\n");             /* close QSPI module which is currently in extended SPI mode only */             deinit_qspi(SPI_FLASH_PROTOCOL_EXTENDED_SPI);             APP_ERR_TRAP(err);         }     } } void QSPI_EraseSector(uint8_t * address) {     fsp_err_t err= FSP_SUCCESS;     err = R_QSPI_Erase(&g_qspi_ctrl, address, SECTOR_SIZE);     if (FSP_SUCCESS != err)     {         APP_ERR_PRINT("R_QSPI_Erase Failed\r\n");         deinit_qspi(g_qspi_cfg.spi_protocol);         APP_ERR_TRAP(err);     }     else     {         err = get_flash_status();         if (FSP_SUCCESS != err)         {             APP_ERR_PRINT("Failed to get status for QSPI operation\r\n");             deinit_qspi(g_qspi_cfg.spi_protocol);             APP_ERR_TRAP(err);         }     } } fsp_err_t QSPI_WritePage(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize) {     fsp_err_t err= FSP_SUCCESS;     /* Write data to QSPI Flash */     err = R_QSPI_Write(&g_qspi_ctrl, _pBuf, (uint8_t *)QSPI_FLASH_ADDRESS(_uiWriteAddr), _usWriteSize);     if (FSP_SUCCESS != err)     {         APP_ERR_PRINT("R_QSPI_Write Failed\r\n");         deinit_qspi(g_qspi_cfg.spi_protocol);         APP_ERR_TRAP(err);     }     else     {         err = get_flash_status();         if (FSP_SUCCESS != err)         {             APP_ERR_PRINT("Failed to get status for QSPI operation\r\n");             deinit_qspi(g_qspi_cfg.spi_protocol);             APP_ERR_TRAP(err);         }     }     return err; } //Due to the qspi Read Mode is set to Fast Read Quad I/O , the flash is mapped to the memory region at 0x6000000 void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize) {     /* Read data from QSPI memory region */     memcpy(_pBuf,  (uint8_t *)QSPI_FLASH_ADDRESS(_uiReadAddr), _uiSize); } uint32_t QSPI_ReadID(void) {     fsp_err_t err = FSP_SUCCESS;     uint8_t write_data;     uint8_t read_data[8];     uint32_t uiID;     write_data = RDID; /* Read ID */     memset(read_data, 0, sizeof(read_data));     err = R_QSPI_DirectWrite(&g_qspi_ctrl, &write_data, 1, true);     if (FSP_SUCCESS != err)     {       return err;     }     err = R_QSPI_DirectRead(&g_qspi_ctrl, read_data, 3);     if (FSP_SUCCESS != err)     {       return err;     }     if ((MX_MANUFACTURER_ID != read_data[0]) || (MEMORY_TYPE != read_data[1]) || (MEMORY_DENSITY != read_data[2]))     {       return FSP_ERR_ASSERTION;     }     uiID=(read_data[0] = (uint32_t)(g_timer_cfg.source_div);                     /* Convert period to PCLK counts so it can be set in hardware. */                     period_counts = (uint64_t)((gpt_desired_period_ms * (pclkd_freq_hz * CLOCK_TYPE_SPECIFIER))  / TIMER_UNITS_MILLISECONDS);                     /* Validate Period Count based on user input (time period in ms) */                     if(GPT_MAX_PERIOD_COUNT < period_counts)                     {                         APP_ERR_PRINT ("\r\n ** INVALID INPUT, DESIRED PERIOD IS OUT OF RANGE. ** \r\n");                     }                     else                     {                         /* Check the status of GPT timer in Periodic mode */                         if(START_GPT != g_timer_open_state)                         {                             /*Initialize Periodic Timer */                             err = init_gpt_timer(&g_timer_ctrl, &g_timer_cfg, PERIODIC_MODE_TIMER);                             if(FSP_SUCCESS != err)                             {                                 APP_ERR_PRINT("** GPT TIMER INIT FAILED ** \r\n");                                 APP_ERR_TRAP(err);                             }                             APP_PRINT("Opened Timer in Periodic Mode\r\n");                             /* Start Periodic Timer*/                             err = start_gpt_timer(&g_timer_ctrl);                             if(FSP_SUCCESS != err)                             {                                 APP_ERR_PRINT("** GPT TIMER START FAILED ** \r\n");                                 /*Close Periodic Timer instance */                                 deinit_gpt_timer(&g_timer_ctrl);                                 APP_ERR_TRAP(err);                             }                             APP_PRINT("Started Timer in Periodic Mode\r\n");                         }                         else                         {                             APP_PRINT("Periodic Timer Already Started, Update Timer Period to : %d \r\n",gpt_desired_period_ms);                         }                         /* Period Set API set the desired period counts on the on-board LED */                         err = R_GPT_PeriodSet(&g_timer_ctrl, (uint32_t)period_counts);                         if (FSP_SUCCESS != err)                         {                             /* GPT Timer PeriodSet Failure message */                             APP_ERR_PRINT ("\r\n ** R_GPT_PeriodSet API failed ** \r\n");                             /*Close Periodic Timer instance */                             deinit_gpt_timer(&g_timer_ctrl);                             APP_ERR_TRAP(err);                         }                     }                     break;                 }                 case CLOSE_GPT:                 {                     deinit_gpt_timer(&g_timer_ctrl);                     APP_PRINT("\r\n GPT timer closed,g_iRunTime is %d\r\n",g_iRunTime);                     g_iRunTime=0;                     break;                 }                 case QSPIWRITE_MODE:                 {                     uint32_t iTime1, iTime2;                     QSPI_EraseSector(p_mem_addr);                     // Fill the data write buffer further to be written in QSPI flash device                     for (uint16_t write_index = RESET_VALUE; write_index < TEST_WRITE_SIZE ; write_index++)                     {                         data_write[write_index] = (uint8_t)write_index;                     }                     APP_PRINT ("\r\nMeasure the time cost of qspi write\r\n");                     iTime1=timer_GetRunTime();                     for(uint16_t page_index = RESET_VALUE;page_index

  • 2024-11-24
  • 回复了主题帖: 【Follow me第二季第3期】1入门任务:搭建环境,下载调试示例程序,Blink,按键

    bigbat 发表于 2024-11-24 15:19 UP的原理图能传一份吗?"ek-ra6m5-v1-designpackage.zip",   我的原理图是怎样滴,我也没 ... 好的

  • 2024-11-23
  • 发表了主题帖: 【Follow me第二季第3期】1入门任务:搭建环境,下载调试示例程序,Blink,按键

    本帖最后由 EPTmachine 于 2024-11-24 21:33 编辑 # 入门任务:搭建环境,下载调试示例程序,Blink,按键 本次Follow Me活动的开发板是瑞萨的EK-RA6M5,在官网可以下载到如下的相关的资料。 官方的《EK-RA6M5 Quick Start Guide.pdf》可以帮助开发者快速了解套件的内容和使用方法。 套件包含了以下的内容 ## 搭建调试环境 e2studio是瑞萨提供的集成开发环境,包含编译器、代码编辑器、工程管理工具、芯片支持包等。 首先在e2studio的[下载页面](https://www.renesas.cn/zh/software-tool/e-studio)选择和电脑系统匹配的安装包。 下载后解压得到安装包,点击应用程序开始安装。 在安装选项中选择RA系列支持和fsp版本即可。安装过程各个界面的选项如下。 选择安装RA系列支持 点击install开始安装。 安装完成后,就可以编辑和调试代码。 ## 示例程序 针对EK-RA6M5,官方提供了丰富的示例代码和帮助文档。EK-RA6M5的产品页面提供了相应的资料和代码下载。 将下载的代码压缩包解压后,其中的示例代码如下所示: 通过菜单栏中的File->Import将工程导入到工作目录中 选择导入存在的工程到工作空间中。 选择工程所在的目录,在"Option"中勾选“Copy projects into workspace”将工程复制到工作空间中。 导入后项目栏中可以看到相应的工程。 在工程的右键选项中选择“Build Project”,完成后即可下载程序。 使用USB线连接电脑和开发板,点击调试按钮即可下载程序进行调试。 ## Blink程序 查看“EK-RA6M5 User's Manual.pdf”,板载三个LED灯的相关信息如下图。 在e2studio中创建EK-RA6M5的工程控制LED闪烁。 在菜单栏中选择"File->New->C/C++ Project" 输入工程名 选择对应的开发套件或者根据芯片型号进行工程创建   剩下的选择默认项即可   在开发瑞萨的RA系列芯片时,需要使用FSP配置工具对外设进行参数设置,在工程栏中点击“configuration.xml”即可打开FSP配置界面。 在“FSP Configuration”界面中对硬件外设和软件组件包进行管理。   查看下载资料"ek-ra6m5-v1-designpackage.zip"中的原理图可知,板上的LED的接线如图所示,控制引脚为P006、P007、P008。 在FSP界面的Pins选项卡页面可以查看相关引脚的设置。   在FSP界面的Stacks选项卡页面可以查看应用中涉及到的功能栈。Blink程序只涉及到引脚状态控制,使用r_ioport模块即可实现功能。 点击右上角的"Generate Project Content"生成相关设置的配置代码。 生成的代码中,与配置相关的部分在文件夹ra_cfg中 接下来编写相关的应用的代码。由于FSP配置生成的代码中包含main函数,每次点击"Generate Project Content"生成代码时都会对main进行改写,所以用户无法直接编写main函数的代码,用户代码的 入口就变为,在不使用RTOS实时操作系统的前提下,在src文件夹下的hal_entry.c中的hal_entry函数为用户代码入口。 hal_entry.c添加实现Blink功能的代码如下: ``` c #include "hal_data.h" FSP_CPP_HEADER void R_BSP_WarmStart(bsp_warm_start_event_t event); FSP_CPP_FOOTER extern bsp_leds_t g_bsp_leds; /*******************************************************************************************************************//** * main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used.  This function * is called by main() when no RTOS is used. **********************************************************************************************************************/ void hal_entry(void) {     /* TODO: add your own code here */ #if BSP_TZ_SECURE_BUILD     /* Enter non-secure code */     R_BSP_NonSecureEnter(); #endif     /* Define the units to be used with the software delay function */     const bsp_delay_units_t bsp_delay_units = BSP_DELAY_UNITS_MILLISECONDS;     /* Set the blink frequency (must be channel)     {         g_sw2_press = true;     } } ``` 在hal_entry函数中,通过对全局变量`g_sw1_press`、`g_sw2_press`的状态进行判断,执行相应的处理逻辑,实现按键1控制LED1蓝灯,按键2控制LED2绿灯的闪烁频率。具体代码如下: ```c #include "button.h" /* Board's user LED */ extern bsp_leds_t g_bsp_leds; /* Boolean flag to determine switch is pressed or not.*/ extern volatile bool g_sw1_press; extern volatile bool g_sw2_press; /*******************************************************************************************************************//** * main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used.  This function * is called by main() when no RTOS is used. **********************************************************************************************************************/ void hal_entry(void) {     /* TODO: add your own code here */ #if BSP_TZ_SECURE_BUILD     /* Enter non-secure code */     R_BSP_NonSecureEnter(); #endif     fsp_err_t err                           = FSP_SUCCESS;     blink_speed_t feq_level= slow_speed;     /* Define the units to be used with the software delay function */     const bsp_delay_units_t bsp_delay_units = BSP_DELAY_UNITS_MILLISECONDS;     /* the blink frequency,high 5h=Hz,normal 2Hz,slow 1Hz , (must be

  • 加入了学习《FollowMe 第二季:3 - EK_RA6M5 开发板入门》,观看 EK-RA6M5 开发板入门

  • 2024-11-03
  • 加入了学习《【2024 DigiKey创意大赛】- 基于毫米波雷达的生命体征检测及健康监护系统》,观看 【2024 DigiKey创意大赛】- 基于毫米波雷达的生命体征检测及健康监护系统-作品提交

  • 2024-03-01
  • 加入了学习《泰克MSO6B探索营》,观看 MSO6B技术介绍

  • 加入了学习《泰克MSO6B探索营》,观看 MSO6B-360度介绍

  • 2024-02-25
  • 发表了主题帖: 【得捷Follow me第4期】PiCO_W5500以太网应用

    ### ****[[ 演示视频 ]](https://training.eeworld.com.cn/video/39289 "[ 演示视频 ]")**** Digikey和EEWorld联合举行的FollowMe第四期,本期使用的板卡是WIZnet推出的RP2040搭配W5500开发板PICO W5500。该评估板可用于以太网应用的开发和测试,在其[产品介绍页面](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico)详细对其板载的芯片种类、芯片数据手册、评估板原理图和应用示例进行了介绍。 在Github上有官方提供的代码示例可供参考: - C/C++ Example - [Ethernet Example](https://github.com/Wiznet/RP2040-HAT-C) - [AWS Example](https://github.com/Wiznet/RP2040-HAT-AWS-C) - [Azure Example](https://github.com/Wiznet/RP2040-HAT-AZURE-C) - [Lwip Example](https://github.com/Wiznet/RP2040-HAT-LWIP-C) - [FreeRTOS Example](https://github.com/Wiznet/RP2040-HAT-FREERTOS-C) - [CircuitPython Example](https://github.com/Wiznet/RP2040-HAT-CircuitPython) - [MicroPython Example](https://github.com/Wiznet/RP2040-HAT-MicroPython) 该评估版给出的资源还是十分丰富,从简单的基础示例到复杂的综合应用都有可以借鉴的代码,学习起来还是很方便的。 # 入门任务开发环境搭建、Blink和串口输出任务 本次活动使用MicroPython作为开发语言,使用的软件位Thonny。Thonny软件的安装很简单,安装选项使用默认即可。 完成安装后,在软件的配置选项中选择使用到的代码解释器类型为MicroPython(Raspberry Pi Pico)。 要想在开发板上运行MicroPython的代码,需要将MicroPython的固件烧写到开发板上。首先从[MicroPython W550_EVB_PICO](https://micropython.org/download/W5500_EVB_PICO/)的发布页面下载对应该开发板的MicroPython固件。 按住开发板上的BootSel按键并上电或者在上电状态下,按住BootSel按键的同时,按下Run按键,开发板会进入BootLoader模式,在电脑上会出现一个RPI-RP2的大容量存储设备。 将下载的MicroPython固件发送到该设备,会自动完成固件的烧写。打开Thonny软件,在右下角选择显示出来的开发板。 在Shell中使用`help('modules')`指令可以查看当前固件中支持的函数类。 编写Blink的代码如下,实现对开发板上的LED灯的控制 ```python from machine import Pin import time led = Pin(25, Pin.OUT) def main(): while True: led.value(1) time.sleep(1) led.value(0) time.sleep(1) if __name__ == "__main__": main() ``` 点击工具栏中的Run按键即可运行上述代码,如果想在上电时就运行上述代码,新建一个`main.py`的文件,并上传到设备(这里指的是的pico w5500开发板)的根目录中,这样上电后程序会自动运行Blink的程序。 可以使用`print`函数向Shell输出信息。以下代码实现发送信息的功能。 ```python from machine import Pin import time led = Pin(25, Pin.OUT) def main(): while True: led.value(1) print('LED is on!\n') time.sleep(1) led.value(0) print('LED is off!\n') time.sleep(1) if __name__ == "__main__": main() ``` 运行程序后,在Thonny的Shell串口可以看到发出的信息。 # 基础任务一:主控板W55500初始化(静态IP配置),ping指令使用和数据包抓取 通过使用help指令可以查看network中包含的类,其中的`WIZNET5K`实现了WIZnet芯片的接口函数。可以很方面地使用板上的W5500外设,实现互联网应用。 通过`import`指令导入以下库,用于开启socket支持、GPIO驱动、SPI驱动、网络函数以及时间函数 ```python from usocket import socket from machine import Pin,SPI import network import time ``` 以下代码为W5500的初始化代码,初始化片上的SPI外设以及W5500芯片后,配置网络接口并测试网咯连接是否成功建立,建立成功后,在Shell中输出网卡的配置信息。 ```python #W5x00 chip init def w5x00_init(): spi=SPI(0,2_000_000, mosi=Pin(19),miso=Pin(16),sck=Pin(18)) nic = network.WIZNET5K(spi,Pin(17),Pin(20)) #spi,cs,reset pin nic.active(True) nic.ifconfig(('192.168.1.20','255.255.255.0','192.168.1.1','8.8.8.8')) while not nic.isconnected(): time.sleep(1) print(nic.regs()) print(nic.ifconfig()) ``` 接下来定义主函数如下,调用w5500芯片输出化函数,同时在main函数的循环中调用延时和GPIO翻转函数,用于提示系统正在运行。 ```python def main(): w5x00_init() while True: led.value(1) time.sleep(1) led.value(0) time.sleep(1) if __name__ == "__main__": main() ``` 文章[Python中`if __name__=='__main__':的作用](https://blog.csdn.net/heqiang525/article/details/89879056)对代码中的main函数调用规则进行了说明。 将上述代码整合到一起,在Thonny中打开文件并点击运行,可以看到Shell中输出了当前的开发板的静态IP配置信息。 在Windows中打开PowerShell,使用Ping指令检测与开发板的网络连接是否成功建立。 ```Shell ping 192.168.1.20 ``` 可以看到有以下的输出,说明W5500芯片正常运行, 使用wireshark抓取PC端的网络数据流,使用过滤条件`ip.addr=192.168.1.20`对抓取到数据进行过滤,可以得到ping指令的数据报,ping指令属于ICMP协议中的功能。 从结果中可以看到ping指令发送方和接收方的IP地址,以及其他的数据包信息。 # 基础任务二:主控板建立TCPIP服务器 该任务选择使用TCP功能进行实现服务器,Http应用使用的就是TCP协议,嵌入式的Web点灯是嵌入式终端作为HTTP Server,响应PC端的HTTP请求,从而实现网页控制板卡上的LED灯状态。 基础任务一实现了初始化W5500的函数和LED控制函数,在此基础上添加一个网页初始化函数,生成用于客户端显示的HTML网页。代码如下: ```python def web_page(): if led.value()==1: led_state="ON" else: led_state="OFF" html = """ Raspberry Pi Pico Web server - WIZnet W5100S Raspberry Pi Pico Web server & WIZnet Ethernet HAT Control LED PICO LED state: """ + led_state + """ ON OFF """ return html ``` 在主函数中创建一个socket,用于监听IP地址为192.168.1.20(这里为W5500的IP地址)网卡的端口80,在主循环中,在接收到PC端的客户端请求数据后,发送HTML数据,在接收到返回的数据后,检查其中是否有led_on或者led_off按钮对应的响应数据,据此改变板卡上LED灯的状态。 ```python def main(): w5x00_init() s = socket() s.bind(('192.168.1.20', 80)) s.listen(5) while True: conn, addr = s.accept() print('Connect from %s' % str(addr)) request = conn.recv(1024) request = str(request) #print('Content = %s' % request) led_on = request.find('/?led=on') led_off = request.find('/?led=off') if led_on == 6: print("LED ON") led.value(1) if led_off == 6: print("LED OFF") led.value(0) response = web_page() conn.send('HTTP/1.1 200 OK\n') conn.send('Connection: close\n') conn.send('Content-Type: text/html\n') conn.send('Content-Length: %s\n\n' % len(response)) conn.send(response) conn.close() if __name__ == "__main__": main() ``` 整合上述的代码并运行后,可以看到Shell中输出了相应的配置信息。 在PC端使用浏览器在对话框中输入`192.168.1.20`即可访问控制页面,点击页面上的按钮,即可实现对板卡上的LED灯控制。 使用WireShark捕获网口的通讯数据,添加`ip.addr=192.168.1.20`过滤出其中数据,可以看到传输的数据为TCP协议数据。 # 进阶任务:访问NTP服务器同步时间,获取时间并显示 NTP服务全称为Network Time Protocol,协议中定义了客户端和服务器两个用于数据交互的对象,客户端通过向服务器发送包含符合NTP协议要求的网络数据包,在服务器响应请求并返回相应的数据包之后,根据NTP协议解析其中的数据,即可得到需要的时间信息。 在Shell中输入`help('modules')`指令可以看到固件中已经包含了ntptime库,可以直接调用其中的ntp接口函数来获取当前的时间。 ```python import ntptime import time def sync_ntp(): ntptime.host = 'ntp1.aliyun.com' ntptime.settime() def main(): now = time.time() t = time.localtime(now) year, month, day, hour, minute, second, *_ = t time_str = f"{year}-{month:02d}-{day:02d} {hour:02d}:{minute:02d}:{second:02d}" print("时间:", time_str) if __name__ == "__main__": main() ``` 时间的数据效果如下图所示。 # 终极任务:实现FTP服务器 FTP全称为[File Transfer Protocol](https://en.wikipedia.org/wiki/Network_Time_Protocol),用于在网络中实现服务器与客户端的文件传输。 在开发板上实现FTP服务器的应用,借鉴已有的MicroPython实现FTP协议的示例,完成FTP服务器的搭建。ftpServer.py如下所示: ```python # # Small ftp server for ESP8266 ans ESP32 Micropython # # Based on the work of chrisgp - Christopher Popp and pfalcon - Paul Sokolovsky # # The server accepts passive mode only. # It runs in foreground and quits, when it receives a quit command # Start the server with: # # import ftp # # Copyright (c) 2016 Christopher Popp (initial ftp server framework) # Copyright (c) 2016 Robert Hammelrath (putting the pieces together # and a few extensions) # Distributed under MIT License # import socket import network import uos import gc def send_list_data(path, dataclient, full): try: # whether path is a directory name for fname in sorted(uos.listdir(path), key=str.lower): dataclient.sendall(make_description(path, fname, full)) except: # path may be a file name or pattern pattern = path.split("/")[-1] path = path[:-(len(pattern) + 1)] if path == "": path = "/" for fname in sorted(uos.listdir(path), key=str.lower): if fncmp(fname, pattern): dataclient.sendall(make_description(path, fname, full)) def make_description(path, fname, full): if full: stat = uos.stat(get_absolute_path(path, fname)) file_permissions = ("drwxr-xr-x" if (stat[0] & 0o170000 == 0o040000) else "-rw-r--r--") file_size = stat[6] description = "{} 1 owner group {:>10} Jan 1 2000 {}\r\n".format( file_permissions, file_size, fname) else: description = fname + "\r\n" return description def send_file_data(path, dataclient): with open(path, "rb") as file: chunk = file.read(512) while len(chunk) > 0: dataclient.sendall(chunk) chunk = file.read(512) def save_file_data(path, dataclient): with open(path, "wb") as file: chunk = dataclient.recv(512) while len(chunk) > 0: file.write(chunk) chunk = dataclient.recv(512) def get_absolute_path(cwd, payload): # Just a few special cases "..", "." and "" # If payload start's with /, set cwd to / # and consider the remainder a relative path if payload.startswith('/'): cwd = "/" for token in payload.split("/"): if token == '..': if cwd != '/': cwd = '/'.join(cwd.split('/')[:-1]) if cwd == '': cwd = '/' elif token != '.' and token != '': if cwd == '/': cwd += token else: cwd = cwd + '/' + token return cwd # compare fname against pattern. Pattern may contain # wildcards ? and *. def fncmp(fname, pattern): pi = 0 si = 0 while pi < len(pattern) and si < len(fname): if (fname[si] == pattern[pi]) or (pattern[pi] == '?'): si += 1 pi += 1 else: if pattern[pi] == '*': # recurse if (pi + 1) == len(pattern): return True while si < len(fname): if fncmp(fname[si:], pattern[pi+1:]): return True else: si += 1 return False else: return False if pi == len(pattern.rstrip("*")) and si == len(fname): return True else: return False def ftpserver(net, port=21, timeout=None): DATA_PORT = 13333 ftpsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) datasocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ftpsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) datasocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) ftpsocket.bind(socket.getaddrinfo("0.0.0.0", port)[0][4]) datasocket.bind(socket.getaddrinfo("0.0.0.0", DATA_PORT)[0][4]) ftpsocket.listen(1) ftpsocket.settimeout(timeout) datasocket.listen(1) datasocket.settimeout(None) msg_250_OK = '250 OK\r\n' msg_550_fail = '550 Failed\r\n' addr = net.ifconfig()[0] print("FTP Server started on ", addr) try: dataclient = None fromname = None do_run = True while do_run: cl, remote_addr = ftpsocket.accept() cl.settimeout(300) cwd = '/' try: # print("FTP connection from:", remote_addr) cl.sendall("220 Hello, this is Micropython.\r\n") while True: gc.collect() data = cl.readline().decode("utf-8").rstrip("\r\n") if len(data) > 8, DATA_PORT % 256)) dataclient, data_addr = datasocket.accept() print("FTP Data connection from:", data_addr) DATA_PORT = 13333 active = False elif command == "PORT": items = payload.split(",") if len(items) >= 6: data_addr = '.'.join(items[:4]) # replace by command session addr if data_addr == "127.0.1.1": data_addr = remote_addr DATA_PORT = int(items[4]) * 256 + int(items[5]) dataclient = socket.socket(socket.AF_INET, socket.SOCK_STREAM) dataclient.settimeout(10) dataclient.connect((data_addr, DATA_PORT)) print("FTP Data connection with:", data_addr) cl.sendall('200 OK\r\n') active = True else: cl.sendall('504 Fail\r\n') elif command == "LIST" or command == "NLST": if not payload.startswith("-"): place = path else: place = cwd try: cl.sendall("150 Here comes the directory listing.\r\n") send_list_data(place, dataclient, command == "LIST" or payload == "-l") cl.sendall("226 Listed.\r\n") except: cl.sendall(msg_550_fail) if dataclient is not None: dataclient.close() dataclient = None elif command == "RETR": try: cl.sendall("150 Opening data connection.\r\n") send_file_data(path, dataclient) cl.sendall("226 Transfer complete.\r\n") except: cl.sendall(msg_550_fail) if dataclient is not None: dataclient.close() dataclient = None elif command == "STOR": try: cl.sendall("150 Ok to send data.\r\n") save_file_data(path, dataclient) cl.sendall("226 Transfer complete.\r\n") except: cl.sendall(msg_550_fail) if dataclient is not None: dataclient.close() dataclient = None elif command == "DELE": try: uos.remove(path) cl.sendall(msg_250_OK) except: cl.sendall(msg_550_fail) elif command == "RMD" or command == "XRMD": try: uos.rmdir(path) cl.sendall(msg_250_OK) except: cl.sendall(msg_550_fail) elif command == "MKD" or command == "XMKD": try: uos.mkdir(path) cl.sendall(msg_250_OK) except: cl.sendall(msg_550_fail) elif command == "RNFR": fromname = path cl.sendall("350 Rename from\r\n") elif command == "RNTO": if fromname is not None: try: uos.rename(fromname, path) cl.sendall(msg_250_OK) except: cl.sendall(msg_550_fail) else: cl.sendall(msg_550_fail) fromname = None elif command == "MDTM": try: tm=localtime(uos.stat(path)[8]) cl.sendall('213 {:04d}{:02d}{:02d}{:02d}{:02d}{:02d}\r\n'.format(*tm[0:6])) except: cl.sendall('550 Fail\r\n') elif command == "STAT": if payload == "": cl.sendall("211-Connected to ({})\r\n" " Data address ({})\r\n" "211 TYPE: Binary STRU: File MODE:" " Stream\r\n".format( remote_addr[0], addr)) else: cl.sendall("213-Directory listing:\r\n") send_list_data(path, cl, True) cl.sendall("213 Done.\r\n") else: cl.sendall("502 Unsupported command.\r\n") print("Unsupported command {} with payload {}".format( command, payload)) except Exception as err: print(err) finally: cl.close() cl = None except Exception as e: print(e) finally: datasocket.close() ftpsocket.close() if dataclient is not None: dataclient.close() # ftpserver() ``` 实际的运行效果,shell端的输出 在FTP客户端可以看到开发板上的文件系统中的文件,并可以对其进行操作。 # 总结 Follow Me本期使用的PICO_W5500开发板主要集中与以太网应用,ping指令学习了解到ICMP协议的作用以及wireshark的使用,HTTP应用了解到TCP协议的应用,NTP获取时间学习到服务器和客户端的数据通讯方式,FTP应用学习到网络中实现文件传输服务的方法。而且使用micropython已经编译好的固件,省去了开发底层驱动的烦恼,可以专注于TCP协议的学习,作为入门和学习的不二之选。 ### [代码包](https://download.eeworld.com.cn/detail/EPTmachine/630302 "代码包")

  • 2024-02-22
  • 加入了学习《 【得捷电子Follow me第4期】》,观看 【得捷Follow me第4期】简易FTP文件服务器

  • 加入了学习《 【得捷电子Follow me第4期】》,观看 【得捷Follow me第4期】入门任务:开发环境搭建

  • 2024-02-20
  • 加入了学习《直播回放: FollowMe 4 W5500-EVB-Pico 使用入门》,观看 W5500-EVB-Pico 使用入门

  • 2024-02-03
  • 回复了主题帖: 健康守护礼的入围名单:脉搏监测健康仪,测出“不觉得”(测评邀请券主场活动)

    个人信息确认无误

  • 2023-12-28
  • 加入了学习《ADI - 世健 工业嘉年华》,观看 ADI - 世健 工业嘉年华 开幕致辞

统计信息

已有85人来访过

  • 芯积分:368
  • 好友:--
  • 主题:47
  • 回复:123

留言

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


现在还没有留言