从M3到M0,可能SPI的接口函数大致类似,但是细节略有不同

仔细观察寄存器描述,虽然个别存在差异,但是真心不知道竟然有太多的“玄机”

这次的问题主要出在了数据宽度上:

1. M3/M4的数据宽度支持8/16,是SPI_CR1中DFF: Data frame format控制的,实际使用中,只要我配置好数据宽度,直接操作DR寄存器即可。

2. M0的看起来更加强大,在SPI_CR2中DS [3:0]: Data size控制,支持4..16个bits的数据。

所以开始的时候我使用M3的操作方式,直接把驱动函数移了过来,下面为初始化代码

 /*
*********************************************************************************************************
* Function Name: bsp_spi_init
* Description : SPI初始化
* Input : None
* Output : None
* Return : None
*********************************************************************************************************
*/
static void
bsp_spi_init(void)
{
SPI_InitTypeDef SPI_InitStructure; BSP_SPI_FRAM_CS(); /* SPI_CS初始化 */
SPI_StructInit(&SPI_InitStructure);
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
SPI_Init(BSP_SPI_FRAM, &SPI_InitStructure);
/** Enable the SPI */
SPI_Cmd(BSP_SPI_FRAM, ENABLE);
}

本以为这样就OK了,后来发现二者还是有区别的:

M3的话你直接写DR寄存器,会自动根据你的配置数据长度8/16发送数据

M0的话,你直接写DR寄存器,他不会根据你写的数据长度发送,依旧发送的是16bits

后来观察ST官方给的驱动代码:

M3的接口函数没有区分,都是直接操作DR

// M3的发送代码
/**
* @brief Transmits a Data through the SPIx/I2Sx peripheral.
* @param SPIx: where x can be
* - 1, 2 or 3 in SPI mode
* - 2 or 3 in I2S mode
* @param Data : Data to be transmitted.
* @retval None
*/
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data)
{
/* Check the parameters */
assert_param(IS_SPI_ALL_PERIPH(SPIx)); /* Write in the DR register the data to be sent */
SPIx->DR = Data;
}

M0的官方代码比较复杂:

/**
* @brief Transmits a Data through the SPIx/I2Sx peripheral.
* @param SPIx: where x can be 1 or 2 in SPI mode to select the SPI peripheral.
* @param Data: Data to be transmitted.
* @retval None
*/
void SPI_SendData8(SPI_TypeDef* SPIx, uint8_t Data)
{
uint32_t spixbase = 0x00; /* Check the parameters */
assert_param(IS_SPI_ALL_PERIPH(SPIx)); spixbase = (uint32_t)SPIx;
spixbase += 0x0C; *(__IO uint8_t *) spixbase = Data;
} /**
* @brief Transmits a Data through the SPIx/I2Sx peripheral.
* @param SPIx: where x can be 1 or 2 in SPI mode or 1 in I2S mode to select
* the SPI peripheral.
* @param Data: Data to be transmitted.
* @retval None
*/
void SPI_I2S_SendData16(SPI_TypeDef* SPIx, uint16_t Data)
{
/* Check the parameters */
assert_param(IS_SPI_ALL_PERIPH(SPIx)); SPIx->DR = (uint16_t)Data;
}

虽然都是操作的DR,但是M0这里把DR强转成8bits宽度的指针,之后操作。

因为我只是发送8bits的数据,所以这样算是OK了

至于其他的非8/16的宽度如何操作,暂时就不去纠结了。。。。

我最后的做法简单粗暴,直接对DR强行转换:

         (*((volatile unsigned char*)(&BSP_SPI_FRAM->DR) ))= dat;

这样免得调用他那个发送的库,各个平台的代码归档起来也方便一些。

至于这样设计的原因,我考虑还是M0的字节对齐问题吧?

