|
| 1 | +/***************************************************************************//** |
| 2 | + * @file drv_tick.cpp |
| 3 | + * @brief Arduino RT-Thread library RISC-V tick driver |
| 4 | + * @author onelife <onelife.real[at]gmail.com> |
| 5 | + ******************************************************************************/ |
| 6 | +#include "components/drivers/include/rtdevice.h" |
| 7 | + |
| 8 | +#if defined(BOARD_SIPEED_LONGAN_NANO) && CONFIG_USING_DRIVER_SPI |
| 9 | + |
| 10 | +#include "bsp/bsp.h" |
| 11 | + |
| 12 | +#if !CONFIG_USING_SPI0 && !CONFIG_USING_SPI1 |
| 13 | +# error "No CONFIG_USING_SPIx enabled" |
| 14 | +#endif |
| 15 | + |
| 16 | +/***************************************************************************//** |
| 17 | + * @addtogroup LonganNano |
| 18 | + * @{ |
| 19 | + ******************************************************************************/ |
| 20 | + |
| 21 | +/* Private define ------------------------------------------------------------*/ |
| 22 | +#ifdef RT_USING_ULOG |
| 23 | +# ifdef BSP_SPI_DEBUG |
| 24 | +# define LOG_LVL LOG_LVL_DBG |
| 25 | +# else |
| 26 | +# define LOG_LVL LOG_LVL_INFO |
| 27 | +# endif |
| 28 | +# define LOG_TAG "SPI" |
| 29 | +# include "components/utilities/ulog/ulog.h" |
| 30 | +#else /* RT_USING_ULOG */ |
| 31 | +# define LOG_E(format, args...) rt_kprintf(format "\n", ##args) |
| 32 | +# define LOG_W LOG_E |
| 33 | +# ifdef BSP_SPI_DEBUG |
| 34 | +# define LOG_I(format, args...) rt_kprintf(format "\n", ##args) |
| 35 | +# else |
| 36 | +# define LOG_I(format, args...) |
| 37 | +# endif |
| 38 | +# define LOG_D LOG_I |
| 39 | +# define LOG_HEX(format, args...) |
| 40 | +#endif /* RT_USING_ULOG */ |
| 41 | + |
| 42 | +/* Private typedef -----------------------------------------------------------*/ |
| 43 | +struct bsp_spi_contex { |
| 44 | + char *name; |
| 45 | + rcu_clock_freq_enum clk_src; |
| 46 | + rt_uint32_t chn; |
| 47 | + rt_uint32_t spi_base; |
| 48 | + rt_uint32_t spi_clk; |
| 49 | + rt_uint32_t gpio_clk; |
| 50 | + rt_uint32_t gpio_port; |
| 51 | + rt_uint32_t mosi_pin; |
| 52 | + rt_uint32_t miso_pin; |
| 53 | + rt_uint32_t sck_pin; |
| 54 | + rt_uint32_t cs_pin; |
| 55 | + // IRQn_Type irq; |
| 56 | +}; |
| 57 | + |
| 58 | +enum bsp_spi_channel { |
| 59 | + #if CONFIG_USING_SPI0 |
| 60 | + SPI_CH0 = 0, |
| 61 | + #endif |
| 62 | + #if CONFIG_USING_SPI1 |
| 63 | + SPI_CH1 = 1, |
| 64 | + #endif |
| 65 | + SPI_CH_NUM = CONFIG_USING_SPI0 + CONFIG_USING_SPI1, |
| 66 | +}; |
| 67 | + |
| 68 | +/* Private function prototypes -----------------------------------------------*/ |
| 69 | +static rt_err_t op_configure(struct rt_spi_device* dev, |
| 70 | + struct rt_spi_configuration* cfg); |
| 71 | +static rt_uint32_t op_xfer(struct rt_spi_device* dev, |
| 72 | + struct rt_spi_message* msg); |
| 73 | + |
| 74 | +/* Private constants ---------------------------------------------------------*/ |
| 75 | + |
| 76 | +/* Private variables ---------------------------------------------------------*/ |
| 77 | +static struct rt_spi_bus spi_dev[SPI_CH_NUM]; |
| 78 | + |
| 79 | +static struct bsp_spi_contex spi_ctx[SPI_CH_NUM] = { |
| 80 | + #if CONFIG_USING_SPI0 |
| 81 | + { |
| 82 | + "SPI0", |
| 83 | + CK_APB2, |
| 84 | + SPI_CH0, |
| 85 | + SPI0, |
| 86 | + RCU_SPI0, |
| 87 | + RCU_GPIOA, |
| 88 | + GPIOA, |
| 89 | + GPIO_PIN_7, |
| 90 | + GPIO_PIN_6, |
| 91 | + GPIO_PIN_5, |
| 92 | + GPIO_PIN_4, |
| 93 | + }, |
| 94 | + #endif |
| 95 | + #if CONFIG_USING_SPI1 |
| 96 | + { |
| 97 | + "SPI1", |
| 98 | + CK_APB1, |
| 99 | + SPI_CH1, |
| 100 | + SPI1, |
| 101 | + RCU_SPI1, |
| 102 | + RCU_GPIOB, |
| 103 | + GPIOB, |
| 104 | + GPIO_PIN_15, |
| 105 | + GPIO_PIN_14, |
| 106 | + GPIO_PIN_13, |
| 107 | + GPIO_PIN_12, |
| 108 | + }, |
| 109 | + #endif |
| 110 | +}; |
| 111 | + |
| 112 | +static struct rt_spi_ops spi_ops = { |
| 113 | + op_configure, |
| 114 | + op_xfer, |
| 115 | +}; |
| 116 | + |
| 117 | +/* Private functions ---------------------------------------------------------*/ |
| 118 | +static rt_err_t op_configure(struct rt_spi_device* dev, |
| 119 | + struct rt_spi_configuration* cfg) { |
| 120 | + struct bsp_spi_contex *ctx; |
| 121 | + spi_parameter_struct init; |
| 122 | + rt_uint32_t clk; |
| 123 | + |
| 124 | + RT_ASSERT(dev != RT_NULL); |
| 125 | + RT_ASSERT(cfg != RT_NULL); |
| 126 | + ctx = (struct bsp_spi_contex *)dev->bus->parent.user_data |
| 127 | + RT_ASSERT(ctx != RT_NULL); |
| 128 | + LOG_D("[SPI%d] op_configure", ctx->chn); |
| 129 | + |
| 130 | + spi_i2s_deinit(ctx->spi_base); |
| 131 | + |
| 132 | + /* NOTE: currently only support master mode */ |
| 133 | + init.device_mode = SPI_MASTER; |
| 134 | + |
| 135 | + if (cfg->mode & RT_SPI_3WIRE) { |
| 136 | + init.trans_mode = SPI_TRANSMODE_BDTRANSMIT; |
| 137 | + } else { |
| 138 | + init.trans_mode = SPI_TRANSMODE_FULLDUPLEX; |
| 139 | + } |
| 140 | + |
| 141 | + if (cfg->data_width <= 8) { |
| 142 | + init.frame_size = SPI_FRAMESIZE_8BIT; |
| 143 | + } else if(cfg->data_width <= 16) { |
| 144 | + init.frame_size = SPI_FRAMESIZE_16BIT; |
| 145 | + } else { |
| 146 | + LOG_W("[SPI%d E] data_width (%d)", ctx->chn, cfg->data_width); |
| 147 | + return RT_EINVAL; |
| 148 | + } |
| 149 | + |
| 150 | + /* NOTE: currently only support software CS */ |
| 151 | + init.nss = SPI_NSS_SOFT; |
| 152 | + |
| 153 | + if (cfg->mode & RT_SPI_MSB) { |
| 154 | + init.endian = SPI_ENDIAN_MSB; |
| 155 | + } else { |
| 156 | + init.endian = SPI_ENDIAN_LSB; |
| 157 | + } |
| 158 | + |
| 159 | + switch (cfg->mode & (RT_SPI_CPOL | RT_SPI_CPHA)) { |
| 160 | + case RT_SPI_MODE_0: |
| 161 | + init.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE; |
| 162 | + break; |
| 163 | + case RT_SPI_MODE_1: |
| 164 | + init.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE; |
| 165 | + break; |
| 166 | + case RT_SPI_MODE_2: |
| 167 | + init.clock_polarity_phase = SPI_CK_PL_HIGH_PH_1EDGE; |
| 168 | + break; |
| 169 | + case RT_SPI_MODE_3: |
| 170 | + init.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE; |
| 171 | + break; |
| 172 | + default: |
| 173 | + break; |
| 174 | + } |
| 175 | + |
| 176 | + if (0 == ctx->chn) { |
| 177 | + clk = rcu_clock_freq_get(CK_APB2); |
| 178 | + } else { |
| 179 | + clk = rcu_clock_freq_get(CK_APB1); |
| 180 | + } |
| 181 | + LOG_D("[SPI%d] APB freq: %7d\n", ctx->chn, clk); |
| 182 | + LOG_D("[SPI%d] MAX freq: %7d\n", ctx->chn, cfg->max_hz); |
| 183 | + if (cfg->max_hz >= clk >> 1) { |
| 184 | + init.prescale = SPI_PSC_2; |
| 185 | + } else if (cfg->max_hz >= clk >> 2) { |
| 186 | + init.prescale = SPI_PSC_4; |
| 187 | + } else if (cfg->max_hz >= clk >> 3) { |
| 188 | + init.prescale = SPI_PSC_8; |
| 189 | + } else if (cfg->max_hz >= clk >> 4) { |
| 190 | + init.prescale = SPI_PSC_16; |
| 191 | + } else if (cfg->max_hz >= clk >> 5) { |
| 192 | + init.prescale = SPI_PSC_32; |
| 193 | + } else if (cfg->max_hz >= clk >> 6) { |
| 194 | + init.prescale = SPI_PSC_64; |
| 195 | + } else if (cfg->max_hz >= clk >> 7) { |
| 196 | + init.prescale = SPI_PSC_128; |
| 197 | + } else { |
| 198 | + init.prescale = SPI_PSC_256; |
| 199 | + } |
| 200 | + |
| 201 | + spi_init(ctx->spi_base, &init); |
| 202 | + spi_crc_off(ctx->spi_base); |
| 203 | + spi_enable(ctx->spi_base); |
| 204 | + |
| 205 | + return RT_EOK; |
| 206 | +}; |
| 207 | + |
| 208 | +static rt_uint32_t op_xfer(struct rt_spi_device* dev, |
| 209 | + struct rt_spi_message* msg) { |
| 210 | + struct bsp_spi_contex *ctx; |
| 211 | + struct rt_spi_configuration *cfg; |
| 212 | + rt_uint8_t mode3 = 0; |
| 213 | + rt_uint32_t i; |
| 214 | + const rt_uint16_t dummy = 0xffff; |
| 215 | + |
| 216 | + RT_ASSERT(dev != NULL); |
| 217 | + RT_ASSERT(msg != NULL); |
| 218 | + ctx = (struct bsp_spi_contex *)dev->bus->parent.user_data; |
| 219 | + cfg = &dev->config; |
| 220 | + |
| 221 | + if (RT_NULL != msg->send_buf) { |
| 222 | + if (cfg->mode & RT_SPI_3WIRE) { |
| 223 | + spi_bidirectional_transfer_config(ctx->spi_base, |
| 224 | + SPI_BIDIRECTIONAL_TRANSMIT); |
| 225 | + mode3 = 1; |
| 226 | + LOG_D("[SPI%d] 3TX (%d)", ctx->chn, msg->length); |
| 227 | + } else { |
| 228 | + LOG_D("[SPI%d] TX (%d)", ctx->chn, msg->length); |
| 229 | + } |
| 230 | + } |
| 231 | + if (RT_NULL != msg->recv_buf) { |
| 232 | + if ((mode3 == 0) && (cfg->mode & RT_SPI_3WIRE)) { |
| 233 | + spi_bidirectional_transfer_config(ctx->spi_base, |
| 234 | + SPI_BIDIRECTIONAL_RECEIVE); |
| 235 | + mode3 = 2; |
| 236 | + LOG_D("[SPI%d] 3RX (%d)", ctx->chn, msg->length); |
| 237 | + } else { |
| 238 | + LOG_D("[SPI%d] RX (%d)", ctx->chn, msg->length); |
| 239 | + } |
| 240 | + } |
| 241 | + |
| 242 | + if (msg->cs_take) { |
| 243 | + LOG_D("[SPI%d] CS enable", ctx->chn); |
| 244 | + gpio_bit_reset(ctx->gpio_port, ctx->cs_pin); |
| 245 | + } |
| 246 | + |
| 247 | + for (i = 0; i < msg->length; i++) { |
| 248 | + if (2 != mode3) { |
| 249 | + while (RESET == spi_i2s_flag_get(ctx->spi_base, SPI_FLAG_TBE)) { |
| 250 | + asm volatile ("nop"); |
| 251 | + } |
| 252 | + if (RT_NULL == msg->send_buf) { |
| 253 | + spi_i2s_data_transmit(ctx->spi_base, dummy); |
| 254 | + } else if (cfg->data_width <= 8) { |
| 255 | + spi_i2s_data_transmit(ctx->spi_base, |
| 256 | + (rt_uint16_t)((rt_uint8_t *)msg->send_buf)[i]); |
| 257 | + } else { |
| 258 | + spi_i2s_data_transmit(ctx->spi_base, |
| 259 | + ((rt_uint16_t *)msg->send_buf)[i]); |
| 260 | + } |
| 261 | + } |
| 262 | + |
| 263 | + if (1 != mode3) { |
| 264 | + while (RESET == spi_i2s_flag_get(ctx->spi_base, SPI_FLAG_RBNE)) { |
| 265 | + asm volatile ("nop"); |
| 266 | + } |
| 267 | + if (RT_NULL == msg->recv_buf) { |
| 268 | + (void)spi_i2s_data_receive(ctx->spi_base); |
| 269 | + } else if (cfg->data_width <= 8) { |
| 270 | + ((rt_uint8_t *)msg->recv_buf)[i] = (rt_uint8_t)spi_i2s_data_receive(ctx->spi_base); |
| 271 | + } else { |
| 272 | + ((rt_uint16_t *)msg->recv_buf)[i] = spi_i2s_data_receive(ctx->spi_base); |
| 273 | + } |
| 274 | + } |
| 275 | + } |
| 276 | + |
| 277 | + if (msg->cs_release) { |
| 278 | + LOG_D("[SPI%d] CS disable", ctx->chn); |
| 279 | + gpio_bit_set(ctx->gpio_port, ctx->cs_pin); |
| 280 | + } |
| 281 | + |
| 282 | + return msg->length; |
| 283 | +}; |
| 284 | + |
| 285 | +/* Public functions ----------------------------------------------------------*/ |
| 286 | +rt_err_t bsp_hw_spi_init(void) { |
| 287 | + uint8_t i; |
| 288 | + rt_err_t ret; |
| 289 | + |
| 290 | + ret = RT_ERROR; |
| 291 | + for (i = 0; i < SPI_CH_NUM; i++) { |
| 292 | + /* enable clock */ |
| 293 | + rcu_periph_clock_enable(spi_ctx[i].gpio_clk); |
| 294 | + rcu_periph_clock_enable(spi_ctx[i].spi_clk); |
| 295 | + /* setup GPIO */ |
| 296 | + gpio_init(spi_ctx[i].gpio_port, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, |
| 297 | + spi_ctx[i].mosi_pin | spi_ctx[i].miso_pin | spi_ctx[i].sck_pin); |
| 298 | + gpio_init(spi_ctx[i].gpio_port, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, |
| 299 | + spi_ctx[i].cs_pin); |
| 300 | + /* register device */ |
| 301 | + spi_dev[i].parent.user_data = (void *)&spi_ctx[i]; |
| 302 | + ret = rt_spi_bus_register( |
| 303 | + &spi_dev[i], |
| 304 | + spi_ctx[i].name, |
| 305 | + &spi_ops); |
| 306 | + RT_ASSERT(ret == RT_EOK); |
| 307 | + LOG_D("[SPI%d] h/w init ok", spi_ctx[i].chn); |
| 308 | + } |
| 309 | + |
| 310 | + return ret; |
| 311 | +} |
| 312 | +INIT_BOARD_EXPORT(bsp_hw_spi_init); |
| 313 | + |
| 314 | +/***************************************************************************//** |
| 315 | + * @} |
| 316 | + ******************************************************************************/ |
| 317 | + |
| 318 | +#endif /* defined(BOARD_SIPEED_LONGAN_NANO) && CONFIG_USING_DRIVER_SPI */ |
0 commit comments