borkedLabs

SAMC20/SAMC21 AC Comparator stuck syncing

So here I was, trying to get even the simple Analog Comparator (AC) example projects (i.e. “Quick Start for the SAM AC Driver”) in Studio on both a custom board and a SAM C21 Xplained Pro eval board. And for some reason it always got stuck syncing.

It always got stuck here:

static inline void ac_enable(
		struct ac_module *const module_inst)
{
	/* Sanity check arguments */
	Assert(module_inst);
	Assert(module_inst->hw);

	Ac *const ac_module = module_inst->hw;

	while (ac_is_syncing(module_inst)) {
		/* Wait until synchronization is complete */
	}

inside the loop waiting for ac_is_syncing to indicate synchronization.

It wasn’t immediately obvious but the issue was a subtle oversight in ASF you just don’t expect to happen.

What’s the problem?

Revision B of the SAMC21 per Errata reference 13404 had a silicon defect where the analog comparator was connected to the ADC1 peripheral gclk channel instead of its intended channel for itself:

ASF had a workaround added a little poorly to fix the issue for the SAMC21. (Most likely before it was fixed with the author unaware with the intention to fix it ultimately)

It can be found in \src\ASF\sam0\drivers\ac\ac_sam_l_c\ac.c

inside the _ac_set_config function

#if (SAMC21) || (SAMC20)
	/* The Analog Comparators and ADC1 use the same generic clock configuration.
 	 * GCLK_ADC1 must be used to configure the clock for AC as GCLK_AC is not 
 	 * functional. Errata reference: 13404 
 	 */
	system_gclk_chan_set_config(34, &gclk_chan_conf);
	system_gclk_chan_enable(34);
#else
	system_gclk_chan_set_config(AC_GCLK_ID, &gclk_chan_conf);
	system_gclk_chan_enable(AC_GCLK_ID);
#endif

as you can see, the SAMC21 and SAMC20 will always configure ADC1 / GCLK ID 34 for the workaround…which is great…only if we still had Revision B chips.

Solution

This is just up in the air, based on the datasheet, the AC GCLK channel is not the last channel, its ID is 40 and the number of defined channel registers go up to 45. It could the registers were entirely missing in Revision B of the chip, or it could have been it was simply not routed to the AC peripheral.

I just went with the assumption that the channel simply was not connected out of oversight. So the solution is to simply move the normal gclk_id config outside the #else, so that it runs always.

#if (SAMC21) || (SAMC20)
	/* The Analog Comparators and ADC1 use the same generic clock configuration.
 	 * GCLK_ADC1 must be used to configure the clock for AC as GCLK_AC is not 
 	 * functional. Errata reference: 13404 
 	 */
	system_gclk_chan_set_config(34, &gclk_chan_conf);
	system_gclk_chan_enable(34);
#endif

	system_gclk_chan_set_config(AC_GCLK_ID, &gclk_chan_conf);
	system_gclk_chan_enable(AC_GCLK_ID);

So if the AC GCLK registers are present, it really doesn’t matter in Rev B if we configure the GCLK as along as we still configure the ADC1 as the workaround at the same time.

Or you can just say, screw it! We won’t get any old Revision B chips and remove the #if exception for the SAMC family altogether.

Note

As of writing, the issue is present on ASF 3.35.

comments powered by Disqus