Different program behavior after shutdown

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello Atmel Community,

 

I'm working on a solution of a strange problem but I haven't found it yet :-(

 

My program works fine as long as I turn the voltage on and load the program file with the IDE on the controller (ATSAMC21E18A).

But after switching of the voltage and turn it on again, it seems the event system doesn't work any more.

 

The PWM from the TCC0 module is running but the event for the ADC triggering is no longer working.

 

Attached the code (I hope someone can help me or know what the problem is):

 

#include <asf.h>
#include "define.h"

void init_all(void);
void adc0_callback(struct adc_module *const module);
void adc1_callback(struct adc_module *const module);

uint16_t vsek1_ana = 0;
uint16_t vsek2_ana = 0;
uint16_t vin_ana = 0;
uint16_t vtemp_ana = 0;
uint16_t vschalt_ana = 0;
uint8_t adc0_counter = 0;
uint8_t adc1_counter = 0;
uint32_t test = 0;

uint16_t buffer[20] = {0};

struct adc_module adc_0;
struct adc_module adc_1;
struct dac_module dac_ausgang;

int main (void)
{
	system_init();

	init_all();																

	delay_init();															

	while (1)
	{
	}
}

void init_all(void)
{

	struct port_config config_port_pin_input;
	port_get_config_defaults(&config_port_pin_input);
	config_port_pin_input.direction = PORT_PIN_DIR_INPUT;
	config_port_pin_input.input_pull = PORT_PIN_PULL_NONE;					

	struct port_config config_port_pin_output;
	port_get_config_defaults(&config_port_pin_output);
	config_port_pin_output.direction = PORT_PIN_DIR_OUTPUT;
	config_port_pin_output.input_pull = PORT_PIN_PULL_NONE;					

	port_pin_set_config(OUT_ANA_EN, &config_port_pin_output);
	port_pin_set_output_level(OUT_ANA_EN, false);							

	port_pin_set_config(OUT_CAN_STBY, &config_port_pin_output);
	port_pin_set_output_level(OUT_CAN_STBY, true);							

	port_pin_set_config(OUT_SCHALT_P, &config_port_pin_output);
	port_pin_set_output_level(OUT_SCHALT_P, false);							

	port_pin_set_config(OUT_VER1, &config_port_pin_output);
	port_pin_set_output_level(OUT_VER1, false);								

	port_pin_set_config(OUT_VER2, &config_port_pin_output);
	port_pin_set_output_level(OUT_VER2, false);								

	port_pin_set_config(OUT_VER3, &config_port_pin_output);
	port_pin_set_output_level(OUT_VER3, false);								

	port_pin_set_config(OUT_VER4, &config_port_pin_output);
	port_pin_set_output_level(OUT_VER4, false);								

	struct system_pinmux_config pinmux_config;
	system_pinmux_get_config_defaults(&pinmux_config);
	pinmux_config.direction = SYSTEM_PINMUX_PIN_DIR_INPUT;					

	pinmux_config.mux_position = MUX_PA05B_ADC0_AIN5;
	system_pinmux_pin_set_config(PIN_PA05,&pinmux_config);					

	pinmux_config.mux_position = MUX_PA06B_ADC0_AIN6;
	system_pinmux_pin_set_config(PIN_PA06,&pinmux_config);					

	pinmux_config.mux_position = MUX_PA08B_ADC1_AIN10;
	system_pinmux_pin_set_config(PIN_PA08,&pinmux_config);					

	pinmux_config.mux_position = MUX_PA09B_ADC1_AIN11;
	system_pinmux_pin_set_config(PIN_PA09,&pinmux_config);					

	pinmux_config.mux_position = MUX_PA10B_ADC0_AIN10;
	system_pinmux_pin_set_config(PIN_PA10,&pinmux_config);					

	struct system_gclk_gen_config gclock_gen_conf_2;
	system_gclk_gen_get_config_defaults(&gclock_gen_conf_2);

	gclock_gen_conf_2.source_clock    = SYSTEM_CLOCK_SOURCE_OSC48M;
	gclock_gen_conf_2.division_factor = 1;
	gclock_gen_conf_2.output_enable = false;

	system_gclk_gen_set_config(GCLK_GENERATOR_0, &gclock_gen_conf_2);
	system_gclk_gen_enable(GCLK_GENERATOR_0);

	struct system_gclk_gen_config gclock_gen_conf;
	system_gclk_gen_get_config_defaults(&gclock_gen_conf);

	gclock_gen_conf.source_clock    = SYSTEM_CLOCK_SOURCE_OSC48M;
	gclock_gen_conf.division_factor = 12;
	gclock_gen_conf.output_enable = false;

	system_gclk_gen_set_config(GCLK_GENERATOR_2, &gclock_gen_conf);
	system_gclk_gen_enable(GCLK_GENERATOR_2);

	struct system_gclk_gen_config gclock_gen_conf_PWM;
	system_gclk_gen_get_config_defaults(&gclock_gen_conf_PWM);				

	gclock_gen_conf_PWM.source_clock    = SYSTEM_CLOCK_SOURCE_XOSC;
	gclock_gen_conf_PWM.division_factor = 2;								

	system_gclk_gen_set_config(GCLK_GENERATOR_3, &gclock_gen_conf_PWM);
	system_gclk_gen_enable(GCLK_GENERATOR_3);								

	struct system_gclk_gen_config gclock_gen_conf_CAN;
	system_gclk_gen_get_config_defaults(&gclock_gen_conf_CAN);				

	gclock_gen_conf_CAN.source_clock = SYSTEM_CLOCK_SOURCE_XOSC;
	gclock_gen_conf_CAN.division_factor = 1;								

	system_gclk_gen_set_config(GCLK_GENERATOR_6, &gclock_gen_conf_CAN);
	system_gclk_gen_enable(GCLK_GENERATOR_6);								

	struct tcc_module tcc_instance;
	struct tcc_config config_tcc;
	struct tcc_events config_events;

	tcc_get_config_defaults(&config_tcc, TCC0);
	config_tcc.counter.clock_source = GCLK_GENERATOR_3;
	config_tcc.counter.clock_prescaler = TCC_CLOCK_PRESCALER_DIV1;
	config_tcc.counter.period = 532;
	config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM;
	config_tcc.compare.match[0] = 266;
	config_tcc.compare.match[1] = 260;
	config_tcc.compare.match[2] = 526;										

	config_tcc.pins.enable_wave_out_pin[0] = true;
	config_tcc.pins.enable_wave_out_pin[4] = true;
	config_tcc.pins.wave_out_pin[0] = PIN_PA04E_TCC0_WO0;
	config_tcc.pins.wave_out_pin[4] = PIN_PA22F_TCC0_WO4;
	config_tcc.pins.wave_out_pin_mux[0] = MUX_PA04E_TCC0_WO0;
	config_tcc.pins.wave_out_pin_mux[4] = MUX_PA22F_TCC0_WO4;				

	tcc_init(&tcc_instance, TCC0, &config_tcc);								

	config_events.generate_event_on_channel[1] = true;
	config_events.generate_event_on_channel[2] = true;						

	tcc_enable_events(&tcc_instance, &config_events);

	TCC0->WEXCTRL.reg = TCC_WEXCTRL_DTHS(2) | TCC_WEXCTRL_DTLS(2) | TCC_WEXCTRL_DTIEN0;

	tcc_enable(&tcc_instance);												

	struct dac_config config_dac;
	dac_get_config_defaults(&config_dac);
	config_dac.output = DAC_OUTPUT_EXTERNAL;
	config_dac.reference = DAC_REFERENCE_AREF;
	dac_init(&dac_ausgang, DAC, &config_dac);								

	struct dac_chan_config config_dac_chan;
	dac_chan_get_config_defaults(&config_dac_chan);
	dac_chan_set_config(&dac_ausgang, DAC_CHANNEL_0, &config_dac_chan);
	dac_chan_enable(&dac_ausgang, DAC_CHANNEL_0);
	dac_enable(&dac_ausgang);												

	struct adc_config config_adc;
	adc_get_config_defaults(&config_adc);								

	config_adc.left_adjust = false;
	config_adc.negative_input = ADC_NEGATIVE_INPUT_GND;
	config_adc.positive_input = ADC_POSITIVE_INPUT_PIN5;
	config_adc.reference = ADC_REFERENCE_AREFA;
	config_adc.event_action = ADC_EVENT_ACTION_START_CONV;												

	adc_init(&adc_0, ADC0, &config_adc);									

	config_adc.positive_input = ADC_POSITIVE_INPUT_PIN10;					

	adc_init(&adc_1, ADC1, &config_adc);									

	adc_enable(&adc_0);
	adc_enable(&adc_1);														

	adc_register_callback(&adc_0, adc0_callback, ADC_CALLBACK_READ_BUFFER);
	adc_enable_callback(&adc_0, ADC_CALLBACK_READ_BUFFER);
	adc_enable_interrupt(&adc_0, ADC_INTERRUPT_RESULT_READY);

	adc_register_callback(&adc_1, adc1_callback, ADC_CALLBACK_READ_BUFFER);
	adc_enable_callback(&adc_1, ADC_CALLBACK_READ_BUFFER);
	adc_enable_interrupt(&adc_1, ADC_INTERRUPT_RESULT_READY);

	struct events_resource example_event;
	struct events_config config;

	events_get_config_defaults(&config);
	config.generator      = EVSYS_ID_GEN_TCC0_MCX_1;
	config.edge_detect    = EVENTS_EDGE_DETECT_RISING;
	config.path           = EVENTS_PATH_SYNCHRONOUS;
	config.clock_source   = GCLK_GENERATOR_0;
	events_allocate(&example_event, &config);

	events_attach_user(&example_event,EVSYS_ID_USER_ADC0_START);
	events_enable_interrupt_source(&example_event,EVSYS_ID_GEN_TCC0_MCX_1);

	struct events_resource example_event_2;
	struct events_config config_2;

	events_get_config_defaults(&config_2);
	config_2.generator      = EVSYS_ID_GEN_TCC0_MCX_2;
	config_2.edge_detect    = EVENTS_EDGE_DETECT_RISING;
	config_2.path           = EVENTS_PATH_SYNCHRONOUS;
	config_2.clock_source   = GCLK_GENERATOR_0;
	events_allocate(&example_event_2, &config_2);

	events_attach_user(&example_event_2,EVSYS_ID_USER_ADC1_START);
	events_enable_interrupt_source(&example_event_2,EVSYS_ID_GEN_TCC0_MCX_2);

	adc_read_buffer_job(&adc_0,&vsek1_ana,1);
	adc_read_buffer_job(&adc_1,&vsek2_ana,1);
}

void adc0_callback(struct adc_module *const module)
{
	port_pin_toggle_output_level(OUT_SCHALT_P);

	if(adc0_counter == 0)
	{
		adc_set_positive_input(&adc_0,ADC_POSITIVE_INPUT_PIN6);
		adc_read_buffer_job(&adc_0,&vin_ana,1);
		adc_start_conversion(&adc_0);
		adc0_counter = 1;
	}
	else if(adc0_counter == 1)
	{
		adc_set_positive_input(&adc_0,ADC_POSITIVE_INPUT_PIN10);
		adc_read_buffer_job(&adc_0,&vschalt_ana,1);
		adc_start_conversion(&adc_0);
		adc0_counter = 2;
	}
	else if(adc0_counter == 2)
	{
		adc_set_positive_input(&adc_0,ADC_POSITIVE_INPUT_PIN5);
		adc_read_buffer_job(&adc_0,&vsek1_ana,1);
		adc0_counter = 0;
	}
}

void adc1_callback(struct adc_module *const module)
{
	port_pin_toggle_output_level(OUT_SCHALT_P);

	if(adc1_counter == 0)
	{
		adc_set_positive_input(&adc_1,ADC_POSITIVE_INPUT_PIN11);
		adc_read_buffer_job(&adc_1,&vtemp_ana,1);
		adc_start_conversion(&adc_1);
		adc1_counter = 1;
	}
	else if(adc1_counter == 1)
	{
		adc_set_positive_input(&adc_1,ADC_POSITIVE_INPUT_PIN10);
		adc_read_buffer_job(&adc_1,&vsek2_ana,1);
		adc1_counter = 0;
	}
}

 Thanks in advance :-)

