如何实现独立片选一主多从

发布时间:2024-01-10  

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


SPI总线拓扑

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

微信截图_20230105161930.png

如上图:

  • 每个从设备都有独立的片选引脚,主机同一时间段内,与一个从设备进行通信,也即选中一个从设备。

  • MOSI/MISO/SCLK并联在一起

  • MISO须是三态门,当从设备未选中时,该脚须设置为高阻态,而不能是输出态,否则会影响总线 !

  • 对于MOSI/SCLK,虽然并联在一起,但是由于仅一个输出,多输入。

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

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

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

怎么破呢?

菊花链拓扑

微信截图_20230105161930.png

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

独立片选拓扑

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


上代码看看:


void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)

{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  if(hspi->Instance==SPI1)

  {

    __HAL_RCC_SPI1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();

    /**SPI1 GPIO Configuration

    PA5     ------> SPI1_SCK

    PA6     ------> SPI1_MISO

    PA7     ------> SPI1_MOSI

    PA15     ------> SPI1_NSS 但是这里不用

    */

    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;

    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);


   /*__HAL_RCC_GPIOC_CLK_ENABLE();

    GPIO_InitStruct.Pin = GPIO_PIN_1;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;

    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);*/ 

  }

}

初始化SPI外设


#define SPI_CS1                        GPIO_PIN_1

#define SPI_CS1_PORT                   GPIOC

#define SPI_CS2                        GPIO_PIN_2

#define SPI_CS2_PORT                   GPIOC

#define SPI_CS3                        GPIO_PIN_3

#define SPI_CS3_PORT                   GPIOC

static void init_spi(SPI_HandleTypeDef * spi_handle)

{

  /* SPI1 parameter configuration*/

  spi_handle->Instance = SPI1;

  spi_handle->Init.Mode = SPI_MODE_MASTER;

  spi_handle->Init.Direction = SPI_DIRECTION_2LINES;

  spi_handle->Init.DataSize = SPI_DATASIZE_8BIT;

  spi_handle->Init.CLKPolarity = SPI_POLARITY_LOW;

  spi_handle->Init.CLKPhase = SPI_PHASE_1EDGE;

  spi_handle->Init.NSS = SPI_NSS_HARD_OUTPUT;

  spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;

  spi_handle->Init.FirstBit = SPI_FIRSTBIT_MSB;

  spi_handle->Init.TIMode = SPI_TIMODE_DISABLE;

  spi_handle->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;

  spi_handle->Init.CRCPolynomial = 10;

  ASSERT (HAL_SPI_Init(spi_handle) != HAL_OK);


 GPIO_InitTypeDef  GPIO_InitStructure;


 __HAL_RCC_GPIOC_CLK_ENABLE();


 GPIO_InitStructure.Pin = SPI_CS1;

 GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;

 GPIO_InitStructure.Pull = GPIO_NOPULL;

 GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;

 HAL_GPIO_Init(SPI_CS1_PORT, &GPIO_InitStructure); 

  

 GPIO_InitStructure.Pin = SPI_CS2;

 HAL_GPIO_Init(SPI_CS2_PORT, &GPIO_InitStructure);  

 

 GPIO_InitStructure.Pin = SPI_CS3;

 HAL_GPIO_Init(SPI_CS3_PORT, &GPIO_InitStructure);   

}

从而原来SPI的收发函数前后加上片选信号即可:


复制

typedef enum 

{  

 SPI_CH_1=0,

 SPI_CH_2,

 SPI_CH_3,

 SPI_CH_LAST,

} SPI_CH;

static HAL_StatusTypeDef SPI_Select(SPI_CH ch)

{

   switch (ch)

   {

     case SPI_CH_1:

       HAL_GPIO_WritePin(SPI_CS1_PORT,SPI_CS1,GPIO_PIN_RESET);

       break;

       

     case SPI_CH_2:

       HAL_GPIO_WritePin(SPI_CS2_PORT,SPI_CS2,GPIO_PIN_RESET);

       break;

       

     case SPI_CH_3:

       HAL_GPIO_WritePin(SPI_CS3_PORT,SPI_CS3,GPIO_PIN_RESET);

       break;       

     

     default:

       return HAL_ERROR;

   }  

   return HAL_OK;

}

static HAL_StatusTypeDef SPI_DeSelect(SPI_CH ch)

