Quellcode durchsuchen

ch569w-evt : add pwm driver, and spi_xfer bug fix (#6240)

add PWM driver, output checked with logic analyzer
spi_xfer() bug fix for cs_pin and message looping
uart pin_mode init moved to uart driver
emuzit vor 2 Jahren
Ursprung
Commit
77067f8729

+ 3 - 0
bsp/wch/risc-v/Libraries/ch56x_drivers/SConscript

@@ -12,6 +12,9 @@ if GetDepend('SOC_SERIES_CH569'):
     if GetDepend('RT_USING_WDT'):
         src += ['ch56x_wdt.c']
 
+if GetDepend('RT_USING_PWM'):
+    src += ['ch56x_pwm.c']
+
 if GetDepend('RT_USING_HWTIMER'):
     src += ['ch56x_timer.c']
 

+ 288 - 0
bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_pwm.c

@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author            Notes
+ * 2022-08-04     Emuzit            first version
+ */
+#include <rthw.h>
+#include <rtdebug.h>
+#include <drivers/rt_drv_pwm.h>
+#include <drivers/pin.h>
+#include "ch56x_pwm.h"
+#include "ch56x_sys.h"
+
+#define PWM_CYCLE_MAX   255     // must be 255 for 0%~100% duty cycle
+
+struct pwm_device
+{
+    struct rt_device_pwm parent;
+    volatile struct pwm_registers *reg_base;
+    uint32_t period;
+};
+static struct pwm_device pwmx_device;
+
+static const uint8_t pwmx_pin[] = {PWM0_PIN, PWM1_PIN, PWM2_PIN, PWM3_PIN};
+
+/**
+ * @brief   Enable or disable PWM channel output.
+ *          Make sure PWM clock is ON for writing registers.
+ *
+ * @param   device is pointer to the rt_device_pwm device.
+ *
+ * @param   channel is the PWM channel (0~3) to operate on.
+ *
+ * @param   enable is to enable PWM when RT_TRUE, or disable when RT_FALSE.
+ *
+ * @return  None.
+ */
+static void pwm_channel_enable(struct rt_device_pwm *device,
+                               uint32_t channel, rt_bool_t enable)
+{
+    struct pwm_device *pwm_device = (struct pwm_device *)device;
+    volatile struct pwm_registers *pxreg = pwm_device->reg_base;
+
+    uint8_t ctrl_mod, polar;
+
+    if (enable)
+    {
+        /* set pwm_out_en to allow pwm output */
+        ctrl_mod = pxreg->CTRL_MOD.reg;
+        pxreg->CTRL_MOD.reg = ctrl_mod | (RB_PWM0_OUT_EN << channel);
+    }
+    else
+    {
+        /* ch56x has no disable bit, set pin out to quiesce */
+        ctrl_mod = pxreg->CTRL_MOD.reg;
+        polar = ctrl_mod & (RB_PWM0_POLAR << channel);
+        rt_pin_write(pwmx_pin[channel], polar ? PIN_HIGH : PIN_LOW);
+        ctrl_mod &= ~(RB_PWM0_OUT_EN << channel);
+        pxreg->CTRL_MOD.reg = ctrl_mod;
+    }
+}
+
+/**
+ * @brief   Set period of the PWM channel.
+ *          Make sure PWM clock is ON for writing registers.
+ *
+ * @param   device is pointer to the rt_device_pwm device.
+ *
+ * @param   channel is the PWM channel (0~3) to operate on.
+ *
+ * @param   period is PWM period in nanoseconds.
+ *
+ * @return  RT_EOK if successful.
+ */
+static rt_err_t pwm_channel_period(struct rt_device_pwm *device,
+                                   uint32_t channel, uint32_t period)
+{
+    struct pwm_device *pwm_device = (struct pwm_device *)device;
+
+    uint32_t clock_div;
+
+    /* All ch56x PWMX channels share the same period, channel ignored.
+     *
+     * Max allowed period is when Fsys@2MHz and CLOCK_DIV is 0 (256) :
+     *     (1 / 2MHz) * 256 * PWM_CYCLE_MAX => 32640000 ns
+     * Note that `period * F_MHz` won't overflow in calculation below.
+    */
+    if (period > (256 * PWM_CYCLE_MAX * 1000 / 2))
+        return -RT_EINVAL;
+
+    if (period != pwm_device->period)
+    {
+        uint32_t Fsys = sys_hclk_get();
+        uint32_t F_MHz = Fsys / 1000000;
+        uint32_t F_mod = Fsys % 1000000;
+
+        /* period = (clock_div / Fsys) * 10^9 * PWM_CYCLE_MAX */
+        clock_div = period * F_MHz + (1000 * PWM_CYCLE_MAX / 2);
+        /* Fsys is mostly in integer MHz, likely to be skipped */
+        if (F_mod != 0)
+        {
+            uint64_t u64v = ((uint64_t)period * F_mod) / 1000000;
+            clock_div += (uint32_t)u64v;
+        }
+        clock_div = clock_div / (1000 * PWM_CYCLE_MAX);
+        if (clock_div > 256)
+            return -RT_EINVAL;
+        /* CLOCK_DIV will be 0 if `clock_div` is 256 */
+        pwm_device->reg_base->CLOCK_DIV = (uint8_t)clock_div;
+        /* cycle_sel set to PWM_CYCLE_SEL_255 for 0%~100% duty cycle */
+        pwmx_device.reg_base->CTRL_CFG.cycle_sel = PWM_CYCLE_SEL_255;
+        pwm_device->period = period;
+    }
+
+    return RT_EOK;
+}
+
+/**
+ * @brief   Set pulse duration of the PWM channel.
+ *          Make sure PWM clock is ON for writing registers.
+ *
+ * @param   device is pointer to the rt_device_pwm device.
+ *
+ * @param   channel is the PWM channel (0~3) to operate on.
+ *
+ * @param   pulse is PWM pulse duration in nanoseconds.
+ *
+ * @return  RT_EOK if successful.
+ */
+static rt_err_t pwm_channel_pulse(struct rt_device_pwm *device,
+                                  uint32_t channel, uint32_t pulse)
+{
+    struct pwm_device *pwm_device = (struct pwm_device *)device;
+
+    uint32_t pdata, period;
+
+    /* duty cycle is calculated with "raw" period setting */
+    period = pwm_device->period;
+    if (!period || pulse > period)
+        return -RT_EINVAL;
+
+    pdata = (pulse * PWM_CYCLE_MAX + (period >> 1)) / period;
+    pwm_device->reg_base->PWM_DATA[channel] = pdata;
+
+    return RT_EOK;
+}
+
+/**
+ * @brief   Set period & pulse of the PWM channel, remain disabled.
+ *          Make sure PWM clock is ON for writing registers.
+ *
+ * @param   device is pointer to the rt_device_pwm device.
+ *
+ * @param   configuration is the channel/period/pulse specification.
+ *          ch56x PWM has no complementary pin, complementary ignored.
+ *          FIXME: can we specify PWM output polarity somehow ?
+ *
+ * @return  RT_EOK if successful.
+ */
+static rt_err_t pwm_device_set(struct rt_device_pwm *device,
+                               struct rt_pwm_configuration *configuration)
+{
+    struct pwm_device *pwm_device = (struct pwm_device *)device;
+
+    uint32_t channel = configuration->channel;
+
+    rt_err_t res;
+
+    res = pwm_channel_period(device, channel, configuration->period);
+    if (res == RT_EOK)
+    {
+        res = pwm_channel_pulse(device, channel, configuration->pulse);
+        if (res == RT_EOK)
+        {
+            rt_pin_mode(pwmx_pin[channel], PIN_MODE_OUTPUT);
+            /* seems to be kept disabled according to sample code */
+            pwm_channel_enable(device, channel, RT_FALSE);
+        }
+    }
+
+    return res;
+}
+
+/**
+ * @brief   Get period & pulse of the PWM channel.
+ *          The returned information is calculated with h/w setting.
+ *
+ * @param   device is pointer to the rt_device_pwm device.
+ *
+ * @param   configuration->channel specify the PWM channel (0~3).
+ *          configuration->period & pulse return the calculated result.
+ *
+ * @return  RT_EOK if successful.
+ */
+static rt_err_t pwm_device_get(struct rt_device_pwm *device,
+                               struct rt_pwm_configuration *configuration)
+{
+    struct pwm_device *pwm_device = (struct pwm_device *)device;
+    volatile struct pwm_registers *pxreg = pwm_device->reg_base;
+
+    uint32_t channel = configuration->channel;
+
+    uint32_t Fsys = sys_hclk_get();
+
+    uint32_t clock_div;
+    uint32_t pdata;
+    uint64_t u64v;
+
+    /* clock_div is actually 256 when CLOCK_DIV is 0 */
+    clock_div = pxreg->CLOCK_DIV;
+    if (clock_div == 0)
+        clock_div = 256;
+
+    u64v = clock_div;
+    u64v = (u64v * 1000*1000*1000 * PWM_CYCLE_MAX + (Fsys >> 1)) / Fsys;
+    configuration->period = (uint32_t)u64v;
+
+    /* `pdata` <= PWM_CYCLE_MAX, calculated pulse won't exceed period */
+    pdata = pxreg->PWM_DATA[channel];
+    u64v = clock_div;
+    u64v = (u64v * 1000*1000*1000 * pdata + (Fsys >> 1)) / Fsys;
+    configuration->pulse = (uint32_t)u64v;
+
+    return RT_EOK;
+}
+
+static rt_err_t pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
+{
+    struct pwm_device *pwm_device = (struct pwm_device *)device;
+
+    struct rt_pwm_configuration *configuration = arg;
+    uint32_t channel = configuration->channel;
+
+    rt_err_t res = RT_EOK;
+
+    RT_ASSERT(device != RT_NULL);
+
+    if (channel >= PWM_CHANNELS)
+        return -RT_EINVAL;
+
+    /* PWM clock needs to be ON to write PWM registers */
+    sys_slp_clk_off0(RB_SLP_CLK_PWMX, SYS_SLP_CLK_ON);
+
+    switch (cmd)
+    {
+    case PWM_CMD_ENABLE:
+        pwm_channel_enable(device, channel, RT_TRUE);
+        break;
+    case PWM_CMD_DISABLE:
+        pwm_channel_enable(device, channel, RT_FALSE);
+        break;
+    case PWM_CMD_SET:
+        return pwm_device_set(device, configuration);
+    case PWM_CMD_GET:
+        return pwm_device_get(device, configuration);
+    case PWM_CMD_SET_PERIOD:
+        return pwm_channel_period(device, channel, configuration->period);
+    case PWM_CMD_SET_PULSE:
+        return pwm_channel_pulse(device, channel, configuration->pulse);
+    default:
+        res = -RT_EINVAL;
+    }
+
+    /* disable PWMX clocking, if all channels are disabled */
+    if ((pwm_device->reg_base->CTRL_MOD.reg & PWM_OUT_EN_MASK) == 0)
+        sys_slp_clk_off0(RB_SLP_CLK_PWMX, SYS_SLP_CLK_OFF);
+
+    return res;
+}
+
+static struct rt_pwm_ops pwm_ops =
+{
+    .control = pwm_control
+};
+
+static int rt_hw_pwm_init(void)
+{
+    /* init pwmx_device with code to save some flash space */
+    pwmx_device.reg_base = (struct pwm_registers *)PWMX_REG_BASE;
+    /* Note: PWM clock OFF here => PWM registers not writable */
+
+    return rt_device_pwm_register(
+           &pwmx_device.parent, PWM_DEVICE_NAME, &pwm_ops, RT_NULL);
+}
+INIT_DEVICE_EXPORT(rt_hw_pwm_init);

+ 103 - 0
bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_pwm.h

@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author            Notes
+ * 2022-08-04     Emuzit            first version
+ */
+#ifndef __CH56X_PWM_H__
+#define __CH56X_PWM_H__
+
+#include "soc.h"
+#include "ch56x_gpio.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PWM_DEVICE_NAME     "pwmx"
+
+#define PWM_CHANNELS        4
+
+#define PWM0_PIN            GET_PIN(B, 15)
+#define PWM1_PIN            GET_PIN(A, 4)
+#define PWM2_PIN            GET_PIN(B, 1)
+#define PWM3_PIN            GET_PIN(B, 2)
+
+union _pwm_ctrl_mod
+{
+    uint8_t reg;
+    struct
+    {
+        uint8_t pwm0_out_en : 1;  // RW, PWM output enable
+        uint8_t pwm1_out_en : 1;
+        uint8_t pwm2_out_en : 1;
+        uint8_t pwm3_out_en : 1;
+        uint8_t pwm0_polar  : 1;  // RW, PWM output polarity
+        uint8_t pwm1_polar  : 1;
+        uint8_t pwm2_polar  : 1;
+        uint8_t pwm3_polar  : 1;
+    };
+};
+#define RB_PWM0_OUT_EN      0x01
+#define RB_PWM1_OUT_EN      0x02
+#define RB_PWM2_OUT_EN      0x04
+#define RB_PWM3_OUT_EN      0x08
+#define RB_PWM0_POLAR       0x10
+#define RB_PWM1_POLAR       0x20
+#define RB_PWM2_POLAR       0x40
+#define RB_PWM3_POLAR       0x80
+
+#define PWM_OUT_EN_MASK     0x0f
+
+union _pwm_ctrl_cfg
+{
+    uint8_t reg;
+    struct
+    {
+        uint8_t cycle_sel   : 1;  // RW, PWM cycle select, 0/1 for 256/255
+        uint8_t resv_1      : 7;
+    };
+};
+#define RB_PWM_CYCLE_SEL    0x01
+
+#define PWM_CYCLE_SEL_256   0
+#define PWM_CYCLE_SEL_255   1
+
+/*
+ * 0x00  R8_PWM_CTRL_MOD:   PWM control register
+ * 0x01  R8_PWM_CTRL_CFG:   PWM control configuration register
+ * 0x02  R8_PWM_CLOCK_DIV:  PWM clock divisor register
+ * 0x04  R8_PWM0_DATA:      PWM0 data holding register
+ * 0x05  R8_PWM1_DATA:      PWM1 data holding register
+ * 0x06  R8_PWM2_DATA:      PWM2 data holding register
+ * 0x07  R8_PWM3_DATA:      PWM3 data holding register
+ */
+struct pwm_registers
+{
+    union _pwm_ctrl_mod     CTRL_MOD;
+    union _pwm_ctrl_cfg     CTRL_CFG;
+    uint8_t                 CLOCK_DIV;
+    uint8_t                 resv_3;
+    union
+    {
+        uint32_t            R32_PWM_DATA;
+        uint8_t             PWM_DATA[4];
+        struct
+        {
+            uint8_t         PWM0_DATA;
+            uint8_t         PWM1_DATA;
+            uint8_t         PWM2_DATA;
+            uint8_t         PWM3_DATA;
+        };
+    };
+};
+CHECK_STRUCT_SIZE(struct pwm_registers, 8);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 26 - 24
bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_spi.c

@@ -164,11 +164,25 @@ static rt_err_t spi_configure(struct rt_spi_device *device, struct rt_spi_config
     return RT_EOK;
 }
 
-static rt_uint32_t _spi_xfer_1(struct rt_spi_device *device, struct rt_spi_message *message)
+/**
+ * @brief   Transfer SPI data for single message.
+ *          Message traversing is done by rt_spi_message().
+ *
+ * @param   device is pointer to the rt_spi_device device.
+ *
+ * @param   message is a link list for data/control information,
+ *          only the first entry is processed.
+ *          Note: ch56x can't do SPI send & recv at the same time.
+ *
+ * @return  `message->length1 if successful, 0 otherwise.
+ */
+static rt_uint32_t spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
 {
     struct spi_bus *spi_bus = (struct spi_bus *)device->bus;
     volatile struct spi_registers *sxreg = spi_bus->reg_base;
 
+    union _spi_ctrl_mod ctrl_mod;
+
     uint8_t *data;
     uint32_t size;
 
@@ -179,22 +193,28 @@ static rt_uint32_t _spi_xfer_1(struct rt_spi_device *device, struct rt_spi_messa
     if (size == 0 || size > 4095)
         return 0;
 
+    ctrl_mod.reg = sxreg->CTRL_MOD.reg | RB_SPI_ALL_CLEAR;
+
     /* ch56x can't do SPI send & recv at the same time */
     if (message->send_buf && !message->recv_buf)
     {
         data = (uint8_t *)message->send_buf;
-        sxreg->CTRL_MOD.fifo_dir = SPI_FIFO_DIR_OUTPUT;
+        ctrl_mod.fifo_dir = SPI_FIFO_DIR_OUTPUT;
     }
     else if (!message->send_buf && message->recv_buf)
     {
         data = (uint8_t *)message->recv_buf;
-        sxreg->CTRL_MOD.fifo_dir = SPI_FIFO_DIR_INPUT;
+        ctrl_mod.fifo_dir = SPI_FIFO_DIR_INPUT;
     }
     else
     {
         return 0;
     }
 
+    sxreg->CTRL_MOD.reg = ctrl_mod.reg;
+    ctrl_mod.all_clear = 0;
+    sxreg->CTRL_MOD.reg = ctrl_mod.reg;
+
     /* set MISO pin direction to match xfer if shared SI/SO pin */
     if (device->config.mode & RT_SPI_3WIRE)
     {
@@ -202,7 +222,7 @@ static rt_uint32_t _spi_xfer_1(struct rt_spi_device *device, struct rt_spi_messa
         rt_pin_mode(spi_bus->miso_pin, mode);
     }
 
-    cs_pin = (rt_base_t)device->user_data;
+    cs_pin = (rt_base_t)device->parent.user_data;
     cs_high = device->config.mode & RT_SPI_CS_HIGH;
 
     if (message->cs_take)
@@ -236,6 +256,8 @@ static rt_uint32_t _spi_xfer_1(struct rt_spi_device *device, struct rt_spi_messa
 
     /* wait for transfer done */
     while (sxreg->TOTAL_COUNT > 0);
+    /* disable DMA, anyway */
+    sxreg->CTRL_CFG.dma_enable = 0;
 
     /* non-DMA recv => read data from FIFO */
     if (size > 0)
@@ -259,26 +281,6 @@ static rt_uint32_t _spi_xfer_1(struct rt_spi_device *device, struct rt_spi_messa
     return message->length;
 }
 
-static rt_uint32_t spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
-{
-    uint32_t total_xsize = 0;
-    uint32_t xsize;
-
-    RT_ASSERT(device != NULL);
-    RT_ASSERT(message != NULL);
-
-    while (message != RT_NULL)
-    {
-        xsize = _spi_xfer_1(device, message);
-        if (xsize != message->length)
-            return 0;
-        total_xsize += xsize;
-        message = message->next;
-    }
-
-    return total_xsize;
-}
-
 static const struct rt_spi_ops spi_ops =
 {
     .configure = spi_configure,

+ 0 - 3
bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_spi.h

@@ -179,9 +179,6 @@ union _spi_int_flag
  * 0x14  R32_SPIx_DMA_NOW:    SPI DMA current address
  * 0x18  R32_SPIx_DMA_BEG:    SPI DMA start address
  * 0x1c  R32_SPIx_DMA_END:    SPI DMA end address
- *
- * CAVEAT: gcc (as of 8.2.0) tends to read 32-bit word for bit field test.
- * Be careful for those with side effect for read (e.g. RBR, IIR).
  */
 struct spi_registers
 {

+ 27 - 18
bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_sys.c

@@ -101,12 +101,15 @@ void sys_slp_clk_off0(uint8_t bits, int off)
     uint8_t u8v;
 
     u8v = sys->SLP_CLK_OFF0.reg;
-    u8v = off ? (u8v | bits) : (u8v & ~bits);
-    level = rt_hw_interrupt_disable();
-    sys_safe_access_enter(sys);
-    sys->SLP_CLK_OFF0.reg = u8v;
-    sys_safe_access_leave(sys);
-    rt_hw_interrupt_enable(level);
+    if ((u8v & bits) != (off ? bits : 0))
+    {
+        u8v = off ? (u8v | bits) : (u8v & ~bits);
+        level = rt_hw_interrupt_disable();
+        sys_safe_access_enter(sys);
+        sys->SLP_CLK_OFF0.reg = u8v;
+        sys_safe_access_leave(sys);
+        rt_hw_interrupt_enable(level);
+    }
 }
 
 /**
@@ -123,12 +126,15 @@ void sys_slp_clk_off1(uint8_t bits, int off)
     uint8_t u8v;
 
     u8v = sys->SLP_CLK_OFF1.reg;
-    u8v = off ? (u8v | bits) : (u8v & ~bits);
-    level = rt_hw_interrupt_disable();
-    sys_safe_access_enter(sys);
-    sys->SLP_CLK_OFF1.reg = u8v;
-    sys_safe_access_leave(sys);
-    rt_hw_interrupt_enable(level);
+    if ((u8v & bits) != (off ? bits : 0))
+    {
+        u8v = off ? (u8v | bits) : (u8v & ~bits);
+        level = rt_hw_interrupt_disable();
+        sys_safe_access_enter(sys);
+        sys->SLP_CLK_OFF1.reg = u8v;
+        sys_safe_access_leave(sys);
+        rt_hw_interrupt_enable(level);
+    }
 }
 
 /**
@@ -171,12 +177,15 @@ int sys_clk_off_by_irqn(uint8_t irqn, int off)
             volatile uint8_t *cxreg = (void *)sys;
             rt_base_t level;
             u8v = cxreg[offset];
-            u8v = off ? (u8v | bitpos) : (u8v & ~bitpos);
-            level = rt_hw_interrupt_disable();
-            sys_safe_access_enter(sys);
-            cxreg[offset] = u8v;
-            sys_safe_access_leave(sys);
-            rt_hw_interrupt_enable(level);
+            if ((u8v & bitpos) != (off ? bitpos : 0))
+            {
+                u8v = off ? (u8v | bitpos) : (u8v & ~bitpos);
+                level = rt_hw_interrupt_disable();
+                sys_safe_access_enter(sys);
+                cxreg[offset] = u8v;
+                sys_safe_access_leave(sys);
+                rt_hw_interrupt_enable(level);
+            }
         }
     }
 

+ 29 - 4
bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_uart.c

@@ -16,6 +16,7 @@
 #else
     #include <drivers/serial.h>
 #endif
+#include <drivers/pin.h>
 #include "ch56x_sys.h"
 #include "ch56x_uart.h"
 #include "isr_sp.h"
@@ -25,11 +26,17 @@
     #error "Please define at least one UARTx"
 #endif
 
+/* Type of irqn/rxd_pin/txd_pin are per uart driver perspective
+ * to save some space, still compatible to RT api call, anyway.
+*/
 struct serial_device
 {
     struct rt_serial_device parent;
     volatile struct uart_registers *reg_base;
-    irq_number_t irqn;
+    uint8_t irqn;
+    uint8_t resv;
+    uint8_t rxd_pin;
+    uint8_t txd_pin;
     char *name;
 };
 
@@ -38,6 +45,8 @@ static struct serial_device serial_device_0 =
 {
     .reg_base = (struct uart_registers *)UART0_REG_BASE,
     .irqn = UART0_IRQn,
+    .rxd_pin = UART_RXD0_PIN,
+    .txd_pin = UART_TXD0_PIN,
     .name = "uart0",
 };
 #endif
@@ -47,6 +56,8 @@ static struct serial_device serial_device_1 =
 {
     .reg_base = (struct uart_registers *)UART1_REG_BASE,
     .irqn = UART1_IRQn,
+    .rxd_pin = UART_RXD1_PIN,
+    .txd_pin = UART_TXD1_PIN,
     .name = "uart1",
 };
 #endif
@@ -56,6 +67,8 @@ static struct serial_device serial_device_2 =
 {
     .reg_base = (struct uart_registers *)UART2_REG_BASE,
     .irqn = UART2_IRQn,
+    .rxd_pin = UART_RXD2_PIN,
+    .txd_pin = UART_TXD2_PIN,
     .name = "uart2",
 };
 #endif
@@ -65,6 +78,8 @@ static struct serial_device serial_device_3 =
 {
     .reg_base = (struct uart_registers *)UART3_REG_BASE,
     .irqn = UART3_IRQn,
+    .rxd_pin = UART_RXD3_PIN,
+    .txd_pin = UART_TXD3_PIN,
     .name = "uart3",
 };
 #endif
@@ -233,15 +248,25 @@ int rt_hw_uart_init(void)
     devices[n++] = &serial_device_0;
 #endif
 
-    /* IMPORTANT: pin mode should be set properly @ board init */
-
     while (--n >= 0)
     {
-        uint32_t flag;
+        uint32_t flag, txd_pin, rxd_pin;
         struct serial_device *serial = devices[n];
         serial->parent.ops = &uart_ops;
         serial->parent.config = config;
 
+        txd_pin = serial->txd_pin;
+        rxd_pin = serial->rxd_pin;
+#ifdef BSP_USING_UART0_PIN_ALT
+        if (serial->irqn == UART0_IRQn)
+        {
+            txd_pin = UART_TXD0_ALT;
+            rxd_pin = UART_RXD0_ALT;
+        }
+#endif
+        rt_pin_mode(txd_pin, PIN_MODE_OUTPUT);
+        rt_pin_mode(rxd_pin, PIN_MODE_INPUT_PULLUP);
+
         sys_clk_off_by_irqn(serial->irqn, SYS_SLP_CLK_ON);
 
         flag = RT_DEVICE_FLAG_RDWR   |

+ 13 - 0
bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_uart.h

@@ -11,11 +11,24 @@
 #define __CH56X_UART_H__
 
 #include "soc.h"
+#include "ch56x_gpio.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+#define UART_RXD0_ALT       GET_PIN(A, 5)
+#define UART_TXD0_ALT       GET_PIN(A, 6)
+
+#define UART_RXD0_PIN       GET_PIN(B, 5)
+#define UART_TXD0_PIN       GET_PIN(B, 6)
+#define UART_RXD1_PIN       GET_PIN(A, 7)
+#define UART_TXD1_PIN       GET_PIN(A, 8)
+#define UART_RXD2_PIN       GET_PIN(A, 2)
+#define UART_TXD2_PIN       GET_PIN(A, 3)
+#define UART_RXD3_PIN       GET_PIN(B, 3)
+#define UART_TXD3_PIN       GET_PIN(B, 4)
+
 #ifndef UART_FIFO_SIZE
 #define UART_FIFO_SIZE      8
 #endif

+ 1 - 0
bsp/wch/risc-v/Libraries/ch56x_drivers/soc.h

@@ -13,6 +13,7 @@
 #include <stdint.h>
 #include <stddef.h>
 #include <assert.h>
+#include <rtdef.h>
 
 #if !defined(SOC_CH567) && \
     !defined(SOC_CH568) && \

+ 8 - 16
bsp/wch/risc-v/ch569w-evt/.config

@@ -110,7 +110,7 @@ CONFIG_RT_USING_SERIAL_V1=y
 # CONFIG_RT_SERIAL_USING_DMA is not set
 CONFIG_RT_SERIAL_RB_BUFSZ=64
 # CONFIG_RT_USING_CAN is not set
-CONFIG_RT_USING_HWTIMER=y
+# CONFIG_RT_USING_HWTIMER is not set
 # CONFIG_RT_USING_CPUTIME is not set
 # CONFIG_RT_USING_I2C is not set
 # CONFIG_RT_USING_PHY is not set
@@ -123,14 +123,8 @@ CONFIG_RT_USING_PIN=y
 # CONFIG_RT_USING_PM is not set
 # CONFIG_RT_USING_RTC is not set
 # CONFIG_RT_USING_SDIO is not set
-CONFIG_RT_USING_SPI=y
-# CONFIG_RT_USING_SPI_BITOPS is not set
-# CONFIG_RT_USING_QSPI is not set
-# CONFIG_RT_USING_SPI_MSD is not set
-# CONFIG_RT_USING_SFUD is not set
-# CONFIG_RT_USING_ENC28J60 is not set
-# CONFIG_RT_USING_SPI_WIFI is not set
-CONFIG_RT_USING_WDT=y
+# CONFIG_RT_USING_SPI is not set
+# CONFIG_RT_USING_WDT is not set
 # CONFIG_RT_USING_AUDIO is not set
 # CONFIG_RT_USING_SENSOR is not set
 # CONFIG_RT_USING_TOUCH is not set
@@ -313,6 +307,7 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8
 # CONFIG_PKG_USING_RAPIDJSON is not set
 # CONFIG_PKG_USING_JSMN is not set
 # CONFIG_PKG_USING_AGILE_JSMN is not set
+# CONFIG_PKG_USING_PARSON is not set
 
 #
 # XML: Extensible Markup Language
@@ -491,8 +486,10 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8
 # CONFIG_PKG_USING_REALTEK_AMEBA is not set
 # CONFIG_PKG_USING_SHT2X is not set
 # CONFIG_PKG_USING_SHT3X is not set
+# CONFIG_PKG_USING_ADT74XX is not set
 # CONFIG_PKG_USING_AS7341 is not set
 # CONFIG_PKG_USING_STM32_SDIO is not set
+# CONFIG_PKG_USING_RTT_ESP_IDF is not set
 # CONFIG_PKG_USING_ICM20608 is not set
 # CONFIG_PKG_USING_BUTTON is not set
 # CONFIG_PKG_USING_PCF8574 is not set
@@ -656,13 +653,8 @@ CONFIG_BSP_USING_UART=y
 CONFIG_BSP_USING_UART1=y
 # CONFIG_BSP_USING_UART2 is not set
 # CONFIG_BSP_USING_UART3 is not set
-CONFIG_BSP_USING_TIMER=y
-CONFIG_BSP_USING_TMR0=y
-CONFIG_BSP_USING_TMR1=y
-# CONFIG_BSP_USING_TMR2 is not set
-CONFIG_BSP_USING_SPI=y
-CONFIG_BSP_USING_SPI0=y
-# CONFIG_BSP_USING_SPI1 is not set
+# CONFIG_BSP_USING_TIMER is not set
+# CONFIG_BSP_USING_SPI is not set
 
 #
 # Onboard Peripheral Drivers

+ 6 - 287
bsp/wch/risc-v/ch569w-evt/applications/main.c

@@ -5,304 +5,23 @@
  *
  * Change Logs:
  * Date           Author            Notes
- * 2022-07-15     Emuzit            first version
- * 2022-07-20     Emuzit            add watchdog test
- * 2022-07-26     Emuzit            add hwtimer test
- * 2022-07-30     Emuzit            add spi master test
+ * 2018-11-27     balanceTWK        first version
  */
 #include <rtthread.h>
-#include <rtdebug.h>
+#include <rtdevice.h>
 #include <drivers/pin.h>
-#include <drivers/watchdog.h>
-#include <drivers/hwtimer.h>
-#include <drivers/spi.h>
 #include "board.h"
 
-static const rt_base_t gpio_int_pins[8] = GPIO_INT_PINS;
-
-/* note : PIN_IRQ_MODE_RISING_FALLING not supported */
-static const uint32_t gpint_mode[] =
-{
-    PIN_IRQ_MODE_RISING,
-    PIN_IRQ_MODE_RISING,
-    PIN_IRQ_MODE_RISING,
-    PIN_IRQ_MODE_RISING,
-    PIN_IRQ_MODE_FALLING,
-    PIN_IRQ_MODE_FALLING,
-    PIN_IRQ_MODE_FALLING,
-    PIN_IRQ_MODE_FALLING,
-};
-
-static struct rt_mailbox *gpint_mb = RT_NULL;
-static struct rt_thread  *gpint_thread = RT_NULL;
-
-static rt_device_t wdg_dev;
-
-static rt_base_t led0, led1;
-
-static void gpio_int_callback(void *pin)
-{
-    led1 = (led1 == PIN_LOW) ? PIN_HIGH : PIN_LOW;
-    rt_pin_write(LED1_PIN, led1);
-
-    if (gpint_mb != RT_NULL)
-    {
-        /* non-block, silently ignore RT_EFULL */
-        rt_mb_send(gpint_mb, (uint32_t)pin);
-    }
-}
-
-static void gpio_int_thread(void *param)
-{
-    while (1)
-    {
-        rt_err_t res;
-        uint32_t pin;
-
-        res = rt_mb_recv(gpint_mb, &pin, RT_WAITING_FOREVER);
-        if (res == RT_EOK)
-        {
-            rt_kprintf("gpio_int #%d (%d)\n", pin, rt_pin_read(pin));
-        }
-        rt_thread_mdelay(100);
-
-#ifdef RT_USING_WDT
-        rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_KEEPALIVE, RT_NULL);
-#endif
-    }
-}
-
-static void test_gpio_int(void)
-{
-    rt_err_t res;
-    int i;
-
-    rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);
-    rt_pin_write(LED1_PIN, led1 = PIN_HIGH);
-
-    /* Enable all gpio interrupt with various modes.
-     * LED0 or GND touching can be used to trigger pin interrupt.
-    */
-    gpint_mb = rt_mb_create("pximb", 8, RT_IPC_FLAG_FIFO);
-    if (gpint_mb == RT_NULL)
-    {
-        rt_kprintf("gpint mailbox create failed !\n");
-    }
-    else
-    {
-        gpint_thread = rt_thread_create("pxith", gpio_int_thread, RT_NULL,
-                                        512, RT_MAIN_THREAD_PRIORITY, 50);
-        if (gpint_thread == RT_NULL)
-        {
-            rt_kprintf("gpint thread create failed !\n");
-        }
-        else
-        {
-            rt_thread_startup(gpint_thread);
-
-            for (i = 0; i < 8; i++)
-            {
-                rt_base_t pin = gpio_int_pins[i];
-                rt_pin_mode(pin, PIN_MODE_INPUT_PULLUP);
-                res = rt_pin_attach_irq(
-                      pin, gpint_mode[i], gpio_int_callback, (void *)pin);
-                if (res != RT_EOK)
-                {
-                    rt_kprintf("rt_pin_attach_irq failed (%d:%d)\n", i, res);
-                }
-                else
-                {
-                    rt_pin_irq_enable(pin, PIN_IRQ_ENABLE);
-                }
-            }
-        }
-    }
-}
-
-#ifdef RT_USING_WDT
-static void test_watchdog(uint32_t seconds)
-{
-    /* Test watchdog with 30s timeout, keepalive with gpio interrupt.
-     *
-     * CAVEAT: With only 8-bit WDOG_COUNT and fixed clocking at Fsys/524288,
-     * watchdog of ch56x may be quite limited with very short timeout.
-    */
-    seconds = 30;
-    wdg_dev = rt_device_find("wdt");
-    if (!wdg_dev)
-    {
-        rt_kprintf("watchdog device not found !\n");
-    }
-    else if (rt_device_init(wdg_dev) != RT_EOK ||
-             rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_SET_TIMEOUT, &seconds) != RT_EOK)
-    {
-        rt_kprintf("watchdog setup failed !\n");
-    }
-    else
-    {
-        rt_kprintf("WDT_TIMEOUT in %d seconds, trigger gpio interrupt to keep alive.\n\n", seconds);
-    }
-}
-#else
-    #define test_watchdog(tov)  do {} while(0)
-#endif
-
-#ifdef RT_USING_HWTIMER
-static struct rt_device *tmr_dev_0;
-static struct rt_device *tmr_dev_1;
-
-static rt_err_t tmr_timeout_cb(rt_device_t dev, rt_size_t size)
-{
-    rt_tick_t tick = rt_tick_get();
-
-    int tmr = (dev == tmr_dev_1) ? 1 : 0;
-
-    rt_kprintf("hwtimer %d timeout callback fucntion @tick %d\n", tmr, tick);
-
-    return RT_EOK;
-}
-
-static void test_hwtimer(void)
-{
-    rt_hwtimerval_t timerval;
-    rt_hwtimer_mode_t mode;
-    rt_size_t tsize;
-
-    /* setup two timers, ONESHOT & PERIOD each
-    */
-    tmr_dev_0 = rt_device_find("timer0");
-    tmr_dev_1 = rt_device_find("timer1");
-    if (tmr_dev_0 == RT_NULL || tmr_dev_1 == RT_NULL)
-    {
-        rt_kprintf("hwtimer device(s) not found !\n");
-    }
-    else if (rt_device_open(tmr_dev_0, RT_DEVICE_OFLAG_RDWR) != RT_EOK ||
-             rt_device_open(tmr_dev_1, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
-    {
-        rt_kprintf("hwtimer device(s) open failed !\n");
-    }
-    else
-    {
-        rt_device_set_rx_indicate(tmr_dev_0, tmr_timeout_cb);
-        rt_device_set_rx_indicate(tmr_dev_1, tmr_timeout_cb);
-
-        timerval.sec = 3;
-        timerval.usec = 500000;
-        tsize = sizeof(timerval);
-        mode = HWTIMER_MODE_ONESHOT;
-        if (rt_device_control(tmr_dev_0, HWTIMER_CTRL_MODE_SET, &mode) != RT_EOK)
-        {
-            rt_kprintf("timer0 set mode failed !\n");
-        }
-        else if (rt_device_write(tmr_dev_0, 0, &timerval, tsize) != tsize)
-        {
-            rt_kprintf("timer0 start failed !\n");
-        }
-        else
-        {
-            rt_kprintf("timer0 started !\n");
-        }
-
-        timerval.sec = 5;
-        timerval.usec = 0;
-        tsize = sizeof(timerval);
-        mode = HWTIMER_MODE_PERIOD;
-        if (rt_device_control(tmr_dev_1, HWTIMER_CTRL_MODE_SET, &mode) != RT_EOK)
-        {
-            rt_kprintf("timer1 set mode failed !\n");
-        }
-        else if (rt_device_write(tmr_dev_1, 0, &timerval, tsize) != tsize)
-        {
-            rt_kprintf("timer1 start failed !\n");
-        }
-        else
-        {
-            rt_kprintf("timer1 started !\n\n");
-        }
-    }
-}
-#else
-    #define test_hwtimer()  do {} while(0)
-#endif
-
-#ifdef RT_USING_SPI
-static struct rt_spi_device spi_dev_w25q;
-
-static void test_spi_master(void)
-{
-    struct rt_spi_configuration cfg;
-    struct rt_spi_message msg1, msg2;
-    rt_err_t res;
-
-    uint8_t buf[16];
-
-    cfg.max_hz = 25 * 1000000;
-    cfg.data_width = 8;
-    cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB | RT_SPI_CS_HIGH;
-
-    res = rt_spi_bus_attach_device(
-          &spi_dev_w25q, W25Q32_SPI_NAME, SPI0_BUS_NAME, (void *)W25Q32_CS_PIN);
-    if (res == RT_EOK && rt_spi_configure(&spi_dev_w25q, &cfg) == RT_EOK)
-    {
-        /* cmd : Read Manufacturer / Device ID (90h) */
-        buf[0] = 0x90;
-        /* address : 0 */
-        buf[1] = buf[2] = buf[3] = 0;
-        msg1.send_buf   = buf;
-        msg1.recv_buf   = RT_NULL;
-        msg1.length     = 4;
-        msg1.cs_take    = 1;
-        msg1.cs_release = 0;
-        msg1.next       = &msg2;
-
-        msg2.send_buf   = RT_NULL;
-        msg2.recv_buf   = buf;
-        msg2.length     = 2;
-        msg2.cs_take    = 0;
-        msg2.cs_release = 1;
-        msg2.next       = RT_NULL;
-
-        rt_spi_transfer_message(&spi_dev_w25q, &msg1);
-        rt_kprintf("use rt_spi_transfer_message() read w25q ID is:%x%x\n", buf[0], buf[1]);
-
-        /* cmd : Read Data (03h)  */
-        buf[0] = 0x03;
-        /* address : 0 */
-        buf[1] = buf[2] = buf[3] = 0;
-        msg2.length = 16;
-        if (rt_spi_transfer_message(&spi_dev_w25q, &msg1) == RT_NULL)
-        {
-            rt_kprintf("rt_spi_transfer_message() 16-byte-read DMA done\n\n");
-        }
-    }
-    else
-    {
-        rt_kprintf("w25q32 attach/configure failed (%d) !\n", res);
-    }
-}
-#else
-    #define test_spi_master()  do {} while(0)
-#endif
-
 void main(void)
 {
-    uint32_t wdog_timeout = 32;
-
-    rt_kprintf("\nCH569W-R0-1v0, HCLK: %dMHz\n\n", sys_hclk_get() / 1000000);
-
-    test_gpio_int();
-    test_watchdog(wdog_timeout);
-    test_hwtimer();
-    test_spi_master();
-
+    /* set LED0 pin mode to output */
     rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
-    rt_pin_write(LED0_PIN, led0 = PIN_LOW);
 
     while (1)
     {
-        /* flashing LED0 every 1 second */
+        rt_pin_write(LED0_PIN, PIN_HIGH);
+        rt_thread_mdelay(500);
+        rt_pin_write(LED0_PIN, PIN_LOW);
         rt_thread_mdelay(500);
-        led0 = (led0 == PIN_LOW) ? PIN_HIGH : PIN_LOW;
-        rt_pin_write(LED0_PIN, led0);
     }
 }

+ 386 - 0
bsp/wch/risc-v/ch569w-evt/applications/test.c

@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author            Notes
+ * 2022-07-15     Emuzit            first version
+ * 2022-07-20     Emuzit            add watchdog test
+ * 2022-07-26     Emuzit            add hwtimer test
+ * 2022-07-30     Emuzit            add spi master test
+ * 2022-08-04     Emuzit            add pwm test
+ */
+#include <rtthread.h>
+#include <rtdebug.h>
+#include <drivers/pin.h>
+#include <drivers/watchdog.h>
+#include <drivers/hwtimer.h>
+#include <drivers/spi.h>
+#include <drivers/rt_drv_pwm.h>
+#include "board.h"
+
+#define PWM_CYCLE_MAX   255
+
+static const rt_base_t gpio_int_pins[8] = GPIO_INT_PINS;
+
+/* note : PIN_IRQ_MODE_RISING_FALLING not supported */
+static const uint32_t gpint_mode[] =
+{
+    PIN_IRQ_MODE_RISING,
+    PIN_IRQ_MODE_RISING,
+    PIN_IRQ_MODE_RISING,
+    PIN_IRQ_MODE_RISING,
+    PIN_IRQ_MODE_FALLING,
+    PIN_IRQ_MODE_FALLING,
+    PIN_IRQ_MODE_FALLING,
+    PIN_IRQ_MODE_FALLING,
+};
+
+static struct rt_mailbox *gpint_mb = RT_NULL;
+static struct rt_thread  *gpint_thread = RT_NULL;
+
+static rt_device_t wdg_dev;
+
+static rt_base_t led0, led1;
+
+static void gpio_int_callback(void *pin)
+{
+    led1 = (led1 == PIN_LOW) ? PIN_HIGH : PIN_LOW;
+    rt_pin_write(LED1_PIN, led1);
+
+    if (gpint_mb != RT_NULL)
+    {
+        /* non-block, silently ignore RT_EFULL */
+        rt_mb_send(gpint_mb, (uint32_t)pin);
+    }
+}
+
+static void gpio_int_thread(void *param)
+{
+    while (1)
+    {
+        rt_err_t res;
+        uint32_t pin;
+
+        res = rt_mb_recv(gpint_mb, &pin, RT_WAITING_FOREVER);
+        if (res == RT_EOK)
+        {
+            rt_kprintf("gpio_int #%d (%d)\n", pin, rt_pin_read(pin));
+        }
+        rt_thread_mdelay(100);
+
+#ifdef RT_USING_WDT
+        rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_KEEPALIVE, RT_NULL);
+#endif
+    }
+}
+
+static void test_gpio_int(void)
+{
+    rt_err_t res;
+    int i;
+
+    rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);
+    rt_pin_write(LED1_PIN, led1 = PIN_HIGH);
+
+    /* Enable all gpio interrupt with various modes.
+     * LED0 or GND touching can be used to trigger pin interrupt.
+    */
+    gpint_mb = rt_mb_create("pximb", 8, RT_IPC_FLAG_FIFO);
+    if (gpint_mb == RT_NULL)
+    {
+        rt_kprintf("gpint mailbox create failed !\n");
+    }
+    else
+    {
+        gpint_thread = rt_thread_create("pxith", gpio_int_thread, RT_NULL,
+                                        512, RT_MAIN_THREAD_PRIORITY, 50);
+        if (gpint_thread == RT_NULL)
+        {
+            rt_kprintf("gpint thread create failed !\n");
+        }
+        else
+        {
+            rt_thread_startup(gpint_thread);
+
+            for (i = 0; i < 8; i++)
+            {
+                rt_base_t pin = gpio_int_pins[i];
+#ifdef RT_USING_PWM
+                if (pin == PWM0_PIN || pin == PWM1_PIN)
+                    continue;
+#endif
+                rt_pin_mode(pin, PIN_MODE_INPUT_PULLUP);
+                res = rt_pin_attach_irq(
+                      pin, gpint_mode[i], gpio_int_callback, (void *)pin);
+                if (res != RT_EOK)
+                {
+                    rt_kprintf("rt_pin_attach_irq failed (%d:%d)\n", i, res);
+                }
+                else
+                {
+                    rt_pin_irq_enable(pin, PIN_IRQ_ENABLE);
+                }
+            }
+        }
+    }
+}
+
+#ifdef RT_USING_WDT
+static void test_watchdog(uint32_t seconds)
+{
+    /* Test watchdog with 30s timeout, keepalive with gpio interrupt.
+     *
+     * CAVEAT: With only 8-bit WDOG_COUNT and fixed clocking at Fsys/524288,
+     * watchdog of ch56x may be quite limited with very short timeout.
+    */
+    seconds = 30;
+    wdg_dev = rt_device_find("wdt");
+    if (!wdg_dev)
+    {
+        rt_kprintf("watchdog device not found !\n");
+    }
+    else if (rt_device_init(wdg_dev) != RT_EOK ||
+             rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_SET_TIMEOUT, &seconds) != RT_EOK)
+    {
+        rt_kprintf("watchdog setup failed !\n");
+    }
+    else
+    {
+        rt_kprintf("WDT_TIMEOUT in %d seconds, trigger gpio interrupt to keep alive.\n\n", seconds);
+    }
+}
+#else
+    #define test_watchdog(tov)  do {} while(0)
+#endif
+
+#ifdef RT_USING_HWTIMER
+static struct rt_device *tmr_dev_0;
+static struct rt_device *tmr_dev_1;
+
+static rt_err_t tmr_timeout_cb(rt_device_t dev, rt_size_t size)
+{
+    rt_tick_t tick = rt_tick_get();
+
+    int tmr = (dev == tmr_dev_1) ? 1 : 0;
+
+    rt_kprintf("hwtimer %d timeout callback fucntion @tick %d\n", tmr, tick);
+
+    return RT_EOK;
+}
+
+static void test_hwtimer(void)
+{
+    rt_hwtimerval_t timerval;
+    rt_hwtimer_mode_t mode;
+    rt_size_t tsize;
+
+    /* setup two timers, ONESHOT & PERIOD each
+    */
+    tmr_dev_0 = rt_device_find("timer0");
+    tmr_dev_1 = rt_device_find("timer1");
+    if (tmr_dev_0 == RT_NULL || tmr_dev_1 == RT_NULL)
+    {
+        rt_kprintf("hwtimer device(s) not found !\n");
+    }
+    else if (rt_device_open(tmr_dev_0, RT_DEVICE_OFLAG_RDWR) != RT_EOK ||
+             rt_device_open(tmr_dev_1, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
+    {
+        rt_kprintf("hwtimer device(s) open failed !\n");
+    }
+    else
+    {
+        rt_device_set_rx_indicate(tmr_dev_0, tmr_timeout_cb);
+        rt_device_set_rx_indicate(tmr_dev_1, tmr_timeout_cb);
+
+        timerval.sec = 3;
+        timerval.usec = 500000;
+        tsize = sizeof(timerval);
+        mode = HWTIMER_MODE_ONESHOT;
+        if (rt_device_control(tmr_dev_0, HWTIMER_CTRL_MODE_SET, &mode) != RT_EOK)
+        {
+            rt_kprintf("timer0 set mode failed !\n");
+        }
+        else if (rt_device_write(tmr_dev_0, 0, &timerval, tsize) != tsize)
+        {
+            rt_kprintf("timer0 start failed !\n");
+        }
+        else
+        {
+            rt_kprintf("timer0 started !\n");
+        }
+
+        timerval.sec = 5;
+        timerval.usec = 0;
+        tsize = sizeof(timerval);
+        mode = HWTIMER_MODE_PERIOD;
+        if (rt_device_control(tmr_dev_1, HWTIMER_CTRL_MODE_SET, &mode) != RT_EOK)
+        {
+            rt_kprintf("timer1 set mode failed !\n");
+        }
+        else if (rt_device_write(tmr_dev_1, 0, &timerval, tsize) != tsize)
+        {
+            rt_kprintf("timer1 start failed !\n");
+        }
+        else
+        {
+            rt_kprintf("timer1 started !\n\n");
+        }
+    }
+}
+#else
+    #define test_hwtimer()  do {} while(0)
+#endif
+
+#ifdef RT_USING_SPI
+static struct rt_spi_device spi_dev_w25q;
+
+static void test_spi_master(void)
+{
+    struct rt_spi_configuration cfg;
+    struct rt_spi_message msg1, msg2;
+    rt_err_t res;
+
+    uint8_t buf[16];
+    int i;
+
+    cfg.max_hz = 25 * 1000000;
+    cfg.data_width = 8;
+    cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;
+
+    res = rt_spi_bus_attach_device(
+          &spi_dev_w25q, W25Q32_SPI_NAME, SPI0_BUS_NAME, (void *)W25Q32_CS_PIN);
+    if (res == RT_EOK && rt_spi_configure(&spi_dev_w25q, &cfg) == RT_EOK)
+    {
+        /* cmd : Read Manufacturer / Device ID (90h) */
+        buf[0] = 0x90;
+        /* address : 0 */
+        buf[1] = buf[2] = buf[3] = 0;
+        msg1.send_buf   = buf;
+        msg1.recv_buf   = RT_NULL;
+        msg1.length     = 4;
+        msg1.cs_take    = 1;
+        msg1.cs_release = 0;
+        msg1.next       = &msg2;
+
+        msg2.send_buf   = RT_NULL;
+        msg2.recv_buf   = buf;
+        msg2.length     = 2;
+        msg2.cs_take    = 0;
+        msg2.cs_release = 1;
+        msg2.next       = RT_NULL;
+
+        rt_spi_transfer_message(&spi_dev_w25q, &msg1);
+        rt_kprintf("use rt_spi_transfer_message() read w25q ID is:%x%x\n", buf[0], buf[1]);
+
+        /* cmd : Read Data (03h)  */
+        buf[0] = 0x03;
+        /* address : 0 */
+        buf[1] = buf[2] = buf[3] = 0;
+        msg2.length = 16;
+        if (rt_spi_transfer_message(&spi_dev_w25q, &msg1) == RT_NULL)
+        {
+            rt_kprintf("SPI0 16-byte DMA read :");
+            for (i = 0; i < 16; i++)
+                rt_kprintf(" %02x", buf[i]);
+            rt_kprintf("\n\n");
+        }
+    }
+    else
+    {
+        rt_kprintf("w25q32 attach/configure failed (%d) !\n", res);
+    }
+}
+#else
+    #define test_spi_master()  do {} while(0)
+#endif
+
+#ifdef RT_USING_PWM
+static struct rt_device_pwm *pwm_dev;
+static uint32_t pwm_period;
+
+rt_err_t rt_pwm_get(struct rt_device_pwm *device,
+                    struct rt_pwm_configuration *cfg);
+
+static void pwm_tick_hook(void)
+{
+    uint32_t pulse;
+
+    if (pwm_dev)
+    {
+        /* PWM.CH3 duty cycle : 0%->100% for every ~2.5 seconds */
+        pulse = (rt_tick_get() >> 1) % (PWM_CYCLE_MAX + 1);
+        pulse = (pwm_period * pulse + PWM_CYCLE_MAX/2) / PWM_CYCLE_MAX;
+        rt_pwm_set_pulse(pwm_dev, 3, pulse);
+    }
+}
+
+static void test_pwm(void)
+{
+    struct rt_pwm_configuration cfg;
+    uint32_t pulse[4];
+    int ch;
+
+    pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEVICE_NAME);
+    if (pwm_dev == RT_NULL)
+    {
+        rt_kprintf("can't find %s device !\n", PWM_DEVICE_NAME);
+    }
+    else
+    {
+        /* for HCLK@80MHz, allowed period is 3187 ~ 812812 */
+        pwm_period = 800*1000;
+
+        pulse[0] = 100*1000;
+        pulse[1] = 400*1000;
+        pulse[2] = 600*1000;
+        pulse[3] = 0;
+
+        for (ch = 0; ch < PWM_CHANNELS; ch++)
+        {
+            rt_pwm_set(pwm_dev, ch, pwm_period, pulse[ch]);
+            rt_pwm_enable(pwm_dev, ch);
+
+            cfg.channel = ch;
+            rt_pwm_get(pwm_dev, &cfg);
+            rt_kprintf("pwm%d period set/get : %d/%d\n", ch, pwm_period, cfg.period);
+            rt_kprintf("pwm%d pulse  set/get : %d/%d\n\n", ch, pulse[ch], cfg.pulse);
+        }
+
+        /* disable PWM.CH0 after 1 second, also start changing CH3 */
+        rt_thread_mdelay(1000);
+        rt_pwm_disable(pwm_dev, 0);
+
+        /* connect PWM3 (PB.2) to LED2 for a visualized PWM effect */
+        rt_pin_mode(LED2_PIN, PIN_MODE_INPUT);
+        rt_tick_sethook(pwm_tick_hook);
+    }
+}
+#else
+    #define test_pwm()  do {} while(0)
+#endif
+
+void main(void)
+{
+    uint32_t wdog_timeout = 32;
+
+    rt_kprintf("\nCH569W-R0-1v0, HCLK: %dMHz\n\n", sys_hclk_get() / 1000000);
+
+    test_gpio_int();
+    test_watchdog(wdog_timeout);
+    test_hwtimer();
+    test_spi_master();
+    test_pwm();
+
+    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
+    rt_pin_write(LED0_PIN, led0 = PIN_LOW);
+
+    while (1)
+    {
+        /* flashing LED0 every 1 second */
+        rt_thread_mdelay(500);
+        led0 = (led0 == PIN_LOW) ? PIN_HIGH : PIN_LOW;
+        rt_pin_write(LED0_PIN, led0);
+    }
+}

+ 19 - 14
bsp/wch/risc-v/ch569w-evt/board/Kconfig

@@ -17,20 +17,25 @@ config BSP_USING_UART
 
     if BSP_USING_UART
         config BSP_USING_UART0
-        bool "using UART0"
-        default n
+            bool "using UART0"
+            default n
+            if BSP_USING_UART0
+                config BSP_USING_UART0_PIN_ALT
+                    bool "UART0 PIN_ALTERNATE (PA5/PA6)"
+                    default n
+            endif
 
         config BSP_USING_UART1
-        bool "using UART1"
-        default y
+            bool "using UART1"
+            default y
 
         config BSP_USING_UART2
-        bool "using UART2"
-        default n
+            bool "using UART2"
+            default n
 
         config BSP_USING_UART3
-        bool "using UART3"
-        default n
+            bool "using UART3"
+            default n
     endif
 
 config BSP_USING_TIMER
@@ -40,16 +45,16 @@ config BSP_USING_TIMER
 
     if BSP_USING_TIMER
         config BSP_USING_TMR0
-        bool "using TMR0"
-        default y
+            bool "using TMR0"
+            default n
 
         config BSP_USING_TMR1
-        bool "using TMR1"
-        default n
+            bool "using TMR1"
+            default n
 
         config BSP_USING_TMR2
-        bool "using TMR2"
-        default n
+            bool "using TMR2"
+            default n
     endif
 
 config BSP_USING_SPI

+ 0 - 3
bsp/wch/risc-v/ch569w-evt/board/board.c

@@ -69,9 +69,6 @@ void rt_hw_board_init()
 #endif
 
 #ifdef RT_USING_CONSOLE
-    /* console is uart1, TXD1/RXD1 : PA8/PA7 */
-    rt_pin_mode(GET_PIN(A, 8), PIN_MODE_OUTPUT);
-    rt_pin_mode(GET_PIN(A, 7), PIN_MODE_INPUT_PULLUP);
     rt_hw_uart_init();
     rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
 #endif

+ 1 - 0
bsp/wch/risc-v/ch569w-evt/board/board.h

@@ -14,6 +14,7 @@
 #include "ch56x_sys.h"
 #include "ch56x_gpio.h"
 #include "ch56x_spi.h"
+#include "ch56x_pwm.h"
 
 #define LED0_PIN            GET_PIN(B, 24)
 #define LED1_PIN            GET_PIN(B, 22)

+ 0 - 8
bsp/wch/risc-v/ch569w-evt/rtconfig.h

@@ -70,10 +70,7 @@
 #define RT_USING_SERIAL
 #define RT_USING_SERIAL_V1
 #define RT_SERIAL_RB_BUFSZ 64
-#define RT_USING_HWTIMER
 #define RT_USING_PIN
-#define RT_USING_SPI
-#define RT_USING_WDT
 
 /* Using USB */
 
@@ -181,11 +178,6 @@
 
 #define BSP_USING_UART
 #define BSP_USING_UART1
-#define BSP_USING_TIMER
-#define BSP_USING_TMR0
-#define BSP_USING_TMR1
-#define BSP_USING_SPI
-#define BSP_USING_SPI0
 
 /* Onboard Peripheral Drivers */