Hi Guys,
I can't work this one out, I have tried everything I can think of and still
not getting the DMA interrupt happening ...
Can someone please look at the code and help?
Many Thanks,
Bernie
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//
--------------------------------------------------------------------------------------------------------------------------------
void PWM::timer2Init(void) {
/* Reset TIM2 peripheral. */
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);
/* Reset prescaler value.
* Running the clock at 5kHz.
*/
/*
* On STM32F4 the timers are not running directly from pure APB1 or
* APB2 clock busses. The APB1 and APB2 clocks used for timers might
* be the double of the APB1 and APB2 clocks. This depends on the
* setting in DCKCFGR register. By default the behaviour is the
* following: If the Prescaler APBx is greater than 1 the derived timer
* APBx clocks will be double of the original APBx frequencies. Only if
* the APBx prescaler is set to 1 the derived timer APBx will equal the
* original APBx frequencies.
*
* In our case here the APB1 is devided by 4 system frequency and APB2
* divided by 2. This means APB1 timer will be 2 x APB1 and APB2 will
* be 2 x APB2. So when we try to calculate the prescaler value we have
* to use rcc_apb1_freqency * 2!!!
*
* For additional information see reference manual for the stm32f4
* familiy of chips. Page 204 and 213
*/
timer_set_prescaler(TIM2, 0);
/* Enable preload. */
timer_disable_preload(TIM2);
/* Continous mode. */
timer_continuous_mode(TIM2);
/* Set Frequency of PWM */
period = (rcc_apb1_frequency ) / 64000; // = 84Mhz / freq we want ( In
toggle mode PWM we have to halve this value )
timer_set_period(TIM2, period); // Default freq is 64khz
/* Enable/Disable outputs. */
timer_enable_oc_output(TIM2, TIM_OC1);
timer_enable_oc_output(TIM2, TIM_OC2);
timer_disable_oc_output(TIM2, TIM_OC3);
timer_disable_oc_output(TIM2, TIM_OC4);
/* -- OC1 configuration -- */
/* Configure global mode of line 1. */
//timer_disable_oc_clear(TIM2, TIM_OC1);
timer_enable_oc_preload(TIM2, TIM_OC1);
timer_set_oc_fast_mode(TIM2, TIM_OC1);
timer_set_oc_mode(TIM2, TIM_OC1, TIM_OCM_TOGGLE); // Toggle mode to get 50%
duty.
/* Set the capture compare value for OC1. */
timer_set_oc_value(TIM2, TIM_OC1, (period * 30 / 180) -1 ); // In toggle
mode we have to double the phase difference to get 120 deg
/* -- OC2 configuration -- */
/* Configure global mode of line 1. */
//timer_disable_oc_clear(TIM2, TIM_OC2);
timer_enable_oc_preload(TIM2, TIM_OC2);
timer_set_oc_fast_mode(TIM2, TIM_OC2);
timer_set_oc_mode(TIM2, TIM_OC2, TIM_OCM_TOGGLE);
/* Set the capture compare value for OC2. */
timer_set_oc_value(TIM2, TIM_OC2, (period * 150 / 180) -1 );
/* ---- */
/* ARR reload enable. */
timer_enable_preload(TIM2);
// Setup for DMA
timer_set_dma_on_update_event(TIM2);
timer_update_on_any(TIM2); // ?
timer_set_master_mode(TIM2,TIM_CR2_MMS_UPDATE ); //?
//timer_set_dma_on_compare_event(TIM2);
/* Counter enable. */
timer_enable_counter(TIM2);
}
//
--------------------------------------------------------------------------------------------------------------------------------
void PWM::setup_pwm_dma(void)
{
// TIM2_UP uses DMA controller 1 Stream 1 Channel 3.
dma_stream_reset(DMA1, DMA_STREAM1);
dma_set_priority(DMA1, DMA_STREAM1, DMA_SxCR_PL_MEDIUM);
dma_set_memory_size(DMA1, DMA_STREAM1, DMA_SxCR_MSIZE_16BIT);
dma_set_peripheral_size(DMA1, DMA_STREAM1, DMA_SxCR_PSIZE_16BIT);
dma_enable_memory_increment_mode(DMA1, DMA_STREAM1);
dma_enable_circular_mode(DMA1, DMA_STREAM1);
dma_set_transfer_mode(DMA1, DMA_STREAM1, DMA_SxCR_DIR_MEM_TO_PERIPHERAL);
// The register to target is the timer CCR1 register
dma_set_peripheral_address(DMA1, DMA_STREAM1, (uint32_t) &TIM_CCR1(TIM2));
// The array v[] is filled with the waveform data to be output
dma_set_memory_address(DMA1, DMA_STREAM1, (uint32_t) waveform);
dma_set_memory_address_1(DMA1, DMA_STREAM1, (uint32_t) waveform1);
dma_enable_double_buffer_mode(DMA1, DMA_STREAM1);
dma_set_number_of_data(DMA1, DMA_STREAM1, ARRAY_SIZE(waveform));
dma_enable_transfer_complete_interrupt(DMA1, DMA_STREAM1);
//dma_enable_half_transfer_interrupt(DMA1, DMA_STREAM1);
dma_channel_select(DMA1, DMA_STREAM1, DMA_SxCR_CHSEL_3);
dma_enable_stream(DMA1, DMA_STREAM1);
timer2Init();
}
//
--------------------------------------------------------------------------------------------------------------------------------
extern "C" void dma1_stream1_isr(void) {
int i;
QK_ISR_ENTRY();
if (dma_get_interrupt_flag(DMA1, DMA_STREAM1, DMA_TCIF)) {
dma_clear_interrupt_flags(DMA1, DMA_STREAM1, DMA_TCIF);
if(dma_get_target(DMA1, DMA_STREAM1)) {
// Can update buffer 0
for(i=0;i<SINE_SAMPLE;++i) {
O_pwm->waveform[i] = O_mod->pwm_table[i];
}
} else {
// Can update buffer 1
for(i=0;i<SINE_SAMPLE;++i) {
O_pwm->waveform1[i] = O_mod->pwm_table[i];
}
}
}
QK_ISR_EXIT();
}
------------------------------------------------------------
-----------------------------------------
On Tue, Jul 14, 2015 at 6:54 PM, Bernard Mentink <bment...@gmail.com> wrote:
> Hi all,
>
> I am having some more issues with DMA, this time timer (I have sucessfully
> got A2D working with DMA.
>
> My problem is this: I have Timer2 setup and it emits PWM on a couple of
> pins just fine.
> I have told it to DMA on update, have setup DMA to what I think should be
> correct, and have setup the timer2 update IRQ .. problem is it never gets
> to the interrupt routine.
>
> The code is:
>
>
> -----------------------------------------------------------------------------------------------------------------
> //
> --------------------------------------------------------------------------------------------------------------------------------
> void PWM::timer2Init(void) {
>
> /* Reset TIM2 peripheral. */
> 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);
>
> /* Reset prescaler value.
> * Running the clock at 5kHz.
> */
> /*
> * On STM32F4 the timers are not running directly from pure APB1 or
> * APB2 clock busses. The APB1 and APB2 clocks used for timers might
> * be the double of the APB1 and APB2 clocks. This depends on the
> * setting in DCKCFGR register. By default the behaviour is the
> * following: If the Prescaler APBx is greater than 1 the derived timer
> * APBx clocks will be double of the original APBx frequencies. Only if
> * the APBx prescaler is set to 1 the derived timer APBx will equal the
> * original APBx frequencies.
> *
> * In our case here the APB1 is devided by 4 system frequency and APB2
> * divided by 2. This means APB1 timer will be 2 x APB1 and APB2 will
> * be 2 x APB2. So when we try to calculate the prescaler value we have
> * to use rcc_apb1_freqency * 2!!!
> *
> * For additional information see reference manual for the stm32f4
> * familiy of chips. Page 204 and 213
> */
> timer_set_prescaler(TIM2, 0);
>
> /* Enable preload. */
> timer_disable_preload(TIM2);
>
> /* Continous mode. */
> timer_continuous_mode(TIM2);
>
> /* Set Frequency of PWM */
> period = (rcc_apb1_frequency ) / 64000; // = 84Mhz / freq we want ( In
> toggle mode PWM we have to halve this value )
> timer_set_period(TIM2, period); // Default freq is 64khz
>
> /* Enable/Disable outputs. */
> timer_enable_oc_output(TIM2, TIM_OC1);
> timer_enable_oc_output(TIM2, TIM_OC2);
> timer_disable_oc_output(TIM2, TIM_OC3);
> timer_disable_oc_output(TIM2, TIM_OC4);
>
> /* -- OC1 configuration -- */
>
> /* Configure global mode of line 1. */
> //timer_disable_oc_clear(TIM2, TIM_OC1);
> timer_enable_oc_preload(TIM2, TIM_OC1);
> timer_set_oc_fast_mode(TIM2, TIM_OC1);
> timer_set_oc_mode(TIM2, TIM_OC1, TIM_OCM_TOGGLE); // Toggle mode to get
> 50% duty.
>
> /* Set the capture compare value for OC1. */
> timer_set_oc_value(TIM2, TIM_OC1, (period * 30 / 180) -1 ); // In toggle
> mode we have to double the phase difference to get 120 deg
>
> /* -- OC2 configuration -- */
>
> /* Configure global mode of line 1. */
> //timer_disable_oc_clear(TIM2, TIM_OC2);
> timer_enable_oc_preload(TIM2, TIM_OC2);
> timer_set_oc_fast_mode(TIM2, TIM_OC2);
> timer_set_oc_mode(TIM2, TIM_OC2, TIM_OCM_TOGGLE);
>
> /* Set the capture compare value for OC2. */
> timer_set_oc_value(TIM2, TIM_OC2, (period * 150 / 180) -1 );
>
> /* ---- */
>
> /* ARR reload enable. */
> timer_enable_preload(TIM2);
>
> // Setup for DMA
> timer_set_dma_on_update_event(TIM2);
> timer_update_on_any(TIM2); // ?
> timer_set_master_mode(TIM2,TIM_CR2_MMS_UPDATE ); //?
> //timer_set_dma_on_compare_event(TIM2);
>
> /* Counter enable. */
> timer_enable_counter(TIM2);
> }
>
> //
> --------------------------------------------------------------------------------------------------------------------------------
> void PWM::setup_pwm_dma(void)
> {
> // TIM2_UP uses DMA controller 1 Stream 1 Channel 3.
> dma_stream_reset(DMA1, DMA_STREAM1);
> dma_set_priority(DMA1, DMA_STREAM1, DMA_SxCR_PL_MEDIUM);
> dma_set_memory_size(DMA1, DMA_STREAM1, DMA_SxCR_MSIZE_16BIT);
> dma_set_peripheral_size(DMA1, DMA_STREAM1, DMA_SxCR_PSIZE_16BIT);
> dma_enable_memory_increment_mode(DMA1, DMA_STREAM1);
> dma_enable_circular_mode(DMA1, DMA_STREAM1);
> dma_set_transfer_mode(DMA1, DMA_STREAM1, DMA_SxCR_DIR_MEM_TO_PERIPHERAL);
> // The register to target is the timer CCR1 register
> dma_set_peripheral_address(DMA1, DMA_STREAM1, (uint32_t) &TIM_CCR1(TIM2));
> // The array v[] is filled with the waveform data to be output
> dma_set_memory_address(DMA1, DMA_STREAM1, (uint32_t) waveform);
> dma_set_memory_address_1(DMA1, DMA_STREAM1, (uint32_t) waveform1);
> dma_enable_double_buffer_mode(DMA1, DMA_STREAM1);
> dma_set_number_of_data(DMA1, DMA_STREAM1, ARRAY_SIZE(waveform));
> dma_enable_transfer_complete_interrupt(DMA1, DMA_STREAM1);
> //dma_enable_half_transfer_interrupt(DMA1, DMA_STREAM1);
> dma_channel_select(DMA1, DMA_STREAM1, DMA_SxCR_CHSEL_3);
> dma_enable_stream(DMA1, DMA_STREAM1);
> timer2Init();
> }
>
> //
> --------------------------------------------------------------------------------------------------------------------------------
>
> extern "C" void dma1_stream1_isr(void) {
> int i;
>
> QK_ISR_ENTRY();
> if (dma_get_interrupt_flag(DMA1, DMA_STREAM1, DMA_TCIF)) {
> dma_clear_interrupt_flags(DMA1, DMA_STREAM1, DMA_TCIF);
> if(dma_get_target(DMA1, DMA_STREAM1)) {
> // Can update buffer 0
> for(i=0;i<SINE_SAMPLE;++i) {
> O_pwm->waveform[i] = O_mod->pwm_table[i];
> }
> } else {
> // Can update buffer 1
> for(i=0;i<SINE_SAMPLE;++i) {
> O_pwm->waveform1[i] = O_mod->pwm_table[i];
> }
> }
> }
> QK_ISR_EXIT();
> }
>
> -----------------------------------------------------------------------------------------------------
>
> Anyone help?
>
> Thanks,
>
> --
>
> -----------------------------------------------------------------------------------------------------------------------------------------
>
> *People born in the 50's have lived *
> *in seven decades.*
> *two centuries,*
> *and two millenniums.*
> *We had the best music, fastest cars, drive-in theaters, soda fountains,
> and happy days.*
> *And we are not even that old yet.*
> *We're just that cool.*
>
> ----------------------------------------------------------------------------------------------------------------------------------------
>
--
-----------------------------------------------------------------------------------------------------------------------------------------
*People born in the 50's have lived *
*in seven decades.*
*two centuries,*
*and two millenniums.*
*We had the best music, fastest cars, drive-in theaters, soda fountains,
and happy days.*
*And we are not even that old yet.*
*We're just that cool.*
----------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------
Don't Limit Your Business. Reach for the Cloud.
GigeNET's Cloud Solutions provide you with the tools and support that
you need to offload your IT needs and focus on growing your business.
Configured For All Businesses. Start Your Cloud Today.
https://www.gigenetcloud.com/
_______________________________________________
libopencm3-devel mailing list
libopencm3-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libopencm3-devel