ADC+DMA 目标数组无更新 解决办法

直接上代码

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : adc_dma.c
  * @brief          : adc_dma program body
  ******************************************************************************
  * @attention
  * F7 开启L1-cache会导致DMA数据不更新。例如串口,adc
  * https://bbs.21ic.com/icview-2380632-1-1.html
  * 如果程序默认内存地址设置为0x20020000开始,即运行于SRAM1,才会出现这种现象。
  * 如果默认内存地址为0x20000000开始,即运行于DTCM,结果是正常的,开启D-cache正常。
  * DMA如果使用了SRAM1,要么就不使用D-cache,要使用D-cache就要手动clean,或者设置为write-through
  * 另一种解决办法如本代码所示,
  * https://blog.csdn.net/weifengdq/article/details/121802176
  
  * @author HLY
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "adc_dma.h"
/* Private includes ----------------------------------------------------------*/
#include "adc.h"
/* Private define ------------------------------------------------------------*/
#define ADC1_BUFFER_SIZE 32*1	//ADC1用了4通道, 存32组, 方便做平均
//#define ADC3_BUFFER_SIZE 32*8	//ADC3用了8通道, 存32组, 方便做平均

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/
/*
@Note If the  application is using the DTCM/ITCM memories (@0x20000000/ 0x0000000: not cacheable and only accessible
      by the Cortex M7 and the  MDMA), no need for cache maintenance when the Cortex M7 and the MDMA access these RAMs.
      If the application needs to use DMA(or other masters) based access or requires more RAM, then  the user has to:
              - Use a non TCM SRAM. (example : D1 AXI-SRAM @ 0x24000000)
              - Add a cache maintenance mechanism to ensure the cache coherence between CPU and other masters(DMAs,DMA2D,LTDC,MDMA).
              - The addresses and the size of cacheable buffers (shared between CPU and other masters)
                must be	properly defined to be aligned to L1-CACHE line size (32 bytes). 
*/
//32字节对齐(地址+大小)
//adc1_data指定到 AXI SRAM 的0x20020000 //设置不正确会进不了debug
//adc3_data指定到 SRAM4 的0x38000000    //
ALIGN_32BYTES (uint16_t adc1_data[ADC1_BUFFER_SIZE]) __attribute__((section(".ARM.__at_0x20020000")));
//ALIGN_32BYTES (uint16_t adc3_data[ADC3_BUFFER_SIZE]) __attribute__((section(".ARM.__at_0x38000000")));
/* Private variables ---------------------------------------------------------*/

/* Private function prototypes -----------------------------------------------*/
/**
  * @brief  adc_dma初始化
  * @param  None
  * @retval None
  * @note   函数放在初始化阶段
*/
void adc_dma_init()
{
  if (HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc1_data, ADC1_BUFFER_SIZE) != HAL_OK)
  {
    Error_Handler();
  }
}
/**
  * @brief  返回adc值
  * @param  None
  * @retval None
  * @note   None
*/
float get_adc_value()
{
  uint32_t ADC_Value = 0;

  for(int i = 0; i < ADC1_BUFFER_SIZE; ++i)
    ADC_Value += adc1_data[i];
  
  ADC_Value = ADC_Value / ADC1_BUFFER_SIZE;
  
  return ADC_Value * 3.3 / 4096;
}
/**
  * @brief  ADC_DMA 半满回调函数
  * @param  None
  * @retval None
  * @note   ADC转换半满中断中把数据存到数组的前半部分
            ping-pong存储
            FIFO
*/
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
  /* Invalidate Data Cache to get the updated content of the SRAM on the first half of the ADC converted data buffer */
  if(hadc->Instance == ADC1) {
      SCB_InvalidateDCache_by_Addr((uint32_t *) &adc1_data[0], ADC1_BUFFER_SIZE);
  } 
}
/**
  * @brief  ADC_DMA 转换完成回调函数
  * @param  None
  * @retval None
  * @note   ADC转换完成中断中把数据存到数组的后半部分
*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
   /* Invalidate Data Cache to get the updated content of the SRAM on the second half of the ADC converted data buffer */
   if(hadc->Instance == ADC1) 
  {
       SCB_InvalidateDCache_by_Addr((uint32_t *) &adc1_data[ADC1_BUFFER_SIZE/2], ADC1_BUFFER_SIZE);
   } 
}
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
    cube生成debug模式使用JINK(5PIN),不然容易KIEL闪退。

    独立看门狗 4s一次。超过4s没更新 即复位

                nvic优先级设置
    中断                  抢占优先级   子优先级
    系统时钟              0             0
    TIM4(FREEMODBUS时钟)0             1[不可改变,已测试]
    串口1                 0             2[不可改变,已测试]
    TIM1捕获(PWM)       2             2
    TIM3(编码器)        3             1
    外部中断1和2          3             2
    TIM1更新中断(没用)  3             3

               GPIO
    TIM2_CH2                PA1
    MOTOR_TURN              PA2
    ADC1_IN5                PA5
    TIM3_CH1                PA6
    TIM3_CH2                PA7
    USART1_TX               PA9
    USART1_RX               PA10
    Photoelectric_Sensor1   PB0
    LED                     PB1
    Photoelectric_Sensor2   PC4
    RCC_OSC_IN              PH0
    RCC_OSC_OUT             PH1

    USART1:用于MODBUS传输
    TIM1:用于计数脉冲个数。                            https://www.jianshu.com/p/eae5386aa8ee
    TIM2:输出PWM                                       https://www.jianshu.com/p/eae5386aa8ee
    TIM3:正交解码模式。                                https://blog.csdn.net/csol1607408930/article/details/112793292
    tim4:用于连接porttimer.c文件的函数,启用FREEMODBUS  https://blog.csdn.net/ASWaterbenben/article/details/105549750
    
  * @author HLY
  ******************************************************************************
