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的移植就完成了。

LoRaWAN_stack移植笔记(三)__SPI的更多相关文章

  1. LoRaWAN_stack移植笔记(一)--RF硬件相关

    和硬件相关的问题 TCXO 的使用 根据SX1276数据手册, 如果使用TCXO,则需要配置RegTcxo寄存器为0x19,代码如下 ``` c void SX1276SetTcxoConfig(vo ...

  2. LoRaWAN_stack移植笔记(七)_数据包的接收发送

    以下的代码适用于LoRa sx1276点对点的通讯,纯粹的考虑在非发射模式下即为接收模式 配置sx1276的射频参数,并且切换到接收模式 //bandwidth [0:125 1:250 2:500] ...

  3. LoRaWAN_stack移植笔记(四)__RTC

    stm32相关的配置 由于例程使用的主控芯片为STM32L151C8T6,而在本设计中使用的主控芯片为STM32L051C8T6,内核不一样,并且Cube库相关的函数接口及配置也会有不同,所以芯片的驱 ...

  4. LoRaWAN_stack移植笔记 (二)_GPIO

    stm32相关的配置 由于例程使用的主控芯片为STM32L151C8T6,而在本设计中使用的主控芯片为STM32L051C8T6,内核不一样,并且Cube库相关的函数接口及配置也会有不同,所以芯片的驱 ...

  5. STemWin5.22移植笔记【转】

    来自:http://www.openedv.com/posts/list/27697.htm STemWin5.22移植笔记 网上关于emwin的资料很少,我在移植的时候查了很多资料,对我一个感觉是好 ...

  6. Oracle学习笔记三 SQL命令

    SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)  

  7. 《CMake实践》笔记三:构建静态库(.a) 与 动态库(.so) 及 如何使用外部共享库和头文件

    <CMake实践>笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE <CMake实践>笔记二:INSTALL/CMAKE_INSTALL_PREFIX &l ...

  8. Mastering Web Application Development with AngularJS 读书笔记(三)

    第一章笔记 (三) 一.Factories factory 方法是创建对象的另一种方式,与service相比更灵活,因为可以注册可任何任意对象创造功能.例如: myMod.factory('notif ...

  9. Python 学习笔记三

    笔记三:函数 笔记二已取消置顶链接地址:http://www.cnblogs.com/dzzy/p/5289186.html 函数的作用: 給代码段命名,就像变量給数字命名一样 可以接收参数,像arg ...

随机推荐

  1. 【Download error:TOO MANY REQUESTS】&【TypeError:excepted string or buffer】

    <用python写网络爬虫>,1.4.4链接爬虫,运行时,遇到错误: Download error:TOO MANY REQUESTS Traceback(most recent call ...

  2. [原创]JAVA解决喝汽水问题

    问题:一瓶汽水单价2.5元,四个瓶盖或者两个瓶子可以换取一瓶汽水.给定金额得出一共能喝几瓶汽水? 实现: #cat drink.java import java.io.BufferedReader; ...

  3. linux 安装命令 nginx 部署

    [TOC] # 安装anocanda wget https://repo.anaconda.com/archive/Anaconda3-2019.03-Linux-x86_64.sh安装:bash A ...

  4. Excel催化剂开源第21波-使用Advanced Installer打包VSTO几个注意问题

    STO项目开发完毕完,最终需要分发给用户,需要Excel催化剂用的是Clickonce发布方式,但也面临到部分用户环境要求太高,设置过程太繁锁,而要求有一些简单的安装方式,用打包工具将其打包为一个EX ...

  5. 抽象数据类型与C++

    类是一种新的数据类型,类似于数据结构,只是它拥有数据结构所没有的部分——“成员函数”,正是因为它所拥有的成员函数这一特性,使得它能隐藏“数据结构”(类)中的数据,不被用户所知道.通过类中的成员函数,使 ...

  6. Java EE.JSP.概述

    JSP最终会被转换成标准Servlet,该转换过程一般出现在第一次请求页面时. JSP页面的主要组成部分如下: HTML 脚本:嵌入Java代码 指令:从整体上控制Servlet的结构 动作:引入现有 ...

  7. linux初学者-DNS集群篇

    linux初学者-DNS集群篇 DNS服务器一般在使用时,为了缓解服务器的压力,多使用一个主DNS服务器,多个副DNS服务器,这些DNS服务器就组成了一个DNS集群. 在DNS主服务器配置好后,需要另 ...

  8. nodejs 如何自动化配置环境参数

    应用场景: 最近用 node 重构了网站的项目,部署到测试环境的时候测试一切正常. 直到有一天,运维把代码上线到内测环境的时候...... 突然发现:内测环境和测试环境竟然是同一台服务器,只不过是把代 ...

  9. java并发笔记之证明 synchronized锁 是否真实存在

    警告⚠️:本文耗时很长,先做好心理准备 证明:偏向锁.轻量级锁.重量级锁真实存在 由[java并发笔记之java线程模型]链接: https://www.cnblogs.com/yuhangwang/ ...

  10. Charles PC端和手机端抓取HTTP和HTTPS协议请求、HTTPS通用抓包规则

    一:HTTP和HTTPS的区别 HTTP是超文本传输协议,被用在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,因此HTTP协议不适合传输一些敏感信息, ...