瀏覽代碼

Use Serial2's FIFO on Teensy 3.1

teensy4-core
PaulStoffregen 10 年之前
父節點
當前提交
36fc4f599e
共有 1 個檔案被更改,包括 117 行新增9 行删除
  1. +117
    -9
      teensy3/serial2.c

+ 117
- 9
teensy3/serial2.c 查看文件

@@ -40,7 +40,6 @@
#define RX_BUFFER_SIZE 64
#define IRQ_PRIORITY 64 // 0 = highest priority, 255 = lowest


////////////////////////////////////////////////////////////////
// changes not recommended below this point....
////////////////////////////////////////////////////////////////
@@ -74,7 +73,11 @@ static volatile uint8_t rx_buffer_tail = 0;
// UART0 and UART1 are clocked by F_CPU, UART2 is clocked by F_BUS
// UART0 has 8 byte fifo, UART1 and UART2 have 1 byte buffer

#ifdef KINETISK_UART1_FIFO
#define C2_ENABLE UART_C2_TE | UART_C2_RE | UART_C2_RIE | UART_C2_ILIE
#else
#define C2_ENABLE UART_C2_TE | UART_C2_RE | UART_C2_RIE
#endif
#define C2_TX_ACTIVE C2_ENABLE | UART_C2_TIE
#define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE
#define C2_TX_INACTIVE C2_ENABLE
@@ -92,8 +95,15 @@ void serial2_begin(uint32_t divisor)
UART1_BDH = (divisor >> 13) & 0x1F;
UART1_BDL = (divisor >> 5) & 0xFF;
UART1_C4 = divisor & 0x1F;
#ifdef KINETISK_UART1_FIFO
UART1_C1 = UART_C1_ILT;
UART1_TWFIFO = 2; // tx watermark, causes S1_TDRE to set
UART1_RWFIFO = 4; // rx watermark, causes S1_RDRF to set
UART1_PFIFO = UART_PFIFO_TXFE | UART_PFIFO_RXFE;
#else
UART1_C1 = 0;
UART1_PFIFO = 0;
#endif
UART1_C2 = C2_TX_INACTIVE;
NVIC_SET_PRIORITY(IRQ_UART1_STATUS, IRQ_PRIORITY);
NVIC_ENABLE_IRQ(IRQ_UART1_STATUS);
@@ -142,7 +152,7 @@ void serial2_end(void)

void serial2_putchar(uint32_t c)
{
uint32_t head;
uint32_t head, n;

if (!(SIM_SCGC4 & SIM_SCGC4_UART1)) return;
head = tx_buffer_head;
@@ -153,7 +163,9 @@ void serial2_putchar(uint32_t c)
if ((UART1_S1 & UART_S1_TDRE)) {
uint32_t tail = tx_buffer_tail;
if (++tail >= TX_BUFFER_SIZE) tail = 0;
UART1_D = tx_buffer[tail];
n = tx_buffer[tail];
if (use9Bits) UART1_C3 = (UART1_C3 & ~0x40) | ((n & 0x100) >> 2);
UART1_D = n;
tx_buffer_tail = tail;
}
} else if (priority >= 256) {
@@ -166,11 +178,48 @@ void serial2_putchar(uint32_t c)
UART1_C2 = C2_TX_ACTIVE;
}

#ifdef KINETISK_UART1_FIFO
void serial2_write(const void *buf, unsigned int count)
{
const uint8_t *p = (const uint8_t *)buf;
const uint8_t *end = p + count;
uint32_t head, n;

if (!(SIM_SCGC4 & SIM_SCGC4_UART1)) return;
while (p < end) {
head = tx_buffer_head;
if (++head >= TX_BUFFER_SIZE) head = 0;
if (tx_buffer_tail == head) {
UART1_C2 = C2_TX_ACTIVE;
do {
int priority = nvic_execution_priority();
if (priority <= IRQ_PRIORITY) {
if ((UART1_S1 & UART_S1_TDRE)) {
uint32_t tail = tx_buffer_tail;
if (++tail >= TX_BUFFER_SIZE) tail = 0;
n = tx_buffer[tail];
if (use9Bits) UART1_C3 = (UART1_C3 & ~0x40) | ((n & 0x100) >> 2);
UART1_D = n;
tx_buffer_tail = tail;
}
} else if (priority >= 256) {
yield();
}
} while (tx_buffer_tail == head);
}
tx_buffer[head] = *p++;
transmitting = 1;
tx_buffer_head = head;
}
UART1_C2 = C2_TX_ACTIVE;
}
#else
void serial2_write(const void *buf, unsigned int count)
{
const uint8_t *p = (const uint8_t *)buf;
while (count-- > 0) serial2_putchar(*p++);
}
#endif

void serial2_flush(void)
{
@@ -224,6 +273,12 @@ int serial2_peek(void)

void serial2_clear(void)
{
#ifdef KINETISK_UART1_FIFO
if (!(SIM_SCGC4 & SIM_SCGC4_UART1)) return;
UART1_C2 &= ~(UART_C2_RE | UART_C2_RIE | UART_C2_ILIE);
UART1_CFIFO = UART_CFIFO_RXFLUSH;
UART1_C2 |= (UART_C2_RE | UART_C2_RIE | UART_C2_ILIE);
#endif
rx_buffer_head = rx_buffer_tail;
}

@@ -239,10 +294,66 @@ void uart1_status_isr(void)
{
uint32_t head, tail, n;
uint8_t c;
#ifdef KINETISK_UART1_FIFO
uint32_t newhead;
uint8_t avail;

//digitalWriteFast(4, HIGH);
if (UART1_S1 & (UART_S1_RDRF | UART_S1_IDLE)) {
__disable_irq();
avail = UART1_RCFIFO;
if (avail == 0) {
// The only way to clear the IDLE interrupt flag is
// to read the data register. But reading with no
// data causes a FIFO underrun, which causes the
// FIFO to return corrupted data. If anyone from
// Freescale reads this, what a poor design! There
// write should be a write-1-to-clear for IDLE.
c = UART1_D;
// flushing the fifo recovers from the underrun,
// but there's a possible race condition where a
// new character could be received between reading
// RCFIFO == 0 and flushing the FIFO. To minimize
// the chance, interrupts are disabled so a higher
// priority interrupt (hopefully) doesn't delay.
// TODO: change this to disabling the IDLE interrupt
// which won't be simple, since we already manage
// which transmit interrupts are enabled.
UART1_CFIFO = UART_CFIFO_RXFLUSH;
__enable_irq();
} else {
__enable_irq();
head = rx_buffer_head;
tail = rx_buffer_tail;
do {
n = UART1_D;
if (use9Bits && (UART1_C3 & 0x80)) n |= 0x100;
newhead = head + 1;
if (newhead >= RX_BUFFER_SIZE) newhead = 0;
if (newhead != tail) {
head = newhead;
rx_buffer[head] = n;
}
} while (--avail > 0);
rx_buffer_head = head;
}
}
c = UART1_C2;
if ((c & UART_C2_TIE) && (UART1_S1 & UART_S1_TDRE)) {
head = tx_buffer_head;
tail = tx_buffer_tail;
do {
if (tail == head) break;
if (++tail >= TX_BUFFER_SIZE) tail = 0;
avail = UART1_S1;
n = tx_buffer[tail];
if (use9Bits) UART1_C3 = (UART1_C3 & ~0x40) | ((n & 0x100) >> 2);
UART1_D = n;
} while (UART1_TCFIFO < 8);
tx_buffer_tail = tail;
if (UART1_S1 & UART_S1_TDRE) UART1_C2 = C2_TX_COMPLETING;
}
#else
if (UART1_S1 & UART_S1_RDRF) {
//digitalWriteFast(5, HIGH);
n = UART1_D;
if (use9Bits && (UART1_C3 & 0x80)) n |= 0x100;
head = rx_buffer_head + 1;
@@ -251,11 +362,9 @@ void uart1_status_isr(void)
rx_buffer[head] = n;
rx_buffer_head = head;
}
//digitalWriteFast(5, LOW);
}
c = UART1_C2;
if ((c & UART_C2_TIE) && (UART1_S1 & UART_S1_TDRE)) {
//digitalWriteFast(5, HIGH);
head = tx_buffer_head;
tail = tx_buffer_tail;
if (head == tail) {
@@ -267,13 +376,12 @@ void uart1_status_isr(void)
UART1_D = n;
tx_buffer_tail = tail;
}
//digitalWriteFast(5, LOW);
}
#endif
if ((c & UART_C2_TCIE) && (UART1_S1 & UART_S1_TC)) {
transmitting = 0;
UART1_C2 = C2_TX_INACTIVE;
}
//digitalWriteFast(4, LOW);
}



Loading…
取消
儲存