GCC Code Coverage Report


Directory: src/drv/
File: src/drv/rcc/src/rcc_driver.c
Date: 2024-01-25 15:03:18
Exec Total Coverage
Lines: 0 162 0.0%
Branches: 0 76 0.0%

Line Branch Exec Source
1 /********************************************************************************************************//**
2 * @file rcc_driver.c
3 *
4 * @brief File containing the APIs for configuring the RCC peripheral.
5 *
6 * Public Functions:
7 * - uint32_t RCC_GetPCLK1Value(void)
8 * - uint32_t RCC_GetPCLK2Value(void)
9 * - uint32_t RCC_GetPLLOutputClock(void)
10 * - uint8_t RCC_SetSystemClock(RCC_Config_t RCC_Config)
11 * - uint8_t RCC_SetMCO1Clk(RCC_Config_t RCC_Config)
12 * - uint8_t RCC_SetMCO2Clk(RCC_Config_t RCC_Config)
13 *
14 * @note
15 * For further information about functions refer to the corresponding header file.
16 */
17
18 #include <stdint.h>
19 #include "stm32f446xx.h"
20 #include "rcc_driver.h"
21
22 /** @brief Frequency of 8 MHz */
23 #define FREQ_8MHZ 8000000
24 /** @brief Frequency of 16 MHz */
25 #define FREQ_16MHZ 16000000
26
27 /** @brief Possible AHB prescaler values */
28 static uint16_t AHB_PreScaler[8] = {2, 4, 8, 16, 64, 128, 256, 512};
29 /** @brief Possible APB prescaler values */
30 static uint8_t APB_PreScaler[4] = {2, 4, 8, 16};
31 /** @brief Possible PLLP prescaler values */
32 static uint8_t PLLP_PreScaler[4] = {2, 4, 6, 8};
33
34 /***********************************************************************************************************/
35 /* Static Function Prototypes */
36 /***********************************************************************************************************/
37
38 /**
39 * @brief Function for configuring the PLL.
40 * @param[in] RCC_Config is the configuration struct.
41 * @return void.
42 */
43 static void RCC_PLLConfig(RCC_Config_t RCC_Config);
44
45 /**
46 * @brief Function for configuring the PLLI2S.
47 * @param[in] RCC_Config is the configuration struct.
48 * @return void.
49 */
50 static void RCC_PLLI2SConfig(RCC_Config_t RCC_Config);
51
52 /***********************************************************************************************************/
53 /* Public API Definitions */
54 /***********************************************************************************************************/
55
56 uint32_t RCC_GetPCLK1Value(void){
57
58 uint32_t pclk1, systemclk, clksrc;
59 uint8_t temp;
60 uint8_t ahbp, apb1p;
61
62 /* Check for SWS */
63 clksrc = ((RCC->CFGR >> RCC_CFGR_SWS) & 0x3);
64
65 if(clksrc == 0){
66 /* clk is HSI */
67 systemclk = FREQ_16MHZ;
68 }
69 else if(clksrc == 1){
70 /* clk is HSE */
71 systemclk = FREQ_8MHZ;
72 }
73 else if(clksrc == 2){
74 /* clk is PLL */
75 systemclk = RCC_GetPLLOutputClock();
76 }
77 else{
78 /* do nothing */
79 }
80
81 /* AHB prescaler */
82 temp = ((RCC->CFGR >> RCC_CFGR_HPRE) & 0xF);
83
84 if(temp < 8){
85 ahbp = 1;
86 }
87 else{
88 ahbp = AHB_PreScaler[temp-8];
89 }
90
91 /* APB1 prescaler */
92 temp = ((RCC->CFGR >> RCC_CFGR_PPRE1) & 0x7);
93
94 if(temp < 4){
95 apb1p = 1;
96 }
97 else{
98 apb1p = APB_PreScaler[temp-4];
99 }
100
101 pclk1 = (systemclk/ahbp)/apb1p;
102
103 return pclk1;
104 }
105
106 uint32_t RCC_GetPCLK2Value(void){
107
108 uint32_t pclk2, systemclk, clksrc;
109 uint8_t temp;
110 uint8_t ahbp, apb2p;
111
112 /* Check for SWS */
113 clksrc = ((RCC->CFGR >> RCC_CFGR_SWS) & 0x3);
114
115 if(clksrc == 0){
116 /* clk is HSI */
117 systemclk = FREQ_16MHZ;
118 }
119 else if(clksrc == 1){
120 /* clk is HSE */
121 systemclk = FREQ_8MHZ;
122 }
123 else if(clksrc == 2){
124 /* clk is PLL */
125 systemclk = RCC_GetPLLOutputClock();
126 }
127 else{
128 /* do nothing */
129 }
130
131 /* AHB prescaler */
132 temp = ((RCC->CFGR >> RCC_CFGR_HPRE) & 0xF);
133
134 if(temp < 8){
135 ahbp = 1;
136 }
137 else{
138 ahbp = AHB_PreScaler[temp-8];
139 }
140
141 /* APB2 prescaler */
142 temp = ((RCC->CFGR >> RCC_CFGR_PPRE2) & 0x7);
143
144 if(temp < 4){
145 apb2p = 1;
146 }
147 else{
148 apb2p = APB_PreScaler[temp-4];
149 }
150
151 pclk2 = (systemclk/ahbp)/apb2p;
152
153 return pclk2;
154 }
155
156 uint32_t RCC_GetPLLOutputClock(void){
157
158 uint8_t pllm = 0;
159 uint16_t plln = 0;
160 uint8_t pllp = 0;
161 uint32_t pll_clock = 0;
162
163 pllm = ((RCC->PLLCFGR >> RCC_PLLCFGR_PLLM) & 0x3F);
164 plln = ((RCC->PLLCFGR >> RCC_PLLCFGR_PLLN) & 0x01FF);
165 pllp = ((RCC->PLLCFGR >> RCC_PLLCFGR_PLLP) & 0x03);
166
167 if((uint8_t)(RCC->PLLCFGR >> RCC_PLLCFGR_PLLSRC) & 0x01){
168 /* HSE oscillator clock selected as PLL clock input */
169 pll_clock = ((uint32_t)(FREQ_8MHZ*plln)/pllm)/PLLP_PreScaler[pllp];
170 }
171 else{
172 /* HSI clock selected as PLL clock input */
173 pll_clock = ((uint32_t)(FREQ_16MHZ*plln)/pllm)/PLLP_PreScaler[pllp];
174 }
175
176 return pll_clock;
177 }
178
179 uint8_t RCC_SetSystemClock(RCC_Config_t RCC_Config){
180
181 /* Check clk_source is a valid value */
182 if(RCC_Config.clk_source > RCC_CLK_SOURCE_PLL_R){
183 return 1;
184 }
185
186 /* Set prescaler values */
187 /* Clear and set AHB prescaler */
188 RCC->CFGR &= ~(0x0F << RCC_CFGR_HPRE);
189 RCC->CFGR |= (RCC_Config.ahb_presc << RCC_CFGR_HPRE);
190 /* Clear and set APB1 prescaler */
191 RCC->CFGR &= ~(0x07 << RCC_CFGR_PPRE1);
192 RCC->CFGR |= (RCC_Config.apb1_presc << RCC_CFGR_PPRE1);
193 /* Clear and set APB2 prescaler */
194 RCC->CFGR &= ~(0x07 << RCC_CFGR_PPRE2);
195 RCC->CFGR |= (RCC_Config.apb2_presc << RCC_CFGR_PPRE2);
196
197 /* Clear the RCC_CFGR_SW bits before setting */
198 RCC->CFGR &= ~(0x03 << RCC_CFGR_SW);
199
200 if(RCC_Config.clk_source == RCC_CLK_SOURCE_HSI){
201 /* Enable HSI source */
202 RCC->CR |= (1 << RCC_CR_HSION);
203 /* Wait unitl source is ready */
204 while(!(RCC->CR & (1 << RCC_CR_HSIRDY)));
205 /* Disable HSE source */
206 RCC->CR &= ~(1 << RCC_CR_HSEON);
207 }
208 else if(RCC_Config.clk_source == RCC_CLK_SOURCE_HSE){
209 /* Set HSE mode */
210 if(RCC_Config.hse_mode == RCC_HSE_BYPASS){
211 RCC->CR |= (1 << RCC_CR_HSEBYP);
212 }
213 else{
214 RCC->CR &= ~(1 << RCC_CR_HSEBYP);
215 }
216 /* Enable HSE source */
217 RCC->CR |= (1 << RCC_CR_HSEON);
218 /* Wait until source is ready */
219 while(!(RCC->CR & (1 << RCC_CR_HSERDY)));
220 /* Switch to HSE source clock */
221 RCC->CFGR |= (0x01 << RCC_CFGR_SW);
222 /* Disable HSI source */
223 RCC->CR &= ~(1 << RCC_CR_HSION);
224 }
225 else{
226 /* Configure PLL */
227 RCC_PLLConfig(RCC_Config);
228 /* Enable PLL source */
229 RCC->CR |= (1 << RCC_CR_PLLON);
230 /* Wait until source is ready */
231 while(!(RCC->CR & (1 << RCC_CR_PLLRDY)));
232 if(RCC_Config.clk_source == RCC_CLK_SOURCE_PLL_P){
233 /* Switch to PLL source clock */
234 RCC->CFGR |= (0x02 << RCC_CFGR_SW);
235 }
236 else if(RCC_Config.clk_source == RCC_CLK_SOURCE_PLL_R){
237 /* Switch to PLL_R source clock */
238 RCC->CFGR |= (0x03 << RCC_CFGR_SW);
239 }
240 else{
241 return 1;
242 }
243 }
244
245 return 0;
246 }
247
248 uint8_t RCC_SetMCO1Clk(RCC_Config_t RCC_Config){
249
250 /* Check if division factor and input source are correct */
251 if((RCC_Config.mco1_presc > MCO_P_5) || (RCC_Config.mco1_source > MCO1_PLL)){
252 return 1;
253 }
254
255 /* Clear and set prescaler value */
256 RCC->CFGR &= ~(0x07 << RCC_CFGR_MCO1PRE);
257 RCC->CFGR |= (RCC_Config.mco1_presc << RCC_CFGR_MCO1PRE);
258 /* Clear and set source value */
259 RCC->CFGR &= ~(0x03 << RCC_CFGR_MCO1);
260 RCC->CFGR |= (RCC_Config.mco1_source << RCC_CFGR_MCO1);
261 /* Check and enable source value */
262 if(RCC_Config.mco1_source == MCO1_HSI){
263 /* Enable HSI source */
264 RCC->CR |= (1 << RCC_CR_HSION);
265 }
266 else if(RCC_Config.mco1_source == MCO1_LSE){
267 /* Disalbe backup protection */
268 PWR_PCLK_EN();
269 PWR->CR |= (1 << PWR_CR_DBP);
270 /* Set LSE bypass */
271 if(RCC_Config.lse_bypass == RCC_LSE_BYPASS){
272 RCC->BDCR |= (1 << RCC_BDCR_LSEBYP);
273 }
274 else{
275 RCC->BDCR &= ~(1 << RCC_BDCR_LSEBYP);
276 }
277 /* Enable LSE source */
278 RCC->BDCR |= (1 << RCC_BDCR_LSEON);
279 }
280 else if(RCC_Config.mco1_source == MCO1_HSE){
281 /* Set HSE mode */
282 if(RCC_Config.hse_mode == RCC_HSE_BYPASS){
283 RCC->CR |= (1 << RCC_CR_HSEBYP);
284 }
285 else{
286 RCC->CR &= ~(1 << RCC_CR_HSEBYP);
287 }
288 /* Enable HSE source */
289 RCC->CR |= (1 << RCC_CR_HSEON);
290 }
291 else{
292 /* Configure PLL */
293 RCC_PLLConfig(RCC_Config);
294 /* Enable PLL */
295 RCC->CR |= (1 << RCC_CR_PLLON);
296 }
297
298 return 0;
299 }
300
301 uint8_t RCC_SetMCO2Clk(RCC_Config_t RCC_Config){
302
303 /* Check if division factor is correct */
304 if(RCC_Config.mco2_presc > MCO_P_5){
305 return 1;
306 }
307
308 /* Clear and set prescaler value */
309 RCC->CFGR &= ~(0x07 << RCC_CFGR_MCO2PRE);
310 RCC->CFGR |= (RCC_Config.mco2_presc << RCC_CFGR_MCO2PRE);
311 /* Clear and set source value */
312 RCC->CFGR &= ~(0x03 << RCC_CFGR_MCO2);
313 RCC->CFGR |= (RCC_Config.mco2_source << RCC_CFGR_MCO2);
314 /* Check and enable source value */
315 if(RCC_Config.mco2_source == MCO2_SYSCLK){
316 /* Do nothing */
317 }
318 else if(RCC_Config.mco2_source == MCO2_PLLI2S){
319 /* Configure PLLI2S */
320 RCC_PLLI2SConfig(RCC_Config);
321 /* Enable PLLI2S */
322 RCC->CR |= (1 << RCC_CR_PLLI2SON);
323 }
324 else if(RCC_Config.mco2_source == MCO2_HSE){
325 /* Set HSE mode */
326 if(RCC_Config.hse_mode == RCC_HSE_BYPASS){
327 RCC->CR |= (1 << RCC_CR_HSEBYP);
328 }
329 else{
330 RCC->CR &= ~(1 << RCC_CR_HSEBYP);
331 }
332 /* Enable HSE source */
333 RCC->CR |= (1 << RCC_CR_HSEON);
334 }
335 else{
336 /* Configure PLL */
337 RCC_PLLConfig(RCC_Config);
338 /* Enable PLL */
339 RCC->CR |= (1 << RCC_CR_PLLON);
340 }
341
342 return 0;
343 }
344
345 /***********************************************************************************************************/
346 /* Static Function Definitions */
347 /***********************************************************************************************************/
348
349 static void RCC_PLLConfig(RCC_Config_t RCC_Config){
350
351 /* Clear and set R prescaler division factor */
352 RCC->PLLCFGR &= ~(0x07 << RCC_PLLCFGR_PLLR);
353 RCC->PLLCFGR |= (RCC_Config.pll_r << RCC_PLLCFGR_PLLR);
354 /* Clear and set Q prescaler division factor */
355 RCC->PLLCFGR &= ~(0x0F << RCC_PLLCFGR_PLLQ);
356 RCC->PLLCFGR |= (RCC_Config.pll_q << RCC_PLLCFGR_PLLQ);
357 /* Clear and set P prescaler division factor */
358 RCC->PLLCFGR &= ~(0x03 << RCC_PLLCFGR_PLLP);
359 RCC->PLLCFGR |= (RCC_Config.pll_p << RCC_PLLCFGR_PLLP);
360 /* Clear and set N prescaler multiplication value */
361 RCC->PLLCFGR &= ~(0x01FF << RCC_PLLCFGR_PLLN);
362 RCC->PLLCFGR |= (RCC_Config.pll_n << RCC_PLLCFGR_PLLN);
363 /* Clear and set M prescaler division factor */
364 RCC->PLLCFGR &= ~(0x3F << RCC_PLLCFGR_PLLM);
365 RCC->PLLCFGR |= (RCC_Config.pll_m << RCC_PLLCFGR_PLLM);
366 /* Clear and set input source for PLL */
367 RCC->PLLCFGR &= ~(0x01 << RCC_PLLCFGR_PLLSRC);
368 RCC->PLLCFGR |= (RCC_Config.pll_source << RCC_PLLCFGR_PLLSRC);
369
370 /* Enable input source for PLL */
371 if(RCC_Config.pll_source == PLL_SOURCE_HSI){
372 /* Enable HSI source */
373 RCC->CR |= (1 << RCC_CR_HSION);
374 }
375 else if(RCC_Config.pll_source == PLL_SOURCE_HSE){
376 /* Set HSE mode */
377 if(RCC_Config.hse_mode == RCC_HSE_BYPASS){
378 RCC->CR |= (1 << RCC_CR_HSEBYP);
379 }
380 else{
381 RCC->CR &= ~(1 << RCC_CR_HSEBYP);
382 }
383 /* Enable HSE source */
384 RCC->CR |= (1 << RCC_CR_HSEON);
385 }
386 else{
387 /* do nothing */
388 }
389 }
390
391 static void RCC_PLLI2SConfig(RCC_Config_t RCC_Config){
392
393 /* Clear and set R prescaler division factor */
394 RCC->PLLI2SCFGR &= ~(0x07 << RCC_PLLI2SCFGR_PLLI2SR);
395 RCC->PLLI2SCFGR |= (RCC_Config.plli2s_r << RCC_PLLI2SCFGR_PLLI2SR);
396 /* Clear and set Q prescaler division factor */
397 RCC->PLLI2SCFGR &= ~(0x0F << RCC_PLLI2SCFGR_PLLI2SQ);
398 RCC->PLLI2SCFGR |= (RCC_Config.plli2s_q << RCC_PLLI2SCFGR_PLLI2SQ);
399 /* Clear and set P prescaler division factor */
400 RCC->PLLI2SCFGR &= ~(0x03 << RCC_PLLI2SCFGR_PLLI2SP);
401 RCC->PLLI2SCFGR |= (RCC_Config.plli2s_p << RCC_PLLI2SCFGR_PLLI2SP);
402 /* Clear and set N prescaler multiplication value */
403 RCC->PLLI2SCFGR &= ~(0x01FF << RCC_PLLI2SCFGR_PLLI2SN);
404 RCC->PLLI2SCFGR |= (RCC_Config.plli2s_n << RCC_PLLI2SCFGR_PLLI2SN);
405 /* Clear and set M prescaler division factor */
406 RCC->PLLI2SCFGR &= ~(0x3F << RCC_PLLI2SCFGR_PLLI2SM);
407 RCC->PLLI2SCFGR |= (RCC_Config.plli2s_m << RCC_PLLI2SCFGR_PLLI2SM);
408 /* Clear and set input source for PLLI2S */
409 RCC->PLLCFGR &= ~(0x01 << RCC_PLLCFGR_PLLSRC);
410 RCC->PLLCFGR |= (RCC_Config.pll_source << RCC_PLLCFGR_PLLSRC);
411
412 /* Enable input source for PLLI2S */
413 if(RCC_Config.pll_source == PLL_SOURCE_HSI){
414 /* Enable HSI source */
415 RCC->CR |= (1 << RCC_CR_HSION);
416 }
417 else if(RCC_Config.pll_source == PLL_SOURCE_HSE){
418 /* Set HSE mode */
419 if(RCC_Config.hse_mode == RCC_HSE_BYPASS){
420 RCC->CR |= (1 << RCC_CR_HSEBYP);
421 }
422 else{
423 RCC->CR &= ~(1 << RCC_CR_HSEBYP);
424 }
425 /* Enable HSE source */
426 RCC->CR |= (1 << RCC_CR_HSEON);
427 }
428 else{
429 /* do nothing */
430 }
431 }
432