From: Andy Spencer Date: Mon, 10 Mar 2014 09:14:40 +0000 (+0000) Subject: Improve time sync accuracy X-Git-Url: http://pileus.org/git/?p=~andy%2Fcsm213a-hw;a=commitdiff_plain;h=70a817bdd055b39c1990778594ed97a532748d31 Improve time sync accuracy This code is kind of messy, but it is more accurate. Noise between time syncs seems to be around 50 nanoseconds. Noise on external event readings seems to be around 500 nanoseconds. External events were tested by manually inserting pins. The mbeds seems to be consistency apart on external events, so some of the noise could be caused by differing thresholds on the wires. Rising edge mode on mbed seems to be ahead, and in falling edge the other is ahead. A large portion of the measurement errors was caused by not properly learning pending DMA requests before enabling the DMA channels. The pending requests seem to need to be disabled in the DMAMUX as well as the DMA controller, and on the pins as well. It's not clearly what the idea reset method is. --- diff --git a/hw2/main.cpp b/hw2/main.cpp index 108000e..87bca11 100644 --- a/hw2/main.cpp +++ b/hw2/main.cpp @@ -20,6 +20,17 @@ * Time synchronization is performed in both directions. */ +/**************** + * Testing vars * + ****************/ + +uint32_t test_xmt_enab = 0; +uint64_t test_xmt_time0 = 0; +uint64_t test_xmt_time1 = 0; + +uint32_t test_rcv_enab = 0; +uint64_t test_rcv_time = 0; + /******************* * Timer functions * *******************/ @@ -92,19 +103,51 @@ void time_ext_sync(uint64_t local, uint64_t world) int ahead = guess > world; time_last_local = local; - time_last_world = guess/2 + world/2; + time_last_world = (guess/2) + (world/2); + //time_last_world = (guess * 3 / 4) + (world * 1 / 4); + //time_last_world = + // (guess - ( guess / 2)) + + // (world - (world - world / 2)); + //time_last_world = + // (guess - (guess - guess / 4)) + + // (world - ( world / 4)); world = time_last_world; - sirq_printf("syncing clocks: %d=%d.%04u -> %d.%04u (err: %s%ld.%09lu)\r\n", +//#ifdef VERBOSE +#if 0 + sirq_printf("syncing clocks: %6d=%d.%04u -> %d.%04u (err: %s%ld.%09lu)\r\n", (int)((local / NSEC_PER_SEC)), (int)((guess / NSEC_PER_SEC)), (int)((guess % NSEC_PER_SEC)/(NSEC_PER_SEC/10000)), (int)((world / NSEC_PER_SEC)), (int)((world % NSEC_PER_SEC)/(NSEC_PER_SEC/10000)), - ahead ? "-" : "", + ahead ? "-" : " ", (int32_t )(error / (int64_t)NSEC_PER_SEC), (uint32_t)(error % (int64_t)NSEC_PER_SEC)); +#endif +//#endif + + // .000000284 + // .000000253 + // .000000264 + // .000000451 + // .000000284 + // .000000267 + // .000000223 + // .000000326 + +} + +void time_printf(const char *label, uint64_t local) +{ + uint64_t world = time_to_world(local); + sirq_printf("%s -- %d.%09u -> %d.%09u\r\n", + label, + (int)(local / NSEC_PER_SEC), + (int)(local % NSEC_PER_SEC), + (int)(world / NSEC_PER_SEC), + (int)(world % NSEC_PER_SEC)); } /************************ @@ -117,7 +160,7 @@ typedef struct { uint8_t buffer[256]; } parser_t; -const uint64_t serial_sync_delay = NSEC_PER_SEC / 10; // 1hz +const uint64_t serial_sync_delay = NSEC_PER_SEC / 100; // 1hz static uint64_t serial_sync_due = 0; static tdma_t *serial_tdma_rcv = NULL; @@ -137,7 +180,10 @@ void serial_send_sync(sirq_t *port, uint64_t now) if (serial_sync_due == 0 || now < serial_sync_due) return; // not ready + //sirq_printf("sending sync\r\n"); + // Calculate world time + uint64_t local = 0; uint64_t world = time_to_world(serial_xmt_local); // Message data @@ -154,23 +200,33 @@ void serial_send_sync(sirq_t *port, uint64_t now) body.time.seconds = world / NSEC_PER_SEC; body.time.nanosec = world % NSEC_PER_SEC; + tdma_stop(serial_tdma_rcv); + + test_xmt_enab = 1; + test_xmt_time0 = 0; + test_xmt_time1 = 0; + + tdma_start(serial_tdma_xmt); sirq_write(port, &head, sizeof(head)); sirq_write(port, &body, sizeof(body)); + tdma_stop(serial_tdma_xmt); - serial_xmt_seq += 1; - serial_sync_due = 0; + // save transmit time + //local = test_xmt_time1; + int valid = tdma_stamp(serial_tdma_xmt, &local); + if (!valid) { + sirq_printf("sync transmit time -- missed\r\n"); + } else { + //time_printf("sync transmit time ", local); + //time_printf("sync transmit test0", test_xmt_time0); + //time_printf("sync transmit test1", test_xmt_time1); + } - // Debug - //sirq_printf("sync msg transmit\r\n"); + tdma_start(serial_tdma_rcv); - // save transmit time - for (int i = 0; i < 1000; i++) - asm("nop"); - int valid = tdma_stamp(serial_tdma_xmt, &serial_xmt_local); - if (!valid) - sirq_printf("missing sync transmit time\r\n"); - tdma_reset(serial_tdma_rcv); - tdma_reset(serial_tdma_xmt); + serial_xmt_seq += 1; + serial_sync_due = 0; + serial_xmt_local = local; } /** @@ -201,9 +257,10 @@ void serial_handle_sync(sync_msg_t *msg) uint64_t current = 0; int valid = tdma_stamp(serial_tdma_rcv, ¤t); if (!valid) - sirq_printf("missing sync receive time\r\n"); - tdma_reset(serial_tdma_rcv); - tdma_reset(serial_tdma_xmt); + sirq_printf("sync receive time -- missing\r\n"); + //else + // time_printf("sync receive time ", current); + tdma_stop(serial_tdma_rcv); // Lookup times uint64_t world = ((uint64_t)msg->time.seconds) * NSEC_PER_SEC @@ -359,7 +416,8 @@ void task_events(uint64_t local, uint64_t world) if (tdma_stamp(tdma_evt, &event)) serial_send_event(0, event); - tdma_reset(tdma_evt); + tdma_stop(tdma_evt); + tdma_start(tdma_evt); } void task_sync(uint64_t local, uint64_t world) @@ -378,6 +436,10 @@ void task_leds(uint64_t local, uint64_t world) void task_debug(uint64_t local, uint64_t world) { //tdma_debug(tdma_rcv); + //tdma_debug(tdma_xmt); + + //sirq_debug(sirq_mbed); + #ifdef VERBOSE sirq_printf("background - %6u.%02u -> %u.%02u\r\n", (uint32_t)(local / NSEC_PER_SEC), @@ -432,9 +494,8 @@ int main(int argc, char **argv) sirq_bbb = sirq_open(SIRQ_UART1, PTE0, PTE1, 115200); // to bbb sirq_mbed = sirq_open(SIRQ_UART2, PTD3, PTD2, 115200); // to mbed - // Setup timers - tdma_evt = tdma_open(TDMA_CHAN0, 3, PTC9, PullDown); // async event + tdma_evt = tdma_open(TDMA_CHAN0, 3, PTC9, PullUp); // async event // mbed time sync tdma_rcv = tdma_open(TDMA_CHAN2, 3, PTD2, PullUp); // time sync rcv @@ -444,10 +505,46 @@ int main(int argc, char **argv) //tdma_rcv = tdma_open(TDMA_CHAN2, 2, USBRX, PullUp); // time sync rcv //tdma_xmt = tdma_open(TDMA_CHAN3, 2, USBTX, PullUp); // time sync xmt + // start timers + tdma_start(tdma_evt); + tdma_start(tdma_rcv); + tdma_start(tdma_xmt); + // Serial timestamping serial_tdma_rcv = tdma_rcv; serial_tdma_xmt = tdma_xmt; + // Test clocks + //MCG->C1 = 0x05; // was 0x1A + //MCG->C2 = 0x2C; // was 0x24 + //MCG->C3 = 0x91; // was 0x91 + //MCG->C4 = 0x10; // was 0x10 + //MCG->C5 = 0x01; // was 0x01 + //MCG->C6 = 0x40; // was 0x40 + //MCG->S = 0x6E; // was 0x6E + //MCG->SC = 0x02; // was 0x02 + //MCG->ATCVH = 0x00; // was 0x00 + //MCG->ATCVL = 0x00; // was 0x00 + //MCG->C7 = 0x00; // was 0x00 + //MCG->C8 = 0x80; // was 0x80 + //MCG->C9 = 0x00; // was 0x00 + //MCG->C10 = 0x00; // was 0x00 + + //sirq_printf("MGC - C1 %02hx\r\n", MCG->C1); // 1A + //sirq_printf("MGC - C2 %02hx\r\n", MCG->C2); // 24 + //sirq_printf("MGC - C3 %02hx\r\n", MCG->C3); // 91 + //sirq_printf("MGC - C4 %02hx\r\n", MCG->C4); // 10 + //sirq_printf("MGC - C5 %02hx\r\n", MCG->C5); // 01 + //sirq_printf("MGC - C6 %02hx\r\n", MCG->C6); // 40 + //sirq_printf("MGC - S %02hx\r\n", MCG->S); // 6E + //sirq_printf("MGC - SC %02hx\r\n", MCG->SC); // 02 + //sirq_printf("MGC - ATCVH %02hx\r\n", MCG->ATCVH); // 00 + //sirq_printf("MGC - ATCVL %02hx\r\n", MCG->ATCVL); // 00 + //sirq_printf("MGC - C7 %02hx\r\n", MCG->C7); // 00 + //sirq_printf("MGC - C8 %02hx\r\n", MCG->C8); // 80 + //sirq_printf("MGC - C9 %02hx\r\n", MCG->C9); // 00 + //sirq_printf("MGC - C10 %02hx\r\n", MCG->C10); // 00 + // Run background loop printf("hello"); while (true) diff --git a/hw2/serial_irq.c b/hw2/serial_irq.c index 67beeab..68945cf 100644 --- a/hw2/serial_irq.c +++ b/hw2/serial_irq.c @@ -4,6 +4,7 @@ #include #include "serial_api.h" #include "serial_irq.h" +#include "timer_dma.h" /* Defines */ #define SIRQ_LEN 1024 @@ -21,6 +22,14 @@ struct sirq_t { queue_t rcv; }; +/* Test data */ +extern uint32_t test_xmt_enab; +extern uint64_t test_xmt_time0; +extern uint64_t test_xmt_time1; + +extern uint32_t test_rcv_enab; +extern uint64_t test_rcv_time; + /* Port data */ static sirq_t sirq_ports[SIRQ_NUM_UART]; @@ -32,7 +41,17 @@ void sirq_handler(uint32_t _port, SerialIrq event) // Handle transmit if (event == TxIrq && port->xmt.rix != port->xmt.wix) { int byte = port->xmt.buf[port->xmt.rix]; + + uint64_t time0 = tdma_time(); serial_putc(&port->uart, byte); + uint64_t time1 = tdma_time(); + + if (test_xmt_enab) { + test_xmt_time0 = time0; + test_xmt_time1 = time1; + test_xmt_enab = 0; + } + port->xmt.rix = (port->xmt.rix+1) % SIRQ_LEN; } else { serial_irq_set(&port->uart, TxIrq, 0); @@ -75,7 +94,7 @@ void sirq_putc(sirq_t *port, int byte) int sirq_getc(sirq_t *port) { int byte = 0; - if (port->rcv.rix < port->rcv.wix) { + if (port->rcv.rix != port->rcv.wix) { byte = port->rcv.buf[port->rcv.rix]; port->rcv.rix = (port->rcv.rix+1) % SIRQ_LEN; } @@ -93,7 +112,29 @@ void sirq_write(sirq_t *port, void *data, int len) /* Check if port is writable */ int sirq_ready(sirq_t *port) { - return port->rcv.rix < port->rcv.wix; + return port->rcv.rix != port->rcv.wix; +} + +/* Debug print */ +void sirq_debug(sirq_t *port) +{ + sirq_printf("xmt - wix:%03x rix:%03x\r\n", port->xmt.wix, port->xmt.rix); + sirq_printf("rcv - wix:%03x rix:%03x\r\n", port->rcv.wix, port->rcv.rix); + sirq_printf("irq - ??\r\n"); + sirq_printf("uart - ??\r\n"); + + // __IO uint8_t BDH; + // __IO uint8_t BDL; + // __IO uint8_t C1; + // __IO uint8_t C2; + // __IO uint8_t S1; + // __IO uint8_t S2; + // __IO uint8_t C3; + // __IO uint8_t D; + // __IO uint8_t MA1; + // __IO uint8_t MA2; + // __IO uint8_t C4; + // __IO uint8_t C5; } /* Write ASCII data to the output queue */ diff --git a/hw2/serial_irq.h b/hw2/serial_irq.h index 5595d14..e640a9e 100644 --- a/hw2/serial_irq.h +++ b/hw2/serial_irq.h @@ -33,6 +33,9 @@ void sirq_write(sirq_t *port, void *data, int len); /* Read In */ int sirq_ready(sirq_t *port); +/* Debug print */ +void sirq_debug(sirq_t *port); + /* Print */ void sirq_vprintf(const char *fmt, va_list ap); void sirq_printf(const char *fmt, ...); diff --git a/hw2/test.cpp b/hw2/test.cpp index 3cfb701..5f95a85 100644 --- a/hw2/test.cpp +++ b/hw2/test.cpp @@ -296,10 +296,10 @@ void test_tdma_run(void) tdma_stamp(tdma2, (uint64_t*)&time2); tdma_stamp(tdma3, (uint64_t*)&time3); - tdma_reset(tdma0); - tdma_reset(tdma1); - tdma_reset(tdma2); - tdma_reset(tdma3); + tdma_start(tdma0); + tdma_start(tdma1); + tdma_start(tdma2); + tdma_start(tdma3); printf(" - timer:"); printf(" %08lx:%08lx", time0[1], time0[0]); diff --git a/hw2/timer_dma.c b/hw2/timer_dma.c index 2e19718..529fd7e 100644 --- a/hw2/timer_dma.c +++ b/hw2/timer_dma.c @@ -6,6 +6,7 @@ #include #include "timer_dma.h" +#include "serial_irq.h" /* Defines */ enum { @@ -36,6 +37,10 @@ struct tdma_t { /* Time stamping */ uint32_t time[2]; + + /* Save state */ + int req; + int irqc; }; /* Port data */ @@ -77,7 +82,7 @@ tdma_t *tdma_open(tdma_chan_t chan, int alt, PinName pin, PinMode mode) pin >= PTC0 ? TDMA_REQ_PTC : pin >= PTA0 ? TDMA_REQ_PTA : 0; - int ircq = mode == PullUp ? 2 : 1; + int irqc = mode == PullUp ? 1 : 2; // Allocate port tdma_t *port = &tdma_ports[chan]; @@ -104,24 +109,30 @@ tdma_t *tdma_open(tdma_chan_t chan, int alt, PinName pin, PinMode mode) // Set pin to generate DMA req port->pin->pcr = PORT_PCR_ISF_MASK // Clear ISR flag | PORT_PCR_MUX(alt) // Pin mapping - | PORT_PCR_IRQC(ircq) // DMA on falling edge + | PORT_PCR_IRQC(irqc) // DMA on falling edge | mode; // Pin pull up/down - // Initial reset - tdma_reset(port); + // Save IRC for later + port->req = req; + port->irqc = irqc; return port; } -void tdma_reset(tdma_t *port) +void tdma_start(tdma_t *port) { if (!port) return; + //sirq_printf("isfr2: %08x\r\n", PORTD->ISFR); + // Clear previous time port->time[0] = 0; port->time[1] = 0; + // Reset DMA Mux + port->mux->cfg &= DMAMUX_CHCFG_ENBL_MASK; + // Freeze DMA channel port->dma->dcr &= ~DMA_DCR_ERQ_MASK; @@ -133,8 +144,41 @@ void tdma_reset(tdma_t *port) port->dma->dar = (uint32_t)&port->time; // Temp timer buffer port->dma->dsr = DMA_DSR_BCR_BCR(8); // 64-bit timer + // Set pin to generate DMA req + port->pin->pcr |= PORT_PCR_ISF_MASK; + port->pin->pcr |= PORT_PCR_IRQC(port->irqc); + // Enable port request port->dma->dcr |= DMA_DCR_ERQ_MASK; + + // Enable DMA Mux + port->mux->cfg = DMAMUX_CHCFG_SOURCE(port->req) + | DMAMUX_CHCFG_ENBL_MASK; + + //sirq_printf("isfr3: %08x\r\n", PORTD->ISFR); +} + +void tdma_stop(tdma_t *port) +{ + if (!port) + return; + + //sirq_printf("isfr0: %08x\r\n", PORTD->ISFR); + + // Disable DMA Mux + port->mux->cfg &= DMAMUX_CHCFG_ENBL_MASK; + + // Freeze DMA channel + port->dma->dcr &= ~DMA_DCR_ERQ_MASK; + + // Reset DMA channel + port->dma->dsr = DMA_DSR_BCR_DONE_MASK; + + // Disable pin DMA request + port->pin->pcr &= ~PORT_PCR_IRQC_MASK; + port->pin->pcr |= PORT_PCR_ISF_MASK; + + //sirq_printf("isfr1: %08x\r\n", PORTD->ISFR); } int tdma_stamp(tdma_t *port, uint64_t *time) diff --git a/hw2/timer_dma.h b/hw2/timer_dma.h index c6d2763..e35af73 100644 --- a/hw2/timer_dma.h +++ b/hw2/timer_dma.h @@ -30,7 +30,8 @@ void tdma_init(void); tdma_t *tdma_open(tdma_chan_t chan, int alt, PinName pin, PinMode mode); /* Flush/Wait */ -void tdma_reset(tdma_t *port); +void tdma_start(tdma_t *port); +void tdma_stop(tdma_t *port); int tdma_stamp(tdma_t *port, uint64_t *time); /* Time */