]> Pileus Git - ~andy/csm213a-hw/commitdiff
Work on second mbed
authorAndy Spencer <andy753421@gmail.com>
Mon, 10 Mar 2014 00:59:02 +0000 (00:59 +0000)
committerAndy Spencer <andy753421@gmail.com>
Mon, 10 Mar 2014 01:02:20 +0000 (01:02 +0000)
Add control program file:
  - Can be used to send a time initialization message to the mbed

Add install program:
  - Install programs on both mbeds and initialize the time on one

Add IRQ driven serial interface:
  - Since we don't have spare DMA controllers available for this
    homework we need to transmit serial data some other way.

  - The IRQ code allows us to queue up large messages to be transmitted
    asynchronous to main background loop. It should also help with
    receiving data at a high rate.

Add task table to main:
  - This lets us schedule tasks at fixed intervals.

Fix various bugs:
  - Timer dma code reset avoid config errors cause by periodical request
    while the DMA controller has nothing to transmit.

.gitignore
common.mk
hw2/control.c [new file with mode: 0644]
hw2/install.sh [new file with mode: 0755]
hw2/main.cpp
hw2/makefile
hw2/messages.h [new file with mode: 0644]
hw2/serial_irq.c [new file with mode: 0644]
hw2/serial_irq.h [new file with mode: 0644]
hw2/timer_dma.c
hw2/timer_dma.h

index 1f72ef646b3872051973e96c8353bd894642b979..d42653c08af37bcffe14c7e41619489c2add5398 100644 (file)
@@ -11,3 +11,4 @@ __pycache__
 xively
 config.mk
 settings.cfg
+control
index 67986509634745ceb9d7303de16a190ec4655bba..a0f65a8959b1c5606dbd6303169c391d49a7ccb1 100644 (file)
--- a/common.mk
+++ b/common.mk
@@ -55,15 +55,15 @@ clean:
        @rm -f $(PROG).bin $(PROG).elf $(OBJS)
 
 # Rules