{

   switch (ch)

   {

     case SPI_CH_1:

       HAL_GPIO_WritePin(SPI_CS1_PORT,SPI_CS1,GPIO_PIN_SET);

       break;

       

     case SPI_CH_2:

       HAL_GPIO_WritePin(SPI_CS2_PORT,SPI_CS2,GPIO_PIN_SET);

       break;

       

     case SPI_CH_3:

       HAL_GPIO_WritePin(SPI_CS3_PORT,SPI_CS3,GPIO_PIN_SET);

       break;       

     

     default:

       return HAL_ERROR;

   }

   return HAL_OK;

}


HAL_StatusTypeDef SPI_TransmitReceive(SPI_CH ch,

                    SPI_HandleTypeDef *hspi, 

                    uint8_t *pTxData, 

                    uint8_t *pRxData, 

                    uint16_t Size,

                    uint32_t Timeout)

{

   HAL_StatusTypeDef ret; 

   if(ch>=SPI_CH_LAST)

     return HAL_ERROR;  

    

   SPI_Select(ch);

   ret = HAL_SPI_TransmitReceive(hspi,pTxData,pRxData,Size,Timeout);

   SPI_DeSelect(ch);

   

   return ret;

}


HAL_StatusTypeDef SPI_Transmit(SPI_CH ch,

                 SPI_HandleTypeDef *hspi, 

                 uint8_t *pData, 

                 uint16_t Size, 

                 uint32_t Timeout)

{

   HAL_StatusTypeDef ret; 

   if(ch>=SPI_CH_LAST)

     return HAL_ERROR;  

    

   SPI_Select(ch);

   ret = HAL_SPI_Transmit(hspi,pData,Size,Timeout);

   SPI_DeSelect(ch);

   

   return ret;  

}

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


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

相关文章

    办? 单片机如何使用,这是每个初学者都会问的问题,大家还会问单片机怎么入门? 其实所有知识的学习入门,如果没有别人帮助,自己独立学习的话,是一个极其痛苦的事情。 我在......
    做项目就一脸懵。 后面又做了一个智能小车项目,买了配件,也没视频教程,就看商家提供的教程死磕。 最后又自己独立写了一遍,做完以后明显感觉自己水平提升了。 主要有几方面的提升: 1.学会......
    目的同时会解决各种各样的问题,这就是提高的过程,这个项目做完基本外设配置过程就熟悉了; 4.最后再做个项目尽量不去参考教程或网上的配置过程自己独立完成,加深印象。这个......
    人的水平,真的不敢强答 =_=,才学有限,仅仅提几点建议吧)建议:   1、要动手实践,要动手实践,要动手实践!下面有位答主也提到了,工科类的东西光看是不够的!算法如何实现,自己独立......
    如何学好PLC编程的思路和办法;今天,小编为大家收集了一些关于如何学好PLC编程的思路和办法,希望大家收下这波安利后,能对PLC编程有个大概的学习思路,自己独立应用PLC完成编程。 1、基本......
    兴的莫过于国内的苹果用户,终于不再“低人一等”,而友商们是怎么看的呢?酷派今天率先站了出来。 酷派称,“跟随是一种最好的恭维”,酷派欢迎iPhone迈入双卡双待世界。 同时,酷派还列出了自己的一些成就,比如2005年推......
    硬件原理 首先我们要把智能小车的硬件原理搞懂,简单的智能小车一般有电机驱动、超声波测距、以及LED和蜂鸣器的提示。 我们只需要搞懂它们的控制原理就行,不需要完全吃透到自己能设计的程度。 2.看源代码 前期你可能还不能自己独立......
    苹果的晚年(2024-09-12)
    的创造力和勃勃生机,为了让自己回到原始状态,定期让自己清零,复位一次,重塑一个新的自我。” 人生需要“归零”。每过一段时间,都要将过去“清零”,让自己重新开始。不要让过去成为现在的包袱,轻装......
    硬件原理 首先我们要把智能小车的硬件原理搞懂,简单的智能小车一般有电机驱动、超声波测距、以及LED和蜂鸣器的提示。 我们只需要搞懂它们的控制原理就行,不需要完全吃透到自己能设计的程度。 2.看源代码 前期你可能还不能自己独立......
    怎么让直流调速更稳;怎么让直流电机调速器在运行中更稳,使用过程中发挥最大功效,一直是众多使用者的疑问,今天就此问题略作阐述。 想要直流调速运行稳,先要从设备源头开始,即直流电机质量好,精度高,然后......

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>