diff --git a/bsp/essemi/es32f0334/README.md b/bsp/essemi/es32f0334/README.md
index a315447dda..369676b7d6 100644
--- a/bsp/essemi/es32f0334/README.md
+++ b/bsp/essemi/es32f0334/README.md
@@ -110,7 +110,7 @@ msh >
 
 ## 4. 联系人信息
 
-- [wangyongquan](https://github.com/wangyq2018) 
+- [liuhongyan](https://gitee.com/liuhongyan98) 
 
 ## 5. 参考
 
diff --git a/bsp/essemi/es32f0334/drivers/bsp_driver_example/.gitignore b/bsp/essemi/es32f0334/drivers/bsp_driver_example/.gitignore
new file mode 100644
index 0000000000..c6127b38c1
--- /dev/null
+++ b/bsp/essemi/es32f0334/drivers/bsp_driver_example/.gitignore
@@ -0,0 +1,52 @@
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
diff --git a/bsp/essemi/es32f0334/drivers/bsp_driver_example/README.md b/bsp/essemi/es32f0334/drivers/bsp_driver_example/README.md
new file mode 100644
index 0000000000..80f12e1949
--- /dev/null
+++ b/bsp/essemi/es32f0334/drivers/bsp_driver_example/README.md
@@ -0,0 +1,47 @@
+# 外设驱动测试用例
+
+## 1、介绍
+
+这个软件包包含一些外设设备操作的例程。
+
+### 1.1 例程说明
+
+| 文件             | 说明                            |
+| ---------------- | ------------------------------- |
+| adc_vol_sample.c       | 使用 ADC 设备转换电压数据 |
+| can_sample.c | 通过 CAN 设备发送一帧,并创建一个线程接收数据然后打印输出。 |
+| hwtimer_sample.c       | 使用 硬件定时器定时 |
+| i2c_sample.c     | 使用 i2c 设备进行读写 |
+| pm.c | 反复进入不同程度的睡眠。 |
+| led_blink_sample.c     |  使用 pin 设备控制 LED 闪烁 |
+| pin_beep_sample.c      | 使用 pin 设备控制蜂鸣器 |
+| pwm_led_sample.c       | 使用 pwm 设备控制 LED 的亮度 |
+| rtc_sample.c           | 使用 rtc 设备设置年月日时分秒信息 |
+| spi_sample.c     | 使用 spi 设备进行读写 |
+| uart_sample.c          | 使用 serial 设备中断接收及轮询发送模式收发数据 |
+
+### 1.2 依赖
+
+依赖设备管理模块提供的设备驱动。
+
+## 2、如何打开 外设驱动测试用例
+
+使用 外设驱动测试用例 需要在 RT-Thread 的menuconfig中选择它,具体路径如下:
+
+```
+Hardware Driver Config --->
+    Peripheral Driver test example--->
+```
+
+## 3、使用 外设驱动测试用例
+
+在打开 Peripheral Driver test example 后,当进行 BSP 编译时,选择的软件包相关源代码会被加入到 BSP 工程中进行编译。
+
+## 4、注意事项
+
+暂无。
+
+## 5、联系方式 & 感谢
+
+* 维护:[misonyo](https://github.com/misonyo)
+* 主页:https://github.com/RT-Thread-packages/peripheral-sample
diff --git a/bsp/essemi/es32f0334/drivers/bsp_driver_example/adc_vol_sample.c b/bsp/essemi/es32f0334/drivers/bsp_driver_example/adc_vol_sample.c
new file mode 100644
index 0000000000..19eed3f35d
--- /dev/null
+++ b/bsp/essemi/es32f0334/drivers/bsp_driver_example/adc_vol_sample.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-29     misonyo      first implementation.
+ */
+/*
+ * 程序清单: ADC 设备使用例程
+ * 例程导出了 adc_sample 命令到控制终端
+ * 命令调用格式:adc_sample
+ * 程序功能:通过 ADC 设备采样电压值并转换为数值。
+ *           示例代码参考电压为3.3V,转换位数为12位。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define ADC_DEV_NAME        "adc0"      /* ADC 设备名称 */
+#define ADC_DEV_CHANNEL     5           /* PA1 ADC 通道 */
+#define REFER_VOLTAGE       330         /* 参考电压 3.3V,数据精度乘以100保留2位小数*/
+#define CONVERT_BITS        (1 << 12)   /* 转换位数为12位 */
+
+static int adc_vol_sample(int argc, char *argv[])
+{
+    rt_adc_device_t adc_dev;
+    rt_uint32_t value, vol;
+    rt_err_t ret = RT_EOK;
+
+    /* 查找设备 */
+    adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);
+    if (adc_dev == RT_NULL)
+    {
+        rt_kprintf("adc sample run failed! can't find %s device!\n", ADC_DEV_NAME);
+        return RT_ERROR;
+    }
+
+    /* 使能设备 */
+    ret = rt_adc_enable(adc_dev, ADC_DEV_CHANNEL);
+
+    /* 读取采样值 */
+    value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
+    rt_kprintf("the value is :%d \n", value);
+
+    /* 转换为对应电压值 */
+    vol = value * REFER_VOLTAGE / CONVERT_BITS;
+    rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100);
+
+    /* 关闭通道 */
+    ret = rt_adc_disable(adc_dev, ADC_DEV_CHANNEL);
+
+    return ret;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(adc_vol_sample, adc voltage convert sample);
diff --git a/bsp/essemi/es32f0334/drivers/bsp_driver_example/can_sample.c b/bsp/essemi/es32f0334/drivers/bsp_driver_example/can_sample.c
new file mode 100644
index 0000000000..e63b11451d
--- /dev/null
+++ b/bsp/essemi/es32f0334/drivers/bsp_driver_example/can_sample.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-06-25     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 CAN 设备使用例程
+ * 例程导出了 can_sample 命令到控制终端
+ * 命令调用格式:can_sample can2
+ * 命令解释:命令第二个参数是要使用的 CAN 设备名称,为空则使用默认的 CAN 设备
+ * 程序功能:通过 CAN 设备发送一帧,并创建一个线程接收数据然后打印输出。
+*/
+
+#include <rtthread.h>
+#include "rtdevice.h"
+
+#define CAN_DEV_NAME       "can2"      /* CAN 设备名称 */
+
+static struct rt_semaphore rx_sem;     /* 用于接收消息的信号量 */
+static rt_device_t can_dev;            /* CAN 设备句柄 */
+
+/* 接收数据回调函数 */
+static rt_err_t can_rx_call(rt_device_t dev, rt_size_t size)
+{
+    /* CAN 接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
+    rt_sem_release(&rx_sem);
+
+    return RT_EOK;
+}
+
+static void can_rx_thread(void *parameter)
+{
+    int i;
+    struct rt_can_msg rxmsg = {0};
+
+    /* 设置接收回调函数 */
+    rt_device_set_rx_indicate(can_dev, can_rx_call);
+
+#ifdef RT_CAN_USING_HDR
+    
+    rt_err_t res;
+    
+    struct rt_can_filter_item items[5] =
+    {
+        RT_CAN_FILTER_ITEM_INIT(0x100, 0, 0, 0, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x100~0x1ff,hdr为-1,设置默认过滤表 */
+        RT_CAN_FILTER_ITEM_INIT(0x300, 0, 0, 0, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x300~0x3ff,hdr为-1 */
+        RT_CAN_FILTER_ITEM_INIT(0x211, 0, 0, 0, 0x7ff, RT_NULL, RT_NULL), /* std,match ID:0x211,hdr为-1 */
+        RT_CAN_FILTER_STD_INIT(0x486, RT_NULL, RT_NULL),                  /* std,match ID:0x486,hdr为-1 */
+        {0x555, 0, 0, 0, 0x7ff, 7,}                                       /* std,match ID:0x555,hdr为7,指定设置7号过滤表 */
+    };
+    struct rt_can_filter_config cfg = {5, 1, items}; /* 一共有5个过滤表 */
+    /* 设置硬件过滤表 */
+    res = rt_device_control(can_dev, RT_CAN_CMD_SET_FILTER, &cfg);
+    RT_ASSERT(res == RT_EOK);
+#endif
+
+    while (1)
+    {
+        /* hdr值为-1,表示直接从uselist链表读取数据 */
+        rxmsg.hdr = -1;
+        /* 阻塞等待接收信号量 */
+        rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
+        /* 从CAN读取一帧数据 */
+        rt_device_read(can_dev, 0, &rxmsg, sizeof(rxmsg));
+        /* 打印数据ID及内容 */
+        rt_kprintf("ID:%x  ", rxmsg.id);
+        for (i = 0; i < 8; i++)
+        {
+            rt_kprintf("%2x ", rxmsg.data[i]);
+        }
+
+        rt_kprintf("\n");
+    }
+}
+
+int can_sample(int argc, char *argv[])
+{
+    struct rt_can_msg msg = {0};
+    rt_err_t res;
+    rt_size_t  size;
+    rt_thread_t thread;
+    char can_name[RT_NAME_MAX];
+    
+    if (argc == 2)
+    {
+        rt_strncpy(can_name, argv[1], RT_NAME_MAX);
+    }
+    else
+    {
+        rt_strncpy(can_name, CAN_DEV_NAME, RT_NAME_MAX);
+    }
+
+    can_dev = rt_device_find(can_name);
+    if (!can_dev)
+    {
+        rt_kprintf("find %s failed!\n", can_name);
+        return RT_ERROR;
+    }
+
+    /* 初始化CAN接收信号量 */
+    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
+
+    /* 以中断接收及发送方式打开CAN设备 */
+    res = rt_device_open(can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);
+    RT_ASSERT(res == RT_EOK);
+
+    thread = rt_thread_create("can_rx", can_rx_thread, RT_NULL, 1024, 25, 10);
+    if (thread != RT_NULL)
+    {
+        rt_thread_startup(thread);
+    }
+    else
+    {
+        rt_kprintf("create can_rx thread failed!\n");
+    }
+
+    msg.id = 0x78;              /* ID为0x78 */
+    msg.ide = RT_CAN_STDID;     /* 标准格式 */
+    msg.rtr = RT_CAN_DTR;       /* 数据帧 */
+    msg.len = 8;                /* 数据长度为8 */
+    /* 待发送的8字节数据 */
+    msg.data[0] = 0x00;
+    msg.data[1] = 0x11;
+    msg.data[2] = 0x22;
+    msg.data[3] = 0x33;
+    msg.data[4] = 0x44;
+    msg.data[5] = 0x55;
+    msg.data[6] = 0x66;
+    msg.data[7] = 0x77;
+    /* 发送一帧CAN数据 */
+    size = rt_device_write(can_dev, 0, &msg, sizeof(msg));
+    if (size == 0)
+    {
+        rt_kprintf("can dev write data failed!\n");
+    }
+    
+    return res;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(can_sample, can device sample);
diff --git a/bsp/essemi/es32f0334/drivers/bsp_driver_example/hwtimer_sample.c b/bsp/essemi/es32f0334/drivers/bsp_driver_example/hwtimer_sample.c
new file mode 100644
index 0000000000..e2e39664f3
--- /dev/null
+++ b/bsp/essemi/es32f0334/drivers/bsp_driver_example/hwtimer_sample.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-30     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 hwtimer 设备使用例程
+ * 例程导出了 hwtimer_sample 命令到控制终端
+ * 命令调用格式:hwtimer_sample
+ * 程序功能:硬件定时器超时回调函数周期性的打印当前tick值,2次tick值之差换算为时间等同于定时时间值。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define HWTIMER_DEV_NAME   "timer0"     /* 定时器名称 */
+
+/* 定时器超时回调函数 */
+static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size)
+{
+    rt_kprintf("tick is :%d !\n", rt_tick_get());
+
+    return 0;
+}
+
+static int hwtimer_sample(int argc, char *argv[])
+{
+    rt_err_t ret = RT_EOK;
+    rt_hwtimerval_t timeout_s;      /* 定时器超时值 */
+    rt_device_t hw_dev = RT_NULL;   /* 定时器设备句柄 */
+    rt_hwtimer_mode_t mode;         /* 定时器模式 */
+
+    /* 查找定时器设备 */
+    hw_dev = rt_device_find(HWTIMER_DEV_NAME);
+    if (hw_dev == RT_NULL)
+    {
+        rt_kprintf("hwtimer sample run failed! can't find %s device!\n", HWTIMER_DEV_NAME);
+        return RT_ERROR;
+    }
+
+    /* 以读写方式打开设备 */
+    ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
+    if (ret != RT_EOK)
+    {
+        rt_kprintf("open %s device failed!\n", HWTIMER_DEV_NAME);
+        return ret;
+    }
+
+    /* 设置超时回调函数 */
+    rt_device_set_rx_indicate(hw_dev, timeout_cb);
+
+    /* 设置模式为周期性定时器 */
+    mode = HWTIMER_MODE_PERIOD;
+    ret = rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
+    if (ret != RT_EOK)
+    {
+        rt_kprintf("set mode failed! ret is :%d\n", ret);
+        return ret;
+    }
+
+    /* 设置定时器超时值为5s并启动定时器 */
+    timeout_s.sec = 5;      /* 秒 */
+    timeout_s.usec = 0;     /* 微秒 */
+
+    if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
+    {
+        rt_kprintf("set timeout value failed\n");
+        return RT_ERROR;
+    }
+
+    /* 延时3500ms */
+    rt_thread_mdelay(3500);
+
+    /* 读取定时器当前值 */
+    rt_device_read(hw_dev, 0, &timeout_s, sizeof(timeout_s));
+    rt_kprintf("Read: Sec = %d, Usec = %d\n", timeout_s.sec, timeout_s.usec);
+
+    return ret;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(hwtimer_sample, hwtimer sample);
diff --git a/bsp/essemi/es32f0334/drivers/bsp_driver_example/i2c_sample.c b/bsp/essemi/es32f0334/drivers/bsp_driver_example/i2c_sample.c
new file mode 100644
index 0000000000..2d386433c6
--- /dev/null
+++ b/bsp/essemi/es32f0334/drivers/bsp_driver_example/i2c_sample.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-15     liuhy       first implementation.
+ */
+/*
+ * 程序清单:这是一个 I2C 设备使用例程
+ * 例程导出了 i2c_io_sample 命令到控制终端
+ * 命令调用格式:i2c_io_sample
+ * 命令解释:使用默认的I2C总线设备
+ * 程序功能:通过 I2C 设备接收数据并打印,然后将接收的字符加1输出。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define I2C_BUS_NAME          "i2c1"  /* I2C总线设备名称 */
+#define SLAVE_ADDR                  0x2D    /* 从机地址 */
+#define STR_LEN                       16    /* 接收发送的数据长度 */
+
+static void i2c_io_sample(int argc, char *argv[])
+{
+    
+    struct rt_i2c_bus_device *i2c_bus = RT_NULL;     /* I2C总线设备句柄 */
+    struct rt_i2c_msg temp_msg;                             /* I2C消息 */
+    rt_uint8_t buffer[STR_LEN] = { 0U }; 
+    rt_uint32_t i,num_msg;
+    rt_size_t s_stat;
+    
+    i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(I2C_BUS_NAME);    /* 通过名字获取I2C总线设备的句柄 */
+    
+    if( i2c_bus == RT_NULL)
+    {
+        rt_kprintf("can't find i2c device :%s !\n",I2C_BUS_NAME);
+        
+        return;
+    }
+    
+        /*初始化消息*/
+        temp_msg.addr = SLAVE_ADDR;  /* 从机地址 */
+        temp_msg.len  = STR_LEN;     /* 传输的数据长度 */
+        temp_msg.buf = buffer;       /* 读写缓存器 */
+    
+        num_msg = 1;             /* 传输一条消息 */
+    
+        temp_msg.flags = RT_I2C_RD;             /* I2C读 */
+        s_stat = rt_i2c_transfer(i2c_bus,&temp_msg,num_msg);   /* 传输消息 */
+        
+        rt_thread_mdelay(400); 
+        
+        if( s_stat == num_msg )
+        {
+            rt_kprintf("receive successful. \n receive messege : %s \n:",buffer);
+            
+            for( i = 0 ; i < STR_LEN ; i++)
+            rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+            rt_kprintf("\n");
+        }
+        else
+        {
+            rt_kprintf("device s% recieve fail \n buffer : s%\n",I2C_BUS_NAME,buffer);
+            return;
+        }
+        
+        for( i = 0 ; i < STR_LEN ; i++)
+        buffer[i]++;
+    
+        temp_msg.flags = RT_I2C_WR;             /* I2C写 */
+        s_stat = rt_i2c_transfer(i2c_bus,&temp_msg,num_msg);   /* 传输一条 */
+        
+        rt_thread_mdelay(400);
+        
+        if( s_stat == num_msg )
+        {
+            rt_kprintf(" send successful \n messege : %s \n:",buffer);
+            
+            for( i = 0 ; i < STR_LEN ; i++)
+            rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+            rt_kprintf("\n");
+        }
+        else
+        {
+            rt_kprintf("device s% send fail \n",I2C_BUS_NAME);
+            return;
+        }
+        
+        return;
+    
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(i2c_io_sample, i2c io sample);
diff --git a/bsp/essemi/es32f0334/drivers/bsp_driver_example/led_blink_sample.c b/bsp/essemi/es32f0334/drivers/bsp_driver_example/led_blink_sample.c
new file mode 100644
index 0000000000..c073b5e5a7
--- /dev/null
+++ b/bsp/essemi/es32f0334/drivers/bsp_driver_example/led_blink_sample.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-09-25     misonyo      first edition.
+ */
+/*
+ * 程序清单:这是一个通过PIN脚控制LED亮灭的使用例程
+ * 例程导出了 led_sample 命令到控制终端
+ * 命令调用格式:led_sample 
+ * 命令解释:命令第二个参数是要使用的PIN脚编号,为空则使用例程默认的引脚编号。
+ * 程序功能:程序创建一个led线程,线程每隔1000ms改变PIN脚状态,达到控制led灯
+ *            亮灭的效果。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <stdlib.h>
+
+/* PIN脚编号,查看驱动文件drv_gpio.c确定 */
+#define LED_PIN_NUM    45  /*PA12*/
+static int pin_num;
+
+static void led_entry(void *parameter)
+{
+    int count = 0;
+    /* 设置PIN脚模式为输出 */
+    rt_pin_mode(pin_num, PIN_MODE_OUTPUT);
+
+    while (1)
+    {
+        count++;
+        rt_kprintf("thread run count : %d\r\n", count);
+        /* 拉低PIN脚 */
+        rt_pin_write(pin_num, PIN_LOW);
+        rt_kprintf("led on!\r\n");
+        /* 延时1000ms */
+        rt_thread_mdelay(1000);
+
+        /* 拉高PIN脚 */
+        rt_pin_write(pin_num, PIN_HIGH);
+        rt_kprintf("led off!\r\n");
+        rt_thread_mdelay(1000);
+    }
+}
+
+static int led_sample(int argc, char *argv[])
+{
+    rt_thread_t tid;
+    rt_err_t ret = RT_EOK;
+
+    /* 判断命令行参数是否给定了PIN脚编号 */
+    if (argc == 2)
+    {
+        pin_num = atoi(argv[1]);
+    }
+    else
+    {
+        pin_num = LED_PIN_NUM;
+    }
+
+    tid = rt_thread_create("led",
+                           led_entry,
+                           RT_NULL,
+                           512,
+                           RT_THREAD_PRIORITY_MAX / 3,
+                           20);
+    if (tid != RT_NULL)
+    {
+        rt_thread_startup(tid);
+    }
+    else
+    {
+        ret = RT_ERROR;
+    }
+
+    return ret;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(led_sample, led sample);
diff --git a/bsp/essemi/es32f0334/drivers/bsp_driver_example/pin_beep_sample.c b/bsp/essemi/es32f0334/drivers/bsp_driver_example/pin_beep_sample.c
new file mode 100644
index 0000000000..911a0c800e
--- /dev/null
+++ b/bsp/essemi/es32f0334/drivers/bsp_driver_example/pin_beep_sample.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-08-15     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 PIN 设备使用例程
+ * 例程导出了 pin_beep_sample 命令到控制终端
+ * 命令调用格式:pin_beep_sample
+ * 程序功能:通过按键控制蜂鸣器对应引脚的电平状态控制蜂鸣器
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+/* 引脚编号,通过查看驱动文件drv_gpio.c确定 */
+#ifndef BEEP_PIN_NUM
+    #define BEEP_PIN_NUM            45  /* PA12 */
+#endif
+#ifndef KEY0_PIN_NUM
+    #define KEY0_PIN_NUM            18  /* PF0 */
+#endif
+#ifndef KEY1_PIN_NUM
+    #define KEY1_PIN_NUM            19  /* PF1 */
+#endif
+
+void beep_on(void *args)
+{
+    rt_kprintf("turn on beep!\n");
+
+    rt_pin_write(BEEP_PIN_NUM, PIN_HIGH);
+}
+
+void beep_off(void *args)
+{
+    rt_kprintf("turn off beep!\n");
+
+    rt_pin_write(BEEP_PIN_NUM, PIN_LOW);
+}
+
+static void pin_beep_sample(void)
+{
+    /* 蜂鸣器引脚为输出模式 */
+    rt_pin_mode(BEEP_PIN_NUM, PIN_MODE_OUTPUT);
+    /* 默认低电平 */
+    rt_pin_write(BEEP_PIN_NUM, PIN_LOW);
+
+    /* 按键0引脚为输入模式 */
+    rt_pin_mode(KEY0_PIN_NUM, PIN_MODE_INPUT_PULLUP);
+    /* 绑定中断,下降沿模式,回调函数名为beep_on */
+    rt_pin_attach_irq(KEY0_PIN_NUM, PIN_IRQ_MODE_FALLING, beep_on, RT_NULL);
+    /* 使能中断 */
+    rt_pin_irq_enable(KEY0_PIN_NUM, PIN_IRQ_ENABLE);
+
+    /* 按键1引脚为输入模式 */
+    rt_pin_mode(KEY1_PIN_NUM, PIN_MODE_INPUT_PULLUP);
+    /* 绑定中断,下降沿模式,回调函数名为beep_off */
+    rt_pin_attach_irq(KEY1_PIN_NUM, PIN_IRQ_MODE_FALLING, beep_off, RT_NULL);
+    /* 使能中断 */
+    rt_pin_irq_enable(KEY1_PIN_NUM, PIN_IRQ_ENABLE);
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(pin_beep_sample, pin beep sample);
diff --git a/bsp/essemi/es32f0334/drivers/bsp_driver_example/pm_sample.c b/bsp/essemi/es32f0334/drivers/bsp_driver_example/pm_sample.c
new file mode 100644
index 0000000000..08258b1650
--- /dev/null
+++ b/bsp/essemi/es32f0334/drivers/bsp_driver_example/pm_sample.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-15     liuhy       first implementation.
+ */
+/*
+ * 程序清单:这是一个 pm睡眠唤醒的使用例程
+ * 例程导出了 pm_sample 命令到控制终端
+ * 命令调用格式:pm_sample
+ * 命令解释:进入不同的睡眠模式,然后用按键唤醒
+ * 程序功能:通过串口输出字符串,告知进入睡眠和唤醒睡眠的情况。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define PM_NAME       "pm"      /* 设备名称 */
+#define WAKE_UP_PIN     18      /* 唤醒源 */
+#define SLEEP_TIMES     12      /* 进入睡眠次数,轮流进入不同的睡眠模式,包括无睡眠模式 */
+
+struct pm_callback_t
+{
+     volatile int in_fun_times;   /*进入函数的次数*/
+     volatile char flag;          /*标志*/
+     volatile int mode;           /*需要打印的模式*/
+};
+
+volatile struct pm_callback_t g_pm_data;
+
+/*进入睡眠前,睡眠唤醒后,都会进入。*/
+/*函数打印睡眠相关的信息*/
+void sleep_in_out_callback(rt_uint8_t event, rt_uint8_t mode, void *data)
+{
+    /*没有标志,不处理*/
+    if(!(g_pm_data.flag))
+    {
+        return;
+    }
+    
+    /*标志不正常,清空标志*/
+    if((g_pm_data.flag) > 2)
+    {
+        (g_pm_data.flag) = 0;
+        return;
+    }
+    
+    /*模式不匹配*/
+    if(g_pm_data.mode != mode )
+    {
+        return;
+    }
+ 
+    /*进入的事件*/
+    switch(event)
+    {
+        /*进入睡眠前*/
+        case RT_PM_ENTER_SLEEP: g_pm_data.flag = 1;
+                                rt_kprintf("\n\r##%d :  ENTER  ",g_pm_data.in_fun_times);
+                                g_pm_data.in_fun_times++;     /*进入睡眠次数+1*/
+                                break;
+        /*睡眠唤醒后*/
+        case RT_PM_EXIT_SLEEP:  g_pm_data.flag = 0;  /*睡眠唤醒后*/
+                                rt_kprintf("\n\rEXIT\n\r");
+                                rt_pm_release(mode);   /*释放休眠模式*/
+                                return;
+        
+        default: break;
+        
+    };
+    
+    /*当前的睡眠模式*/
+    switch(mode)
+    {
+        case PM_SLEEP_MODE_NONE: rt_kprintf("PM_SLEEP_MODE_NONE\n\r");
+                                break;
+        case PM_SLEEP_MODE_IDLE:  rt_kprintf("PM_SLEEP_MODE_IDLE\n\r");
+                                break;
+        case PM_SLEEP_MODE_LIGHT: rt_kprintf("PM_SLEEP_MODE_LIGHT\n\r");
+                                break;
+        case PM_SLEEP_MODE_DEEP:  rt_kprintf("PM_SLEEP_MODE_DEEP\n\r");
+                                break;
+        case PM_SLEEP_MODE_STANDBY: rt_kprintf("PM_SLEEP_MODE_STANDBY\n\r");
+                                break;
+        case PM_SLEEP_MODE_SHUTDOWN:  rt_kprintf("PM_SLEEP_MODE_SHUTDOWN\n\r");
+                                break;      
+        case PM_SLEEP_MODE_MAX:  rt_kprintf("PM_SLEEP_MODE_MAX\n\r");
+                                break;
+        default: break;           
+    }
+    
+}
+
+/* pm测试函数 */
+static void pm_test(void *parameter)
+{
+    int in_mode[7],i = 0;
+    
+        g_pm_data.in_fun_times = 0;
+        g_pm_data.flag = 0;
+    
+        in_mode[0] = PM_SLEEP_MODE_NONE;
+        in_mode[1] = PM_SLEEP_MODE_IDLE;
+        in_mode[2] = PM_SLEEP_MODE_LIGHT;
+        in_mode[3] = PM_SLEEP_MODE_DEEP;
+        in_mode[4] = PM_SLEEP_MODE_STANDBY;
+        in_mode[5] = PM_SLEEP_MODE_SHUTDOWN;
+        in_mode[6] = PM_SLEEP_MODE_MAX;
+    
+    /*设置回调函数和私有数据*/
+    rt_pm_notify_set(sleep_in_out_callback,RT_NULL);
+       
+    while(i < SLEEP_TIMES)
+   {
+       
+       g_pm_data.mode = in_mode[i%6];
+       
+       /*无休眠模式,不赋予标志*/
+       if(g_pm_data.mode != PM_SLEEP_MODE_NONE)
+       {
+            g_pm_data.flag = 2;  
+       
+       }
+       
+       /*请求选择的休眠模式*/
+       rt_pm_request(in_mode[i%6]);
+
+       rt_thread_mdelay(500);
+       
+       /*无休眠模式,不需要额外的等待*/
+       while(( g_pm_data.flag != 0 )&&(g_pm_data.mode != PM_SLEEP_MODE_NONE))
+       {
+           rt_thread_mdelay(500);
+       }
+       
+       /*释放选择的休眠模式*/
+       rt_pm_release(in_mode[i%6]);
+       
+       i++;
+       
+   }
+      /*清除回调函数和私有数据*/
+    rt_pm_notify_set(RT_NULL,RT_NULL);
+   rt_kprintf("thread pm_test close\n\r");
+}
+
+/*按键唤醒的回调函数*/
+void wake_by_pin(void *args)
+{
+
+}
+
+static int pm_sample(int argc, char *argv[])
+{
+    rt_thread_t thread;
+    
+    /* 按键引脚为输入模式 */
+    rt_pin_mode(WAKE_UP_PIN, PIN_MODE_INPUT_PULLUP);
+    
+    /* 绑定中断,下降沿模式,回调函数名为wake_by_pin */
+    rt_pin_attach_irq(WAKE_UP_PIN, PIN_IRQ_MODE_RISING, wake_by_pin, RT_NULL);
+    /* 使能中断 */
+    rt_pin_irq_enable(WAKE_UP_PIN, PIN_IRQ_ENABLE);
+    
+    thread = rt_thread_create("pm_test", pm_test, RT_NULL, 1024, 25, 10);
+    
+    if (thread != RT_NULL)
+    {
+        rt_thread_startup(thread);
+    }
+    else
+    {
+        rt_kprintf("create pm_test thread failed!\n\r");
+    }
+    
+    return RT_EOK;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(pm_sample, pm sample);
diff --git a/bsp/essemi/es32f0334/drivers/bsp_driver_example/pwm_led_sample.c b/bsp/essemi/es32f0334/drivers/bsp_driver_example/pwm_led_sample.c
new file mode 100644
index 0000000000..1ac2361445
--- /dev/null
+++ b/bsp/essemi/es32f0334/drivers/bsp_driver_example/pwm_led_sample.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-25     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 PWM 设备使用例程
+ * 例程导出了 pwm_led_sample 命令到控制终端
+ * 命令调用格式:pwm_led_sample
+ * 程序功能:通过 PWM 设备控制 LED 灯的亮度,可以看到LED不停的由暗变到亮,然后又从亮变到暗。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define LED_PIN_NUM         45      /* PA12 LED PIN脚编号,查看驱动文件drv_gpio.c确定 */
+#define PWM_DEV_NAME        "pwm0"  /* PWM设备名称 */
+#define PWM_DEV_CHANNEL     2       /* PA9 PWM通道 */
+
+struct rt_device_pwm *pwm_dev;      /* PWM设备句柄 */
+
+static int pwm_led_sample(int argc, char *argv[])
+{
+    rt_uint32_t period, pulse, dir;
+
+    period = 500000;    /* 周期为0.5ms,单位为纳秒ns */
+    dir = 1;            /* PWM脉冲宽度值的增减方向 */
+    pulse = 0;          /* PWM脉冲宽度值,单位为纳秒ns */
+
+    /* 查找设备 */
+    pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
+    if (pwm_dev == RT_NULL)
+    {
+        rt_kprintf("pwm sample run failed! can't find %s device!\n", PWM_DEV_NAME);
+        return RT_ERROR;
+    }
+
+    /* 设置PWM周期和脉冲宽度默认值 */
+    rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
+    /* 使能设备 */
+    rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
+    
+    while (1)
+    {
+        rt_thread_mdelay(50);
+        if (dir)
+        {
+            pulse += 5000;      /* 从0值开始每次增加5000ns */
+        }
+        else
+        {
+            pulse -= 5000;      /* 从最大值开始每次减少5000ns */
+        }
+        if (pulse >= period)
+        {
+            dir = 0;
+        }
+        if (0 == pulse)
+        {
+            dir = 1;
+        }
+
+        /* 设置PWM周期和脉冲宽度 */
+        rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
+    }
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(pwm_led_sample, pwm sample);
diff --git a/bsp/essemi/es32f0334/drivers/bsp_driver_example/rtc_sample.c b/bsp/essemi/es32f0334/drivers/bsp_driver_example/rtc_sample.c
new file mode 100644
index 0000000000..711a3a0ebb
--- /dev/null
+++ b/bsp/essemi/es32f0334/drivers/bsp_driver_example/rtc_sample.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-30     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 RTC 设备使用例程
+ * 例程导出了 rtc_sample 命令到控制终端
+ * 命令调用格式:rtc_sample
+ * 程序功能:设置RTC设备的日期和时间,延时一段时间后获取当前时间并打印显示。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+static int rtc_sample(int argc, char *argv[])
+{
+    rt_err_t ret = RT_EOK;
+    time_t now;
+
+    /* 设置日期 */
+    ret = set_date(2018, 12, 3);
+    if (ret != RT_EOK)
+    {
+        rt_kprintf("set RTC date failed\n");
+        return ret;
+    }
+
+    /* 设置时间 */
+    ret = set_time(11, 15, 50);
+    if (ret != RT_EOK)
+    {
+        rt_kprintf("set RTC time failed\n");
+        return ret;
+    }
+
+    /* 延时3秒 */
+    rt_thread_mdelay(3000);
+
+    /* 获取时间 */
+    now = time(RT_NULL);
+    rt_kprintf("%s\n", ctime(&now));
+
+    return ret;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(rtc_sample, rtc sample);
diff --git a/bsp/essemi/es32f0334/drivers/bsp_driver_example/spi_sample.c b/bsp/essemi/es32f0334/drivers/bsp_driver_example/spi_sample.c
new file mode 100644
index 0000000000..994888cdb0
--- /dev/null
+++ b/bsp/essemi/es32f0334/drivers/bsp_driver_example/spi_sample.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-15     liuhy       first implementation.
+ */
+/*
+ * 程序清单:这是一个 SPI 设备使用例程
+ * 例程导出了 spi_io_sample 命令到控制终端
+ * 命令调用格式:spi_io_sample
+ * 程序功能:通过SPI设备先读取数据,然后每个字符加1后输出。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define SPI_DEVICE_NAME     "spi00"
+#define BUF_LEN             16
+
+static void spi_io_sample(int argc, char *argv[])
+{
+    struct rt_spi_device * spi_dev;          /* spi设备的句柄 */
+    struct rt_spi_configuration spi_config;
+    rt_uint8_t i,buffer[BUF_LEN] = { 0U };
+    rt_err_t s_stat;
+    rt_err_t result;
+    
+     /* 查找 spi设备 获取spi设备句柄 */
+    spi_dev = (struct rt_spi_device *)rt_device_find(SPI_DEVICE_NAME);
+    
+    if (spi_dev == RT_NULL)
+    {
+        rt_kprintf("spi sample run failed! can't find %s device!\n", SPI_DEVICE_NAME);
+        return;
+    }
+    
+    
+    /* 清空配置结构体 */
+    rt_memset(&spi_config,0,sizeof(struct rt_spi_configuration));
+    
+    spi_config.mode &= ~RT_SPI_SLAVE; /* 主机模式 */
+    spi_config.mode &= ~RT_SPI_3WIRE; /* 4线,双向传输 */
+    spi_config.mode |= RT_SPI_CPHA;   /* 第二边沿采样 */
+    spi_config.mode |= RT_SPI_CPOL;   /* 空闲高电平 */
+    spi_config.mode |= RT_SPI_NO_CS;  /* 禁用软件从机选择管理 */
+    spi_config.mode |= RT_SPI_MSB;    /* 高位在前 */
+    
+    spi_config.data_width = 8;        /* 数据长度:8 */
+    
+    spi_config.max_hz = 2000000;      /* 最快时钟频率 */
+    
+    /* 配置SPI设备 */
+    s_stat = rt_spi_configure(spi_dev,&spi_config);
+    
+    if(s_stat != RT_EOK)
+    {
+        rt_kprintf(" spi config fail !\n ");
+        return;
+    }
+    
+    
+    /* 获取总线 ,防止总线被多个线程同时使用 */
+    result = rt_spi_take_bus(spi_dev);
+    
+    if (result != RT_EOK)
+    {
+        rt_kprintf(" %s take spi bus  failed! \n", SPI_DEVICE_NAME);
+        return;
+    }
+    
+    /* 选中片选 */
+    result = rt_spi_take(spi_dev);
+    
+    if (result != RT_EOK)
+    {
+        rt_kprintf(" %s take spi cs  failed! \n", SPI_DEVICE_NAME);
+        return;
+    }
+    
+    
+    /*接收一次数据*/
+    result = rt_spi_recv(spi_dev,buffer,BUF_LEN);
+    
+    if(result != BUF_LEN)
+    {
+        rt_kprintf("receive fail. \n buffer is : %s \n:",buffer);
+            
+        for( i = 0 ; i < BUF_LEN ; i++)
+         rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+        rt_kprintf("\n");
+        
+        return;
+    }
+    
+    rt_kprintf("receive successful. \n buffer is : %s \n:",buffer);
+            
+    for( i = 0 ; i < BUF_LEN ; i++)
+    rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+    rt_kprintf("\n");
+    
+    /* 将接收到的数据加1 */
+    for( i = 0 ; i < BUF_LEN ; i++)
+      buffer[i]++;
+    
+    /*发送数据*/
+    result = rt_spi_send(spi_dev,buffer,BUF_LEN);
+    
+    if(result != BUF_LEN)
+    {
+        rt_kprintf("send fail. \n buffer is : %s \n:",buffer);
+            
+        for( i = 0 ; i < BUF_LEN ; i++)
+         rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+        rt_kprintf("\n");
+        
+        return;
+    }
+    
+    rt_kprintf("send successful. \n buffer is : %s \n:",buffer);
+            
+    for( i = 0 ; i < BUF_LEN ; i++)
+    rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+    rt_kprintf("\n");
+   
+    /* 释放片选 */
+    result = rt_spi_release(spi_dev);
+    
+    if (result != RT_EOK)
+    {
+        rt_kprintf(" %s release spi cs failed! \n", SPI_DEVICE_NAME);
+        return;
+    } 
+    
+    /* 释放总线 */
+    result = rt_spi_release_bus(spi_dev);
+    
+    if (result != RT_EOK)
+    {
+        rt_kprintf(" %s release spi bus  failed! \n", SPI_DEVICE_NAME);
+        return;
+    }
+    
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(spi_io_sample, spi  sample);
diff --git a/bsp/essemi/es32f0334/drivers/bsp_driver_example/uart_sample.c b/bsp/essemi/es32f0334/drivers/bsp_driver_example/uart_sample.c
new file mode 100644
index 0000000000..cbfd6bccef
--- /dev/null
+++ b/bsp/essemi/es32f0334/drivers/bsp_driver_example/uart_sample.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-08-15     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 串口 设备使用例程
+ * 例程导出了 uart_sample 命令到控制终端
+ * 命令调用格式:uart_sample uart2
+ * 命令解释:命令第二个参数是要使用的串口设备名称,为空则使用默认的串口设备
+ * 程序功能:通过串口输出字符串"hello RT-Thread!",然后错位输出输入的字符
+*/
+
+#include <rtthread.h>
+
+#define SAMPLE_UART_NAME       "uart1"      /* 串口设备名称 */
+
+/* 用于接收消息的信号量 */
+static struct rt_semaphore rx_sem;
+static rt_device_t serial;
+
+/* 接收数据回调函数 */
+static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
+{
+    /* 串口接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
+    rt_sem_release(&rx_sem);
+
+    return RT_EOK;
+}
+
+static void serial_thread_entry(void *parameter)
+{
+    char ch;
+
+    while (1)
+    {
+        /* 从串口读取一个字节的数据,没有读取到则等待接收信号量 */
+        while (rt_device_read(serial, -1, &ch, 1) != 1)
+        {
+            /* 阻塞等待接收信号量,等到信号量后再次读取数据 */
+            rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
+        }
+        /* 读取到的数据通过串口错位输出 */
+        ch = ch + 1;
+        rt_device_write(serial, 0, &ch, 1);
+    }
+}
+
+static int uart_sample(int argc, char *argv[])
+{
+    rt_err_t ret = RT_EOK;
+    char uart_name[RT_NAME_MAX];
+    char str[] = "hello RT-Thread!\r\n";
+
+    if (argc == 2)
+    {
+        rt_strncpy(uart_name, argv[1], RT_NAME_MAX);
+    }
+    else
+    {
+        rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX);
+    }
+
+    /* 查找串口设备 */
+    serial = rt_device_find(uart_name);
+    if (!serial)
+    {
+        rt_kprintf("find %s failed!\n", uart_name);
+        return RT_ERROR;
+    }
+
+    /* 初始化信号量 */
+    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
+    /* 以中断接收及轮询发送方式打开串口设备 */
+    rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
+    /* 设置接收回调函数 */
+    rt_device_set_rx_indicate(serial, uart_input);
+    /* 发送字符串 */
+    rt_device_write(serial, 0, str, (sizeof(str) - 1));
+
+    /* 创建 serial 线程 */
+    rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
+    /* 创建成功则启动线程 */
+    if (thread != RT_NULL)
+    {
+        rt_thread_startup(thread);
+    }
+    else
+    {
+        ret = RT_ERROR;
+    }
+
+    return ret;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(uart_sample, uart device sample);
diff --git a/bsp/essemi/es32f0334/figures/ES-PDS-ES32F369x-V1.3.jpg b/bsp/essemi/es32f0334/figures/ES-PDS-ES32F369x-V1.3.jpg
new file mode 100644
index 0000000000..e8d8cc653c
Binary files /dev/null and b/bsp/essemi/es32f0334/figures/ES-PDS-ES32F369x-V1.3.jpg differ
diff --git a/bsp/essemi/es32f0334/figures/内核用例.PNG b/bsp/essemi/es32f0334/figures/内核用例.PNG
new file mode 100644
index 0000000000..4c4f8e05ba
Binary files /dev/null and b/bsp/essemi/es32f0334/figures/内核用例.PNG differ
diff --git a/bsp/essemi/es32f0334/figures/内核配置.PNG b/bsp/essemi/es32f0334/figures/内核配置.PNG
new file mode 100644
index 0000000000..f5901c0e59
Binary files /dev/null and b/bsp/essemi/es32f0334/figures/内核配置.PNG differ
diff --git a/bsp/essemi/es32f0334/figures/驱动用例.PNG b/bsp/essemi/es32f0334/figures/驱动用例.PNG
new file mode 100644
index 0000000000..5abb7ac952
Binary files /dev/null and b/bsp/essemi/es32f0334/figures/驱动用例.PNG differ
diff --git a/bsp/essemi/es32f0334/figures/驱动配置.PNG b/bsp/essemi/es32f0334/figures/驱动配置.PNG
new file mode 100644
index 0000000000..925342ec24
Binary files /dev/null and b/bsp/essemi/es32f0334/figures/驱动配置.PNG differ
diff --git a/bsp/essemi/es32f0334/libraries/ES32F033x_ALD_StdPeriph_Driver/EASTSOFT_ES32F033x_ALD.chm b/bsp/essemi/es32f0334/libraries/ES32F033x_ALD_StdPeriph_Driver/EASTSOFT_ES32F033x_ALD.chm
new file mode 100644
index 0000000000..9f5df67080
Binary files /dev/null and b/bsp/essemi/es32f0334/libraries/ES32F033x_ALD_StdPeriph_Driver/EASTSOFT_ES32F033x_ALD.chm differ
diff --git a/bsp/essemi/es32f0654/drivers/bsp_driver_example/.gitignore b/bsp/essemi/es32f0654/drivers/bsp_driver_example/.gitignore
new file mode 100644
index 0000000000..c6127b38c1
--- /dev/null
+++ b/bsp/essemi/es32f0654/drivers/bsp_driver_example/.gitignore
@@ -0,0 +1,52 @@
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
diff --git a/bsp/essemi/es32f0654/drivers/bsp_driver_example/README.md b/bsp/essemi/es32f0654/drivers/bsp_driver_example/README.md
new file mode 100644
index 0000000000..80f12e1949
--- /dev/null
+++ b/bsp/essemi/es32f0654/drivers/bsp_driver_example/README.md
@@ -0,0 +1,47 @@
+# 外设驱动测试用例
+
+## 1、介绍
+
+这个软件包包含一些外设设备操作的例程。
+
+### 1.1 例程说明
+
+| 文件             | 说明                            |
+| ---------------- | ------------------------------- |
+| adc_vol_sample.c       | 使用 ADC 设备转换电压数据 |
+| can_sample.c | 通过 CAN 设备发送一帧,并创建一个线程接收数据然后打印输出。 |
+| hwtimer_sample.c       | 使用 硬件定时器定时 |
+| i2c_sample.c     | 使用 i2c 设备进行读写 |
+| pm.c | 反复进入不同程度的睡眠。 |
+| led_blink_sample.c     |  使用 pin 设备控制 LED 闪烁 |
+| pin_beep_sample.c      | 使用 pin 设备控制蜂鸣器 |
+| pwm_led_sample.c       | 使用 pwm 设备控制 LED 的亮度 |
+| rtc_sample.c           | 使用 rtc 设备设置年月日时分秒信息 |
+| spi_sample.c     | 使用 spi 设备进行读写 |
+| uart_sample.c          | 使用 serial 设备中断接收及轮询发送模式收发数据 |
+
+### 1.2 依赖
+
+依赖设备管理模块提供的设备驱动。
+
+## 2、如何打开 外设驱动测试用例
+
+使用 外设驱动测试用例 需要在 RT-Thread 的menuconfig中选择它,具体路径如下:
+
+```
+Hardware Driver Config --->
+    Peripheral Driver test example--->
+```
+
+## 3、使用 外设驱动测试用例
+
+在打开 Peripheral Driver test example 后,当进行 BSP 编译时,选择的软件包相关源代码会被加入到 BSP 工程中进行编译。
+
+## 4、注意事项
+
+暂无。
+
+## 5、联系方式 & 感谢
+
+* 维护:[misonyo](https://github.com/misonyo)
+* 主页:https://github.com/RT-Thread-packages/peripheral-sample
diff --git a/bsp/essemi/es32f0654/drivers/bsp_driver_example/adc_vol_sample.c b/bsp/essemi/es32f0654/drivers/bsp_driver_example/adc_vol_sample.c
new file mode 100644
index 0000000000..19eed3f35d
--- /dev/null
+++ b/bsp/essemi/es32f0654/drivers/bsp_driver_example/adc_vol_sample.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-29     misonyo      first implementation.
+ */
+/*
+ * 程序清单: ADC 设备使用例程
+ * 例程导出了 adc_sample 命令到控制终端
+ * 命令调用格式:adc_sample
+ * 程序功能:通过 ADC 设备采样电压值并转换为数值。
+ *           示例代码参考电压为3.3V,转换位数为12位。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define ADC_DEV_NAME        "adc0"      /* ADC 设备名称 */
+#define ADC_DEV_CHANNEL     5           /* PA1 ADC 通道 */
+#define REFER_VOLTAGE       330         /* 参考电压 3.3V,数据精度乘以100保留2位小数*/
+#define CONVERT_BITS        (1 << 12)   /* 转换位数为12位 */
+
+static int adc_vol_sample(int argc, char *argv[])
+{
+    rt_adc_device_t adc_dev;
+    rt_uint32_t value, vol;
+    rt_err_t ret = RT_EOK;
+
+    /* 查找设备 */
+    adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);
+    if (adc_dev == RT_NULL)
+    {
+        rt_kprintf("adc sample run failed! can't find %s device!\n", ADC_DEV_NAME);
+        return RT_ERROR;
+    }
+
+    /* 使能设备 */
+    ret = rt_adc_enable(adc_dev, ADC_DEV_CHANNEL);
+
+    /* 读取采样值 */
+    value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
+    rt_kprintf("the value is :%d \n", value);
+
+    /* 转换为对应电压值 */
+    vol = value * REFER_VOLTAGE / CONVERT_BITS;
+    rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100);
+
+    /* 关闭通道 */
+    ret = rt_adc_disable(adc_dev, ADC_DEV_CHANNEL);
+
+    return ret;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(adc_vol_sample, adc voltage convert sample);
diff --git a/bsp/essemi/es32f0654/drivers/bsp_driver_example/can_sample.c b/bsp/essemi/es32f0654/drivers/bsp_driver_example/can_sample.c
new file mode 100644
index 0000000000..4c16d1d555
--- /dev/null
+++ b/bsp/essemi/es32f0654/drivers/bsp_driver_example/can_sample.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-06-25     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 CAN 设备使用例程
+ * 例程导出了 can_sample 命令到控制终端
+ * 命令调用格式:can_sample can2
+ * 命令解释:命令第二个参数是要使用的 CAN 设备名称,为空则使用默认的 CAN 设备
+ * 程序功能:通过 CAN 设备发送一帧,并创建一个线程接收数据然后打印输出。
+*/
+
+#include <rtthread.h>
+#include "rtdevice.h"
+
+#define CAN_DEV_NAME       "can"      /* CAN 设备名称 */
+
+static struct rt_semaphore rx_sem;     /* 用于接收消息的信号量 */
+static rt_device_t can_dev;            /* CAN 设备句柄 */
+
+/* 接收数据回调函数 */
+static rt_err_t can_rx_call(rt_device_t dev, rt_size_t size)
+{
+    /* CAN 接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
+    rt_sem_release(&rx_sem);
+
+    return RT_EOK;
+}
+
+static void can_rx_thread(void *parameter)
+{
+    int i;
+    struct rt_can_msg rxmsg = {0};
+
+    /* 设置接收回调函数 */
+    rt_device_set_rx_indicate(can_dev, can_rx_call);
+
+#ifdef RT_CAN_USING_HDR
+    
+    rt_err_t res;
+    
+    struct rt_can_filter_item items[5] =
+    {
+        RT_CAN_FILTER_ITEM_INIT(0x100, 0, 0, 0, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x100~0x1ff,hdr为-1,设置默认过滤表 */
+        RT_CAN_FILTER_ITEM_INIT(0x300, 0, 0, 0, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x300~0x3ff,hdr为-1 */
+        RT_CAN_FILTER_ITEM_INIT(0x211, 0, 0, 0, 0x7ff, RT_NULL, RT_NULL), /* std,match ID:0x211,hdr为-1 */
+        RT_CAN_FILTER_STD_INIT(0x486, RT_NULL, RT_NULL),                  /* std,match ID:0x486,hdr为-1 */
+        {0x555, 0, 0, 0, 0x7ff, 7,}                                       /* std,match ID:0x555,hdr为7,指定设置7号过滤表 */
+    };
+    struct rt_can_filter_config cfg = {5, 1, items}; /* 一共有5个过滤表 */
+    /* 设置硬件过滤表 */
+    res = rt_device_control(can_dev, RT_CAN_CMD_SET_FILTER, &cfg);
+    RT_ASSERT(res == RT_EOK);
+#endif
+
+    while (1)
+    {
+        /* hdr值为-1,表示直接从uselist链表读取数据 */
+        rxmsg.hdr = -1;
+        /* 阻塞等待接收信号量 */
+        rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
+        /* 从CAN读取一帧数据 */
+        rt_device_read(can_dev, 0, &rxmsg, sizeof(rxmsg));
+        /* 打印数据ID及内容 */
+        rt_kprintf("ID:%x  ", rxmsg.id);
+        for (i = 0; i < 8; i++)
+        {
+            rt_kprintf("%2x ", rxmsg.data[i]);
+        }
+
+        rt_kprintf("\n");
+    }
+}
+
+int can_sample(int argc, char *argv[])
+{
+    struct rt_can_msg msg = {0};
+    rt_err_t res;
+    rt_size_t  size;
+    rt_thread_t thread;
+    char can_name[RT_NAME_MAX];
+    
+    if (argc == 2)
+    {
+        rt_strncpy(can_name, argv[1], RT_NAME_MAX);
+    }
+    else
+    {
+        rt_strncpy(can_name, CAN_DEV_NAME, RT_NAME_MAX);
+    }
+
+    can_dev = rt_device_find(can_name);
+    if (!can_dev)
+    {
+        rt_kprintf("find %s failed!\n", can_name);
+        return RT_ERROR;
+    }
+
+    /* 初始化CAN接收信号量 */
+    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
+
+    /* 以中断接收及发送方式打开CAN设备 */
+    res = rt_device_open(can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);
+    RT_ASSERT(res == RT_EOK);
+
+    thread = rt_thread_create("can_rx", can_rx_thread, RT_NULL, 1024, 25, 10);
+    if (thread != RT_NULL)
+    {
+        rt_thread_startup(thread);
+    }
+    else
+    {
+        rt_kprintf("create can_rx thread failed!\n");
+    }
+
+    msg.id = 0x78;              /* ID为0x78 */
+    msg.ide = RT_CAN_STDID;     /* 标准格式 */
+    msg.rtr = RT_CAN_DTR;       /* 数据帧 */
+    msg.len = 8;                /* 数据长度为8 */
+    /* 待发送的8字节数据 */
+    msg.data[0] = 0x00;
+    msg.data[1] = 0x11;
+    msg.data[2] = 0x22;
+    msg.data[3] = 0x33;
+    msg.data[4] = 0x44;
+    msg.data[5] = 0x55;
+    msg.data[6] = 0x66;
+    msg.data[7] = 0x77;
+    /* 发送一帧CAN数据 */
+    size = rt_device_write(can_dev, 0, &msg, sizeof(msg));
+    if (size == 0)
+    {
+        rt_kprintf("can dev write data failed!\n");
+    }
+    
+    return res;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(can_sample, can device sample);
diff --git a/bsp/essemi/es32f0654/drivers/bsp_driver_example/hwtimer_sample.c b/bsp/essemi/es32f0654/drivers/bsp_driver_example/hwtimer_sample.c
new file mode 100644
index 0000000000..e2e39664f3
--- /dev/null
+++ b/bsp/essemi/es32f0654/drivers/bsp_driver_example/hwtimer_sample.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-30     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 hwtimer 设备使用例程
+ * 例程导出了 hwtimer_sample 命令到控制终端
+ * 命令调用格式:hwtimer_sample
+ * 程序功能:硬件定时器超时回调函数周期性的打印当前tick值,2次tick值之差换算为时间等同于定时时间值。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define HWTIMER_DEV_NAME   "timer0"     /* 定时器名称 */
+
+/* 定时器超时回调函数 */
+static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size)
+{
+    rt_kprintf("tick is :%d !\n", rt_tick_get());
+
+    return 0;
+}
+
+static int hwtimer_sample(int argc, char *argv[])
+{
+    rt_err_t ret = RT_EOK;
+    rt_hwtimerval_t timeout_s;      /* 定时器超时值 */
+    rt_device_t hw_dev = RT_NULL;   /* 定时器设备句柄 */
+    rt_hwtimer_mode_t mode;         /* 定时器模式 */
+
+    /* 查找定时器设备 */
+    hw_dev = rt_device_find(HWTIMER_DEV_NAME);
+    if (hw_dev == RT_NULL)
+    {
+        rt_kprintf("hwtimer sample run failed! can't find %s device!\n", HWTIMER_DEV_NAME);
+        return RT_ERROR;
+    }
+
+    /* 以读写方式打开设备 */
+    ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
+    if (ret != RT_EOK)
+    {
+        rt_kprintf("open %s device failed!\n", HWTIMER_DEV_NAME);
+        return ret;
+    }
+
+    /* 设置超时回调函数 */
+    rt_device_set_rx_indicate(hw_dev, timeout_cb);
+
+    /* 设置模式为周期性定时器 */
+    mode = HWTIMER_MODE_PERIOD;
+    ret = rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
+    if (ret != RT_EOK)
+    {
+        rt_kprintf("set mode failed! ret is :%d\n", ret);
+        return ret;
+    }
+
+    /* 设置定时器超时值为5s并启动定时器 */
+    timeout_s.sec = 5;      /* 秒 */
+    timeout_s.usec = 0;     /* 微秒 */
+
+    if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
+    {
+        rt_kprintf("set timeout value failed\n");
+        return RT_ERROR;
+    }
+
+    /* 延时3500ms */
+    rt_thread_mdelay(3500);
+
+    /* 读取定时器当前值 */
+    rt_device_read(hw_dev, 0, &timeout_s, sizeof(timeout_s));
+    rt_kprintf("Read: Sec = %d, Usec = %d\n", timeout_s.sec, timeout_s.usec);
+
+    return ret;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(hwtimer_sample, hwtimer sample);
diff --git a/bsp/essemi/es32f0654/drivers/bsp_driver_example/i2c_sample.c b/bsp/essemi/es32f0654/drivers/bsp_driver_example/i2c_sample.c
new file mode 100644
index 0000000000..2d386433c6
--- /dev/null
+++ b/bsp/essemi/es32f0654/drivers/bsp_driver_example/i2c_sample.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-15     liuhy       first implementation.
+ */
+/*
+ * 程序清单:这是一个 I2C 设备使用例程
+ * 例程导出了 i2c_io_sample 命令到控制终端
+ * 命令调用格式:i2c_io_sample
+ * 命令解释:使用默认的I2C总线设备
+ * 程序功能:通过 I2C 设备接收数据并打印,然后将接收的字符加1输出。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define I2C_BUS_NAME          "i2c1"  /* I2C总线设备名称 */
+#define SLAVE_ADDR                  0x2D    /* 从机地址 */
+#define STR_LEN                       16    /* 接收发送的数据长度 */
+
+static void i2c_io_sample(int argc, char *argv[])
+{
+    
+    struct rt_i2c_bus_device *i2c_bus = RT_NULL;     /* I2C总线设备句柄 */
+    struct rt_i2c_msg temp_msg;                             /* I2C消息 */
+    rt_uint8_t buffer[STR_LEN] = { 0U }; 
+    rt_uint32_t i,num_msg;
+    rt_size_t s_stat;
+    
+    i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(I2C_BUS_NAME);    /* 通过名字获取I2C总线设备的句柄 */
+    
+    if( i2c_bus == RT_NULL)
+    {
+        rt_kprintf("can't find i2c device :%s !\n",I2C_BUS_NAME);
+        
+        return;
+    }
+    
+        /*初始化消息*/
+        temp_msg.addr = SLAVE_ADDR;  /* 从机地址 */
+        temp_msg.len  = STR_LEN;     /* 传输的数据长度 */
+        temp_msg.buf = buffer;       /* 读写缓存器 */
+    
+        num_msg = 1;             /* 传输一条消息 */
+    
+        temp_msg.flags = RT_I2C_RD;             /* I2C读 */
+        s_stat = rt_i2c_transfer(i2c_bus,&temp_msg,num_msg);   /* 传输消息 */
+        
+        rt_thread_mdelay(400); 
+        
+        if( s_stat == num_msg )
+        {
+            rt_kprintf("receive successful. \n receive messege : %s \n:",buffer);
+            
+            for( i = 0 ; i < STR_LEN ; i++)
+            rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+            rt_kprintf("\n");
+        }
+        else
+        {
+            rt_kprintf("device s% recieve fail \n buffer : s%\n",I2C_BUS_NAME,buffer);
+            return;
+        }
+        
+        for( i = 0 ; i < STR_LEN ; i++)
+        buffer[i]++;
+    
+        temp_msg.flags = RT_I2C_WR;             /* I2C写 */
+        s_stat = rt_i2c_transfer(i2c_bus,&temp_msg,num_msg);   /* 传输一条 */
+        
+        rt_thread_mdelay(400);
+        
+        if( s_stat == num_msg )
+        {
+            rt_kprintf(" send successful \n messege : %s \n:",buffer);
+            
+            for( i = 0 ; i < STR_LEN ; i++)
+            rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+            rt_kprintf("\n");
+        }
+        else
+        {
+            rt_kprintf("device s% send fail \n",I2C_BUS_NAME);
+            return;
+        }
+        
+        return;
+    
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(i2c_io_sample, i2c io sample);
diff --git a/bsp/essemi/es32f0654/drivers/bsp_driver_example/led_blink_sample.c b/bsp/essemi/es32f0654/drivers/bsp_driver_example/led_blink_sample.c
new file mode 100644
index 0000000000..42c956a060
--- /dev/null
+++ b/bsp/essemi/es32f0654/drivers/bsp_driver_example/led_blink_sample.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-09-25     misonyo      first edition.
+ */
+/*
+ * 程序清单:这是一个通过PIN脚控制LED亮灭的使用例程
+ * 例程导出了 led_sample 命令到控制终端
+ * 命令调用格式:led_sample 41
+ * 命令解释:命令第二个参数是要使用的PIN脚编号,为空则使用例程默认的引脚编号。
+ * 程序功能:程序创建一个led线程,线程每隔1000ms改变PIN脚状态,达到控制led灯
+ *            亮灭的效果。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <stdlib.h>
+
+/* PIN脚编号,查看驱动文件drv_gpio.c确定 */
+#define LED_PIN_NUM    40   /*PB9*/
+static int pin_num;
+
+static void led_entry(void *parameter)
+{
+    int count = 0;
+    /* 设置PIN脚模式为输出 */
+    rt_pin_mode(pin_num, PIN_MODE_OUTPUT);
+
+    while (1)
+    {
+        count++;
+        rt_kprintf("thread run count : %d\r\n", count);
+        /* 拉低PIN脚 */
+        rt_pin_write(pin_num, PIN_LOW);
+        rt_kprintf("led on!\r\n");
+        /* 延时1000ms */
+        rt_thread_mdelay(1000);
+
+        /* 拉高PIN脚 */
+        rt_pin_write(pin_num, PIN_HIGH);
+        rt_kprintf("led off!\r\n");
+        rt_thread_mdelay(1000);
+    }
+}
+
+static int led_sample(int argc, char *argv[])
+{
+    rt_thread_t tid;
+    rt_err_t ret = RT_EOK;
+
+    /* 判断命令行参数是否给定了PIN脚编号 */
+    if (argc == 2)
+    {
+        pin_num = atoi(argv[1]);
+    }
+    else
+    {
+        pin_num = LED_PIN_NUM;
+    }
+
+    tid = rt_thread_create("led",
+                           led_entry,
+                           RT_NULL,
+                           512,
+                           RT_THREAD_PRIORITY_MAX / 3,
+                           20);
+    if (tid != RT_NULL)
+    {
+        rt_thread_startup(tid);
+    }
+    else
+    {
+        ret = RT_ERROR;
+    }
+
+    return ret;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(led_sample, led sample);
diff --git a/bsp/essemi/es32f0654/drivers/bsp_driver_example/pin_beep_sample.c b/bsp/essemi/es32f0654/drivers/bsp_driver_example/pin_beep_sample.c
new file mode 100644
index 0000000000..29dfbe1b2f
--- /dev/null
+++ b/bsp/essemi/es32f0654/drivers/bsp_driver_example/pin_beep_sample.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-08-15     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 PIN 设备使用例程
+ * 例程导出了 pin_beep_sample 命令到控制终端
+ * 命令调用格式:pin_beep_sample
+ * 程序功能:通过按键控制蜂鸣器对应引脚的电平状态控制蜂鸣器
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+/* 引脚编号,通过查看驱动文件drv_gpio.c确定 */
+#ifndef BEEP_PIN_NUM
+    #define BEEP_PIN_NUM            40  /* PB9 */
+#endif
+#ifndef KEY0_PIN_NUM
+    #define KEY0_PIN_NUM            18  /* PF0 */
+#endif
+#ifndef KEY1_PIN_NUM
+    #define KEY1_PIN_NUM            19  /* PF1 */
+#endif
+
+void beep_on(void *args)
+{
+    rt_kprintf("turn on beep!\n");
+
+    rt_pin_write(BEEP_PIN_NUM, PIN_HIGH);
+}
+
+void beep_off(void *args)
+{
+    rt_kprintf("turn off beep!\n");
+
+    rt_pin_write(BEEP_PIN_NUM, PIN_LOW);
+}
+
+static void pin_beep_sample(void)
+{
+    /* 蜂鸣器引脚为输出模式 */
+    rt_pin_mode(BEEP_PIN_NUM, PIN_MODE_OUTPUT);
+    /* 默认低电平 */
+    rt_pin_write(BEEP_PIN_NUM, PIN_LOW);
+
+    /* 按键0引脚为输入模式 */
+    rt_pin_mode(KEY0_PIN_NUM, PIN_MODE_INPUT_PULLUP);
+    /* 绑定中断,下降沿模式,回调函数名为beep_on */
+    rt_pin_attach_irq(KEY0_PIN_NUM, PIN_IRQ_MODE_FALLING, beep_on, RT_NULL);
+    /* 使能中断 */
+    rt_pin_irq_enable(KEY0_PIN_NUM, PIN_IRQ_ENABLE);
+
+    /* 按键1引脚为输入模式 */
+    rt_pin_mode(KEY1_PIN_NUM, PIN_MODE_INPUT_PULLUP);
+    /* 绑定中断,下降沿模式,回调函数名为beep_off */
+    rt_pin_attach_irq(KEY1_PIN_NUM, PIN_IRQ_MODE_FALLING, beep_off, RT_NULL);
+    /* 使能中断 */
+    rt_pin_irq_enable(KEY1_PIN_NUM, PIN_IRQ_ENABLE);
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(pin_beep_sample, pin beep sample);
diff --git a/bsp/essemi/es32f0654/drivers/bsp_driver_example/pm_sample.c b/bsp/essemi/es32f0654/drivers/bsp_driver_example/pm_sample.c
new file mode 100644
index 0000000000..f7287e36ac
--- /dev/null
+++ b/bsp/essemi/es32f0654/drivers/bsp_driver_example/pm_sample.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-15     liuhy       first implementation.
+ */
+/*
+ * 程序清单:这是一个 pm睡眠唤醒的使用例程
+ * 例程导出了 pm_sample 命令到控制终端
+ * 命令调用格式:pm_sample
+ * 命令解释:进入不同的睡眠模式,然后用按键唤醒
+ * 程序功能:通过串口输出字符串,告知进入睡眠和唤醒睡眠的情况。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define PM_NAME       "pm"      /* 设备名称 */
+#define WAKE_UP_PIN     18      /* 唤醒源 */
+#define SLEEP_TIMES     12      /* 进入睡眠次数,轮流进入不同的睡眠模式,包括无睡眠模式 */
+
+
+struct pm_callback_t
+{
+     volatile int in_fun_times;   /*进入函数的次数*/
+     volatile char flag;          /*标志*/
+     volatile int mode;           /*需要打印的模式*/
+};
+
+volatile struct pm_callback_t g_pm_data;
+
+/*进入睡眠前,睡眠唤醒后,都会进入。*/
+/*函数打印睡眠相关的信息*/
+void sleep_in_out_callback(rt_uint8_t event, rt_uint8_t mode, void *data)
+{
+    /*没有标志,不处理*/
+    if(!(g_pm_data.flag))
+    {
+        return;
+    }
+    
+    /*标志不正常,清空标志*/
+    if((g_pm_data.flag) > 2)
+    {
+        (g_pm_data.flag) = 0;
+        return;
+    }
+    
+    /*模式不匹配*/
+    if(g_pm_data.mode != mode )
+    {
+        return;
+    }
+ 
+    /*进入的事件*/
+    switch(event)
+    {
+        /*进入睡眠前*/
+        case RT_PM_ENTER_SLEEP: g_pm_data.flag = 1;
+                                rt_kprintf("\n\r##%d :  ENTER  ",g_pm_data.in_fun_times);
+                                g_pm_data.in_fun_times++;     /*进入睡眠次数+1*/
+                                break;
+        /*睡眠唤醒后*/
+        case RT_PM_EXIT_SLEEP:  g_pm_data.flag = 0;  /*睡眠唤醒后*/
+                                rt_kprintf("\n\rEXIT\n\r");
+                                rt_pm_release(mode);   /*释放休眠模式*/
+                                return;
+        
+        default: break;
+        
+    };
+    
+    /*当前的睡眠模式*/
+    switch(mode)
+    {
+        case PM_SLEEP_MODE_NONE: rt_kprintf("PM_SLEEP_MODE_NONE\n\r");
+                                break;
+        case PM_SLEEP_MODE_IDLE:  rt_kprintf("PM_SLEEP_MODE_IDLE\n\r");
+                                break;
+        case PM_SLEEP_MODE_LIGHT: rt_kprintf("PM_SLEEP_MODE_LIGHT\n\r");
+                                break;
+        case PM_SLEEP_MODE_DEEP:  rt_kprintf("PM_SLEEP_MODE_DEEP\n\r");
+                                break;
+        case PM_SLEEP_MODE_STANDBY: rt_kprintf("PM_SLEEP_MODE_STANDBY\n\r");
+                                break;
+        case PM_SLEEP_MODE_SHUTDOWN:  rt_kprintf("PM_SLEEP_MODE_SHUTDOWN\n\r");
+                                break;      
+        case PM_SLEEP_MODE_MAX:  rt_kprintf("PM_SLEEP_MODE_MAX\n\r");
+                                break;
+        default: break;           
+    }
+    
+}
+
+/* pm测试函数 */
+static void pm_test(void *parameter)
+{
+    int in_mode[7],i = 0;
+    
+        g_pm_data.in_fun_times = 0;
+        g_pm_data.flag = 0;
+    
+        in_mode[0] = PM_SLEEP_MODE_NONE;
+        in_mode[1] = PM_SLEEP_MODE_IDLE;
+        in_mode[2] = PM_SLEEP_MODE_LIGHT;
+        in_mode[3] = PM_SLEEP_MODE_DEEP;
+        in_mode[4] = PM_SLEEP_MODE_STANDBY;
+        in_mode[5] = PM_SLEEP_MODE_SHUTDOWN;
+        in_mode[6] = PM_SLEEP_MODE_MAX;
+    
+    /*设置回调函数和私有数据*/
+    rt_pm_notify_set(sleep_in_out_callback,RT_NULL);
+       
+    while(i < SLEEP_TIMES)
+   {
+       
+       g_pm_data.mode = in_mode[i%6];
+       
+       /*无休眠模式,不赋予标志*/
+       if(g_pm_data.mode != PM_SLEEP_MODE_NONE)
+       {
+            g_pm_data.flag = 2;  
+       
+       }
+       
+       /*请求选择的休眠模式*/
+       rt_pm_request(in_mode[i%6]);
+
+       rt_thread_mdelay(500);
+       
+       /*无休眠模式,不需要额外的等待*/
+       while(( g_pm_data.flag != 0 )&&(g_pm_data.mode != PM_SLEEP_MODE_NONE))
+       {
+           rt_thread_mdelay(500);
+       }
+       
+       /*释放选择的休眠模式*/
+       rt_pm_release(in_mode[i%6]);
+       
+       i++;
+       
+   }
+      /*清除回调函数和私有数据*/
+    rt_pm_notify_set(RT_NULL,RT_NULL);
+   rt_kprintf("thread pm_test close\n\r");
+}
+
+/*按键唤醒的回调函数*/
+void wake_by_pin(void *args)
+{
+
+}
+
+static int pm_sample(int argc, char *argv[])
+{
+    rt_thread_t thread;
+    
+    /* 按键引脚为输入模式 */
+    rt_pin_mode(WAKE_UP_PIN, PIN_MODE_INPUT_PULLUP);
+    
+    /* 绑定中断,下降沿模式,回调函数名为wake_by_pin */
+    rt_pin_attach_irq(WAKE_UP_PIN, PIN_IRQ_MODE_RISING, wake_by_pin, RT_NULL);
+    /* 使能中断 */
+    rt_pin_irq_enable(WAKE_UP_PIN, PIN_IRQ_ENABLE);
+    
+    thread = rt_thread_create("pm_test", pm_test, RT_NULL, 1024, 25, 10);
+    
+    if (thread != RT_NULL)
+    {
+        rt_thread_startup(thread);
+    }
+    else
+    {
+        rt_kprintf("create pm_test thread failed!\n\r");
+    }
+    
+    return RT_EOK;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(pm_sample, pm sample);
diff --git a/bsp/essemi/es32f0654/drivers/bsp_driver_example/pwm_led_sample.c b/bsp/essemi/es32f0654/drivers/bsp_driver_example/pwm_led_sample.c
new file mode 100644
index 0000000000..ce1573aa55
--- /dev/null
+++ b/bsp/essemi/es32f0654/drivers/bsp_driver_example/pwm_led_sample.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-25     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 PWM 设备使用例程
+ * 例程导出了 pwm_led_sample 命令到控制终端
+ * 命令调用格式:pwm_led_sample
+ * 程序功能:通过 PWM 设备控制 LED 灯的亮度,可以看到LED不停的由暗变到亮,然后又从亮变到暗。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define LED_PIN_NUM         16      /* LED PIN脚编号,查看驱动文件drv_gpio.c确定 */
+#define PWM_DEV_NAME        "pwm1"  /* PWM设备名称 */
+#define PWM_DEV_CHANNEL     4       /* PB9 PWM通道 */
+
+struct rt_device_pwm *pwm_dev;      /* PWM设备句柄 */
+
+static int pwm_led_sample(int argc, char *argv[])
+{
+    rt_uint32_t period, pulse, dir;
+
+    period = 500000;    /* 周期为0.5ms,单位为纳秒ns */
+    dir = 1;            /* PWM脉冲宽度值的增减方向 */
+    pulse = 0;          /* PWM脉冲宽度值,单位为纳秒ns */
+
+    /* 查找设备 */
+    pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
+    if (pwm_dev == RT_NULL)
+    {
+        rt_kprintf("pwm sample run failed! can't find %s device!\n", PWM_DEV_NAME);
+        return RT_ERROR;
+    }
+
+    /* 设置PWM周期和脉冲宽度默认值 */
+    rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
+    /* 使能设备 */
+    rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
+    
+    while (1)
+    {
+        rt_thread_mdelay(50);
+        if (dir)
+        {
+            pulse += 5000;      /* 从0值开始每次增加5000ns */
+        }
+        else
+        {
+            pulse -= 5000;      /* 从最大值开始每次减少5000ns */
+        }
+        if (pulse >= period)
+        {
+            dir = 0;
+        }
+        if (0 == pulse)
+        {
+            dir = 1;
+        }
+
+        /* 设置PWM周期和脉冲宽度 */
+        rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
+    }
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(pwm_led_sample, pwm sample);
diff --git a/bsp/essemi/es32f0654/drivers/bsp_driver_example/rtc_sample.c b/bsp/essemi/es32f0654/drivers/bsp_driver_example/rtc_sample.c
new file mode 100644
index 0000000000..711a3a0ebb
--- /dev/null
+++ b/bsp/essemi/es32f0654/drivers/bsp_driver_example/rtc_sample.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-30     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 RTC 设备使用例程
+ * 例程导出了 rtc_sample 命令到控制终端
+ * 命令调用格式:rtc_sample
+ * 程序功能:设置RTC设备的日期和时间,延时一段时间后获取当前时间并打印显示。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+static int rtc_sample(int argc, char *argv[])
+{
+    rt_err_t ret = RT_EOK;
+    time_t now;
+
+    /* 设置日期 */
+    ret = set_date(2018, 12, 3);
+    if (ret != RT_EOK)
+    {
+        rt_kprintf("set RTC date failed\n");
+        return ret;
+    }
+
+    /* 设置时间 */
+    ret = set_time(11, 15, 50);
+    if (ret != RT_EOK)
+    {
+        rt_kprintf("set RTC time failed\n");
+        return ret;
+    }
+
+    /* 延时3秒 */
+    rt_thread_mdelay(3000);
+
+    /* 获取时间 */
+    now = time(RT_NULL);
+    rt_kprintf("%s\n", ctime(&now));
+
+    return ret;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(rtc_sample, rtc sample);
diff --git a/bsp/essemi/es32f0654/drivers/bsp_driver_example/spi_sample.c b/bsp/essemi/es32f0654/drivers/bsp_driver_example/spi_sample.c
new file mode 100644
index 0000000000..994888cdb0
--- /dev/null
+++ b/bsp/essemi/es32f0654/drivers/bsp_driver_example/spi_sample.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-15     liuhy       first implementation.
+ */
+/*
+ * 程序清单:这是一个 SPI 设备使用例程
+ * 例程导出了 spi_io_sample 命令到控制终端
+ * 命令调用格式:spi_io_sample
+ * 程序功能:通过SPI设备先读取数据,然后每个字符加1后输出。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define SPI_DEVICE_NAME     "spi00"
+#define BUF_LEN             16
+
+static void spi_io_sample(int argc, char *argv[])
+{
+    struct rt_spi_device * spi_dev;          /* spi设备的句柄 */
+    struct rt_spi_configuration spi_config;
+    rt_uint8_t i,buffer[BUF_LEN] = { 0U };
+    rt_err_t s_stat;
+    rt_err_t result;
+    
+     /* 查找 spi设备 获取spi设备句柄 */
+    spi_dev = (struct rt_spi_device *)rt_device_find(SPI_DEVICE_NAME);
+    
+    if (spi_dev == RT_NULL)
+    {
+        rt_kprintf("spi sample run failed! can't find %s device!\n", SPI_DEVICE_NAME);
+        return;
+    }
+    
+    
+    /* 清空配置结构体 */
+    rt_memset(&spi_config,0,sizeof(struct rt_spi_configuration));
+    
+    spi_config.mode &= ~RT_SPI_SLAVE; /* 主机模式 */
+    spi_config.mode &= ~RT_SPI_3WIRE; /* 4线,双向传输 */
+    spi_config.mode |= RT_SPI_CPHA;   /* 第二边沿采样 */
+    spi_config.mode |= RT_SPI_CPOL;   /* 空闲高电平 */
+    spi_config.mode |= RT_SPI_NO_CS;  /* 禁用软件从机选择管理 */
+    spi_config.mode |= RT_SPI_MSB;    /* 高位在前 */
+    
+    spi_config.data_width = 8;        /* 数据长度:8 */
+    
+    spi_config.max_hz = 2000000;      /* 最快时钟频率 */
+    
+    /* 配置SPI设备 */
+    s_stat = rt_spi_configure(spi_dev,&spi_config);
+    
+    if(s_stat != RT_EOK)
+    {
+        rt_kprintf(" spi config fail !\n ");
+        return;
+    }
+    
+    
+    /* 获取总线 ,防止总线被多个线程同时使用 */
+    result = rt_spi_take_bus(spi_dev);
+    
+    if (result != RT_EOK)
+    {
+        rt_kprintf(" %s take spi bus  failed! \n", SPI_DEVICE_NAME);
+        return;
+    }
+    
+    /* 选中片选 */
+    result = rt_spi_take(spi_dev);
+    
+    if (result != RT_EOK)
+    {
+        rt_kprintf(" %s take spi cs  failed! \n", SPI_DEVICE_NAME);
+        return;
+    }
+    
+    
+    /*接收一次数据*/
+    result = rt_spi_recv(spi_dev,buffer,BUF_LEN);
+    
+    if(result != BUF_LEN)
+    {
+        rt_kprintf("receive fail. \n buffer is : %s \n:",buffer);
+            
+        for( i = 0 ; i < BUF_LEN ; i++)
+         rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+        rt_kprintf("\n");
+        
+        return;
+    }
+    
+    rt_kprintf("receive successful. \n buffer is : %s \n:",buffer);
+            
+    for( i = 0 ; i < BUF_LEN ; i++)
+    rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+    rt_kprintf("\n");
+    
+    /* 将接收到的数据加1 */
+    for( i = 0 ; i < BUF_LEN ; i++)
+      buffer[i]++;
+    
+    /*发送数据*/
+    result = rt_spi_send(spi_dev,buffer,BUF_LEN);
+    
+    if(result != BUF_LEN)
+    {
+        rt_kprintf("send fail. \n buffer is : %s \n:",buffer);
+            
+        for( i = 0 ; i < BUF_LEN ; i++)
+         rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+        rt_kprintf("\n");
+        
+        return;
+    }
+    
+    rt_kprintf("send successful. \n buffer is : %s \n:",buffer);
+            
+    for( i = 0 ; i < BUF_LEN ; i++)
+    rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+    rt_kprintf("\n");
+   
+    /* 释放片选 */
+    result = rt_spi_release(spi_dev);
+    
+    if (result != RT_EOK)
+    {
+        rt_kprintf(" %s release spi cs failed! \n", SPI_DEVICE_NAME);
+        return;
+    } 
+    
+    /* 释放总线 */
+    result = rt_spi_release_bus(spi_dev);
+    
+    if (result != RT_EOK)
+    {
+        rt_kprintf(" %s release spi bus  failed! \n", SPI_DEVICE_NAME);
+        return;
+    }
+    
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(spi_io_sample, spi  sample);
diff --git a/bsp/essemi/es32f0654/drivers/bsp_driver_example/uart_sample.c b/bsp/essemi/es32f0654/drivers/bsp_driver_example/uart_sample.c
new file mode 100644
index 0000000000..cb750efe6e
--- /dev/null
+++ b/bsp/essemi/es32f0654/drivers/bsp_driver_example/uart_sample.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-08-15     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 串口 设备使用例程
+ * 例程导出了 uart_sample 命令到控制终端
+ * 命令调用格式:uart_sample uart2
+ * 命令解释:命令第二个参数是要使用的串口设备名称,为空则使用默认的串口设备
+ * 程序功能:通过串口输出字符串"hello RT-Thread!",然后错位输出输入的字符
+*/
+
+#include <rtthread.h>
+
+#define SAMPLE_UART_NAME       "uart2"      /* 串口设备名称 */
+
+/* 用于接收消息的信号量 */
+static struct rt_semaphore rx_sem;
+static rt_device_t serial;
+
+/* 接收数据回调函数 */
+static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
+{
+    /* 串口接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
+    rt_sem_release(&rx_sem);
+
+    return RT_EOK;
+}
+
+static void serial_thread_entry(void *parameter)
+{
+    char ch;
+
+    while (1)
+    {
+        /* 从串口读取一个字节的数据,没有读取到则等待接收信号量 */
+        while (rt_device_read(serial, -1, &ch, 1) != 1)
+        {
+            /* 阻塞等待接收信号量,等到信号量后再次读取数据 */
+            rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
+        }
+        /* 读取到的数据通过串口错位输出 */
+        ch = ch + 1;
+        rt_device_write(serial, 0, &ch, 1);
+    }
+}
+
+static int uart_sample(int argc, char *argv[])
+{
+    rt_err_t ret = RT_EOK;
+    char uart_name[RT_NAME_MAX];
+    char str[] = "hello RT-Thread!\r\n";
+
+    if (argc == 2)
+    {
+        rt_strncpy(uart_name, argv[1], RT_NAME_MAX);
+    }
+    else
+    {
+        rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX);
+    }
+
+    /* 查找串口设备 */
+    serial = rt_device_find(uart_name);
+    if (!serial)
+    {
+        rt_kprintf("find %s failed!\n", uart_name);
+        return RT_ERROR;
+    }
+
+    /* 初始化信号量 */
+    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
+    /* 以中断接收及轮询发送方式打开串口设备 */
+    rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
+    /* 设置接收回调函数 */
+    rt_device_set_rx_indicate(serial, uart_input);
+    /* 发送字符串 */
+    rt_device_write(serial, 0, str, (sizeof(str) - 1));
+
+    /* 创建 serial 线程 */
+    rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
+    /* 创建成功则启动线程 */
+    if (thread != RT_NULL)
+    {
+        rt_thread_startup(thread);
+    }
+    else
+    {
+        ret = RT_ERROR;
+    }
+
+    return ret;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(uart_sample, uart device sample);
diff --git a/bsp/essemi/es32f0654/figures/内核用例.PNG b/bsp/essemi/es32f0654/figures/内核用例.PNG
new file mode 100644
index 0000000000..4c4f8e05ba
Binary files /dev/null and b/bsp/essemi/es32f0654/figures/内核用例.PNG differ
diff --git a/bsp/essemi/es32f0654/figures/内核配置.PNG b/bsp/essemi/es32f0654/figures/内核配置.PNG
new file mode 100644
index 0000000000..f5901c0e59
Binary files /dev/null and b/bsp/essemi/es32f0654/figures/内核配置.PNG differ
diff --git a/bsp/essemi/es32f0654/figures/驱动用例.PNG b/bsp/essemi/es32f0654/figures/驱动用例.PNG
new file mode 100644
index 0000000000..a93b4186ae
Binary files /dev/null and b/bsp/essemi/es32f0654/figures/驱动用例.PNG differ
diff --git a/bsp/essemi/es32f0654/figures/驱动配置.PNG b/bsp/essemi/es32f0654/figures/驱动配置.PNG
new file mode 100644
index 0000000000..8ec566f7ab
Binary files /dev/null and b/bsp/essemi/es32f0654/figures/驱动配置.PNG differ
diff --git a/bsp/essemi/es32f369x/drivers/bsp_driver_example/.gitignore b/bsp/essemi/es32f369x/drivers/bsp_driver_example/.gitignore
new file mode 100644
index 0000000000..c6127b38c1
--- /dev/null
+++ b/bsp/essemi/es32f369x/drivers/bsp_driver_example/.gitignore
@@ -0,0 +1,52 @@
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
diff --git a/bsp/essemi/es32f369x/drivers/bsp_driver_example/README.md b/bsp/essemi/es32f369x/drivers/bsp_driver_example/README.md
new file mode 100644
index 0000000000..80f12e1949
--- /dev/null
+++ b/bsp/essemi/es32f369x/drivers/bsp_driver_example/README.md
@@ -0,0 +1,47 @@
+# 外设驱动测试用例
+
+## 1、介绍
+
+这个软件包包含一些外设设备操作的例程。
+
+### 1.1 例程说明
+
+| 文件             | 说明                            |
+| ---------------- | ------------------------------- |
+| adc_vol_sample.c       | 使用 ADC 设备转换电压数据 |
+| can_sample.c | 通过 CAN 设备发送一帧,并创建一个线程接收数据然后打印输出。 |
+| hwtimer_sample.c       | 使用 硬件定时器定时 |
+| i2c_sample.c     | 使用 i2c 设备进行读写 |
+| pm.c | 反复进入不同程度的睡眠。 |
+| led_blink_sample.c     |  使用 pin 设备控制 LED 闪烁 |
+| pin_beep_sample.c      | 使用 pin 设备控制蜂鸣器 |
+| pwm_led_sample.c       | 使用 pwm 设备控制 LED 的亮度 |
+| rtc_sample.c           | 使用 rtc 设备设置年月日时分秒信息 |
+| spi_sample.c     | 使用 spi 设备进行读写 |
+| uart_sample.c          | 使用 serial 设备中断接收及轮询发送模式收发数据 |
+
+### 1.2 依赖
+
+依赖设备管理模块提供的设备驱动。
+
+## 2、如何打开 外设驱动测试用例
+
+使用 外设驱动测试用例 需要在 RT-Thread 的menuconfig中选择它,具体路径如下:
+
+```
+Hardware Driver Config --->
+    Peripheral Driver test example--->
+```
+
+## 3、使用 外设驱动测试用例
+
+在打开 Peripheral Driver test example 后,当进行 BSP 编译时,选择的软件包相关源代码会被加入到 BSP 工程中进行编译。
+
+## 4、注意事项
+
+暂无。
+
+## 5、联系方式 & 感谢
+
+* 维护:[misonyo](https://github.com/misonyo)
+* 主页:https://github.com/RT-Thread-packages/peripheral-sample
diff --git a/bsp/essemi/es32f369x/drivers/bsp_driver_example/adc_vol_sample.c b/bsp/essemi/es32f369x/drivers/bsp_driver_example/adc_vol_sample.c
new file mode 100644
index 0000000000..f9444982d4
--- /dev/null
+++ b/bsp/essemi/es32f369x/drivers/bsp_driver_example/adc_vol_sample.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-29     misonyo      first implementation.
+ */
+/*
+ * 程序清单: ADC 设备使用例程
+ * 例程导出了 adc_sample 命令到控制终端
+ * 命令调用格式:adc_sample
+ * 程序功能:通过 ADC 设备采样电压值并转换为数值。
+ *           示例代码参考电压为3.3V,转换位数为12位。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define ADC_DEV_NAME        "adc0"      /* ADC 设备名称 */
+#define ADC_DEV_CHANNEL     5           /* ADC 通道 5 PA1*/
+#define REFER_VOLTAGE       330         /* 参考电压 3.3V,数据精度乘以100保留2位小数*/
+#define CONVERT_BITS        (1 << 12)   /* 转换位数为12位 */
+
+static int adc_vol_sample(int argc, char *argv[])
+{
+    rt_adc_device_t adc_dev;
+    rt_uint32_t value, vol;
+    rt_err_t ret = RT_EOK;
+
+    /* 查找设备 */
+    adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);
+    if (adc_dev == RT_NULL)
+    {
+        rt_kprintf("adc sample run failed! can't find %s device!\n", ADC_DEV_NAME);
+        return RT_ERROR;
+    }
+
+    /* 使能设备 */
+    ret = rt_adc_enable(adc_dev, ADC_DEV_CHANNEL);
+
+    /* 读取采样值 */
+    value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
+    rt_kprintf("the value is :%d \n", value);
+
+    /* 转换为对应电压值 */
+    vol = value * REFER_VOLTAGE / CONVERT_BITS;
+    rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100);
+
+    /* 关闭通道 */
+    ret = rt_adc_disable(adc_dev, ADC_DEV_CHANNEL);
+
+    return ret;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(adc_vol_sample, adc voltage convert sample);
diff --git a/bsp/essemi/es32f369x/drivers/bsp_driver_example/can_sample.c b/bsp/essemi/es32f369x/drivers/bsp_driver_example/can_sample.c
new file mode 100644
index 0000000000..bfbd50095e
--- /dev/null
+++ b/bsp/essemi/es32f369x/drivers/bsp_driver_example/can_sample.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-06-25     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 CAN 设备使用例程
+ * 例程导出了 can_sample 命令到控制终端
+ * 命令调用格式:can_sample can
+ * 命令解释:命令第二个参数是要使用的 CAN 设备名称,为空则使用默认的 CAN 设备
+ * 程序功能:通过 CAN 设备发送一帧,并创建一个线程接收数据然后打印输出。
+*/
+
+#include <rtthread.h>
+#include "rtdevice.h"
+
+#define CAN_DEV_NAME       "can"      /* CAN 设备名称 */
+
+static struct rt_semaphore rx_sem;     /* 用于接收消息的信号量 */
+static rt_device_t can_dev;            /* CAN 设备句柄 */
+
+/* 接收数据回调函数 */
+static rt_err_t can_rx_call(rt_device_t dev, rt_size_t size)
+{
+    /* CAN 接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
+    rt_sem_release(&rx_sem);
+
+    return RT_EOK;
+}
+
+static void can_rx_thread(void *parameter)
+{
+    int i;
+    struct rt_can_msg rxmsg = {0};
+
+    /* 设置接收回调函数 */
+    rt_device_set_rx_indicate(can_dev, can_rx_call);
+
+#ifdef RT_CAN_USING_HDR
+    
+    rt_err_t res;
+    
+    struct rt_can_filter_item items[5] =
+    {
+        RT_CAN_FILTER_ITEM_INIT(0x100, 0, 0, 0, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x100~0x1ff,hdr为-1,设置默认过滤表 */
+        RT_CAN_FILTER_ITEM_INIT(0x300, 0, 0, 0, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x300~0x3ff,hdr为-1 */
+        RT_CAN_FILTER_ITEM_INIT(0x211, 0, 0, 0, 0x7ff, RT_NULL, RT_NULL), /* std,match ID:0x211,hdr为-1 */
+        RT_CAN_FILTER_STD_INIT(0x486, RT_NULL, RT_NULL),                  /* std,match ID:0x486,hdr为-1 */
+        {0x555, 0, 0, 0, 0x7ff, 7,}                                       /* std,match ID:0x555,hdr为7,指定设置7号过滤表 */
+    };
+    struct rt_can_filter_config cfg = {5, 1, items}; /* 一共有5个过滤表 */
+    /* 设置硬件过滤表 */
+    res = rt_device_control(can_dev, RT_CAN_CMD_SET_FILTER, &cfg);
+    RT_ASSERT(res == RT_EOK);
+#endif
+
+    while (1)
+    {
+        /* hdr值为-1,表示直接从uselist链表读取数据 */
+        rxmsg.hdr = -1;
+        /* 阻塞等待接收信号量 */
+        rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
+        /* 从CAN读取一帧数据 */
+        rt_device_read(can_dev, 0, &rxmsg, sizeof(rxmsg));
+        /* 打印数据ID及内容 */
+        rt_kprintf("ID:%x  ", rxmsg.id);
+        for (i = 0; i < 8; i++)
+        {
+            rt_kprintf("%2x ", rxmsg.data[i]);
+        }
+
+        rt_kprintf("\n");
+    }
+}
+
+int can_sample(int argc, char *argv[])
+{
+    struct rt_can_msg msg = {0};
+    rt_err_t res;
+    rt_size_t  size;
+    rt_thread_t thread;
+    char can_name[RT_NAME_MAX];
+    
+    if (argc == 2)
+    {
+        rt_strncpy(can_name, argv[1], RT_NAME_MAX);
+    }
+    else
+    {
+        rt_strncpy(can_name, CAN_DEV_NAME, RT_NAME_MAX);
+    }
+
+    can_dev = rt_device_find(can_name);
+    if (!can_dev)
+    {
+        rt_kprintf("find %s failed!\n", can_name);
+        return RT_ERROR;
+    }
+
+    /* 初始化CAN接收信号量 */
+    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
+
+    /* 以中断接收及发送方式打开CAN设备 */
+    res = rt_device_open(can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);
+    RT_ASSERT(res == RT_EOK);
+
+    thread = rt_thread_create("can_rx", can_rx_thread, RT_NULL, 1024, 25, 10);
+    if (thread != RT_NULL)
+    {
+        rt_thread_startup(thread);
+    }
+    else
+    {
+        rt_kprintf("create can_rx thread failed!\n");
+    }
+
+    msg.id = 0x78;              /* ID为0x78 */
+    msg.ide = RT_CAN_STDID;     /* 标准格式 */
+    msg.rtr = RT_CAN_DTR;       /* 数据帧 */
+    msg.len = 8;                /* 数据长度为8 */
+    /* 待发送的8字节数据 */
+    msg.data[0] = 0x00;
+    msg.data[1] = 0x11;
+    msg.data[2] = 0x22;
+    msg.data[3] = 0x33;
+    msg.data[4] = 0x44;
+    msg.data[5] = 0x55;
+    msg.data[6] = 0x66;
+    msg.data[7] = 0x77;
+    /* 发送一帧CAN数据 */
+    size = rt_device_write(can_dev, 0, &msg, sizeof(msg));
+    if (size == 0)
+    {
+        rt_kprintf("can dev write data failed!\n");
+    }
+    
+    return res;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(can_sample, can device sample);
diff --git a/bsp/essemi/es32f369x/drivers/bsp_driver_example/hwtimer_sample.c b/bsp/essemi/es32f369x/drivers/bsp_driver_example/hwtimer_sample.c
new file mode 100644
index 0000000000..e2e39664f3
--- /dev/null
+++ b/bsp/essemi/es32f369x/drivers/bsp_driver_example/hwtimer_sample.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-30     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 hwtimer 设备使用例程
+ * 例程导出了 hwtimer_sample 命令到控制终端
+ * 命令调用格式:hwtimer_sample
+ * 程序功能:硬件定时器超时回调函数周期性的打印当前tick值,2次tick值之差换算为时间等同于定时时间值。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define HWTIMER_DEV_NAME   "timer0"     /* 定时器名称 */
+
+/* 定时器超时回调函数 */
+static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size)
+{
+    rt_kprintf("tick is :%d !\n", rt_tick_get());
+
+    return 0;
+}
+
+static int hwtimer_sample(int argc, char *argv[])
+{
+    rt_err_t ret = RT_EOK;
+    rt_hwtimerval_t timeout_s;      /* 定时器超时值 */
+    rt_device_t hw_dev = RT_NULL;   /* 定时器设备句柄 */
+    rt_hwtimer_mode_t mode;         /* 定时器模式 */
+
+    /* 查找定时器设备 */
+    hw_dev = rt_device_find(HWTIMER_DEV_NAME);
+    if (hw_dev == RT_NULL)
+    {
+        rt_kprintf("hwtimer sample run failed! can't find %s device!\n", HWTIMER_DEV_NAME);
+        return RT_ERROR;
+    }
+
+    /* 以读写方式打开设备 */
+    ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
+    if (ret != RT_EOK)
+    {
+        rt_kprintf("open %s device failed!\n", HWTIMER_DEV_NAME);
+        return ret;
+    }
+
+    /* 设置超时回调函数 */
+    rt_device_set_rx_indicate(hw_dev, timeout_cb);
+
+    /* 设置模式为周期性定时器 */
+    mode = HWTIMER_MODE_PERIOD;
+    ret = rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
+    if (ret != RT_EOK)
+    {
+        rt_kprintf("set mode failed! ret is :%d\n", ret);
+        return ret;
+    }
+
+    /* 设置定时器超时值为5s并启动定时器 */
+    timeout_s.sec = 5;      /* 秒 */
+    timeout_s.usec = 0;     /* 微秒 */
+
+    if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
+    {
+        rt_kprintf("set timeout value failed\n");
+        return RT_ERROR;
+    }
+
+    /* 延时3500ms */
+    rt_thread_mdelay(3500);
+
+    /* 读取定时器当前值 */
+    rt_device_read(hw_dev, 0, &timeout_s, sizeof(timeout_s));
+    rt_kprintf("Read: Sec = %d, Usec = %d\n", timeout_s.sec, timeout_s.usec);
+
+    return ret;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(hwtimer_sample, hwtimer sample);
diff --git a/bsp/essemi/es32f369x/drivers/bsp_driver_example/i2c_sample.c b/bsp/essemi/es32f369x/drivers/bsp_driver_example/i2c_sample.c
new file mode 100644
index 0000000000..4fd42baf41
--- /dev/null
+++ b/bsp/essemi/es32f369x/drivers/bsp_driver_example/i2c_sample.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-15     liuhy       first implementation.
+ */
+/*
+ * 程序清单:这是一个 I2C 设备使用例程
+ * 例程导出了 i2c_io_sample 命令到控制终端
+ * 命令调用格式:i2c_io_sample
+ * 命令解释:使用默认的I2C总线设备i2c0
+ * 程序功能:通过 I2C 设备接收数据并打印,然后将接收的字符加1输出。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define I2C_BUS_NAME          "i2c0"  /* I2C总线设备名称 */
+#define SLAVE_ADDR                  0x2D    /* 从机地址 */
+#define STR_LEN                       16    /* 接收发送的数据长度 */
+
+static void i2c_io_sample(int argc, char *argv[])
+{
+    
+    struct rt_i2c_bus_device *i2c_bus = RT_NULL;     /* I2C总线设备句柄 */
+    struct rt_i2c_msg temp_msg;                             /* I2C消息 */
+    rt_uint8_t buffer[STR_LEN] = { 0U }; 
+    rt_uint32_t i,num_msg;
+    rt_size_t s_stat;
+    
+    i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(I2C_BUS_NAME);    /* 通过名字获取I2C总线设备的句柄 */
+    
+    if( i2c_bus == RT_NULL)
+    {
+        rt_kprintf("can't find i2c device :%s !\n",I2C_BUS_NAME);
+        
+        return;
+    }
+    
+        /*初始化消息*/
+        temp_msg.addr = SLAVE_ADDR;  /* 从机地址 */
+        temp_msg.len  = STR_LEN;     /* 传输的数据长度 */
+        temp_msg.buf = buffer;       /* 读写缓存器 */
+    
+        num_msg = 1;             /* 传输一条消息 */
+    
+        temp_msg.flags = RT_I2C_RD;             /* I2C读 */
+        s_stat = rt_i2c_transfer(i2c_bus,&temp_msg,num_msg);   /* 传输消息 */
+        
+        rt_thread_mdelay(400); 
+        
+        if( s_stat == num_msg )
+        {
+            rt_kprintf("receive successful. \n receive messege : %s \n:",buffer);
+            
+            for( i = 0 ; i < STR_LEN ; i++)
+            rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+            rt_kprintf("\n");
+        }
+        else
+        {
+            rt_kprintf("device s% recieve fail \n buffer : s%\n",I2C_BUS_NAME,buffer);
+            return;
+        }
+        
+        for( i = 0 ; i < STR_LEN ; i++)
+        buffer[i]++;
+    
+        temp_msg.flags = RT_I2C_WR;             /* I2C写 */
+        s_stat = rt_i2c_transfer(i2c_bus,&temp_msg,num_msg);   /* 传输一条 */
+        
+        rt_thread_mdelay(400);
+        
+        if( s_stat == num_msg )
+        {
+            rt_kprintf(" send successful \n messege : %s \n:",buffer);
+            
+            for( i = 0 ; i < STR_LEN ; i++)
+            rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+            rt_kprintf("\n");
+        }
+        else
+        {
+            rt_kprintf("device s% send fail \n",I2C_BUS_NAME);
+            return;
+        }
+        
+        return;
+    
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(i2c_io_sample, i2c io sample);
diff --git a/bsp/essemi/es32f369x/drivers/bsp_driver_example/led_blink_sample.c b/bsp/essemi/es32f369x/drivers/bsp_driver_example/led_blink_sample.c
new file mode 100644
index 0000000000..f1c9901ad0
--- /dev/null
+++ b/bsp/essemi/es32f369x/drivers/bsp_driver_example/led_blink_sample.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-09-25     misonyo      first edition.
+ */
+/*
+ * 程序清单:这是一个通过PIN脚控制LED亮灭的使用例程
+ * 例程导出了 led_sample 命令到控制终端
+ * 命令调用格式:led_sample 41
+ * 命令解释:命令第二个参数是要使用的PIN脚编号,为空则使用例程默认的引脚编号。
+ * 程序功能:程序创建一个led线程,线程每隔1000ms改变PIN脚状态,达到控制led灯
+ *            亮灭的效果。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <stdlib.h>
+
+/* PIN脚编号,查看驱动文件drv_gpio.c确定 */
+#define LED_PIN_NUM    19     /*PF1*/
+static int pin_num;
+
+static void led_entry(void *parameter)
+{
+    int count = 0;
+    /* 设置PIN脚模式为输出 */
+    rt_pin_mode(pin_num, PIN_MODE_OUTPUT);
+
+    while (1)
+    {
+        count++;
+        rt_kprintf("thread run count : %d\r\n", count);
+        /* 拉低PIN脚 */
+        rt_pin_write(pin_num, PIN_LOW);
+        rt_kprintf("led on!\r\n");
+        /* 延时1000ms */
+        rt_thread_mdelay(1000);
+
+        /* 拉高PIN脚 */
+        rt_pin_write(pin_num, PIN_HIGH);
+        rt_kprintf("led off!\r\n");
+        rt_thread_mdelay(1000);
+    }
+}
+
+static int led_sample(int argc, char *argv[])
+{
+    rt_thread_t tid;
+    rt_err_t ret = RT_EOK;
+
+    /* 判断命令行参数是否给定了PIN脚编号 */
+    if (argc == 2)
+    {
+        pin_num = atoi(argv[1]);
+    }
+    else
+    {
+        pin_num = LED_PIN_NUM;
+    }
+
+    tid = rt_thread_create("led",
+                           led_entry,
+                           RT_NULL,
+                           512,
+                           RT_THREAD_PRIORITY_MAX / 3,
+                           20);
+    if (tid != RT_NULL)
+    {
+        rt_thread_startup(tid);
+    }
+    else
+    {
+        ret = RT_ERROR;
+    }
+
+    return ret;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(led_sample, led sample);
diff --git a/bsp/essemi/es32f369x/drivers/bsp_driver_example/pin_beep_sample.c b/bsp/essemi/es32f369x/drivers/bsp_driver_example/pin_beep_sample.c
new file mode 100644
index 0000000000..58a7bf1891
--- /dev/null
+++ b/bsp/essemi/es32f369x/drivers/bsp_driver_example/pin_beep_sample.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-08-15     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 PIN 设备使用例程
+ * 例程导出了 pin_beep_sample 命令到控制终端
+ * 命令调用格式:pin_beep_sample
+ * 程序功能:通过按键控制蜂鸣器对应引脚的电平状态控制蜂鸣器
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+/* 引脚编号,通过查看驱动文件drv_gpio.c确定 */
+#ifndef BEEP_PIN_NUM
+    #define BEEP_PIN_NUM            19  /* PF1 */
+#endif
+#ifndef KEY0_PIN_NUM
+    #define KEY0_PIN_NUM            52  /* PC11 */
+#endif
+#ifndef KEY1_PIN_NUM
+    #define KEY1_PIN_NUM            53  /* PC12 */
+#endif
+
+void beep_on(void *args)
+{
+    rt_kprintf("turn on beep!\n");
+
+    rt_pin_write(BEEP_PIN_NUM, PIN_HIGH);
+}
+
+void beep_off(void *args)
+{
+    rt_kprintf("turn off beep!\n");
+
+    rt_pin_write(BEEP_PIN_NUM, PIN_LOW);
+}
+
+static void pin_beep_sample(void)
+{
+    /* 蜂鸣器引脚为输出模式 */
+    rt_pin_mode(BEEP_PIN_NUM, PIN_MODE_OUTPUT);
+    /* 默认低电平 */
+    rt_pin_write(BEEP_PIN_NUM, PIN_LOW);
+
+    /* 按键0引脚为输入模式 */
+    rt_pin_mode(KEY0_PIN_NUM, PIN_MODE_INPUT_PULLUP);
+    /* 绑定中断,下降沿模式,回调函数名为beep_on */
+    rt_pin_attach_irq(KEY0_PIN_NUM, PIN_IRQ_MODE_FALLING, beep_on, RT_NULL);
+    /* 使能中断 */
+    rt_pin_irq_enable(KEY0_PIN_NUM, PIN_IRQ_ENABLE);
+
+    /* 按键1引脚为输入模式 */
+    rt_pin_mode(KEY1_PIN_NUM, PIN_MODE_INPUT_PULLUP);
+    /* 绑定中断,下降沿模式,回调函数名为beep_off */
+    rt_pin_attach_irq(KEY1_PIN_NUM, PIN_IRQ_MODE_FALLING, beep_off, RT_NULL);
+    /* 使能中断 */
+    rt_pin_irq_enable(KEY1_PIN_NUM, PIN_IRQ_ENABLE);
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(pin_beep_sample, pin beep sample);
diff --git a/bsp/essemi/es32f369x/drivers/bsp_driver_example/pm_sample.c b/bsp/essemi/es32f369x/drivers/bsp_driver_example/pm_sample.c
new file mode 100644
index 0000000000..b886876108
--- /dev/null
+++ b/bsp/essemi/es32f369x/drivers/bsp_driver_example/pm_sample.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-15     liuhy       first implementation.
+ */
+/*
+ * 程序清单:这是一个 pm睡眠唤醒的使用例程
+ * 例程导出了 pm_sample 命令到控制终端
+ * 命令调用格式:pm_sample
+ * 命令解释:进入不同的睡眠模式,然后用按键唤醒
+ * 程序功能:通过串口输出字符串,告知进入睡眠和唤醒睡眠的情况。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include "drv_pm.h"
+
+#define PM_NAME       "pm"      /* 设备名称 */
+#define WAKE_UP_PIN     51      /* 唤醒源 */
+#define SLEEP_TIMES     12      /* 进入睡眠次数,轮流进入不同的睡眠模式,包括无睡眠模式 */
+
+
+struct pm_callback_t
+{
+     volatile int in_fun_times;   /*进入函数的次数*/
+     volatile char flag;          /*标志*/
+     volatile int mode;           /*需要打印的模式*/
+};
+
+volatile struct pm_callback_t g_pm_data;
+ 
+uint32_t save_load_mem[1024] __attribute__ ((aligned(4)));  /*备份的空间*/
+
+/*进入睡眠前,睡眠唤醒后,都会进入。*/
+/*函数打印睡眠相关的信息*/
+void sleep_in_out_callback(rt_uint8_t event, rt_uint8_t mode, void *data)
+{
+    /*没有标志,不处理*/
+    if(!(g_pm_data.flag))
+    {
+        return;
+    }
+    
+    /*标志不正常,清空标志*/
+    if((g_pm_data.flag) > 2)
+    {
+        (g_pm_data.flag) = 0;
+        return;
+    }
+    
+    /*模式不匹配*/
+    if(g_pm_data.mode != mode )
+    {
+        return;
+    }
+ 
+    /*进入的事件*/
+    switch(event)
+    {
+        /*进入睡眠前*/
+        case RT_PM_ENTER_SLEEP: g_pm_data.flag = 1;
+                                rt_kprintf("\n\r##%d :  ENTER  ",g_pm_data.in_fun_times);
+                                save_register(UART0,sizeof(UART_TypeDef),save_load_mem);    /*备份寄存器的值*/
+                                g_pm_data.in_fun_times++;     /*进入睡眠次数+1*/
+                                break;
+        /*睡眠唤醒后*/
+        case RT_PM_EXIT_SLEEP:  g_pm_data.flag = 0;  /*睡眠唤醒后*/
+                                load_register(UART0,sizeof(UART_TypeDef),save_load_mem);    /*还原寄存器的值*/
+                                rt_kprintf("\n\rEXIT\n\r");
+                                rt_pm_release(mode);   /*释放休眠模式*/
+                                return;
+        
+        default: break;
+        
+    };
+    
+    /*当前的睡眠模式*/
+    switch(mode)
+    {
+        case PM_SLEEP_MODE_NONE: rt_kprintf("PM_SLEEP_MODE_NONE\n\r");
+                                break;
+        case PM_SLEEP_MODE_IDLE:  rt_kprintf("PM_SLEEP_MODE_IDLE\n\r");
+                                break;
+        case PM_SLEEP_MODE_LIGHT: rt_kprintf("PM_SLEEP_MODE_LIGHT\n\r");
+                                break;
+        case PM_SLEEP_MODE_DEEP:  rt_kprintf("PM_SLEEP_MODE_DEEP\n\r");
+                                break;
+        case PM_SLEEP_MODE_STANDBY: rt_kprintf("PM_SLEEP_MODE_STANDBY\n\r");
+                                break;
+        case PM_SLEEP_MODE_SHUTDOWN:  rt_kprintf("PM_SLEEP_MODE_SHUTDOWN\n\r");
+                                break;      
+        case PM_SLEEP_MODE_MAX:  rt_kprintf("PM_SLEEP_MODE_MAX\n\r");
+                                break;
+        default: break;           
+    }
+    
+}
+
+/* pm测试函数 */
+static void pm_test(void *parameter)
+{
+    int in_mode[7],i = 0;
+    
+        g_pm_data.in_fun_times = 0;
+        g_pm_data.flag = 0;
+    
+        in_mode[0] = PM_SLEEP_MODE_NONE;
+        in_mode[1] = PM_SLEEP_MODE_IDLE;
+        in_mode[2] = PM_SLEEP_MODE_LIGHT;
+        in_mode[3] = PM_SLEEP_MODE_DEEP;
+        in_mode[4] = PM_SLEEP_MODE_STANDBY;
+        in_mode[5] = PM_SLEEP_MODE_SHUTDOWN;
+        in_mode[6] = PM_SLEEP_MODE_MAX;
+    
+    /*设置回调函数和私有数据*/
+    rt_pm_notify_set(sleep_in_out_callback,RT_NULL);
+       
+    while(i < SLEEP_TIMES)
+   {
+       
+       g_pm_data.mode = in_mode[i%6];
+       
+       /*无休眠模式,不赋予标志*/
+       if(g_pm_data.mode != PM_SLEEP_MODE_NONE)
+       {
+            g_pm_data.flag = 2;  
+       
+       }
+       
+       /*请求选择的休眠模式*/
+       rt_pm_request(in_mode[i%6]);
+
+       rt_thread_mdelay(500);
+       
+       /*无休眠模式,不需要额外的等待*/
+       while(( g_pm_data.flag != 0 )&&(g_pm_data.mode != PM_SLEEP_MODE_NONE))
+       {
+           rt_thread_mdelay(500);
+       }
+       
+       /*释放选择的休眠模式*/
+       rt_pm_release(in_mode[i%6]);
+       
+       i++;
+       
+   }
+      /*清除回调函数和私有数据*/
+    rt_pm_notify_set(RT_NULL,RT_NULL);
+    rt_kprintf("thread pm_test close\n\r");
+   
+}
+
+/*按键唤醒的回调函数*/
+void wake_by_pin(void *args)
+{
+
+}
+
+static int pm_sample(int argc, char *argv[])
+{
+    rt_thread_t thread;
+    
+    /* 按键引脚为输入模式 */
+    rt_pin_mode(WAKE_UP_PIN, PIN_MODE_INPUT_PULLUP);
+    
+    /* 绑定中断,下降沿模式,回调函数名为wake_by_pin */
+    rt_pin_attach_irq(WAKE_UP_PIN, PIN_IRQ_MODE_RISING, wake_by_pin, RT_NULL);
+    /* 使能中断 */
+    rt_pin_irq_enable(WAKE_UP_PIN, PIN_IRQ_ENABLE);
+    
+    thread = rt_thread_create("pm_test", pm_test, RT_NULL, 1024, 25, 10);
+    
+    if (thread != RT_NULL)
+    {
+        rt_thread_startup(thread);
+    }
+    else
+    {
+        rt_kprintf("create pm_test thread failed!\n\r");
+    }
+    
+    return RT_EOK;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(pm_sample, pm sample);
diff --git a/bsp/essemi/es32f369x/drivers/bsp_driver_example/pwm_led_sample.c b/bsp/essemi/es32f369x/drivers/bsp_driver_example/pwm_led_sample.c
new file mode 100644
index 0000000000..df82c1b41c
--- /dev/null
+++ b/bsp/essemi/es32f369x/drivers/bsp_driver_example/pwm_led_sample.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-25     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 PWM 设备使用例程
+ * 例程导出了 pwm_led_sample 命令到控制终端
+ * 命令调用格式:pwm_led_sample
+ * 程序功能:通过 PWM 设备控制 LED 灯的亮度,可以看到LED不停的由暗变到亮,然后又从亮变到暗。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define LED_PIN_NUM         19      /* PF1 LED PIN脚编号,查看驱动文件drv_gpio.c确定 */
+#define PWM_DEV_NAME        "pwm1"  /* PWM设备名称 */
+#define PWM_DEV_CHANNEL     2       /* PA1 PWM通道 */
+
+struct rt_device_pwm *pwm_dev;      /* PWM设备句柄 */
+
+static int pwm_led_sample(int argc, char *argv[])
+{
+    rt_uint32_t period, pulse, dir;
+
+    period = 500000;    /* 周期为0.5ms,单位为纳秒ns */
+    dir = 1;            /* PWM脉冲宽度值的增减方向 */
+    pulse = 0;          /* PWM脉冲宽度值,单位为纳秒ns */
+
+    /* 查找设备 */
+    pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
+    if (pwm_dev == RT_NULL)
+    {
+        rt_kprintf("pwm sample run failed! can't find %s device!\n", PWM_DEV_NAME);
+        return RT_ERROR;
+    }
+
+    /* 设置PWM周期和脉冲宽度默认值 */
+    rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
+    /* 使能设备 */
+    rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
+    
+    while (1)
+    {
+        rt_thread_mdelay(50);
+        if (dir)
+        {
+            pulse += 5000;      /* 从0值开始每次增加5000ns */
+        }
+        else
+        {
+            pulse -= 5000;      /* 从最大值开始每次减少5000ns */
+        }
+        if (pulse >= period)
+        {
+            dir = 0;
+        }
+        if (0 == pulse)
+        {
+            dir = 1;
+        }
+
+        /* 设置PWM周期和脉冲宽度 */
+        rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
+    }
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(pwm_led_sample, pwm sample);
diff --git a/bsp/essemi/es32f369x/drivers/bsp_driver_example/rtc_sample.c b/bsp/essemi/es32f369x/drivers/bsp_driver_example/rtc_sample.c
new file mode 100644
index 0000000000..711a3a0ebb
--- /dev/null
+++ b/bsp/essemi/es32f369x/drivers/bsp_driver_example/rtc_sample.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-30     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 RTC 设备使用例程
+ * 例程导出了 rtc_sample 命令到控制终端
+ * 命令调用格式:rtc_sample
+ * 程序功能:设置RTC设备的日期和时间,延时一段时间后获取当前时间并打印显示。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+static int rtc_sample(int argc, char *argv[])
+{
+    rt_err_t ret = RT_EOK;
+    time_t now;
+
+    /* 设置日期 */
+    ret = set_date(2018, 12, 3);
+    if (ret != RT_EOK)
+    {
+        rt_kprintf("set RTC date failed\n");
+        return ret;
+    }
+
+    /* 设置时间 */
+    ret = set_time(11, 15, 50);
+    if (ret != RT_EOK)
+    {
+        rt_kprintf("set RTC time failed\n");
+        return ret;
+    }
+
+    /* 延时3秒 */
+    rt_thread_mdelay(3000);
+
+    /* 获取时间 */
+    now = time(RT_NULL);
+    rt_kprintf("%s\n", ctime(&now));
+
+    return ret;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(rtc_sample, rtc sample);
diff --git a/bsp/essemi/es32f369x/drivers/bsp_driver_example/spi_sample.c b/bsp/essemi/es32f369x/drivers/bsp_driver_example/spi_sample.c
new file mode 100644
index 0000000000..994888cdb0
--- /dev/null
+++ b/bsp/essemi/es32f369x/drivers/bsp_driver_example/spi_sample.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-15     liuhy       first implementation.
+ */
+/*
+ * 程序清单:这是一个 SPI 设备使用例程
+ * 例程导出了 spi_io_sample 命令到控制终端
+ * 命令调用格式:spi_io_sample
+ * 程序功能:通过SPI设备先读取数据,然后每个字符加1后输出。
+*/
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define SPI_DEVICE_NAME     "spi00"
+#define BUF_LEN             16
+
+static void spi_io_sample(int argc, char *argv[])
+{
+    struct rt_spi_device * spi_dev;          /* spi设备的句柄 */
+    struct rt_spi_configuration spi_config;
+    rt_uint8_t i,buffer[BUF_LEN] = { 0U };
+    rt_err_t s_stat;
+    rt_err_t result;
+    
+     /* 查找 spi设备 获取spi设备句柄 */
+    spi_dev = (struct rt_spi_device *)rt_device_find(SPI_DEVICE_NAME);
+    
+    if (spi_dev == RT_NULL)
+    {
+        rt_kprintf("spi sample run failed! can't find %s device!\n", SPI_DEVICE_NAME);
+        return;
+    }
+    
+    
+    /* 清空配置结构体 */
+    rt_memset(&spi_config,0,sizeof(struct rt_spi_configuration));
+    
+    spi_config.mode &= ~RT_SPI_SLAVE; /* 主机模式 */
+    spi_config.mode &= ~RT_SPI_3WIRE; /* 4线,双向传输 */
+    spi_config.mode |= RT_SPI_CPHA;   /* 第二边沿采样 */
+    spi_config.mode |= RT_SPI_CPOL;   /* 空闲高电平 */
+    spi_config.mode |= RT_SPI_NO_CS;  /* 禁用软件从机选择管理 */
+    spi_config.mode |= RT_SPI_MSB;    /* 高位在前 */
+    
+    spi_config.data_width = 8;        /* 数据长度:8 */
+    
+    spi_config.max_hz = 2000000;      /* 最快时钟频率 */
+    
+    /* 配置SPI设备 */
+    s_stat = rt_spi_configure(spi_dev,&spi_config);
+    
+    if(s_stat != RT_EOK)
+    {
+        rt_kprintf(" spi config fail !\n ");
+        return;
+    }
+    
+    
+    /* 获取总线 ,防止总线被多个线程同时使用 */
+    result = rt_spi_take_bus(spi_dev);
+    
+    if (result != RT_EOK)
+    {
+        rt_kprintf(" %s take spi bus  failed! \n", SPI_DEVICE_NAME);
+        return;
+    }
+    
+    /* 选中片选 */
+    result = rt_spi_take(spi_dev);
+    
+    if (result != RT_EOK)
+    {
+        rt_kprintf(" %s take spi cs  failed! \n", SPI_DEVICE_NAME);
+        return;
+    }
+    
+    
+    /*接收一次数据*/
+    result = rt_spi_recv(spi_dev,buffer,BUF_LEN);
+    
+    if(result != BUF_LEN)
+    {
+        rt_kprintf("receive fail. \n buffer is : %s \n:",buffer);
+            
+        for( i = 0 ; i < BUF_LEN ; i++)
+         rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+        rt_kprintf("\n");
+        
+        return;
+    }
+    
+    rt_kprintf("receive successful. \n buffer is : %s \n:",buffer);
+            
+    for( i = 0 ; i < BUF_LEN ; i++)
+    rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+    rt_kprintf("\n");
+    
+    /* 将接收到的数据加1 */
+    for( i = 0 ; i < BUF_LEN ; i++)
+      buffer[i]++;
+    
+    /*发送数据*/
+    result = rt_spi_send(spi_dev,buffer,BUF_LEN);
+    
+    if(result != BUF_LEN)
+    {
+        rt_kprintf("send fail. \n buffer is : %s \n:",buffer);
+            
+        for( i = 0 ; i < BUF_LEN ; i++)
+         rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+        rt_kprintf("\n");
+        
+        return;
+    }
+    
+    rt_kprintf("send successful. \n buffer is : %s \n:",buffer);
+            
+    for( i = 0 ; i < BUF_LEN ; i++)
+    rt_kprintf(" %x",(unsigned int)buffer[i]);
+            
+    rt_kprintf("\n");
+   
+    /* 释放片选 */
+    result = rt_spi_release(spi_dev);
+    
+    if (result != RT_EOK)
+    {
+        rt_kprintf(" %s release spi cs failed! \n", SPI_DEVICE_NAME);
+        return;
+    } 
+    
+    /* 释放总线 */
+    result = rt_spi_release_bus(spi_dev);
+    
+    if (result != RT_EOK)
+    {
+        rt_kprintf(" %s release spi bus  failed! \n", SPI_DEVICE_NAME);
+        return;
+    }
+    
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(spi_io_sample, spi  sample);
diff --git a/bsp/essemi/es32f369x/drivers/bsp_driver_example/uart_sample.c b/bsp/essemi/es32f369x/drivers/bsp_driver_example/uart_sample.c
new file mode 100644
index 0000000000..e059df32bb
--- /dev/null
+++ b/bsp/essemi/es32f369x/drivers/bsp_driver_example/uart_sample.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-08-15     misonyo      first implementation.
+ */
+/*
+ * 程序清单:这是一个 串口 设备使用例程
+ * 例程导出了 uart_sample 命令到控制终端
+ * 命令调用格式:uart_sample uart2
+ * 命令解释:命令第二个参数是要使用的串口设备名称,为空则使用默认的串口设备
+ * 程序功能:通过串口输出字符串"hello RT-Thread!",然后错位输出输入的字符
+*/
+
+#include <rtthread.h>
+
+#define SAMPLE_UART_NAME       "uart0"      /* 串口设备名称 */
+
+/* 用于接收消息的信号量 */
+static struct rt_semaphore rx_sem;
+static rt_device_t serial;
+
+/* 接收数据回调函数 */
+static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
+{
+    /* 串口接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
+    rt_sem_release(&rx_sem);
+
+    return RT_EOK;
+}
+
+static void serial_thread_entry(void *parameter)
+{
+    char ch;
+
+    while (1)
+    {
+        /* 从串口读取一个字节的数据,没有读取到则等待接收信号量 */
+        while (rt_device_read(serial, -1, &ch, 1) != 1)
+        {
+            /* 阻塞等待接收信号量,等到信号量后再次读取数据 */
+            rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
+        }
+        /* 读取到的数据通过串口错位输出 */
+        ch = ch + 1;
+        rt_device_write(serial, 0, &ch, 1);
+    }
+}
+
+static int uart_sample(int argc, char *argv[])
+{
+    rt_err_t ret = RT_EOK;
+    char uart_name[RT_NAME_MAX];
+    char str[] = "hello RT-Thread!\r\n";
+
+    if (argc == 2)
+    {
+        rt_strncpy(uart_name, argv[1], RT_NAME_MAX);
+    }
+    else
+    {
+        rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX);
+    }
+
+    /* 查找串口设备 */
+    serial = rt_device_find(uart_name);
+    if (!serial)
+    {
+        rt_kprintf("find %s failed!\n", uart_name);
+        return RT_ERROR;
+    }
+
+    /* 初始化信号量 */
+    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
+    /* 以中断接收及轮询发送方式打开串口设备 */
+    rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
+    /* 设置接收回调函数 */
+    rt_device_set_rx_indicate(serial, uart_input);
+    /* 发送字符串 */
+    rt_device_write(serial, 0, str, (sizeof(str) - 1));
+
+    /* 创建 serial 线程 */
+    rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
+    /* 创建成功则启动线程 */
+    if (thread != RT_NULL)
+    {
+        rt_thread_startup(thread);
+    }
+    else
+    {
+        ret = RT_ERROR;
+    }
+
+    return ret;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(uart_sample, uart device sample);
diff --git a/bsp/essemi/es32f369x/drivers/drv_pm.c b/bsp/essemi/es32f369x/drivers/drv_pm.c
new file mode 100644
index 0000000000..ffe46ff6f3
--- /dev/null
+++ b/bsp/essemi/es32f369x/drivers/drv_pm.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author        Notes
+ * 2020-12-15     liuhy        the first version
+ */
+
+#include "drv_pm.h"
+
+#ifdef RT_USING_PM
+
+//uint32_t save_mem[1024] __attribute__ ((aligned(4)));
+
+void save_register(void *p_head,uint32_t size,void *p_save)
+{
+     memcpy(p_save,p_head,size);
+}
+ 
+void load_register(void *p_head,uint32_t size,void *p_load)
+{
+    uint32_t tmp;
+     memcpy(p_head,p_load,size);
+    
+    if((p_head == UART0) || (p_head == UART1) || (p_head == UART2) || 
+         (p_head == UART3) || (p_head == UART4) || (p_head == UART5) )
+    {
+        tmp = ((UART_TypeDef*)p_load)->IVS;
+        ((UART_TypeDef*)p_head)->IER = tmp;
+    }
+}
+
+static void uart_console_reconfig(void)
+{
+    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
+
+    rt_device_control(rt_console_get_device(), RT_DEVICE_CTRL_CONFIG, &config);
+}
+
+static void delay(void)
+{
+    long i;
+    rt_base_t level;
+
+    level = rt_hw_interrupt_disable();
+    i = 0;
+    do{
+        i++;
+    }
+    while (i < 4000000); 
+    
+    rt_hw_interrupt_enable(level);
+}
+
+/**
+ * This function will put ES32F369x into sleep mode.
+ *
+ * @param pm pointer to power manage structure
+ */
+
+struct pm_callback_t
+{
+     volatile int in_fun_times;   /*进入函数的次数*/
+     volatile char flag;          /*标志*/
+     volatile int mode;           /*需要打印的模式*/
+};
+
+extern volatile struct pm_callback_t g_pm_data;
+
+static void sleep(struct rt_pm *pm, uint8_t mode)
+{
+   
+    switch (mode)
+    {
+    case PM_SLEEP_MODE_NONE:
+        break;
+
+    case PM_SLEEP_MODE_IDLE:
+        break;
+
+    case PM_SLEEP_MODE_LIGHT:
+        /* Enter SLEEP Mode, Main regulator is ON */
+        ald_pmu_stop1_enter();
+        delay();
+      
+        break;
+
+    case PM_SLEEP_MODE_DEEP:           
+        /* Enter STOP 2 mode  */
+        ald_pmu_stop2_enter();
+        delay();
+        break;
+
+    case PM_SLEEP_MODE_STANDBY:
+        /* Enter STANDBY mode */
+        ald_pmu_stop2_enter();
+        delay();
+        break;
+
+    case PM_SLEEP_MODE_SHUTDOWN:
+        /* Enter SHUTDOWNN mode */
+        ald_pmu_stop2_enter();
+        delay();
+        break;
+
+    default:
+        RT_ASSERT(0);
+        break;
+    }
+    
+}
+
+static uint8_t run_speed[PM_RUN_MODE_MAX][2] =
+{
+    {48, 0},
+    {48, 1},
+    {24, 2},
+    {2,  3},
+};
+
+static void run(struct rt_pm *pm, uint8_t mode)
+{
+    static uint8_t last_mode;
+    static char *run_str[] = PM_RUN_MODE_NAMES;
+    extern uint32_t __system_clock;
+
+    if (mode == last_mode)
+        return;
+    last_mode = mode;
+
+    ald_cmu_clock_config_default();
+    __system_clock = 24000000;
+    switch (mode)
+    {
+    case PM_RUN_MODE_HIGH_SPEED:
+    case PM_RUN_MODE_NORMAL_SPEED:
+        /* hosc 12MHz, from hosc/3 pll to 48MHz */
+        ald_cmu_pll1_config(CMU_PLL1_INPUT_HRC_6, CMU_PLL1_OUTPUT_48M);
+        /* MCLK 48MHz */
+        ald_cmu_clock_config(CMU_CLOCK_PLL1, 48000000);
+        break;
+    case PM_RUN_MODE_MEDIUM_SPEED:
+        break;
+    case PM_RUN_MODE_LOW_SPEED:
+        ald_cmu_clock_config(CMU_CLOCK_HRC, 2000000);
+        break;
+    default:
+        break;
+    }
+
+    /* 4. 更新外设时钟 */
+    uart_console_reconfig();
+    /* Re-Configure the Systick time */
+    SysTick_Config(ald_cmu_get_sys_clock() / RT_TICK_PER_SECOND);
+
+    rt_kprintf("switch to %s mode, frequency = %d MHz\n", run_str[mode], run_speed[mode][0]);
+}
+
+/**
+ * This function caculate the PM tick from OS tick
+ *
+ * @param tick OS tick
+ *
+ * @return the PM tick
+ */
+static rt_tick_t es32f3_pm_tick_from_os_tick(rt_tick_t tick)
+{
+    rt_uint32_t freq = 1;
+
+    return (freq * tick / RT_TICK_PER_SECOND);
+}
+
+/**
+ * This function caculate the OS tick from PM tick
+ *
+ * @param tick PM tick
+ *
+ * @return the OS tick
+ */
+static rt_tick_t es32f3_os_tick_from_pm_tick(rt_uint32_t tick)
+{
+    static rt_uint32_t os_tick_remain = 0;
+    rt_uint32_t ret, freq;
+
+    freq = 1;
+    ret = (tick * RT_TICK_PER_SECOND + os_tick_remain) / freq;
+
+    os_tick_remain += (tick * RT_TICK_PER_SECOND);
+    os_tick_remain %= freq;
+
+    return ret;
+}
+
+/**
+ * This function start the timer of pm
+ *
+ * @param pm Pointer to power manage structure
+ * @param timeout How many OS Ticks that MCU can sleep
+ */
+static void pm_timer_start(struct rt_pm *pm, rt_uint32_t timeout)
+{
+    RT_ASSERT(pm != RT_NULL);
+    RT_ASSERT(timeout > 0);
+
+    if (timeout != RT_TICK_MAX)
+    {
+        /* Convert OS Tick to pmtimer timeout value */
+        timeout = es32f3_pm_tick_from_os_tick(timeout);
+        /* MAX 0xFFFF */
+        if (timeout > 0xFFFF)
+        {
+            timeout = 0xFFFF;
+        }
+    }
+}
+
+/**
+ * This function stop the timer of pm
+ *
+ * @param pm Pointer to power manage structure
+ */
+static void pm_timer_stop(struct rt_pm *pm)
+{
+    RT_ASSERT(pm != RT_NULL);
+}
+
+/**
+ * This function calculate how many OS Ticks that MCU have suspended
+ *
+ * @param pm Pointer to power manage structure
+ *
+ * @return OS Ticks
+ */
+static rt_tick_t pm_timer_get_tick(struct rt_pm *pm)
+{
+    rt_uint32_t timer_tick;
+
+    RT_ASSERT(pm != RT_NULL);
+
+    timer_tick = 1;
+
+    return es32f3_os_tick_from_pm_tick(timer_tick);
+}
+
+/**
+ * This function initialize the power manager
+ */
+int drv_pm_hw_init(void)
+{
+    static const struct rt_pm_ops _ops =
+    {
+        sleep,
+        run,
+        pm_timer_start,
+        pm_timer_stop,
+        pm_timer_get_tick
+    };
+
+    rt_uint8_t timer_mask = 0;
+
+    /* initialize timer mask */
+    timer_mask = 1UL << PM_SLEEP_MODE_DEEP;
+
+    /* initialize system pm module */
+    rt_system_pm_init(&_ops, timer_mask, RT_NULL);
+
+    return 0;
+}
+INIT_BOARD_EXPORT(drv_pm_hw_init);
+
+#endif
diff --git a/bsp/essemi/es32f369x/drivers/drv_pm.h b/bsp/essemi/es32f369x/drivers/drv_pm.h
new file mode 100644
index 0000000000..56de29eef5
--- /dev/null
+++ b/bsp/essemi/es32f369x/drivers/drv_pm.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author        Notes
+ * 2019-04-01     wangyq        the first version
+ */
+
+#ifndef DRV_PM_H__
+#define DRV_PM_H__
+
+#include <rthw.h>
+#include <board.h>
+#include <rtdevice.h>
+#include <ald_cmu.h>
+#include <ald_pmu.h>
+#include "shell.h"
+
+int rt_hw_pm_init(void);
+
+extern void save_register(void *p_head,uint32_t size,void *p_save);
+ 
+extern void load_register(void *p_head,uint32_t size,void *p_load);
+
+#endif
diff --git a/bsp/essemi/es32f369x/figures/内核用例.PNG b/bsp/essemi/es32f369x/figures/内核用例.PNG
new file mode 100644
index 0000000000..4c4f8e05ba
Binary files /dev/null and b/bsp/essemi/es32f369x/figures/内核用例.PNG differ
diff --git a/bsp/essemi/es32f369x/figures/内核配置.PNG b/bsp/essemi/es32f369x/figures/内核配置.PNG
new file mode 100644
index 0000000000..f5901c0e59
Binary files /dev/null and b/bsp/essemi/es32f369x/figures/内核配置.PNG differ
diff --git a/bsp/essemi/es32f369x/figures/驱动用例.PNG b/bsp/essemi/es32f369x/figures/驱动用例.PNG
new file mode 100644
index 0000000000..a93b4186ae
Binary files /dev/null and b/bsp/essemi/es32f369x/figures/驱动用例.PNG differ
diff --git a/bsp/essemi/es32f369x/figures/驱动配置.PNG b/bsp/essemi/es32f369x/figures/驱动配置.PNG
new file mode 100644
index 0000000000..8ec566f7ab
Binary files /dev/null and b/bsp/essemi/es32f369x/figures/驱动配置.PNG differ