#define CAPSENSE_SHIFT_STCP_IO _SFR_IO_ADDR(PORTC)
#define CAPSENSE_SHIFT_STCP_BIT 7
+#define CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE 2
#define CAPSENSE_READ_ROWS_PIN_1 _SFR_IO_ADDR(PIND)
#define CAPSENSE_READ_ROWS_PIN_2 _SFR_IO_ADDR(PIND)
#define CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "in %[dest_row_1], %[ioreg_row_1]\n\tin %[dest_row_2], %[ioreg_row_2]"
+#define CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS \
+ "st %a[arr]+, %[dest_row_1]" "\n\t" \
+ "st %a[arr]+, %[dest_row_2]"
+#define CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS_FAKE \
+ "st %a[arr], %[dest_row_1]" "\n\t" \
+ "st %a[arr], %[dest_row_2]"
#define CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS [dest_row_1] "=&r" (dest_row_1), [dest_row_2] "=&r" (dest_row_2)
#define CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS [ioreg_row_1] "I" (CAPSENSE_READ_ROWS_PIN_1), [ioreg_row_2] "I" (CAPSENSE_READ_ROWS_PIN_2)
#define CAPSENSE_READ_ROWS_LOCAL_VARS uint8_t dest_row_1, dest_row_2
#define CAPSENSE_READ_ROWS_VALUE (dest_row_1 & 0xf)
+#define CAPSENSE_READ_ROWS_EXTRACT_FROM_ARRAY do { dest_row_1 = array[p0++]; dest_row_2 = array[p0++]; } while (0)
+
// Note: for now Beamspring reads PIND twice to match model F timings. We might change that in the future
#define CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row) (row)
#ifndef CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL
#define CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col) (col)
#endif
+
#define CAPSENSE_CONDUCTIVE_PLASTIC_IS_PULLED_UP_ON_KEYPRESS
#elif defined(CONTROLLER_IS_XWHATSIT_MODEL_F_OR_WCASS_MODEL_F)
#define CAPSENSE_SHIFT_STCP_IO _SFR_IO_ADDR(PORTD)
#define CAPSENSE_SHIFT_STCP_BIT 6
+#define CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE 2
#define CAPSENSE_READ_ROWS_PIN_1 _SFR_IO_ADDR(PINC)
#define CAPSENSE_READ_ROWS_PIN_2 _SFR_IO_ADDR(PIND)
#define CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "in %[dest_row_1], %[ioreg_row_1]\n\tin %[dest_row_2], %[ioreg_row_2]"
+#define CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS \
+ "st %a[arr]+, %[dest_row_1]" "\n\t" \
+ "st %a[arr]+, %[dest_row_2]"
+#define CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS_FAKE \
+ "st %a[arr], %[dest_row_1]" "\n\t" \
+ "st %a[arr], %[dest_row_2]"
#define CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS [dest_row_1] "=&r" (dest_row_1), [dest_row_2] "=&r" (dest_row_2)
#define CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS [ioreg_row_1] "I" (CAPSENSE_READ_ROWS_PIN_1), [ioreg_row_2] "I" (CAPSENSE_READ_ROWS_PIN_2)
#define CAPSENSE_READ_ROWS_LOCAL_VARS uint8_t dest_row_1, dest_row_2
#define CAPSENSE_READ_ROWS_VALUE ((dest_row_1 >> 4) | (dest_row_2 << 4))
+#define CAPSENSE_READ_ROWS_EXTRACT_FROM_ARRAY do { dest_row_1 = array[p0++]; dest_row_2 = array[p0++]; } while (0)
#define CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row) (7-(row))
#define CAPSENSE_PHYSICAL_ROW_TO_KEYMAP_ROW(row) (7-(row))
#ifndef CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL
#define CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col) (col)
#endif
+
#define CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS
-#elif defined(CONTROLLER_IS_THROUGHT_HOLE_BEAMSPRING)
+#elif defined(CONTROLLER_IS_THROUGHT_HOLE_BEAMSPRING) || defined(CONTROLLER_IS_THROUGHT_HOLE_MODEL_F)
#define CAPSENSE_DAC_MCP4921
#define CAPSENSE_DAC_NCS F6
#define CAPSENSE_SHIFT_STCP_IO _SFR_IO_ADDR(PORTF)
#define CAPSENSE_SHIFT_STCP_BIT 7
-
-// TODO
// Rows:
// Physical position from left to right: (only the right-most are used for beamspring)
// 1 2 3 4 5 6 7 8
// TH schematic numbering (sense/row lines)
// 8 6 7 5 4 3 2 1
// F5, B5, F4, B4, D4, C6, D1, D0
+
+#if MATRIX_ROWS <= 4
+#define CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE 2
#define CAPSENSE_READ_ROWS_PIN_1 _SFR_IO_ADDR(PINC)
#define CAPSENSE_READ_ROWS_PIN_2 _SFR_IO_ADDR(PIND)
#define CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "in %[dest_row_1], %[ioreg_row_1]\n\tin %[dest_row_2], %[ioreg_row_2]"
+#define CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS \
+ "st %a[arr]+, %[dest_row_1]" "\n\t" \
+ "st %a[arr]+, %[dest_row_2]"
+#define CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS_FAKE \
+ "st %a[arr], %[dest_row_1]" "\n\t" \
+ "st %a[arr], %[dest_row_2]"
#define CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS [dest_row_1] "=&r" (dest_row_1), [dest_row_2] "=&r" (dest_row_2)
#define CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS [ioreg_row_1] "I" (CAPSENSE_READ_ROWS_PIN_1), [ioreg_row_2] "I" (CAPSENSE_READ_ROWS_PIN_2)
#define CAPSENSE_READ_ROWS_LOCAL_VARS uint8_t dest_row_1, dest_row_2
#define CAPSENSE_READ_ROWS_VALUE (((dest_row_1 >> 4) & 0x04) | (dest_row_2 & 0x03) | ((dest_row_2 >> 1) & 0x08))
+#define CAPSENSE_READ_ROWS_EXTRACT_FROM_ARRAY do { dest_row_1 = array[p0++]; dest_row_2 = array[p0++]; } while (0)
+#else
+#define CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE 4
+#define CAPSENSE_READ_ROWS_PIN_1 _SFR_IO_ADDR(PINC)
+#define CAPSENSE_READ_ROWS_PIN_2 _SFR_IO_ADDR(PIND)
+#define CAPSENSE_READ_ROWS_PIN_3 _SFR_IO_ADDR(PINB)
+#define CAPSENSE_READ_ROWS_PIN_4 _SFR_IO_ADDR(PINF)
+#define CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "in %[dest_row_1], %[ioreg_row_1]\n\tin %[dest_row_2], %[ioreg_row_2]\n\tin %[dest_row_3], %[ioreg_row_3]\n\tin %[dest_row_4], %[ioreg_row_4]"
+#define CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS \
+ "st %a[arr]+, %[dest_row_1]" "\n\t" \
+ "st %a[arr]+, %[dest_row_2]" "\n\t" \
+ "st %a[arr]+, %[dest_row_3]" "\n\t" \
+ "st %a[arr]+, %[dest_row_4]"
+#define CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS_FAKE \
+ "st %a[arr], %[dest_row_1]" "\n\t" \
+ "st %a[arr], %[dest_row_2]" "\n\t" \
+ "st %a[arr], %[dest_row_3]" "\n\t" \
+ "st %a[arr], %[dest_row_4]"
+#define CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS [dest_row_1] "=&r" (dest_row_1), [dest_row_2] "=&r" (dest_row_2), [dest_row_3] "=&r" (dest_row_3), [dest_row_4] "=&r" (dest_row_4)
+#define CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS [ioreg_row_1] "I" (CAPSENSE_READ_ROWS_PIN_1), [ioreg_row_2] "I" (CAPSENSE_READ_ROWS_PIN_2), [ioreg_row_3] "I" (CAPSENSE_READ_ROWS_PIN_3), [ioreg_row_4] "I" (CAPSENSE_READ_ROWS_PIN_4)
+#define CAPSENSE_READ_ROWS_LOCAL_VARS uint8_t dest_row_1, dest_row_2, dest_row_3, dest_row_4
+#define CAPSENSE_READ_ROWS_VALUE (((dest_row_1 >> 4) & 0x04) | (dest_row_2 & 0x03) | ((dest_row_2 >> 1) & 0x08) | (dest_row_3 & 0x10) | ((dest_row_3 << 1) & 0x40) | ((dest_row_4 << 1) & 0x20) | ((dest_row_4 << 2) & 0x80))
+#define CAPSENSE_READ_ROWS_EXTRACT_FROM_ARRAY do { dest_row_1 = array[p0++]; dest_row_2 = array[p0++]; dest_row_3 = array[p0++]; dest_row_4 = array[p0++]; } while (0)
+#endif
-#define CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row) (3-(row))
-#define CAPSENSE_PHYSICAL_ROW_TO_KEYMAP_ROW(row) (3-(row))
+#define CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row) (MATRIX_ROWS-1-(row))
+#define CAPSENSE_PHYSICAL_ROW_TO_KEYMAP_ROW(row) (MATRIX_ROWS-1-(row))
#ifndef CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL
#define CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col) (col)
#endif
-//#define CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS
+
+#if defined(CONTROLLER_IS_THROUGHT_HOLE_BEAMSPRING)
#define CAPSENSE_CONDUCTIVE_PLASTIC_IS_PULLED_UP_ON_KEYPRESS
-// TODO END
+#else
+#define CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS
+#endif
#else
#error "Please specify whether the flyplate is pushed down or pulled up on keypress!"
#endif
+/* Notes on Expansion Header:
+
+Pinout:
+--1--O O--2--
+--3--O O--4--
+--5--O O--6--
+
+Pin 1 is always VCC
+Pin 6 in always GND
+
+When using xwhatsit's solenoid controller board,
+pin 2 is connected to the ENABLE input of the current
+limiter, and pin 4 drives the solenoid.
+
+On original xwhatsit controllers:
+pin 2 = PB7
+pin 3 = PB4
+pin 4 = PB6
+pin 5 = PB5
+
+On the TH xwhatsit controller:
+pin 2 = HEADER3 = TXO = PD3
+pin 3 = HEADER1 = D(igital)6 = PD7
+pin 4 = HEADER4 = RXI = PD2
+pin 5 = HEADER2 = D(igital)7 = PE6
+*/
+
+#ifdef USING_SOLENOID_ENABLE_PIN
+// ^^ this must be defined in config.h if you are using and xwhatsit type solenoid
+#endif
+
+
static inline uint8_t read_rows(void)
{
CAPSENSE_READ_ROWS_LOCAL_VARS;
writePin(CAPSENSE_SHIFT_STCP, 0);
}
+void shift_data(uint32_t data)
+{
+ int i;
+ for (i=SHIFT_BITS-1; i>=0; i--)
+ {
+ writePin(CAPSENSE_SHIFT_DIN, (data >> (SHIFT_BITS - 1)) & 1);
+ writePin(CAPSENSE_SHIFT_SHCP, 1);
+ writePin(CAPSENSE_SHIFT_SHCP, 0);
+ data <<= 1;
+ }
+ writePin(CAPSENSE_SHIFT_STCP, 1);
+ writePin(CAPSENSE_SHIFT_STCP, 0);
+}
+
void shift_select_col_no_strobe(uint8_t col)
{
int i;
wait_us(CAPSENSE_KEYBOARD_SETTLE_TIME_US);
}
-// the following function requires storage for 2 * (time + 1) bytes
+// Timing:
+// IN instructions (1 * CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE)
+// Store to array instructions (2 * number of bytes)
+// adiw: 1 cycle
+// cp: 1 cycle
+// cpc: 1 cycle
+// brlo: 2 cycles (when jumping)
+// --- Total loop length:
+// 3 * CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE + 5 cycles
+// first sample elements will be taken after [1..CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE-1] cycles
+// second sample elements will be taken after
+// [3 * CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE + 5 + 1..
+// 3 * CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE + 5 + CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE-1] cycles
+
+// the following function requires storage for CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE * (time + 1) bytes
// but returns valid data only in the first (time + 1) bytes
void test_multiple(uint8_t col, uint16_t time, uint8_t *array)
{
"ldi %B[index], 0" "\n\t"
"cli" "\n\t"
"sbi %[stcp_regaddr], %[stcp_bit]" "\n\t"
- "1:" CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "\n\t"
- "st %a[arr]+, %[dest_row_1]" "\n\t"
- "st %a[arr]+, %[dest_row_2]" "\n\t"
+ "1:" CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "\n\t"
+ CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS "\n\t"
"adiw %A[index], 0x01" "\n\t"
"cp %A[index], %A[time]" "\n\t"
"cpc %B[index], %B[time]" "\n\t"
p0 = p1 = 0;
for (i=0; i<=time; i++)
{
- dest_row_1 = array[p0++];
- dest_row_2 = array[p0++];
+ CAPSENSE_READ_ROWS_EXTRACT_FROM_ARRAY;
array[p1++] = CAPSENSE_READ_ROWS_VALUE;
}
shift_select_nothing();
"ldi %B[index], 0" "\n\t"
"cli" "\n\t"
"sbi %[stcp_regaddr], %[stcp_bit]" "\n\t"
- "1:" CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "\n\t"
- "st %a[arr], %[dest_row_1]" "\n\t"
- "st %a[arr], %[dest_row_2]" "\n\t"
+ "1:" CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "\n\t"
+ CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS_FAKE "\n\t"
"adiw %A[index], 0x01" "\n\t"
"cp %A[index], %A[time]" "\n\t"
"cpc %B[index], %B[time]" "\n\t"
void test_col_print_data_v2(uint8_t col)
{
uprintf("%d: ", col);
- static uint8_t data[NRTIMES*2];
+ static uint8_t data[NRTIMES*CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE];
static uint8_t sums[(TESTATONCE+1) * MATRIX_ROWS];
uint8_t to_time = NRTIMES-1;
uint8_t from_time = 0;
uint8_t row;
for (row=0; row < MATRIX_ROWS; row++)
{
- if (pgm_read_byte(&keymaps[0][row][col]) != KC_NO)
+ if (pgm_read_word(&keymaps[0][row][col]) != KC_NO)
{
valid_physical_rows |= (((matrix_row_t)1) << CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row)); // convert keymap row to physical row
}
uint8_t physical_col = CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col);
uint8_t row;
for (row = 0; row < MATRIX_ROWS; row++) {
- if (pgm_read_byte(&keymaps[0][row][col]) != KC_NO) {
+ if (pgm_read_word(&keymaps[0][row][col]) != KC_NO) {
uint16_t threshold = measure_middle(physical_col, CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row), CAPSENSE_HARDCODED_SAMPLE_TIME, CAPSENSE_CAL_EACHKEY_REPS);
uint8_t besti = 0;
uint16_t best_diff = (uint16_t)abs(threshold - cal_thresholds[besti]);
}
}
for (i=0;i<CAPSENSE_CAL_BINS;i++) {
+ uint16_t bin_signal_level;
if ((cal_thresholds_max[i] == 0xFFFFU) || (cal_thresholds_min[i] == 0xFFFFU)) {
- #ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS
- cal_thresholds[i] += CAPSENSE_CAL_THRESHOLD_OFFSET;
- #else
- cal_thresholds[i] -= CAPSENSE_CAL_THRESHOLD_OFFSET;
- #endif
+ bin_signal_level = cal_thresholds[i];
+ } else {
+ bin_signal_level = (cal_thresholds_max[i] + cal_thresholds_min[i]) / 2;
+ }
+ #ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS
+ if ((bin_signal_level + CAPSENSE_CAL_THRESHOLD_OFFSET) > CAPSENSE_DAC_MAX)
+ {
+ cal_thresholds[i] = CAPSENSE_DAC_MAX;
+ } else {
+ cal_thresholds[i] = bin_signal_level + CAPSENSE_CAL_THRESHOLD_OFFSET;
+ }
+ #else
+ if (bin_signal_level < CAPSENSE_CAL_THRESHOLD_OFFSET)
+ {
+ cal_thresholds[i] = 0;
} else {
- #ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS
- cal_thresholds[i] = (cal_thresholds_max[i] + cal_thresholds_min[i]) / 2 + CAPSENSE_CAL_THRESHOLD_OFFSET;
- #else
- cal_thresholds[i] = (cal_thresholds_max[i] + cal_thresholds_min[i]) / 2 - CAPSENSE_CAL_THRESHOLD_OFFSET;
- #endif
+ cal_thresholds[i] = bin_signal_level - CAPSENSE_CAL_THRESHOLD_OFFSET;
}
+ #endif
}
}
setPinOutput(B0);
writePin(B0, 1);
#endif
+ #ifdef USING_SOLENOID_ENABLE_PIN
+ // ^^ this must be defined in config.h if you are using and xwhatsit type solenoid
+ setPinOutput(USING_SOLENOID_ENABLE_PIN);
+ writePin(USING_SOLENOID_ENABLE_PIN, 1);
+ #endif
}
void matrix_init_custom(void) {