Code: Select all
OSAL_IRQ_HANDLER(TIMER2_COMPA_vect) {
static int8_t i;
/* Data byte.*/
static msg_t byte;
uint8_t bit;
OSAL_IRQ_PROLOGUE();
switch (sds_state) {
case IDLE:
osalSysLockFromISR();
byte = sdRequestDataI(&SDS);
osalSysUnlockFromISR();
if (byte >= Q_OK)
sds_state = TRANSMIT_INIT;
/* Do Nothing.*/
break;
case RECEIVE_INIT:
i = 0;
byte = 0;
sds_state = RECEIVE;
break; /* Break for the initial half period.*/
case RECEIVE:
if (i < sds_bits_per_char) {
byte |= palReadPad(AVR_SDS_RX_PORT, AVR_SDS_RX_PIN) << i;
++i;
} else {
/* If last bit is STOP, then assume info is correct. Otherwise, treat as garbage*/
if (palReadPad(AVR_SDS_RX_PORT, AVR_SDS_RX_PIN)) {
osalSysLockFromISR();
sdIncomingDataI(&SDS, byte);
osalSysUnlockFromISR();
}
sds_state = IDLE;
i = 0;
byte = 0;
}
break;
case TRANSMIT_INIT:
/* Transmit must not be interrupted.*/
usartS_disable_rx();
sds_state = TRANSMIT;
i = -1;
/* No break here or timing will be wrong.*/
case TRANSMIT:
/* START.*/
if (i == -1) {
bit = 0;
}
/* STOP.*/
else if (i == sds_bits_per_char) {
bit = 1;
sds_state = IDLE;
/* Re-enable receive at the end of a transmit.*/
usartS_enable_rx();
}
/* Data.*/
else {
bit = (byte & (1 << i)) != 0;
}
palWritePad(AVR_SDS_TX_PORT, AVR_SDS_TX_PIN, bit);
++i;
break;
}
OSAL_IRQ_EPILOGUE();
}
I didn't include the INT0 interrupt because it is not used for transmission. This might look long, but enough to say that the RS232 protocol itself works because I can transmit one character. However, I don't really know why I can only get one character from the queue. `SDS` is the serial driver, which *should* be properly initialized with `sdObjectInit`. Without any other I/O available (most if not all are used for other stuff), I can't really see what's going on inside the program.
BTW, RX pin is PD2, and TX is PC0. I can post the full code if needed.