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