打印

【转】LoRaWAN_stack移植笔记(三)__SPI

[复制链接]
690|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
MTCN2013|  楼主 | 2017-1-31 14:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
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 初始化配置
初始化的函数体如下:
``` c
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 );
其中引脚定义是这样的 c
define RADIO_MOSI PA_7define RADIO_MISO PA_6define RADIO_SCLK PA_5define 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 );    }    //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 = SpiInOut( &SX1276.Spi, 0 );    }    //NSS = 1;    GpioWrite( &SX1276.Spi.Nss, 1 );}
至此,LoRaWAN例程中的SPI的移植就完成了。


相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

28

主题

155

帖子

1

粉丝