int main(void) { #if defined( STM32F4XX ) || defined( STM32F10x ) /* Timer und Interrupt-Prioritaeten einstellen */ SystemInit(); SysTick_Config(SystemCoreClock/1000*(SYSTICK_TIMER_INTERVAL_MS)); assert( SystemCoreClock == SYSTEMCORECLOCK_HZ ); /* SysTick-IRQ deaktivieren. In manchen Implementierungen der Standard Peripheral Library funktioniert NVIC_DisableIRQ() nicht mit SysTick_IRQn */ uint32_t saveSysTickCtrl = SysTick->CTRL; SysTick->CTRL = 0; /* NVIC/ISRs konfigurieren */ NVIC_PriorityGroupConfig(0); NVIC_SetPriority(SysTick_IRQn, 1); NVIC_SetPriority(CTRL_LOOP_TIMER_IRQn, 2); NVIC_SetPriority(HIGHSPEED_TIMER_IRQn, 0); /* Alle Interrupts sperren Interrupts duerfen erst erlaubt werden, wenn das LCD und die anderen Fehlerausgabekanaele (Morsen) initialisiert sind, damit eventuelle Fehlermeldungen nicht verloren gehen. */ __disable_irq(); /* SysTick wieder einschalten (laeuft noch nicht los) */ SysTick->CTRL = saveSysTickCtrl; /* Zyklenzaehler fuer Profiling aktivieren */ cyccnt_init(); #ifdef STM32F10x /* Pins des Debug-Interfaces freigeben */ AFIO->MAPR &= ~AFIO_MAPR_SWJ_CFG; // RM0008 S. 176 AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_2; #endif #endif /* GPIOs vorbereiten (Takt fuer GPIO, Takt fuer Alternate Functions etc.) */ initGpioClock(GPIOA); initGpioClock(GPIOB); initGpioClock(GPIOC); initGpioClock(GPIOD); initGpioClock(GPIOE); buzzer_pwm_init(); buzzer_pwm_setFrequency_hz(2000); while(1); } /** Basistakt, aus dem Summer-Frequenz heruntergeteilt wird */ #define PWM_BASE_CLOCK_HZ 2100000 /** Summer: Initialisierung * * Port-Pin einstellen (und als Ausgang konfigurieren), Timer vorbereiten. * @return EXIT_SUCCESS */ exit_t buzzer_pwm_init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; GPIO_TypeDef* GPIOx; TIM_TypeDef* TIMx; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; volatile int mode = BUZZER_PWM; #if( BUZZER_PWM == buzzer_STM32F4XX_TIM3_PB5 ) /* Timer clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); /* GPIO clock enable */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); /* GPIOB Configuration: TIM3 CH2 (PB5) */ GPIOx = GPIOB; TIMx = TIM3; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_Init(GPIOx, &GPIO_InitStructure); /* Connect Timer pins to AF2 */ GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_TIM3); #elif( BUZZER_PWM == buzzer_STM32F4XX_TIM4_PB7 ) /* Timer clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); /* GPIO clock enable */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); /* GPIOB Configuration: TIM4 CH2 (PB7) */ GPIOx = GPIOB; TIMx = TIM4; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; GPIO_Init(GPIOx, &GPIO_InitStructure); /* Connect Timer pins to AF2 */ GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_TIM4); #else #error "Invalid config for buzzer pwm" #endif /* Vorteiler berechnen */ uint32_t prescalerValue = ((SystemCoreClock /2) / PWM_BASE_CLOCK_HZ) - 1; assert(prescalerValue < UINT16_MAX); uint32_t frequ_hz = 2500; uint32_t period = PWM_BASE_CLOCK_HZ / frequ_hz; assert(period < UINT16_MAX); /* Time base configuration */ TIM_TimeBaseStructure.TIM_Period = period; TIM_TimeBaseStructure.TIM_Prescaler = prescalerValue; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure); /* Da nur an einem Pin etwas angeschlossen wird, werden alle Kanaele gleich konfiguriert. */ /* PWM1 Mode configuration: Channel1 bis 4 */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = period/2; // 50% duty cycle TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIMx, &TIM_OCInitStructure); TIM_OC1PreloadConfig(TIMx, TIM_OCPreload_Enable); TIM_OC2Init(TIMx, &TIM_OCInitStructure); TIM_OC2PreloadConfig(TIMx, TIM_OCPreload_Enable); TIM_OC3Init(TIMx, &TIM_OCInitStructure); TIM_OC3PreloadConfig(TIMx, TIM_OCPreload_Enable); TIM_OC4Init(TIMx, &TIM_OCInitStructure); TIM_OC4PreloadConfig(TIMx, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIMx, ENABLE); /* Der Zaehler/Timer wird nicht eingeschaltet, damit der Summer nicht sofort lossummt. */ /* TIMx enable counter */ TIM_Cmd(TIMx, DISABLE); return EXIT_SUCCESS; } /** Summer De-Initialisierung: Pin auf Eingang stellen * * @return EXIT_SUCCESS */ exit_t buzzer_pwm_deinit(void) { switch( BUZZER_PWM ) { case buzzer_STM32F4XX_TIM3_PB5: io_setInput(PB5); io_clearBit(PB5); break; case buzzer_STM32F4XX_TIM4_PB7: io_setInput(PB7); io_clearBit(PB7); break; default: assert(false); break; } return EXIT_SUCCESS; } /** Summer-Frequenz einstellen * * @param[in] f: Frequenz. f = 0 bedeutet ausgeschaltet * @return EXIT_SUCCESS */ exit_t buzzer_pwm_setFrequency_hz(unsigned int f) { TIM_TypeDef* TIMx; switch( BUZZER_PWM ) { case buzzer_STM32F4XX_TIM3_PB5: TIMx = TIM3; break; case buzzer_STM32F4XX_TIM4_PB7: TIMx = TIM4; break; default: assert(false); break; } volatile TIM_TypeDef* TIMxx = TIMx; // FIXME: Nur fuer Debug if( f == 0 ) { /* Disable Buzzer */ TIM_Cmd(TIMx, DISABLE); } else { /* Counter overflow value */ uint32_t period = PWM_BASE_CLOCK_HZ / f; assert(period < UINT16_MAX); TIMx->ARR = period; /* Set the Capture Compare Register value */ TIMx->CCR1 = period/2; TIMx->CCR2 = period/2; TIMx->CCR3 = period/2; TIMx->CCR4 = period/2; TIM_Cmd(TIMx, ENABLE); } return EXIT_SUCCESS; }