OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4458|回复: 7

SPI通过硬件控制片选,每个字节都会自动拉高,有什么方法可以让他一次写入多个字节呢?

[复制链接]

41

主题

278

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2357
金钱
2357
注册时间
2019-10-29
在线时间
380 小时
发表于 2020-8-21 10:30:41 | 显示全部楼层 |阅读模式
1金钱
本帖最后由 chenyuan 于 2020-8-21 11:33 编辑

前段时间在弄 SPI+DMA 配置好后,(刚开始是软件控制片选)我直接在读写数据前后加上拉低/拉高电平,但是出现这个现象,如图1/2。然后我就在读写函数后加上了等待,然后出现如图3/4现象。在片选拉低后,要等比较长时间才能开始读写数据。所以我就想通过控制硬件片选来读写数据,但是每读写一个数据,片选就自动拉高了,那么有什么方法可以拉低硬件片选,读写完多个字节再拉高吗?下面代码是 硬件片选和SPI+DMA的配置
  1. /* SPI1 init function */
  2. void MX_SPI1_Init(void)
  3. {

  4.         hspi1.Instance = SPI1;
  5.         hspi1.Init.Mode = SPI_MODE_MASTER;                        //设置SPI工作模式,设置为主模式
  6.         hspi1.Init.Direction = SPI_DIRECTION_2LINES;              //设置SPI单向或者双向的数据模式:SPI设置为双线模式
  7.         hspi1.Init.DataSize = SPI_DATASIZE_8BIT;                  //设置SPI的数据大小:SPI发送接收8位帧结构
  8.         hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;                //串行同步时钟的空闲状态为低电平
  9.         hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;                    //串行同步时钟的第一个跳变沿(上升或下降)数据被采样
  10.          hspi1.Init.NSS = SPI_NSS_HARD_OUTPUT;                            //NSS信号由软件控制    SPI_NSS_HARD_OUTPUT   SPI_NSS_SOFT
  11.         hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;   //定义波特率预分频的值:波特率预分频值为4
  12.         hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;                   //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
  13.        hspi1.Init.TIMode = SPI_TIMODE_DISABLE;                   //关闭TI模式
  14.        hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;   //关闭硬件CRC校验
  15.        hspi1.Init.CRCPolynomial = 7;                             //CRC值计算的多项式
  16.        hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  17.        hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;//SPI_NSS_PULSE_DISABLE;             //
  18.    
  19.         if (HAL_SPI_Init(&hspi1) != HAL_OK)
  20.        {
  21.                  _Error_Handler(__FILE__, __LINE__);
  22.        }
  23. }


  24. void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
  25. {

  26.   GPIO_InitTypeDef GPIO_InitStruct;
  27.   if(spiHandle->Instance==SPI1)
  28.   {
  29.   /* USER CODE BEGIN SPI1_MspInit 0 */

  30.   /* USER CODE END SPI1_MspInit 0 */
  31.     /* SPI1 clock enable */
  32.     __HAL_RCC_SPI1_CLK_ENABLE();
  33.   
  34.     /**SPI1 GPIO Configuration   
  35.     PB3     ------> SPI1_SCK
  36.     PB4     ------> SPI1_MISO
  37.     PB5     ------> SPI1_MOSI
  38.     */
  39. GPIO_InitStruct.Pin = GPIO_PIN_15;
  40. GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  41. GPIO_InitStruct.Pull = GPIO_NOPULL;
  42. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  43. GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;
  44. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  45.       
  46.     GPIO_InitStruct.Pin = A7106_SCK_Pin|A7106_MISO_Pin|A7106_MOSI_Pin;
  47.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  48.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  49.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  50.     GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;
  51.     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  52.     /* SPI1 DMA Init */
  53.     /* SPI1_TX Init */
  54.     hdma_spi1_tx.Instance = DMA1_Channel3;                          //通道选择
  55.     hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;             //存储器到外设
  56.     hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;                 //外设非增量模式
  57.     hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;                     //存储器增量模式
  58.     hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;    //外设数据长度:8位
  59.     hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;       //存储器数据长度:8位
  60.     hdma_spi1_tx.Init.Mode = DMA_NORMAL;                            //DMA普通模式
  61.     hdma_spi1_tx.Init.Priority = DMA_PRIORITY_HIGH;
  62.     if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
  63.     {
  64.       _Error_Handler(__FILE__, __LINE__);
  65.     }

  66.     __HAL_LINKDMA(spiHandle,hdmatx,hdma_spi1_tx);

  67.     /* SPI1_RX Init */
  68.     hdma_spi1_rx.Instance = DMA1_Channel2;
  69.     hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
  70.     hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
  71.     hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
  72.     hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  73.     hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
  74.     hdma_spi1_rx.Init.Mode = DMA_NORMAL;
  75.     hdma_spi1_rx.Init.Priority = DMA_PRIORITY_HIGH;
  76.     if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
  77.     {
  78.       _Error_Handler(__FILE__, __LINE__);
  79.     }

  80.     __HAL_LINKDMA(spiHandle,hdmarx,hdma_spi1_rx);

  81.   /* USER CODE BEGIN SPI1_MspInit 1 */

  82.   /* USER CODE END SPI1_MspInit 1 */
  83.   }
  84. }
