LoRaWAN_stack移植筆記(三)__SPI


stm32相關的配置

由於例程使用的主控芯片為STM32L151C8T6,而在本設計中使用的主控芯片為STM32L051C8T6,內核不一樣,並且Cube庫相關的函數接口及配置也會有不同,所以芯片的驅動所以做修改。

SPI 的配置

SPI使用的是STM32的硬件接口-SPI1 MOSI MISO
可以看到例程中,對SPI接口進行了再一層的封裝,封裝如下:

/*!
 * SPI driver structure definition
 */
struct Spi_s
{
    SPI_HandleTypeDef Spi;
    Gpio_t Mosi;
    Gpio_t Miso;
    Gpio_t Sclk;
    Gpio_t Nss;
};

其中:

	SPI_HandleTypeDef Spi;

是原先的STM32Cube庫的封裝,在此基礎上,將SPI的引腳也封裝進了自定義的Spi_s結構體中。這樣,查看結構體就可以看到SPI的所有情況。

SPI 初始化配置

初始化的函數體如下:

void SpiInit( Spi_t *obj, PinNames mosi, PinNames miso, PinNames sclk, PinNames nss )
{
    __HAL_RCC_SPI1_FORCE_RESET( );
    __HAL_RCC_SPI1_RELEASE_RESET( );

    __HAL_RCC_SPI1_CLK_ENABLE( );

    obj->Spi.Instance = ( SPI_TypeDef *) SPI1_BASE;

    GpioInit( &obj->Mosi, mosi, PIN_ALTERNATE_FCT, PIN_PUSH_PULL, PIN_PULL_DOWN, GPIO_AF0_SPI1 );
    GpioInit( &obj->Miso, miso, PIN_ALTERNATE_FCT, PIN_PUSH_PULL, PIN_PULL_DOWN, GPIO_AF0_SPI1 );
    GpioInit( &obj->Sclk, sclk, PIN_ALTERNATE_FCT, PIN_PUSH_PULL, PIN_PULL_DOWN, GPIO_AF0_SPI1 );

    if( nss != NC )
    {
        GpioInit( &obj->Nss, nss, PIN_ALTERNATE_FCT, PIN_PUSH_PULL, PIN_PULL_UP, GPIO_AF0_SPI1 );
    }
    else
    {
        obj->Spi.Init.NSS = SPI_NSS_SOFT;
			  GpioInit( &SX1276.Spi.Nss, RADIO_NSS, PIN_OUTPUT, PIN_PUSH_PULL, PIN_PULL_UP, 1 );
    }

    if( nss == NC )
    {
        SpiFormat( obj, SPI_DATASIZE_8BIT, SPI_POLARITY_LOW, SPI_PHASE_1EDGE, 0 );
    }
    else
    {
        SpiFormat( obj, SPI_DATASIZE_8BIT, SPI_POLARITY_LOW, SPI_PHASE_1EDGE, 1 );
    }
		obj->Spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;

    HAL_SPI_Init( &obj->Spi );
}
``` c
SPI的初始化函數是這樣被調用的:
``` c
SpiInit( &SX1276.Spi, RADIO_MOSI, RADIO_MISO,RADIO_SCLK, NC );

//初始化函數的原型
void SpiInit( Spi_t *obj, PinNames mosi, PinNames miso, PinNames sclk, PinNames nss );

其中引腳定義是這樣的

#define RADIO_MOSI                                PA_7
#define RADIO_MISO                                PA_6
#define RADIO_SCLK                                PA_5
#define RADIO_NSS                                 PA_4

可以看到SPI的MOSI/MISO/SCLK腳都有看到,但是NSS腳看到,而是傳了NC。

這是為什么呢?
可以看到程序里面有段話

if( nss != NC )
{
    GpioInit( &obj->Nss, nss, PIN_ALTERNATE_FCT, PIN_PUSH_PULL, PIN_PULL_UP, GPIO_AF0_SPI1 );
}
else
{
    obj->Spi.Init.NSS = SPI_NSS_SOFT;
	GpioInit( &SX1276.Spi.Nss, RADIO_NSS, PIN_OUTPUT, PIN_PUSH_PULL, PIN_PULL_UP, 1 );
}

