|
| 1 | +#include "Keyboard.h" |
| 2 | + |
| 3 | + |
| 4 | + |
| 5 | +const int cDiv = 2; //dividor of clock, higher the value better the ADC accuracy, may require recalibration |
| 6 | +int key0 = 32; //code of key 1 |
| 7 | +int key1 = 108; //code of key 2 |
| 8 | +float act0 = 0.5f; //activation fraction of key 1 |
| 9 | +float act1 = 0.5f; //activation fraction of key 2 |
| 10 | +bool RapidTrigger = false; //Rapid Trigger |
| 11 | +float RTrange = 0.1f; //Rapid trigger fraction |
| 12 | +int res = 8; //define resolution - 8/10/12 bits, will require recalibration |
| 13 | + |
| 14 | +// Calibration Values |
| 15 | +const int min0 = 20; |
| 16 | +const int min1 = 20; |
| 17 | +const int max0 = 200; |
| 18 | +const int max1 = 200; |
| 19 | + |
| 20 | +// Dont change |
| 21 | + |
| 22 | +volatile bool key0on = false; |
| 23 | +volatile bool key1on = false; |
| 24 | +volatile int RTlimit = 0; |
| 25 | +const int gClk = 3; //used to define which generic clock we will use for ADC |
| 26 | +volatile int Analog0 = 0; |
| 27 | +volatile int Analog1 = 0; |
| 28 | +volatile float a0 = 0.0f; |
| 29 | +volatile float a1 = 0.0f; |
| 30 | +volatile int PA0 = 0; |
| 31 | +volatile int PA1 = 0; |
| 32 | +volatile int resolution; |
| 33 | +volatile int RTR0; |
| 34 | +volatile int RTR1; |
| 35 | +volatile int RTL0 = 0; |
| 36 | +volatile int RTL1 = 0; |
| 37 | + |
| 38 | +void setup() { |
| 39 | + |
| 40 | + //genericClockSetup(gClk,cDiv); //setup generic clock and routed it to ADC |
| 41 | + resolution = pow(2, res) - 1; |
| 42 | + genericClockSetup(gClk, cDiv); |
| 43 | + ADCSetup(); |
| 44 | + a0 = ((max0 - min0) / float(resolution)); |
| 45 | + a1 = ((max1 - min1) / float(resolution)); |
| 46 | + act0 = int(act0 * a0 * resolution); |
| 47 | + act1 = int(act1 * a1 * resolution); |
| 48 | + RTR0 = int(RTrange * a0 * resolution); |
| 49 | + RTR1 = int(RTrange * a1 * resolution); |
| 50 | + RTL0 = RTL0; |
| 51 | + RTL1 = RTL1; |
| 52 | + Keyboard.begin(); |
| 53 | +} |
| 54 | + |
| 55 | + |
| 56 | + |
| 57 | + |
| 58 | +void loop() { |
| 59 | + |
| 60 | + readKey0(); |
| 61 | + readKey1(); |
| 62 | + |
| 63 | +} |
| 64 | + |
| 65 | +void keyb0() { |
| 66 | + if (key0on == false && Analog0 > act0) { |
| 67 | + Keyboard.press(key0); |
| 68 | + key0on = true; |
| 69 | + } else if (key0on == true && Analog0 < act0) { |
| 70 | + Keyboard.release(key0); |
| 71 | + key0on = false; |
| 72 | + } |
| 73 | +} |
| 74 | + |
| 75 | +void keyb1() { |
| 76 | + if (key1on == false && Analog1 > act1) { |
| 77 | + Keyboard.press(key1); |
| 78 | + key1on = true; |
| 79 | + } else if (key1on == true && Analog1 < act1) { |
| 80 | + Keyboard.release(key1); |
| 81 | + key1on = false; |
| 82 | + } |
| 83 | +} |
| 84 | + |
| 85 | + |
| 86 | + |
| 87 | +void keyrt0() { |
| 88 | + if (!key0on) { |
| 89 | + if (Analog0 > act0 && Analog0 - RTL0 > RTR0) { |
| 90 | + Keyboard.press(key0); |
| 91 | + key0on = true; |
| 92 | + }; |
| 93 | + if (RTL0 > Analog0) { |
| 94 | + RTL0 = Analog0; |
| 95 | + }; |
| 96 | + } else { |
| 97 | + if (RTL0 - Analog0 > RTR0) { |
| 98 | + Keyboard.release(key0); |
| 99 | + key0on = false; |
| 100 | + }; |
| 101 | + if (RTL0 < Analog0) { |
| 102 | + RTL0 = Analog0; |
| 103 | + }; |
| 104 | + }; |
| 105 | +} |
| 106 | + |
| 107 | +void keyrt1() { |
| 108 | + if (!key1on) { |
| 109 | + if (Analog1 > act1 && Analog1 - RTL1 > RTR1) { |
| 110 | + Keyboard.press(key1); |
| 111 | + key1on = true; |
| 112 | + }; |
| 113 | + if (RTL1 > Analog1) { |
| 114 | + RTL1 = Analog1; |
| 115 | + }; |
| 116 | + } else { |
| 117 | + if (RTL1 - Analog1 > RTR1) { |
| 118 | + Keyboard.release(key1); |
| 119 | + key1on = false; |
| 120 | + }; |
| 121 | + if (RTL1 < Analog1) { |
| 122 | + RTL1 = Analog1; |
| 123 | + }; |
| 124 | + }; |
| 125 | +} |
| 126 | + |
| 127 | +//function for configuring ports or pins, note that this will not use the same pin numbering scheme as Arduino |
| 128 | + |
| 129 | +void readKey0() { |
| 130 | + |
| 131 | + ADC->INPUTCTRL.reg = ADC_INPUTCTRL_GAIN_DIV2 | ADC_INPUTCTRL_MUXNEG_GND | ADC_INPUTCTRL_MUXPOS_PIN0; |
| 132 | + |
| 133 | + /* Start the ADC using a software trigger. */ |
| 134 | + ADC->SWTRIG.bit.START = true; |
| 135 | + |
| 136 | + /* Wait for the result ready flag to be set. */ |
| 137 | + while (ADC->INTFLAG.bit.RESRDY == 0) |
| 138 | + ; |
| 139 | + |
| 140 | + /* Clear the flag. */ |
| 141 | + ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY; |
| 142 | + |
| 143 | + /* Read the value. */ |
| 144 | + if (PA0 != ADC->RESULT.reg) { |
| 145 | + Analog0 = int(a0 * (ADC->RESULT.reg - min0)); |
| 146 | + if (RapidTrigger) { |
| 147 | + keyrt0(); |
| 148 | + } else { |
| 149 | + keyb0(); |
| 150 | + }; |
| 151 | + ; |
| 152 | + }; |
| 153 | + PA0 = ADC->RESULT.reg; |
| 154 | +} |
| 155 | + |
| 156 | + |
| 157 | + |
| 158 | +void readKey1() { |
| 159 | + |
| 160 | + ADC->INPUTCTRL.reg = ADC_INPUTCTRL_GAIN_DIV2 | ADC_INPUTCTRL_MUXNEG_GND | ADC_INPUTCTRL_MUXPOS_PIN2; |
| 161 | + |
| 162 | + /* Start the ADC using a software trigger. */ |
| 163 | + ADC->SWTRIG.bit.START = true; |
| 164 | + |
| 165 | + /* Wait for the result ready flag to be set. */ |
| 166 | + while (ADC->INTFLAG.bit.RESRDY == 0) |
| 167 | + ; |
| 168 | + |
| 169 | + /* Clear the flag. */ |
| 170 | + ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY; |
| 171 | + |
| 172 | + /* Read the value. */ |
| 173 | + if (PA1 != ADC->RESULT.reg) { |
| 174 | + Analog1 = int(a1 * (ADC->RESULT.reg - min1)); |
| 175 | + if (RapidTrigger) { |
| 176 | + keyrt1(); |
| 177 | + } else { |
| 178 | + keyb1(); |
| 179 | + }; |
| 180 | + ; |
| 181 | + }; |
| 182 | + PA1 = ADC->RESULT.reg; |
| 183 | +} |
| 184 | + |
| 185 | + |
| 186 | + |
| 187 | + |
| 188 | +void genericClockSetup(int clk, int dFactor) { |
| 189 | + // Enable the APBC clock for the ADC |
| 190 | + REG_PM_APBCMASK |= PM_APBCMASK_ADC; |
| 191 | + |
| 192 | + //This allows you to setup a div factor for the selected clock certain clocks allow certain division factors: Generic clock generators 3 - 8 8 division factor bits - DIV[7:0] |
| 193 | + GCLK->GENDIV.reg |= GCLK_GENDIV_ID(clk) | GCLK_GENDIV_DIV(dFactor); |
| 194 | + while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) |
| 195 | + ; |
| 196 | + |
| 197 | + //configure the generator of the generic clock with 48MHz clock |
| 198 | + GCLK->GENCTRL.reg |= GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID(clk); // GCLK_GENCTRL_DIVSEL don't need this, it makes divide based on power of two |
| 199 | + while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) |
| 200 | + ; |
| 201 | + |
| 202 | + //enable clock, set gen clock number, and ID to where the clock goes (30 is ADC) |
| 203 | + GCLK->CLKCTRL.reg |= GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(clk) | GCLK_CLKCTRL_ID(30); |
| 204 | + while (GCLK->STATUS.bit.SYNCBUSY) |
| 205 | + ; |
| 206 | +} |
| 207 | + |
| 208 | + |
| 209 | +void PortSetup() { |
| 210 | + /* Set PB09 as an input pin. */ |
| 211 | + PORT->Group[1].DIRCLR.reg = PORT_PA02; |
| 212 | + |
| 213 | + /* Enable the peripheral multiplexer for PB09. */ |
| 214 | + PORT->Group[1].PINCFG[9].reg |= PORT_PINCFG_PMUXEN; |
| 215 | + |
| 216 | + /* Set PB09 to function B which is analog input. */ |
| 217 | + PORT->Group[1].PMUX[4].reg = PORT_PMUX_PMUXO_B; |
| 218 | + |
| 219 | + |
| 220 | + /* Set PB09 as an input pin. */ |
| 221 | + PORT->Group[1].DIRCLR.reg = PORT_PB08; |
| 222 | + |
| 223 | + /* Enable the peripheral multiplexer for PB09. */ |
| 224 | + PORT->Group[1].PINCFG[9].reg |= PORT_PINCFG_PMUXEN; |
| 225 | + |
| 226 | + /* Set PB09 to function B which is analog input. */ |
| 227 | + PORT->Group[1].PMUX[4].reg = PORT_PMUX_PMUXO_B; |
| 228 | +} |
| 229 | + |
| 230 | + |
| 231 | + |
| 232 | +void ADCSetup() { |
| 233 | + |
| 234 | + |
| 235 | + |
| 236 | + |
| 237 | + uint32_t bias = (*((uint32_t *)ADC_FUSES_BIASCAL_ADDR) & ADC_FUSES_BIASCAL_Msk) >> ADC_FUSES_BIASCAL_Pos; |
| 238 | + uint32_t linearity = (*((uint32_t *)ADC_FUSES_LINEARITY_0_ADDR) & ADC_FUSES_LINEARITY_0_Msk) >> ADC_FUSES_LINEARITY_0_Pos; |
| 239 | + linearity |= ((*((uint32_t *)ADC_FUSES_LINEARITY_1_ADDR) & ADC_FUSES_LINEARITY_1_Msk) >> ADC_FUSES_LINEARITY_1_Pos) << 5; |
| 240 | + |
| 241 | + /* Wait for bus synchronization. */ |
| 242 | + while (ADC->STATUS.bit.SYNCBUSY) {}; |
| 243 | + |
| 244 | + /* Write the calibration data. */ |
| 245 | + ADC->CALIB.reg = ADC_CALIB_BIAS_CAL(bias) | ADC_CALIB_LINEARITY_CAL(linearity); |
| 246 | + |
| 247 | + |
| 248 | + |
| 249 | + while (ADC->STATUS.bit.SYNCBUSY) {}; |
| 250 | + |
| 251 | + /* Use the internal VCC reference. This is 1/2 of what's on VCCA. |
| 252 | + since VCCA is typically 3.3v, this is 1.65v. |
| 253 | +*/ |
| 254 | + ADC->REFCTRL.reg = ADC_REFCTRL_REFSEL_INTVCC1; |
| 255 | + |
| 256 | + /* Only capture one sample. The ADC can actually capture and average multiple |
| 257 | + samples for better accuracy, but there's no need to do that for this |
| 258 | + example. |
| 259 | +*/ |
| 260 | + ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1; |
| 261 | + |
| 262 | + /* Set the clock prescaler to 512, which will run the ADC at |
| 263 | + 8 Mhz / 512 = 31.25 kHz. |
| 264 | + Set the resolution to 12bit. |
| 265 | +*/ |
| 266 | + if (res == 8) { |
| 267 | + ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV4 | ADC_CTRLB_RESSEL_8BIT; |
| 268 | + } else if (res == 10) { |
| 269 | + ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV4 | ADC_CTRLB_RESSEL_10BIT; |
| 270 | + } else if (res == 12) { |
| 271 | + ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV4 | ADC_CTRLB_RESSEL_12BIT; |
| 272 | + } else { |
| 273 | + Serial.println("Unsupported resolution, change the value res to 8 10 or 12"); |
| 274 | + }; |
| 275 | + |
| 276 | + /* Configure the input parameters. |
| 277 | +
|
| 278 | + - GAIN_DIV2 means that the input voltage is halved. This is important |
| 279 | + because the voltage reference is 1/2 of VCCA. So if you want to |
| 280 | + measure 0-3.3v, you need to halve the input as well. |
| 281 | +
|
| 282 | + - MUXNEG_GND means that the ADC should compare the input value to GND. |
| 283 | +
|
| 284 | + - MUXPOST_PIN3 means that the ADC should read from AIN3, or PB09. |
| 285 | + This is A2 on the Feather M0 board. |
| 286 | +*/ |
| 287 | + |
| 288 | + |
| 289 | + |
| 290 | + while (ADC->STATUS.bit.SYNCBUSY) {}; |
| 291 | + |
| 292 | + /* Enable the ADC. */ |
| 293 | + ADC->CTRLA.bit.ENABLE = true; |
| 294 | +} |
| 295 | + |
| 296 | + |
0 commit comments