复制代码


4.png
3.png
2.png
1.png

最佳答案

查看完整内容[请看2#楼]

问题已解决,见:http://www.openedv.com/forum.php?mod=viewthread&tid=331756
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

41

主题

278

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2357
金钱
2357
注册时间
2019-10-29
在线时间
380 小时
 楼主| 发表于 2020-8-21 10:30:42 | 显示全部楼层
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165537
金钱
165537
注册时间
2010-12-1
在线时间
2117 小时
发表于 2020-8-24 01:08:31 | 显示全部楼层
选软件CS
回复

使用道具 举报

41

主题

278

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2357
金钱
2357
注册时间
2019-10-29
在线时间
380 小时
 楼主| 发表于 2020-8-24 09:03:16 | 显示全部楼层

原子哥  选软件CS的时候会出现上面图片的现象,拉低后要过差不多10us才开始读写数据
回复

使用道具 举报

8

主题

154

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
439
金钱
439
注册时间
2018-12-21
在线时间
126 小时
发表于 2020-8-24 14:17:01 | 显示全部楼层
我记得STM32F1系列的MCU,那个SPI CS由硬件控制的时候只要开始传输以后就不会自动拉高了,即使所有数据传输完毕依然保持为低,除非关闭SPI硬件。
Hardware NSS management (SSM = 0)
Two configurations are possible depending on the NSS output configuration (SSOE bit
in register SPI_CR2).
– NSS output enabled (SSM = 0, SSOE = 1)
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.
– NSS output disabled (SSM = 0, SSOE = 0)
This configuration allows multimaster capability for devices operating in master
mode. For devices set as slave, the NSS pin acts as a classical NSS input: the
slave is selected when NSS is low and deselected when NSS high.


之前还看过论坛有人抱怨为啥SPI的CS不会自己在完成传输后自己拉高呢!
回复

使用道具 举报

41

主题

278

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2357
金钱
2357
注册时间
2019-10-29
在线时间
380 小时
 楼主| 发表于 2020-8-24 17:56:43 | 显示全部楼层
0x00000000 发表于 2020-8-24 14:17
我记得STM32F1系列的MCU,那个SPI CS由硬件控制的时候只要开始传输以后就不会自动拉高了,即使所有数据传输 ...

我这个用的是STM32F0系列的 用的hal库开发的,但是对hal库的一些用法不太熟,可能是他函数里面对NSS管理又配置了

对哦 兄弟有碰到过在SPI+DMA读写函数前,通过软件拉低片选,但是要过个十几us才开始读写数据
回复

使用道具 举报

8

主题

154

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
439
金钱
439
注册时间
2018-12-21
在线时间
126 小时
发表于 2020-8-24 19:31:45 | 显示全部楼层
chenyuan 发表于 2020-8-24 17:56
我这个用的是STM32F0系列的 用的hal库开发的,但是对hal库的一些用法不太熟,可能是他函数里面对NSS管理 ...

按照F1系列的描述,配置好DMA和SPI以后只要使能DMA通道,传输就立即执行,跟NSS引脚没有丝毫关系。
我使用DMA+SPI时候,没有测量过引脚波形,就一次通过。反正看起来还蛮正常的,也不知道使能传输后具体过多少时间才开始传输。按照官方的参考手册的时序图,延迟只有几个时钟周期。按理说F0应该差不多,你看看你的代码和测量方式有没有问题。
回复

使用道具 举报

41

主题

278

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2357
金钱
2357
注册时间
2019-10-29
在线时间
380 小时
 楼主| 发表于 2020-8-25 11:35:56 | 显示全部楼层
本帖最后由 chenyuan 于 2020-8-25 11:37 编辑
0x00000000 发表于 2020-8-24 19:31
按照F1系列的描述,配置好DMA和SPI以后只要使能DMA通道,传输就立即执行,跟NSS引脚没有丝毫关系。
我使 ...

你用SPI+DMA的不是和外设通讯哦? 我这是通过SPI和一个RF芯片进行通讯,之前用的是硬件SPI,配置好后 直接这样用
  1.     RADIO_NSS_L;
  2.    HAL_SPI_TransmitReceive(&hspi1, pTxData,pRxData,Size, 50)
  3.    RADIO_NSS_H;
复制代码

所以我配置好DMA,直接将 HAL_SPI_TransmitReceive(&hspi1, pTxData,pRxData,Size, 50)这个函数替换成这个HAL_SPI_TransmitReceive_DMA(&hspi1, pTxData,pRxData,Size),然后就出现了帖子中 图2 的现象,然后在拉高片选前加了个等待,数据才是在CS选中范围内,如 图4。但是他的一个时间感觉有些问题,所以想请教下大家
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-15 03:58

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表