HOWTO: Use STM32 SPI half duplex mode
HOWTO: Use STM32 SPI half duplex mode
I’ve got my hands onto some STM32F030F4P6 ARM-Cortex M0 processors.
Though touted as “32 cents 32-bit micro”, it is not that inexpensive from DigiKey in one-off quantity ($1.45).
However it is still cheaper than ATmegas and offers 3 times the performance.
The chip comes in 20-pin TSSOP package.
Limited pins require much more thoughts when assigning pin function.
For example, using 3-pin half-duplex SPI instead of 4-pin full-duplex SPI saves me 1 very precious GPIO pin.
It should be noted that not all SPI slave devices support half duplex mode,
and most devices will not mention half-duplex mode in the datasheets.
Generally, a SPI slave device supports half duplex SPI mode if:

- The device’s MISO (or DOUT) pin uses open-drain output.
- This is usually true because open-drain allows multiple SPI slaves to share the same MISO line.
- In the communication protocol, the slave device always waits for the master to send fixed number of bytes (commands) from MOSI,
- then returns a fixed number of bytes to MISO.
- Some devices which transmit and receive data simultaneously cannot be used in half-duplex mode.
- The slave ignores whatever appears on the MOSI pin when transmitting data to the master.
- This is usually not mentioned in the datasheet.
- However, if the slave device mandates a CS or STROBE signal to be asserted at the beginning of each data exchange,
- we can usually assume this is true.
- Reason being that the slave device is using CS to reset its internal state
- rather than always listening and parsing command byte(s) from the master.
Half-duplex wiring of STM32 SPI is as follows:

In particular, MOSI and SCK are configured as “Alternate Function” mode.
Hardware CS (NSS) management must be disabled and user shall manually control CS using GPIO output.
R2 is pull-up resistor as required by SPI.
R1 works as protection resistor in case STM32 MOSI pin somehow enters into push-pull output mode.
The SPI setup code is as follows:
void SPI_Configure()
{
SPI_InitTypeDef SPI_InitStructure;
// Enable SPI1 clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
// SPI1 configuration
SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx; // Initially Tx
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; // Clock steady high
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; // Data write on rising (second) edge
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
SPI_InitStructure.SPI_CRCPolynomial = ;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_RxFIFOThresholdConfig(SPI1, SPI_RxFIFOThreshold_QF);
SPI_Cmd(SPI1, ENABLE);
}
Line 7 sets the SPI peripheral to half-dulex transmission mode.
Line 17 sets the SPI FIFO buffer threshold to quarter full.
This is new in STM32F0 with 4-byte SPI FIFO buffer.
SPI_RxFIFOThreshold_QF meaning that the SPI_I2S_FLAG_RXNE flag will be set as soon as 1 byte
(quarter buffer) is shifted into receiving FIFO.
SPI master sending data to slave is as simple as:
void send_byte(uint8_t val)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_4); // CS low
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); //wait buffer empty
SPI_SendData8(SPI1, val);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET); //wait finish sending
GPIO_SetBits(GPIOA, GPIO_Pin_4); // CS high
}
The following code demonstrates master sends 1 byte command to slave and reads 1 byte back.
uint8_t send_and_read_byte(uint8_t cmd)
{
uint8_t result;
GPIO_ResetBits(GPIOA, GPIO_Pin_4); // CS low
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); //wait buffer empty
SPI_SendData8(SPI1, cmd);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET); //wait finish sending
// Read receiving FIFO until it is empty
while (SPI_GetReceptionFIFOStatus(SPI1) != SPI_ReceptionFIFOStatus_Empty)
SPI_ReceiveData8(SPI1);
SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Rx);
while (!(SPI1->SR & SPI_I2S_FLAG_RXNE)) ; // wait data received
GPIO_SetBits(GPIOA, GPIO_Pin_4); // CS high
SPI1->CR1 |= SPI_Direction_Tx; // Set Tx mode to stop Rx clock
result = SPI_ReceiveData8(SPI1);
return result;
}
Immediately after one byte is sent, the program empties all stale data in the FIFO (line 9, 10),
then sets SPI direction to receiving mode (line 11).
As soon as SPI enters into receiving mode, STM32 will continuously generate clock on SCK pin until receiving mode is disabled.
Along with the clock toggling, data are shifted from MOSI pin into receiving FIFO,
and SPI_I2S_FLAG_RXNE flag is set once 1 byte of data is received (line 12).
The program then disables CS (line 13, to disable slave output)
and switches SPI back to transmitting mode (line 14, to stop the clock).
These two steps must be executed fast enough before the next clock is sent out to prevent the slave device enter into any undefined state.
Timing is very critical here especially when SPI clock is high.
To receive multiple bytes from the slave, put line 9-15 into a loop but disable CS only after all data are read.
Important thing is to always disable receiving mode immediately after FIFO is quarter full,
and verify using a scope or logic analyser to ensure exact 8 clocks are send in-between each reading.
HOWTO: Use STM32 SPI half duplex mode的更多相关文章
- The STM32 SPI and FPGA communication
The STM32 SPI and FPGA communication STM32 spi bus communication SPI bus in the study, the protocol ...
- 关于STM32 SPI NSS的讨论
NSS分为内部引脚和外部引脚. NSS外部引脚可以作为输入信号或者输出信号, 输入信号一般用作硬件方式从机的片选, 而输出信号一般用于主SPI去片选与之相连的从SPI. NSS从设备选择有两种模式: ...
- stm32 SPI介绍和配置
SPI是一种高速的,全双工同步的通信总线,在芯片管脚上占用了四根线,节约了芯片的管脚,同时为PCB的布局节省了空间,提供了方便,因此越来越多的芯片集成了这种通信协议,STM32也就有了SPI接口. 有 ...
- STM32 SPI 发送第一个数据不成功问题
STM32的标准库,跟HAL库都是很实用的, 在使用SPI库的过程中一定要注意时序的问题. 我在调试SPI过程中,调试了两个IC,都是用HAL库, 第一个IC没出问题,第二个IC出现了第一次发送数据不 ...
- STM32—SPI读写FLASH
目录 FLASH简介 W25Q64 W25Q64简介 FLASH控制指令 FLASH内部存储结构 代码讲解 读取芯片ID 发送写使能信号 等待FLASH不忙 擦除扇区 写入数据 读取数据 注 FLAS ...
- STM32—SPI详解
目录 一.什么是SPI 二.SPI协议 物理层 协议层 1.通讯时序图 2.起始和停止信号 3.数据有效性 4.通讯模式 三.STM32中的SPI 简介 功能框图 1.通讯引脚 2.时钟控制逻辑 3. ...
- STM32 SPI DMA 的使用
一是想总结一下SPI总线的特点与注意点,二是总结一下SPI DMA的使用 一.SPI信号线说明 通常SPI通过4个引脚与外部器件相连: MISO:主设备输入/从设备输出引脚.该引脚在从模式下发送数据, ...
- STM32.SPI(25Q16)
1.首先认识下W25Q16DVSIG, SOP8 SPI FLASH 16MBIT 2MB(4096个字节) (里面可以放字库,图片,也可以程序掉电不丢失数据放里面) 例程讲解: ① 1.用到SPI ...
- 2.2寸(14PIN)TFT液晶屏STM32 SPI 控制
屏幕如图所示,共14个IO口(也可能只有13个),控制屏幕的有9个IO口 详细版介绍见:http://www.ciast.net/post/20151112.html 反面IO口图: 连接通过SPI方 ...
随机推荐
- mybatis一对多关联查询——(九)
1.需求: 查询所有订单信息及订单下的订单明细信息. 订单信息与订单明细为一对多关系. 2. sql语句 确定主查询表:订单表 确定关联查询表:订单明细表 在一对一查询基础上添加订单明细表关 ...
- 003_vim使用tip
vim 使用tip 编写python程序 自动插入头信息: #!/usr/bin/env python # coding=utf-8 输入.或按TAB键会触发代码补全功能 :w保存代码之后会自动检查代 ...
- $.ajax的一些总结
1.$.ajaxSetup()函数来全局设置 $.ajaxSetup({ url: "/xmlhttp/", global: false, ty ...
- nodejs mysql 执行多条sql语句
执行多条查询语句 为了安全起见,默认情况下是不允许执行多条查询语句的.要使用多条查询语句的功能,就需要在创建数据库连接的时候打开这一功能: var connection = mysql.createC ...
- 带你走进Android Afinal框架的世界
1.什么是Afinal框架? Afinal是一个开源的android的orm和ioc应用开发框架,其特点是小巧灵活,代码入侵量少.在android应用开发中,通过Afinal的ioc框架,诸如ui绑定 ...
- K8S Dashborad登陆认证文档
K8S Dashboard是官方的一个基于WEB的用户界面,专门用来管理K8S集群,并可展示集群的状态.因为我们使用kubeadm搭建的集群会默认开启RABC(角色访问控制机制),所以我们必须要进行额 ...
- zTree搜索
自写 zTree搜索功能 -- 关键字查询 -- 递归无限层 唠叨一哈 前两天朋友跟我说要一个ztree的搜索功能,我劈头就是一巴掌:这种方法难道无数前辈还做少了?自己去找,我很忙~然后我默默地蹲着写 ...
- 搭建微信小程序基本的https与wss环境
年底了写一篇小程序环境搭建的文章, 主要是怎么搭建一个线上环境以及怎么不改动原有http Api的情况 1.准备工作 域名一个 免费证书(推荐: 腾讯云.阿里云.便宜ssl 都是免费的 配置好后先将证 ...
- 洛谷P4742 [Wind Festival]Running In The Sky [Tarjan缩点,DAGDP]
题目传送门 Running In The Sky 格式难调,题面就不放了. 分析: 一句话题意:给定一张带点权的有向图,求最长点权路径及该路径上的最大点权. 很明显的$DAGDP$,因此需要缩点,将该 ...
- java中的二进制运算简单理解
package test9; public class StreamTest { public static void main(String[] args) { int a = 15;// 0b11 ...