zoukankan      html  css  js  c++  java
  • 记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函数

     

  • 相关阅读:
    [哈希][倍增] Jzoj P5856 01串
    [exgcd] Jzoj P5855 吃蛋糕
    [折半搜索][分治][二分] Jzoj P5851 f
    [lca][主席树] Jzoj P5850 e
    [二分][树状数组] Jzoj P5849 d
    [容斥] Jzoj P5843 b
    [前缀和][枚举] Jzoj P5842 a
    [平衡规划][模拟][前缀和] Jzoj P4724 斐波那契
    [spfa] Jzoj P4722 跳楼机
    [模拟] Jzoj P2499 东风谷早苗
  • 原文地址:https://www.cnblogs.com/Raowz/p/13074089.html
Copyright © 2011-2022 走看看