Skip to content

Instantly share code, notes, and snippets.

@mutability
Last active January 9, 2020 13:02
Show Gist options
  • Save mutability/ea02e61d522f8f5102af5fe62f4f4951 to your computer and use it in GitHub Desktop.
Save mutability/ea02e61d522f8f5102af5fe62f4f4951 to your computer and use it in GitHub Desktop.
Measure Cypress FX3 timer tick period / errors
diff -ur fx3_sdk_1_3_4_src/sdk/firmware/src/system/cyu3vic.c fx3_sdk_1_3_4_src.patched/sdk/firmware/src/system/cyu3vic.c
--- fx3_sdk_1_3_4_src/sdk/firmware/src/system/cyu3vic.c 2017-11-24 09:45:52.000000000 +0800
+++ fx3_sdk_1_3_4_src.patched/sdk/firmware/src/system/cyu3vic.c 2020-01-09 16:46:45.146468433 +0800
@@ -34,12 +34,18 @@
#define CY_U3P_WDT1_DISABLE_MASK (CY_U3P_GCTL_MODE1_MASK)
#define CY_U3P_WDT1_MODE_INTR_MASK (1 << CY_U3P_GCTL_MODE1_POS)
-/* Assuming timer clock frequency as 32KHz */
-#define CY_U3P_OS_TIMER_TICK_OFFSET (7)
-#define CY_U3P_OS_TIMER_TICK_COUNT (32)
+/* Represent the timer tick count as a 16:16 fixed-point value */
+#define CY_U3P_OS_TIMER_TICK_SCALE_BITS (16)
+#define CY_U3P_OS_TIMER_TICK_SCALE (1 << CY_U3P_OS_TIMER_TICK_SCALE_BITS)
+#define CY_U3P_OS_TIMER_TICK_VALUE(f) ((uint32_t)((f) * CY_U3P_OS_TIMER_TICK_SCALE + 0.5))
+#define CY_U3P_OS_TIMER_TICK_INT_PART(x) ((x) >> CY_U3P_OS_TIMER_TICK_SCALE_BITS)
+#define CY_U3P_OS_TIMER_TICK_FRAC_PART(x) ((x) & (CY_U3P_OS_TIMER_TICK_SCALE - 1))
+#define CY_U3P_OS_TIMER_TICK_COUNT CY_U3P_OS_TIMER_TICK_VALUE(32.768)
+#define CY_U3P_OS_TIMER_TICK_OFFSET CY_U3P_OS_TIMER_TICK_VALUE(7.003488)
uint16_t glOsTimerInterval = 1;
-static uint32_t glOsTimerTickCount = CY_U3P_OS_TIMER_TICK_COUNT;
+static uint32_t glOsTimerTickIncrement = CY_U3P_OS_TIMER_TICK_COUNT;
+static uint32_t glOsTimerTickCount = 0;
void
CyU3PVicInit (
@@ -191,27 +197,28 @@
if ((intervalMs == 0) || (intervalMs > 1000))
{
glOsTimerInterval = 1;
- glOsTimerTickCount = CY_U3P_OS_TIMER_TICK_COUNT;
+ glOsTimerTickIncrement = CY_U3P_OS_TIMER_TICK_COUNT;
}
else
{
glOsTimerInterval = intervalMs;
- glOsTimerTickCount = intervalMs * CY_U3P_OS_TIMER_TICK_COUNT;
+ glOsTimerTickIncrement = intervalMs * CY_U3P_OS_TIMER_TICK_COUNT;
}
/* Adjust the time taken for disabling and enabling the
* timer as a part of interrupt handling. */
- glOsTimerTickCount -= CY_U3P_OS_TIMER_TICK_OFFSET;
+ glOsTimerTickIncrement -= CY_U3P_OS_TIMER_TICK_OFFSET;
+ glOsTimerTickCount = 0;
/* Calculate the significant bits for the timer. */
tmp = 0;
- while ((1 << tmp) <= glOsTimerTickCount)
+ while ((1 << tmp) <= CY_U3P_OS_TIMER_TICK_INT_PART(glOsTimerTickIncrement) + 1)
{
tmp++;
}
/* Load the timer count. */
- GCTLAON->watchdog_timer1 = glOsTimerTickCount;
+ GCTLAON->watchdog_timer1 = CY_U3P_OS_TIMER_TICK_INT_PART(glOsTimerTickIncrement);
CyU3PBusyWait (100);
/* Enable the WDT1 interrupt */
@@ -242,14 +249,20 @@
GCTLAON->watchdog_cs |= CY_U3P_WDT1_DISABLE_MASK;
wdtcs = GCTLAON->watchdog_cs;
- /* Reload the counter. */
- GCTLAON->watchdog_timer1 = glOsTimerTickCount;
+ /* Update the count */
+ glOsTimerTickCount += glOsTimerTickIncrement;
+
+ /* Reload the counter with the integer part of the tick count */
+ GCTLAON->watchdog_timer1 = CY_U3P_OS_TIMER_TICK_INT_PART(glOsTimerTickCount);
/* Restart the timer */
wdtcs = GCTLAON->watchdog_cs & (~CY_U3P_GCTL_MODE1_MASK);
wdtcs |= (CY_U3P_GCTL_INTR1 | CY_U3P_WDT1_MODE_INTR_MASK);
GCTLAON->watchdog_cs = wdtcs;
+ /* Retain only the fractional part of the count for next time */
+ glOsTimerTickCount = CY_U3P_OS_TIMER_TICK_FRAC_PART(glOsTimerTickCount);
+
/* Invoke the OS scheduler. */
CyU3POsTimerHandler ();
}
# UART output using FX3 SDK 1.3.4 on the CYUSB3KIT-003 development board:
== STARTED ==
OS = 1001 GPIO = 23433601 expected=0 actual=0 error=0 ppm
OS = 2001 GPIO = 46873550 expected=24000000 actual=23439949 error=23893 ppm
OS = 3001 GPIO = 70313557 expected=48000000 actual=46879956 error=23891 ppm
OS = 4001 GPIO = 93753550 expected=72000000 actual=70319949 error=23891 ppm
OS = 5001 GPIO = 117193554 expected=96000000 actual=93759953 error=23891 ppm
OS = 6001 GPIO = 140633547 expected=120000000 actual=117199946 error=23891 ppm
OS = 7001 GPIO = 164073548 expected=144000000 actual=140639947 error=23891 ppm
OS = 8001 GPIO = 187513553 expected=168000000 actual=164079952 error=23891 ppm
OS = 9001 GPIO = 210953544 expected=192000000 actual=187519943 error=23891 ppm
OS = 10001 GPIO = 234393536 expected=216000000 actual=210959935 error=23891 ppm
OS = 11001 GPIO = 257833542 expected=240000000 actual=234399941 error=23891 ppm
OS = 12001 GPIO = 281273552 expected=264000000 actual=257839951 error=23890 ppm
OS = 13001 GPIO = 304713545 expected=288000000 actual=281279944 error=23890 ppm
[...]
OS = 177001 GPIO = 4148873548 expected=4224000000 actual=4125439947 error=23890 ppm
OS = 178001 GPIO = 4172313548 expected=4248000000 actual=4148879947 error=23890 ppm
OS = 179001 GPIO = 4195753551 expected=4272000000 actual=4172319950 error=23890 ppm
/* This demo measures the difference between time as measured by
* the nominally 1ms OS timer ticks (CyU3PGetTime()) and time as
* measured by a complex GPIO timer running at a known frequency.
*/
#include "cyu3system.h"
#include "cyu3os.h"
#include "cyu3error.h"
#include "cyu3uart.h"
#include "cyu3gpio.h"
#include "cyu3utils.h"
static void debug_init()
{
CyU3PUartConfig_t uartConfig;
CyU3PUartInit ();
uartConfig.baudRate = CY_U3P_UART_BAUDRATE_115200;
uartConfig.stopBit = CY_U3P_UART_ONE_STOP_BIT;
uartConfig.parity = CY_U3P_UART_NO_PARITY;
uartConfig.txEnable = CyTrue;
uartConfig.rxEnable = CyFalse;
uartConfig.flowCtrl = CyFalse;
uartConfig.isDma = CyTrue;
CyU3PUartSetConfig (&uartConfig, NULL);
CyU3PUartTxSetBlockXfer (0xFFFFFFFF);
CyU3PDebugInit (CY_U3P_LPP_SOCKET_UART_CONS, 8);
CyU3PDebugPreamble(CyFalse);
}
static uint32_t gpio_frequency;
static void gpio_init()
{
CyU3PGpioClock_t gpioClock;
CyU3PGpioComplexConfig_t complex;
uint32_t sysClk;
gpioClock.clkSrc = CY_U3P_SYS_CLK;
gpioClock.fastClkDiv = 16;
gpioClock.halfDiv = 0;
gpioClock.slowClkDiv = 0;
gpioClock.simpleDiv = CY_U3P_GPIO_SIMPLE_DIV_BY_16;
CyU3PGpioInit(&gpioClock, NULL);
CyU3PDeviceGpioOverride(24, CyFalse);
complex.driveHighEn = CyFalse;
complex.driveLowEn = CyFalse;
complex.inputEn = CyFalse;
complex.intrMode = CY_U3P_GPIO_NO_INTR;
complex.outValue = CyFalse;
complex.period = (uint32_t)~0;
complex.pinMode = CY_U3P_GPIO_MODE_STATIC;
complex.threshold = 0;
complex.timer = 0;
complex.timerMode = CY_U3P_GPIO_TIMER_HIGH_FREQ;
CyU3PGpioSetComplexConfig(24, &complex);
CyU3PDeviceGetSysClkFreq(&sysClk);
gpio_frequency = sysClk / 16;
}
static uint32_t read_gpio_timer()
{
uint32_t value = 0;
CyU3PGpioComplexSampleNow(24, &value);
return value;
}
static void mainthread(uint32_t input)
{
debug_init();
gpio_init();
CyU3PDebugPrint (2, "== STARTED ==\r\n");
uint32_t firstOsTick = 0;
uint32_t firstGpioCount = 0;
while (1) {
CyU3PThreadSleep(1000);
uint32_t osTicks = CyU3PGetTime();
uint32_t gpioCount = read_gpio_timer();
if (!firstOsTick) {
firstOsTick = osTicks;
firstGpioCount = gpioCount;
}
/* nb: this is only correct until the GPIO timer wraps around */
double expectedCount = (osTicks - firstOsTick) / 1000.0 * gpio_frequency; /* timer ticks are meant to be running at 1000Hz */
double actualCount = (gpioCount - firstGpioCount);
double errorPPM = (actualCount == 0 ? 0 : 1000000.0 * (expectedCount / actualCount - 1));
CyU3PDebugPrint (2, "OS = %u GPIO = %u expected=%u actual=%u error=%u ppm\r\n", osTicks, gpioCount, (uint32_t)expectedCount, (uint32_t)actualCount, (uint32_t)errorPPM);
}
}
#define APPTHREAD_STACK (0x0800)
#define APPTHREAD_PRIORITY (8)
void CyFxApplicationDefine(void)
{
static CyU3PThread appThread;
void *ptr = CyU3PMemAlloc (APPTHREAD_STACK);;
CyU3PThreadCreate (&appThread, /* Thread structure. */
"21:main", /* Thread ID and name. */
mainthread, /* Thread entry function. */
0, /* Thread input parameter. */
ptr, /* Pointer to the allocated thread stack. */
APPTHREAD_STACK, /* Allocated thread stack size. */
APPTHREAD_PRIORITY, /* Thread priority. */
APPTHREAD_PRIORITY, /* Thread pre-emption threshold: No preemption. */
CYU3P_NO_TIME_SLICE, /* No time slice. Thread will run until task is
completed or until the higher priority
thread gets active. */
CYU3P_AUTO_START); /* Start the thread immediately. */
}
int main (void)
{
CyU3PIoMatrixConfig_t io_cfg;
CyU3PDeviceInit (NULL);
CyU3PDeviceCacheControl (CyTrue, CyTrue, CyTrue);
/* Configure the IO matrix for the device. */
CyU3PMemSet ((uint8_t *)&io_cfg, 0, sizeof(io_cfg));
io_cfg.isDQ32Bit = CyFalse;
io_cfg.s0Mode = CY_U3P_SPORT_INACTIVE;
io_cfg.s1Mode = CY_U3P_SPORT_INACTIVE;
io_cfg.useUart = CyTrue;
io_cfg.useI2C = CyFalse;
io_cfg.useI2S = CyFalse;
io_cfg.useSpi = CyFalse;
io_cfg.lppMode = CY_U3P_IO_MATRIX_LPP_UART_ONLY;
io_cfg.gpioSimpleEn[0] = 0;
io_cfg.gpioSimpleEn[1] = 0;
io_cfg.gpioComplexEn[0] = 0;
io_cfg.gpioComplexEn[1] = 0;
CyU3PDeviceConfigureIOMatrix (&io_cfg);
CyU3PKernelEntry (); /* does not return */
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment