硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1632|回复: 11
收起左侧

[SPI/QSPI] SPI能通讯,加了DMA无法通讯

[复制链接]

1

主题

0

回帖

3

积分

新手上路

积分
3
发表于 2024-5-28 17:33:56 | 显示全部楼层 |阅读模式

芯片为H750,代码由CubeMX生成,生成代码配置如下,给一个LCD屏用,所以为单输出模式。


[C] 纯文本查看 复制代码
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    spi.c
  * @brief   This file provides code for the configuration
  *          of the SPI instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "spi.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

SPI_HandleTypeDef hspi2;
DMA_HandleTypeDef hdma_spi2_tx;

/* SPI2 init function */
void MX_SPI2_Init(void)
{

  /* USER CODE BEGIN SPI2_Init 0 */

  /* USER CODE END SPI2_Init 0 */

  /* USER CODE BEGIN SPI2_Init 1 */

  /* USER CODE END SPI2_Init 1 */
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_MASTER;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES_TXONLY;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH;
  hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi2.Init.NSS = SPI_NSS_SOFT;
  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 0x0;
  hspi2.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
  hspi2.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
  hspi2.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
  hspi2.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi2.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi2.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
  hspi2.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
  hspi2.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
  hspi2.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
  hspi2.Init.IOSwap = SPI_IO_SWAP_DISABLE;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI2_Init 2 */

  /* USER CODE END SPI2_Init 2 */

}

