Skip to content

Commit 40e8e7c

Browse files
author
Owen
authored
Add ring buffer for serial TX (#95)
Add ring buffer for serial TX
2 parents 7158d82 + 3eacc3b commit 40e8e7c

File tree

3 files changed

+80
-40
lines changed

3 files changed

+80
-40
lines changed

cores/arduino/am_sdk_ap3/mcu/apollo3/hal/am_hal_uart.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1104,7 +1104,12 @@ am_hal_uart_flags_get(void *pHandle, uint32_t *ui32Flags)
11041104
return AM_HAL_STATUS_INVALID_HANDLE;
11051105
}
11061106

1107-
return UARTn(ui32Module)->FR;
1107+
//Correct code
1108+
*ui32Flags = (uint32_t)UARTn(ui32Module)->FR;
1109+
return AM_HAL_STATUS_SUCCESS;
1110+
1111+
//return UARTn(ui32Module)->FR; //Incorrect code?
1112+
11081113
} // am_hal_uart_flags_get()
11091114

11101115
//*****************************************************************************

cores/arduino/ard_sup/ap3_uart.h

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class Uart : public HardwareSerial
6767
uint32_t printf(const char *pcFmt, ...);
6868
using Print::write; // pull in write(str) and write(buf, size) from Print
6969

70-
void rx_isr(void);
70+
void uart_isr(void);
7171

7272
operator bool() { return true; } // todo: wait for a serial terminal to be open... probably depends on RTS or CTS...
7373

@@ -86,26 +86,6 @@ class Uart : public HardwareSerial
8686

8787
ap3_err_t set_config(HardwareSerial_Config_e HWSconfig);
8888
ap3_err_t _begin(void); // call once all members + config structure are set up
89-
90-
// ap3_err_t initialize( void );
91-
92-
// SERCOM *sercom;
93-
// RingBuffer rxBuffer;
94-
// RingBuffer txBuffer;
95-
96-
// uint8_t uc_pinRX;
97-
// uint8_t uc_pinTX;
98-
// SercomRXPad uc_padRX;
99-
// SercomUartTXPad uc_padTX;
100-
// uint8_t uc_pinRTS;
101-
// volatile uint32_t* pul_outsetRTS;
102-
// volatile uint32_t* pul_outclrRTS;
103-
// uint32_t ul_pinMaskRTS;
104-
// uint8_t uc_pinCTS;
105-
106-
// SercomNumberStopBit extractNbStopBit(uint16_t config);
107-
// SercomUartCharSize extractCharSize(uint16_t config);
108-
// SercomParityMode extractParity(uint16_t config);
10989
};
11090

11191
#endif // _AP3_UART_H_

cores/arduino/ard_sup/uart/ap3_uart.cpp

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,7 @@ int Uart::available()
9090

9191
int Uart::availableForWrite()
9292
{
93-
// return _tx_buffer.availableForStore();
94-
return 127; // todo:
93+
return _tx_buffer.availableForStore();
9594
}
9695

9796
int Uart::peek()
@@ -118,19 +117,47 @@ size_t Uart::write(const uint8_t data)
118117
size_t Uart::write(const uint8_t *buffer, size_t size)
119118
{
120119
uint32_t ui32BytesWritten = 0;
120+
uint32_t remaining = size;
121121

122-
// todo: use a local buffer to guarantee lifespan of data (maybe txbuffer, but maybe not a ring buffer? b/c of efficiency + not breaking up transfers)
122+
//FIFO on Apollo3 is 32 bytes
123123

124-
const am_hal_uart_transfer_t sUartWrite =
125-
{
126-
.ui32Direction = AM_HAL_UART_WRITE,
127-
.pui8Data = (uint8_t *)buffer,
128-
.ui32NumBytes = size,
129-
.ui32TimeoutMs = AM_HAL_UART_WAIT_FOREVER,
130-
.pui32BytesTransferred = (uint32_t *)&ui32BytesWritten,
131-
};
132-
am_hal_uart_transfer(_handle, &sUartWrite);
133-
return ui32BytesWritten;
124+
//If TX UART is sitting idle, load it. This will start the ISR TX handler as well.
125+
uint32_t uartFlags;
126+
am_hal_uart_flags_get(_handle, &uartFlags);
127+
if (uartFlags & AM_HAL_UART_FR_TX_EMPTY)
128+
{
129+
uint32_t amtToSend = remaining;
130+
if (amtToSend > AM_HAL_UART_FIFO_MAX)
131+
amtToSend = AM_HAL_UART_FIFO_MAX;
132+
133+
remaining -= amtToSend;
134+
135+
//Transfer to local buffer
136+
uint8_t tempTX[AM_HAL_UART_FIFO_MAX];
137+
for (int x = 0; x < amtToSend; x++)
138+
tempTX[x] = buffer[x];
139+
140+
const am_hal_uart_transfer_t sUartWrite =
141+
{
142+
.ui32Direction = AM_HAL_UART_WRITE,
143+
.pui8Data = (uint8_t *)tempTX,
144+
.ui32NumBytes = amtToSend,
145+
.ui32TimeoutMs = AM_HAL_UART_WAIT_FOREVER,
146+
.pui32BytesTransferred = (uint32_t *)&ui32BytesWritten,
147+
};
148+
am_hal_uart_transfer(_handle, &sUartWrite);
149+
}
150+
151+
//Transfer any remaining bytes into ring buffer
152+
for (int x = size - remaining; x < size; x++)
153+
{
154+
//If TX ring buffer is full, begin blocking
155+
while (_tx_buffer.availableForStore() == 0)
156+
delay(1);
157+
_tx_buffer.store_char(buffer[x]);
158+
}
159+
160+
return ui32BytesWritten; //Return number of bytes pushed to UART hardware
134161
}
135162

