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:

  1. The device’s MISO (or DOUT) pin uses open-drain output.
  2. This is usually true because open-drain allows multiple SPI slaves to share the same MISO line.
  3. In the communication protocol, the slave device always waits for the master to send fixed number of bytes (commands) from MOSI,
  4. then returns a fixed number of bytes to MISO.
  5. Some devices which transmit and receive data simultaneously cannot be used in half-duplex mode.
  6. The slave ignores whatever appears on the MOSI pin when transmitting data to the master.
  7. This is usually not mentioned in the datasheet.
  8. However, if the slave device mandates a CS or STROBE signal to be asserted at the beginning of each data exchange,
  9. we can usually assume this is true.
  10. Reason being that the slave device is using CS to reset its internal state
  11. 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的更多相关文章

  1. The STM32 SPI and FPGA communication

    The STM32 SPI and FPGA communication STM32 spi bus communication SPI bus in the study, the protocol ...

  2. 关于STM32 SPI NSS的讨论

    NSS分为内部引脚和外部引脚. NSS外部引脚可以作为输入信号或者输出信号, 输入信号一般用作硬件方式从机的片选, 而输出信号一般用于主SPI去片选与之相连的从SPI. NSS从设备选择有两种模式: ...

  3. stm32 SPI介绍和配置

    SPI是一种高速的,全双工同步的通信总线,在芯片管脚上占用了四根线,节约了芯片的管脚,同时为PCB的布局节省了空间,提供了方便,因此越来越多的芯片集成了这种通信协议,STM32也就有了SPI接口. 有 ...

  4. STM32 SPI 发送第一个数据不成功问题

    STM32的标准库,跟HAL库都是很实用的, 在使用SPI库的过程中一定要注意时序的问题. 我在调试SPI过程中,调试了两个IC,都是用HAL库, 第一个IC没出问题,第二个IC出现了第一次发送数据不 ...

  5. STM32—SPI读写FLASH

    目录 FLASH简介 W25Q64 W25Q64简介 FLASH控制指令 FLASH内部存储结构 代码讲解 读取芯片ID 发送写使能信号 等待FLASH不忙 擦除扇区 写入数据 读取数据 注 FLAS ...

  6. STM32—SPI详解

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

  7. STM32 SPI DMA 的使用

    一是想总结一下SPI总线的特点与注意点,二是总结一下SPI DMA的使用 一.SPI信号线说明 通常SPI通过4个引脚与外部器件相连: MISO:主设备输入/从设备输出引脚.该引脚在从模式下发送数据, ...

  8. STM32.SPI(25Q16)

    1.首先认识下W25Q16DVSIG, SOP8 SPI FLASH 16MBIT  2MB(4096个字节) (里面可以放字库,图片,也可以程序掉电不丢失数据放里面) 例程讲解: ① 1.用到SPI ...

  9. 2.2寸(14PIN)TFT液晶屏STM32 SPI 控制

    屏幕如图所示,共14个IO口(也可能只有13个),控制屏幕的有9个IO口 详细版介绍见:http://www.ciast.net/post/20151112.html 反面IO口图: 连接通过SPI方 ...

随机推荐

  1. UI渲染回顾简单笔记

    UI渲染的简单过程: CPU,GPU,显示器协同工作,CPU 中计算显示内容,比如视图的创建.布局计算.图片解码.文本绘制等,然后将计算结果提交给GPU,由 GPU 进行变换.合成.渲染.随后 GPU ...

  2. iOS 判断相册相机是否允许

    1 判断是否允许使用相机: NSString *mediaType = AVMediaTypeVideo; AVAuthorizationStatus authStatus = [AVCaptureD ...

  3. Sortable.js

    拖拽的时候主要由这几个事件完成, ondragstart 事件:当拖拽元素开始被拖拽的时候触发的事件,此事件作用在被拖曳元素上 ondragenter 事件:当拖曳元素进入目标元素的时候触发的事件,此 ...

  4. 面试:----Struts和springmvc的区别--区别上

    SpringMVC和Struts2的区别 1核心控制器(前端控制器,预处理控制器):对于使用过MVC框架的人来说这个词应该不会陌生.核心控制器的主要用途处理所有的请求.然后对那些特殊的请求.统一的进行 ...

  5. windows常用设置

    1.截图   A.QQ打开,ctrl + Alt + A   B. cmd 输入  截图工具 2.录制windows操作步骤    命令行输入:psr.exe

  6. Linux内核启动流程分析(二)【转】

    转自:http://blog.chinaunix.net/uid-25909619-id-3380544.html S3C2410 Linux 2.6.35.7启动分析(第二阶段) 接着上面的分析,第 ...

  7. linux使用badblocks命令扫描硬盘排除故障(待验证)

    检查硬盘是否产生坏道并输出# badblocks -s -v -o /root/badblocks.log /dev/sda              //公司操作 -s     Show the p ...

  8. java 完全解耦

    只要有一个方法操作的是类而非接口,那么你就只能使用这个类及其子类,如果你想要将这个方法应用于不在此继承结构中的某个类,那么你就会触霉头,接口可以在很大程度上放宽这种限制,因此,我们可以编写可服用性更好 ...

  9. Spring中AOP实现

    1.什么是SpringAOP 什么是aop:Aspect Oriented Programming的缩写,面向切面编程,通过预编译和动态代理实现程序功能的 统一维护的一种技术 主要功能:日志记录,性能 ...

  10. IO知识点整理(序列化,管道流,数据流,字节数组流,与编码)

    一:序列化的问题 1.序列号的使用问题 关于在序列化中的序列号的使用问题,一般要是使用. 因为,每次要序列化的类产生都会产生一个一个新的序列号,如果将这个类的程序修改后,就会产生新的序列号,以前序列化 ...