void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(spiHandle->Instance==SPI2)
  {
  /* USER CODE BEGIN SPI2_MspInit 0 */

  /* USER CODE END SPI2_MspInit 0 */
    /* SPI2 clock enable */
    __HAL_RCC_SPI2_CLK_ENABLE();

    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**SPI2 GPIO Configuration
    PC1     ------> SPI2_MOSI
    PA12     ------> SPI2_SCK
    */
    GPIO_InitStruct.Pin = LCD_SDA_Pin;
    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_SPI2;
    HAL_GPIO_Init(LCD_SDA_GPIO_Port, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = LCD_SCL_Pin;
    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_SPI2;
    HAL_GPIO_Init(LCD_SCL_GPIO_Port, &GPIO_InitStruct);

    /* SPI2 DMA Init */
    /* SPI2_TX Init */
    hdma_spi2_tx.Instance = DMA1_Stream0;
    hdma_spi2_tx.Init.Request = DMA_REQUEST_SPI2_TX;
    hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_spi2_tx.Init.Mode = DMA_NORMAL;
    hdma_spi2_tx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_spi2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_spi2_tx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(spiHandle,hdmatx,hdma_spi2_tx);

    /* SPI2 interrupt Init */
    HAL_NVIC_SetPriority(SPI2_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(SPI2_IRQn);
  /* USER CODE BEGIN SPI2_MspInit 1 */

  /* USER CODE END SPI2_MspInit 1 */
  }
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{

  if(spiHandle->Instance==SPI2)
  {
  /* USER CODE BEGIN SPI2_MspDeInit 0 */

  /* USER CODE END SPI2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SPI2_CLK_DISABLE();

    /**SPI2 GPIO Configuration
    PC1     ------> SPI2_MOSI
    PA12     ------> SPI2_SCK
    */
    HAL_GPIO_DeInit(LCD_SDA_GPIO_Port, LCD_SDA_Pin);

    HAL_GPIO_DeInit(LCD_SCL_GPIO_Port, LCD_SCL_Pin);

    /* SPI2 DMA DeInit */
    HAL_DMA_DeInit(spiHandle->hdmatx);

    /* SPI2 interrupt Deinit */
    HAL_NVIC_DisableIRQ(SPI2_IRQn);
  /* USER CODE BEGIN SPI2_MspDeInit 1 */

  /* USER CODE END SPI2_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */


显示代码如下
[C] 纯文本查看 复制代码
void IPSLCD_Picture(ushort* pic)
{
	IPSLCD_WriteREG(0x2C);
	LCD_CS(0);
	hspi2.Init.DataSize = SPI_DATASIZE_16BIT;
	HAL_SPI_Init(&hspi2);
	HAL_SPI_Transmit_DMA(&hspi2, (uchar*)pic, 57600);
//	HAL_SPI_Transmit(&hspi2, (uchar*)pic, 57600, timeout);
	hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
	HAL_SPI_Init(&hspi2);
	LCD_CS(1);
}


调用注释中的HAL_SPI_Transmit屏幕可以正常显示,但用HAL_SPI_Transmit_DMA则不行。
尝试过修改为全双工模式,并使用HAL_SPI_TransmitReceive_DMA,同样也不行。不知道该如何下手了
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117564
QQ
发表于 2024-5-29 09:03:45 | 显示全部楼层
驱动的什么显示屏,是不是类似ST7789,这个可以参考我们开源的H7-TOOL APP V1.X工程,里面是用的SPI DMA驱动的。
回复

使用道具 举报

1

主题

7

回帖

10

积分

新手上路

积分
10
发表于 2024-5-29 09:33:19 | 显示全部楼层
eric2013 发表于 2024-5-29 09:03
驱动的什么显示屏,是不是类似ST7789,这个可以参考我们开源的H7-TOOL APP V1.X工程,里面是用的SPI DMA驱 ...

能给个链接吗,我也是遇到这个问题
回复

使用道具 举报

2

主题

38

回帖

44

积分

新手上路

积分
44
发表于 2024-5-29 09:45:05 | 显示全部楼层
HAL_SPI_Transmit_DMA这个函数使用了并不是立刻马上就把数据给传过去了,结合你的代码,可能会出现DMA刚准备传输数据,你就把CS拉高了,结果就是LCD收不到数据
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117564
QQ
发表于 2024-5-29 15:10:11 | 显示全部楼层
回复

使用道具 举报

4

主题

25

回帖

37

积分

新手上路

积分
37
发表于 2024-5-29 15:10:38 | 显示全部楼层
    HAL_SPI_Transmit_DMA(&hspi2, (uchar*)pic, 57600);
//  HAL_SPI_Transmit(&hspi2, (uchar*)pic, 57600, timeout);
    hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
    HAL_SPI_Init(&hspi2);
    LCD_CS(1);


CS拉高前等DMA传输完成再拉高
回复

使用道具 举报

1

主题

7

回帖

10

积分

新手上路

积分
10
发表于 2024-6-3 10:39:16 | 显示全部楼层
eric2013 发表于 2024-5-29 15:10
https://forum.anfulai.cn/forum.php?mod=viewthread&tid=95468&extra=page%3D1

感谢,现在问题解决了
回复

使用道具 举报

9

主题

16

回帖

43

积分

新手上路

积分
43
发表于 2024-6-6 15:02:52 | 显示全部楼层
面包人 发表于 2024-5-29 15:10
HAL_SPI_Transmit_DMA(&hspi2, (uchar*)pic, 57600);
//  HAL_SPI_Transmit(&hspi2, (uchar*)pic, 576 ...

醍醐灌顶,我好像是因为这个问题
回复

使用道具 举报

9

主题

16

回帖

43

积分

新手上路

积分
43
发表于 2024-6-6 15:06:29 | 显示全部楼层
面包人 发表于 2024-5-29 15:10
HAL_SPI_Transmit_DMA(&hspi2, (uchar*)pic, 57600);
//  HAL_SPI_Transmit(&hspi2, (uchar*)pic, 576 ...

果然是这个问题原本我写成了
while(HAL_SPI_GetState(&hspi2) == HAL_SPI_STATE_BUSY);
HAL_SPI_Transmit_DMA(&hspi2,(&data),1);
应该改为
HAL_SPI_Transmit_DMA(&hspi2,(&data),1);
while(HAL_SPI_GetState(&hspi2) == HAL_SPI_STATE_BUSY);
回复

使用道具 举报

9

主题

16

回帖

43

积分

新手上路

积分
43
发表于 2024-6-7 08:51:25 | 显示全部楼层
cokesu 发表于 2024-6-6 15:06
果然是这个问题原本我写成了
while(HAL_SPI_GetState(&hspi2) == HAL_SPI_STATE_BUSY);
HAL_SPI_Transm ...

更新一下,判断这个在H7 SPI+DMA上还是不行,但是407上可以,修改为HAL_SPI_Transmit_DMA(&hspi2,ColorTable+150000,3600);
while (HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY);
这样H7才能正常使用
回复

使用道具 举报

20

主题

102

回帖

162

积分

初级会员

积分
162
QQ
发表于 2024-6-19 23:21:29 | 显示全部楼层
请教一下,就是我想把ADC采集的数据传给PC端吗,然后我开启了ADC的DMA这个传输的是从外设到内存,然后SPI我也开启了DMA,然后SPI的DMA我应该用SPI_TX把这个数据发给W5500的缓冲区,然后使用TCP传给上位机的端口吗?还是说不需要SPI的TX,再用一个新的DMA函数HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength):定义好起始内存地址还有数据长度,直接用Socket发送?就是自己ADC采集的时候定义了一个数组,这个不就是ADC采集之后DMA转移到这个缓冲区了吗,再用SPI的DMA把这里面的数据转移到W5500的缓冲区,然后再发送,这样可以吗?
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117564
QQ
发表于 2024-6-20 08:35:21 | 显示全部楼层
不吃鱼的猫大人 发表于 2024-6-19 23:21
请教一下,就是我想把ADC采集的数据传给PC端吗,然后我开启了ADC的DMA这个传输的是从外设到内存,然后SPI我 ...

处理好同步关系,直接SPI DMA发送ADC DMA数据缓存都可以的。
回复

使用道具 举报

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

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-15 02:01 , Processed in 0.050718 second(s), 24 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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