其意思就是設置為NC就配置NSS 為軟件控制,即NSS腳只做片選使用,x像GPIO一樣控制他拉高拉低就可以控制片選的使能與否了。

還有一處,設置SPI的工作頻率的

SpiFrequency( obj, 10000000 );

void SpiFrequency( Spi_t *obj, uint32_t hz )
{
    uint32_t divisor;

    divisor = SystemCoreClock / hz;

    // Find the nearest power-of-2
    divisor = divisor > 0 ? divisor-1 : 0;
    divisor |= divisor >> 1;
    divisor |= divisor >> 2;
    divisor |= divisor >> 4;
    divisor |= divisor >> 8;
    divisor |= divisor >> 16;
    divisor++;

    divisor = __ffs( divisor ) - 1;

    divisor = ( divisor > 0x07 ) ? 0x07 : divisor;

    obj->Spi.Init.BaudRatePrescaler = divisor << 3;
}

由於__ffs這個函數只有Cotex-M3以上內核才能調用,但是通過計算可知若傳參為10000000,__ffs這個函數的返回值為0x03,所以可得obj->Spi.Init.BaudRatePrescaler = 8,即SPI_BAUDRATEPRESCALER_8
因為

#define SPI_BAUDRATEPRESCALER_8         ((uint32_t)SPI_CR1_BR_1)
#define SPI_CR1_BR_1                (0x2U << SPI_CR1_BR_Pos)                   
#define SPI_CR1_BR_Pos              (3U)   

所以此處設置Spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
最后再調用

HAL_SPI_Init( &obj->Spi );

至此,SPI的初始化就完成了。

SPI 讀寫

接下來就是SPI的讀寫操作了,由於都是使用的Cube庫,對寄存器的命名並沒有什么不同,直接保留例程中的代碼就可以了。

//獲取SPI的標志位狀態
FlagStatus SpiGetFlag( Spi_t *obj, uint16_t flag )
{
    FlagStatus bitstatus = RESET;

    // Check the status of the specified SPI flag
    if( ( obj->Spi.Instance->SR & flag ) != ( uint16_t )RESET )
    {
        // SPI_I2S_FLAG is set
        bitstatus = SET;
    }
    else
    {
        // SPI_I2S_FLAG is reset
        bitstatus = RESET;
    }
    // Return the SPI_I2S_FLAG status
    return  bitstatus;
}

//SPI讀寫
uint16_t SpiInOut( Spi_t *obj, uint16_t outData )
{
    uint8_t rxData = 0;

    if( ( obj == NULL ) || ( obj->Spi.Instance ) == NULL )
    {
        assert_param( FAIL );
    }

    __HAL_SPI_ENABLE( &obj->Spi );

    while( SpiGetFlag( obj, SPI_FLAG_TXE ) == RESET );
    obj->Spi.Instance->DR = ( uint16_t ) ( outData & 0xFF );

    while( SpiGetFlag( obj, SPI_FLAG_RXNE ) == RESET );
    rxData = ( uint16_t ) obj->Spi.Instance->DR;

    return( rxData );
}

在使用上,需要注意NSS引腳的操作,在進行讀寫前進行使能,讀寫完畢之后失能。程序如下圖所示:

//SPI寫
void SX1276WriteBuffer( uint8_t addr, uint8_t *buffer, uint8_t size )
{
    uint8_t i;

    //NSS = 0;
    GpioWrite( &SX1276.Spi.Nss, 0 );

    SpiInOut( &SX1276.Spi, addr | 0x80 );
    for( i = 0; i < size; i++ )
    {
        SpiInOut( &SX1276.Spi, buffer[i] );
    }

    //NSS = 1;
    GpioWrite( &SX1276.Spi.Nss, 1 );
}

//SPI讀
void SX1276ReadBuffer( uint8_t addr, uint8_t *buffer, uint8_t size )
{
    uint8_t i;

    //NSS = 0;
    GpioWrite( &SX1276.Spi.Nss, 0 );

    SpiInOut( &SX1276.Spi, addr & 0x7F );

    for( i = 0; i < size; i++ )
    {
        buffer[i] = SpiInOut( &SX1276.Spi, 0 );
    }

    //NSS = 1;
    GpioWrite( &SX1276.Spi.Nss, 1 );
}

至此,LoRaWAN例程中的SPI的移植就完成了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM