From a881c05e58abec97e906cb613cee528ec5a4d9cc Mon Sep 17 00:00:00 2001 From: emuzit <98307908+emuzit@users.noreply.github.com> Date: Tue, 2 Aug 2022 10:36:49 +0800 Subject: [PATCH] ch569w-evt : add spi master driver, SPI0 tested (#6205) * ch569w-evt : add spi master driver, SPI0 tested * Update bsp/wch/risc-v/ch569w-evt/board/Kconfig * Update bsp/wch/risc-v/ch569w-evt/board/Kconfig Co-authored-by: Man, Jianting (Meco) <920369182@qq.com> --- .../risc-v/Libraries/ch56x_drivers/SConscript | 3 + .../Libraries/ch56x_drivers/ch56x_spi.c | 318 ++++++++++++++++++ .../Libraries/ch56x_drivers/ch56x_spi.h | 218 ++++++++++++ .../Libraries/ch56x_drivers/ch56x_sys.c | 27 +- .../Libraries/ch56x_drivers/ch56x_sys.h | 1 + .../Libraries/ch56x_drivers/ch56x_timer.c | 4 + bsp/wch/risc-v/ch569w-evt/.config | 11 +- bsp/wch/risc-v/ch569w-evt/applications/main.c | 133 ++++++-- bsp/wch/risc-v/ch569w-evt/board/Kconfig | 15 + bsp/wch/risc-v/ch569w-evt/board/board.h | 4 + bsp/wch/risc-v/ch569w-evt/rtconfig.h | 3 + 11 files changed, 704 insertions(+), 33 deletions(-) create mode 100644 bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_spi.c create mode 100644 bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_spi.h diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/SConscript b/bsp/wch/risc-v/Libraries/ch56x_drivers/SConscript index f936f62ceb..7b79db221a 100644 --- a/bsp/wch/risc-v/Libraries/ch56x_drivers/SConscript +++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/SConscript @@ -15,6 +15,9 @@ if GetDepend('SOC_SERIES_CH569'): if GetDepend('RT_USING_HWTIMER'): src += ['ch56x_timer.c'] +if GetDepend('RT_USING_SPI'): + src += ['ch56x_spi.c'] + if GetDepend('RT_USING_PIN'): src += ['ch56x_gpio.c'] diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_spi.c b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_spi.c new file mode 100644 index 0000000000..49cfa330a7 --- /dev/null +++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_spi.c @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-07-30 Emuzit first version + */ +#include +#include +#include +#include +#include "ch56x_spi.h" +#include "ch56x_sys.h" + +#if !defined(BSP_USING_SPI0) && !defined(BSP_USING_SPI1) + #error "Please define at least one SPIx" +#endif + +struct spi_bus +{ + struct rt_spi_bus parent; + volatile struct spi_registers *reg_base; + irq_number_t irqn; + char *name; + rt_base_t sck_pin; + rt_base_t mosi_pin; + rt_base_t miso_pin; +}; + +#ifdef BSP_USING_SPI0 +static struct spi_bus spi_bus_0 = +{ + .reg_base = (struct spi_registers *)SPI0_REG_BASE, + .irqn = SPI0_IRQn, + .name = SPI0_BUS_NAME, + .sck_pin = SPI0_SCK_PIN, + .mosi_pin = SPI0_MOSI_PIN, + .miso_pin = SPI0_MISO_PIN, +}; +#endif +#ifdef BSP_USING_SPI1 +static struct spi_bus spi_bus_1 = +{ + .reg_base = (struct spi_registers *)SPI1_REG_BASE, + .irqn = SPI1_IRQn, + .name = SPI1_BUS_NAME, + .sck_pin = SPI1_SCK_PIN, + .mosi_pin = SPI1_MOSI_PIN, + .miso_pin = SPI1_MISO_PIN, +}; +#endif + +static uint8_t _spi_pin_config(struct rt_spi_device *device, struct rt_spi_configuration *config) +{ + struct spi_bus *spi_bus = (struct spi_bus *)device->bus; + + uint8_t mode; + + /* RT_SPI_3WIRE means SI/SO pin shared */ + mode = config->mode & (RT_SPI_MASTER | RT_SPI_SLAVE | RT_SPI_3WIRE); + if (mode == RT_SPI_MASTER) + { + mode = RB_SPI_MOSI_OE | RB_SPI_SCK_OE; + rt_pin_mode(spi_bus->mosi_pin, PIN_MODE_OUTPUT); + rt_pin_mode(spi_bus->sck_pin, PIN_MODE_OUTPUT); + } + else if (mode == RT_SPI_SLAVE) + { + mode = RB_SPI_MISO_OE | RB_SPI_MODE_SLAVE; + rt_pin_mode(spi_bus->miso_pin, PIN_MODE_OUTPUT); + } + else if (mode == RT_SPI_MASTER | RT_SPI_3WIRE) + { + mode = RB_SPI_2WIRE_MOD | RB_SPI_MISO_OE | RB_SPI_SCK_OE; + rt_pin_mode(spi_bus->miso_pin, PIN_MODE_INPUT); + rt_pin_mode(spi_bus->sck_pin, PIN_MODE_OUTPUT); + } + else + { + mode = RB_SPI_2WIRE_MOD | RB_SPI_MISO_OE | RB_SPI_MODE_SLAVE; + rt_pin_mode(spi_bus->miso_pin, PIN_MODE_INPUT); + } + + return mode; +} + +static rt_err_t spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *config) +{ + volatile struct spi_registers *sxreg; + struct rt_spi_device *owner; + + union _spi_ctrl_mod ctrl_mod; + uint8_t mode; + uint32_t Fsys; + uint32_t div; + + rt_base_t cs_pin; + int inactive; + + RT_ASSERT(device != RT_NULL); + + /* ch56x SPI supports only 8-bit data */ + if (config->data_width != 8) + return -RT_EINVAL; + + ctrl_mod.reg = _spi_pin_config(device, config); + + /* ch56x SPI supports only mode 0 & mode 3 */ + mode = config->mode & (RT_SPI_CPOL | RT_SPI_CPHA); + if (mode == RT_SPI_MODE_0) + ctrl_mod.mst_sck_mod = MST_SCK_MOD_0; + else if (mode == RT_SPI_MODE_3) + ctrl_mod.mst_sck_mod = MST_SCK_MOD_3; + else + return -RT_EINVAL; + + /* CLOCK_DIV is 8-bit, reject excessively low max_hz */ + Fsys = sys_hclk_get(); + if (config->max_hz < Fsys / 255) + return -RT_EINVAL; + + /* minimum allowable CLOCK_DIV is 2 */ + div = (Fsys + config->max_hz - 1) / config->max_hz; + if (div < 2) + div = 2; + + sxreg = ((struct spi_bus *)device->bus)->reg_base; + sxreg->CLOCK_DIV = div; + + mode = config->mode & (RT_SPI_MSB | RT_SPI_LSB); + sxreg->CTRL_CFG.reg = (mode == RT_SPI_MSB) ? 0 : RB_SPI_BIT_ORDER; + sxreg->INTER_EN.reg = 0; + + ctrl_mod.all_clear = 1; + sxreg->CTRL_MOD.reg = ctrl_mod.reg; + ctrl_mod.all_clear = 0; + sxreg->CTRL_MOD.reg = ctrl_mod.reg; + + mode = config->mode & (RT_SPI_MASTER | RT_SPI_SLAVE); + if (mode == RT_SPI_MASTER) + { + /* get bus owner before this configure */ + owner = device->bus->owner; + if (owner && owner != device) + { + /* make sure predecessor's CS is deactived */ + inactive = (owner->config.mode & RT_SPI_CS_HIGH) ? PIN_LOW : PIN_HIGH; + cs_pin = (rt_base_t)owner->parent.user_data; + rt_pin_write(cs_pin, inactive); + } + /* bus owner is maintained by upper layer, do not update here */ + + inactive = (config->mode & RT_SPI_CS_HIGH) ? PIN_LOW : PIN_HIGH; + cs_pin = (rt_base_t)device->parent.user_data; + rt_pin_write(cs_pin, inactive); + rt_pin_mode(cs_pin, PIN_MODE_OUTPUT); + } + + /* `config` is actually `device->config` : spi_core.c */ + //device->config = *config; + + return RT_EOK; +} + +static rt_uint32_t _spi_xfer_1(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; + + uint8_t *data; + uint32_t size; + + rt_base_t cs_pin; + int cs_high; + + size = message->length; + if (size == 0 || size > 4095) + return 0; + + /* 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; + } + else if (!message->send_buf && message->recv_buf) + { + data = (uint8_t *)message->recv_buf; + sxreg->CTRL_MOD.fifo_dir = SPI_FIFO_DIR_INPUT; + } + else + { + return 0; + } + + /* set MISO pin direction to match xfer if shared SI/SO pin */ + if (device->config.mode & RT_SPI_3WIRE) + { + rt_base_t mode = message->send_buf ? PIN_MODE_OUTPUT : PIN_MODE_INPUT; + rt_pin_mode(spi_bus->miso_pin, mode); + } + + cs_pin = (rt_base_t)device->user_data; + cs_high = device->config.mode & RT_SPI_CS_HIGH; + + if (message->cs_take) + { + /* take/activate CS */ + rt_pin_write(cs_pin, cs_high ? PIN_HIGH : PIN_LOW); + } + + sxreg->TOTAL_COUNT = size; + + if (size > SPI_FIFO_SIZE) + { + sxreg->DMA_BIG = (uint32_t)data; + sxreg->DMA_END = (uint32_t)(data + size); + sxreg->CTRL_CFG.dma_enable = 1; + /* mark no need to read FIFO */ + size = 0; + } + else + { + if (message->send_buf) + { + /* keep sending, won't overflow */ + while (size) + { + sxreg->FIFO = *data++; + size--; + } + } + } + + /* wait for transfer done */ + while (sxreg->TOTAL_COUNT > 0); + + /* non-DMA recv => read data from FIFO */ + if (size > 0) + { + while (size--) + *data++ = sxreg->FIFO; + } + + /* set MISO as input after xfer if shared SI/SO pin */ + if (device->config.mode & RT_SPI_3WIRE) + { + rt_pin_mode(spi_bus->miso_pin, PIN_MODE_INPUT); + } + + if (message->cs_release) + { + /* release/deactivate CS */ + rt_pin_write(cs_pin, cs_high ? PIN_LOW : PIN_HIGH); + } + + 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, + .xfer = spi_xfer, +}; + +static int rt_hw_spi_init(void) +{ + struct spi_bus *devices[2]; + + rt_err_t res, ret = RT_EOK; + + int n = 0; + +#ifdef BSP_USING_SPI1 + devices[n++] = &spi_bus_1; +#endif +#ifdef BSP_USING_SPI0 + devices[n++] = &spi_bus_0; +#endif + + while (--n >= 0) + { + struct spi_bus *spi_bus = devices[n]; + + sys_clk_off_by_irqn(spi_bus->irqn, SYS_SLP_CLK_ON); + + res = rt_spi_bus_register(&spi_bus->parent, spi_bus->name, &spi_ops); + if (res != RT_EOK) + { + ret = res; + } + }; + + return ret; +} +INIT_DEVICE_EXPORT(rt_hw_spi_init); diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_spi.h b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_spi.h new file mode 100644 index 0000000000..dbceff7b89 --- /dev/null +++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_spi.h @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-07-30 Emuzit first version + */ +#ifndef __CH56X_SPI_H__ +#define __CH56X_SPI_H__ + +#include "soc.h" +#include "ch56x_gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SPI0_BUS_NAME "spi0" +#define SPI1_BUS_NAME "spi1" + +#ifndef SPI0_SCS_PIN +#define SPI0_SCS_PIN GET_PIN(A, 12) +#endif +#define SPI0_SCK_PIN GET_PIN(A, 13) +#define SPI0_MOSI_PIN GET_PIN(A, 14) +#define SPI0_MISO_PIN GET_PIN(A, 15) + +#ifdef SOC_SERIES_CH569 +#ifndef SPI1_SCS_PIN +#define SPI1_SCS_PIN GET_PIN(B, 11) +#endif +#define SPI1_SCK_PIN GET_PIN(B, 12) +#define SPI1_MOSI_PIN GET_PIN(B, 13) +#define SPI1_MISO_PIN GET_PIN(B, 14) + +#else +#define SPI1_SCK_PIN GET_PIN(A, 0) +#define SPI1_MOSI_PIN GET_PIN(A, 1) +#define SPI1_MISO_PIN GET_PIN(A, 2) +#endif + +#define SPI_FIFO_SIZE 8 + +union _spi_ctrl_mod +{ + uint8_t reg; + struct + { + uint8_t mode_slave : 1; // RW, SPI master/slave (0/1) mode select + uint8_t all_clear : 1; // RW, clear FIFO/count/int-flag + uint8_t two_wire : 1; // RW, 2/3-wire mode (0/1), SPI slave + uint8_t mst_sck_mod : 1; // RW, mode0/mode3 (0/1) for SCK idle L/H + uint8_t fifo_dir : 1; // RW, FIFO direction is output/input (0/1) + uint8_t sck_oe : 1; // RW, SCK pin output enable + uint8_t mosi_oe : 1; // RW, MOSI pin output enable + uint8_t miso_oe : 1; // RW, MISO pin output enable + }; + struct + { + uint8_t stuff_0 : 3; + uint8_t slv_cmd_mod : 1; // RW, 1st byte is data/cmd (0/1), SPI slave + uint8_t stuff_4 : 4; + }; +}; +#define RB_SPI_MODE_SLAVE 0x01 +#define RB_SPI_ALL_CLEAR 0x02 +#define RB_SPI_2WIRE_MOD 0x04 +#define RB_SPI_MST_SCK_MOD 0x08 +#define RB_SPI_SLV_CMD_MOD 0x08 +#define RB_SPI_FIFO_DIR 0x10 +#define RB_SPI_SCK_OE 0x20 +#define RB_SPI_MOSI_OE 0x40 +#define RB_SPI_MISO_OE 0x80 + +#define MST_SCK_MOD_0 0 +#define MST_SCK_MOD_3 1 + +#define SPI_FIFO_DIR_OUTPUT 0 +#define SPI_FIFO_DIR_INPUT 1 + +union _spi_ctrl_cfg +{ + uint8_t reg; + struct + { + uint8_t dma_enable : 1; // RW, enable DMA function + uint8_t resv_1 : 1; + uint8_t dma_loop : 1; // RW, enable DMA loop mode (0 => single) + uint8_t resv_3 : 1; + uint8_t auto_if : 1; // RW, enable auto clear RB_SPI_IF_BYTE_END + uint8_t bit_order : 1; // RW, data bit ordering, LSB/MSB first (0/1) + uint8_t resv_6 : 2; + }; +}; +#define RB_SPI_DMA_ENABLE 0x01 +#define RB_SPI_DMA_LOOP 0x04 +#define RB_SPI_AUTO_IF 0x10 +#define RB_SPI_BIT_ORDER 0x20 + +#define SPI_BIT_ORDER_MSB 0 +#define SPI_BIT_ORDER_LSB 1 + +union _spi_inter_en +{ + uint8_t reg; + struct + { + uint8_t cnt_end : 1; // RW, IE for all bytes transfered + uint8_t byte_end : 1; // RW, IE for single byte transfered + uint8_t fifo_hf : 1; // RW, IE for FIFO half full + uint8_t dma_end : 1; // RW, IE for end of DMA + uint8_t fifo_ov : 1; // RW, IE for FIFO full or empty + uint8_t resv_5 : 2; + uint8_t fst_byte : 1; // RW, IE for 1st byte received, SPI slave + }; +}; +#define RB_SPI_IE_CNT_END 0x01 +#define RB_SPI_IE_BYTE_END 0x02 +#define RB_SPI_IE_FIFO_HF 0x04 +#define RB_SPI_IE_DMA_END 0x08 +#define RB_SPI_IE_FIFO_OV 0x10 +#define RB_SPI_IE_FST_BYTE 0x80 + +union _spi_run_flag +{ + uint8_t reg; + struct + { + uint8_t resv_0 : 4; + uint8_t slv_cmd_act : 1; // RO, SPI slave cmd received + uint8_t fifo_ready : 1; // RO, SPI FIFO ready to transfer + uint8_t slv_cs_load : 1; // RO, SPI slave is loading R8_SPIx_SLAVE_PRE + uint8_t slv_select : 1; // RO, SPI slave CS active (selected) + }; +}; +#define RB_SPI_SLV_CMD_ACT 0x10 +#define RB_SPI_FIFO_READY 0x20 +#define RB_SPI_SLV_CS_LOAD 0x40 +#define RB_SPI_SLV_SELECT 0x80 + +union _spi_int_flag +{ + uint8_t reg; + struct + { + uint8_t cnt_end : 1; // RW1, IF for all bytes transfered + uint8_t byte_end : 1; // RW1, IF for single byte transfered + uint8_t fifo_hf : 1; // RW1, IF for FIFO half full + uint8_t dma_end : 1; // RW1, IF for end of DMA + uint8_t fifo_ov : 1; // RW1, IF for FIFO full or empty + uint8_t resv_5 : 1; + uint8_t free : 1; // RO, current SPI state is free + uint8_t fst_byte : 1; // RW1, IF for 1st byte received, SPI slave + }; +}; +#define RB_SPI_IF_CNT_END 0x01 +#define RB_SPI_IF_BYTE_END 0x02 +#define RB_SPI_IF_FIFO_HF 0x04 +#define RB_SPI_IF_DMA_END 0x08 +#define RB_SPI_IF_FIFO_OV 0x10 +#define RB_SPI_FREE 0x40 +#define RB_SPI_IF_FST_BYTE 0x80 + +/* + * 0x00 R8_SPIx_CTRL_MOD: SPI mode setting register + * 0x01 R8_SPIx_CTRL_CFG: SPI configuration register + * 0x02 R8_SPIx_INTER_EN: SPI interrupt enable register + * 0x03 R8_SPIx_CLOCK_DIV: SPI master clock divisor, minimum 2 + * 0x03 R8_SPIx_SLAVE_PRE: SPI slave preset data (reset as 10h) + * 0x04 R8_SPIx_BUFFER: SPI data buffer + * 0x05 R8_SPIx_RUN_FLAG: SPI working state register + * 0x06 R8_SPIx_INT_FLAG: SPI interrupt flags register + * 0x07 R8_SPIx_FIFO_COUNT: SPI FIFO data count + * 0x0c R16_SPIx_TOTAL_CNT: SPI total data length to transfer + * 0x10 R8_SPIx_FIFO: SPI FIFO + * 0x13 R8_SPIx_FIFO_COUNT1: SPI FIFO data count + * 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 +{ + union _spi_ctrl_mod CTRL_MOD; + union _spi_ctrl_cfg CTRL_CFG; + union _spi_inter_en INTER_EN; + union + { + uint8_t CLOCK_DIV; + uint8_t SLAVE_PRE; + }; + uint8_t BUFFER; + union _spi_run_flag RUN_FLAG; + union _spi_int_flag INT_FLAG; + uint8_t FIFO_COUNT; + uint32_t resv_8; + uint16_t TOTAL_COUNT; + uint16_t resv_0e; + uint8_t FIFO; + uint8_t resv_11[2]; + uint8_t FIFO_COUNT1; + uint32_t DMA_NOW; + uint32_t DMA_BIG; + uint32_t DMA_END; +}; +CHECK_STRUCT_SIZE(struct spi_registers, 0x20); + +rt_err_t spi_cs_pin_assign(int spi_n, rt_base_t cs_pin); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_sys.c b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_sys.c index 51305e4a51..899f173aed 100644 --- a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_sys.c +++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_sys.c @@ -11,6 +11,8 @@ #include #include "ch56x_sys.h" +static uint32_t hclk_freq; + rt_inline uint8_t _slp_clk_off0_irqn_bit(uint8_t irqn) { uint8_t bitpos; @@ -221,6 +223,8 @@ int sys_hclk_set(uint32_t freq) sys->CLK_CFG_CTRL.reg = clk_cfg_ctrl_wdat(clksel); sys_safe_access_leave(sys); rt_hw_interrupt_enable(level); + /* save to hclk_freq for quick report */ + sys_hclk_calc(); clksel = 0; } @@ -228,11 +232,24 @@ int sys_hclk_set(uint32_t freq) } /** - * @brief Get current HCLK frequency. + * @brief Get saved HCLK frequency. + * + * Valid only if HCLK is set strickly with sys_hclk_set(). + * Use sys_hclk_calc() otherwise. + * + * @return Returns saved HCLK frequency (Hz, 0 if not set yet). + */ +uint32_t sys_hclk_get(void) +{ + return hclk_freq; +} + +/** + * @brief Get current HCLK frequency, calculated from hw setting. * * @return Returns current HCLK frequency (Hz). */ -uint32_t sys_hclk_get(void) +uint32_t sys_hclk_calc(void) { volatile struct sys_registers *sys = (void *)SYS_REG_BASE; @@ -240,10 +257,12 @@ uint32_t sys_hclk_get(void) if (sys->CLK_CFG_CTRL.sel_pll == CLK_SEL_PLL_USB_480M) { - return plldiv ? 480000000 / plldiv : 30000000; + hclk_freq = plldiv ? 480000000 / plldiv : 30000000; } else { - return plldiv ? 30000000 / plldiv : 2000000; + hclk_freq = plldiv ? 30000000 / plldiv : 2000000; } + + return hclk_freq; } diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_sys.h b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_sys.h index 9b2b7b3e54..9405f3c062 100644 --- a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_sys.h +++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_sys.h @@ -382,6 +382,7 @@ struct sys_registers CHECK_STRUCT_SIZE(struct sys_registers, 0x28); +uint32_t sys_hclk_calc(void); uint32_t sys_hclk_get(void); int sys_hclk_set(uint32_t freq); int sys_clk_off_by_irqn(uint8_t irqn, int off); diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_timer.c b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_timer.c index be388386c6..a420e53b4d 100644 --- a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_timer.c +++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_timer.c @@ -14,6 +14,10 @@ #include "ch56x_timer.h" #include "isr_sp.h" +#if !defined(BSP_USING_TMR0) && !defined(BSP_USING_TMR1) && !defined(BSP_USING_TMR2) + #error "Please define at least one TMRx" +#endif + struct hwtimer_device { struct rt_hwtimer_device parent; diff --git a/bsp/wch/risc-v/ch569w-evt/.config b/bsp/wch/risc-v/ch569w-evt/.config index cb3bcbf285..7512b2f132 100644 --- a/bsp/wch/risc-v/ch569w-evt/.config +++ b/bsp/wch/risc-v/ch569w-evt/.config @@ -123,7 +123,13 @@ 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 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_AUDIO is not set # CONFIG_RT_USING_SENSOR is not set @@ -654,6 +660,9 @@ 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 # # Onboard Peripheral Drivers diff --git a/bsp/wch/risc-v/ch569w-evt/applications/main.c b/bsp/wch/risc-v/ch569w-evt/applications/main.c index 3c126ce04f..7716789025 100644 --- a/bsp/wch/risc-v/ch569w-evt/applications/main.c +++ b/bsp/wch/risc-v/ch569w-evt/applications/main.c @@ -8,12 +8,14 @@ * 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 */ #include #include #include #include #include +#include #include "board.h" static const rt_base_t gpio_int_pins[8] = GPIO_INT_PINS; @@ -34,12 +36,9 @@ static const uint32_t gpint_mode[] = static struct rt_mailbox *gpint_mb = RT_NULL; static struct rt_thread *gpint_thread = RT_NULL; -static rt_base_t led0, led1; - static rt_device_t wdg_dev; -static struct rt_device *tmr_dev_0; -static struct rt_device *tmr_dev_1; +static rt_base_t led0, led1; static void gpio_int_callback(void *pin) { @@ -73,31 +72,13 @@ static void gpio_int_thread(void *param) } } -#ifdef RT_USING_HWTIMER -static rt_err_t tmr_timeout_cb(rt_device_t dev, rt_size_t size) +static void test_gpio_int(void) { - 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; -} -#endif - -void main(void) -{ - rt_hwtimerval_t timerval; - rt_hwtimer_mode_t mode; - rt_size_t tsize; - - uint32_t seconds; rt_err_t res; - int i; - rt_kprintf("\nCH569W-R0-1v0, HCLK: %dMHz\n\n", sys_hclk_get() / 1000000); + 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. @@ -136,8 +117,11 @@ void main(void) } } } +} #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, @@ -158,9 +142,32 @@ void main(void) { 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"); @@ -210,13 +217,83 @@ void main(void) } else { - rt_kprintf("timer1 started !\n"); + rt_kprintf("timer1 started !\n\n"); } } +} +#else + #define test_hwtimer() do {} while(0) #endif - rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT); - rt_pin_write(LED1_PIN, led1 = PIN_HIGH); +#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(); rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT); rt_pin_write(LED0_PIN, led0 = PIN_LOW); diff --git a/bsp/wch/risc-v/ch569w-evt/board/Kconfig b/bsp/wch/risc-v/ch569w-evt/board/Kconfig index 80a2613d03..c760c1338b 100644 --- a/bsp/wch/risc-v/ch569w-evt/board/Kconfig +++ b/bsp/wch/risc-v/ch569w-evt/board/Kconfig @@ -51,6 +51,21 @@ config BSP_USING_TIMER bool "using TMR2" default n endif + +config BSP_USING_SPI + bool "using on-chip spi" + select RT_USING_SPI + default n + + if BSP_USING_SPI + config BSP_USING_SPI0 + bool "using SPI0" + default n + + config BSP_USING_SPI1 + bool "using SPI1" + default n + endif endmenu menu "Onboard Peripheral Drivers" diff --git a/bsp/wch/risc-v/ch569w-evt/board/board.h b/bsp/wch/risc-v/ch569w-evt/board/board.h index 631352203c..08a5c5b9d2 100644 --- a/bsp/wch/risc-v/ch569w-evt/board/board.h +++ b/bsp/wch/risc-v/ch569w-evt/board/board.h @@ -13,11 +13,15 @@ #include #include "ch56x_sys.h" #include "ch56x_gpio.h" +#include "ch56x_spi.h" #define LED0_PIN GET_PIN(B, 24) #define LED1_PIN GET_PIN(B, 22) #define LED2_PIN GET_PIN(B, 23) +#define W25Q32_CS_PIN GET_PIN(A, 12) +#define W25Q32_SPI_NAME "spi00" + #define SYS_HCLK_FREQ 80000000 // 80 MHz #define RAMX_SIZE 32 // USER_MEM 00/01/1x : 32/64/96 KB diff --git a/bsp/wch/risc-v/ch569w-evt/rtconfig.h b/bsp/wch/risc-v/ch569w-evt/rtconfig.h index 99bad3ce80..acf5ce234f 100644 --- a/bsp/wch/risc-v/ch569w-evt/rtconfig.h +++ b/bsp/wch/risc-v/ch569w-evt/rtconfig.h @@ -72,6 +72,7 @@ #define RT_SERIAL_RB_BUFSZ 64 #define RT_USING_HWTIMER #define RT_USING_PIN +#define RT_USING_SPI #define RT_USING_WDT /* Using USB */ @@ -183,6 +184,8 @@ #define BSP_USING_TIMER #define BSP_USING_TMR0 #define BSP_USING_TMR1 +#define BSP_USING_SPI +#define BSP_USING_SPI0 /* Onboard Peripheral Drivers */