#include "init.h" #include /* DMA буфер под DAC */ uint16_t g_dac_buffer[SINE_POINTS]; /* Базовый синус 0..1 (float), пересчитывается один раз */ static float s_sine_base[SINE_POINTS]; /* ---- Вспомогательно: получить реальную частоту тактирования TIM2 ---- TIM2 находится на APB1. Если prescaler APB1 != 1, то таймер тактируется *2. */ static uint32_t TIM2_GetTimerClockHz(void) { RCC_ClocksTypeDef clocks; uint32_t pclk1; RCC_GetClocksFreq(&clocks); pclk1 = clocks.PCLK1_Frequency; /* Если делитель APB1 больше 1, таймеры на APB1 получают частоту 2*PCLK1 */ if ((RCC->CFGR & RCC_CFGR_PPRE1) != RCC_CFGR_PPRE1_DIV1) { return (pclk1 * 2u); } return pclk1; } /* ---------------- GPIO ---------------- PA4 = аналог (DAC OUT1) PA5 = аналог (ADC IN5) */ void GPIO_Init_All(void) { GPIO_InitTypeDef gpio; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); gpio.GPIO_Pin = DAC_OUT_PIN | AMP_ADC_PIN; gpio.GPIO_Mode = GPIO_Mode_AN; gpio.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &gpio); } /* ---------------- DAC1 (Channel 1 -> PA4) ---------------- */ void DAC1_Init_All(void) { DAC_InitTypeDef dac; RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); DAC_StructInit(&dac); dac.DAC_Trigger = DAC_Trigger_T2_TRGO; /* запуск от TIM2 TRGO (как в файле) */ dac.DAC_OutputBuffer = DAC_OutputBuffer_Enable; DAC_Init(DAC_Channel_1, &dac); DAC_Cmd(DAC_Channel_1, ENABLE); /* Разрешаем запросы DMA от DAC */ DAC_DMACmd(DAC_Channel_1, ENABLE); } /* ---------------- DMA1 Stream5 Channel7 -> DAC1 ---------------- */ void DMA1_For_DAC1_Init(uint16_t *buf, uint32_t n) { DMA_InitTypeDef dma; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); DMA_DeInit(DMA1_Stream5); while (DMA_GetCmdStatus(DMA1_Stream5) != DISABLE) { } DMA_StructInit(&dma); dma.DMA_Channel = DMA_Channel_7; dma.DMA_PeripheralBaseAddr = (uint32_t)&DAC->DHR12R1; dma.DMA_Memory0BaseAddr = (uint32_t)buf; dma.DMA_DIR = DMA_DIR_MemoryToPeripheral; dma.DMA_BufferSize = n; dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable; dma.DMA_MemoryInc = DMA_MemoryInc_Enable; dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; dma.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; dma.DMA_Mode = DMA_Mode_Circular; dma.DMA_Priority = DMA_Priority_High; dma.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_Init(DMA1_Stream5, &dma); DMA_Cmd(DMA1_Stream5, ENABLE); } /* ---------------- TIM2 TRGO: частота обновления DAC ---------------- */ void TIM2_TRGO_Init(uint32_t update_hz) { TIM_TimeBaseInitTypeDef tim; uint32_t timclk; uint32_t period; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseStructInit(&tim); timclk = TIM2_GetTimerClockHz(); /* Prescaler = 0 (делим на 1), Period под update_hz */ /* period = timclk/update_hz - 1 */ period = (timclk / update_hz); if (period == 0u) { period = 1u; } period = period - 1u; tim.TIM_Prescaler = 0u; tim.TIM_CounterMode = TIM_CounterMode_Up; tim.TIM_ClockDivision = TIM_CKD_DIV1; tim.TIM_Period = (uint32_t)period; TIM_TimeBaseInit(TIM2, &tim); /* TRGO на событие Update */ TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); TIM_Cmd(TIM2, ENABLE); } /* ---------------- ADC1 on PA5 (Channel 5) ---------------- */ void ADC1_PA5_Init(void) { ADC_InitTypeDef adc; ADC_CommonInitTypeDef adc_common; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); ADC_CommonStructInit(&adc_common); adc_common.ADC_Mode = ADC_Mode_Independent; adc_common.ADC_Prescaler = ADC_Prescaler_Div4; adc_common.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; adc_common.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; ADC_CommonInit(&adc_common); ADC_StructInit(&adc); adc.ADC_Resolution = ADC_Resolution_12b; adc.ADC_ScanConvMode = DISABLE; adc.ADC_ContinuousConvMode = DISABLE; /* читаем по запросу */ adc.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; adc.ADC_DataAlign = ADC_DataAlign_Right; adc.ADC_NbrOfConversion = 1; ADC_Init(ADC1, &adc); ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_144Cycles); ADC_Cmd(ADC1, ENABLE); } /* Усреднение АЦП (чтобы меньше шумело) */ uint16_t ADC1_ReadAverage(uint8_t samples) { uint32_t sum; uint8_t i; uint16_t v; if (samples == 0u) { samples = 1u; } sum = 0u; for (i = 0u; i < samples; i++) { ADC_SoftwareStartConv(ADC1); while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET) { } v = (uint16_t)ADC_GetConversionValue(ADC1); sum += (uint32_t)v; } return (uint16_t)(sum / (uint32_t)samples); } /* ---- Ключевое требование: НЕ пихать ADC напрямую в волну ---- Конвертируем: ADC -> Voltage -> Amplitude 0..100 */ uint8_t ADC_To_Amplitude_0_100(uint16_t adc_raw) { float voltage; float a; voltage = ((float)adc_raw * VREF_VOLTS) / (float)ADC_MAX_12BIT; /* нормируем в 0..100 */ a = (voltage / VREF_VOLTS) * 100.0f; if (a < 0.0f) { a = 0.0f; } if (a > 100.0f) { a = 100.0f; } return (uint8_t)(a + 0.5f); } /* Предрасчёт базового синуса (0..1) */ void SineBase_Init(void) { uint32_t i; for (i = 0u; i < SINE_POINTS; i++) { /* (sin + 1)/2 -> 0..1 */ s_sine_base[i] = (sinf(2.0f * 3.1415926f * (float)i / (float)SINE_POINTS) + 1.0f) * 0.5f; } } /* Обновить DMA-буфер под новую амплитуду 0..100 */ void SineBuffer_Update(uint8_t amplitude_0_100) { uint32_t i; float k; k = ((float)amplitude_0_100) / 100.0f; for (i = 0u; i < SINE_POINTS; i++) { float v; v = s_sine_base[i] * k; /* 0..1 * 0..1 */ g_dac_buffer[i] = (uint16_t)(v * (float)DAC_MAX_12BIT); } }