记rtthread中使用spi驱动时对于HAL_SPI_MspInit在何时调用(源码阅读)

根据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函数

 

 

posted @ 2020-06-10 22:45  一半丶  阅读(2280)  评论(0编辑  收藏  举报