STM32 SPI硬件NSS

STM32F1的SPI NSS引脚并不是通常认为的,打开硬件NSS后在发送数据的时候NSS输出低,去片选从设备,在发送完成后释放从设备,硬件NSS而是用来实现多主机模式的。

当时我还以为买到了假STM32了呢。


在我们配置SPI为硬件NSS之后,配置代码如下,发现不论发不发数据NSS都为0V;

//SPI Pins SCK MOSIGPIO_InitStructure.GPIO_Pin     = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_15;GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_AF_PP;//注意这里GPIO_Init(GPIOB,&GPIO_InitStructure);SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;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_Hard;//注意这里SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;SPI_InitStructure.SPI_FirstBit  = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init(SPI2,&SPI_InitStructure);SPI_SSOutputCmd(SPI2,ENABLE);//注意这里SPI_Cmd(SPI2,ENABLE);

在阅读Reference Manual时发现这么一句话

This configuration is used only when the device operates in master mode. The NSS signal is driven low when the master starts the communication and is kept low until the SPI is disabled.

大概意思是:在disable SPI之后NSS才会不被拉低。于是我就这样:

SPI_Cmd(SPI2,DISABLE);

发现NSS是0.5V左右,注意是0.5V,这里像是开漏输出的样子;为什么没有输出3.3V,于是在NSS上加了一个10K上拉电阻,结果NSS输出了3.3V,这不就是开漏吗?这也是为了能够线与,实现多主机模式吧。

加了上拉电阻之后SPI的NSS功能就算正常啦。


Reference Manual写到

When configured in master mode with NSS configured as an input (MSTR=1 and SSOE=0) and if NSS is pulled low, the SPI enters the master mode fault state: the MSTR bit is automatically cleared and the device is configured in slave mode

其中说到SSOE = 0,NSS配置为输入,当NSS为低电平时,SPI 进入从机模式,也就下边的代码,注意这里使用的SPI_NSS_Hard。

SPI_SSOutputCmd(SPI2,DISABLE);

在NSS未接上拉电阻的时候,NSS为逻辑0 ,那么SPI就会进入从机模式,SCK和MOSI上无数据;接上拉电阻之后,这下就变正常啦,在NSS为高时SPI是主机模式SCK和MOSI可以输出数据,当外部把NSS拉低后SPI就进入了从机模式。


那可不可以这样

//SPI Pin NSSGPIO_InitStructure.GPIO_Pin     = GPIO_Pin_12;GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_Out_PP;//注意这里GPIO_Init(GPIOB,&GPIO_InitStructure);GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_SET);//注意这里SPI_InitStructure.SPI_NSS       = SPI_NSS_Hard;SPI_SSOutputCmd(SPI2,ENABLE);//注意这里

NSS引脚不用复用推挽输出 ,而是用推挽输出,也就是PB12不接入SPI,这样NSS可以通过软件的控制输出高电平和低电平,也许可以省略一个上拉电阻(别问我为什么这么扣,为了省去一个上拉电阻大费周章,因为我的板子没有设计上拉电阻,测试的上拉电阻是从外部接的),结论是否定的,因为推挽输出 是这样的

两个SPI的NSS引脚都是推挽输出,当一个输出高,一个输出低,那么他们会各自分得1.6V的电压,也就是逻辑1,若设置了SSOE = 0,SPI 也不会 从主机自动变成从机。


那么可不可以这样

//SPI Pin NSSGPIO_InitStructure.GPIO_Pin     = GPIO_Pin_12;GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_Out_OD;//注意这里GPIO_Init(GPIOB,&GPIO_InitStructure);GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_SET);//注意这里SPI_InitStructure.SPI_NSS       = SPI_NSS_Hard;SPI_SSOutputCmd(SPI2,ENABLE);//注意这里

PB12开漏输出,然后在外部上拉一个大电阻。哈哈,这次答案是肯定的,NSS有高有低,SPI也可以进入从机模式,但是上拉电阻还是不能省啊。


PB12没有设置成复用功能,为什么SPI还会检测到NSS引脚的低电平,而后进入从机模式呢?

看上面STM32 GPIO的图,会发现不管输出设为那种模式,输入是一直连接到STM32 内部的,这也就是为什么 STM32 固件库里输入模式只有这几种模式,而没有复用输入的原因。

GPIO_Mode_AIN = 0x0,GPIO_Mode_IN_FLOATING = 0x04,GPIO_Mode_IPD = 0x28,GPIO_Mode_IPU = 0x48,

那怎么才能使用多主机模式呢?

  1. NSS设置成复用功能,加上拉电阻,SPI_NSS_Hard,且在不发送数据时失能NSS输出,在要发送数据时使能NSS输出。

  2. NSS设置成开漏输出,加上拉电阻,SPI_NSS_Hard,且在不发送数据时失能NSS输出,在要发送数据时使能NSS输出。

  3. 第2种方法真鸡肋


如果只是单主机模式,那么配置模式就比较的随意啦。

  1. NSS设置成复用功能,加上拉电阻,SPI_NSS_Hard,SPI_SSOutputCmd(SPI2,ENABLE),软件去控制NSS。

  2. NSS设置成开漏输出,加上拉电阻或者推挽输出,SPI_NSS_Hard,SPI_SSOutputCmd(SPI2,ENABLE),软件去控制NSS。

  3. 直接NSS设置成推挽输出,SPI_NSS_Soft,软件去控制NSS。

  4. 还是第3种方法最实用。