136163
// Stop Bits
@@ -370,9 +397,9 @@ ap3_err_t Uart::_begin(void)
370397

371398
UARTn(_instance)->LCRH_b.FEN = 0; // Disable that pesky FIFO
372399

373-
// Enable RX interrupts
400+
// Enable TX and RX interrupts
374401
NVIC_EnableIRQ((IRQn_Type)(UART0_IRQn + _instance));
375-
am_hal_uart_interrupt_enable(_handle, (AM_HAL_UART_INT_RX));
402+
am_hal_uart_interrupt_enable(_handle, (AM_HAL_UART_INT_RX | AM_HAL_UART_INT_TX));
376403
am_hal_interrupt_master_enable();
377404

378405
// Register the class into the local list
@@ -487,7 +514,7 @@ ap3_err_t ap3_uart_pad_funcsel(uint8_t instance, ap3_uart_pad_type_e type, ap3_g
487514
// Interrupt handler for the UART.
488515
//
489516
//*****************************************************************************
490-
inline void Uart::rx_isr(void)
517+
inline void Uart::uart_isr(void)
491518
{
492519

493520
uint32_t ui32Status;
@@ -517,21 +544,49 @@ inline void Uart::rx_isr(void)
517544
_rx_buffer.store_char(rx_c);
518545
}
519546
}
547+
548+
if (ui32Status & AM_HAL_UART_INT_TX)
549+
{
550+
//If bytes are sitting in TX buffer, load them into UART buffer for transfer
551+
if (_tx_buffer.available())
552+
{
553+
uint32_t ui32BytesWritten = 0;
554+
555+
uint32_t amtToSend = _tx_buffer.available();
556+
if (amtToSend > AM_HAL_UART_FIFO_MAX)
557+
amtToSend = AM_HAL_UART_FIFO_MAX;
558+
559+
//Transfer to local buffer
560+
uint8_t tempTX[AM_HAL_UART_FIFO_MAX];
561+
for (int x = 0; x < amtToSend; x++)
562+
tempTX[x] = _tx_buffer.read_char();
563+
564+
const am_hal_uart_transfer_t sUartWrite =
565+
{
566+
.ui32Direction = AM_HAL_UART_WRITE,
567+
.pui8Data = (uint8_t *)tempTX,
568+
.ui32NumBytes = (uint32_t)amtToSend,
569+
.ui32TimeoutMs = AM_HAL_UART_WAIT_FOREVER,
570+
.pui32BytesTransferred = (uint32_t *)&ui32BytesWritten,
571+
};
572+
am_hal_uart_transfer(_handle, &sUartWrite);
573+
}
574+
}
520575
}
521576

522577
// Individual ISR implementations for the two UART peripherals on the Apollo3
523578
extern "C" void am_uart_isr(void)
524579
{
525580
if (ap3_uart_handles[0] != NULL)
526581
{
527-
ap3_uart_handles[0]->rx_isr();
582+
ap3_uart_handles[0]->uart_isr();
528583
}
529584
}
530585

531586
extern "C" void am_uart1_isr(void)
532587
{
533588
if (ap3_uart_handles[1] != NULL)
534589
{
535-
ap3_uart_handles[1]->rx_isr();
590+
ap3_uart_handles[1]->uart_isr();
536591
}
537592
}

0 commit comments

Comments
 (0)