STM32 M0之SPI的更多相关文章

  1. STM32学习笔记——SPI串行通讯(向原子哥学习)

    一.SPI  简介 SPI是 Serial Peripheral interface 的缩写,就是串行外围设备接口.SPI 接口主要应用在  EEPROM, FLASH,实时时钟,AD 转换器,还有数 ...

  2. 怎样从Cortex-m向STM32移植使用SPI接口协议

    /*************************************************************************************************** ...

  3. STM32—4线SPI驱动SSD1306 OLED

    文章目录 一.OLED简介 二.驱动SSD1306所需知识 1.引脚介绍 2.通信时序 3.显存GRAM 4.字库 5.SSD1306基本命令 三.代码讲解 1.相关引脚配置 2.模拟SPI通信 3. ...

  4. STM32—SPI详解

    目录 一.什么是SPI 二.SPI协议 物理层 协议层 1.通讯时序图 2.起始和停止信号 3.数据有效性 4.通讯模式 三.STM32中的SPI 简介 功能框图 1.通讯引脚 2.时钟控制逻辑 3. ...

  5. STM32的SPI口的DMA读写[原创www.cnblogs.com/helesheng]

    SPI是我最常用的接口之一,连接管脚仅为4根:在常见的芯片间通信方式中,速度远优于UART.I2C等其他接口.STM32的SPI口的同步时钟最快可到PCLK的二分之一,单个字节或字的通信时间都在us以 ...

  6. [stm32] 一个简单的stm32vet6驱动的天马4线SPI-1.77寸LCD彩屏DEMO

    书接上文<1.一个简单的nRF51822驱动的天马4线SPI-1.77寸LCD彩屏DEMO> 我们发现用16MHz晶振的nRF51822驱动1.77寸的spi速度达不到要求 本节主要采用7 ...

  7. 嵌入式单片机STM32应用技术(课本)

    目录SAIU R20 1 6 第1页第1 章. 初识STM32..................................................................... ...

  8. SPI接口扫盲 SPI定义/SPI时序(CPHA CPOL)

    SPI接口扫盲   douqingl@gmail.com   为何要写这篇文档?百度上找出来的SPI接口中文描述都说的太过简略,没有一篇文档能够详尽的将SPI介绍清楚的.wikipedia英文版[注释 ...

  9. 【转】spi测试自发自收(中断通信方式)

    1.初始化spi时钟 void spiRccinit(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); RCC_APB2Peri ...

随机推荐

  1. Material Icons 查找的替代办法

    1 问题 1.1 国内访问 google 困难,众所周知 1.2 在平时的工作中使用 Material Icons 如何查询呢 2 办法 2.1 github.com 把包 download 2.2 ...

  2. .net+文件夹上传

    ASP.NET上传文件用FileUpLoad就可以,但是对文件夹的操作却不能用FileUpLoad来实现. 下面这个示例便是使用ASP.NET来实现上传文件夹并对文件夹进行压缩以及解压. ASP.NE ...

  3. 基于Web的文件上传管理系统

    一般10M以下的文件上传通过设置Web.Config,再用VS自带的FileUpload控件就可以了,但是如果要上传100M甚至1G的文件就不能这样上传了.我这里分享一下我自己开发的一套大文件上传控件 ...

  4. SSH 远程上传本地文件至服务器

    使用SSH命令行传输文件到远程服务器   以前一直在windows下用SSH Secure Shell连接远程服务器,它自带了一个可视化的文件传输工具,跟ftp差不多 但是它也存在一个缺陷,不支持编码 ...

  5. 《视觉SLAM十四讲》学习日志(二)——初识SLAM

    小萝卜机器人的例子: 就像这种机器人,它的下面有一组轮子,脑袋上有相机(眼睛),为了让它能够探索一个房间,它需要知道: 1.我在哪——定位 2.周围环境怎么样——建图 定位和建图可以理解成感知的 &q ...

  6. call()与构造函数的运用

    一.简介 call()和apply()方法是所有函数体的固有属性,可以在指定作用域下调用函数.这里面有两层意思:1.可以在另外的作用域下调用函数:2.当函数体是是构造函数时,call()方法能达到类之 ...

  7. Elasticsearch的Search详解

    介绍 ES不是新技术,是将全文检索和数据分析.分布式整合到一起. 基于lucene开发,提供简单的restful api接口.java api接口.其他语言开发接口等. 实现了分布式的搜索引擎和分析引 ...

  8. 连接Android模拟器

    一.如何找到adb?    安装夜神安卓模拟器后,电脑桌面会有“夜神模拟器”的启动图标,鼠标右键--打开文件所在的位置,就会进入***\Nox\bin,默认路径是C:\Program Files (x ...

  9. Mysql触发器详解以及union的使用

    ---恢复内容开始--- Mysql触发器定义: 当一个表中有insert update delete事件发生,触发一个事件,执行一段代码.作用: 同步数据创建: create trigger 名称 ...

  10. cookie和session的区别及其原理

    1.为什么要有cookie/session? HTTP是一种无状态的协议,为了分辨链接是谁发起的,需自己去解决这个问题.不然有些情况下即使是同一个网站每打开一个页面也都要登录一下.而Session和C ...