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

ToR_TDA

Свой
  • Постов

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

  • Посещение

Весь контент ToR_TDA


  1. В общем так я и не понял в чем у меня проблема в режиме контроля входного тока. По достижению примерно 0,48А тока в регистре статуса устанавливается бит IN_IINDPM и рост тока прекращается независимо от состояния регистра IIN_DPM Register и ножки ILIM_HIZ, ножку я уже подключил напрямую к VDDA тем по сути отключив этот лимит полностью и по-идеи остается регистр IIN_DPM, но не работает. Больше пол ампера не выдает, Если снять контроль входного тока то ток просто потихоньку растет по мере поднятия напряжения на ионисторах и не останавливается. Зависит от того что утсановлено в Charge Current Register Но достигал и 2А и больше, что уже перебор для меня.
  2. А это не примерно то же что и FUSB302? А то я только китайскую pdf нашел не все понял)))
  3. Я выяснил что для моей инициализации ChargeOption0 Register 0x024A (с контролем входного тока) регистр IIN_HOST регулирует входной ток, но только вниз до примерно 0,48А Я бы это объяснил ножкой ILIM_HIZ, по идеи выбирается меньшая из двух установок по регистру или по ножке, но там много 2,25В что около 3А
  4. Я купил без проблем и я все понимаю, но это не по теме топика.
  5. Данные из IIN_HOST переписываются в IIN_DPM то есть IIN_HOST это просто буферный регистр, а IIN_DPM только для чтения, но я читаю их оба одновременно, там одинаковые значения, то что я и пишу.
  6. По значениям MaxChargeVoltage Register работает, проверял, заряжает до того уровня что там записано очень точно и затем поддерживает.
  7. При использовании BQ25713 микроконтроллер делает только инициализацию и при использовании Power Delivery переинициализирует регистры. Я говорил именно о отдельном DC-DC на МК, который заменит все функции BQ, то есть измерение 2-х токов входного и выходного, измерение 2-х напряжений, контроль за 2-мя парами. У меня режим от USB только заряд. тут какие задачи 1. принимать на входе 5-20В, то есть либо понижать либо повышать. Максимальное напряжение заряда в BQ в регистре. 2. Контролировать ток как заряда так и от USB дабы выставлять максимум по протоколу, ну или ходя бы просто не перегружать USB.
  8. Я плыты со сборкой заказывал, только 3 штуки опытных, но вообще микросхема не редкость, с некоторым риском можно даже просто на алиэкспресс взять Или про что разговор? Не понял
  9. В общем, для тех кому интересно, что сделал на данный момент: Транзистор 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А. Это в любом случае будет такая же топология, но возможно да, можно было бы управлять этим просто от МК, 2 комплементарных ШИМ и 4 входа АЦП. Но это такая себе приличная задача. Делать что-то в аналоге, это такое себе удовольствие, тут много режимов Входное напряжение 5-20В при выходном 10В то есть и повышаем и понижаем, все с контролем тока. Аналоговое управляемое решение конечно возможно, но по нынешним меркам мне легче даже было бы отдельный небольшой МК на управляемый DC-DC поставить. Что-то сразу не подумал. Но опять таки это задача выходила за рамки.
  10. Сейчас разбираюсь конкретно с BQ25713 Если есть предложения с учетом PD, то интересно. Была конечно сразу такая идея и возможно так и сделаю, хоят непонятно как будет работать МС при этом, какой ток будет. Думал может кто с ними работал, знает что. Я просто думаю, что её все таки можно запустить на зарядку от нуля, хотя возможно ошибаюсь Записываю 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, но транзистор все равно в линейном
  11. Да, 0x0004, 0x0002, 0x0008 И да, 4 ионистора основной источник в автономном режиме.
  12. Не, запись 1,024 В в MinSystemVoltage не приводит к успеху. CHRG_OK гаснет через задержку и ничего не происходит.
  13. Спасибо за ответ. Во, именно у меня получается LDO Mode , потому транзистор в линейном, но в MinSystemVoltage Register по дефолту 0В и я еще его тоже обновлял на 0x0000 и это не меняет ситуацию. По идеи я должен как-то перейти сразу к режиму Charge, но что я должен сделать. Хм, интересно, почему? Что я проглядел? Ну, типа Power Delivery в будущем Это не резервирование, это основной источник питания устройства, оно автономное, решил заложить режим быстрой зарядки от USB PD, такое требование.
  14. Уважаемые форумчане, Работал ли кто-то с микросхема Buck-Boost конвертера для зарядки батарей. У меня немного специфичная задача от её типового применения, я заряжаю 4 ионистора, а не LiIon, потому у меня процесс зарядки от нуля может происходить. Сейчас на плате микроконтроллер подключен к ней по I2C и связь есть, регистры читаются корректно, то что и должно быть в дефолтном состоянии. Не совсем понимаю как я должен ее инициализировать дабы получить заряд до 2,7x4В с током 1-2А для начала. Хочу получить управление именно по регистрам, а не по внешним ножкам. Схема как на EVO плате, питание USB 5В Ножка CHRG_OK устанавливается в Ок, как положено. Сейчас пишу в регистры: Charge Current Register MaxChargeVoltage Register Микросхеме реагирует, но греется транзистор Q2 на выходе. Это собственно и проблема, он в линейном режиме находится, а должен быть открыт. Это описано, что он может быть в линейном, на как это изменить я что-то понять не могу. bq25713.pdf tidrxq7.pdf
  15. В общем, сам спросил сам и отвечаю:) Все сделал в точности по примеру "Example 2: 3p3z compensator" из приведенного выше документа только с изменением на КИХ фильтр и вывод на ЦАП по ДМА. Показываю ключевые моменты кода. Главная идея, что данные от АЦП передаем через DMA напрямую в FMAС "perip to perip". На самом деле там в примере есть "секреточка", а в целом все проблемы связаны с тем, что ST еще не допилили ни CMSIS, ни CubeMX, ни свои библиотеки под этот новый блок до конца. #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(); } }
  16. STM32G474 Nucleo ADC+DMA+FMAC

    Приветствую форумчане! Захотелось мне для опыта запустить блок аппаратного фильтра на 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 (тактирование) /* 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****/
  17. Возможно для этого придуманы IDE, что бы не лезть в Datasheet каждый раз. 2 Такта memory access time при fHCLK > 48MHz Не принципиально, аналогично остановке АЦП. После обнаружения события в буфере необходимо сделать еще N отсчетов АЦП, затем остановить. Процессору должен по итогам работы достаться массив данных из 256 элементов, с событием располагающемся в районе 128 элемента. Вот пример оцифровки со скоростью 1МГц в буфер через ПДП, а затем медленная передача на ПК через SWO
  18. Спасибо всем отписавшимся jcxz, MrBearManul, Baser мне понадобиться время что бы все это обдумать. Да, похоже получается обработка в прерывании будет лучше. На тот момент я думал, что через ПДП это можно сделать быстрее, но все верно, получается асинхронный счет сэмплов, а это глупость. Абсолютно верно. Не обязательно фронт, в идеале любой настраиваемый триггер. Про неспешный анализ после остановки АЦП совершенно верно. Хотел произвольный триггер, не только фронт/спад. Да, читать данные данные в циклическом буфере для поиска определенных состояний. Да, регистр DMA1_Channel1->CNDTR, действительно содержит информацию о оставшемся количестве слов до заполнения циклического буфера (если я ничего не попутал), но получается придется читать его асинхронно, а это плохо. ISR от DMA. скорость выборки из флеша 1 такт, не? Да, ничего лишнего только АЦП, кольцевой буфер, блок триггера, и команда на остановку АЦП. В общем, задача очень похожа на то как работают цифровые осциллографы. То есть поиск события в буфере, после события дополняем буфер на еще N отсчетов, а далее стоп и медленно обрабатываем. В идеале я хотел бы получать буфер на 256 точек, в котором посередине было бы мое событие. Да, похоже что так. Я понял, согласен. 32 такта на чтение из регистра АЦП, сохранения в кольцевой буфер, инкремент указателя, проверка пары условий с чтением из буфера и при совпадении остановка АЦП. Думаете не заморачиваться?
  19. Почему? 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; // перезапуск АЦП }
  20. АЦП создает новое данное раз в 1uS, мне бы хотелось иметь глобальную переменную, обновляющуюся раз в 1uS и несущую в себе информацию о адресе в буфере adc_buf[256] по которому была произведена последняя передача ПДП. Пример события: while (1) { if (adc_buf[128] > 1000 && adc_buf[127] < 1000) { HAL_ADC_Stop_DMA(&hadc1); } }
  21. АЦП в режиме continuous mode сам себя перезапускает, по готовности АЦП отрабатывает ПДП. Да, я останавливаю работу АЦП и тем останавливается ПДП, вопрос только на какой был последний переданный элемент массива adc_buf[256]; Да, как это получать максимально просто и правильно?
  22. Нет, это не проблема, просто я хочу по некоторому событию в структуре данных буфера АЦП делать остановку DMA и дальше работать со статичным массивом, но одна из вещей которая мне нужна это знание на каком элементе ДМА было остановлено. Если я правильно понял в этом регистре будет храниться число оставшихся данных для передачи. И в circular mode, для моего случает когда буфер дойдет до 0, произойдет перезагрузка на 255? Этот регистр декрементируется да?
  23. Здравствуйте форумчане! МК - 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) { }
  24. Так как у меня нет отдельной информации о переполнении АЦП, я назначу обе крайние точки 32767 и -32768 как "out of range".
  25. Каюсь, не всю программу выложил. Это связано было со способом приема данных с АЦП через 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);
×
×
  • Создать...