Last active
January 9, 2020 13:02
-
-
Save mutability/ea02e61d522f8f5102af5fe62f4f4951 to your computer and use it in GitHub Desktop.
Measure Cypress FX3 timer tick period / errors
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 (); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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