]> Pileus Git - ~andy/csm213a-hw/blob - hw2/main.cpp
47b701b4f2d2c269711032a59e082f3222b4783b
[~andy/csm213a-hw] / hw2 / main.cpp
1 #include "messages.h"
2
3 #include "mbed.h"
4 #include "serial_irq.h"
5 #include "serial_dma.h"
6 #include "timer_dma.h"
7
8 /**
9  * Mode of operation:
10  *   Devices 1 and 2 synchronize clocks using serial messages.
11  *
12  *   1. Each serial message timestamped using the hardware timer capture
13  *      registers in both the sender and receiver.
14  *   2. The sender transmits the send timestamp during the next time-sync
15  *      message.
16  *   3. The receiver then compares the senders timestamp with it's own
17  *      timestamp for the corresponding messages and calculates an offset.
18  *   4. The offset is used to compensate the receivers local clock.
19  *
20  *   Time synchronization is performed in both directions.
21  */
22
23 /*******************
24  * Timer functions *
25  *******************/
26
27 #define NSEC_PER_SEC 1000000000ULL
28
29 uint64_t time_last_local; // timestamp at last time sync
30 uint64_t time_last_world; // offset at last time sync
31
32 /**
33  * Generate time stamp for an async event:
34  *   time:  drift compensated wall-clock time
35  *   stamp: event timestamp from PIT Module
36  */
37 uint64_t time_to_world(uint64_t local)
38 {
39         uint64_t elapsed = local - time_last_local;
40         return time_last_world + elapsed;
41 }
42
43 /**
44  * Synchronize the timer internal state with updates
45  * from an external time sync message.
46  *   local: our internal timestamp for the event
47  *   world: reference timestamp from the other device
48  */
49 void time_ext_init(uint64_t local, uint64_t world)
50 {
51         sirq_printf("initialize clocks: %d -> %d\r\n",
52                         (int)(local/NSEC_PER_SEC),
53                         (int)(world/NSEC_PER_SEC));
54
55         time_last_local = local;
56         time_last_world = world;
57 }
58
59 /**
60  * Synchronize the timer internal state with updates
61  * from an external time sync message.
62  *   local: our internal timestamp for the event
63  *   world: reference timestamp from the other device
64  */
65 void time_ext_sync(uint64_t local, uint64_t world)
66 {
67         uint64_t guess = time_to_world(local);
68
69         time_last_local = local;
70         time_last_world = (guess/2) + (world/2);
71         //time_last_world = (guess * 3 / 4) + (world * 1 / 4);
72         //time_last_world =
73         //      (guess - (        guess / 2)) +
74         //      (world - (world - world / 2));
75         //time_last_world =
76         //      (guess - (guess - guess / 4)) +
77         //      (world - (        world / 4));
78
79         world = time_last_world;
80
81 //#ifdef VERBOSE
82 #if 1
83         uint64_t error = world > guess ? world - guess :
84                          guess > world ? guess - world : 0;
85         int      ahead = guess > world;
86         sirq_printf("syncing clocks: %6d=%d.%04u -> %d.%04u (err: %s%ld.%09lu)\r\n",
87                         (int)((local / NSEC_PER_SEC)),
88                         (int)((guess / NSEC_PER_SEC)),
89                         (int)((guess % NSEC_PER_SEC)/(NSEC_PER_SEC/10000)),
90                         (int)((world / NSEC_PER_SEC)),
91                         (int)((world % NSEC_PER_SEC)/(NSEC_PER_SEC/10000)),
92                         ahead ? "-" : " ",
93                         (int32_t )(error / (int64_t)NSEC_PER_SEC),
94                         (uint32_t)(error % (int64_t)NSEC_PER_SEC));
95 #endif
96 //#endif
97 }
98
99 void time_printf(const char *label, uint64_t local)
100 {
101         uint64_t world = time_to_world(local);
102         sirq_printf("%s -- %d.%09u -> %d.%09u\r\n",
103                         label,
104                         (int)(local / NSEC_PER_SEC),
105                         (int)(local % NSEC_PER_SEC),
106                         (int)(world / NSEC_PER_SEC),
107                         (int)(world % NSEC_PER_SEC));
108 }
109
110 /*********************
111  * Signal generation *
112  *********************/
113
114 // for 24 Mhz clock, 24/1000 = 3/125
115 // for 48 Mhz clock  48/1000 = 6/125
116 // for 50 Mhz clock  50/1000 = 1/20  (FLL/2)
117 #define EMIT_CLOCKS(nsec) ((uint16_t)((nsec)   / 20))
118 #define EMIT_NSEC(clocks) ((uint16_t)((clocks) * 20))
119
120 static uint32_t *emit_pcr    = 0; // transmit pin name
121
122 static uint64_t  emit_start  = 0; // transmit start time (world time)
123 static uint64_t  emit_period = 0; // transmit period
124 static uint64_t  emit_due    = 0; // next transmit (world time)
125
126 static uint32_t  emit_slack  = 0; // how far ahead we need to schedule, in us
127 static uint32_t  emit_worst  = 0; // worst-case latency in task table
128
129 void emit_init(int alt, PinName pin, PinMode mode)
130 {
131         // Find pin
132         emit_pcr = (uint32_t*)(PORTA_BASE + pin);
133
134         // Enable clocks
135         SIM->SCGC6            |= SIM_SCGC6_TPM1_MASK;
136         SIM->SOPT2            |= SIM_SOPT2_TPMSRC(1);
137
138         // Debug print on SOPT2
139         // -- mbed may set PLLFLL when configuring UART0
140         sirq_printf("SOPT2: u0src=%d tpmsrc=%d %s %s clkos=%d %s\r\n",
141                 (SIM->SOPT2 & SIM_SOPT2_UART0SRC_MASK)     >> SIM_SOPT2_UART0SRC_SHIFT,
142                 (SIM->SOPT2 & SIM_SOPT2_TPMSRC_MASK)       >> SIM_SOPT2_TPMSRC_SHIFT,
143                 (SIM->SOPT2 & SIM_SOPT2_UART0SRC_MASK)     ? "USBSRC" : "usbsrc",
144                 (SIM->SOPT2 & SIM_SOPT2_PLLFLLSEL_MASK)    ? "PLL/2"  : "FLL",
145                 (SIM->SOPT2 & SIM_SOPT2_CLKOUTSEL_MASK)    >> SIM_SOPT2_CLKOUTSEL_SHIFT,
146                 (SIM->SOPT2 & SIM_SOPT2_RTCCLKOUTSEL_MASK) ? "RTCOS"  : "rtcos");
147
148         // Set pin mode
149         emit_pcr[0]            = PORT_PCR_ISF_MASK
150                                | PORT_PCR_MUX(alt)
151                                | mode;
152
153         // Setup Timer/PWM Module
154         TPM1->SC               = TPM_SC_TOF_MASK;
155         TPM1->CNT              = TPM_CNT_COUNT(0);
156         TPM1->MOD              = TPM_MOD_MOD(0xFFFF);
157
158         TPM1->CONTROLS[0].CnSC = TPM_CnSC_CHF_MASK    // clear flag
159                                | TPM_CnSC_MSB_MASK    // set output highon match,
160                                | TPM_CnSC_ELSB_MASK   // cleared on overflow
161                                | TPM_CnSC_ELSA_MASK;  // ..
162
163         TPM1->STATUS           = TPM_STATUS_CH0F_MASK
164                                | TPM_STATUS_TOF_MASK;
165
166         TPM1->CONF             = TPM_CONF_CSOO_MASK;
167 }
168
169 void emit_enable(uint64_t start, uint64_t period)
170 {
171         const int slack_clocks = 0x8000; // tune based on emit_worst
172
173         emit_start  = start;
174         emit_period = period;
175         emit_due    = start + period;
176
177         // TODO - tune slack time
178         // TODO - check clock power
179         // TODO - TPM clock source
180         emit_slack  = EMIT_NSEC(slack_clocks);
181
182         time_printf("emit scheduled", emit_due);
183 }
184
185 void emit_schedule(uint64_t when)
186 {
187         uint64_t now    = time_to_world(tdma_time());
188         uint64_t start  = when - now;     // transmit time
189         uint64_t stop   = start + 100000; // 100 us pulse
190
191         // Disable timer
192         TPM1->SC               = TPM_SC_TOF_MASK;
193
194         // Set transmit time
195         TPM1->CONTROLS[0].CnV  = EMIT_CLOCKS(start);
196         TPM1->MOD              = TPM_MOD_MOD(EMIT_CLOCKS(stop));
197
198         // Start the timer
199         TPM1->SC               = TPM_SC_TOF_MASK
200                                | TPM_SC_PS(0)
201                                | TPM_SC_CMOD(1);
202
203         // Clock testing
204         uint32_t test_tpm0 = TPM1->SC;
205         uint32_t test_pit0 = PIT->CHANNEL[1].CVAL;
206         for (int i = 0; i < 1000; i++)
207                 asm("nop");
208         uint32_t test_tpm1 = TPM1->SC;
209         uint32_t test_pit1 = PIT->CHANNEL[1].CVAL;
210         uint32_t test_tpm  = test_tpm0 - test_tpm0;
211         uint32_t test_pit  = test_pit1 - test_pit0;
212         sirq_printf("pit/tpm: tpm=%04hx/%04hx=%d pit=%08x/%08x=%d\r\n",
213                         test_tpm0, test_tpm1, test_tpm,
214                         test_pit0, test_pit1, test_pit);
215
216         // Debug output
217         //sirq_printf("emitting event\r\n");
218 }
219
220 void emit_transmit(uint64_t local, uint64_t world)
221 {
222         static uint64_t prev = 0;
223
224         // Record how how much time we have to reschedule
225         if (prev && (local-prev) > emit_worst)
226                 emit_worst = (local-prev);
227         prev = local;
228
229         // Schedule task if needed
230         if (emit_due && emit_period &&
231             world+emit_slack > emit_due) {
232                 emit_schedule(emit_due);
233                 emit_due += emit_period;
234         }
235 }
236
237 /************************
238  * Serial I/O functions *
239  ************************/
240
241 typedef struct {
242         int      index;
243         int      state;
244         uint8_t  buffer[256];
245 } parser_t;
246
247 static uint32_t serial_device_id   = 0;
248
249 const  uint64_t serial_sync_delay  = NSEC_PER_SEC / 100;
250 static uint64_t serial_sync_due    = 0;
251
252 static tdma_t  *serial_tdma_rcv    = NULL;
253 static tdma_t  *serial_tdma_xmt    = NULL;
254
255 /**
256  * Convert world to local time
257  */
258 uint64_t serial_read_time(ntime_t time)
259 {
260         return ((uint64_t)time.seconds) * NSEC_PER_SEC
261              + ((uint64_t)time.nanosec);
262 }
263
264 ntime_t serial_write_time(uint64_t time)
265 {
266         ntime_t buf = {};
267         buf.seconds = time / NSEC_PER_SEC;
268         buf.nanosec = time % NSEC_PER_SEC;
269         return buf;
270 }
271
272 int serial_time_stamp(tdma_t *port, uint64_t *local, uint64_t *world,
273                 const char *msg)
274 {
275         int valid = tdma_stamp(port, local);
276         *world = time_to_world(*local);
277
278         if (!valid)
279                 sirq_printf("%s -- missing\r\n", msg);
280         //else
281         //      time_printf(msg, current);
282
283         return valid;
284 }
285
286 /**
287  * Output initialization message init message
288  */
289 void serial_send_init(uint16_t device, uint64_t local)
290 {
291 }
292
293 /**
294  * Output time sync message
295  */
296 void serial_send_sync(sirq_t *port, uint64_t now)
297 {
298         if (serial_sync_due == 0 || now < serial_sync_due)
299                 return; // not ready
300
301         // Message data
302         header_t   head;
303         sync_msg_t body;
304
305         // Write header
306         head.header = MSG_HEADER;
307         head.msgid  = MSG_ID_SYNC;
308         head.length = sizeof(body);
309         head.cksum  = 0; // todo
310
311         tdma_stop(serial_tdma_rcv, 0);
312         tdma_start(serial_tdma_xmt);
313
314         sirq_write(port, &head, sizeof(head));
315
316         tdma_stop(serial_tdma_xmt, 100);
317         tdma_start(serial_tdma_rcv);
318
319         // Save transmit time
320         uint64_t local = 0, world = 0;
321         serial_time_stamp(serial_tdma_xmt, &local, &world,
322                         "sync time transmit");
323
324         // Debug output
325         //sirq_printf("sync time transmit\r\n");
326         //time_printf("  local", local);
327         //time_printf("  world", world);
328
329         // Write body with updated time and send
330         body.time = serial_write_time(world);
331
332         sirq_write(port, &body, sizeof(body));
333
334         // Queue next transmit time
335         serial_sync_due  = 0;
336 }
337
338 /**
339  * Output external event received message
340  *   event: id of the received event
341  *   time:  compensated timestamp of the event
342  */
343 void serial_send_event(sirq_t *port, uint16_t event, uint64_t local)
344 {
345         time_printf("event received", local);
346
347         // Convert timestamp
348         uint64_t world = time_to_world(local);
349         ntime_t  ltime = serial_write_time(local);
350         ntime_t  wtime = serial_write_time(world);
351
352         // Message data
353         header_t    head = {};
354         event_msg_t body = {};
355
356         // Transmit sync message
357         head.header = MSG_HEADER;
358         head.msgid  = MSG_ID_EVENT;
359         head.length = sizeof(body);
360         head.cksum  = 0; // todo
361
362         body.device = serial_device_id;
363         body.event  = event;
364         body.world  = wtime;
365         body.local  = ltime;
366
367         // Transmit message to BBB
368         sirq_write(port, &head, sizeof(head));
369         sirq_write(port, &body, sizeof(body));
370 }
371
372 /**
373  * Handle init message
374  */
375 void serial_handle_init(init_msg_t *msg)
376 {
377         sirq_printf("initialize: %s %s %s %s %s\r\n",
378                 msg->valid & MSG_VALID_DEVICE ? "DEV"    : "dev",
379                 msg->valid & MSG_VALID_START  ? "START"  : "start",
380                 msg->valid & MSG_VALID_PERIOD ? "PERIOD" : "period",
381                 msg->valid & MSG_VALID_WORLD  ? "WORLD"  : "world",
382                 msg->valid & MSG_VALID_SYNC   ? "SYNC"   : "sync");
383         sirq_printf("  dev    -- %d\r\n", msg->device);
384         time_printf("  start ", serial_read_time(msg->start));
385         time_printf("  period", serial_read_time(msg->period));
386         time_printf("  world ", serial_read_time(msg->world));
387
388         if (msg->valid & MSG_VALID_DEVICE)
389                 serial_device_id = msg->device;
390
391         if (msg->valid & MSG_VALID_START ||
392             msg->valid & MSG_VALID_PERIOD) {
393                 uint64_t start  = serial_read_time(msg->start);
394                 uint64_t period = serial_read_time(msg->period);
395                 emit_enable(start, period);
396         }
397
398         if (msg->valid & MSG_VALID_WORLD) {
399                 uint64_t world = serial_read_time(msg->world);
400                 uint64_t local = tdma_time();
401                 time_ext_init(local, world);
402         }
403
404         if (msg->valid & MSG_VALID_SYNC)
405                 serial_sync_due = tdma_time() + serial_sync_delay;
406 }
407
408 /**
409  * Handle sync message
410  */
411 void serial_handle_sync(sync_msg_t *msg)
412 {
413         // Read receive timestamp
414         uint64_t local = 0, world = 0;
415         serial_time_stamp(serial_tdma_rcv, &local, &world,
416                         "sync time receive ");
417         tdma_stop(serial_tdma_rcv, 0);
418
419         // Lookup reference time from message
420         uint64_t reference = serial_read_time(msg->time);
421
422         // Debug output
423         //sirq_printf("sync time receive\r\n");
424         //time_printf("  local", local);
425         //time_printf("  world", world);
426         //time_printf("  ref  ", reference);
427
428         // Synchronize the clocks
429         time_ext_sync(local, reference);
430
431         // Queue transmit to other board
432         serial_sync_due   = tdma_time() + serial_sync_delay;
433 }
434
435 /**
436  * Handle event message
437  */
438 void serial_handle_event(event_msg_t *msg)
439 {
440 }
441
442 /**
443  * Deliver message
444  */
445 void serial_deliver(int msgid, void *body)
446 {
447         switch (msgid) {
448                 case MSG_ID_INIT:
449                         //sirq_printf("received init msg\r\n");
450                         serial_handle_init((init_msg_t*)body);
451                         break;
452                 case MSG_ID_SYNC:
453                         //sirq_printf("received sync msg\r\n");
454                         serial_handle_sync((sync_msg_t*)body);
455                         break;
456                 case MSG_ID_EVENT:
457                         //sirq_printf("received event msg\r\n");
458                         serial_handle_event((event_msg_t*)body);
459                         break;
460         }
461 }
462
463 /**
464  * Process serial receive messages
465  */
466 void serial_receive(parser_t *parser, int byte)
467 {
468         //sirq_printf("serial_receive - %02x\r\n", byte);
469
470         // Lookup pointers
471         header_t *head = (header_t*)parser->buffer;
472         void     *body = (void*)(head+1);
473         const int max_length = sizeof(parser->buffer)-sizeof(header_t);
474
475         // Process uart messages
476         parser->buffer[parser->index++] = byte;
477         switch (parser->state) {
478                 case 0: // Search
479                         if (parser->index == sizeof(uint16_t)) {
480                                 if (head->header == MSG_HEADER) {
481                                         parser->state = 1;
482                                 } else {
483                                         parser->buffer[0] = parser->buffer[1];
484                                         parser->index = 1;
485                                 }
486                         }
487                         break;
488                 case 1: // Header
489                         if (parser->index == sizeof(header_t)) {
490                                 if (head->length <= max_length &&
491                                     head->msgid  <= MSG_MAX_ID) {
492                                         parser->state = 2;
493                                 } else {
494                                         parser->index = 0;
495                                         parser->state = 0;
496                                 }
497                         }
498                         break;
499                 case 2: // Data
500                         if (parser->index == (int)sizeof(header_t)+head->length) {
501                                 serial_deliver(head->msgid, body);
502                                 parser->index = 0;
503                                 parser->state = 0;
504                         }
505                         break;
506         }
507 }
508
509 /********************
510  * Data definitions *
511  ********************/
512
513 // LEDs
514 DigitalOut led1(LED1);
515 DigitalOut led2(LED2);
516
517 // Message Parsers
518 parser_t   parser_dbg;
519 parser_t   parser_bbb;
520 parser_t   parser_mbed;
521
522 // Serial IRQ
523 sirq_t    *sirq_dbg;
524 sirq_t    *sirq_bbb;
525 sirq_t    *sirq_mbed;
526
527 // Timer DMA
528 tdma_t    *tdma_evt;
529 tdma_t    *tdma_rcv;
530 tdma_t    *tdma_xmt;
531
532 /*********
533  * Tasks *
534  *********/
535
536 void task_serial(uint64_t local, uint64_t world)
537 {
538         while (sirq_ready(sirq_dbg)) {
539                 //sirq_printf("serial recv - dbg\r\n");
540                 serial_receive(&parser_dbg,  sirq_getc(sirq_dbg));
541         }
542
543         while (sirq_ready(sirq_bbb)) {
544                 //sirq_printf("serial recv - bbb\r\n");
545                 serial_receive(&parser_bbb,  sirq_getc(sirq_bbb));
546         }
547
548         while (sirq_ready(sirq_mbed)) {
549                 //sirq_printf("serial recv - mbed\r\n");
550                 serial_receive(&parser_mbed, sirq_getc(sirq_mbed));
551         }
552 }
553
554 void task_events(uint64_t local, uint64_t world)
555 {
556         uint64_t event = 0;
557
558 #ifdef VERBOSE
559         if (tdma_stamp(tdma_evt, &event)) {
560                 sirq_printf("event received - evt\r\n");
561         if (tdma_stamp(tdma_rcv, &event))
562                 sirq_printf("event received - rcv\r\n");
563         if (tdma_stamp(tdma_xmt, &event))
564                 sirq_printf("event received - xmt\r\n");
565 #endif
566
567         if (tdma_stamp(tdma_evt, &event))
568                 serial_send_event(sirq_bbb, 0, event);
569         tdma_stop(tdma_evt, 0);
570         tdma_start(tdma_evt);
571 }
572
573 void task_sync(uint64_t local, uint64_t world)
574 {
575         serial_send_sync(sirq_mbed, local);
576 }
577
578 void task_leds(uint64_t local, uint64_t world)
579 {
580         static uint32_t which = 0;
581         led1 = (which == 0);
582         led2 = (which == 1);
583         which ^= 1;
584 }
585
586 void task_emit(uint64_t local, uint64_t world)
587 {
588         emit_transmit(local, world);
589 }
590
591 void task_debug(uint64_t local, uint64_t world)
592 {
593         //tdma_debug(tdma_rcv);
594         //tdma_debug(tdma_xmt);
595
596         //sirq_debug(sirq_mbed);
597
598         serial_send_event(sirq_bbb, 1, local);
599
600 #ifdef VERBOSE
601         sirq_printf("background - %6u.%02u -> %u.%02u\r\n",
602                         (uint32_t)(local / NSEC_PER_SEC),
603                         (uint32_t)(local % NSEC_PER_SEC / 10000000),
604                         (uint32_t)(world / NSEC_PER_SEC),
605                         (uint32_t)(world % NSEC_PER_SEC / 10000000));
606 #endif
607 }
608
609 /********
610  * Main *
611  ********/
612
613 #define N_ELEM(x) (sizeof(x) / sizeof((x)[0]))
614
615 extern void test_main(void);
616 extern serial_t stdio_uart;
617
618 static struct {
619         void (*task)(uint64_t, uint64_t);
620         uint64_t period;
621         uint64_t due;
622 } tasks[] = {
623         { task_serial, 0          }, // always
624         { task_events, 0          }, // always -- testing
625         { task_sync,   0          }, // always
626         { task_emit,   0          }, // always
627         { task_leds,   100000000  }, // 10hz
628         { task_debug,  1000000000 }, // 1hz
629 };
630
631 void background(void)
632 {
633         // Debugging
634         uint64_t local = tdma_time();
635         uint64_t world = time_to_world(local);
636
637         // Run the scheduler
638         for (unsigned i = 0; i < N_ELEM(tasks); i++) {
639                 if (local >= tasks[i].due) {
640                         tasks[i].task(local, world);
641                         tasks[i].due += tasks[i].period;
642                 }
643         }
644 }
645
646 int main(int argc, char **argv)
647 {
648         tdma_init();
649         emit_init(3, PTE20, PullDown);
650
651         //pin = 1;
652
653         // Open serial ports
654         sirq_dbg   = sirq_open(SIRQ_UART0, USBTX, USBRX, 115200); // to pc
655         sirq_bbb   = sirq_open(SIRQ_UART1, PTE0,  PTE1,  115200); // to bbb
656         sirq_mbed  = sirq_open(SIRQ_UART2, PTD3,  PTD2,  115200); // to mbed
657
658         // Setup timers
659         tdma_evt   = tdma_open(TDMA_CHAN0, 3, PTC9,  PullDown); // async event
660
661         // mbed time sync
662         tdma_rcv   = tdma_open(TDMA_CHAN2, 3, PTD2,  PullUp);   // time sync rcv
663         tdma_xmt   = tdma_open(TDMA_CHAN3, 3, PTD3,  PullUp);   // time sync xmt
664
665         // host time sync
666         //tdma_rcv   = tdma_open(TDMA_CHAN2, 2, USBRX, PullUp); // time sync rcv
667         //tdma_xmt   = tdma_open(TDMA_CHAN3, 2, USBTX, PullUp); // time sync xmt
668
669         // start timers
670         tdma_start(tdma_evt);
671         tdma_start(tdma_rcv);
672         tdma_start(tdma_xmt);
673
674         // Serial timestamping
675         serial_tdma_rcv = tdma_rcv;
676         serial_tdma_xmt = tdma_xmt;
677
678         // configure crystal oscilator for high gain operation
679         MCG->C2 |= MCG_C2_HGO0_MASK;
680
681         // Test clocks
682         //MCG->C1    = 0x05; // was 0x1A
683         //MCG->C2    = 0x2C; // was 0x24
684         //MCG->C3    = 0x91; // was 0x91
685         //MCG->C4    = 0x10; // was 0x10
686         //MCG->C5    = 0x01; // was 0x01
687         //MCG->C6    = 0x40; // was 0x40
688         //MCG->S     = 0x6E; // was 0x6E
689         //MCG->SC    = 0x02; // was 0x02
690         //MCG->ATCVH = 0x00; // was 0x00
691         //MCG->ATCVL = 0x00; // was 0x00
692         //MCG->C7    = 0x00; // was 0x00
693         //MCG->C8    = 0x80; // was 0x80
694         //MCG->C9    = 0x00; // was 0x00
695         //MCG->C10   = 0x00; // was 0x00
696
697         //sirq_printf("MGC - C1    %02hx\r\n", MCG->C1);     // 1A
698         //sirq_printf("MGC - C2    %02hx\r\n", MCG->C2);     // 24
699         //sirq_printf("MGC - C3    %02hx\r\n", MCG->C3);     // 91
700         //sirq_printf("MGC - C4    %02hx\r\n", MCG->C4);     // 10
701         //sirq_printf("MGC - C5    %02hx\r\n", MCG->C5);     // 01
702         //sirq_printf("MGC - C6    %02hx\r\n", MCG->C6);     // 40
703         //sirq_printf("MGC - S     %02hx\r\n", MCG->S);      // 6E
704         //sirq_printf("MGC - SC    %02hx\r\n", MCG->SC);     // 02
705         //sirq_printf("MGC - ATCVH %02hx\r\n", MCG->ATCVH);  // 00
706         //sirq_printf("MGC - ATCVL %02hx\r\n", MCG->ATCVL);  // 00
707         //sirq_printf("MGC - C7    %02hx\r\n", MCG->C7);     // 00
708         //sirq_printf("MGC - C8    %02hx\r\n", MCG->C8);     // 80
709         //sirq_printf("MGC - C9    %02hx\r\n", MCG->C9);     // 00
710         //sirq_printf("MGC - C10   %02hx\r\n", MCG->C10);    // 00
711
712         // Run background loop
713         while (true)
714                 background();
715
716         // Performance testing
717         //uint64_t prev = 0, due = 0;
718         //uint64_t worst[10] = {};
719         //int      count = 0;
720         //while (true) {
721         //      uint64_t local = tdma_time();
722         //      if (prev && (local-prev) > worst[count])
723         //              worst[count] = (local-prev);
724         //      prev = local;
725         //      if (local > due) {
726         //              if (count == 5) {
727         //                      static char str[] = "background background background\r\n";
728         //                      sirq_write(sirq_dbg, str, sizeof(str));
729         //              }
730         //              if (count == 9) {
731         //                      sirq_printf("background\r\n");
732         //                      for (int i = 0; i < 10; i++) {
733         //                              sirq_printf("  worst[%d] = 0.%09u\r\n",
734         //                                              i, worst[i]);
735         //                              worst[i] = 0;
736         //                      }
737         //              }
738         //              due += NSEC_PER_SEC;
739         //              count = (count + 1) % 10;
740         //      }
741         //}
742
743         // Run tests
744         //test_main();
745
746         return 0;
747 }