]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_STM32F103_Primer_GCC/ST_Code/buzzer.c
Update to use the latest version of the Ride libraries.
[freertos] / Demo / CORTEX_STM32F103_Primer_GCC / ST_Code / buzzer.c
1 /********************* (C) COPYRIGHT 2007 RAISONANCE S.A.S. *******************/\r
2 /**\r
3 *\r
4 * @file     buzzer.c\r
5 * @brief    Buzzer dedicated functions with RTTTL format support.\r
6 * @author   IB\r
7 * @date     07/2007\r
8 *\r
9 **/\r
10 /******************************************************************************/\r
11 \r
12 /* Includes ------------------------------------------------------------------*/\r
13 #include "circle.h"\r
14 \r
15 /// @cond Internal\r
16 \r
17 /* Private typedef -----------------------------------------------------------*/\r
18 \r
19 /*! Octaves */\r
20 enum eOctave  {\r
21       OCT_440  = 0,  /*!< o = 5 */\r
22       OCT_880  = 1,  /*!< o = 6 */\r
23       OCT_1760 = 2,  /*!< o = 7 */\r
24       OCT_3520 = 3,  /*!< o = 8 */\r
25       OCT_7040 = 4   /*!< o = 9 */\r
26       } octave;\r
27 \r
28 /*! Notes */\r
29 enum eNotes  {\r
30       NOTE_PAUSE = 0,    /*!< P  */\r
31       NOTE_LA    = 1,    /*!< A  */\r
32       NOTE_LA_H  = 8+1,  /*!< A# */\r
33       NOTE_SI    = 2,    /*!< B  */\r
34       NOTE_DO    = 3,    /*!< C  */\r
35       NOTE_DO_H  = 8+3,  /*!< C# */\r
36       NOTE_RE    = 4,    /*!< D  */\r
37       NOTE_RE_H  = 8+4,  /*!< D# */\r
38       NOTE_MI    = 5,    /*!< E  */\r
39       NOTE_FA    = 6,    /*!< F  */\r
40       NOTE_FA_H  = 8+6,  /*!< F# */\r
41       NOTE_SOL   = 7,    /*!< G  */\r
42       NOTE_SOL_H = 8+7   /*!< G# */\r
43       } note;\r
44 \r
45 /* Private define ------------------------------------------------------------*/\r
46 #define BUZZER_SHORTBEEP_DURATION   100\r
47 #define BUZZER_LONGBEEP_DURATION    1000\r
48 #define RTTTL_SEP                   ':'\r
49    \r
50 /* Private macro -------------------------------------------------------------*/\r
51 /* Private variables ---------------------------------------------------------*/\r
52 int                              buzz_counter         = 0;\r
53 int                              buzz_in_progress     = 0;\r
54 static TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;\r
55 static TIM_OCInitTypeDef         TIM_OCInitStructure;\r
56 u16                              CCR_Val              = 0x2EE0;\r
57 enum BUZZER_mode                 Buzzer_Mode          = BUZZER_UNDEF;\r
58 u32                              Buzzer_Counter       = 0;\r
59 \r
60 // For the melody.\r
61 const u8*                        CurrentMelody        = 0;\r
62 const u8*                        CurrentMelodySTART   = 0;\r
63 u8                               DefaultOctave        = OCT_880;\r
64 u8                               DefaultDuration      = 4;\r
65 u16                              DefaultBeats         = 63;\r
66 \r
67 u16 Note_Freq [16] = {\r
68    0,    //pause\r
69    440,  //A=LA\r
70    494,  //B=SI\r
71    524,  //C=DO\r
72    588,  //D=RE\r
73    660,  //E=MI\r
74    698,  //F=FA\r
75    784,  //G=SOL\r
76    0,    // "8+n" for "NOTE#"\r
77    466,  //A#=LA#\r
78    0,\r
79    544,  //C#=DO#\r
80    622,  //D#=RE#\r
81    0,\r
82    740,  //F#=FA#\r
83    830   //G#=SOL#\r
84    };\r
85 \r
86 /* Private function prototypes -----------------------------------------------*/\r
87 static void PlayMusic( void );\r
88 static void BUZZER_SetFrequency( u16 freq );\r
89 \r
90 /* Private functions ---------------------------------------------------------*/\r
91 \r
92 /*******************************************************************************\r
93 *\r
94 *                                PlayMusic\r
95 *\r
96 *******************************************************************************/\r
97 /**\r
98 *\r
99 *  Play the next note of the current melody.\r
100 *\r
101 **/\r
102 /******************************************************************************/\r
103 static void PlayMusic( void )\r
104    {\r
105    u8 duration = DefaultDuration;\r
106    u8 c;\r
107 \r
108    // Discard blank characters\r
109    while ( *CurrentMelody == ' ')\r
110       {\r
111       CurrentMelody++;\r
112       }\r
113 \r
114    // Check whether a duration is present.\r
115    if ( (*CurrentMelody > '0') && (*CurrentMelody < '9') )\r
116       {\r
117       duration = *CurrentMelody++ - '0';\r
118 \r
119       if ( (*CurrentMelody > '0') && (*CurrentMelody < '9') )\r
120          {\r
121          duration *= 10;\r
122          duration += (*CurrentMelody++ - '0');\r
123          }\r
124       }\r
125 \r
126    Buzzer_Counter = ( (32/duration) * 256L * 32L) / DefaultBeats;\r
127    Buzzer_Counter*= (RCC_ClockFreq.SYSCLK_Frequency / 12000000L); //Adapt to HCLK1\r
128 \r
129    //read the note\r
130    c = *CurrentMelody++;\r
131 \r
132    if ( (c >= 'a') && (c <= 'z') )\r
133       {\r
134       c+=('A'-'a');\r
135       }\r
136 \r
137    if ( c == 'P' )\r
138       {\r
139       note = NOTE_PAUSE;\r
140       }\r
141    else if ( (c >= 'A') && (c <= 'G') )\r
142       {\r
143       note = (c - 'A') + NOTE_LA;\r
144 \r
145       if ( *CurrentMelody == '#' )\r
146          {\r
147          note|=0x8;\r
148          CurrentMelody++;\r
149          }\r
150       }\r
151 \r
152    octave = DefaultOctave;\r
153    c = *CurrentMelody;\r
154 \r
155    if ( (c>= '5') && (c<= '8') )\r
156       {\r
157       octave = OCT_440 + (c-'5');\r
158       CurrentMelody++;\r
159       }\r
160 \r
161    BUZZER_SetFrequency ( (Note_Freq [ note ] * (1<<octave)));\r
162 \r
163    //discard delimiter and ignore special duration\r
164    while ( (c = *CurrentMelody++) != 0 )\r
165       {\r
166       if ( c==',')\r
167          break;\r
168       }\r
169 \r
170    if ( *(CurrentMelody-1)==0 )\r
171       {\r
172       CurrentMelody  = 0;\r
173       }\r
174 \r
175    if ( c == 0 )\r
176       {\r
177       BUZZER_SetMode ( BUZZER_OFF );\r
178       }\r
179    }\r
180 \r
181 /***********************************************************************************\r
182 *\r
183 *                                BUZZER_SetFrequency\r
184 *\r
185 ************************************************************************************/\r
186 /**\r
187 *\r
188 *  Set the buzzer frequency\r
189 *\r
190 *  @param[in]  freq New frequency.\r
191 *\r
192 **/\r
193 /********************************************************************************/\r
194 void BUZZER_SetFrequency ( u16 freq )\r
195    {\r
196    /* Calculate the frequency (depend on the PCLK1 clock value) */\r
197    CCR_Val = (RCC_ClockFreq.PCLK1_Frequency / freq);\r
198 \r
199    TIM_TimeBaseStructure.TIM_Period          = CCR_Val * 2;\r
200    TIM_TimeBaseStructure.TIM_Prescaler       = 0x0;\r
201    TIM_TimeBaseStructure.TIM_ClockDivision   = 0x0;\r
202    TIM_TimeBaseStructure.TIM_CounterMode     = TIM_CounterMode_Up;\r
203 \r
204    TIM_TimeBaseInit( TIM3, &TIM_TimeBaseStructure );\r
205 \r
206    /* Output Compare Toggle Mode configuration: Channel3 */\r
207    TIM_OCInitStructure.TIM_OCMode   = TIM_OCMode_PWM1;\r
208    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;\r
209    TIM_OCInitStructure.TIM_Pulse    = CCR_Val;\r
210 \r
211    TIM_OC3Init( TIM3, &TIM_OCInitStructure );\r
212    TIM_OC3PreloadConfig( TIM3, TIM_OCPreload_Enable );\r
213    }\r
214 \r
215 /* Public functions for CircleOS ---------------------------------------------*/\r
216 \r
217 /*******************************************************************************\r
218 *\r
219 *                                BUZZER_Init\r
220 *\r
221 *******************************************************************************/\r
222 /**\r
223 *\r
224 *  Buzzer Initialization\r
225 *\r
226 *  @attention  This function must <b>NOT</b> be called by the user.\r
227 *\r
228 **/\r
229 /******************************************************************************/\r
230 void BUZZER_Init( void )\r
231    {\r
232    GPIO_InitTypeDef GPIO_InitStructure;\r
233 \r
234    /* Enable GPIOB clock  */\r
235    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );\r
236 \r
237    /* GPIOB Configuration: TIM3 3in Output */\r
238    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0;\r
239    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;\r
240    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;\r
241 \r
242    GPIO_Init( GPIOB, &GPIO_InitStructure );\r
243 \r
244    /* TIM3 Configuration ------------------------------------------------------*/\r
245    /* TIM3CLK = 18 MHz, Prescaler = 0x0, TIM3 counter clock = 18  MHz */\r
246    /* CC update rate = TIM3 counter clock / (2* CCR_Val) ~= 750 Hz */\r
247 \r
248    /* Enable TIM3 clock */\r
249    RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3, ENABLE );\r
250    TIM_DeInit( TIM3 );\r
251    TIM_TimeBaseStructInit( &TIM_TimeBaseStructure );\r
252    TIM_OCStructInit( &TIM_OCInitStructure );\r
253 \r
254    /* Time base configuration */\r
255    TIM_TimeBaseStructure.TIM_Period          = 0xFFFF;\r
256    TIM_TimeBaseStructure.TIM_Prescaler       = 0x0;\r
257    TIM_TimeBaseStructure.TIM_ClockDivision   = 0x0;\r
258    TIM_TimeBaseStructure.TIM_CounterMode     = TIM_CounterMode_Up;\r
259 \r
260    TIM_TimeBaseInit( TIM3, &TIM_TimeBaseStructure );\r
261 \r
262    /* Output Compare Toggle Mode configuration: Channel3 */\r
263    TIM_OCInitStructure.TIM_OCMode   = TIM_OCMode_Toggle;\r
264    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;\r
265    TIM_OCInitStructure.TIM_Pulse    = CCR_Val;\r
266 \r
267    TIM_OC3Init( TIM3, &TIM_OCInitStructure );\r
268    TIM_OC3PreloadConfig( TIM3, TIM_OCPreload_Disable );\r
269    BUZZER_SetFrequency( 440 );\r
270 \r
271    /* Enable TIM3 IT */\r
272    TIM_ITConfig( TIM3, TIM_IT_CC3, ENABLE );\r
273 \r
274    Buzzer_Mode  = BUZZER_OFF;\r
275    }\r
276 \r
277 /*******************************************************************************\r
278 *\r
279 *                                BUZZER_Handler\r
280 *\r
281 *******************************************************************************/\r
282 /**\r
283 *\r
284 *  Called by the CircleOS scheduler to manage Buzzer tasks.\r
285 *\r
286 *  @attention  This function must <b>NOT</b> be called by the user.\r
287 *\r
288 **/\r
289 /******************************************************************************/\r
290 void BUZZER_Handler( void )\r
291    {\r
292    int fSetOFF = 0;\r
293 \r
294    if ( Buzzer_Mode == BUZZER_PLAYMUSIC )\r
295       {\r
296       if ( Buzzer_Counter == 0 )\r
297          {\r
298          PlayMusic();\r
299          }\r
300       else \r
301          {\r
302          Buzzer_Counter--;\r
303          }\r
304 \r
305       return;\r
306       }\r
307    else if ( Buzzer_Mode == BUZZER_SHORTBEEP )\r
308       {\r
309       if ( Buzzer_Counter++ == (BUZZER_SHORTBEEP_DURATION) ) \r
310          {\r
311          Buzzer_Mode  = BUZZER_OFF;\r
312 \r
313          return;\r
314          }\r
315       if ( Buzzer_Counter == (BUZZER_SHORTBEEP_DURATION/2) )\r
316          {\r
317          fSetOFF = 1;\r
318          }\r
319       }\r
320    else if ( Buzzer_Mode == BUZZER_LONGBEEP )\r
321       {\r
322       if ( Buzzer_Counter++ == (BUZZER_LONGBEEP_DURATION) )\r
323          {\r
324          Buzzer_Mode  = BUZZER_OFF;\r
325 \r
326          return;\r
327          }\r
328       if ( Buzzer_Counter > (BUZZER_LONGBEEP_DURATION/2) )\r
329          {\r
330          fSetOFF = 1;\r
331          }\r
332       }\r
333 \r
334    if ( fSetOFF == 1 )\r
335       {\r
336       TIM_Cmd(TIM3, DISABLE);\r
337       }\r
338    }\r
339 \r
340 /// @endcond\r
341 \r
342 /* Public functions ----------------------------------------------------------*/\r
343 \r
344 /*******************************************************************************\r
345 *\r
346 *                                BUZZER_GetMode\r
347 *\r
348 *******************************************************************************/\r
349 /**\r
350 *\r
351 *  Get the current buzzer mode.\r
352 *\r
353 *  @return  Current buzzer mode.\r
354 *\r
355 **/\r
356 /******************************************************************************/\r
357 enum BUZZER_mode BUZZER_GetMode( void )\r
358    {\r
359    return Buzzer_Mode;\r
360    }\r
361 \r
362 /*******************************************************************************\r
363 *\r
364 *                                BUZZER_SetMode\r
365 *\r
366 *******************************************************************************/\r
367 /**\r
368 *\r
369 *  Set new buzzer mode\r
370 *\r
371 *  @param[in]  mode  New buzzer mode.\r
372 *\r
373 **/\r
374 /******************************************************************************/\r
375 void BUZZER_SetMode( enum BUZZER_mode mode )\r
376    {\r
377    Buzzer_Mode    = mode;\r
378    Buzzer_Counter = 0;\r
379 \r
380    switch ( mode )\r
381       {\r
382       case BUZZER_PLAYMUSIC   :\r
383          PlayMusic(); //start melody\r
384          /* no break */\r
385 \r
386       case BUZZER_LONGBEEP    :\r
387       case BUZZER_SHORTBEEP   :\r
388       case BUZZER_ON          :\r
389          TIM_Cmd( TIM3, ENABLE );\r
390          break;\r
391 \r
392       case BUZZER_OFF         :\r
393          TIM_Cmd( TIM3, DISABLE );\r
394          break;\r
395       }\r
396    }\r
397 \r
398 /*******************************************************************************\r
399 *\r
400 *                                BUZZER_PlayMusic\r
401 *\r
402 *******************************************************************************/\r
403 /**\r
404 *\r
405 *  Plays the provided melody that follows the RTTTL Format.\r
406 *\r
407 *  Official Specification\r
408 *  @verbatim\r
409 <ringing-tones-text-transfer-language> :=\r
410    <name> <sep> [<defaults>] <sep> <note-command>+\r
411 <name> := <char>+ ; maximum name length 10 characters\r
412 <sep> := ":"\r
413 <defaults> :=\r
414    <def-note-duration> |\r
415    <def-note-scale> |\r
416    <def-beats>\r
417 <def-note-duration> := "d=" <duration>\r
418 <def-note-scale> := "o=" <scale>\r
419 <def-beats> := "b=" <beats-per-minute>\r
420 <beats-per-minute> := 25,28,...,900 ; decimal value\r
421 ; If not specified, defaults are\r
422    ;\r
423    ; 4 = duration\r
424    ; 6 = scale\r
425    ; 63 = beats-per-minute\r
426 <note-command> :=\r
427    [<duration>] <note> [<scale>] [<special-duration>] <delimiter>\r
428    <duration> :=\r
429    "1" | ; Full 1/1 note\r
430    "2" | ; 1/2 note\r
431    "4" | ; 1/4 note\r
432    "8" | ; 1/8 note\r
433    "16" | ; 1/16 note\r
434    "32" | ; 1/32 note\r
435 <note> :=\r
436    "P"  | ; pause\r
437    "C"  |\r
438    "C#" |\r
439    "D"  |\r
440    "D#" |\r
441    "E"  |\r
442    "F"  |\r
443    "F#" |\r
444    "G"  |\r
445    "G#" |\r
446    "A"  |\r
447    "A#" |\r
448    "B"\r
449 <scale> :=\r
450    "5" | ; Note A is 440Hz\r
451    "6" | ; Note A is 880Hz\r
452    "7" | ; Note A is 1.76 kHz\r
453    "8" ; Note A is 3.52 kHz\r
454 <special-duration> :=\r
455    "." ; Dotted note\r
456 <delimiter> := ","\r
457 @endverbatim\r
458 *\r
459 *  @param[in]  melody New melody to play on buzzer.\r
460 *\r
461 **/\r
462 /******************************************************************************/\r
463 void BUZZER_PlayMusic (const u8 *melody )\r
464    {\r
465    u8    c;\r
466    u8    default_id  = 0;\r
467    u16   default_val = 0;\r
468 \r
469    DefaultOctave      = OCT_880;  // Default for the default Octave.\r
470    DefaultDuration    = 4;        // Default for the default Duration.\r
471    DefaultBeats       = 63;\r
472    CurrentMelody      = melody;\r
473    CurrentMelodySTART = melody;\r
474 \r
475    while( *CurrentMelody != RTTTL_SEP )\r
476       {\r
477       if( *CurrentMelody == 0 ) \r
478          {\r
479          return;\r
480          }\r
481 \r
482       // Discard the melody name.\r
483       CurrentMelody++; \r
484       }\r
485 \r
486    // Now read the defaults if any.\r
487    for( ++CurrentMelody; *CurrentMelody != RTTTL_SEP; CurrentMelody++ )\r
488       {\r
489       if( *CurrentMelody == 0 ) \r
490          {\r
491          return;\r
492          }\r
493 \r
494       // Discard any blank.\r
495       while ( *CurrentMelody == ' ' ) \r
496          {\r
497          CurrentMelody++;\r
498          }\r
499 \r
500       c = *CurrentMelody;\r
501 \r
502       if ( c == RTTTL_SEP )\r
503          {\r
504          break;\r
505          }\r
506 \r
507       if ( (c >= 'a') && (c <= 'z') )\r
508          {\r
509          c+=('A'-'a');\r
510          }\r
511 \r
512       if ( (c >= 'A') && (c <= 'Z') )\r
513          {\r
514          default_id = c;\r
515          continue;\r
516          }\r
517 \r
518       if ( (c >= '0') && (c <= '9') )\r
519          {\r
520          default_val *= 10;\r
521          default_val += (c-'0');\r
522          c = * (CurrentMelody + 1 );\r
523 \r
524          if ( (c >= '0') && (c <= '9') )\r
525             {\r
526             continue;\r
527             }\r
528 \r
529          if ( default_id == 'D' )\r
530             {\r
531             DefaultDuration = default_val;\r
532             }\r
533          else if ( default_id == 'O' )\r
534             {\r
535             DefaultOctave = default_val - 5;\r
536 \r
537             if ( DefaultOctave > OCT_7040 )\r
538                DefaultOctave = OCT_440;\r
539             }\r
540          else if ( default_id == 'B' )\r
541             {\r
542             DefaultBeats = default_val;\r
543 \r
544             if ( ( DefaultBeats == 0 ) || ( DefaultBeats > 500 ) )\r
545                DefaultBeats = 63;\r
546             }\r
547 \r
548          default_val = 0;\r
549          default_id  = 0;\r
550          }\r
551       }\r
552 \r
553    BUZZER_SetMode( BUZZER_PLAYMUSIC );\r
554    }\r