/* * Copyright (c) 2006-2022, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2022-06-04 BruceOu first implementation */ #include "drv_spi.h" #ifdef RT_USING_SPI #if defined(BSP_USING_SPI0) || defined(BSP_USING_SPI1) || defined(BSP_USING_SPI2) #define LOG_TAG "drv.spi" #include #ifdef BSP_USING_SPI0 static struct rt_spi_bus spi_bus0; #endif #ifdef BSP_USING_SPI1 static struct rt_spi_bus spi_bus1; #endif #ifdef BSP_USING_SPI2 static struct rt_spi_bus spi_bus2; #endif static const struct gd32_spi spi_bus_obj[] = { #ifdef BSP_USING_SPI0 { SPI0, "spi0", RCU_SPI0, RCU_GPIOA, &spi_bus0, GPIOA, GPIO_PIN_5, GPIO_PIN_6, GPIO_PIN_7, } #endif /* BSP_USING_SPI0 */ #ifdef BSP_USING_SPI1 { SPI1, "spi1", RCU_SPI1, RCU_GPIOB, &spi_bus1, GPIOB, GPIO_PIN_12, GPIO_PIN_14, GPIO_PIN_15, } #endif /* BSP_USING_SPI1 */ #ifdef BSP_USING_SPI2 { SPI2, "spi2", RCU_SPI2, RCU_GPIOB, &spi_bus2, GPIOB, GPIO_PIN_3, GPIO_PIN_4, GPIO_PIN_5, } #endif /* BSP_USING_SPI2 */ }; /* private rt-thread spi ops function */ static rt_err_t spi_configure(struct rt_spi_device* device, struct rt_spi_configuration* configuration); static rt_uint32_t spixfer(struct rt_spi_device* device, struct rt_spi_message* message); static struct rt_spi_ops gd32_spi_ops = { .configure = spi_configure, .xfer = spixfer, }; /** * @brief SPI Initialization * @param gd32_spi: SPI BUS * @retval None */ static void gd32_spi_init(struct gd32_spi *gd32_spi) { /* enable SPI clock */ rcu_periph_clock_enable(gd32_spi->spi_clk); rcu_periph_clock_enable(gd32_spi->gpio_clk); /* Init SPI SCK MOSI */ gpio_init(gd32_spi->spi_port, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, gd32_spi->sck_pin | gd32_spi->mosi_pin); /* Init SPI MISO */ gpio_init(gd32_spi->spi_port, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, gd32_spi->miso_pin); } static rt_err_t spi_configure(struct rt_spi_device* device, struct rt_spi_configuration* configuration) { struct rt_spi_bus * spi_bus = (struct rt_spi_bus *)device->bus; struct gd32_spi *spi_device = (struct gd32_spi *)spi_bus->parent.user_data; spi_parameter_struct spi_init_struct; uint32_t spi_periph = spi_device->spi_periph; RT_ASSERT(device != RT_NULL); RT_ASSERT(configuration != RT_NULL); //Init SPI gd32_spi_init(spi_device); /* data_width */ if(configuration->data_width <= 8) { spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT; } else if(configuration->data_width <= 16) { spi_init_struct.frame_size = SPI_FRAMESIZE_16BIT; } else { return RT_EIO; } /* baudrate */ { rcu_clock_freq_enum spi_src; uint32_t spi_apb_clock; uint32_t max_hz; max_hz = configuration->max_hz; LOG_D("sys freq: %d\n", rcu_clock_freq_get(CK_SYS)); LOG_D("CK_APB2 freq: %d\n", rcu_clock_freq_get(CK_APB2)); LOG_D("max freq: %d\n", max_hz); if (spi_periph == SPI1 || spi_periph == SPI2) { spi_src = CK_APB1; } else { spi_src = CK_APB2; } spi_apb_clock = rcu_clock_freq_get(spi_src); if(max_hz >= spi_apb_clock/2) { spi_init_struct.prescale = SPI_PSC_2; } else if (max_hz >= spi_apb_clock/4) { spi_init_struct.prescale = SPI_PSC_4; } else if (max_hz >= spi_apb_clock/8) { spi_init_struct.prescale = SPI_PSC_8; } else if (max_hz >= spi_apb_clock/16) { spi_init_struct.prescale = SPI_PSC_16; } else if (max_hz >= spi_apb_clock/32) { spi_init_struct.prescale = SPI_PSC_32; } else if (max_hz >= spi_apb_clock/64) { spi_init_struct.prescale = SPI_PSC_64; } else if (max_hz >= spi_apb_clock/128) { spi_init_struct.prescale = SPI_PSC_128; } else { /* min prescaler 256 */ spi_init_struct.prescale = SPI_PSC_256; } } /* baudrate */ switch(configuration->mode & RT_SPI_MODE_3) { case RT_SPI_MODE_0: spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE; break; case RT_SPI_MODE_1: spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE; break; case RT_SPI_MODE_2: spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_1EDGE; break; case RT_SPI_MODE_3: spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE; break; } /* MSB or LSB */ if(configuration->mode & RT_SPI_MSB) { spi_init_struct.endian = SPI_ENDIAN_MSB; } else { spi_init_struct.endian = SPI_ENDIAN_LSB; } spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX; spi_init_struct.device_mode = SPI_MASTER; spi_init_struct.nss = SPI_NSS_SOFT; spi_crc_off(spi_periph); /* init SPI */ spi_init(spi_periph, &spi_init_struct); /* Enable SPI_MASTER */ spi_enable(spi_periph); return RT_EOK; }; static rt_uint32_t spixfer(struct rt_spi_device* device, struct rt_spi_message* message) { struct rt_spi_bus * gd32_spi_bus = (struct rt_spi_bus *)device->bus; struct gd32_spi *spi_device = (struct gd32_spi *)gd32_spi_bus->parent.user_data; struct rt_spi_configuration * config = &device->config; struct gd32_spi_cs * gd32_spi_cs = device->parent.user_data; uint32_t spi_periph = spi_device->spi_periph; RT_ASSERT(device != NULL); RT_ASSERT(message != NULL); /* take CS */ if(message->cs_take) { gpio_bit_reset(gd32_spi_cs->GPIOx, gd32_spi_cs->GPIO_Pin); LOG_D("spi take cs\n"); } { if(config->data_width <= 8) { const rt_uint8_t * send_ptr = message->send_buf; rt_uint8_t * recv_ptr = message->recv_buf; rt_uint32_t size = message->length; LOG_D("spi poll transfer start: %d\n", size); while(size--) { rt_uint8_t data = 0xFF; if(send_ptr != RT_NULL) { data = *send_ptr++; } // Todo: replace register read/write by gd32f4 lib //Wait until the transmit buffer is empty while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE)); // Send the byte spi_i2s_data_transmit(spi_periph, data); //Wait until a data is received while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE)); // Get the received data data = spi_i2s_data_receive(spi_periph); if(recv_ptr != RT_NULL) { *recv_ptr++ = data; } } LOG_D("spi poll transfer finsh\n"); } else if(config->data_width <= 16) { const rt_uint16_t * send_ptr = message->send_buf; rt_uint16_t * recv_ptr = message->recv_buf; rt_uint32_t size = message->length; while(size--) { rt_uint16_t data = 0xFF; if(send_ptr != RT_NULL) { data = *send_ptr++; } //Wait until the transmit buffer is empty while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE)); // Send the byte spi_i2s_data_transmit(spi_periph, data); //Wait until a data is received while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE)); // Get the received data data = spi_i2s_data_receive(spi_periph); if(recv_ptr != RT_NULL) { *recv_ptr++ = data; } } } } /* release CS */ if(message->cs_release) { gpio_bit_set(gd32_spi_cs->GPIOx, gd32_spi_cs->GPIO_Pin); LOG_D("spi release cs\n"); } return message->length; }; int rt_hw_spi_init(void) { int result = 0; int i; for (i = 0; i < sizeof(spi_bus_obj) / sizeof(spi_bus_obj[0]); i++) { spi_bus_obj[i].spi_bus->parent.user_data = (void *)&spi_bus_obj[i]; result = rt_spi_bus_register(spi_bus_obj[i].spi_bus, spi_bus_obj[i].bus_name, &gd32_spi_ops); RT_ASSERT(result == RT_EOK); LOG_D("%s bus init done", spi_bus_obj[i].bus_name); } return result; } INIT_BOARD_EXPORT(rt_hw_spi_init); #endif /* BSP_USING_SPI0 || BSP_USING_SPI1 || BSP_USING_SPI2 */ #endif /* RT_USING_SPI */