**/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "iwdg.h"
#include "tim.h"
#include "usart.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* CUBE Includes */
#include "gpio.h"
#include "dma.h"
/* FREEMODBUS Includes */
#include "mb.h"
#include "port.h"
#include "demo.h"
/* C Includes */
#include "stdio.h"
/* user Includes */
#include "motor.h"
#include "encoder.h"
#include "led.h"
#include "adc_dma.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
u8 once_flag = 1;//仅运行一次标志位。只有当其为0,才运行其他代码
uint8_t zero_error = HAL_BUSY;//零位传感器错误码
float ane = -90,adc = -1;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* Enable I-Cache---------------------------------------------------------*/
  SCB_EnableICache();

  /* Enable D-Cache---------------------------------------------------------*/
  SCB_EnableDCache();

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */
  MX_GPIO_Init();
  MX_DMA_Init();  //DMA必需放在要使用设备前面!!!
  MX_TIM1_Init(); //TIM1必需在TIM2前面初始化!!!
  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_TIM4_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  MX_TIM3_Init();
  MX_TIM2_Init();
  MX_IWDG_Init();
  /* USER CODE BEGIN 2 */
  eMBInit( MB_RTU, 0x01, 1, 9600, MB_PAR_NONE); //初始化modbus,走modbusRTU,从站地址为0x01,端口为1。
  eMBEnable(  );                                //使能modbus
  use_led_init();                               //LED初始化
  adc_dma_init();                               //adc_dma初始化
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    HAL_IWDG_Refresh(&hiwdg); //看门狗喂狗[debug设置断点时请注释看门狗]
    modbus_handler();         //modbus处理函数
    (void)eMBPoll();          //启动modbus
    //adc = get_adc_value();
    
    if(!once_flag)
    {  
      motor_Absolute_angle_out(ane);
    }
    else if(once_flag)
    {
     if(Zero_Detection(0X2FFFFF) == HAL_OK)
     {
        HAL_Delay(500);
        once_flag = 0;
        pusle_it = 0;//初始化电机脉冲计数值
        motor_out_ok = HAL_OK;
     }
     else if(zero_error == HAL_TIMEOUT)
     {
       use_led_setmode();//如果归零传感器异常超时,led灯两闪两灭
       while(1);//错误
     }
    }
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure LSE Drive Capability
  */
  HAL_PWR_EnableBkUpAccess();
  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 25;
  RCC_OscInitStruct.PLL.PLLN = 432;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Activate the Over-Drive mode
  */
  if (HAL_PWREx_EnableOverDrive() != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值