From 3181ce710456048706521ad51874c88991b80d48 Mon Sep 17 00:00:00 2001 From: Duncan Wilkie Date: Sun, 13 Aug 2023 23:20:03 -0500 Subject: Main now handles slaves. --- controller/src/main.c | 189 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 172 insertions(+), 17 deletions(-) (limited to 'controller/src/main.c') 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 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? } -- cgit v1.2.3