UC3A3 ADC hang seldomly

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

Hi,

I have a custom board based on EVK1104 (UC3A3256). I based my code on examples from ASF1.7.

Anyone else had problems with the ADC hanging very rarely? I read from the ADC a few times per second where the read is pulled from a PC, the uC does the read and sends respons back. Shortest to longest time to fail from power on we measured is 4 to 22 hours.

What happens is that there is no respons from the board and the USB connection to the PC dropps out. The watchdog reboots the board and it can be used again. But since the PC softare is holding the COM-port (we use USB CDC code from ASF 1.7), the USB cable needs to be unplugged and replugged before there can be any connection.

I call this to init the ADC:

void adcInit(void) {
	// GPIO pin/ADC-function map.
	static const gpio_map_t ADC_GPIO_MAP = { { ADC_HV_VOLTAGE_PIN,
			ADC_HV_VOLTAGE_FUNCTION }, { ADC_ASIC_VOLTAGE_PIN,
			ADC_ASIC_VOLTAGE_FUNCTION }, { ADC_HV_CURRENT_PIN,
			ADC_HV_CURRENT_FUNCTION }, { ADC_ASIC_CURRENT_PIN,
			ADC_ASIC_CURRENT_FUNCTION }, { ADC_MON_V_PIN,
			ADC_MON_V_FUNCTION }, { ADC_HEATSINK_TEMP_PIN,
			ADC_HEATSINK_TEMP_FUNCTION }, { ADC_ASIC_TEMP_PIN,
			ADC_ASIC_TEMP_FUNCTION } };

	// Assign and enable GPIO pins to the ADC function.
	gpio_enable_module(ADC_GPIO_MAP, sizeof(ADC_GPIO_MAP)
			/ sizeof(ADC_GPIO_MAP[0]));

	// configure ADC
	// Lower the ADC clock to match the ADC characteristics (because we configured
	// the CPU clock to 12MHz, and the ADC clock characteristics are usually lower;
	// cf. the ADC Characteristic section in the datasheet).
	AVR32_ADC.mr |= 0x2 << AVR32_ADC_MR_PRESCAL_OFFSET;
	adc_configure(adc);

	// Enable the ADC channels.
	adc_enable(adc, ADC_HV_VOLTAGE_CHANNEL);
	adc_enable(adc, ADC_ASIC_VOLTAGE_CHANNEL);
	adc_enable(adc, ADC_MON_V_CHANNEL);
	adc_enable(adc, ADC_HV_CURRENT_CHANNEL);
	adc_enable(adc, ADC_ASIC_CURRENT_CHANNEL);
	adc_enable(adc, ADC_HEATSINK_TEMP_CHANNEL);
	adc_enable(adc, ADC_ASIC_TEMP_CHANNEL);
}

Where adc_enable is:

void adc_enable(volatile avr32_adc_t * adc, unsigned short channel)
{
  Assert( adc!=NULL );
  Assert( channel <= AVR32_ADC_CHANNELS_MSB );  // check if channel exist

  // enable channel
  adc->cher = (1 << channel);
}

I call this to start the ADC:

void adc_start(volatile avr32_adc_t * adc)
{
  Assert( adc!=NULL );

  // start conversion
  adc->cr = AVR32_ADC_START_MASK;
}

This to read the result:

unsigned long adc_get_value(volatile avr32_adc_t * adc, unsigned short channel)
{
  Assert( adc!=NULL );
  Assert( channel <= AVR32_ADC_CHANNELS_MSB );  // check if channel exist

  // wait for end of conversion
  while(adc_check_eoc(adc, channel) != HIGH);
  return *((unsigned long * )((&(adc->cdr0)) + channel));
}

So the guess would be that last while is the problem. But why would it only be a problem after 10k-400k reads?

I'm going to put a timeout on that while now to see if that is the problem. But any other information on what could be the problem would be appreciated.

Thanks!
Anders

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

Added the timeout and a LED that goes on if the timeout has been reached.

If I increase the number of reads of the ADC to 10k samples/s I get a timeout within 10s. at 2.5k samples/s it takes a bit longer.

I have a loop reading ADC values on the boards. It can make 20k samples/s without getting timeout on the ADC. This loop is not pulled by the PC. But when I start pulling from the PC, I get timeout quite quickly. Within seconds when I read the on board loop at 20k samples/s.

The message handling is done in serial programming with the ADC reads. So there is no interrupts that may want to come in between and want to use the ADC at the same time as some other code.

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

Found now that it is only one channel that is causing the problem. If I at the last point before ADC read change to another channel, it works perfect (except for wrong ADC channel is read). It couldn´t be a stack overflow or anything?

The exact same function call is used in the on board loop that reads the ADC. It is only when I pull from the PC that just that ADC channel hangs the uC (or make timeout on the conversion).

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

Tried increasing the stack size to 8k from 4k. Is it enough to just search the solution and at all instances where stack_size is mentioned change from 4k to 8k?

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

I made a part of the main system loop that reads the ADC value for the channel that is making troubble, and puts it into a variable. When the PC askes for that ADC channel, I instead read from the variable. Seems to be working 4 hours after system test. Lets see what the weekend does.

It is however an ugly workaround for a non-understood problem.

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

Weekend test:
On one computer, no crash and 65h passed. The other crash after 28h. This other computer ursually crashed after 4-12 hours. Have restarted that test now.

Any idéas anyone? Anyone had a similar problem?

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

My suspicion is that the problem is not with the ADC code but in the USB/PC polling code.

I would try to isolate the problem by modifying the micro code so that the PC reads values from an array instead of from the ADC.
Increment the value(s) in that array after the PC performs a read.

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

I have the same function beeing called when the PC askes for data from an analogue channel and when the uC asks for it.

Changing in the routine for reading the HV from ADC_HV_VOLTAGE_CHANNEL to ADC_ASIC_VOLTAGE_CHANNEL. So that I get the wrong channel makes the problem go away.

They are defined as:

#define ADC_HV_VOLTAGE_CHANNEL 0
#define ADC_ASIC_VOLTAGE_CHANNEL 2

The only differance I can see is that the call stack depth is higher when called from PC. But then how does the change above make it right? And why only problem once in 20k samples.

Also doing as you said, make the uC read the ADC and put in a register that is read by the PC also makes it work. But only needed for the ADC_HV_VOLTAGE_CHANNEL. The other 7 channels are ok anyway, and asked for by the PC as often as the HV.

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

So I have been running trough the weekend now. I was able to run for 40 hours and do 1.4 million image readouts before I got the fail now. That is about 140 gigabytes of data transfered before fail.