ch32v307 dev board, part 3
Next step on getting an NTP server running on the ch32v307 dev board is verifying the local clock.
This is part of a series on the ch32v307 dev board
There's two local clocks to consider: the PTP hardware timestamp clock, and the PPS input capture clock. I'll focus just on the PTP hardware timestamp clock in this post.
PTP hardware timestamp clock
The main registers that everything is built around are: PTPTSHR, which is a 32 bit counter of seconds and PTPTSLR, which counts 31 bits of fractional seconds (in other words, each count is 1/(2**31) seconds or 465 picoseconds).
There's two different modes of operation to keep these registers updated: fine and coarse.
PTP clock coarse mode
With coarse mode, a value is added to the subsecond register with every microprocessor clock cycle. When the subsecond register overflows 31 bits, one second is added to the second register. Since this microprocessor runs at 144MHz, each clock cycle is 6944 picoseconds. The closest value to add to the subsecond register is 15/2**31, or 6984 picoseconds. This runs the clock 0.57% fast, which isn't great.
PTP clock fine mode
With fine mode, a value is added to an accumulator with every clock cycle, and when that accumulator overflows, another value is added to the subsecond register. That gives you control of the frequency in 1/2**32 steps. To correct for the 0.57% error in the PTPSSIR/PTPTSLR combination, I would set PTPTSAR to 4270485982/2**32, which should update the PTPTSLR register at 99.43% normal speed.
There's two problems with this mode on this hardware: when subsecond overflows, multiple seconds are added to the second register, and the accumulator does not work properly.
Fine mode problem: subsecond overflows
To compare my computer's clock to the micro's clock, I had the micro print out the time once per second (second column). The computer then took its timestamp of that message (first column) and compared the difference in duration from the start. The ratio (third column) between the durations of both clocks should be very close to 1.0 if everything is running properly.
I set the seconds register to 1690513986 at startup, but it reads as x2 that amount. The subsecond register is running at half the speed it should be, but every time it overflows, it adds two to the seconds register. This ends up at nearly the right ratio, but this isn't a quality clock. I explored shifting the seconds right by 1 bit (effectively a divide by 2), but that lead me to my second problem.
Fine mode problem: subsecond register updates
The subsecond register should be moving at 99.43% original speed, not 50% speed. To measure this more closely, I polled the subsecond register once per clock cycle and measured how frequently it updated:
for(int i = 0; i < 10; i++) {
a = ETH->PTPTSLR;
b = ETH->PTPTSLR;
c = ETH->PTPTSLR;
d = ETH->PTPTSLR;
e = ETH->PTPTSLR;
f = ETH->PTPTSLR;
g = ETH->PTPTSLR;
printf("%u %u %u %u %u %u %u\r\n", a, b, c, d, e, f, g);
}
The unrolled loop reading PTPTSLR compiles down to this nice assembly:
670: 454c lw a1,12(a0)
672: 4550 lw a2,12(a0)
674: 4554 lw a3,12(a0)
676: 4558 lw a4,12(a0)
678: 455c lw a5,12(a0)
67a: 00c52803 lw a6,12(a0)
67e: 00c52883 lw a7,12(a0)
I counted how many times I saw PTPTSLR change out of the total number of measurements.
With 4270485982, I would expect it to change 99.43% of the time, but it changed 49.7% of the time, which is why the clock was running at 50%. I picked some values to set PTPTSAR to see how it behaved. It got back some pretty strange results.
PTPTSAR | Expected | Actual |
---|---|---|
4270485982 | 99.43% | 49.7% |
3221225472 | 75% | 50% |
3049426780 | 71% | 42% |
2920577761 | 68% | 36% |
2662879723 | 62% | 38% |
2190433320 | 51% | 49% |
2147483648 | 50% | 50% |
2126008811 | 49.5% | 49.5% |
2104533975 | 49% | 50% |
1632087572 | 38% | 38% |
1073741824 | 25% | 25% |
Additionally, the setting of PTPTSAR affected the updates of the second register:
PTPTSAR | second register |
---|---|
4294967295 | +2s on overflow |
2147483648 | +2s |
1073741824 | +4s |
536870912 | +8s |
268435456 | +16s |
134217728 | +32s |
67108864 | +64s |
33554432 | +128s |
16777216 | +256s |
8388608 | +512s |
4194304 | +1024s |
The ch32v307 PTP hardware is very similiar to the stm32f4xx PTP hardware. Except fine mode doesn't have these problems on the stm32f4xx.
So I'll be exploring adjusting the frequency via a software clock instead of a hardware clock.