zoukankan      html  css  js  c++  java
  • STM32 M0之SPI

    从M3到M0,可能SPI的接口函数大致类似,但是细节略有不同

    仔细观察寄存器描述,虽然个别存在差异,但是真心不知道竟然有太多的“玄机”

    这次的问题主要出在了数据宽度上:

    1. M3/M4的数据宽度支持8/16,是SPI_CR1中DFF: Data frame format控制的,实际使用中,只要我配置好数据宽度,直接操作DR寄存器即可。

    2. M0的看起来更加强大,在SPI_CR2中DS [3:0]: Data size控制,支持4..16个bits的数据。

    所以开始的时候我使用M3的操作方式,直接把驱动函数移了过来,下面为初始化代码

     1 /*
     2  *********************************************************************************************************
     3  * Function Name:    bsp_spi_init
     4  * Description    :    SPI初始化
     5  * Input        :    None
     6  * Output        :    None
     7  * Return        :    None
     8  *********************************************************************************************************
     9  */
    10 static void
    11 bsp_spi_init(void)
    12 {
    13     SPI_InitTypeDef    SPI_InitStructure;
    14 
    15     BSP_SPI_FRAM_CS(1);                                /* SPI_CS初始化                                    */
    16     SPI_StructInit(&SPI_InitStructure);
    17     SPI_InitStructure.SPI_Mode        = SPI_Mode_Master;
    18     SPI_InitStructure.SPI_DataSize    = SPI_DataSize_8b;
    19     SPI_InitStructure.SPI_CPOL        = SPI_CPOL_High;
    20     SPI_InitStructure.SPI_CPHA        = SPI_CPHA_2Edge;
    21     SPI_InitStructure.SPI_NSS        = SPI_NSS_Soft;
    22     SPI_InitStructure.SPI_FirstBit    = SPI_FirstBit_LSB;
    23     SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
    24     SPI_Init(BSP_SPI_FRAM, &SPI_InitStructure);
    25     /** Enable the SPI    */
    26     SPI_Cmd(BSP_SPI_FRAM, ENABLE);
    27 }

    本以为这样就OK了,后来发现二者还是有区别的:

    M3的话你直接写DR寄存器,会自动根据你的配置数据长度8/16发送数据

    M0的话,你直接写DR寄存器,他不会根据你写的数据长度发送,依旧发送的是16bits

    后来观察ST官方给的驱动代码:

    M3的接口函数没有区分,都是直接操作DR

    // M3的发送代码
    /**
      * @brief  Transmits a Data through the SPIx/I2Sx peripheral.
      * @param  SPIx: where x can be
      *   - 1, 2 or 3 in SPI mode 
      *   - 2 or 3 in I2S mode
      * @param  Data : Data to be transmitted.
      * @retval None
      */
    void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data)
    {
      /* Check the parameters */
      assert_param(IS_SPI_ALL_PERIPH(SPIx));
      
      /* Write in the DR register the data to be sent */
      SPIx->DR = Data;
    }

    M0的官方代码比较复杂:

    /**
      * @brief  Transmits a Data through the SPIx/I2Sx peripheral.
      * @param  SPIx: where x can be 1 or 2 in SPI mode to select the SPI peripheral.
      * @param  Data: Data to be transmitted.
      * @retval None
      */
    void SPI_SendData8(SPI_TypeDef* SPIx, uint8_t Data)
    {
      uint32_t spixbase = 0x00;
    
      /* Check the parameters */
      assert_param(IS_SPI_ALL_PERIPH(SPIx));
    
      spixbase = (uint32_t)SPIx; 
      spixbase += 0x0C;
      
      *(__IO uint8_t *) spixbase = Data;
    }
    
    /**
      * @brief  Transmits a Data through the SPIx/I2Sx peripheral.
      * @param  SPIx: where x can be 1 or 2 in SPI mode or 1 in I2S mode to select 
      *   the SPI peripheral. 
      * @param  Data: Data to be transmitted.
      * @retval None
      */
    void SPI_I2S_SendData16(SPI_TypeDef* SPIx, uint16_t Data)
    {
      /* Check the parameters */
      assert_param(IS_SPI_ALL_PERIPH(SPIx));
      
      SPIx->DR = (uint16_t)Data;
    }

    虽然都是操作的DR,但是M0这里把DR强转成8bits宽度的指针,之后操作。

    因为我只是发送8bits的数据,所以这样算是OK了

    至于其他的非8/16的宽度如何操作,暂时就不去纠结了。。。。

    我最后的做法简单粗暴,直接对DR强行转换:

    1         (*((volatile unsigned char*)(&BSP_SPI_FRAM->DR) ))= dat;

    这样免得调用他那个发送的库,各个平台的代码归档起来也方便一些。

    至于这样设计的原因,我考虑还是M0的字节对齐问题吧?

    博客园:http://www.cnblogs.com/linux-farmer/
  • 相关阅读:
    Haskell语言学习笔记(38)Lens(1)
    Haskell语言学习笔记(37)RWS, RWST
    Haskell语言学习笔记(36)Data.List.Zipper
    Haskell语言学习笔记(35)Contravariant
    编程漫谈系列(4)协变(covariance),逆变(contravariance)与不变(invariance)
    Boost.Coroutine2:学习使用Coroutine(协程)
    C++17尝鲜:类模板中的模板参数自动推导
    bzoj 2797 [Poi2012]Squarks 枚举一个,推出所有
    FWT 学习笔记
    A* k短路 学习笔记
  • 原文地址:https://www.cnblogs.com/linux-farmer/p/9492504.html
Copyright © 2011-2022 走看看