Skip to content

Commit 26b61fc

Browse files
authored
Add files via upload
1 parent 9515475 commit 26b61fc

File tree

1 file changed

+296
-0
lines changed

1 file changed

+296
-0
lines changed

BexiPad.ino

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
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

Comments
 (0)