你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32的SPI外设片选只有一个怎么破?

[复制链接]
STMCU小助手 发布时间:2022-6-23 21:00

之前用STM32的SPI需要控制很多外部芯片,可是一个SPI的外设只有一个片选,要实现独立片选一主多从,怎么实现呢?


SPI总线拓扑

一般地,SPI总线按照下图方式进行连接,一主多从。



D20@Z{HTNK{J0FJJ1[EQZ26.png

如上图:

  • 每个从设备都有独立的片选引脚,主机同一时间段内,与一个从设备进行通信,也即选中一个从设备。
  • MOSI/MISO/SCLK并联在一起
  • MISO须是三态门,当从设备未选中时,该脚须设置为高阻态,而不能是输出态,否则会影响总线
  • 对于MOSI/SCLK,虽然并联在一起,但是由于仅一个输出,多输入。

但是你看STM32的SPI外设,一个SPI仅有一个NSS信号,以STM32F407的SPI2为例:


那么要实现前面说的一主多从,怎么办呢?有朋友说,直接用GPIO去模拟不就可以了。

不错,SPI总线要用GPIO模拟还是很容易的,但是这样做波特率做不高,需要占用CPU时间,效率比较低!而用SPI外设控制器,底层bit流的收发由外设控制器实现,用GPIO模拟则需要CPU参与。


怎么破呢?菊花链拓扑


]$)3V2VSM`}FB4IQGA%D@UH.png

这种方案,省引脚。但是要移位控制,相对独立片选效率还是低不少。


独立片选拓扑

SPI外设的MOSI、MISO、SCK还是照用不误,但是片选我们不用,设置成通用输出模式,再用其他的GPIO片选从芯片即可。

上代码看看:

  1. <font face="Tahoma"><font size="3">void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
  2. {
  3.   GPIO_InitTypeDef GPIO_InitStruct = {<font color="rgb(184, 215, 163)">0</font>};
  4.   <font color="rgb(86, 156, 214)">if</font>(hspi->Instance==SPI1)
  5.   {
  6.     __HAL_RCC_SPI1_CLK_ENABLE();
  7.     __HAL_RCC_GPIOA_CLK_ENABLE();
  8.     <font color="rgb(87, 166, 74)"><i>/**SPI1 GPIO Configuration
  9.     PA5     ------> SPI1_SCK
  10.     PA6     ------> SPI1_MISO
  11.     PA7     ------> SPI1_MOSI
  12.     PA15     ------> SPI1_NSS 但是这里不用
  13.     */</i></font>
  14.     GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
  15.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  16.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  17.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  18.     GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
  19.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  20.    /*__HAL_RCC_GPIOC_CLK_ENABLE();
  21.     GPIO_InitStruct.Pin = GPIO_PIN_1;
  22.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  23.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  24.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  25.     GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
  26.     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);*/
  27.   }
  28. }
  29. </font></font><p style="line-height: 26px;"><font color="black"><font face="Tahoma"><font size="3">初始化SPI外设</font></font></font></p><font face="Tahoma"><font size="3"><font color="rgb(155, 155, 155)">#define SPI_CS1                        GPIO_PIN_1</font>
  30. <font color="rgb(155, 155, 155)">#define SPI_CS1_PORT                   GPIOC</font>
  31. <font color="rgb(155, 155, 155)">#define SPI_CS2                        GPIO_PIN_2</font>
  32. <font color="rgb(155, 155, 155)">#define SPI_CS2_PORT                   GPIOC</font>
  33. <font color="rgb(155, 155, 155)">#define SPI_CS3                        GPIO_PIN_3</font>
  34. <font color="rgb(155, 155, 155)">#define SPI_CS3_PORT                   GPIOC</font>
  35. static void init_spi(SPI_HandleTypeDef * spi_handle)
  36. {
  37.   <font color="rgb(87, 166, 74)"><i>/* SPI1 parameter configuration*/</i></font>
  38.   spi_handle->Instance = SPI1;
  39.   spi_handle->Init.Mode = SPI_MODE_MASTER;
  40.   spi_handle->Init.Direction = SPI_DIRECTION_2LINES;
  41.   spi_handle->Init.DataSize = SPI_DATASIZE_8BIT;
  42.   spi_handle->Init.CLKPolarity = SPI_POLARITY_LOW;
  43.   spi_handle->Init.CLKPhase = SPI_PHASE_1EDGE;
  44.   spi_handle->Init.NSS = SPI_NSS_HARD_OUTPUT;
  45.   spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  46.   spi_handle->Init.FirstBit = SPI_FIRSTBIT_MSB;
  47.   spi_handle->Init.TIMode = SPI_TIMODE_DISABLE;
  48.   spi_handle->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  49.   spi_handle->Init.CRCPolynomial = <font color="rgb(184, 215, 163)">10</font>;
  50.   ASSERT (HAL_SPI_Init(spi_handle) != HAL_OK);

  51. GPIO_InitTypeDef  GPIO_InitStructure;

  52. __HAL_RCC_GPIOC_CLK_ENABLE();

  53. GPIO_InitStructure.Pin = SPI_CS1;
  54. GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
  55. GPIO_InitStructure.Pull = GPIO_NOPULL;
  56. GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;
  57. HAL_GPIO_Init(SPI_CS1_PORT, &GPIO_InitStructure);
  58.   
  59. GPIO_InitStructure.Pin = SPI_CS2;
  60. HAL_GPIO_Init(SPI_CS2_PORT, &GPIO_InitStructure);  

  61. GPIO_InitStructure.Pin = SPI_CS3;
  62. HAL_GPIO_Init(SPI_CS3_PORT, &GPIO_InitStructure);   
  63. }
  64. </font></font><p style="line-height: 26px;"><font color="black"><font face="Tahoma"><font size="3">从而原来SPI的收发函数前后加上片选信号即可:</font></font></font></p><font face="Tahoma"><font size="3"><font color="rgb(86, 156, 214)">typedef</font> <font color="rgb(86, 156, 214)">enum</font>
  65. {  
  66. SPI_CH_1=<font color="rgb(184, 215, 163)">0</font>,
  67. SPI_CH_2,
  68. SPI_CH_3,
  69. SPI_CH_LAST,
  70. } SPI_CH;
  71. static HAL_StatusTypeDef SPI_Select(SPI_CH ch)
  72. {
  73.    <font color="rgb(86, 156, 214)">switch</font> (ch)
  74.    {
  75.      <font color="rgb(86, 156, 214)">case</font> SPI_CH_1:
  76.        HAL_GPIO_WritePin(SPI_CS1_PORT,SPI_CS1,GPIO_PIN_RESET);
  77.        <font color="rgb(86, 156, 214)">break</font>;
  78.       
  79.      <font color="rgb(86, 156, 214)">case</font> SPI_CH_2:
  80.        HAL_GPIO_WritePin(SPI_CS2_PORT,SPI_CS2,GPIO_PIN_RESET);
  81.        <font color="rgb(86, 156, 214)">break</font>;
  82.       
  83.      <font color="rgb(86, 156, 214)">case</font> SPI_CH_3:
  84.        HAL_GPIO_WritePin(SPI_CS3_PORT,SPI_CS3,GPIO_PIN_RESET);
  85.        <font color="rgb(86, 156, 214)">break</font>;      
  86.      
  87.      <font color="rgb(86, 156, 214)">default</font>:
  88.        <font color="rgb(86, 156, 214)">return</font> HAL_ERROR;
  89.    }  
  90.    <font color="rgb(86, 156, 214)">return</font> HAL_OK;
  91. }
  92. static HAL_StatusTypeDef SPI_DeSelect(SPI_CH ch)
  93. {
  94.    <font color="rgb(86, 156, 214)">switch</font> (ch)
  95.    {
  96.      <font color="rgb(86, 156, 214)">case</font> SPI_CH_1:
  97.        HAL_GPIO_WritePin(SPI_CS1_PORT,SPI_CS1,GPIO_PIN_SET);
  98.        <font color="rgb(86, 156, 214)">break</font>;
  99.       
  100.      <font color="rgb(86, 156, 214)">case</font> SPI_CH_2:
  101.        HAL_GPIO_WritePin(SPI_CS2_PORT,SPI_CS2,GPIO_PIN_SET);
  102.        <font color="rgb(86, 156, 214)">break</font>;
  103.       
  104.      <font color="rgb(86, 156, 214)">case</font> SPI_CH_3:
  105.        HAL_GPIO_WritePin(SPI_CS3_PORT,SPI_CS3,GPIO_PIN_SET);
  106.        <font color="rgb(86, 156, 214)">break</font>;      
  107.      
  108.      <font color="rgb(86, 156, 214)">default</font>:
  109.        <font color="rgb(86, 156, 214)">return</font> HAL_ERROR;
  110.    }
  111.    <font color="rgb(86, 156, 214)">return</font> HAL_OK;
  112. }

  113. HAL_StatusTypeDef SPI_TransmitReceive(SPI_CH ch,
  114.                     SPI_HandleTypeDef *hspi,
  115.                     uint8_t *pTxData,
  116.                     uint8_t *pRxData,
  117.                     uint16_t Size,
  118.                     uint32_t Timeout)
  119. {
  120.    HAL_StatusTypeDef ret;
  121.    <font color="rgb(86, 156, 214)">if</font>(ch>=SPI_CH_LAST)
  122.      <font color="rgb(86, 156, 214)">return</font> HAL_ERROR;  
  123.    
  124.    SPI_Select(ch);
  125.    ret = HAL_SPI_TransmitReceive(hspi,pTxData,pRxData,Size,Timeout);
  126.    SPI_DeSelect(ch);
  127.    
  128.    <font color="rgb(86, 156, 214)">return</font> ret;
  129. }

  130. HAL_StatusTypeDef SPI_Transmit(SPI_CH ch,
  131.                  SPI_HandleTypeDef *hspi,
  132.                  uint8_t *pData,
  133.                  uint16_t Size,
  134.                  uint32_t Timeout)
  135. {
  136.    HAL_StatusTypeDef ret;
  137.    <font color="rgb(86, 156, 214)">if</font>(ch>=SPI_CH_LAST)
  138.      <font color="rgb(86, 156, 214)">return</font> HAL_ERROR;  
  139.    
  140.    SPI_Select(ch);
  141.    ret = HAL_SPI_Transmit(hspi,pData,Size,Timeout);
  142.    SPI_DeSelect(ch);
  143.    
  144.    <font color="rgb(86, 156, 214)">return</font> ret;  
  145. }</font></font>
复制代码

如此一来,一个SPI外设就可以控制多个从芯片了。你如果有兴趣,不妨照这个思路试试看



收藏 评论0 发布时间:2022-6-23 21:00

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版