From 5f3b2829ba56629466234ca1693cf7fed0908975 Mon Sep 17 00:00:00 2001
From: Jake Read <jake.read@cba.mit.edu>
Date: Sat, 7 Aug 2021 13:53:30 -0400
Subject: [PATCH] upd8 some interrupt notes, note on PA17

---
 README.md          | 63 ++++++++++++++++++++++++++++++++++++++++++++++
 ancient/code/tc5.h | 44 ++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+)
 create mode 100644 ancient/code/tc5.h

diff --git a/README.md b/README.md
index b4691ef..3f50a9d 100644
--- a/README.md
+++ b/README.md
@@ -48,3 +48,66 @@ directory.
 One of the troubles with Arduino is that people forget that it is just a big C++ library. This means that everything under the sun (that compiles) is legal here. *That* means that we can use Arduino as a crutch, but write really nice Special Function Register code inside of the same executable. Great!
 
 Indeed, in the PlatformIO environment, we even have wonderful autocomplete handles on the D51's core register map. For some examples of this kind of manipulation, check out the `hunks` in the [ponyo](https://gitlab.cba.mit.edu/squidworks/ponyo) project.
+
+## D51 Errata and Dev Notes
+
+### Adafruit and PA17 
+
+This is not mentioned in the ada doc, but *beware PA17* - ada uses this (afaik) to debug their USB implementation... you can pull it hi / lo as much as you want, but when a USB connection is made ada will reclaim the pin and output some kind of tick on it. Unclear to me. Unfortunately for yrs truly the D51 modules I've built have the RS485 termination enable pin on this line. 
+
+I believe it's possible to find your way through the ada / arduino build core and rm the output, I've done it once before, but have since lost my notes on where it is. 
+
+### Interrupt Clear / Set
+
+**2021 08 07**
+
+We can ostensibly set and clear interrupts in the D51 with code like:
+
+`SERCOM1->USART.INTENCLR.bit.DRE = 1;`
+
+FWIW there's the additional step of actually enabling them through the `NVIC` (nested vector interrupt controller), which we do once during a setup, like:
+
+```cpp
+NVIC_EnableIRQ(SERCOM1_2_IRQn); // rx interrupts 
+NVIC_EnableIRQ(SERCOM1_1_IRQn); // transmit complete interrupt 
+NVIC_EnableIRQ(SERCOM1_0_IRQn); // data register empty interrupts 
+```
+
+And then use the `INTENCLR / INTENSET` registers to turn them on / off during operation. In any case, I've found the `.bit` interface to be a little less reliable (for whatever reason) than a more direct register access like below:
+
+`SERCOM1->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_DRE;`
+
+So - watch for that. Use the second line if in doubt. 
+
+### Interrupt Lines / Handlers / Which is Which 
+
+It's not exactly clear from the datasheet which interrupt handler is which action. For example to get an RXC interrupt on the SER1 UART, we have:
+
+```cpp
+// enabling the thing from NVIC 
+NVIC_EnableIRQ(SERCOM1_2_IRQn); // rx interrupts 
+
+// turning it on in the peripheral
+SERCOM1->USART.INTENSET.reg = SERCOM_USART_INTENSET_RXC;
+
+// handling it 
+void SERCOM1_2_Handler(void){
+
+}
+```
+
+So how are we meant to discover which is which? Well, we can find this line wherever `samd51j19a.h` is located in your build system:
+
+`SERCOM1_2_IRQn = 52, /**< 52 SAMD51J19A Serial Communication Interface 1 (SERCOM1): SERCOM1_2 */`
+
+Showing that this is interrupt line '52' - which is what gets passed to the NVIC when the interrupt needs to fire (AFAIK), then on the datasheet section `10.2` we get a list of the `Interrupt Line Mapping` which shows that this line `52` is mapped to `SERCOM1_2` interrupt: well, how do we know that `SER1_2` is the RXC interrupt? It's actually not clear, but I have found that the register map / interrupt flags i.e. in the D51 datasheet `34.8.8` has the DRE in bit position `0` (it's interrupt SERx_0), TXC in position `1` (it's SERx_1) and RXC in position `2` (SERx_2) etc. 
+
+Notice also that multiple interrupts can be mapped to the same handler, i.e. back in DS `10.2` we have SER1_3, SER1_4, SER1_5, and SER1_7 all on line `53` - FWIW I can't tell you if they each have different handlers, but I suspect they would all come through something like:
+
+```cpp
+void SERCOM1_3_Handler(void){}
+```
+
+And then we can check flags `SERCOM1->USART.INTFLAG.reg` to figure which of these was actually set when the thing was called. 
+
+GLHF. 
\ No newline at end of file
diff --git a/ancient/code/tc5.h b/ancient/code/tc5.h
new file mode 100644
index 0000000..d557f9e
--- /dev/null
+++ b/ancient/code/tc5.h
@@ -0,0 +1,44 @@
+
+void startup_step_operator(void){
+  // some pin fiddling,
+  GPIO_PORT.DIRSET.reg = DIR_BM;
+  GPIO_PORT.OUTCLR.reg = DIR_BM;
+  GPIO_PORT.DIRSET.reg = STEP_BM;
+  /*
+  GPIO_PORT.PINCFG[STEP_PIN].bit.PMUXEN = 1;
+  if(STEP_PIN % 2){ // true when odd,
+    GPIO_PORT.PMUX[STEP_PIN >> 1].reg |= PORT_PMUX_PMUXO(STEP_TIMER_PERIPHERAL);
+  } else {
+    GPIO_PORT.PMUX[STEP_PIN >> 1].reg |= PORT_PMUX_PMUXE(STEP_TIMER_PERIPHERAL);
+  }
+  */
+  // our pin is on PB00 / TC7-WO[0]
+  // which is something of a welp, it should be on a timer pin that is defined...
+  // live and learn, we'll use the interrupt to step, kind of a bummer, but here we are
+  // a handful of these can only be written to when the thing is turnt off
+  TC5->COUNT16.CTRLA.bit.SWRST = 1;
+  //TC5->COUNT16.CTRLA.bit.ENABLE = 0;
+  // unmask clocks
+  MCLK->APBCMASK.reg |= MCLK_APBCMASK_TC5;
+  // make one clk,
+  GCLK->GENCTRL[TIMER_B_GCLK_NUM].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL) | GCLK_GENCTRL_GENEN;
+  while(GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL(TIMER_B_GCLK_NUM));
+  // ok, clock to these channels...
+  GCLK->PCHCTRL[TC5_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(TIMER_B_GCLK_NUM);
+  // turn them ooon...
+  TC5->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_PRESCSYNC_PRESC | TC_CTRLA_PRESCALER_DIV16 | TC_CTRLA_CAPTEN0;
+  // going to set this up to count at some time, we will tune
+  TC5->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_MFRQ;
+  // allow interrupt to trigger on this event (overflow)
+	TC5->COUNT16.INTENSET.bit.MC0 = 1;
+  TC5->COUNT16.INTENSET.bit.MC1 = 1;
+  // set the period, should show a lower bound of ~ 200 counts (that's 400 cpu counts, for interrupt of... 800ns)
+  while(TC5->COUNT16.SYNCBUSY.bit.CC0);
+	TC5->COUNT16.CC[0].reg = STEP_TICKER_B_FULL_COUNT;
+	// enable, sync for enable write
+  while(TC5->COUNT16.SYNCBUSY.bit.ENABLE);
+	TC5->COUNT16.CTRLA.bit.ENABLE = 1;
+	// enable the IRQ
+	NVIC_EnableIRQ(TC5_IRQn);
+  // do step pin stuff ?
+}
-- 
GitLab