Explain clock synchronization mechanism

This commit is contained in:
jazzpi 2022-08-03 00:52:28 +02:00
parent 76427bdede
commit 9c1d743bfd

View File

@ -1,5 +1,116 @@
#include "ClockSync.h"
/**
* @file ClockSync.c
* @author Jasper v. Blanckenburg (j.blanckenburg@fasttube.de)
* @brief Clock synchronization mechanism -- slave side
* @version 0.1
* @date 2022-08-02
*
* @copyright Copyright (c) 2022
*
* OVERVIEW
* =========
* The slaves use the STM's internal clock (HSI), which is -- especially at
* higher temperatures -- quite inaccurate (±4% over the STM's working
* temperature range, according to the datasheet).
*
* Since the CAN bitrate is directly determined from the HSI (through prescaling
* & time quanta), an inaccurate HSI means an inaccurate CAN bitrate. Especially
* once the battery heats up, this leads to packet loss and ultimately the CAN
* transceiver entering Bus-Off due to too many transmission errors.
*
* The easy fix would be to use an external clock (HSE), i.e. a quartz crystal.
* Although a crystal is present on the slaves, it does not work on every one
* and is mounted on the (inaccessible) underside. Thus, we need to make do with
* the HSI.
*
* Fortunately, the HSI frequency can be trimmed through the HSITRIM bits in the
* RCC_CR register (see STM32F412 reference manual, section 6.2.2; as well as
* STM AN5067).
*
* The HSITRIM register provides the mechanism for manipulating the HSI
* frequency, however we still need to determine what value to manipulate it to.
* Since we don't really care about the absolute accuracy of the slaves' clocks,
* but rather their relative accuracy to the other nodes on the CAN bus
* (especially the master), we can synchronize the clocks to one another via
* timed CAN frames.
*
* TIMED CAN FRAMES
* ================
* As the master is the least affected by the battery heating up, and also had
* the most accurate clock during testing, we use it to generate the timed
* frames.
*
* It sends frames from timer interrupts and with high priority (low ID) to
* ensure minimal deviation from their intended frequency. It sends two separate
* kinds of frames: CLOCK_SYNC and MASTER_HEARTBEAT.
*
* The MASTER_HEARTBEAT frames are sent every 100 ms. Their purpose is simply to
* reliably have messages on the bus, so that the slaves can tell whether they
* are roughly in sync with the master by checking for their reception (see the
* FREQUENCY HOPPING section).
*
* The CLOCK_SYNC frames are sent every 1000 ms. They serve as the external
* clock source. The slaves continually trim their HSI according to the time
* they measure between to CLOCK_SYNC frames (see the NORMAL OPERATION section).
*
* FREQUENCY HOPPING
* =================
* If the HSI is very out of sync with the master's clock (e.g. because the AMS
* was restarted with a warm battery), the slaves don't receive any CAN packets
* from the master and thus can't rely on the CLOCK_SYNC frames for
* synchronization. In this case, they rely on what is essentially frequency
* hopping.
*
* The frequency hopping mechanism has two stages: One to get in the right
* ballpark, and one to make the communication reliable enough for normal
* operation.
*
* STAGE 1
* -------
* Stage 1 trims the HSI until at least one MASTER_HEARTBEAT frame has been
* received. The frequency alternates between lower and higher values, i.e. if
* the trim was initially 16, it will go through the following values:
*
* 16 -> 14 -> 18 -> 12 -> 20 -> 10 -> 22 -> ...
*
* Once a MASTER_HEARTBEAT frame has been received, the slave transitions to
* stage 2.
*
* STAGE 2
* -------
* Stage 2 trims the HSI further until at least three consecutive
* MASTER_HEARTBEAT frames have been received. The frequency alternates in the
* same fashion as in stage 1, but now around the frequency where a
* MASTER_HEARTBEAT frame was received in stage 1, and more slowly.
*
* Once three consecutive MASTER_HEARTBEAT frames have been received, the slave
* transitions to normal operation.
*
* NORMAL OPERATION
* ================
* During normal operation, the HSI is continually trimmed so that CLOCK_SYNC
* frames are received every 1000 ms. Since the slave measures time in
* milliseconds (via the HAL_GetTick() function), this allows a measurement
* accuracy of 0.1%. Each increment of HSITRIM should account for an approximate
* 0.3% increase in the clock frequency, according to AN5067, so the 0.1%
* accuracy is more than enough for accurate trimming.
*
* By counting the ticks between two CLOCK_SYNC frames, the slave determines its
* actual HSI frequency (assuming the master clock is accurate):
*
* f_real = 16 MHz * measured_ticks / 1000
*
* If the real frequency differs from the target frequency (16 MHz) by more than
* the trim delta, the trim is incremented or decremented accordingly.
*
* The trim delta is determined dynamically: It is the difference between the
* real frequency before and after each trim.
*
* If the slave misses two consecutive CLOCK_SYNC frames for whatever reason, it
* returns to (stage 1) frequency hopping.
*/
#include "AMS_CAN.h"
#include "stm32f412rx.h"