This topic has a solution.
Last Edited: Mon. Oct 15, 2018 - 02:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There is a lot going on that may or may not be related to the problem, have you tested with a reduced example (no dac, a single gclk generator, one adc channel etc)? 

Whats going on here?

events_enable_interrupt_source(&example_event,EVSYS_ID_GEN_TCC0_MCX_1);

This function is used when you need the event to also generate an interrupt.  And you can only enable

enum events_interrupt_source {
    /** Overrun in event channel detected interrupt */
    EVENTS_INTERRUPT_OVERRUN,
    /** Event signal propagation in event channel detected interrupt */
    EVENTS_INTERRUPT_DETECT,
};

Typically (as in the example project) you would need

static void configure_event_interrupt(struct events_resource *resource,
		struct events_hook *hook)
{
    events_create_hook(hook, event_counter);
    events_add_hook(resource, hook);
    events_enable_interrupt_source(resource, EVENTS_INTERRUPT_DETECT);
}

/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Lars,

 

thanks for your answer.

You're right, the event interrupt source is not right and in addition not required. I have deleted this line :-)

 

I have reduced the programcode to only the required ones. Furthermore I tested a lot of different configurations but it doesn't worked.

 

The program is runinng and making his job as long as I put the voltage on and programming it over the Atmel Studio 7.

After switching the voltage off and turning it on again the PWM is running, but the ADC callback will not be hit.

 

Randomly, I have seen (with a oscilloscope) that if I switch the voltage only for under 1 second off, the controller restarts and is running normally (ADC callback works).

Only if the voltage is switched off longer than 1 second, the callback is not working. I have no idea, but it seems that the event is not working any more.

 

By the way, I have tested the behavior on 3 electronics.

 

Regards Martin

(small program attached)

Attachment(s): 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You might have some random trash in the config_events struct, try

struct tcc_events config_events = { 0 };

I don't know if significant here but generally you would not have the "instance" structs as locals on the stack (i.e., make tcc_instance and example_event global).

/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Lars,

 

I have tried your solution and it works :-)

 

After setting the tcc_events and tcc_module to global, the events are triggering the ADC after restart the controller.

 

Thanks for your help.

 

Regards