···1#include "main.h"
023-/**
4- * @brief The application entry point.
5- * @retval int
6- */
7-int main(void)
0000000008{
0000910- /* Infinite loop */
11- while (1)
12- {
13- }
0000000000000000000000014}
15000000000001617-/**
18- * @brief This function is executed in case of error occurrence.
19- * @retval None
20- */
21-void Error_Handler(void)
0000000000000000000000000000000000000022{
23- /* USER CODE BEGIN Error_Handler_Debug */
24- /* User can add his own implementation to report the HAL error return state */
25- __disable_irq();
26- while (1)
27- {
28- }
29- /* USER CODE END Error_Handler_Debug */
000000000000030}
31-#ifdef USE_FULL_ASSERT
32-/**
33- * @brief Reports the name of the source file and the source line number
34- * where the assert_param error has occurred.
35- * @param file: pointer to the source file name
36- * @param line: assert_param error line source number
37- * @retval None
38- */
39-void assert_failed(uint8_t *file, uint32_t line)
40{
41- /* USER CODE BEGIN 6 */
42- /* User can add his own implementation to report the file name and line number,
43- ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
44- /* USER CODE END 6 */
45}
46-#endif /* USE_FULL_ASSERT */
···1#include "main.h"
2+#include <math.h>
34+#define SINE_SAMPLES 256
5+6+static uint16_t sine_table[SINE_SAMPLES];
7+8+/* --------------------------------------------------------------------------
9+ * clock_init
10+ *
11+ * HSI (16 MHz) -> PLL -> 84 MHz SYSCLK
12+ * PLL: M=16, N=336, P=4 => 16/16 * 336 / 4 = 84 MHz
13+ * APB1 = 84/2 = 42 MHz (DAC, TIM6, USART2)
14+ * APB2 = 84/1 = 84 MHz
15+ * APB1 timer clock = 84 MHz (doubled because APB1 prescaler > 1)
16+ * -------------------------------------------------------------------------- */
17+static void clock_init(void)
18{
19+ /* Voltage scale 3 (supports up to 120 MHz, fine for 84 MHz).
20+ PWR clock must be enabled before touching PWR registers. */
21+ RCC->APB1ENR |= RCC_APB1ENR_PWREN;
22+ PWR->CR = (PWR->CR & ~PWR_CR_VOS) | (1UL << PWR_CR_VOS_Pos);
2324+ /* 2 wait states required for 84 MHz. Must be set before speeding up. */
25+ FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_LATENCY_2WS;
26+27+ /* Enable HSI and wait for it to be ready */
28+ RCC->CR |= RCC_CR_HSION;
29+ while (!(RCC->CR & RCC_CR_HSIRDY)) {}
30+31+ /* Configure PLL (still off at this point) */
32+ RCC->PLLCFGR = (16 << RCC_PLLCFGR_PLLM_Pos) | /* M: divide HSI down to 1 MHz */
33+ (336 << RCC_PLLCFGR_PLLN_Pos) | /* N: multiply to 336 MHz VCO */
34+ (1 << RCC_PLLCFGR_PLLP_Pos) | /* P=4 (01): 336/4 = 84 MHz */
35+ (2 << RCC_PLLCFGR_PLLQ_Pos) | /* Q: USB etc, unused here */
36+ (2 << RCC_PLLCFGR_PLLR_Pos); /* R: I2S etc, unused here */
37+ /* PLLSRC bit = 0 => HSI source (default) */
38+39+ RCC->CR |= RCC_CR_PLLON;
40+ while (!(RCC->CR & RCC_CR_PLLRDY)) {}
41+42+ /* APB1 prescaler /2 so APB1 peripherals run at 42 MHz.
43+ Timers on APB1 still get 84 MHz (hardware doubles it when prescaler > 1). */
44+ RCC->CFGR = RCC_CFGR_PPRE1_DIV2;
45+46+ /* Switch SYSCLK to PLL */
47+ RCC->CFGR |= RCC_CFGR_SW_PLL;
48+ while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) {}
49+50+ SystemCoreClock = 84000000;
51}
5253+/* --------------------------------------------------------------------------
54+ * dac_dma_init
55+ *
56+ * TIM6 fires at 256 kHz => DMA copies one sample per tick =>
57+ * 256-sample table plays back at 256000/256 = 1000 Hz
58+ * -------------------------------------------------------------------------- */
59+static void dac_dma_init(void)
60+{
61+ /* Enable clocks for everything we touch */
62+ RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_DMA1EN;
63+ RCC->APB1ENR |= RCC_APB1ENR_DACEN | RCC_APB1ENR_TIM6EN;
6465+ /* PA4 = DAC_OUT1: set to analog mode (MODER = 0b11) so the DAC
66+ drives the pin directly without the GPIO output stage interfering */
67+ GPIOA->MODER |= (3U << (4 * 2));
68+69+ /* TIM6 ---------------------------------------------------------------
70+ Counter clock = APB1 timer clock = 84 MHz
71+ Sample rate = 84 MHz / (PSC+1) / (ARR+1) = 84 MHz / 1 / 328 = ~256 kHz
72+ TRGO fires on every update event, which triggers the DAC */
73+ TIM6->PSC = 0;
74+ TIM6->ARR = 3279; /* reload value: 84MHz/3280 = ~25.6kHz, /256 samples = ~100Hz */
75+ TIM6->CR2 = (2 << TIM_CR2_MMS_Pos); /* MMS=010: Update -> TRGO */
76+77+ /* DMA1 Stream5 Channel7 (hardwired to DAC channel 1 in the DMA mux) --
78+ Memory (sine_table) -> Peripheral (DAC->DHR12R1)
79+ Circular: wraps back to the start after SINE_SAMPLES transfers */
80+ DMA1_Stream5->CR = 0;
81+ while (DMA1_Stream5->CR & DMA_SxCR_EN) {} /* wait for any prior EN to clear */
82+83+ DMA1_Stream5->CR = (7 << DMA_SxCR_CHSEL_Pos) | /* channel 7 */
84+ DMA_SxCR_DIR_0 | /* memory -> peripheral */
85+ DMA_SxCR_CIRC | /* circular mode */
86+ DMA_SxCR_MINC | /* increment memory pointer */
87+ DMA_SxCR_MSIZE_0 | /* memory word = 16 bit */
88+ DMA_SxCR_PSIZE_0; /* periph word = 16 bit */
89+90+ DMA1_Stream5->NDTR = SINE_SAMPLES; /* number of transfers */
91+ DMA1_Stream5->PAR = (uint32_t)&DAC->DHR12R1; /* destination: DAC data reg*/
92+ DMA1_Stream5->M0AR = (uint32_t)sine_table; /* source: our table */
93+ DMA1_Stream5->CR |= DMA_SxCR_EN;
94+95+ /* DAC channel 1 -------------------------------------------------------
96+ TEN1 = trigger enable
97+ TSEL1 = 000 (default) = TIM6 TRGO triggers each conversion
98+ DMAEN1 = DAC issues a DMA request on each trigger
99+ BOFF1 = 0 (default) = output buffer ON, drives PA4 directly
100+ EN1 = channel enable */
101+ DAC->CR = DAC_CR_TEN1 | DAC_CR_DMAEN1 | DAC_CR_EN1;
102+103+ /* Start the timer last so everything is ready when samples start flowing */
104+ TIM6->CR1 = TIM_CR1_CEN;
105+}
106+107+int main(void)
108{
109+ /* Blink LD2 (PA5) 5 times to confirm the MCU is executing */
110+ RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
111+ GPIOA->MODER = (GPIOA->MODER & ~(3U << (5*2))) | (1U << (5*2));
112+ for (int b = 0; b < 5; b++) {
113+ GPIOA->BSRR = (1U << 5);
114+ for (volatile int i = 0; i < 300000; i++) {}
115+ GPIOA->BSRR = (1U << (5+16));
116+ for (volatile int i = 0; i < 300000; i++) {}
117+ }
118+119+ clock_init();
120+121+ /* Build sine table at runtime: 12-bit unsigned, centred at mid-scale.
122+ Output swings 0-3.3V (or 0-Vref) peak-to-peak */
123+ for (int i = 0; i < SINE_SAMPLES; i++)
124+ sine_table[i] = (uint16_t)(2048 + 2047.0f * sinf(2.0f * 3.14159265f * i / SINE_SAMPLES));
125+126+ dac_dma_init();
127+128+ while (1) {}
129}
130+131+void Error_Handler(void)
0000000132{
133+ __disable_irq();
134+ while (1) {}
00135}
0
···60target_link_directories(${CMAKE_PROJECT_NAME} PRIVATE ${MX_LINK_DIRS})
6162# Add libraries to the project
63-target_link_libraries(${CMAKE_PROJECT_NAME} ${MX_LINK_LIBS})
6465# Add the map file to the list of files to be removed with 'clean' target
66set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES ADDITIONAL_CLEAN_FILES ${CMAKE_PROJECT_NAME}.map)
···60target_link_directories(${CMAKE_PROJECT_NAME} PRIVATE ${MX_LINK_DIRS})
6162# Add libraries to the project
63+target_link_libraries(${CMAKE_PROJECT_NAME} ${MX_LINK_LIBS} m)
6465# Add the map file to the list of files to be removed with 'clean' target
66set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES ADDITIONAL_CLEAN_FILES ${CMAKE_PROJECT_NAME}.map)