1 /********************* (C) COPYRIGHT 2007 RAISONANCE S.A.S. *******************/
\r
5 * @brief Buzzer dedicated functions with RTTTL format support.
\r
10 /******************************************************************************/
\r
12 /* Includes ------------------------------------------------------------------*/
\r
17 /* Private typedef -----------------------------------------------------------*/
\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
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
45 /* Private define ------------------------------------------------------------*/
\r
46 #define BUZZER_SHORTBEEP_DURATION 100
\r
47 #define BUZZER_LONGBEEP_DURATION 1000
\r
48 #define RTTTL_SEP ':'
\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
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
67 u16 Note_Freq [16] = {
\r
76 0, // "8+n" for "NOTE#"
\r
86 /* Private function prototypes -----------------------------------------------*/
\r
87 static void PlayMusic( void );
\r
88 static void BUZZER_SetFrequency( u16 freq );
\r
90 /* Private functions ---------------------------------------------------------*/
\r
92 /*******************************************************************************
\r
96 *******************************************************************************/
\r
99 * Play the next note of the current melody.
\r
102 /******************************************************************************/
\r
103 static void PlayMusic( void )
\r
105 u8 duration = DefaultDuration;
\r
108 // Discard blank characters
\r
109 while ( *CurrentMelody == ' ')
\r
114 // Check whether a duration is present.
\r
115 if ( (*CurrentMelody > '0') && (*CurrentMelody < '9') )
\r
117 duration = *CurrentMelody++ - '0';
\r
119 if ( (*CurrentMelody > '0') && (*CurrentMelody < '9') )
\r
122 duration += (*CurrentMelody++ - '0');
\r
126 Buzzer_Counter = ( (32/duration) * 256L * 32L) / DefaultBeats;
\r
127 Buzzer_Counter*= (RCC_ClockFreq.SYSCLK_Frequency / 12000000L); //Adapt to HCLK1
\r
130 c = *CurrentMelody++;
\r
132 if ( (c >= 'a') && (c <= 'z') )
\r
141 else if ( (c >= 'A') && (c <= 'G') )
\r
143 note = (c - 'A') + NOTE_LA;
\r
145 if ( *CurrentMelody == '#' )
\r
152 octave = DefaultOctave;
\r
153 c = *CurrentMelody;
\r
155 if ( (c>= '5') && (c<= '8') )
\r
157 octave = OCT_440 + (c-'5');
\r
161 BUZZER_SetFrequency ( (Note_Freq [ note ] * (1<<octave)));
\r
163 //discard delimiter and ignore special duration
\r
164 while ( (c = *CurrentMelody++) != 0 )
\r
170 if ( *(CurrentMelody-1)==0 )
\r
177 BUZZER_SetMode ( BUZZER_OFF );
\r
181 /***********************************************************************************
\r
183 * BUZZER_SetFrequency
\r
185 ************************************************************************************/
\r
188 * Set the buzzer frequency
\r
190 * @param[in] freq New frequency.
\r
193 /********************************************************************************/
\r
194 void BUZZER_SetFrequency ( u16 freq )
\r
196 /* Calculate the frequency (depend on the PCLK1 clock value) */
\r
197 CCR_Val = (RCC_ClockFreq.PCLK1_Frequency / freq);
\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
204 TIM_TimeBaseInit( TIM3, &TIM_TimeBaseStructure );
\r
206 /* Output Compare Toggle Mode configuration: Channel3 */
\r
207 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
\r
208 TIM_OCInitStructure.TIM_Channel = TIM_Channel_3;
\r
209 TIM_OCInitStructure.TIM_Pulse = CCR_Val;
\r
211 TIM_OCInit( TIM3, &TIM_OCInitStructure );
\r
212 TIM_OC3PreloadConfig( TIM3, TIM_OCPreload_Enable );
\r
215 /* Public functions for CircleOS ---------------------------------------------*/
\r
217 /*******************************************************************************
\r
221 *******************************************************************************/
\r
224 * Buzzer Initialization
\r
226 * @attention This function must <b>NOT</b> be called by the user.
\r
229 /******************************************************************************/
\r
230 void BUZZER_Init( void )
\r
232 GPIO_InitTypeDef GPIO_InitStructure;
\r
234 /* Enable GPIOB clock */
\r
235 RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
\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
242 GPIO_Init( GPIOB, &GPIO_InitStructure );
\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
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
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
260 TIM_TimeBaseInit( TIM3, &TIM_TimeBaseStructure );
\r
262 /* Output Compare Toggle Mode configuration: Channel3 */
\r
263 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
\r
264 TIM_OCInitStructure.TIM_Channel = TIM_Channel_3;
\r
265 TIM_OCInitStructure.TIM_Pulse = CCR_Val;
\r
267 TIM_OCInit( TIM3, &TIM_OCInitStructure );
\r
268 TIM_OC3PreloadConfig( TIM3, TIM_OCPreload_Disable );
\r
269 BUZZER_SetFrequency( 440 );
\r
271 /* Enable TIM3 IT */
\r
272 TIM_ITConfig( TIM3, TIM_IT_CC3, ENABLE );
\r
274 Buzzer_Mode = BUZZER_OFF;
\r
277 /*******************************************************************************
\r
281 *******************************************************************************/
\r
284 * Called by the CircleOS scheduler to manage Buzzer tasks.
\r
286 * @attention This function must <b>NOT</b> be called by the user.
\r
289 /******************************************************************************/
\r
290 void BUZZER_Handler( void )
\r
294 if ( Buzzer_Mode == BUZZER_PLAYMUSIC )
\r
296 if ( Buzzer_Counter == 0 )
\r
307 else if ( Buzzer_Mode == BUZZER_SHORTBEEP )
\r
309 if ( Buzzer_Counter++ == (BUZZER_SHORTBEEP_DURATION) )
\r
311 Buzzer_Mode = BUZZER_OFF;
\r
315 if ( Buzzer_Counter == (BUZZER_SHORTBEEP_DURATION/2) )
\r
320 else if ( Buzzer_Mode == BUZZER_LONGBEEP )
\r
322 if ( Buzzer_Counter++ == (BUZZER_LONGBEEP_DURATION) )
\r
324 Buzzer_Mode = BUZZER_OFF;
\r
328 if ( Buzzer_Counter > (BUZZER_LONGBEEP_DURATION/2) )
\r
334 if ( fSetOFF == 1 )
\r
336 TIM_Cmd(TIM3, DISABLE);
\r
342 /* Public functions ----------------------------------------------------------*/
\r
344 /*******************************************************************************
\r
348 *******************************************************************************/
\r
351 * Get the current buzzer mode.
\r
353 * @return Current buzzer mode.
\r
356 /******************************************************************************/
\r
357 enum BUZZER_mode BUZZER_GetMode( void )
\r
359 return Buzzer_Mode;
\r
362 /*******************************************************************************
\r
366 *******************************************************************************/
\r
369 * Set new buzzer mode
\r
371 * @param[in] mode New buzzer mode.
\r
374 /******************************************************************************/
\r
375 void BUZZER_SetMode( enum BUZZER_mode mode )
\r
377 Buzzer_Mode = mode;
\r
378 Buzzer_Counter = 0;
\r
382 case BUZZER_PLAYMUSIC :
\r
383 PlayMusic(); //start melody
\r
386 case BUZZER_LONGBEEP :
\r
387 case BUZZER_SHORTBEEP :
\r
389 TIM_Cmd( TIM3, ENABLE );
\r
393 TIM_Cmd( TIM3, DISABLE );
\r
398 /*******************************************************************************
\r
402 *******************************************************************************/
\r
405 * Plays the provided melody that follows the RTTTL Format.
\r
407 * Official Specification
\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
414 <def-note-duration> |
\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
425 ; 63 = beats-per-minute
\r
427 [<duration>] <note> [<scale>] [<special-duration>] <delimiter>
\r
429 "1" | ; Full 1/1 note
\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
459 * @param[in] melody New melody to play on buzzer.
\r
462 /******************************************************************************/
\r
463 void BUZZER_PlayMusic (const u8 *melody )
\r
467 u16 default_val = 0;
\r
469 DefaultOctave = OCT_880; // Default for the default Octave.
\r
470 DefaultDuration = 4; // Default for the default Duration.
\r
472 CurrentMelody = melody;
\r
473 CurrentMelodySTART = melody;
\r
475 while( *CurrentMelody != RTTTL_SEP )
\r
477 if( *CurrentMelody == 0 )
\r
482 // Discard the melody name.
\r
486 // Now read the defaults if any.
\r
487 for( ++CurrentMelody; *CurrentMelody != RTTTL_SEP; CurrentMelody++ )
\r
489 if( *CurrentMelody == 0 )
\r
494 // Discard any blank.
\r
495 while ( *CurrentMelody == ' ' )
\r
500 c = *CurrentMelody;
\r
502 if ( c == RTTTL_SEP )
\r
507 if ( (c >= 'a') && (c <= 'z') )
\r
512 if ( (c >= 'A') && (c <= 'Z') )
\r
518 if ( (c >= '0') && (c <= '9') )
\r
521 default_val += (c-'0');
\r
522 c = * (CurrentMelody + 1 );
\r
524 if ( (c >= '0') && (c <= '9') )
\r
529 if ( default_id == 'D' )
\r
531 DefaultDuration = default_val;
\r
533 else if ( default_id == 'O' )
\r
535 DefaultOctave = default_val - 5;
\r
537 if ( DefaultOctave > OCT_7040 )
\r
538 DefaultOctave = OCT_440;
\r
540 else if ( default_id == 'B' )
\r
542 DefaultBeats = default_val;
\r
544 if ( ( DefaultBeats == 0 ) || ( DefaultBeats > 500 ) )
\r
553 BUZZER_SetMode( BUZZER_PLAYMUSIC );
\r