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>
This commit is contained in:
parent
58c4f41ac7
commit
a881c05e58
|
@ -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']
|
||||
|
||||
|
|
|
@ -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 <rthw.h>
|
||||
#include <rtdebug.h>
|
||||
#include <drivers/spi.h>
|
||||
#include <drivers/pin.h>
|
||||
#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);
|
|
@ -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
|
|
@ -11,6 +11,8 @@
|
|||
#include <rtdebug.h>
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <rtthread.h>
|
||||
#include <rtdebug.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;
|
||||
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -13,11 +13,15 @@
|
|||
#include <stdint.h>
|
||||
#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
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in New Issue