-%.o: %.c makefile ../common.mk ../config.mk
+%.o: %.c $(wildcard *.h) makefile ../common.mk ../config.mk
        @echo "CC   $<"
        @$(GCC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
 
-%.o: %.cc makefile ../common.mk ../config.mk
+%.o: %.cc $(wildcard *.h) makefile ../common.mk ../config.mk
        @echo "CXX  $<"
        @$(GXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
 
-%.o: %.cpp makefile ../common.mk ../config.mk
+%.o: %.cpp $(wildcard *.h) makefile ../common.mk ../config.mk
        @echo "CXX  $<"
        @$(GXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
 
diff --git a/hw2/control.c b/hw2/control.c
new file mode 100644 (file)
index 0000000..fa54a97
--- /dev/null
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <arpa/inet.h>
+
+#include <time.h>
+
+#include "messages.h"
+
+void error(char *msg)
+{
+       printf("Error: %s\n", msg);
+       exit(0);
+}
+
+void dump(const char *label, uint8_t *data, int len)
+{
+       int i;
+       printf("%s: ", label);
+       for (i = 0; i < len; i++)
+               printf("%02hhx ", data[i]);
+       printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+       char *device = argv[1];
+       if (!device)
+               error("usage: host /dev/ttyACM0");
+
+       header_t   head = {};
+       sync_msg_t body = {};
+
+       struct timespec ts;
+       clock_gettime(CLOCK_REALTIME, &ts);
+
+       head.header = MSG_HEADER;
+       head.msgid  = MSG_ID_SYNC;
+       head.length = sizeof(sync_msg_t);
+       head.cksum  = 0; // todo
+
+       body.seq    = 0;
+       body.time.seconds = ts.tv_sec;
+       body.time.nanosec = ts.tv_nsec;
+
+       dump("head", (uint8_t*)&head, sizeof(head));
+       dump("body", (uint8_t*)&body, sizeof(body));
+
+       FILE *fd = fopen(device, "a+");
+       if (!fd) error("opening device");
+       int len = 0;
+       len += fwrite(&head, 1, sizeof(head), fd);
+       len += fwrite(&body, 1, sizeof(body), fd);
+       fclose(fd);
+
+       printf("wrote %d bytes\n", len);
+
+       return 0;
+}
diff --git a/hw2/install.sh b/hw2/install.sh
new file mode 100755 (executable)
index 0000000..f00994e
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+function install
+{
+       bin=$1
+       dev=$2
+       mnt=$3
+
+       if [ -b "$dev" ]; then
+               echo "Installing: $bin -> $mnt"
+               mount "$mnt"
+               cp "$bin" "$mnt"
+               umount "$mnt"
+       else
+               echo Error: No USB found
+       fi
+}
+
+if [ -z "$1" ] || [ "$1" = "-h" ]; then
+       echo "usage: install.sh image.bin"
+       exit 0
+fi
+
+install "$1" /dev/sdb /mnt/mbed1 &
+install "$1" /dev/sdc /mnt/mbed2 &
+
+wait
index 4f42dd26110b517d368c74bc9754b04b519a07ae..82f28f75a3d4e62bd722cd69459bab3120969cb1 100644 (file)
@@ -1,4 +1,7 @@
+#include "messages.h"
+
 #include "mbed.h"
+#include "serial_irq.h"
 #include "serial_dma.h"
 #include "timer_dma.h"
 
  *   Time synchronization is performed in both directions.
  */
 
-/***********************
- * Message Definitions *
- ***********************/
-
-#define MSG_HEADER 0x1234
-
-typedef enum {
-       MSG_ID_SYNC,       // Time synchronization
-       MSG_ID_EVENT,      // Event occurred
-} msgid_t;
-
-typedef struct {
-       uint32_t seconds;  // Seconds since 1970 (without leap seconds)
-       uint32_t nanosec;  // Nanoseconds since 'seconds'
-} ntime_t;
-
-typedef struct {
-       uint16_t header;   // Message Header
-       uint16_t mesgid;   // Message ID
-       uint16_t length;   // Body length
-       uint16_t cksum;    // Body checksum
-} header_t;
-
-typedef struct {
-       uint16_t seq;      // Current sequence counter
-       uint16_t prev;     // Sequence of previous message
-       ntime_t  time;     // Time of previous message
-} sync_msg_t;
-
-typedef struct {
-       uint16_t device;   // Device ID
-       uint16_t event;    // Event ID
-       ntime_t  time;     // Timestamp
-} event_msg_t;
-
 /*******************
  * Timer functions *
  *******************/
 
+#define NSEC_PER_SEC 1000000000ULL
+
+uint64_t time_last_local; // timestamp at last time sync
+uint64_t time_last_world; // offset at last time sync
+
+/**
+ * Generate time stamp for an async event:
+ *   local: drift compensated wall-clock time
+ *   world: nanoseconds in world time world
+ *   valid: local timestamp at valid valid
+ */
+//uint64_t time_to_local(uint64_t world, uint64_t valid)
+//{
+//     uint64_t now =
+//     local =  + (stamp);
+//}
+
 /**
  * Generate time stamp for an async event:
  *   time:  drift compensated wall-clock time
- *   stamp: event timestamp from Timer/PWM Module
+ *   stamp: event timestamp from PIT Module
  */
-void time_stamp(ntime_t *time, uint32_t stamp)
+uint64_t time_to_world(uint64_t local)
 {
-       // todo
+       uint64_t elapsed = local - time_last_local;
+       return time_last_world + elapsed;
 }
 
 /**
@@ -79,23 +65,98 @@ void time_rtc_comp(void)
 /**
  * Synchronize the timer internal state with updates
  * from an external time sync message.
- *   ours: our internal timestamp for the event
- *   ref:  reference timestamp from the other device
+ *   local: our internal timestamp for the event
+ *   world: reference timestamp from the other device
  */
-void time_ext_sync(ntime_t *ours, ntime_t *ref)
+void time_ext_init(uint64_t local, uint64_t world)
 {
-       // todo
+       sirq_printf("initialize clocks: %d -> %d\r\n",
+                       (int)(local/NSEC_PER_SEC),
+                       (int)(world/NSEC_PER_SEC));
+
+       time_last_local = local;
+       time_last_world = world;
+}
+
+/**
+ * Synchronize the timer internal state with updates
+ * from an external time sync message.
+ *   local: our internal timestamp for the event
+ *   world: reference timestamp from the other device
+ */
+void time_ext_sync(uint64_t local, uint64_t world)
+{
+       sirq_printf("syncing clocks: %d -> %d\r\n",
+                       (int)(local/NSEC_PER_SEC),
+                       (int)(world/NSEC_PER_SEC));
+
+       time_last_local = local;
+       time_last_world = world;
 }
 
 /************************
  * Serial I/O functions *
  ************************/
 
+typedef struct {
+       int      index;
+       int      state;
+       uint8_t  buffer[256];
+} parser_t;
+
+const  uint64_t serial_sync_delay = NSEC_PER_SEC * 2; // 1hz
+static uint64_t serial_sync_due   = 0;
+
+static tdma_t  *serial_tdma_rcv   = NULL;
+static tdma_t  *serial_tdma_xmt   = NULL;
+
+static uint64_t serial_prev_local = 0;
+static uint64_t serial_prev_seq   = 0;
+
+static uint64_t serial_xmt_local  = 0;
+static uint64_t serial_xmt_seq    = 0;
+
 /**
  * Output time sync message
  */
-void serial_send_sync(void)
+void serial_send_sync(sirq_t *port, uint64_t now)
 {
+       if (serial_sync_due == 0 || now < serial_sync_due)
+               return; // not ready
+
+       // Calculate world time
+       uint64_t world = time_to_world(serial_xmt_local);
+
+       // Message data
+       header_t   head;
+       sync_msg_t body;
+
+       // Transmit sync message
+       head.header = MSG_HEADER;
+       head.msgid  = MSG_ID_SYNC;
+       head.length = sizeof(body);
+       head.cksum  = 0; // todo
+
+       body.seq          = serial_xmt_seq;
+       body.time.seconds = world / NSEC_PER_SEC;
+       body.time.nanosec = world % NSEC_PER_SEC;
+
+       sirq_write(port, &head, sizeof(head));
+       sirq_write(port, &body, sizeof(body));
+
+       serial_xmt_seq  += 1;
+       serial_sync_due  = 0;
+
+       // Debug
+       sirq_printf("sync msg transmit\r\n");
+
+       // 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_xmt);
 }
 
 /**
@@ -103,15 +164,124 @@ void serial_send_sync(void)
  *   event: id of the received event
  *   time:  compensated timestamp of the event
  */
-void serial_send_event(uint16_t event, ntime_t *time)
+void serial_send_event(uint16_t event, uint64_t local)
 {
+       uint64_t world = time_to_world(local);
+
+       ntime_t time = {};
+       time.seconds = (uint32_t)(world / NSEC_PER_SEC);
+       time.nanosec = (uint32_t)(world % NSEC_PER_SEC);
+
+       sirq_printf("event received - %08x:%08x - %u.%u\r\n",
+               (uint32_t)(local >> 32), (uint32_t)local,
+               time.seconds, time.nanosec);
+       // todo
+}
+
+/**
+ * Handle sync message
+ */
+void serial_handle_sync(sync_msg_t *msg)
+{
+       // Read receive timestamp for next time sync message
+       uint64_t current = 0;
+       int valid = tdma_stamp(serial_tdma_rcv, &current);
+       if (!valid)
+               sirq_printf("missing sync receive time\r\n");
+       tdma_reset(serial_tdma_rcv);
+
+       // Lookup times
+       uint64_t world = ((uint64_t)msg->time.seconds) * NSEC_PER_SEC
+                      + ((uint64_t)msg->time.nanosec);
+
+       // Initialize
+       if (msg->seq == 0) {
+               uint64_t local = tdma_time();
+               time_ext_init(local, world);
+       }
+
+       // Valid times timestamp
+       if (serial_prev_seq == (msg->seq-1)) {
+               uint64_t local = serial_prev_local;
+               time_ext_sync(local, world);
+       }
+
+       // Queue transmit to other board
+       serial_sync_due   = tdma_time() + serial_sync_delay;
+
+       // Update states
+       serial_prev_local = current;
+       serial_prev_seq   = msg->seq;
+}
+
+/**
+ * Handle event message
+ */
+void serial_handle_event(event_msg_t *msg)
+{
+}
+
+/**
+ * Deliver message
+ */
+void serial_deliver(int msgid, void *body)
+{
+       switch (msgid) {
+               case MSG_ID_SYNC:
+                       sirq_printf("received sync msg\r\n");
+                       serial_handle_sync((sync_msg_t*)body);
+                       break;
+               case MSG_ID_EVENT:
+                       sirq_printf("received event msg\r\n");
+                       serial_handle_event((event_msg_t*)body);
+                       break;
+       }
 }
 
 /**
  * Process serial receive messages
  */
-void serial_receive(void)
+void serial_receive(parser_t *parser, int byte)
 {
+       //sirq_printf("serial_receive - %02x\r\n", byte);
+
+       // Lookup pointers
+       header_t *head = (header_t*)parser->buffer;
+       void     *body = (void*)(head+1);
+       const int max_length = sizeof(parser->buffer)-sizeof(header_t);
+
+       // Process uart messages
+       parser->buffer[parser->index++] = byte;
+       switch (parser->state) {
+               case 0: // Search
+                       if (parser->index == sizeof(uint16_t)) {
+                               if (head->header == MSG_HEADER) {
+                                       parser->state = 1;
+                               } else {
+                                       parser->buffer[0] = parser->buffer[1];
+                                       parser->index = 1;
+                               }
+                       }
+                       break;
+               case 1: // Header
+                       if (parser->index == sizeof(header_t)) {
+                               if (head->length <= max_length &&
+                                   head->msgid  <= MSG_MAXID) {
+                                       parser->state = 2;
+                               } else {
+                                       parser->index = 0;
+                                       parser->state = 0;
+                               }
+                       }
+                       break;
+               case 2: // Data
+                       if (parser->index == (int)sizeof(header_t)+head->length) {
+                               serial_deliver(head->msgid, body);
+                               parser->index = 0;
+                               parser->state = 0;
+                       }
+                       break;
+       }
 }
 
 /********************
@@ -122,35 +292,152 @@ void serial_receive(void)
 DigitalOut led1(LED1);
 DigitalOut led2(LED2);
 
-// UARTs         tx      rx
-Serial     uart0(USBTX,  USBRX);
-Serial     uart1(PTE0,   PTE1);
-Serial     uart2(PTD3,   PTD2);
+// Message Parsers
+parser_t   parser_dbg;
+parser_t   parser_bbb;
+parser_t   parser_mbed;
 
-// Serial DMA
-sdma_t    *sdma0;
-sdma_t    *sdma1;
-sdma_t    *sdma2;
+// Serial IRQ
+sirq_t    *sirq_dbg;
+sirq_t    *sirq_bbb;
+sirq_t    *sirq_mbed;
 
 // Timer DMA
-tdma_t    *tdma0;
-tdma_t    *tdma1;
-tdma_t    *tdma2;
-tdma_t    *tdma3;
+tdma_t    *tdma_evt;
+tdma_t    *tdma_rcv;
+tdma_t    *tdma_xmt;
+
+/*********
+ * Tasks *
+ *********/
+
+void task_serial(uint64_t local, uint64_t world)
+{
+       while (sirq_ready(sirq_dbg)) {
+               //sirq_printf("serial recv - dbg\r\n");
+               serial_receive(&parser_dbg,  sirq_getc(sirq_dbg));
+       }
+
+       while (sirq_ready(sirq_bbb)) {
+               //sirq_printf("serial recv - bbb\r\n");
+               serial_receive(&parser_bbb,  sirq_getc(sirq_bbb));
+       }
+
+       while (sirq_ready(sirq_mbed)) {
+               //sirq_printf("serial recv - mbed\r\n");
+               serial_receive(&parser_mbed, sirq_getc(sirq_mbed));
+       }
+}
+
+void task_events(uint64_t local, uint64_t world)
+{
+       uint64_t event = 0;
+
+#ifdef VERBOSE
+       if (tdma_stamp(tdma_evt, &event)) {
+               sirq_printf("event received - evt\r\n");
+       if (tdma_stamp(tdma_rcv, &event))
+               sirq_printf("event received - rcv\r\n");
+       if (tdma_stamp(tdma_xmt, &event))
+               sirq_printf("event received - xmt\r\n");
+#endif
+
+       if (tdma_stamp(tdma_evt, &event))
+               serial_send_event(0, event);
+       tdma_reset(tdma_evt);
+}
+
+void task_sync(uint64_t local, uint64_t world)
+{
+       serial_send_sync(sirq_bbb, local);
+}
+
+void task_leds(uint64_t local, uint64_t world)
+{
+       static uint32_t which = 0;
+       led1 = (which == 0);
+       led2 = (which == 1);
+       which ^= 1;
+}
+
+void task_debug(uint64_t local, uint64_t world)
+{
+       //tdma_debug(tdma_rcv);
+       sirq_printf("background - %6d.%02d -> %d.%02d\r\n",
+                       (uint32_t)(local / NSEC_PER_SEC),
+                       (uint32_t)(local % NSEC_PER_SEC / 10000000),
+                       (uint32_t)(world / NSEC_PER_SEC),
+                       (uint32_t)(world % NSEC_PER_SEC / 10000000));
+}
 
 /********
  * Main *
  ********/
 
-void test_main(void);
+#define N_ELEM(x) (sizeof(x) / sizeof((x)[0]))
+
+extern void test_main(void);
+extern serial_t stdio_uart;
+
+static struct {
+       void (*task)(uint64_t, uint64_t);
+       uint64_t period;
+       uint64_t due;
+} tasks[] = {
+       { task_serial, 0          }, // always
+       { task_events, 1000000000 }, // always
+       { task_sync,   0          }, // always
+       { task_leds,   100000000  }, // 10hz
+       { task_debug,  1000000000 }, // 1hz
+};
+
+void background(void)
+{
+       // Debugging
+       uint64_t local = tdma_time();
+       uint64_t world = time_to_world(local);
+
+       // Run the scheduler
+       for (unsigned i = 0; i < N_ELEM(tasks); i++) {
+               if (local >= tasks[i].due) {
+                       tasks[i].task(local, world);
+                       tasks[i].due += tasks[i].period;
+               }
+       }
+}
 
 int main(int argc, char **argv)
 {
-       uart0.baud(115200);
-       uart1.baud(115200);
-       uart2.baud(115200);
+       tdma_init();
+
+       // Open serial ports
+       sirq_dbg   = sirq_open(SIRQ_UART0, USBTX, USBRX, 115200); // to pc
+       sirq_bbb   = sirq_open(SIRQ_UART1, PTD3,  PTD2,  115200); // to bbb
+       sirq_mbed  = sirq_open(SIRQ_UART2, PTE0,  PTE1,  115200); // to mbed
+
+
+       // Setup timers
+       tdma_evt   = tdma_open(TDMA_CHAN0, 3, PTC9,  PullDown); // async event
+
+       // mbed time sync
+       tdma_rcv   = tdma_open(TDMA_CHAN2, 3, PTD2,  PullUp);   // time sync rcv
+       tdma_xmt   = tdma_open(TDMA_CHAN3, 3, PTD3,  PullUp);   // time sync xmt
+
+       // host time sync
+       //tdma_rcv   = tdma_open(TDMA_CHAN2, 2, USBRX, PullUp); // time sync rcv
+       //tdma_xmt   = tdma_open(TDMA_CHAN3, 2, USBTX, PullUp); // time sync xmt
+
+       // Serial timestamping
+       serial_tdma_rcv = tdma_rcv;
+       serial_tdma_xmt = tdma_xmt;
+
+       // Run background loop
+       printf("hello");
+       while (true)
+               background();
 
-       test_main();
+       // Run tests
+       //test_main();
 
        return 0;
 }
index 0f9b65d4c80e4f2bac64d3747e6f18b2a882aca7..b32f808bd8aab647de4043adab4be95f2f069788 100644 (file)
@@ -1,10 +1,22 @@
 PROG = mbed
-OBJS = main.o test.o serial_dma.o timer_dma.o
+UART = /dev/ttyACM0
+OBJS = main.o test.o serial_irq.o serial_dma.o timer_dma.o
 
 CPPFLAGS =
 LDFLAGS  = -lm
 
-default: info install
+default: info run
+
+control: control.c
+       gcc -Wall -o control control.c
+
+run: all control install.sh
+       @./install.sh $(PROG).bin
+       @./control $(UART)
+
+terms:
+       term /dev/ttyACM0 &
+       term /dev/ttyACM1 &
 
 dist:
        zip mbed.zip makefile ../common.mk *.{c,cpp,h} */*.{cpp,.h}
diff --git a/hw2/messages.h b/hw2/messages.h
new file mode 100644 (file)
index 0000000..20887cc
--- /dev/null
@@ -0,0 +1,40 @@
+/***********************
+ * Message Definitions *
+ ***********************/
+
+#include <stdint.h>
+
+#define MSG_HEADER 0x1234
+#define MSG_MAXID  2
+
+#pragma pack(1)
+
+typedef enum {
+       MSG_ID_SYNC,       // Time synchronization
+       MSG_ID_EVENT,      // Event occurred
+} msgid_t;
+
+typedef struct {
+       uint32_t seconds;  // Seconds since 1970 (without leap seconds)
+       uint32_t nanosec;  // Nanoseconds since 'seconds'
+} ntime_t;
+
+typedef struct {
+       uint16_t header;   // Message Header
+       uint16_t msgid;    // Message ID
+       uint16_t length;   // Body length
+       uint16_t cksum;    // Body checksum
+} header_t;
+
+typedef struct {
+       uint32_t seq;      // Current sequence counter
+       ntime_t  time;     // Time of previous message
+} sync_msg_t;
+
+typedef struct {
+       uint16_t device;   // Device ID
+       uint16_t event;    // Event ID
+       ntime_t  time;     // Timestamp
+} event_msg_t;
+
+#pragma pack()
diff --git a/hw2/serial_irq.c b/hw2/serial_irq.c
new file mode 100644 (file)
index 0000000..67beeab
--- /dev/null
@@ -0,0 +1,114 @@
+#include <MKL46Z4.h>\r
+\r
+#include <stdint.h>\r
+#include <stdio.h>\r
+#include "serial_api.h"\r
+#include "serial_irq.h"\r
+\r
+/* Defines */\r
+#define SIRQ_LEN  1024\r
+\r
+/* Port structure */\r
+typedef struct {\r
+       int     rix;\r
+       int     wix;\r
+       uint8_t buf[SIRQ_LEN];\r
+} queue_t;\r
+\r
+struct sirq_t {\r
+       serial_t uart;\r
+       queue_t  xmt;\r
+       queue_t  rcv;\r
+};\r
+\r
+/* Port data */\r
+static sirq_t sirq_ports[SIRQ_NUM_UART];\r
+\r
+/* Receive handler */\r
+void sirq_handler(uint32_t _port, SerialIrq event)\r
+{\r
+       sirq_t *port = (sirq_t *)_port;\r
+\r
+       // Handle transmit\r
+       if (event == TxIrq && port->xmt.rix != port->xmt.wix) {\r
+               int byte = port->xmt.buf[port->xmt.rix];\r
+               serial_putc(&port->uart, byte);\r
+               port->xmt.rix = (port->xmt.rix+1) % SIRQ_LEN;\r
+       } else {\r
+               serial_irq_set(&port->uart, TxIrq, 0);\r
+       }\r
+\r
+       // Handle receive\r
+       if (event == RxIrq) {\r
+               int byte = serial_getc(&port->uart);\r
+               port->rcv.buf[port->rcv.wix] = byte;\r
+               port->rcv.wix = (port->rcv.wix+1) % SIRQ_LEN;\r
+       }\r
+}\r
+\r
+/* Open port */\r
+sirq_t *sirq_open(sirq_uart_t uart, PinName tx, PinName rx, int baud)\r
+{\r
+       // Allocate port\r
+       sirq_t *port = &sirq_ports[uart];\r
+\r
+       // Configure port\r
+       serial_init(&port->uart, tx, rx);\r
+       serial_baud(&port->uart, baud);\r
+\r
+       // Set IRQ handlers\r
+       serial_irq_handler(&port->uart, sirq_handler, (uint32_t)port);\r
+       serial_irq_set(&port->uart, RxIrq, 1);\r
+\r
+       return port;\r
+}\r
+\r
+/* Write byte to the port */\r
+void sirq_putc(sirq_t *port, int byte)\r
+{\r
+       port->xmt.buf[port->xmt.wix] = byte;\r
+       port->xmt.wix = (port->xmt.wix+1) % SIRQ_LEN;\r
+       serial_irq_set(&port->uart, TxIrq, 1);\r
+}\r
+\r
+/* Read byte from the port */\r
+int sirq_getc(sirq_t *port)\r
+{\r
+       int byte = 0;\r
+       if (port->rcv.rix < port->rcv.wix) {\r
+               byte = port->rcv.buf[port->rcv.rix];\r
+               port->rcv.rix = (port->rcv.rix+1) % SIRQ_LEN;\r
+       }\r
+       return byte;\r
+}\r
+\r
+/* Buffered write */\r
+void sirq_write(sirq_t *port, void *data, int len)\r
+{\r
+       uint8_t *bytes = (uint8_t*)data;\r
+       for (int i = 0; i < len; i++)\r
+               sirq_putc(port, bytes[i]);\r
+}\r
+\r
+/* Check if port is writable */\r
+int sirq_ready(sirq_t *port)\r
+{\r
+       return port->rcv.rix < port->rcv.wix;\r
+}\r
+\r
+/* Write ASCII data to the output queue */\r
+void sirq_vprintf(const char *fmt, va_list ap)\r
+{\r
+       static char buf[512];\r
+       int len = vsnprintf(buf, sizeof(buf), fmt, ap);\r
+       for (int i = 0; i < len; i++)\r
+               sirq_putc(&sirq_ports[0], buf[i]);\r
+}\r
+\r
+void sirq_printf(const char *fmt, ...)\r
+{\r
+       va_list ap;\r
+       va_start(ap, fmt);\r
+       sirq_vprintf(fmt, ap);\r
+       va_end(ap);\r
+}\r
diff --git a/hw2/serial_irq.h b/hw2/serial_irq.h
new file mode 100644 (file)
index 0000000..5595d14
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef SERIAL_IRQ_H
+#define SERIAL_IRQ_H
+
+#include <stdarg.h>
+#include <MKL46Z4.h>
+#include <PinNames.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Sizes */
+#define SIRQ_NUM_UART 3
+
+/* Serial Ports */
+typedef enum {
+       SIRQ_UART0,
+       SIRQ_UART1,
+       SIRQ_UART2,
+} sirq_uart_t;
+
+/* Port */
+typedef struct sirq_t sirq_t;
+
+/* Open */
+sirq_t *sirq_open(sirq_uart_t uart, PinName tx, PinName rx, int baud);
+
+/* Read/Write */
+void sirq_putc(sirq_t *port, int byte);
+int  sirq_getc(sirq_t *port);
+void sirq_write(sirq_t *port, void *data, int len);
+
+/* Read In */
+int  sirq_ready(sirq_t *port);
+
+/* Print */
+void sirq_vprintf(const char *fmt, va_list ap);
+void sirq_printf(const char *fmt, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index 23f11e226a23d83d8585bf2eacbd3c918423ba3a..2e197186cec8b507d902b75b660dfd141aaf4cf5 100644 (file)
@@ -71,7 +71,7 @@ void tdma_init(void)
 }\r
 \r
 /* DMA Functions */\r
-tdma_t *tdma_open(tdma_chan_t chan, PinName pin, PinMode mode)\r
+tdma_t *tdma_open(tdma_chan_t chan, int alt, PinName pin, PinMode mode)\r
 {\r
        int req  = pin >= PTD0 ? TDMA_REQ_PTD :\r
                   pin >= PTC0 ? TDMA_REQ_PTC :\r
@@ -95,7 +95,7 @@ tdma_t *tdma_open(tdma_chan_t chan, PinName pin, PinMode mode)
                        | DMA_DCR_DINC_MASK         // Dest increment\r
                        | DMA_DCR_SSIZE(0)          // 32-bit access\r
                        | DMA_DCR_DSIZE(0)          // 32-bit access\r
-                       | DMA_DCR_ERQ_MASK;         // Enable port request\r
+                       | DMA_DCR_D_REQ_MASK;       // Only run once\r
 \r
        // Setup and enable DMA MUX\r
        port->mux->cfg  = DMAMUX_CHCFG_SOURCE(req)  // Request source\r
@@ -103,42 +103,101 @@ tdma_t *tdma_open(tdma_chan_t chan, PinName pin, PinMode mode)
 \r
        // Set pin to generate DMA req\r
        port->pin->pcr  = PORT_PCR_ISF_MASK         // Clear ISR flag\r
-                       | PORT_PCR_MUX(3)           // Pin mapping\r
+                       | PORT_PCR_MUX(alt)         // Pin mapping\r
                        | PORT_PCR_IRQC(ircq)       // DMA on falling edge\r
                        | mode;                     // Pin pull up/down\r
 \r
+       // Initial reset\r
+       tdma_reset(port);\r
+\r
        return port;\r
 }\r
 \r
 void tdma_reset(tdma_t *port)\r
 {\r
+       if (!port)\r
+               return;\r
+\r
        // Clear previous time\r
        port->time[0] = 0;\r
        port->time[1] = 0;\r
 \r
+       // Freeze DMA channel\r
+       port->dma->dcr &= ~DMA_DCR_ERQ_MASK;\r
+\r
        // Reset DMA channel\r
-       port->dma->dsr  = DMA_DSR_BCR_DONE_MASK;\r
+       port->dma->dsr  =  DMA_DSR_BCR_DONE_MASK;\r
 \r
        // Set addresses and size\r
-       port->dma->sar  = (uint32_t)&PIT->LTMR64H;  // Global timer\r
-       port->dma->dar  = (uint32_t)&port->time;    // Temp timer buffer\r
-       port->dma->dsr  = DMA_DSR_BCR_BCR(8);       // 64-bit timer\r
+       port->dma->sar  =  (uint32_t)&PIT->LTMR64H;  // Global timer\r
+       port->dma->dar  =  (uint32_t)&port->time;    // Temp timer buffer\r
+       port->dma->dsr  =  DMA_DSR_BCR_BCR(8);       // 64-bit timer\r
+\r
+       // Enable port request\r
+       port->dma->dcr |=  DMA_DCR_ERQ_MASK;\r
 }\r
 \r
 int tdma_stamp(tdma_t *port, uint64_t *time)\r
 {\r
+       uint64_t clocks;\r
+\r
+       if (!port)\r
+               return 0;\r
+\r
        if (port->dma->dsr & DMA_DSR_BCR_BCR_MASK)\r
                return 0;\r
 \r
        // Read the timestamp\r
-       *time = ((uint64_t)~port->time[0]) << 32\r
-             | ((uint64_t)~port->time[1]) << 0;\r
+       clocks = ((uint64_t)~port->time[0]) << 32\r
+              | ((uint64_t)~port->time[1]) << 0;\r
 \r
-       // Debug output..\r
-       //printf(" - sar:%08lx dar:%08lx pcr:%08lx dsr:%08lx time:%08lx:%08lx",\r
-       //      port->dma->sar, port->dma->dar,\r
-       //      port->pin->pcr, port->dma->dsr,\r
-       //      (uint32_t)(*time >> 32), (uint32_t)*time);\r
+       // Convert to nanoseconds\r
+       *time  = clocks * 1000 / 24;\r
 \r
        return 1;\r
 }\r
+\r
+uint64_t tdma_time(void)\r
+{\r
+       uint32_t tmh = PIT->LTMR64H;\r
+       uint32_t tml = PIT->LTMR64L;\r
+\r
+       // Read the timestamp\r
+       uint64_t clocks = ((uint64_t)~tmh) << 32\r
+                       | ((uint64_t)~tml) << 0;\r
+\r
+       // Convert to nanoseconds\r
+       return clocks * 1000 / 24;\r
+}\r
+\r
+void tdma_debug(tdma_t *port)\r
+{\r
+       int dsr = port->dma->dsr;\r
+       int dcr = port->dma->dcr;\r
+\r
+       printf("dsr: %s %s %s %s %s %s %d\r\n",\r
+                        dsr & DMA_DSR_BCR_CE_MASK   ? "CE"      : "ce",\r
+                        dsr & DMA_DSR_BCR_BES_MASK  ? "BSE"     : "bse",\r
+                        dsr & DMA_DSR_BCR_BED_MASK  ? "BED"     : "bed",\r
+                        dsr & DMA_DSR_BCR_REQ_MASK  ? "REQ"     : "req",\r
+                        dsr & DMA_DSR_BCR_BSY_MASK  ? "BSY"     : "bsy",\r
+                        dsr & DMA_DSR_BCR_DONE_MASK ? "DONE"    : "done",\r
+                        dsr & DMA_DSR_BCR_BCR_MASK);\r
+\r
+       printf("dcr: %s %s %s %s %s %s %s %s ssize=%d:%d mod=%d:%d link=%d:%d:%d\r\n",\r
+                        dcr & DMA_DCR_EINT_MASK     ? "EINT"    : "eint",\r
+                        dcr & DMA_DCR_ERQ_MASK      ? "ERQ"     : "erq",\r
+                        dcr & DMA_DCR_CS_MASK       ? "CS"      : "cs",\r
+                        dcr & DMA_DCR_AA_MASK       ? "AA"      : "aa",\r
+                        dcr & DMA_DCR_EADREQ_MASK   ? "EADRREQ" : "eadrreq",\r
+                        dcr & DMA_DCR_SINC_MASK     ? "SINC"    : "sinc",\r
+                        dcr & DMA_DCR_DINC_MASK     ? "DINC"    : "dinc",\r
+                        dcr & DMA_DCR_D_REQ_MASK    ? "DREQ"    : "dreq",\r
+                       (dcr & DMA_DCR_SSIZE_MASK ) >> DMA_DCR_SSIZE_SHIFT,\r
+                       (dcr & DMA_DCR_DSIZE_MASK ) >> DMA_DCR_DSIZE_SHIFT,\r
+                       (dcr & DMA_DCR_SMOD_MASK  ) >> DMA_DCR_SMOD_SHIFT,\r
+                       (dcr & DMA_DCR_DMOD_MASK  ) >> DMA_DCR_DMOD_SHIFT,\r
+                       (dcr & DMA_DCR_LINKCC_MASK) >> DMA_DCR_LINKCC_SHIFT,\r
+                       (dcr & DMA_DCR_LCH1_MASK  ) >> DMA_DCR_LCH1_SHIFT,\r
+                       (dcr & DMA_DCR_LCH2_MASK  ) >> DMA_DCR_LCH2_SHIFT);\r
+}\r
index cf672d04603f6ccb2a721365ab41ea0f0116740a..c6d276307581c77a473137cb63527e2dce42aa8d 100644 (file)
@@ -27,12 +27,18 @@ typedef struct tdma_t tdma_t;
 void tdma_init(void);
 
 /* Open */
-tdma_t *tdma_open(tdma_chan_t chan, PinName pin, PinMode mode);
+tdma_t *tdma_open(tdma_chan_t chan, int alt, PinName pin, PinMode mode);
 
 /* Flush/Wait */
 void tdma_reset(tdma_t *port);
 int  tdma_stamp(tdma_t *port, uint64_t *time);
 
+/* Time */
+uint64_t tdma_time(void);
+
+/* Debug print */
+void tdma_debug(tdma_t *port);
+
 #ifdef __cplusplus
 }
 #endif