Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add uart flow control (take 2) #41

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
73 changes: 51 additions & 22 deletions firmware/app_layer_v1/features.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ static void PinsInit() {
SetPinDigitalIn(i, 0); // all other pins: input, no-pull
}
for (i = 0; i < NUM_UART_MODULES; ++i) {
SetPinUart(0, i, 0, 0); // UART RX disabled
SetPinUart(0, i, 0, 0, 0); // UART RX disabled
// Why isn't TX reset?
SetPinUart(0, i, 0, 1, 0); // UART CTS disabled
SetPinUart(0, i, 1, 1, 0); // UART RTS disabled
}
// clear and enable global CN interrupts
_CNIF = 0;
Expand Down Expand Up @@ -110,33 +113,59 @@ void SetPinPwm(int pin, int pwm_num, int enable) {
PinSetRpor(pin, enable ? (pwm_num == 8 ? 35 : 18 + pwm_num) : 0);
}

void SetPinUart(int pin, int uart_num, int dir, int enable) {
log_printf("SetPinUart(%d, %d, %d, %d)", pin, uart_num, dir, enable);
void SetPinUart(int pin, int uart_num, int dir, int flow, int enable) {
log_printf("SetPinUart(%d, %d, %d, %d, %d)", pin, uart_num, dir, flow, enable);
SAVE_PIN_FOR_LOG(pin);
SAVE_UART_FOR_LOG(uart_num);
if (dir) {
// TX
const BYTE rp[] = { 3, 5, 28, 30 };
PinSetRpor(pin, enable ? rp[uart_num] : 0);
if (!flow) {
if (dir) {
// TX
const BYTE rp[] = { 3, 5, 28, 30 };
PinSetRpor(pin, enable ? rp[uart_num] : 0);
} else {
// RX
int rpin = enable ? PinToRpin(pin) : 0x3F;
switch (uart_num) {
case 0:
_U1RXR = rpin;
break;

case 1:
_U2RXR = rpin;
break;

case 2:
_U3RXR = rpin;
break;

case 3:
_U4RXR = rpin;
break;
}
}
} else {
// RX
int rpin = enable ? PinToRpin(pin) : 0x3F;
switch (uart_num) {
case 0:
_U1RXR = rpin;
break;
if (dir) { // RTS output
const BYTE rp[] = { 4, 6, 29, 31 };
PinSetRpor(pin, enable ? rp[uart_num] : 0);
} else { // CTS input
int rpin = enable ? PinToRpin(pin) : 0x3F;
switch (uart_num) {
case 0:
_U1CTSR = rpin;
break;

case 1:
_U2RXR = rpin;
break;
case 1:
_U2CTSR = rpin;
break;

case 2:
_U3RXR = rpin;
break;
case 2:
_U3CTSR = rpin;
break;

case 3:
_U4RXR = rpin;
break;
case 3:
_U4CTSR = rpin;
break;
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion firmware/app_layer_v1/features.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void SetPinDigitalOut(int pin, int value, int open_drain);
void SetPinDigitalIn(int pin, int pull);
void SetPinAnalogIn(int pin);
void SetPinPwm(int pin, int pwm_num, int enable);
void SetPinUart(int pin, int uart_num, int dir, int enable);
void SetPinUart(int pin, int uart_num, int dir, int flow, int enable);
void SetPinSpi(int pin, int spi_num, int mode, int enable);
void SetPinInCap(int pin, int incap_num, int enable);
void HardReset();
Expand Down
4 changes: 3 additions & 1 deletion firmware/app_layer_v1/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,8 @@ static BOOL MessageDone() {
rx_msg.args.uart_config.rate,
rx_msg.args.uart_config.speed4x,
rx_msg.args.uart_config.two_stop_bits,
rx_msg.args.uart_config.parity);
rx_msg.args.uart_config.parity,
rx_msg.args.uart_config.flow);
break;

case SET_PIN_UART:
Expand All @@ -344,6 +345,7 @@ static BOOL MessageDone() {
SetPinUart(rx_msg.args.set_pin_uart.pin,
rx_msg.args.set_pin_uart.uart_num,
rx_msg.args.set_pin_uart.dir,
rx_msg.args.set_pin_uart.flow,
rx_msg.args.set_pin_uart.enable);
break;

Expand Down
12 changes: 10 additions & 2 deletions firmware/app_layer_v1/protocol_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,19 @@ typedef struct PACKED {
BYTE data[0];
} UART_DATA_ARGS;

typedef enum {
FLOW_NONE,
FLOW_IRDA,
FLOW_RTSCTS,
FLOW_RS485,
} UART_FLOW_MODE;

// uart config
typedef struct PACKED {
BYTE parity : 2;
BYTE two_stop_bits : 1;
BYTE speed4x : 1;
BYTE : 2;
BYTE flow : 2;
BYTE uart_num : 2;
WORD rate;
} UART_CONFIG_ARGS;
Expand All @@ -182,7 +189,8 @@ typedef struct PACKED {
BYTE pin : 6;
BYTE : 2;
BYTE uart_num : 2;
BYTE : 4;
BYTE : 3;
BYTE flow : 1;
BYTE dir : 1;
BYTE enable : 1;
} SET_PIN_UART_ARGS;
Expand Down
22 changes: 13 additions & 9 deletions firmware/app_layer_v1/uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,13 @@ DEFINE_REG_SETTERS_1B(NUM_UART_MODULES, _U, TXIE)
DEFINE_REG_SETTERS_1B(NUM_UART_MODULES, _U, TXIF)
DEFINE_REG_SETTERS_1B(NUM_UART_MODULES, _U, TXIP)

static void UARTConfigInternal(int uart_num, int rate, int speed4x, int two_stop_bits, int parity, int external);
static void UARTConfigInternal(int uart_num, int rate, int speed4x, int two_stop_bits, int parity,
int flow_mode, int external);

void UARTInit() {
int i;
for (i = 0; i < NUM_UART_MODULES; ++i) {
UARTConfigInternal(i, 0, 0, 0, 0, 0);
UARTConfigInternal(i, 0, 0, 0, 0, 0, 0);
Set_URXIP[i](4); // RX int. priority 4
Set_UTXIP[i](4); // TX int. priority 4
}
Expand All @@ -83,12 +84,15 @@ static inline void UARTSendStatus(int uart_num, int enabled) {
AppProtocolSendMessage(&msg);
}

static void UARTConfigInternal(int uart_num, int rate, int speed4x, int two_stop_bits, int parity, int external) {
static void UARTConfigInternal(int uart_num, int rate, int speed4x, int two_stop_bits, int parity,
int flow_mode, int external) {
volatile UART* regs = uart_reg[uart_num];
UART_STATE* uart = &uarts[uart_num];
// for irda, idle state is 0 for both RX and TX (i.e. for TFBS4711)
const int flow_map[] = {0x0000, 0x1010, 0x0200, 0x0a00}; // none, irda, rtscts, rs485/simplex
if (external) {
log_printf("UARTConfig(%d, %d, %d, %d, %d)", uart_num, rate, speed4x,
two_stop_bits, parity);
log_printf("UARTConfig(%d, %d, %d, %d, %d, %d)", uart_num, rate, speed4x,
two_stop_bits, parity, flow_mode);
}
SAVE_UART_FOR_LOG(uart_num);
Set_URXIE[uart_num](0); // disable RX int.
Expand All @@ -106,7 +110,8 @@ static void UARTConfigInternal(int uart_num, int rate, int speed4x, int two_stop
Set_URXIF[uart_num](0); // clear RX int.
Set_UTXIF[uart_num](0); // clear TX int.
Set_URXIE[uart_num](1); // enable RX int.
regs->uxmode = 0x8000 | (speed4x ? 0x0008 : 0x0000) | two_stop_bits | (parity << 1); // enable
regs->uxmode = 0x8000 | flow_map[flow_mode & 0x3] \
| (speed4x ? 0x0008 : 0x0000) | two_stop_bits | (parity << 1); // enable
regs->uxsta = 0x8400; // IRQ when TX buffer is empty, enable TX, IRQ when character received.
uart->num_tx_since_last_report = TX_BUF_SIZE;
} else {
Expand All @@ -116,8 +121,8 @@ static void UARTConfigInternal(int uart_num, int rate, int speed4x, int two_stop
}
}

void UARTConfig(int uart_num, int rate, int speed4x, int two_stop_bits, int parity) {
UARTConfigInternal(uart_num, rate, speed4x, two_stop_bits, parity, 1);
void UARTConfig(int uart_num, int rate, int speed4x, int two_stop_bits, int parity, int flow_mode) {
UARTConfigInternal(uart_num, rate, speed4x, two_stop_bits, parity, flow_mode, 1);
}


Expand Down Expand Up @@ -225,4 +230,3 @@ void UARTTransmit(int uart_num, const void* data, int size) {
#if NUM_UART_MODULES >= 4
DEFINE_INTERRUPT_HANDLERS(4)
#endif

2 changes: 1 addition & 1 deletion firmware/app_layer_v1/uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

void UARTInit();
void UARTConfig(int uart_num, int rate, int speed4x, int two_stop_bits,
int parity);
int parity, int flow_mode);
void UARTTransmit(int uart_num, const void* data, int size);
void UARTTasks();

Expand Down
33 changes: 29 additions & 4 deletions software/IOIOLib/src/ioio/lib/api/IOIO.java
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,17 @@ public PulseInput openPulseInput(int pin, PulseMode mode)
* The parity mode, as in {@link Parity}.
* @param stopbits
* Number of stop bits, as in {@link StopBits}.
* @param mode
* Flow control mode, as in {@link FlowMode}. This can by FLOW_NONE,
* FLOW_IRDA, FLOW_RTSCTS, or FLOW_RS485.
* @param rts
* Pin number specification for the RTS (Request To Send) output pin.
* If the flow control mode is not FLOW_RTSCTS or FLOW_RS485, then
* this parameter is ignored.
* @param cts
* Pin number specification for the CTS (Clear To Send) input pin.
* If the flow control mode is not FLOW_RTSCTS or FLOW_RS485, then
* this parameter is ignored.
* @return Interface of the assigned module.
* @throws ConnectionLostException
* Connection was lost before or during the execution of this
Expand All @@ -496,20 +507,34 @@ public PulseInput openPulseInput(int pin, PulseMode mode)
* @see Uart
*/
public Uart openUart(DigitalInput.Spec rx, DigitalOutput.Spec tx, int baud,
Parity parity, StopBits stopbits) throws ConnectionLostException;
Parity parity, StopBits stopbits, Uart.FlowMode mode, DigitalOutput.Spec rts,
DigitalInput.Spec cts) throws ConnectionLostException;

/**
* Shorthand for
* {@link #openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, Uart.StopBits)}
* {@link #openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, Uart.StopBits, Uart.FlowMode, DigitalOutput.Spec, DigitalInput.Spec)}
* , where the input pins use their default specs. {@link #INVALID_PIN} can
* be used on either pin if a TX- or RX-only UART is needed.
* be used on either pin if a TX- or RX-only UART is needed. The flow mode is FLOW_NONE.
*
* @see #openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity,
* Uart.StopBits)
* Uart.StopBits, Uart.FlowMode, DigitalOutput.Spec, DigitalInput.Spec)
*/
public Uart openUart(int rx, int tx, int baud, Parity parity,
StopBits stopbits) throws ConnectionLostException;

/**
* Shorthand for
* {@link #openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, Uart.StopBits, Uart.FlowMode, DigitalOutput.Spec, DigitalInput.Spec)}
* , where the input pins use their default specs. {@link #INVALID_PIN} can
* be used on either pin if a TX- or RX-only UART is needed.
*
* @see #openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity,
* Uart.StopBits, Uart.FlowMode, DigitalOutput.Spec, DigitalInput.Spec)
*/
public Uart openUart(int rx, int tx, int baud, Uart.Parity parity,
Uart.StopBits stopbits, Uart.FlowMode mode, int rts,
int cts) throws ConnectionLostException;

/**
* Open a SPI master module, enabling communication with multiple
* SPI-enabled slave modules.
Expand Down
17 changes: 15 additions & 2 deletions software/IOIOLib/src/ioio/lib/api/Uart.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
* asynchronous point-to-point data transfer. It typically serves for opening
* consoles or as a basis for higher-level protocols, such as MIDI, RS-232 and
* RS-485. Uart instances are obtained by calling
* {@link IOIO#openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, Uart.StopBits)}.
* {@link IOIO#openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, Uart.StopBits, Uart.FlowMode, DigitalOutput.Spec, DigitalInput.Spec)}.
* <p>
* The UART protocol is completely symmetric - there is no "master" and "slave"
* at this layer. Each end may send any number of bytes at arbitrary times,
Expand Down Expand Up @@ -70,7 +70,7 @@
* </pre>
*
* @see IOIO#openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity,
* Uart.StopBits)
* Uart.StopBits, Uart.FlowMode, DigitalOutput.Spec, DigitalInput.Spec)
*/
public interface Uart extends Closeable {
/** Parity-bit mode. */
Expand All @@ -91,6 +91,19 @@ enum StopBits {
TWO
}

/** Flow control line modes */
enum FlowMode {
/** No flow control. */
NONE,
/** Use IRDA encode/decode and no flow control. */
IRDA,
/** Use RTS/CTS lines for flow control. */
RTSCTS,
/** Raise RTS when transmitting (for RS-485 transmit enable).
Note that CTS should be connected to RTS. */
RS485,
}

/**
* Gets the input stream.
*
Expand Down
Loading