drivers/jlink: fix calculate_swo_prescaler formula
authorAdrian Negreanu <adrian.negreanu@nxp.com>
Mon, 7 Sep 2020 19:36:10 +0000 (22:36 +0300)
committerAntonio Borneo <borneo.antonio@gmail.com>
Sun, 27 Sep 2020 16:40:12 +0000 (17:40 +0100)
a) TPIU_ACPR is defined as:
SWO_baudrate = TRACECLKIN/(TPIU_ACPR +1)

b) TPIU_ACPR is set by armv7m_trace_tpiu_config()
target_write_u32(target, TPIU_ACPR, Prescaler-1), so
TPIU_ACPR = Prescaler-1

Replacing TPIU_ACPR in a), we get:
SWO_baudrate = TRACECLKIN/Prescaler, so

c) Prescaler = TRACECLKIN/SWO_baudrate

The Prescaler calculated by calculate_swo_prescaler() is greater by 1:
Prescaler = TRACECLKIN/SWO_baudrate + 1

The second problem is that even in situations when
an exact baudrate match is possible,
the resulting TRACECLKIN/Prescaler already has a 3% deviation.

For example, TRACECLKIN=88000000, SWO_baudrate=500000,
calculate_swo_prescaler will return Prescaler=171.
The correct value should be Prescaler=176 (TPIU_ACPR=175).

Might be related to https://sourceforge.net/p/openocd/tickets/263/

Change-Id: Ib4d6df6e34685a9be4c2995cb500b2411c76e39b
Signed-off-by: Adrian Negreanu <adrian.negreanu@nxp.com>
Reviewed-on: http://openocd.zylin.com/5807
Tested-by: jenkins
Reviewed-by: Marc Schink <dev@zapb.de>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
src/jtag/drivers/jlink.c

index 57e357b79b441450f94cb0aac9c465f597468629..910799ce2f3b2e38c6b634408c89765b0566be29 100644 (file)
@@ -1270,16 +1270,14 @@ static bool calculate_swo_prescaler(unsigned int traceclkin_freq,
                uint32_t trace_freq, uint16_t *prescaler)
 {
        unsigned int presc;
-       double deviation;
-
-       presc = ((1.0 - SWO_MAX_FREQ_DEV) * traceclkin_freq) / trace_freq + 1;
-
+       presc = DIV_ROUND_UP(traceclkin_freq, trace_freq);
        if (presc > TPIU_ACPR_MAX_SWOSCALER)
                return false;
 
-       deviation = fabs(1.0 - ((double)trace_freq * presc / traceclkin_freq));
-
-       if (deviation > SWO_MAX_FREQ_DEV)
+       /* Probe's UART speed must be within 3% of the TPIU's SWO baud rate. */
+       unsigned int max_deviation = (traceclkin_freq * 3) / 100;
+       if (presc * trace_freq < traceclkin_freq - max_deviation ||
+           presc * trace_freq > traceclkin_freq + max_deviation)
                return false;
 
        *prescaler = presc;