+/*********************
+ * Signal generation *
+ *********************/
+
+static uint32_t *emit_pcr = 0; // transmit pin name
+
+static uint64_t emit_start = 0; // transmit start time
+static uint64_t emit_period = 0; // transmit period
+static uint64_t emit_due = 0; // next transmit time
+
+static uint32_t emit_slack = 0; // how far ahead we need to schedule
+static uint32_t emit_worst = 0; // worst-case latency in task table
+
+void emit_init(int alt, PinName pin, PinMode mode)
+{
+ // Find pin
+ emit_pcr = (uint32_t*)(PORTA_BASE + pin);
+
+ // Enable clocks
+ SIM->SCGC6 |= SIM_SCGC6_TPM0_MASK;
+
+ SIM->SOPT2 |= SIM_SOPT2_TPMSRC(1);
+ SIM->SOPT4 |= SIM_SOPT4_TPM1CLKSEL_MASK;
+
+ // Set pin mode
+ emit_pcr[0] = PORT_PCR_ISF_MASK
+ | PORT_PCR_MUX(alt)
+ | mode;
+
+ // Setup Timer/PWM Module
+ TPM0->SC = TPM_SC_TOF_MASK
+ | TPM_SC_PS(1); // 24 MHz clock ?
+ TPM0->CNT = TPM_CNT_COUNT(0);
+ TPM0->MOD = TPM_MOD_MOD(0xFFFF);
+
+ TPM0->CONTROLS[0].CnSC = TPM_CnSC_CHF_MASK // clear flag
+ | TPM_CnSC_MSB_MASK // pulse output on match
+ | TPM_CnSC_MSA_MASK // ..
+ | TPM_CnSC_ELSA_MASK; // pulse high
+
+ TPM0->CONTROLS[0].CnV = 0xFFFF; // time delay
+
+ TPM0->STATUS = TPM_STATUS_CH0F_MASK
+ | TPM_STATUS_TOF_MASK;
+
+ TPM0->CONF = TPM_CONF_CSOO_MASK;
+}
+
+void emit_enable(uint64_t start, uint64_t period)
+{
+ emit_start = start;
+ emit_period = period;
+ emit_due = start + period;
+
+ emit_slack = 10000; // tune based on emit_worst
+
+ time_printf("scheuled emit - ", emit_due);
+}
+
+void emit_schedule(uint64_t when)
+{
+ uint64_t now = tdma_time();
+ uint16_t delay = (uint16_t)(when-now);
+
+ // Clear pending flags
+ //emit_pcr[0] |= PORT_PCR_ISF_MASK
+
+ // Disable timer
+ TPM0->SC = TPM_SC_TOF_MASK;
+
+ // Set transmit time
+ TPM0->CNT = TPM_CNT_COUNT(0);
+ TPM0->CONTROLS[0].CnV = delay;
+
+ // Start the timer
+ TPM0->SC = TPM_SC_TOF_MASK
+ | TPM_SC_CMOD(1);
+}
+
+void emit_transmit(void)
+{
+ static uint64_t prev;
+
+ // Get a fresh timestamp
+ uint64_t world = tdma_time();
+
+ // Record how how much time we have to reschedule
+ if (prev && world - prev > emit_worst)
+ emit_worst = prev;
+
+ // Schedule task if needed
+ if (world+emit_slack > emit_due)
+ emit_schedule(emit_due);
+}
+