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. SDWebImage源码阅读-第二篇

    一  SDWebImageManager的downloadImageWithURL的方法 上一篇,我们刚开了个头,分析了一下开始加载图片之前如何取消其他正在下载的任务,接着,我们回到 - (void) ...

  2. Manacher's Algorithm 马拉车算法

    作用:求一个字符串中的最长子串,同时还可以求所有子串的长度. 题目链接: https://vjudge.net/contest/254692#problem/B 代码: #include<bit ...

  3. RabbitMQ集群使用Haproxy负载均衡

    (1).下载 http://www.haproxy.org/#down (2).解压 tar -zxvf haproxy-1.5.18.tar.gz (3).安装 1).编译 make TARGET= ...

  4. order by 字段自动填写脚本

    新版 firefox 中的 hackbar 没有 order by 字段填写, 所以就有了这个: =begin pod sql注入中自动输出order by 的位数 =end pod sub MAIN ...

  5. 大数据系列之数据仓库Hive安装

    Hive系列博文,持续更新~~~ 大数据系列之数据仓库Hive原理 大数据系列之数据仓库Hive安装 大数据系列之数据仓库Hive中分区Partition如何使用 大数据系列之数据仓库Hive命令使用 ...

  6. Objective-C 与JAVA的SHA1/HmacSHA1加密算法实现

    最近研究IOS手机上登录的功能.由于加密方式使用SHA1算法.网上也没找到直接的例子,最终参照StackoverFlow上的大神,完成了加密实现. 先上代码: //HmacSHA1加密: +(NSSt ...

  7. css中width和padding-top实现正方形

    .div{ width: 100%; height: 0; padding-top: 100% } 这个时候,padding-top的值与width相等,所以可以让div宽高一样,值为width的值

  8. 当父级绑定了DataContext之内的数据源时,子级想重新绑回DataContext

    <Grid x:Name="NewDeploymentObjectPanel" Background="White" DataContext=" ...

  9. Flutter与Dart 入门

    Flutter简介 Flutter是google推出的,一个使用Dart语言开发的跨平台移动UI框架,通过自建绘制引擎,能高性能.高保真地进行Android和IOS开发. Flutter是什么 Flu ...

  10. EntityFramework系列:SQLite的CodeFrist和RowVersion

    没什么好说的,能支持DropCreateDatabaseIfModelChanges和RowVersion的Sqlite谁都想要.EntityFramework7正在添加对Sqlite的支持,虽然EF ...