cancel
Showing results for 
Search instead for 
Did you mean: 

Timer/DAC reset?

danieldaniel93
Associate II
Posted on July 16, 2016 at 19:21

I'm trying to do a thorough exploration of the DAC, so set up a demo on a STM32F429I-Discovery that uses a number of different techniques to set up a waveform, switching between them (and spitting out the demo name) when the user button is pressed.

Everything works fine - if it's run first. The two demos that use the DAC wave generation fail in different ways if the other one is run first. This makes me think the issue is that I'm not properly resetting something between demos. Actually, two somethings, as the two fail in different ways. I'm using libopencm3 as a HAL. Here's the reset code, which is also run before the first demo, just to make sure:

static
void
dac_teardown(
void
) {
timer_disable_counter(TIM6);
timer_disable_update_event(TIM6);
timer_reset(TIM6);
dac_disable(CHANNEL_2);
dac_trigger_disable(CHANNEL_2);
dac_disable_waveform_generation(CHANNEL_2);
}

The first example - noise generation - doesn't use the timer, but uses a software trigger in the main code to cause new values to be loaded from the DAC. Here's the setup code:

static
void
dac_noise_setup(
void
) {
dac_set_waveform_generation(DAC_CR_WAVE2_NOISE);
/* 9 bit - or 512 - maximum amplitude value, 1024 sample wavelength */
dac_set_waveform_characteristics(DAC_CR_MAMP2_8);
dac_set_trigger_source(DAC_CR_TSEL2_SW);
dac_trigger_enable(CHANNEL_2);
dac_enable(CHANNEL_2);
}

When this demo is run first, it works fine. If run after the second demo (setup below), it acts like MAMPS is set to 12 instead of 8. The second demo uses the the timer6 trigger to generate a triangle wave. Setup is:

static
void
dac_triangle_setup(
void
) {
/* Set up and start the dac wave generation */
dac_set_waveform_generation(DAC_CR_WAVE2_TRI);
dac_set_waveform_characteristics(DAC_CR_MAMP2_10);
dac_buffer_enable(CHANNEL_2);
dac_trigger_enable(CHANNEL_2);
dac_set_trigger_source(DAC_CR_TSEL2_T6);
dac_enable(CHANNEL_2);
/* Set up and start the timer. */
timer_set_prescaler(TIM6, 0);
timer_set_period(TIM6, 9);
timer_continuous_mode(TIM6);
timer_enable_update_event(TIM6);
timer_set_master_mode(TIM6, TIM_CR2_MMS_UPDATE);
timer_enable_counter(TIM6);
}

Again, this works if it's run first. If run after the noise demo above, it doesn't generate output. Both demo's run fine if I run them first. If I run them second, or switch to the other demo and then back to them after running them first, I get the broken behavior described. I've disabled all the other demos, so no other setup code is running. The reference manual talks about order dependencies for some of these things, but that I run the teardown code before any demos and they still work first time makes me think I've got those right, possibly incorrectly. Note that I'm posting libopencm3 code because I want to post the code I'm using. If you have working code to do similar things using a different HAL, please don't hesitate to share it! #stm32 #timer #dac
5 REPLIES 5
AvaTar
Lead
Posted on July 18, 2016 at 08:29

> Note that I'm posting libopencm3 code because I want to post the code I'm using.

 

Don't know any details about libopencm3, but the ''old'' SPL had a xxx_DeInit() function for every peripheral, to undo previous settings, and put the peripheral in a known state.

Worst case, you can do it manually by setting the DAC registers back to their reset values.

Posted on July 18, 2016 at 09:57

Every peripheral module can be individually reset through its respective bit in RCC_AHBxRSTR/RCC_APBxRSTR. Review the RCC registers chapter in RM.

If you are using a ''library'', then that library may have some state variables which need to be explicitly reset, too; if it's so, than that's a well-deserved punishment for using the ''library''.

JW

AvaTar
Lead
Posted on July 18, 2016 at 11:16

> If you are using a ''library'', then that library may have some state variables which need to be explicitly reset, too; if it's so, than that's a well-deserved punishment for using the ''library''.

 

IMHO rather for not reading the Reference Manual ...

danieldaniel93
Associate II
Posted on July 19, 2016 at 19:48

That indeed was the issue. Thanks.

The ''library'' is just a hardware abstraction layer. Frankly, I'd rather work with at least a nice set of defines for the registers and flags than have to look their values up in the manual all the time. It does go a step further, offering rcc_reset_pulse(RST_TIM6) for the use here. It's a lot lighter than the STM offering along these lines, which is one of the reasons I'm using it. 

As for reading the manual - what a great idea! Here I sat with it open on my desktop for hours, just paging through  it looking at all the pretty pictures and nifty acronyms, and it never occurred to me that they might actually mean something. What a thought!

Posted on July 21, 2016 at 22:18

> Frankly, I'd rather work with at least a nice set of defines for the registers and flags than have to look their values up in the manual all the time.

This is what the CMSIS-mandated default headers are for. I don't say they are nice, but a solid starting point they are.

> It does go a step further, offering rcc_reset_pulse(RST_TIM6) for the use here.

#include ''stm32f429xx.h''

RCC->APB1RSTR = RCC_APB1RSTR_TIM6RST;

RCC->APB1RSTR = 0;

Short, easy, concise, easily back-traceable to the RM. There's no need for a function or macro to wipe every slot. As soon as it gets to the real functionality, there's little to abstract anyway.

OTOH, except for cases where a genuine mimic for reset is appropriate (e.g. exiting for the application from a bootloader) I'd go for explicit setting of all relevant registers of the timer, rather than resetting it.

YMMV, of course.

> As for reading the manual - what a great idea! Here I sat with it open on my desktop for hours,

> just paging through  it looking at all the pretty pictures and nifty acronyms, and it never occurred to me that they might actually mean something.

Yes, it appears to be the case.

😉

JW