Implement EPP protocol
This commit is contained in:
parent
f220046ce2
commit
6c70fa0752
@ -3,61 +3,43 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <board/cpu.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
#include <arch/gpio.h>
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user