Electronic – The value of the TCC counter on an ATSAM controller always reads as zero

cortex-m0register

I use an ATSAMD21 to generate a custom signal with the help of a PWM generator.

Basically, I set up TCC0 as a PWM generator, and use its overflow interrupt to set up the CC registers for the next pulse. It all works fine, the signal looks as it should look like. However, as it is important for the interrupt to occur before the shortest possible polarity change in my signal, I wanted to check the interrupt latency, to detect a possible failure case. That should be as simple as checking the COUNT register at the beginning of the interrupt, shouldn't it?

However, the COUNT register always reads as zero.

It doesn't matter whether I use REG_TCC0_COUNT or TCC0->COUNT.bit.COUNT, it always reads as 0. I can be sure that the actual value of the counter is not zero, because the timer is set to a very fast clock generator, and on the oscilloscope I can see that the typical interrupt latency is where the counter should already be around 100.

Interestingly, I can write to the COUNT register. If I do so, I can verify that the next pulse is shortened by the respective amount. And after the write, if I read it back, I read the value I just wrote.

As the same processor is used in the Arduino Zero, this issue was already asked on the Arduino forums a few years ago, but there is still no answer:

One of the proposed solutions was to wait for the SYNCBUSY to be cleared, but it didn't work, neither for the poster on the Arduino forum, nor for me.

Best Answer

There is a command in the Control B register of the TCC peripherals,

  • READSYNC – Force a read synchronization of COUNT

The value of the COUNT register is not valid until this command is issued and fully executed.

Sample code, tested on a SAMD21E17A device:

// Step 1: Issue READYSYNC command
TCC0->CTRLBSET.reg = TCC_CTRLBSET_CMD_READSYNC;

// Step 2: Wait until the command is fully executed
while (TCC0->SYNCBUSY.bit.CTRLB); // or while (TCC0->SYNCBUSY.reg);

// Step 3: Now we can read the value of the COUNT register
int count = TCC0->COUNT.reg;

The resulting value of the variable count corresponds to the value of the counter when the READSYNC command was actually executed.

For additional information, check chapter 31 of the SAM D21/DA1 Family datasheet