Choco OS  V.0.16.9.0
Join to the chocolate world
oc_saipll.c
1 
27 #include <oc_saipll.h>
28 #include <oc_machine.h>
29 #include <oc_lsf.h>
30 #include <oc_clock_lld.h>
31 #include <oc_array.h>
32 #include <oc_math.h>
33 #include <oc_mcs.h>
34 
40 #define _________________________________________MACROS_SECTION_____________________________________________________________________________
41 
42 #define IsRam(Address) (oC_LSF_IsRamAddress(Address) || oC_LSF_IsExternalAddress(Address))
43 #define IsRom(Address) oC_LSF_IsRomAddress(Address)
44 #define RCC_CR oC_Register(RCC,RCC_CR)
45 #define RCC_PLLSAICFGR oC_Register(RCC,RCC_PLLSAICFGR)
46 #define RCC_PLLCFGR oC_Register(RCC,RCC_PLLCFGR)
47 #define RCC_DCKCFGR oC_Register(RCC,RCC_DCKCFGR)
48 #define IsOutputLineUsed(OutputLineIndex) (WantedFrequencies[OutputLineIndex] != 0)
49 #define IsAnyOutputLineUsed() (IsOutputLineUsed(oC_SaiPll_OutputLine_LTDC) || \
50  IsOutputLineUsed(oC_SaiPll_OutputLine_PLL48CLK) || \
51  IsOutputLineUsed(oC_SaiPll_OutputLine_SAICLK) )
52 #define SetOutputLineUsed(OutputLineIndex,Freq,PermissibleDifference) \
53  WantedFrequencies[OutputLineIndex] = Freq;\
54  PermissibleDifferencies[OutputLineIndex]= PermissibleDifference
55 #define GetPllSaiPDivisor(RegisterValue) ( ((RegisterValue+1)<<1) )
56 #define GetPllSaiDivRDivisor(RegisterValue) ( 0x2 <<(RegisterValue) )
57 #define CountFrequency(Input,Divisor) ( (oC_Frequency_t) (((oC_Frequency_t)(Input))/( (oC_Frequency_t)(Divisor) )))
58 #define IsFrequencyAcceptable(WantedFrequency,PermissibleDifference,Frequency) ( oC_ABS(WantedFrequency,Frequency) <= PermissibleDifference )
59 #define IsPLLSAIxCorrect(PLLSAIx,OutputLineIndex) ( (PLLSAIx) >= PLLSAIxRanges[OutputLineIndex].Min && (PLLSAIx) <= PLLSAIxRanges[OutputLineIndex].Max )
60 #define IsPLLSAIDIVxCorrect(PLLSAIDIVx,OutputLineIndex) ( (PLLSAIDIVx) >= PLLSAIDIVxRanges[OutputLineIndex].Min && (PLLSAIDIVx) <= PLLSAIDIVxRanges[OutputLineIndex].Max )
61 
62 #undef _________________________________________MACROS_SECTION_____________________________________________________________________________
63 
69 #define _________________________________________TYPES_SECTION______________________________________________________________________________
70 
71 typedef struct
72 {
73  uint8_t PLLM;
74  uint16_t PLLSAIN;
75 
76  union
77  {
78  struct
79  {
80  uint16_t PLLSAIR;
81  uint16_t PLLSAIP;
82  uint16_t PLLSAIQ;
83  };
84  uint16_t PLLSAIx[oC_SaiPll_OutputLine_NumberOfElements];
85  };
86 
87  union
88  {
89  struct
90  {
91  uint16_t PLLSAIDIVR;
92  uint16_t PLLSAIDIVP;
93  uint16_t PLLSAIDIVQ;
94  };
95  uint16_t PLLSAIDIVx[oC_SaiPll_OutputLine_NumberOfElements];
96  };
97 } PllConfig_t;
98 
99 typedef struct
100 {
101  oC_Frequency_t PllSaiInput;
102  oC_Frequency_t VcoOutput;
103 
104  union
105  {
106  struct
107  {
108  oC_Frequency_t PLLSAIR;
109  oC_Frequency_t PLLSAIP;
110  oC_Frequency_t PLLSAIQ;
111  };
113  };
114 
115  union
116  {
117  struct
118  {
119  oC_Frequency_t LTDC;
120  oC_Frequency_t PLL48CLK;
121  oC_Frequency_t SAICLK;
122  };
124  };
126 
127 typedef struct
128 {
129  uint16_t Min;
130  uint16_t Max;
131 } Range_t;
132 
133 typedef struct
134 {
135  uint16_t ValueForRegister;
136  oC_SaiPll_OutputLine_t OutputLine;
137 } Divisor_t;
138 
139 #undef _________________________________________TYPES_SECTION______________________________________________________________________________
140 
146 #define _________________________________________LOCAL_PROTOTYPES_SECTION___________________________________________________________________
147 
148 static oC_ErrorCode_t ReadCurrentPllConfig ( PllConfig_t * outPllConfig );
149 static void CountFrequencies ( PllConfig_t * PllConfig , LineFrequencies_t * outFrequencies );
150 static bool FindDivisorForOutputLine ( PllConfig_t * PllConfig , oC_SaiPll_OutputLine_t OutputLineIndex , oC_Frequency_t Frequency , oC_Frequency_t PermissibleDifference , oC_Frequency_t * outRealFrequency );
151 static oC_ErrorCode_t FindNewPllConfig ( PllConfig_t * PllConfig , oC_SaiPll_OutputLine_t OutputLineIndex , oC_Frequency_t Frequency , oC_Frequency_t PermissibleDifference , oC_Frequency_t * outRealFrequency );
152 static oC_ErrorCode_t ConfigurePll ( PllConfig_t * PllConfig , oC_SaiPll_OutputLine_t OutputLine );
153 
154 #undef _________________________________________LOCAL_PROTOTYPES_SECTION___________________________________________________________________
155 
161 #define _________________________________________VARIABLES_SECTION__________________________________________________________________________
162 
163 static oC_Frequency_t WantedFrequencies[oC_SaiPll_OutputLine_NumberOfElements] = {0};
164 static oC_Frequency_t PermissibleDifferencies[oC_SaiPll_OutputLine_NumberOfElements] = {0};
165 static const Range_t PLLSAIxRanges[oC_SaiPll_OutputLine_NumberOfElements] = {
166  [oC_SaiPll_OutputLine_LTDC] = { .Min = 2 , .Max = 7 },
167  [oC_SaiPll_OutputLine_PLL48CLK] = { .Min = 0 , .Max = 3 },
168  [oC_SaiPll_OutputLine_SAICLK] = { .Min = 2 , .Max = 15 },
169 };
170 static const Range_t PLLSAIDIVxRanges[oC_SaiPll_OutputLine_NumberOfElements] = {
171  [oC_SaiPll_OutputLine_LTDC] = { .Min = 0 , .Max = 3 },
172  [oC_SaiPll_OutputLine_PLL48CLK] = { .Min = 0 , .Max = 1 },
173  [oC_SaiPll_OutputLine_SAICLK] = { .Min = 0 , .Max = 31 },
174 };
175 
176 
177 #undef _________________________________________VARIABLES_SECTION__________________________________________________________________________
178 
179 
185 #define _________________________________________INTERFACE_FUNCTIONS_SECTION________________________________________________________________
186 
187 //==========================================================================================================================================
200 //==========================================================================================================================================
201 oC_ErrorCode_t oC_SaiPll_Configure( oC_SaiPll_OutputLine_t OutputLine , oC_Frequency_t Frequency , oC_Frequency_t PermissibleDifference , oC_Frequency_t * outRealFrequency )
202 {
203  oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
204  oC_SaiPll_OutputLine_t outputLineIndex = OutputLine & oC_SaiPll_OutputLine_IndexMask;
205 
206  if(
207  ErrorCondition( outputLineIndex < oC_SaiPll_OutputLine_NumberOfElements , oC_ErrorCode_WrongParameters ) &&
208  ErrorCondition( Frequency > 0 , oC_ErrorCode_WrongFrequency ) &&
209  ErrorCondition( IsRam(outRealFrequency) , oC_ErrorCode_OutputAddressNotInRAM )
210  )
211  {
212  PllConfig_t pllConfig = {0};
213 
214  if(
215  oC_AssignErrorCode(&errorCode , ReadCurrentPllConfig(&pllConfig) ) &&
216  oC_AssignErrorCode(&errorCode , FindNewPllConfig(&pllConfig,outputLineIndex,Frequency,PermissibleDifference,outRealFrequency) ) &&
217  oC_AssignErrorCode(&errorCode , ConfigurePll(&pllConfig,OutputLine) )
218  )
219  {
220  SetOutputLineUsed(outputLineIndex,Frequency,PermissibleDifference);
221  errorCode = oC_ErrorCode_None;
222  }
223  }
224 
225  return errorCode;
226 }
227 
228 #undef _________________________________________INTERFACE_FUNCTIONS_SECTION________________________________________________________________
229 
235 #define _________________________________________LOCAL_FUNCTIONS_SECTION____________________________________________________________________
236 
237 //==========================================================================================================================================
241 //==========================================================================================================================================
242 static oC_ErrorCode_t ReadCurrentPllConfig( PllConfig_t * outPllConfig )
243 {
244  oC_ErrorCode_t errorCode = oC_ErrorCode_None;
245 
247 
248  outPllConfig->PLLM = RCC_PLLCFGR->PLLM;
249  outPllConfig->PLLSAIN = RCC_PLLSAICFGR->PLLSAIN;
250  outPllConfig->PLLSAIP = RCC_PLLSAICFGR->PLLSAIP;
251  outPllConfig->PLLSAIQ = RCC_PLLSAICFGR->PLLSAIQ;
252  outPllConfig->PLLSAIR = RCC_PLLSAICFGR->PLLSAIR;
253 
254  outPllConfig->PLLSAIDIVQ= RCC_DCKCFGR->PLLSAIDIVQ;
255  outPllConfig->PLLSAIDIVR= RCC_DCKCFGR->PLLSAIDIVR;
256  outPllConfig->PLLSAIDIVP= 1;
257 
259 
260  return errorCode;
261 }
262 
263 
264 //==========================================================================================================================================
268 //==========================================================================================================================================
269 static void CountFrequencies( PllConfig_t * PllConfig , LineFrequencies_t * outFrequencies )
270 {
271  oC_Frequency_t oscillatorFrequency = oC_CLOCK_LLD_GetOscillatorFrequency();
272 
273  /* ********************************************************************
274  * *
275  * If these assertions failed, then something goes really wrong. *
276  * Probably registers addresses are not set correctly, cause this *
277  * cannot be 0. *
278  * The other option is that the local functions are not called *
279  * correctly - this is mean, that PllConfig is not initialized before *
280  * usage. It should be read from the machine registers by using *
281  * function 'ReadCurrentPllConfig' *
282  * *
283  * ********************************************************************/
284  oC_ASSERT(PllConfig->PLLSAIQ > 0);
285  oC_ASSERT(PllConfig->PLLSAIR > 0);
286 
287  outFrequencies->PllSaiInput = CountFrequency(oscillatorFrequency , PllConfig->PLLM);
288  outFrequencies->VcoOutput = outFrequencies->PllSaiInput * ((oC_Frequency_t)PllConfig->PLLSAIN);
289  outFrequencies->PLLSAIP = CountFrequency(outFrequencies->VcoOutput , GetPllSaiPDivisor(PllConfig->PLLSAIP));
290  outFrequencies->PLLSAIQ = CountFrequency(outFrequencies->VcoOutput , PllConfig->PLLSAIQ);
291  outFrequencies->PLLSAIR = CountFrequency(outFrequencies->VcoOutput , PllConfig->PLLSAIR);
292  outFrequencies->LTDC = CountFrequency(outFrequencies->PLLSAIR , GetPllSaiDivRDivisor(PllConfig->PLLSAIDIVR));
293  outFrequencies->SAICLK = CountFrequency(outFrequencies->PLLSAIQ , PllConfig->PLLSAIDIVQ + 1);
294  outFrequencies->PLL48CLK = outFrequencies->PLLSAIP;
295 
296 }
297 
298 //==========================================================================================================================================
302 //==========================================================================================================================================
303 static bool FindDivisorForOutputLine(PllConfig_t * PllConfig , oC_SaiPll_OutputLine_t OutputLineIndex , oC_Frequency_t Frequency , oC_Frequency_t PermissibleDifference , oC_Frequency_t * outRealFrequency )
304 {
305  bool found = false;
306  LineFrequencies_t newFrequencies = {0};
307 
308  for(uint16_t PLLSAIx = PLLSAIxRanges[OutputLineIndex].Min ; !found && PLLSAIx <= PLLSAIxRanges[OutputLineIndex].Max ; PLLSAIx++)
309  {
310  PllConfig->PLLSAIx[OutputLineIndex] = PLLSAIx;
311 
312  for(uint16_t PLLSAIDIVx = PLLSAIDIVxRanges[OutputLineIndex].Min ; PLLSAIDIVx <= PLLSAIDIVxRanges[OutputLineIndex].Max ; PLLSAIDIVx++)
313  {
314  PllConfig->PLLSAIDIVx[OutputLineIndex] = PLLSAIDIVx;
315 
316  CountFrequencies(PllConfig , &newFrequencies);
317 
318  if(IsFrequencyAcceptable(Frequency,PermissibleDifference,newFrequencies.OutputLinesFrequencies[OutputLineIndex]))
319  {
320  found = true;
321  if(outRealFrequency)
322  {
323  *outRealFrequency = newFrequencies.OutputLinesFrequencies[OutputLineIndex];
324  }
325  break;
326  }
327  }
328  }
329 
330  return found;
331 }
332 
333 //==========================================================================================================================================
337 //==========================================================================================================================================
338 static oC_ErrorCode_t FindNewPllConfig( PllConfig_t * PllConfig , oC_SaiPll_OutputLine_t OutputLineIndex , oC_Frequency_t Frequency , oC_Frequency_t PermissibleDifference , oC_Frequency_t * outRealFrequency )
339 {
340  oC_ErrorCode_t errorCode = oC_ErrorCode_FrequencyNotPossible;
341 
343 
344  if(IsAnyOutputLineUsed() && FindDivisorForOutputLine(PllConfig,OutputLineIndex,Frequency,PermissibleDifference,outRealFrequency))
345  {
346  /* **************************************
347  * Some PLL output is used, so we must *
348  * try to reconfigure the PLL first *
349  * **************************************/
350  errorCode = oC_ErrorCode_None;
351  }
352 
353  if(oC_ErrorOccur(errorCode))
354  {
355  /* ****************************************
356  * Frequency not found, not possible or
357  * none of output lines is used, so
358  * we must/can to try reconfigure PLL
359  * ****************************************/
360 
361  for(PllConfig->PLLSAIN = 49 ; PllConfig->PLLSAIN < 433 ; PllConfig->PLLSAIN++)
362  {
363  bool foundAll = true;
364 
365  for( oC_SaiPll_OutputLine_t outputLineIndex = 0 ; outputLineIndex < oC_SaiPll_OutputLine_NumberOfElements && foundAll ; outputLineIndex++ )
366  {
367  if(OutputLineIndex == outputLineIndex)
368  {
369  foundAll = foundAll && FindDivisorForOutputLine(PllConfig,OutputLineIndex,Frequency,PermissibleDifference,outRealFrequency);
370  }
371  else if(IsOutputLineUsed(outputLineIndex))
372  {
373  foundAll = foundAll && FindDivisorForOutputLine(PllConfig,outputLineIndex,WantedFrequencies[outputLineIndex],PermissibleDifferencies[outputLineIndex],NULL);
374  }
375  }
376 
377  if(foundAll)
378  {
379  /* We found all needed frequencies, so we can stop here */
380  errorCode = oC_ErrorCode_None;
381  break;
382  }
383  }
384  }
385 
387 
388  return errorCode;
389 }
390 
391 //==========================================================================================================================================
395 //==========================================================================================================================================
396 static oC_ErrorCode_t ConfigurePll( PllConfig_t * PllConfig , oC_SaiPll_OutputLine_t OutputLine )
397 {
398  oC_ErrorCode_t errorCode = oC_ErrorCode_None;
399 
400  for(oC_SaiPll_OutputLine_t outputLineIndex = 0; outputLineIndex < oC_SaiPll_OutputLine_NumberOfElements ; outputLineIndex++ )
401  {
402  uint16_t PLLSAIx = PllConfig->PLLSAIx[outputLineIndex];
403  uint16_t PLLSAIDIVx = PllConfig->PLLSAIDIVx[outputLineIndex];
404 
405  if( !IsPLLSAIxCorrect(PLLSAIx , outputLineIndex) )
406  {
407  errorCode = oC_ErrorCode_MachineCanBeDamaged;
408  }
409  if( !IsPLLSAIDIVxCorrect(PLLSAIDIVx , outputLineIndex) )
410  {
411  errorCode = oC_ErrorCode_MachineCanBeDamaged;
412  }
413  }
414 
415  if(!oC_ErrorOccur(errorCode))
416  {
418 
419  RCC_CR->PLLSAION = 0;
420 
421  while(RCC_CR->PLLSAIRDY == 1);
422 
423  RCC_PLLSAICFGR->PLLSAIN = PllConfig->PLLSAIN;
424  RCC_PLLSAICFGR->PLLSAIP = PllConfig->PLLSAIP;
425  RCC_PLLSAICFGR->PLLSAIQ = PllConfig->PLLSAIQ;
426  RCC_PLLSAICFGR->PLLSAIR = PllConfig->PLLSAIR;
427 
428  RCC_DCKCFGR->PLLSAIDIVR = PllConfig->PLLSAIDIVR;
429  RCC_DCKCFGR->PLLSAIDIVQ = PllConfig->PLLSAIDIVQ;
430 
431  if(OutputLine & oC_SaiPll_OutputLine_SAI1CLK)
432  {
433  RCC_DCKCFGR->SAI1SEL = 0;
434  }
435  if(OutputLine & oC_SaiPll_OutputLine_SAI2CLK)
436  {
437  RCC_DCKCFGR->SAI2SEL = 0;
438  }
439 
440  RCC_CR->PLLSAION = 1;
441 
442  while(RCC_CR->PLLSAIRDY == 0);
443 
445  }
446 
447  return errorCode;
448 }
449 
450 #undef _________________________________________LOCAL_FUNCTIONS_SECTION____________________________________________________________________
Basic math operations.
oC_SaiPll_OutputLine_t
stores selection of the output line
Definition: oc_saipll.h:55
double oC_Frequency_t
type to store frequency
Definition: oc_frequency.h:76
Number of main elements (maximum index) in the type.
Definition: oc_saipll.h:60
The file with interface for LSF module.
Additional definition for SAI2 CLK line.
Definition: oc_saipll.h:63
Output of the PLL connected to the LTDC module (LTDC Clock)
Definition: oc_saipll.h:57
Additional definition for SAI1 CLK line.
Definition: oc_saipll.h:62
The file with LLD interface for the CLOCK driver.
This is the mask to get index of the line from the type.
Definition: oc_saipll.h:61
Contains machine core specific functions.
Output of the PLL connected to the PLL48CLK.
Definition: oc_saipll.h:58
static void oC_MCS_EnterCriticalSection(void)
Enters to critical section.
Definition: oc_mcs.h:755
Static array definitions.
Output of the PLL connected to the SAI.
Definition: oc_saipll.h:59
The file with interface for the machine module.
static bool oC_MCS_ExitCriticalSection(void)
Exits from critical section.
Definition: oc_mcs.h:784
oC_ErrorCode_t oC_SaiPll_Configure(oC_SaiPll_OutputLine_t OutputLine, oC_Frequency_t Frequency, oC_Frequency_t PermissibleDifference, oC_Frequency_t *outRealFrequency)
Configures SAI PLL.
Definition: oc_saipll.c:201
oC_Frequency_t oC_CLOCK_LLD_GetOscillatorFrequency(void)
returns frequency of the oscillator
Definition: oc_clock_lld.c:248
#define NULL
pointer to a zero
Definition: oc_null.h:37