diff --git a/src/board/arduino/mega2560/parallel.c b/src/board/arduino/mega2560/parallel.c index 7b6d6ea..8880390 100644 --- a/src/board/arduino/mega2560/parallel.c +++ b/src/board/arduino/mega2560/parallel.c @@ -3,61 +3,43 @@ #include #include +#include +#include #include -// See http://efplus.com/techref/io/parallel/1284/eppmode.htm -struct ParallelPins { - // Data (KSO0 - KSO7) - bi-directional - uint8_t d0; - uint8_t d1; - uint8_t d2; - uint8_t d3; - uint8_t d4; - uint8_t d5; - uint8_t d6; - uint8_t d7; - // Wait# (KSO9) - input - // low to indicate cycle may begin, high to indicate cycle may end - uint8_t wait_n; - // Write# (KSI0) - output - // low to indicate write cycle, high to indicate read cycle - uint8_t write_n; - // DataStrobe# (KSI1) - output - // low indicates a data cycle - uint8_t data_n; - // Reset# (KSI2) - output - // low requests device reset - uint8_t reset_n; - // AddressStrobe# (KSI3) - output - // low indicates an address cycle - uint8_t addr_n; - // Strap0 (KSI4) - // 1K-Ohm pull-down resistor - uint8_t strap_0; - // Strap1 (KSI5) - // 1K-Ohm pull-down resistor - uint8_t strap_1; -}; - // Mapping of 24-pin ribbon cable to parallel pins. See schematic -static struct ParallelPins pins = { - .d0 = 1, - .d1 = 2, - .d2 = 3, - .d3 = 7, - .d4 = 9, - .d5 = 10, - .d6 = 13, - .d7 = 16, - .wait_n = 18, - .write_n = 4, - .data_n = 5, - .reset_n = 6, - .addr_n = 8, - .strap_0 = 11, - .strap_1 = 12, -}; +#define PINS \ + /* Data (KSO0 - KSO7) - bi-directional */ \ + PIN(d0, 1) \ + PIN(d1, 2) \ + PIN(d2, 3) \ + PIN(d3, 7) \ + PIN(d4, 9) \ + PIN(d5, 10) \ + PIN(d6, 13) \ + PIN(d7, 16) \ + /* Wait# (KSO9) - input */ \ + /* low to indicate cycle may begin, high to indicate cycle may end */ \ + PIN(wait_n, 18) \ + /* Write# (KSI0) - output */ \ + /* low to indicate write cycle, high to indicate read cycle */ \ + PIN(write_n, 4) \ + /* DataStrobe# (KSI1) - output */ \ + /* low indicates a data cycle */ \ + PIN(data_n, 5) \ + /* Reset# (KSI2) - output */ \ + /* low requests device reset */ \ + PIN(reset_n, 6) \ + /* AddressStrobe# (KSI3) - output */ \ + /* low indicates an address cycle */ \ + PIN(addr_n, 8) \ + /* Strap0 (KSI4) */ \ + /* 1K-Ohm pull-down resistor */ \ + PIN(strap_0, 11) \ + /* Strap1 (KSI5) */ \ + /* 1K-Ohm pull-down resistor */ \ + PIN(strap_1, 12) // Mapping of 24-pin ribbon cable to GPIOs static struct Gpio gpios[24] = { @@ -75,27 +57,141 @@ static struct Gpio gpios[24] = { GPIO(C, 7), GPIO(C, 6) }; -#define PIN_GPIO(N) \ - struct Gpio * N = NULL; \ - if (pins.N > 0 && pins.N < 24) N = &gpios[pins.N - 1]; \ - if (!N) return; \ - gpio_set_dir(N, false); \ - gpio_set(N, false); +// Parallel struct definition +// See http://efplus.com/techref/io/parallel/1284/eppmode.htm +struct Parallel { + #define PIN(N, P) struct Gpio * N; + PINS + #undef PIN +}; + +// Set port to all high-impedance inputs +void parallel_hiz(struct Parallel * port) { + #define PIN(N, P) \ + gpio_set_dir(port->N, false); \ + gpio_set(port->N, false); + PINS + #undef PIN +} + +// Set port to initial state required before being able to perform cycles +void parallel_reset(struct Parallel * port) { + parallel_hiz(port); + + // Set reset line low + gpio_set_dir(port->reset_n, true); + + // Wait 5 microseconds + _delay_us(5); + + // Make sure strobes are high outputs + gpio_set(port->data_n, true); + gpio_set(port->addr_n, true); + gpio_set_dir(port->data_n, true); + gpio_set_dir(port->addr_n, true); + + // Set write line high output + gpio_set(port->write_n, true); + gpio_set_dir(port->write_n, true); + + // Pull up wait line + gpio_set(port->wait_n, true); + + //TODO: something with straps + + // Wait 5 microseconds + _delay_us(5); + + // Set reset line high, ending reset + gpio_set(port->reset_n, true); +} + +#define DATA_BITS \ + DATA_BIT(0) \ + DATA_BIT(1) \ + DATA_BIT(2) \ + DATA_BIT(3) \ + DATA_BIT(4) \ + DATA_BIT(5) \ + DATA_BIT(6) \ + DATA_BIT(7) + +//TODO: address cycle, read cycle, timeout +int parallel_transaction(struct Parallel * port, uint8_t * data, int length, bool read, bool addr) { + int i; + for (i = 0; i < length; i++) { + // Wait for wait line to be low + while (gpio_get(port->wait_n)) {} + + // Set write line + gpio_set(port->write_n, read); + + if (!read) { + // Set data + uint8_t byte = data[i]; + #define DATA_BIT(B) \ + gpio_set(port->d ## B, (byte & (1 << B)) > 0); \ + gpio_set_dir(port->d ## B, true); + DATA_BITS + #undef DATA_BIT + } + + // Wait 5 microseconds + _delay_us(5); + + if (addr) { + // Set address strobe low + gpio_set(port->addr_n, false); + } else { + // Set data strobe low + gpio_set(port->data_n, false); + } + + // Wait for wait line to be high + while (!gpio_get(port->wait_n)) {} + + if (read) { + uint8_t byte = 0; + #define DATA_BIT(B) \ + if (gpio_get(port->d ## B)) byte |= (1 << B); + DATA_BITS + #undef DATA_BIT + data[i] = byte; + } + + if (addr) { + // Set address strobe high + gpio_set(port->addr_n, true); + } else { + // Set data strobe high + gpio_set(port->data_n, true); + } + + // Wait 5 microseconds + _delay_us(5); + + // Reset data lines to high impedance inputs + #define DATA_BIT(B) \ + gpio_set_dir(port->d ## B, false); \ + gpio_set(port->d ## B, false); + DATA_BITS + #undef DATA_BIT + + // Set write line high + gpio_set(port->data_n, true); + } + + return i; +} + +// Parallel struct instance +static struct Parallel PORT = { + #define PIN(N, P) .N = &gpios[P - 1], + PINS + #undef PIN +}; void parallel(void) { - PIN_GPIO(d0); - PIN_GPIO(d1); - PIN_GPIO(d2); - PIN_GPIO(d3); - PIN_GPIO(d4); - PIN_GPIO(d5); - PIN_GPIO(d6); - PIN_GPIO(d7); - PIN_GPIO(wait_n); - PIN_GPIO(write_n); - PIN_GPIO(data_n); - PIN_GPIO(reset_n); - PIN_GPIO(addr_n); - PIN_GPIO(strap_0); - PIN_GPIO(strap_1); + struct Parallel * port = &PORT; + parallel_hiz(port); }