/** Configure and enable RCC for peripherals (ADC1, ADC2, Timer) */ static inline void adc_init_rcc( void ) { #if USE_AD1 || USE_AD2 || USE_AD3 /* Timer peripheral clock enable. */ rcc_periph_clock_enable(RCC_TIM_ADC); #if defined(STM32F4) adc_set_clk_prescale(ADC_CCR_ADCPRE_BY2); #endif /* Enable ADC peripheral clocks. */ #if USE_AD1 rcc_periph_clock_enable(RCC_ADC1); #endif #if USE_AD2 rcc_periph_clock_enable(RCC_ADC2); #endif #if USE_AD3 rcc_periph_clock_enable(RCC_ADC3); #endif /* Time Base configuration */ timer_reset(TIM_ADC); timer_set_mode(TIM_ADC, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); /* timer counts with ADC_TIMER_FREQUENCY */ uint32_t timer_clk = timer_get_frequency(TIM_ADC); timer_set_prescaler(TIM_ADC, (timer_clk / ADC_TIMER_FREQUENCY) - 1); timer_set_period(TIM_ADC, ADC_TIMER_PERIOD); /* Generate TRGO on every update (when counter reaches period reload value) */ timer_set_master_mode(TIM_ADC, TIM_CR2_MMS_UPDATE); timer_enable_counter(TIM_ADC); #endif // USE_AD1 || USE_AD2 || USE_AD3 }
void funcgen_plat_timer_setup(int channel, int period_ns) { uint32_t timer; switch (channel) { case 1: timer = TIM7; break; case 0: default: timer = TIM6; break; } timer_reset(timer); // APB is maxed at 42Mhz, so APB timers run at 84Mhz // dac says 1msps max max, so at 1msps, we want a period of what, 1 Mhz _overflows_ // so at least 2 Mhz clock..., let's say 4 Mhz timer clock for max res stuff // want to run the clock pretty quick, let's say 50ns steps or so at the bottom end, // at ~24Mhz or similar, // this is _F4_ specific! /* two ranges is probably su*/ if (period_ns > 50) { timer_set_prescaler(timer, 3); // 84 / 21 - 1 ticks at ~48ns timer_set_period(timer, (period_ns / 48) - 1); } // if (period_ns * 50 > 0x6000) { // /* don't even try and run that fast with this slow a wave */ // timer_set_prescaler(timer, 83); // 1Mhz (84/1 - 1) ticks at 1usecs // timer_set_period(timer, (period_ns / 1000) - 1); // } timer_enable_irq(timer, TIM_DIER_UIE); timer_set_master_mode(timer, TIM_CR2_MMS_UPDATE); timer_enable_counter(timer); }
/* Configure and enable RCC for peripherals (ADC1, ADC2, Timer) */ static inline void adc_init_rcc( void ) { #if defined (USE_AD1) || defined (USE_AD2) uint32_t timer; volatile uint32_t *rcc_apbenr; uint32_t rcc_apb; #if defined(USE_AD_TIM4) timer = TIM4; rcc_apbenr = &RCC_APB1ENR; rcc_apb = RCC_APB1ENR_TIM4EN; #elif defined(USE_AD_TIM1) timer = TIM1; rcc_apbenr = &RCC_APB2ENR; rcc_apb = RCC_APB2ENR_TIM1EN; #else timer = TIM2; rcc_apbenr = &RCC_APB1ENR; rcc_apb = RCC_APB1ENR_TIM2EN; #endif /* * Historic Note: * Previously in libstm32 we were setting the ADC clock here. * It was being set to PCLK2 DIV2 resulting in 36MHz clock on the ADC. I am * pretty sure that this is wrong as based on the datasheet the ADC clock * must not exceed 14MHz! Now the clock is being set by the clock init * routine in libopencm3 so we don't have to set up this clock ourselves any * more. This comment is here just as a reminder and may be removed in the * future when we know that everything is working properly. * (by Esden the historian :D) */ /* Timer peripheral clock enable. */ rcc_peripheral_enable_clock(rcc_apbenr, rcc_apb); /* GPIO peripheral clock enable. */ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN); /* Enable ADC peripheral clocks. */ #ifdef USE_AD1 rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_ADC1EN); #endif #ifdef USE_AD2 rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_ADC2EN); #endif /* Time Base configuration */ timer_reset(timer); timer_set_mode(timer, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); timer_set_period(timer, 0xFF); timer_set_prescaler(timer, 0x8); timer_set_clock_division(timer, 0x0); /* Generate TRGO on every update. */ timer_set_master_mode(timer, TIM_CR2_MMS_UPDATE); timer_enable_counter(timer); #endif // defined (USE_AD1) || defined (USE_AD2) }
/** Configure and enable RCC for peripherals (ADC1, ADC2, Timer) */ static inline void adc_init_rcc( void ) { #if USE_AD1 || USE_AD2 || USE_AD3 uint32_t timer; volatile uint32_t *rcc_apbenr; uint32_t rcc_apb; #if defined(USE_AD_TIM4) timer = TIM4; rcc_apbenr = &RCC_APB1ENR; rcc_apb = RCC_APB1ENR_TIM4EN; #elif defined(USE_AD_TIM1) timer = TIM1; rcc_apbenr = &RCC_APB2ENR; rcc_apb = RCC_APB2ENR_TIM1EN; #else timer = TIM2; rcc_apbenr = &RCC_APB1ENR; rcc_apb = RCC_APB1ENR_TIM2EN; #endif /* Timer peripheral clock enable. */ rcc_peripheral_enable_clock(rcc_apbenr, rcc_apb); #if defined(STM32F4) adc_set_clk_prescale(ADC_CCR_ADCPRE_BY2); #endif /* Enable ADC peripheral clocks. */ #if USE_AD1 rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_ADC1EN); #endif #if USE_AD2 rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_ADC2EN); #endif #if USE_AD3 rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_ADC3EN); #endif /* Time Base configuration */ timer_reset(timer); timer_set_mode(timer, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); #if defined(STM32F1) timer_set_period(timer, 0xFF); timer_set_prescaler(timer, 0x8); #elif defined(STM32F4) timer_set_period(timer, 0xFFFF); timer_set_prescaler(timer, 0x53); #endif //timer_set_clock_division(timer, 0x0); /* Generate TRGO on every update. */ timer_set_master_mode(timer, TIM_CR2_MMS_UPDATE); timer_enable_counter(timer); #endif // USE_AD1 || USE_AD2 || USE_AD3 }
/* --- FTFM (with edits) --- Bullet points are the steps needed. Pulse width modulation mode allows you to generate a signal with a frequency determined by the value of the TIMx_ARR register (the period) and a duty cycle determined by the value of the TIMx_CCRx register (the output compare value). -- Set TIMx_ARR to desired frequency -- Set TIMx_CCRx to desired duty cycle The PWM mode can be selected independently on each channel (one PWM per OCx output) by writing 110 (PWM mode 1) or ‘111 (PWM mode 2) in the OCxM bits in the TIMx_CCMRx register. -- Write PWM Mode 1 or PWM Mode 2 to OCxM bits in TIMx_CCMRx register You must enable the corresponding preload register by setting the OCxPE bit in the TIMx_CCMRx register, and eventually the auto-reload preload register by setting the ARPE bit in the TIMx_CR1 register. -- Set corresponding OCxPE bit in TIMx_CCMRx register -- Set ARPE bit in TIMx_CR1 As the preload registers are transferred to the shadow registers only when an update event occurs, before starting the counter, you have to initialize all the registers by setting the UG bit in the TIMx_EGR register. -- set UG bit in TIMx_EGR register OCx polarity is software programmable using the CCxP bit in the TIMx_CCER register. It can be programmed as active high or active low. OCx output is enabled by the CCxE bit in the TIMx_CCER register. Refer to the TIMx_CCERx register description for more details. -- set desired polarity in TIMx_CCER -- set CCxE bit in TIMx_CCER (enable output) */ static void pwm_init(uint32_t timer, uint8_t channel, uint32_t period) { // Convert channel number to internal rep enum tim_oc_id chan; switch (channel) { case 1: chan = TIM_OC1; break; case 2: chan = TIM_OC2; break; case 3: chan = TIM_OC3; break; case 4: chan = TIM_OC4; break; default: assert(false); chan = -1; break; } // Timer Base Configuration // timer_reset(timer); timer_set_mode(timer, TIM_CR1_CKD_CK_INT, // clock division TIM_CR1_CMS_EDGE, // Center-aligned mode selection TIM_CR1_DIR_UP); // TIMx_CR1 DIR: Direction timer_continuous_mode(timer); // Disables TIM_CR1_OPM (One pulse mode) timer_set_period(timer, period); // Sets TIMx_ARR timer_set_prescaler(timer, 1); // Adjusts speed of timer timer_set_clock_division(timer, 0); // Adjusts speed of timer timer_set_master_mode(timer, TIM_CR2_MMS_UPDATE); // Master Mode Selection timer_enable_preload(timer); // Set ARPE bit in TIMx_CR1 // Channel-specific settings timer_set_oc_value(timer, chan, 0); // sets TIMx_CCRx timer_set_oc_mode(timer, chan, TIM_OCM_PWM1); // Sets PWM Mode 1 timer_enable_oc_preload(timer, chan); // Sets OCxPE in TIMx_CCMRx timer_set_oc_polarity_high(timer, chan); // set desired polarity in TIMx_CCER timer_enable_oc_output(timer, chan); // set CCxE bit in TIMx_CCER (enable output) // Initialize all counters in the register switch (timer) { case TIM1: TIM1_EGR |= TIM_EGR_UG; break; case TIM2: TIM2_EGR |= TIM_EGR_UG; break; case TIM3: TIM3_EGR |= TIM_EGR_UG; break; case TIM4: TIM4_EGR |= TIM_EGR_UG; break; case TIM5: TIM5_EGR |= TIM_EGR_UG; break; case TIM6: TIM6_EGR |= TIM_EGR_UG; break; case TIM7: TIM7_EGR |= TIM_EGR_UG; break; case TIM8: TIM8_EGR |= TIM_EGR_UG; break; default: assert(false); break; } }
static void timer_setup(void) { /* Set up the timer TIM2 for injected sampling */ uint32_t timer; timer = TIM2; rcc_periph_clock_enable(RCC_TIM2); /* Time Base configuration */ timer_reset(timer); timer_set_mode(timer, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); timer_set_period(timer, 0xFF); timer_set_prescaler(timer, 0x8); timer_set_clock_division(timer, 0x0); /* Generate TRGO on every update. */ timer_set_master_mode(timer, TIM_CR2_MMS_UPDATE); timer_enable_counter(timer); }
/*--------------------------------------------------------------------*/ void timer_setup(void) { /* Enable TIM2 clock. */ rcc_periph_clock_enable(RCC_TIM2); timer_reset(TIM2); /* Timer global mode: - No divider, Alignment edge, Direction up */ timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); timer_continuous_mode(TIM2); timer_set_period(TIM2, 1000); timer_disable_oc_output(TIM2, TIM_OC2 | TIM_OC3 | TIM_OC4); timer_enable_oc_output(TIM2, TIM_OC1); timer_disable_oc_clear(TIM2, TIM_OC1); timer_disable_oc_preload(TIM2, TIM_OC1); timer_set_oc_slow_mode(TIM2, TIM_OC1); timer_set_oc_mode(TIM2, TIM_OC1, TIM_OCM_TOGGLE); timer_set_oc_value(TIM2, TIM_OC1, 500); timer_disable_preload(TIM2); /* Set the timer trigger output (for the DAC) to the channel 1 output compare */ timer_set_master_mode(TIM2, TIM_CR2_MMS_COMPARE_OC1REF); timer_enable_counter(TIM2); }
static void timer_setup(void) { /* Set up the timer TIM2 for injected sampling */ uint32_t timer; volatile uint32_t *rcc_apbenr; uint32_t rcc_apb; timer = TIM2; rcc_apbenr = &RCC_APB1ENR; rcc_apb = RCC_APB1ENR_TIM2EN; rcc_peripheral_enable_clock(rcc_apbenr, rcc_apb); /* Time Base configuration */ timer_reset(timer); timer_set_mode(timer, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); timer_set_period(timer, 0xFF); timer_set_prescaler(timer, 0x8); timer_set_clock_division(timer, 0x0); /* Generate TRGO on every update. */ timer_set_master_mode(timer, TIM_CR2_MMS_UPDATE); timer_enable_counter(timer); }
void accel_highg_init() { uint8_t channel_array[16]; gpio_set_mode(GPIOB, GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG, GPIO0 | GPIO1 | GPIO2); adc_set_dual_mode(ADC_CR1_DUALMOD_RSM); /* ADC1 + ADC2 dual mode */ adc_set_dual_mode(ADC_CR1_DUALMOD_ISM); adc_enable_external_trigger_injected(ADC1, ADC_CR2_JEXTSEL_TIM1_TRGO); adc_enable_external_trigger_injected(ADC3, ADC_CR2_JEXTSEL_TIM1_TRGO); adc_enable_dma(ADC1); adc_enable_dma(ADC3); adc_power_on(ADC1); adc_power_on(ADC2); adc_power_on(ADC3); adc_stab_sleep(); adc_reset_calibration(ADC1); adc_reset_calibration(ADC2); adc_reset_calibration(ADC3); adc_calibration(ADC1); adc_calibration(ADC2); adc_calibration(ADC3); memset(channel_array, 0, sizeof(channel_array)); channel_array[0] = 10; adc_set_injected_sequence(ADC1, 1, channel_array); channel_array[0] = 11; adc_set_injected_sequence(ADC2, 1, channel_array); channel_array[0] = 12; adc_set_injected_sequence(ADC3, 1, channel_array); timer_reset(TIM1); timer_enable_irq(TIM1, TIM_DIER_UIE); timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); /* 500Hz */ timer_set_prescaler(TIM1, 64); timer_set_period(TIM1, 2250); /* Generate TRGO */ timer_set_master_mode(TIM1, TIM_CR2_MMS_UPDATE); dma_set_peripheral_address(DMA1, DMA_CHANNEL5, (uint32_t) &ADC1_DR); dma_set_read_from_memory(DMA1, DMA_CHANNEL5); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL5); dma_set_peripheral_size(DMA1, DMA_CHANNEL5, DMA_CCR_PSIZE_32BIT); dma_set_memory_size(DMA1, DMA_CHANNEL5, DMA_CCR_MSIZE_32BIT); dma_set_priority(DMA1, DMA_CHANNEL5, DMA_CCR_PL_HIGH); dma_set_peripheral_address(DMA1, DMA_CHANNEL6, (uint32_t) &ADC3_DR); dma_set_read_from_peripheral(DMA1, DMA_CHANNEL6); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL6); dma_set_peripheral_size(DMA1, DMA_CHANNEL6, DMA_CCR_PSIZE_16BIT); dma_set_memory_size(DMA1, DMA_CHANNEL6, DMA_CCR_MSIZE_16BIT); dma_set_priority(DMA1, DMA_CHANNEL6, DMA_CCR_PL_HIGH); dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL5); dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL6); }