Перейти к содержанию
    

ToR_TDA

Свой
  • Постов

    295
  • Зарегистрирован

  • Посещение

Сообщения, опубликованные ToR_TDA


  1. В общем так я и не понял в чем у меня проблема в режиме контроля входного тока. По достижению примерно 0,48А тока в регистре статуса устанавливается бит IN_IINDPM и рост тока прекращается независимо от состояния регистра IIN_DPM Register и ножки ILIM_HIZ, ножку я уже подключил напрямую к VDDA тем по сути отключив этот лимит полностью  и по-идеи остается регистр IIN_DPM, но не работает. Больше пол ампера не выдает,
    Если снять контроль входного тока то ток просто потихоньку растет по мере поднятия напряжения на ионисторах и не останавливается. Зависит от того что утсановлено в Charge Current Register
    Но достигал и 2А и больше, что уже перебор для меня.

  2. Я выяснил что для моей инициализации  ChargeOption0 Register 0x024A (с контролем входного тока) регистр IIN_HOST регулирует входной ток, но только вниз до примерно 0,48А

    Я бы это объяснил ножкой ILIM_HIZ, по идеи выбирается меньшая из двух установок по регистру или по ножке, но там много 2,25В что около 3А

  3. 2 minutes ago, Plain said:

    У меня не личное недоверие, а просто статистика, что эти BQxx, вся линейка, т.е. SoC с MSP внутри, всегда были ограничены в продаже, КД и статусе производства, ну и I2C по определению не место в ответственных задачах.

    Я купил без проблем и я все понимаю, но это не по теме топика.

  4. 11 minutes ago, Plain said:

    Не отвечающий — IIN_DPM, очевидно.

    Данные из IIN_HOST переписываются в IIN_DPM то есть IIN_HOST это просто буферный регистр, а IIN_DPM только для чтения, но я читаю их оба одновременно, там одинаковые значения, то что я и пишу.

  5. 2 minutes ago, Plain said:

    итого, при двух транзисторах схема умеет как запасать энергию, так и выдавать требуемое стабилизированное напряжение.

    При использовании BQ25713 микроконтроллер делает только инициализацию и при использовании Power Delivery переинициализирует регистры.
    Я говорил именно о отдельном DC-DC на МК, который заменит все функции BQ, то есть измерение 2-х токов входного и выходного, измерение 2-х напряжений, контроль за 2-мя парами.
    У меня режим от USB только заряд.
    тут какие задачи
    1. принимать на входе 5-20В, то есть либо понижать либо повышать. Максимальное напряжение заряда в BQ в регистре.
    2. Контролировать ток как заряда так и от USB дабы выставлять максимум по протоколу, ну или ходя бы просто не перегружать USB.

  6. 6 minutes ago, x893 said:

    А случайно нет лишней пустышки (или запаянной) ?

    Я плыты со сборкой заказывал, только 3 штуки опытных, но вообще микросхема не редкость, с некоторым риском можно даже просто на алиэкспресс взять
    Или про что разговор? Не понял

  7. В общем, для тех кому интересно, что сделал на данный момент:
    Транзистор Q2 перемкнул. Микросхема работает, с нуля заряжает и показывает в статусе Fast Charge

    Инициализация ChargeOption0 Register 0x024A
    Здесь из важного делаем LDO Mode Disable

    Из того что сейчас проблема, это ток заряда, меряю по входному току от USB
    Если оставить IDPM Enable то максимальный ток от USB всего 0,5А
    Если поставить  IDPM Disable то ток от USB начинает неограниченно расти по мере заряда, я прервал на более 2А
    При этом ток заряда 2048 mA в регистре Charge Current Register

    Режим ограничения входного тока IDPM Enable вроде как штука очень удобная и нужная, но я не понимаю откуда берется такое маленькое ограничение.
    В регистр за это отвечающий IIN_HOST Register пишу 0x1E00 что примерно 1,5А

    на ножке ILIM_HIZ аналогового выбора ограничения 2,25В, что по идеи равно 3А.

    6 hours ago, Plain said:

    Собственно преобразователь

    image.thumb.png.7b84828dc4242a994c1ad94e390737f1.png

    Это в любом случае будет такая же топология, но возможно да, можно было бы управлять этим просто от МК, 2 комплементарных ШИМ и 4 входа АЦП.
    Но это такая себе приличная задача.
    Делать что-то в аналоге, это такое себе удовольствие, тут много режимов
    Входное напряжение 5-20В при выходном 10В то есть и повышаем и понижаем, все с контролем тока.
    Аналоговое управляемое решение конечно возможно, но по нынешним меркам мне легче даже было бы отдельный небольшой МК на управляемый DC-DC поставить. Что-то сразу не подумал.
    Но опять таки это задача выходила за рамки.

  8. Just now, Plain said:

    гораздо проще сделать.

    Сейчас разбираюсь конкретно с BQ25713
    Если есть предложения с учетом PD, то интересно.
     

    2 minutes ago, Plain said:

    т.е. просто выкинуть.

    Была конечно сразу такая идея и возможно так и сделаю, хоят непонятно как будет работать МС при этом, какой ток будет.
    Думал может кто с ними работал, знает что.
    Я просто думаю, что её все таки можно запустить на зарядку от нуля, хотя возможно ошибаюсь

    Записываю 0x4A03 в ChargeOption0 Register с проверкой записи, вроде тем самым обнуляю бит 
    LDO Mode Enable
    When battery voltage is below minimum system voltage (REG0x0D/0C()), the
    charger is in pre-charge with LDO mode enabled.
    0b: Disable LDO mode, BATFET fully ON. Precharge current is set by battery
    pack internal resistor. The system is regulated by the MaxChargeVoltage
    register.

    Но ничего не меняется, ток управляется, кстати из Charge Current Register, но транзистор все равно в линейном

  9. 2 minutes ago, mov said:

    LDO Mode Enable

    Спасибо за ответ.
    Во, именно у меня получается LDO Mode , потому транзистор в линейном, но в MinSystemVoltage Register по дефолту 0В и я еще его тоже обновлял на 0x0000 и это не меняет ситуацию.
    По идеи я должен как-то перейти сразу к режиму Charge, но что я должен сделать.

    1 minute ago, Plain said:

    Наверное, нужно записать 1,024 В в MinSystemVoltage, но вообще, зачем так сложно

    Хм, интересно, почему? Что я проглядел?

    3 minutes ago, Plain said:

    но вообще, зачем так сложно

    Ну, типа Power Delivery в будущем

    Это не резервирование, это основной источник питания устройства, оно автономное, решил заложить режим быстрой зарядки от USB PD, такое требование.

  10. Уважаемые форумчане,
    Работал ли кто-то с микросхема Buck-Boost конвертера для зарядки батарей.
    У меня немного специфичная задача от её типового применения, я заряжаю 4 ионистора, а не LiIon, потому у меня процесс зарядки от нуля может происходить.
    Сейчас на плате микроконтроллер подключен к ней по I2C и связь есть, регистры читаются корректно, то что и должно быть в дефолтном состоянии.
    Не совсем понимаю как я должен ее инициализировать дабы получить заряд до 2,7x4В с током 1-2А для начала. Хочу получить управление именно по регистрам, а не по внешним ножкам.
    Схема как на EVO плате, питание USB 5В
    Ножка CHRG_OK устанавливается в Ок, как положено.
    Сейчас пишу в регистры:
    Charge Current Register
    MaxChargeVoltage Register
    Микросхеме реагирует, но греется транзистор Q2 на выходе.
    Это собственно и проблема, он в линейном режиме находится, а должен быть открыт.
    Это описано, что он может быть в линейном, на как это изменить я что-то понять не могу.
    image.thumb.png.98f23f8b94cde7605c8e1852c1319191.pngimage.thumb.png.369f61aa904abbd7a5a940776b9fb520.png

    bq25713.pdf tidrxq7.pdf

  11. В общем, сам спросил сам и отвечаю:)

    Все сделал в точности по примеру "Example 2: 3p3z compensator" из приведенного выше документа только с изменением на КИХ фильтр и вывод на ЦАП по ДМА.

    Показываю ключевые моменты кода. Главная идея, что данные от АЦП передаем через DMA напрямую в FMAС  "perip to perip".

    На самом деле там в примере есть "секреточка", а в целом все проблемы связаны с тем, что ST еще не допилили ни CMSIS, ни CubeMX, ни свои библиотеки под этот новый блок до конца.

    1146543756_ScreenImg(44).thumb.png.f0a693bac2b991efdcbd9e7151d67720.png

    #define FILTER_OUT_BUFFER_SIZE 1
    #define FILTER_IN_BUFFER_SIZE 1
    #define FILTER_TAP 127
      
    ADC_HandleTypeDef hadc1;
    DMA_HandleTypeDef hdma_adc1;
    DAC_HandleTypeDef hdac2;
    DMA_HandleTypeDef hdma_dac2_ch1;
    FMAC_HandleTypeDef hfmac;
    DMA_HandleTypeDef hdma_fmac_read;
    TIM_HandleTypeDef htim4;
    
    uint16_t ADC_data[FILTER_IN_BUFFER_SIZE];  // Данные с АЦП
    uint16_t FMAC_out[FILTER_OUT_BUFFER_SIZE]; // Данные на выходе фильтра
    
    static int16_t FilterCoeffB[127] =			// Коэффициенты КИХ
    {-10,-10,-10,-9,-9,-9,-8,-8,-7,-6,-5,-4,-2,0,3,6,10,14,19,25,32,40,48,57,68,79,91,104,118,134,150,
    166,184,203,222,242,263,284,306,328,350,373,396,418,441,463,485,506,527,547,566,585,602,618,633,
    646,659,669,679,686,692,696,699,700,699,696,692,686,679,669,659,646,633,618,602,585,566,547,527,
    506,485,463,441,418,396,373,350,328,306,284,263,242,222,203,184,166,150,134,118,104,91,79,68,57,
    48,40,32,25,19,14,10,6,3,0,-2,-4,-5,-6,-7,-8,-8,-9,-9,-9,-10,-10,-10};
    
    int main(void)
    {
      __HAL_RCC_FMAC_CLK_ENABLE();
      // Структура для настройки фильтра
      FMAC_FilterConfigTypeDef sFmacConfig; 			// declare a filter configuration structure
      sFmacConfig.CoeffBaseAddress = 0; 				// Set the coefficient buffer base address
      sFmacConfig.CoeffBufferSize = FILTER_TAP; 		// Set the coefficient buffer size to the number of coeffs
      sFmacConfig.InputBaseAddress = FILTER_TAP; 		// Set the Input buffer base address to the next free address
      sFmacConfig.InputBufferSize = FILTER_TAP + 1;		// Set the input buffer size greater than the number of coeffs
      sFmacConfig.InputThreshold = 0; 					// Set the input watermark to zero since we are using DMA
      sFmacConfig.OutputBaseAddress = FILTER_TAP*2 + 1; // Set the Output buffer base address to the next free address
      sFmacConfig.OutputBufferSize = FILTER_OUT_BUFFER_SIZE;// Set the output buffer size
      sFmacConfig.OutputThreshold = 0; 					// Set the output watermark to zero since we are using DMA
      sFmacConfig.pCoeffA = NULL; 						// No A coefficients since FIR
      sFmacConfig.CoeffASize = 0;
      sFmacConfig.pCoeffB = FilterCoeffB; 				// Pointer to the coefficients in memory
      sFmacConfig.CoeffBSize = FILTER_TAP; 				// Number of coefficients
      sFmacConfig.Filter = FMAC_FUNC_CONVO_FIR; 		// Select FIR filter function
    //sFmacConfig.InputAccess = FMAC_BUFFER_ACCESS_DMA; // Enable DMA input transfer
      sFmacConfig.InputAccess = FMAC_BUFFER_ACCESS_NONE;// Disable DMA input transfer
      sFmacConfig.OutputAccess = FMAC_BUFFER_ACCESS_DMA;// Enable DMA output transfer
      sFmacConfig.Clip = FMAC_CLIP_ENABLED; 			// Enable clipping of the output at 0x7FFF and 0x8000
      sFmacConfig.P = FILTER_TAP; 						// P parameter contains number of coefficients
      sFmacConfig.Q = 0; 								// Q parameter is not used
      sFmacConfig.R = 0;  								// R parameter contains the post-shift value (none)
      if (HAL_FMAC_FilterConfig(&hfmac, &sFmacConfig) != HAL_OK) // Configure the FMAC
      Error_Handler(); 									// Configuration Error
      
      uint16_t Filter_output_Size = FILTER_OUT_BUFFER_SIZE;					  // Только так:)
      HAL_FMAC_FilterStart(&hfmac, (int16_t*)&FMAC_out, &Filter_output_Size); // Запускаем FMAC
    
      uint32_t *Fmac_Wdata;
    //  Fmac_Wdata = (uint32_t *) FMAC->WDATA;	// Так работать не будет
      Fmac_Wdata = (uint32_t *) 0x40021418;	// Секреточка:)
      HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);	// ADC Calibration
      HAL_ADC_Start_DMA(&hadc1, Fmac_Wdata, FILTER_IN_BUFFER_SIZE);	// Запускаем АЦП с сохранением по DMA
      HAL_DAC_Start_DMA(&hdac2, DAC_CHANNEL_1, (uint32_t*)&FMAC_out, FILTER_OUT_BUFFER_SIZE, DAC_ALIGN_12B_R); // Выводим входные данные FIR фильтра на ЦАП
      HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);	// Запускаем таймер для тактирования всего
      
        while (1)
      {
          
      }
     }
    
    static void MX_ADC1_Init(void)
    {
      ADC_MultiModeTypeDef multimode = {0};
      ADC_ChannelConfTypeDef sConfig = {0};
      /** Common config*/
      hadc1.Instance = ADC1;
      hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
      hadc1.Init.Resolution = ADC_RESOLUTION_12B;
      hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
      hadc1.Init.GainCompensation = 0;
      hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
      hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
      hadc1.Init.LowPowerAutoWait = DISABLE;
      hadc1.Init.ContinuousConvMode = DISABLE;
      hadc1.Init.NbrOfConversion = 1;
      hadc1.Init.DiscontinuousConvMode = DISABLE;
      hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T4_TRGO;
      hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
      hadc1.Init.DMAContinuousRequests = ENABLE;
      hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
      hadc1.Init.OversamplingMode = DISABLE;
      if (HAL_ADC_Init(&hadc1) != HAL_OK)
      {
        Error_Handler();
      }
      /** Configure the ADC multi-mode*/
      multimode.Mode = ADC_MODE_INDEPENDENT;
      if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
      {
        Error_Handler();
      }
      /** Configure Regular Channel*/
      sConfig.Channel = ADC_CHANNEL_1;
      sConfig.Rank = ADC_REGULAR_RANK_1;
      sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
      sConfig.SingleDiff = ADC_SINGLE_ENDED;
      sConfig.OffsetNumber = ADC_OFFSET_NONE;
      sConfig.Offset = 1;
      if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
      {
        Error_Handler();
      }
    }

     

  12. Приветствую форумчане!

    Захотелось мне для опыта запустить блок аппаратного фильтра на STM32G474 в режиме реального времени. То есть данные с АЦП поступают через DMA на FMAC, там LP FIR фильтр, а дальше опять через DMA на ЦАП. Честно говоря я похоже переоценил свои знания и полностью завяз в попытки это написать и даже понять как это должно выглядеть. Использую CubeIDE и, соответственно, кодогенератор MX, специализированных знаний по Cortex-M4 не имею, поможИте как говорится.

    Писал КИХ по ПЛИС-ы но там все как-то прозрачнее, а тут я даже не понимаю как сигнал по линии задержки должен двигаться и как тактируется блок так как все скрыто структурами.

    Для тактирования запустил таймер 4 на 100кГц, все хочу тактировать от него. АЦП работает скидывает данные по ПДП в единичный буфер. Вспомогательный ЦАП так же через ПДП считывает оттуда и выводит наружу, тут все ОК.

    Второй ЦАП должен выводить уже отфильтрованные , ну естессно тут ничего не работает))

    Вот что накидал из кусков кода

    https://www.st.com/resource/en/application_note/dm00605584-digital-filter-implementation-with-the-fmac-using-stm32cubeg4-mcu-package-stmicroelectronics.pdf

    https://www.compel.ru/lib/139617

    Но не понимаю даже почему кодогенератор не делает инициализации для FMAC DMA, или делает, но я не понимаю.

    Не пинайте сильно)

    Еще осциллограф прикрепил, желтый входной, синий - отсчеты АЦП (выведенные церез ЦАП), зеленый тестовая синусоида на ЦАП2, красный - таймер 4 (тактирование)

    image.thumb.png.7684e9bf111d20009b4bf74d7f641300.png

    /* USER CODE BEGIN Header */
    /**
      ******************************************************************************
      * @file           : main.c
      * @brief          : Main program body
      ******************************************************************************
      * @attention
      *
      * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
      * All rights reserved.</center></h2>
      *
      * This software component is licensed by ST under BSD 3-Clause license,
      * the "License"; You may not use this file except in compliance with the
      * License. You may obtain a copy of the License at:
      *                        opensource.org/licenses/BSD-3-Clause
      *
      ******************************************************************************
      */
    /* USER CODE END Header */
    /* Includes ------------------------------------------------------------------*/
    #include "main.h"
    
    /* Private includes ----------------------------------------------------------*/
    /* USER CODE BEGIN Includes */
    
    /* 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 ---------------------------------------------------------*/
    ADC_HandleTypeDef hadc1;
    DMA_HandleTypeDef hdma_adc1;
    
    DAC_HandleTypeDef hdac1;
    DAC_HandleTypeDef hdac2;
    DMA_HandleTypeDef hdma_dac1_ch1;
    DMA_HandleTypeDef hdma_dac2_ch1;
    
    FMAC_HandleTypeDef hfmac;
    DMA_HandleTypeDef hdma_fmac_read;
    DMA_HandleTypeDef hdma_fmac_write;
    
    UART_HandleTypeDef hlpuart1;
    
    TIM_HandleTypeDef htim1;
    TIM_HandleTypeDef htim4;
    
    /* USER CODE BEGIN PV */
    
    uint16_t ADC_data[1]; // Данные с АЦП
    uint16_t FMAC_out[1]; // Данные на выходе фильтра
    
    // Тестовый синус для проверки ЦАП-ов
    uint16_t Test_data[64] =
    {2048,2248,2447,2642,2831,3013,3185,3346,3495,3630,3750,3853,3939,4007,4056,4085,
    4095,4085,4056,4007,3939,3853,3750,3630,3495,3346,3185,3013,2831,2642,2447,2248,
    2048,1847,1648,1453,1264,1082,910,749,600,465,345,242,156,88,39,10,
    0,10,39,88,156,242,345,465,600,749,910,1082,1264,1453,1648,1847};
    
    // Коэффициенты КИХ фильтра
    static int16_t FilterCoeffB[51] =
    {0,11,25,46,78,122,182,261,360,481,623,787,970,1169,1382,1603,1828,2051,2266,2468,2649,2806,2934,3028,3086,3105,
    3086,3028,2934,2806,2649,2468,2266,2051,1828,1603,1382,1169,970,787,623,481,360,261,182,122,78,46,25,11,0};
    
    /* USER CODE END PV */
    
    /* Private function prototypes -----------------------------------------------*/
    void SystemClock_Config(void);
    static void MX_GPIO_Init(void);
    static void MX_DMA_Init(void);
    static void MX_LPUART1_UART_Init(void);
    static void MX_TIM1_Init(void);
    static void MX_ADC1_Init(void);
    static void MX_DAC1_Init(void);
    static void MX_TIM4_Init(void);
    static void MX_FMAC_Init(void);
    static void MX_DAC2_Init(void);
    /* USER CODE BEGIN PFP */
    
    /* USER CODE END PFP */
    
    /* Private user code ---------------------------------------------------------*/
    /* USER CODE BEGIN 0 */
    
    void delay_us (uint16_t us)
    {
    	__HAL_TIM_SET_COUNTER(&htim1,0);  // set the counter value a 0
    	while (__HAL_TIM_GET_COUNTER(&htim1) < us);  // wait for the counter to reach the us input in the parameter
    }
    
    /* USER CODE END 0 */
    
    /**
      * @brief  The application entry point.
      * @retval int
      */
    int main(void)
    {
      /* USER CODE BEGIN 1 */
    
      /* USER CODE END 1 */
    
      /* 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 */
    
      /* USER CODE END SysInit */
    
      /* Initialize all configured peripherals */
      MX_GPIO_Init();
      MX_DMA_Init();
      MX_LPUART1_UART_Init();
      MX_TIM1_Init();
      MX_ADC1_Init();
      MX_DAC1_Init();
      MX_TIM4_Init();
      MX_FMAC_Init();
      MX_DAC2_Init();
      /* USER CODE BEGIN 2 */
    
      HAL_TIM_Base_Start(&htim1);
      HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);
    
      HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, (uint32_t*)&ADC_data, 1, DAC_ALIGN_12B_R); // Выводим входные данные на ЦАП для контроля
    
      HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED); 		// ADC Calibration
      HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_data, 1); 			// Запускаем АЦП с сохранением по DMA
    
      HAL_DAC_Start_DMA(&hdac2, DAC_CHANNEL_1, (uint32_t*)&FMAC_out, 1, DAC_ALIGN_12B_R); // Выводим входные данные КИХ фильра на ЦАП
    //  HAL_DAC_Start_DMA(&hdac2, DAC_CHANNEL_1, (uint32_t*)&Test_data, 64, DAC_ALIGN_12B_R); // Тестовая синусоида для проверки ЦАП-а
    
      __HAL_RCC_FMAC_CLK_ENABLE();
      FMAC_FilterConfigTypeDef sFmacConfig; 			/* declare a filter configuration structure */
      sFmacConfig.CoeffBaseAddress = 0; 				/* Set the coefficient buffer base address */
      sFmacConfig.CoeffBufferSize = 51; 				/* Set the coefficient buffer size to the number of coeffs */
      sFmacConfig.InputBaseAddress = 51; 				/* Set the Input buffer base address to the next free address */
      sFmacConfig.InputBufferSize = 100; 				/* Set the input buffer size greater than the number of coeffs */
      sFmacConfig.InputThreshold = 0; 					/* Set the input watermark to zero since we are using DMA */
      sFmacConfig.OutputBaseAddress = 151; 				/* Set the Output buffer base address to the next free address */
      sFmacConfig.OutputBufferSize = 100; 				/* Set the output buffer size */
      sFmacConfig.OutputThreshold = 0; 					/* Set the output watermark to zero since we are using DMA */
      sFmacConfig.pCoeffA = NULL; 						/* No A coefficients since FIR */
      sFmacConfig.CoeffASize = 0;
      sFmacConfig.pCoeffB = FilterCoeffB; 				/* Pointer to the coefficients in memory */
      sFmacConfig.CoeffBSize = 51; 						/* Number of coefficients */
      sFmacConfig.Filter = FMAC_FUNC_CONVO_FIR; 		/* Select FIR filter function */
      sFmacConfig.InputAccess = FMAC_BUFFER_ACCESS_DMA; /* Enable DMA input transfer */
      sFmacConfig.OutputAccess = FMAC_BUFFER_ACCESS_DMA;/* Enable DMA output transfer */
      sFmacConfig.Clip = FMAC_CLIP_ENABLED; 			/* Enable clipping of the output at 0x7FFF and 0x8000 */
      sFmacConfig.P = 51; 								/* P parameter contains number of coefficients */
      sFmacConfig.Q = 0; 								/* Q parameter is not used */
      sFmacConfig.R = 0;  								/* R parameter contains the post-shift value (none) */
      if (HAL_FMAC_FilterConfig(&hfmac, &sFmacConfig) != HAL_OK) /* Configure the FMAC */
      Error_Handler(); 									/* Configuration Error */
    
      if (HAL_FMAC_AppendFilterData(&hfmac, (int16_t*)&ADC_data[0], (uint16_t*)1) != HAL_OK)
       Error_Handler();
    
      if (HAL_FMAC_FilterStart(&hfmac, (int16_t*)&FMAC_out, (uint16_t*)1) != HAL_OK)
      Error_Handler();
    
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
    //	  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
    //	  HAL_Delay(50);
    //	  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
    //	  HAL_Delay(50);
    
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */
      }
      /* USER CODE END 3 */
    }
    
    /**
      * @brief System Clock Configuration
      * @retval None
      */
    void SystemClock_Config(void)
    {
      RCC_OscInitTypeDef RCC_OscInitStruct = {0};
      RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
      RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
    
      /** Configure the main internal regulator output voltage
      */
      HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST);
      /** Initializes the RCC Oscillators according to the specified parameters
      * in the RCC_OscInitTypeDef structure.
      */
      RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
      RCC_OscInitStruct.HSEState = RCC_HSE_ON;
      RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
      RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
      RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV6;
      RCC_OscInitStruct.PLL.PLLN = 85;
      RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
      RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
      RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
      if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != 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_DIV1;
      RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
      if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
      {
        Error_Handler();
      }
      /** Initializes the peripherals clocks
      */
      PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPUART1|RCC_PERIPHCLK_ADC12;
      PeriphClkInit.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_PCLK1;
      PeriphClkInit.Adc12ClockSelection = RCC_ADC12CLKSOURCE_SYSCLK;
      if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
      {
        Error_Handler();
      }
    }
    
    /**
      * @brief ADC1 Initialization Function
      * @param None
      * @retval None
      */
    static void MX_ADC1_Init(void)
    {
    
      /* USER CODE BEGIN ADC1_Init 0 */
    
      /* USER CODE END ADC1_Init 0 */
    
      ADC_MultiModeTypeDef multimode = {0};
      ADC_ChannelConfTypeDef sConfig = {0};
    
      /* USER CODE BEGIN ADC1_Init 1 */
    
      /* USER CODE END ADC1_Init 1 */
      /** Common config
      */
      hadc1.Instance = ADC1;
      hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
      hadc1.Init.Resolution = ADC_RESOLUTION_12B;
      hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
      hadc1.Init.GainCompensation = 0;
      hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
      hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
      hadc1.Init.LowPowerAutoWait = DISABLE;
      hadc1.Init.ContinuousConvMode = ENABLE;
      hadc1.Init.NbrOfConversion = 1;
      hadc1.Init.DiscontinuousConvMode = DISABLE;
      hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T4_TRGO;
      hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
      hadc1.Init.DMAContinuousRequests = ENABLE;
      hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
      hadc1.Init.OversamplingMode = DISABLE;
      if (HAL_ADC_Init(&hadc1) != HAL_OK)
      {
        Error_Handler();
      }
      /** Configure the ADC multi-mode
      */
      multimode.Mode = ADC_MODE_INDEPENDENT;
      if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
      {
        Error_Handler();
      }
      /** Configure Regular Channel
      */
      sConfig.Channel = ADC_CHANNEL_1;
      sConfig.Rank = ADC_REGULAR_RANK_1;
      sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
      sConfig.SingleDiff = ADC_SINGLE_ENDED;
      sConfig.OffsetNumber = ADC_OFFSET_NONE;
      sConfig.Offset = 0;
      if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
      {
        Error_Handler();
      }
      /* USER CODE BEGIN ADC1_Init 2 */
    
      /* USER CODE END ADC1_Init 2 */
    
    }
    
    /**
      * @brief DAC1 Initialization Function
      * @param None
      * @retval None
      */
    static void MX_DAC1_Init(void)
    {
    
      /* USER CODE BEGIN DAC1_Init 0 */
    
      /* USER CODE END DAC1_Init 0 */
    
      DAC_ChannelConfTypeDef sConfig = {0};
    
      /* USER CODE BEGIN DAC1_Init 1 */
    
      /* USER CODE END DAC1_Init 1 */
      /** DAC Initialization
      */
      hdac1.Instance = DAC1;
      if (HAL_DAC_Init(&hdac1) != HAL_OK)
      {
        Error_Handler();
      }
      /** DAC channel OUT1 config
      */
      sConfig.DAC_HighFrequency = DAC_HIGH_FREQUENCY_INTERFACE_MODE_AUTOMATIC;
      sConfig.DAC_DMADoubleDataMode = DISABLE;
      sConfig.DAC_SignedFormat = DISABLE;
      sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
      sConfig.DAC_Trigger = DAC_TRIGGER_T4_TRGO;
      sConfig.DAC_Trigger2 = DAC_TRIGGER_NONE;
      sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
      sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_EXTERNAL;
      sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;
      if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL_1) != HAL_OK)
      {
        Error_Handler();
      }
      /* USER CODE BEGIN DAC1_Init 2 */
    
      /* USER CODE END DAC1_Init 2 */
    
    }
    
    /**
      * @brief DAC2 Initialization Function
      * @param None
      * @retval None
      */
    static void MX_DAC2_Init(void)
    {
    
      /* USER CODE BEGIN DAC2_Init 0 */
    
      /* USER CODE END DAC2_Init 0 */
    
      DAC_ChannelConfTypeDef sConfig = {0};
    
      /* USER CODE BEGIN DAC2_Init 1 */
    
      /* USER CODE END DAC2_Init 1 */
      /** DAC Initialization
      */
      hdac2.Instance = DAC2;
      if (HAL_DAC_Init(&hdac2) != HAL_OK)
      {
        Error_Handler();
      }
      /** DAC channel OUT1 config
      */
      sConfig.DAC_HighFrequency = DAC_HIGH_FREQUENCY_INTERFACE_MODE_AUTOMATIC;
      sConfig.DAC_DMADoubleDataMode = DISABLE;
      sConfig.DAC_SignedFormat = DISABLE;
      sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
      sConfig.DAC_Trigger = DAC_TRIGGER_T4_TRGO;
      sConfig.DAC_Trigger2 = DAC_TRIGGER_NONE;
      sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
      sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_EXTERNAL;
      sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;
      if (HAL_DAC_ConfigChannel(&hdac2, &sConfig, DAC_CHANNEL_1) != HAL_OK)
      {
        Error_Handler();
      }
      /* USER CODE BEGIN DAC2_Init 2 */
    
      /* USER CODE END DAC2_Init 2 */
    
    }
    
    /**
      * @brief FMAC Initialization Function
      * @param None
      * @retval None
      */
    static void MX_FMAC_Init(void)
    {
    
      /* USER CODE BEGIN FMAC_Init 0 */
    
      /* USER CODE END FMAC_Init 0 */
    
      /* USER CODE BEGIN FMAC_Init 1 */
    
      /* USER CODE END FMAC_Init 1 */
    
      hfmac.Instance = FMAC;
      if (HAL_FMAC_Init(&hfmac) != HAL_OK)
      {
        Error_Handler();
      }
      /* USER CODE BEGIN FMAC_Init 2 */
    
      /* USER CODE END FMAC_Init 2 */
    
    }
    
    /**
      * @brief LPUART1 Initialization Function
      * @param None
      * @retval None
      */
    static void MX_LPUART1_UART_Init(void)
    {
    
      /* USER CODE BEGIN LPUART1_Init 0 */
    
      /* USER CODE END LPUART1_Init 0 */
    
      /* USER CODE BEGIN LPUART1_Init 1 */
    
      /* USER CODE END LPUART1_Init 1 */
      hlpuart1.Instance = LPUART1;
      hlpuart1.Init.BaudRate = 115200;
      hlpuart1.Init.WordLength = UART_WORDLENGTH_8B;
      hlpuart1.Init.StopBits = UART_STOPBITS_1;
      hlpuart1.Init.Parity = UART_PARITY_NONE;
      hlpuart1.Init.Mode = UART_MODE_TX_RX;
      hlpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
      hlpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
      hlpuart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
      hlpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
      if (HAL_UART_Init(&hlpuart1) != HAL_OK)
      {
        Error_Handler();
      }
      if (HAL_UARTEx_SetTxFifoThreshold(&hlpuart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
      {
        Error_Handler();
      }
      if (HAL_UARTEx_SetRxFifoThreshold(&hlpuart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
      {
        Error_Handler();
      }
      if (HAL_UARTEx_DisableFifoMode(&hlpuart1) != HAL_OK)
      {
        Error_Handler();
      }
      /* USER CODE BEGIN LPUART1_Init 2 */
    
      /* USER CODE END LPUART1_Init 2 */
    
    }
    
    /**
      * @brief TIM1 Initialization Function
      * @param None
      * @retval None
      */
    static void MX_TIM1_Init(void)
    {
    
      /* USER CODE BEGIN TIM1_Init 0 */
    
      /* USER CODE END TIM1_Init 0 */
    
      TIM_ClockConfigTypeDef sClockSourceConfig = {0};
      TIM_MasterConfigTypeDef sMasterConfig = {0};
    
      /* USER CODE BEGIN TIM1_Init 1 */
    
      /* USER CODE END TIM1_Init 1 */
      htim1.Instance = TIM1;
      htim1.Init.Prescaler = 170-1;
      htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
      htim1.Init.Period = 65535;
      htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
      htim1.Init.RepetitionCounter = 0;
      htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
      if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
      {
        Error_Handler();
      }
      sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
      if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
      {
        Error_Handler();
      }
      sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
      sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
      sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
      if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
      {
        Error_Handler();
      }
      /* USER CODE BEGIN TIM1_Init 2 */
    
      /* USER CODE END TIM1_Init 2 */
    
    }
    
    /**
      * @brief TIM4 Initialization Function
      * @param None
      * @retval None
      */
    static void MX_TIM4_Init(void)
    {
    
      /* USER CODE BEGIN TIM4_Init 0 */
    
      /* USER CODE END TIM4_Init 0 */
    
      TIM_ClockConfigTypeDef sClockSourceConfig = {0};
      TIM_MasterConfigTypeDef sMasterConfig = {0};
      TIM_OC_InitTypeDef sConfigOC = {0};
    
      /* USER CODE BEGIN TIM4_Init 1 */
    
      /* USER CODE END TIM4_Init 1 */
      htim4.Instance = TIM4;
      htim4.Init.Prescaler = 1;
      htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
      htim4.Init.Period = 849;
      htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
      htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
      if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
      {
        Error_Handler();
      }
      sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
      if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
      {
        Error_Handler();
      }
      if (HAL_TIM_PWM_Init(&htim4) != HAL_OK)
      {
        Error_Handler();
      }
      sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
      sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
      if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
      {
        Error_Handler();
      }
      sConfigOC.OCMode = TIM_OCMODE_PWM1;
      sConfigOC.Pulse = 425;
      sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
      sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;
      if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
      {
        Error_Handler();
      }
      /* USER CODE BEGIN TIM4_Init 2 */
    
      /* USER CODE END TIM4_Init 2 */
      HAL_TIM_MspPostInit(&htim4);
    
    }
    
    /**
      * Enable DMA controller clock
      */
    static void MX_DMA_Init(void)
    {
    
      /* DMA controller clock enable */
      __HAL_RCC_DMAMUX1_CLK_ENABLE();
      __HAL_RCC_DMA1_CLK_ENABLE();
      __HAL_RCC_DMA2_CLK_ENABLE();
    
      /* DMA interrupt init */
      /* DMA1_Channel1_IRQn interrupt configuration */
      HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
      HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
      /* DMA1_Channel2_IRQn interrupt configuration */
      HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
      HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
      /* DMA1_Channel4_IRQn interrupt configuration */
      HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 0, 0);
      HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
      /* DMA1_Channel5_IRQn interrupt configuration */
      HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);
      HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
      /* DMA2_Channel1_IRQn interrupt configuration */
      HAL_NVIC_SetPriority(DMA2_Channel1_IRQn, 0, 0);
      HAL_NVIC_EnableIRQ(DMA2_Channel1_IRQn);
    
    }
    
    /**
      * @brief GPIO Initialization Function
      * @param None
      * @retval None
      */
    static void MX_GPIO_Init(void)
    {
      GPIO_InitTypeDef GPIO_InitStruct = {0};
    
      /* GPIO Ports Clock Enable */
      __HAL_RCC_GPIOC_CLK_ENABLE();
      __HAL_RCC_GPIOF_CLK_ENABLE();
      __HAL_RCC_GPIOA_CLK_ENABLE();
      __HAL_RCC_GPIOB_CLK_ENABLE();
    
      /*Configure GPIO pin : B1_Pin */
      GPIO_InitStruct.Pin = B1_Pin;
      GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
      GPIO_InitStruct.Pull = GPIO_NOPULL;
      HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
    
    }
    
    /* 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 */
    
    /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

     

    ScreenImg (43).png

  13. 6 minutes ago, jcxz said:

    Интересно - как Вы вообще инициализировали систему тактирования МК даже не имея понятия какая латентность у флеша МК??? :russian_ru:

    Возможно для этого придуманы IDE, что бы не лезть в Datasheet каждый раз. 2 Такта memory access time при fHCLK > 48MHz

    6 minutes ago, jcxz said:

    Для защёлкивания содержимого DMA-буфера в какой-то момент, совершенно не нужно останавливать DMA или АЦП. Достаточно просто переключить их на другой буфер.

    Не принципиально, аналогично остановке АЦП.

    6 minutes ago, jcxz said:

    Впрочем после обнаружения события в буфере, DMA можно и остановить. Но не с целью фиксации позиции, а с целью уменьшения общей загрузки системы

    После обнаружения события в буфере необходимо сделать еще N отсчетов АЦП, затем остановить.

    6 minutes ago, jcxz said:

    (чтобы процессору досталось больше ресурсов шины для обработки защёлкнутых данных).

    Процессору должен по итогам работы достаться массив данных из 256 элементов, с событием располагающемся в районе 128 элемента.

    Вот пример оцифровки со скоростью 1МГц в буфер через ПДП, а затем медленная передача на ПК через SWO

    image.thumb.png.c82df4a4b3c81f50e3af43eb9097df5b.png

  14. Спасибо всем отписавшимся jcxzMrBearManulBaser мне понадобиться время что бы все это обдумать.

    Да, похоже получается обработка в прерывании будет лучше. На тот момент я думал, что через ПДП это можно сделать быстрее, но все верно, получается асинхронный счет сэмплов, а это глупость.

    19 hours ago, Baser said:

    1. АЦП с частотой 1МГц цифрует входной сигнал и через ПДП складывает результаты в циклический буфер на 256 значений.

    Абсолютно верно.

    19 hours ago, Baser said:

    2. Одновременно ТС хочет анализировать сигнал на перепад (фронт), после чего останавливать АЦП и неспешно анализировать данные.

    Не обязательно фронт, в идеале любой настраиваемый триггер. Про неспешный анализ после остановки АЦП совершенно верно.

    19 hours ago, Baser said:

    1. Для анализа перепада входного сигнала использовать (11.3.7 Analog watchdog).

    Хотел произвольный триггер, не только фронт/спад.

    19 hours ago, Baser said:

    2. Периодически читать последние результаты АЦП и ловить перепад сигнала (но если перепад короткий, его можно и пропустить).

    Да, читать данные данные в циклическом буфере для поиска определенных состояний.

    Да, регистр DMA1_Channel1->CNDTR, действительно содержит информацию о оставшемся количестве слов до заполнения циклического буфера (если я ничего не попутал), но получается придется читать его асинхронно, а это плохо.

    18 hours ago, jcxz said:

    А ISR-ов у вас - ни одного нет? И длительность их выполнения какая? (Особенно если внутри них такие же кал-вызовы)

    А какова скорость выборки из флеша (код то наверное из флеша выполняется)?

    Если запретить все прерывания и работать через регистры, то тогда наверное можно получить 1 мкс...

     

    ISR от DMA. скорость выборки из флеша 1 такт, не? Да, ничего лишнего только АЦП, кольцевой буфер, блок триггера, и команда на остановку АЦП.

    В общем, задача очень похожа на то как работают цифровые осциллографы. То есть поиск события в буфере, после события дополняем буфер на еще N отсчетов, а далее стоп и медленно обрабатываем.

    В идеале я хотел бы получать буфер на 256 точек, в котором посередине было бы мое событие.

    18 hours ago, jcxz said:

    Может вам просто работать по прерыванию, без DMA? А то Вы вроде сделали DMA, а теперь пытаетесь убить все его преимущества и привести к алгоритму функционирования "по прерываниям".

    Зачем вам DMA если стараетесь с ним бороться???  :wacko2:

    Просто опрашивайте АЦП поллингом или по прерыванию - так будет лучше и проще.

    PS: А то как в анекдоте про мужика купишего автомобиль, а потом спрашивающего - "а куда тут кобылу запрягать-то?"

    Да, похоже что так.

    5 hours ago, MrBearManul said:

    Гм... У вас поиск события никак не привязан к данным в буфере, т.к. выполняется асинхронно сбору. И неатомарности будут присутствовать: пока обращаетесь к паре ячеек, они уже раз двадцать переобновятся.

    Я понял, согласен.

    5 hours ago, MrBearManul said:

    Вычтете такты на вход в прерывание (для CM3 примерно 12,  точнее надо смотреть документацию), на выход (тоже примерно 12) и на сам код прерывания тоже. Останется не так уж и много.

    32 такта на чтение из регистра АЦП, сохранения в кольцевой буфер, инкремент указателя, проверка пары условий с чтением из буфера и при совпадении остановка АЦП. 

    Думаете не заморачиваться?

  15. 30 minutes ago, jcxz said:

    Для такой остановки "глобальная переменная, обновляющаяся раз в 1uS" бесполезна. Потому как точность остановки вашего цикла имеет временной лаг намного больше (может даже - в разы больше).

    Почему? 1uS это не так и мало это целых 56 тактов при 56МГц. Остановка АЦП может быть и через CMSIS, это не столь важно, мой вопрос от этого не меняется.

    Я уже понял, что нужно разобраться с регистром DMA_CNDTR1, но пока я не понял, какие именно данные мне в нем ожидать при циклическом заполнении буфера длиной 256 слов.

    У меня МК 32F103С8T6, но я думаю эти принципы должны распространятся по крайней мере на все 100-е МК.

    Да, есть событие по окончанию преобразования группы каналов АЦП, можно вызвать по нему прерывание, но я лишь хочу знать текущее положение потока DMA в буфере, например чтобы сделать такое условие:

    ADC1->CR2 |= ADC_CR2_SWSTART;
    uint8_t adc_buf_pos;
    
    
     if (adc_buf[adc_buf_pos-127] > 1000 && adc_buf[adc_buf_pos -128] < 1000 && adc_buf_pos == 255)
     {
       ADC1->CR2 &= ~ADC_CR2_SWSTART;
     }

    Где adc_buf_pos это суть вопроса

    Неправильно наверху написал, скорее так:

    ADC1->CR2 |= ADC_CR2_SWSTART; // старт АЦП
    uint8_t adc_buf_pos;
    
    while(1)
    {
     if (adc_buf[128] > 1000 && adc_buf[127] < 1000)
     {
       
       while(adc_buf_pos<255)
       {
         adc_buf_pos = ???;
       }
       ADC1->CR2 &= ~ADC_CR2_SWSTART; // Стоп АЦП
       // обработка статического массива
     }
     ADC1->CR2 |= ADC_CR2_SWSTART; // перезапуск АЦП 
    }

     

  16. 1 minute ago, jcxz said:

    Я уже писал: это зависит от максимально допустимого временного лага. Чем больше допустимый лаг - тем проще.

    АЦП создает новое данное раз в 1uS, мне бы хотелось иметь глобальную переменную, обновляющуюся раз в 1uS и несущую в себе информацию о адресе в буфере adc_buf[256] по которому была произведена последняя передача ПДП.

    1 minute ago, jcxz said:

    И от того - по какому событию нужно останаливать это всё?

    Пример события:

      while (1)
    {  
     if (adc_buf[128] > 1000 && adc_buf[127] < 1000)
     {
       HAL_ADC_Stop_DMA(&hadc1);
     }
    }
  17. 27 minutes ago, jcxz said:

    Остановить наверное можно, но не DMA, а источник триггер-событий для него (таймер?).

    АЦП в режиме continuous mode сам себя перезапускает, по готовности АЦП отрабатывает ПДП. Да, я останавливаю работу АЦП и тем останавливается ПДП, вопрос только на какой был последний переданный элемент массива adc_buf[256];

    27 minutes ago, jcxz said:

    текущую позицию DMA-потока

    Да, как это получать максимально просто и правильно?

  18. Just now, jcxz said:

     Или у вас какие-то проблемы в общем алгоритме работы....

    Нет, это не проблема, просто я хочу по некоторому событию в структуре данных буфера АЦП делать остановку DMA и дальше работать со статичным массивом, но одна из вещей которая мне нужна это знание на каком элементе ДМА было остановлено.

    Если я правильно понял в этом регистре будет храниться число оставшихся данных для передачи. И в circular mode, для моего случает когда буфер дойдет до 0, произойдет перезагрузка на 255? Этот регистр декрементируется да?

    316052473_.thumb.png.13a6567ebad50f0774a484aa90163a0a.png

  19. Здравствуйте форумчане!

    МК - STM32F103. Сохраняю данные с АЦП в циклический буфер с передачей по DMA, все работает ок, ниже примерный код с HAL, инициализация не показана, но это не суть, вопрос такой: я хочу иметь возможность в любой момент времени узнать адрес или номер элемента массива adc_buf в который произойдет очередное сохранение (или последний куда сохранение было сделано). То есть указатель бегающий вместе со DMA.

    Один из вариантов, который я продумывал было инкремент некоторой переменной в прерывании по готовности передачи DMA, но есть ли нормальный (лучший) способ это делать, ведь этот указатель уже должен быть частью DMA, мне лишь надо его читать.

    #define ADC_BUF_LEN 256
    ADC_HandleTypeDef hadc1;
    uint16_t adc_buf[ADC_BUF_LEN];
    ADC_HandleTypeDef hadc1;
    
    HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buf, ADC_BUF_LEN);
      while (1)
    {  
    
    }

     

  20. 2 hours ago, AHTOXA said:

    Да, в этом случае опасно только одно значение -32768.

    Так как у меня нет отдельной информации о переполнении АЦП, я назначу обе крайние точки 32767 и -32768 как "out of range".

  21. 2 minutes ago, AHTOXA said:

    "I= --3.-35 A".

    Каюсь, не всю программу выложил. Это связано было со способом приема данных с АЦП через 2 отдельных байта MSB и LSB.

    int16_t current;
    char sign;
    div_t fracDigit;
    char Str_Buffer[20];
    int8_t MSB = 0x83;
    uint8_t LSB = 0x00; //например -32000
    
    current = abs (MSB << 8 | LSB);
    if (MSB >= 0)  sign = ' ';
    else           sign = '-';
    fracDigit = div(current/10,1000);
    sprintf(Str_Buffer, "I= %1c%1d.%03d A", sign, fracDigit.quot, fracDigit.rem);

     

×
×
  • Создать...