根据RTThread官方文档操作,可以正常的使用SPI驱动。但是在操作过程中实现了HAL_SPI_MspInit函数,但不知在何处调用了该函数。
记录一下查找过程。
#define RT_USING_SPI #define BSP_USING_SPI1 /*这两个宏是在操作过程中定义的,会引申出一些函数参与编译*/ /*在drv_spi.c中有一个全局结构体数组spi_config*/ static struct stm32_spi_config spi_config[] = { /*这里只复制SPI1部分,其余部分等同*/ #ifdef BSP_USING_SPI1 SPI1_BUS_CONFIG, #endif ... }; /********************以下是对该结构的剖析*****************************/ /*在drv_spi.h*/ struct stm32_spi_config { SPI_TypeDef *Instance; char *bus_name; struct dma_config *dma_rx, *dma_tx; }; /*在spi_config.h*/ #ifdef BSP_USING_SPI1 #ifndef SPI1_BUS_CONFIG #define SPI1_BUS_CONFIG \ { \ .Instance = SPI1, \ .bus_name = "spi1", \ } #endif /* SPI1_BUS_CONFIG */ #endif /* BSP_USING_SPI1 */ /**********************************************************************/ /*因此可以知道该全局结构体的值应为*/ spi_config[0].Instance = SPI1; /*该处也解释了list_devicename为spi1的原因*/ spi_config[0].bus_name = "spi1";
static const struct rt_spi_ops stm_spi_ops = { .configure = spi_configure, //此处是关键 .xfer = spixfer, //此函数是针对SPI接收和发送数据的 }; static rt_err_t spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration) { RT_ASSERT(device != RT_NULL); RT_ASSERT(configuration != RT_NULL); struct stm32_spi *spi_drv = rt_container_of(device->bus, struct stm32_spi, spi_bus); spi_drv->cfg = configuration; return stm32_spi_init(spi_drv, configuration); } 逐层追下去 static rt_err_t stm32_spi_init(struct stm32_spi *spi_drv, struct rt_spi_configuration *cfg) { /*此处略去不必要代码*/ ... if (HAL_SPI_Init(spi_handle) != HAL_OK) { return RT_EIO; } ... /*此处略去不必要代码*/ } /*终于在HAL_SPI_Init中找到了去处*/ HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi) { /*此处略去不必要代码*/ if (hspi->State == HAL_SPI_STATE_RESET) { /* Allocate lock resource and initialize it */ hspi->Lock = HAL_UNLOCKED; HAL_SPI_MspInit(hspi); } /*此处略去不必要代码*/ }
接下来,我们该找 stm_spi_ops.configure在哪里被调用执行就知道rtthread如何调用HAL_SPI_MspInit函数了、
在drv_spi.c中有如下函数
int rt_hw_spi_init(void) { stm32_get_dma_info(); return rt_hw_spi_bus_init(); }
INIT_BOARD_EXPORT(rt_hw_spi_init);
rt_hw_spi_init在系统启动时会自动执行
static struct stm32_spi spi_bus_obj[sizeof(spi_config) / sizeof(spi_config[0])] = {0}; static int rt_hw_spi_bus_init(void) { rt_err_t result; for (int i = 0; i < sizeof(spi_config) / sizeof(spi_config[0]); i++) { spi_bus_obj[i].config = &spi_config[i]; spi_bus_obj[i].spi_bus.parent.user_data = &spi_config[i]; spi_bus_obj[i].handle.Instance = spi_config[i].Instance; ...//此处略去不必要代码 result = rt_spi_bus_register(&spi_bus_obj[i].spi_bus, spi_config[i].bus_name, &stm_spi_ops); RT_ASSERT(result == RT_EOK); LOG_D("%s bus init done", spi_config[i].bus_name); } return result; }
查看rt_spi_bus_register
rt_err_t rt_spi_bus_register(struct rt_spi_bus *bus, const char *name, const struct rt_spi_ops *ops) { rt_err_t result; result = rt_spi_bus_device_init(bus, name); if (result != RT_EOK) return result; /* initialize mutex lock */ rt_mutex_init(&(bus->lock), name, RT_IPC_FLAG_FIFO); /* set ops */ bus->ops = ops; //在此处赋值 /* initialize owner */ bus->owner = RT_NULL; //该指针表示是挂载在SPI BUS上那一个从设备在使用 /* set bus mode */ bus->mode = RT_SPI_BUS_MODE_SPI; return RT_EOK; }
追到此处已经大概明了。
如果不使用SFUD的话,可以自行配置SPI的参数以及工作模式(这个结构体rt_spi_configuration),然后将bus->owner设置为自己,调用rt_spi_configure函数完成初始化。
rt_err_t rt_spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *cfg) { rt_err_t result; RT_ASSERT(device != RT_NULL); /* set configuration */ device->config.data_width = cfg->data_width; device->config.mode = cfg->mode & RT_SPI_MODE_MASK ; device->config.max_hz = cfg->max_hz ; if (device->bus != RT_NULL) { result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER); if (result == RT_EOK) { if (device->bus->owner == device) //注意:在写configure函数时需要将bus->owner设置为自己才能成功的调用到HAL_SPI_MspInit { device->bus->ops->configure(device, &device->config); } /* release lock */ rt_mutex_release(&(device->bus->lock)); } } return RT_EOK; }
使用SFUD的话发送和接受都会调用bus的opt的configure从而执行到HAL_SPI_MspInit。
注:记录一下sfud中rt_sfud_flash_probe --->sfud_device_init ---> hardware_init ---> sfud_spi_port_init 这一系列调用。关联了
sfud_flash结构中的 sfud_spi结构体成员 的 wr(发送接收函数)函数指针 到 spi_write_read ----->rt_spi_send/rt_spi_recv ----> rt_spi_transfer ---> rt_spi_device->bus->ops->xfer ---> drv_spi.c中的spixfer函数---> HAL库中的HAL_SPI_Transmit函数