summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDuncan Wilkie <antigravityd@gmail.com>2023-08-13 23:20:03 -0500
committerDuncan Wilkie <antigravityd@gmail.com>2023-08-13 23:20:03 -0500
commit3181ce710456048706521ad51874c88991b80d48 (patch)
tree65fb6d55492fc746f294546a7095387e2a99600e
parent0a35e7d7be87baedc193644342ef1636940fba1e (diff)
Main now handles slaves.HEADmaster
-rw-r--r--controller/src/main.c189
1 files changed, 172 insertions, 17 deletions
diff --git a/controller/src/main.c b/controller/src/main.c
index a5f47c4..320f7c6 100644
--- a/controller/src/main.c
+++ b/controller/src/main.c
@@ -7,7 +7,7 @@
#include "inc/hw_uart.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
-
+#include <math.h>
void UART1IntHandler(void) {
UARTIntClear(UART1_BASE, UART_INT_RX);
@@ -29,22 +29,169 @@ static bool quit_parsing(uint8_t) { // TODO: fix library parsers so this works.
}
-bool note_on_flag = false;
+typedef struct {
+ uint8_t head;
+ uint16_t array[256];
+} AxisRingbuf;
+
+inline void ringbuf_advance(AxisRingbuf f) {
+ f.array[head] = 0;
+ ++f.head;
+}
+
+inline void ringbuf_set(AxisRingbuf f, uint8_t idx, uint16_t val) {
+ f.array[head + idx] = val;
+}
+
+inline uint16_t ringbuf_get(AxisRingbuf f, unit8_t idx) {
+ return f.array[head + idx];
+}
+
+typedef struct {
+ bool expecting_type;
+ uint8_t received_type;
+ AxisRingbuf outstanding_presses;
+} AxisParse;
+
+bool clock_high = false;
+uint32_t clock_count = 0;
+uint8_t preparing_row_byte = 0;
+uint8_t preparing_col_byte = 0;
+
+AxisParse column = {true, 0, {0, {0}}};
+AxisParse row = {true, 0, {0, {0}}};
+
+
+typedef struct {
+ uint8_t column;
+ uint8_t row;
+ uint32_t clock_count;
+} Keypress;
+
+typedef struct {
+ uint8_t head;
+ Keypress presses[32];
+} PressBuffer;
+
+PressBuffer outstanding;
+
+void press_add(uint8_t column, uint8_t row) {
+ outstanding.presses[outstanding.head + 31 % 32] = {column, row, clock_count};
+}
+
+uint32_t press_search(uint8_t column, uint8_t row) {
+ for (int i = 0; i < 32; i++) {
+ Keypress test = outstanding.presses[outstanding.head + i % 32];
+ if (test.column == column && test.row == row)
+ return clock_count - test.clock_count;
+ }
+
+ return 0;
+
+}
+
+void press_advance() {
+ outstanding.presses[outstanding.head] = 0;
+ if (outstanding.head == 31)
+ outstanding.head = 0;
+ else
+ ++outstanding.head;
+}
+
-void button_handler(void) {
- GPIOIntClear(GPIO_PORTF_BASE, GPIO_INT_PIN_4);
- if (!note_on_flag) {
- note_on(0x02, 0x40, 0x40);
- note_on_flag = true;
+#define KEY_PRESSED 0b1000'0000
+#define KEY_RELEASED 0b1010'0000
+#define VEL_PRESSED 0b1100'0000
+#define VEL_RELEASED 0b1110'0000
+double uint32_to_uint7 = 1.0 * 127 / UINT32_MAX;
+void key_handler(uint8_t type, uint8_t column, uint8_t row) {
+ switch (type) {
+ case KEY_PRESSED:
+ press_add(column, row);
+ break;
+ case KEY_RELEASED:
+ note_off(row, column);
+ break;
+ case VEL_PRESSED:
+ // TODO: think about exponential response/timing analysis wrt final hardware.
+ note_on(row, column, floor(uint32_to_uint7 * press_search(column, row) + 0.5));
+ break;
+ case VEL_RELEASED:
+ break; // No release velocity for now.
+ }
+
+ press_advance();
+
+}
+
+void column_handler(uint8_t byte) {
+ if (column.expecting_type) {
+ if (byte > 0b1000'0000) {
+ column.received_type = byte;
+ column.expecting_type = false;
+ }
} else {
- note_off(0x02, 0x40);
- note_on_flag = false;
+ uint16_t corresp = ringbuf_get(row.outstanding_presses, byte - 1);
+ if (coresp >> 8 == column.received_type) // Found other coord.
+ key_handler(column.received_type, byte, (uint8_t)corresp);
+ else
+ ringbuf_set(column.outstanding_presses, byte - 1, (received_type << 8) | byte);
+
+ column.expecting_type = true;
}
+
+ ringbuf_advance(column.outstanding_presses);
+
}
+void row_handler(uint8_t byte) {
+ if (row.expecting_type) {
+ if (byte > 0b1000'0000) {
+ row.received_type = byte;
+ row.expecting_type = false;
+ }
+ } else {
+ uint16_t corresp = ringbuf_get(column.outstanding_presses, byte - 1);
+ if (coresp >> 8 == row.received_type) // Found other coord.
+ key_handler(row.received_type, (uint8_t)corresp, byte);
+ else
+ ringbuf_set(row.outstanding_presses, byte - 1, (received_type << 8) | byte);
+
+ row.expecting_type = true;
+ }
+
+ ringbuf_advance(row.outstanding_presses);
+
+}
+
+void systick_handler(void) {
+ if (clock_high) {
+ uint32_t port_state = GPIOPinRead(GPIO_PORTE_BASE, GPIO_PIN_2 | GPIO_PIN_1);
+ GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_0, 0);
+ uint8_t row_pin_state = (port_state >> GPIO_PIN_1) & 0x01;
+ uint8_t col_pin_state = (port_state >> GPIO_PIN_2) & 0x01;
+ uint8_t bit = clock_count % 8;
+ preparing_row_byte |= (row_pin_state) << bit;
+ preparing_col_byte |= (col_pin_state) << bit;
+ if (bit == 7) {
+ row_handler(preparing_row_byte);
+ column_handler(preparing_column_byte);
+ preparing_row_byte = 0;
+ preparing_column_byte = 0;
+ }
+ ++clock_count;
+ clock_high = false;
+ } else {
+ GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_0, 1);
+ clock_high = true;
+ }
+}
int main() {
+ // Set main clock to 80MHz.
+ SysCtlClockSet(SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_SYSDIV_2_5 | SYSCTL_XTAL_16MHZ);
+
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
// Initialize UART1.
@@ -95,14 +242,22 @@ int main() {
midi_init(new_pfns);
- // Interrupt whenever GPIO pin PF4 changes, due to SW1 button press.
- SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
- GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_4);
- GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD_WPU);
- GPIOIntTypeSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_RISING_EDGE);
- GPIOIntEnable(GPIO_PORTF_BASE, GPIO_INT_PIN_4);
- GPIOIntRegister(GPIO_PORTF_BASE, button_handler);
- while(true); // Main application loop.
+ // Must emulate Atmel's three-wire serial in software with GPIO: we need to count SPI clock cycles.
+ // Uses SysTick to manage both clocks.
+ SysTickPeriodSet(320); // System clock is 80MHz, so for bus clock of 500kHz set to 160---double for both edges.
+ SysTickEnable();
+ SysTickIntEnable();
+ SysTickIntRegister(systick_handler);
+
+ // TODO: understand the various pad config and what is expected by the slaves.
+ GPIOPinTypeGPIOInput(GPIO_PORTE_BASE, GPIO_PIN_0); // Row.
+ GPIOPinTypeGPIOInput(GPIO_PORTE_BASE, GPIO_PIN_1); // Column.
+ GPIOPinTypeGPIOOutput(GPIO_PORTE_BASE, GPIO_PIN_2); // Clock.
+ GPIOPadConfigSet(GPIO_PORTE_BASE, GPIO_PIN_2, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD);
+
+ while(true); // Main application loop.
+ // TODO: think about making slaves dependent on master for power, so resetting master resets slaves.
+ // Possibly cycle a transistor here?
}