RT-Thread SPI usage tutorial

RT-Thread SPI Tutorial

The experimental environment uses the Pandora development board of punctual atom.

The SPI slave device uses the BMP280 temperature, humidity and atmospheric pressure sensor.

Use RT-Thread Studio to build basic functions.

1. Create a project

Use RT-Thread Studio IDE to create chip-level projects. After the creation is complete, you can directly compile and download for testing.

2. Add driver

2.1 Project configuration

After the project is created, 组建和服务层/Drivers/SPIopen the SPI driver in RT-Thread Studio.

insert image description here

Then configure the SPI:

insert image description here

After the configuration is complete, Ctrl+Ssaving the configuration will automatically update the project code.

After completing the configuration, you also need to board.hopen the macro of the SPI that needs to be used in .

insert image description here

Then board.cadd STM32 SPI initialization code, you can generate code by configuring CubeMX:

SPI_HandleTypeDef hspi2;

/* SPI2 init function */
void MX_SPI2_Init(void)
{
    
    

  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_MASTER;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi2.Init.NSS = SPI_NSS_SOFT;
  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    
    
    Error_Handler();
  }

}

void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
    
    

  GPIO_InitTypeDef GPIO_InitStruct = {
    
    0};
  if(spiHandle->Instance==SPI2)
  {
    
    
  /* USER CODE BEGIN SPI2_MspInit 0 */

  /* USER CODE END SPI2_MspInit 0 */
    /* SPI2 clock enable */
    __HAL_RCC_SPI2_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**SPI2 GPIO Configuration
    PB13     ------> SPI2_SCK
    PB14     ------> SPI2_MISO
    PB15     ------> SPI2_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* USER CODE BEGIN SPI2_MspInit 1 */

  /* USER CODE END SPI2_MspInit 1 */
  }
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{
    
    

  if(spiHandle->Instance==SPI2)
  {
    
    
  /* USER CODE BEGIN SPI2_MspDeInit 0 */

  /* USER CODE END SPI2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SPI2_CLK_DISABLE();

    /**SPI2 GPIO Configuration
    PB13     ------> SPI2_SCK
    PB14     ------> SPI2_MISO
    PB15     ------> SPI2_MOSI
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15);

  /* USER CODE BEGIN SPI2_MspDeInit 1 */

  /* USER CODE END SPI2_MspDeInit 1 */
  }
}

After completion, the SPI driver is added.

2.2 Code Analysis

2.2.1 SPI driver usage process
  1. The SPI bus device rt_spi_bus_register() is registered in the SPI device driver framework through the interface.
  2. The SPI device driver framework rt_device_register()registers the SPI bus device in the I/O device manager through the interface.
  3. The SPI slave driver rt_spi_bus_attach_device()mounts the slave device on the SPI bus device through the interface, and registers it in the SPI device driver framework.
  4. The SPI slave driver accesses the SPI slave device hardware through the SPI device interface.
2.2.2 Code

In the drivers group 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);

With the declaration here INIT_BOARD_EXPORT(), add initialization code to .rti_fn.1the section:

#define INIT_EXPORT(fn, level)                                                       \
            RT_USED const init_fn_t __rt_init_##fn SECTION(".rti_fn." level) = fn
#define INIT_BOARD_EXPORT(fn)           INIT_EXPORT(fn, "1")

Then focus on initializing the device driver board.cin rt_hw_board_init()-> in.rt_components_board_init()

void rt_components_board_init(void)
{
    
    
    volatile const init_fn_t *fn_ptr;

    for (fn_ptr = &__rt_init_rti_board_start; fn_ptr < &__rt_init_rti_board_end; fn_ptr++)
    {
    
    
        (*fn_ptr)();
    }
#endif
}

rt_hw_spi_bus_init()Called again rt_spi_bus_register(), rt_spi_bus_register()call rt_spi_bus_device_init()to call to rt_device_register()complete the registration.

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 const struct rt_spi_ops stm_spi_ops =
{
    
    
    .configure = spi_configure,
    .xfer = spixfer,
};

HAL_SPI_Init()Initialization stm32_spi_init()is done in and registered in ops. After attach, call directly rt_spi_configure()to complete the initialization.

Note that unlike the use of i2c, SPI must be bound through attach to use the SPI device interface.

3. Using SPI

Complete the bmp280 code to read the Device ID, add it to the file bmp280.c, and then add the file to the project:

#include <rtthread.h>
#include <rtdevice.h>
#include <drv_spi.h>

#define BME280_SPI_DEVICE_NAME "spi20"
#define BEM280_REG_ID 0XD0

rt_bool_t initialnized = RT_FALSE;

static void spi_bme280_demo(void)
{
    
    
    uint8_t data = BEM280_REG_ID | (1 << 7);
    rt_err_t err;

    struct rt_spi_device * spi_bme280;
    if (!initialnized) {
    
    
        initialnized = RT_TRUE;
        err = rt_hw_spi_device_attach("spi2", BME280_SPI_DEVICE_NAME, GPIOB, GPIO_PIN_12);
        if (err) {
    
    
            rt_kprintf("attach device error\r\n");
            return ;
        }
    }

    spi_bme280 = (struct rt_spi_device *)rt_device_find(BME280_SPI_DEVICE_NAME);
    if (spi_bme280 == RT_NULL) {
    
    
        rt_kprintf("find %s error\r\n", BME280_SPI_DEVICE_NAME);
        return ;
    }

    struct rt_spi_configuration cfg = {
    
    
            .mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB,
            .data_width = 8,
            .max_hz = 1 * 1000 * 1000
    };
    err = rt_spi_configure(spi_bme280, &cfg);
    if (err != RT_NULL) {
    
    
        rt_kprintf("spi configurate error\r\n");
        return ;
    }

    uint8_t send_buf[5] = {
    
    data, 0xff};
    uint8_t recv_buf[5];
    if (rt_spi_transfer(spi_bme280, send_buf, recv_buf, 2) == 0) {
    
    
        rt_kprintf("spi transfer error\r\n");
    }

    rt_kprintf("bme280 id: 0x%02x\r\n", recv_buf[1]);
}

MSH_CMD_EXPORT(spi_bme280_demo, read bme280 id);

The CS Pin I use here is PB12, pay attention to the attach interface parameters.

4. Test

The Device ID of BMP280 is 0x58, BME280 is 0x60.

Compile and burn the above project, and enter the command to verify:

insert image description here

insert image description here

Guess you like

Origin blog.csdn.net/duapple/article/details/129113790