Skip to content

Add ring buffer for serial TX #95

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

Merged
merged 12 commits into from
Dec 3, 2019
7 changes: 6 additions & 1 deletion cores/arduino/am_sdk_ap3/mcu/apollo3/hal/am_hal_uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -1104,7 +1104,12 @@ am_hal_uart_flags_get(void *pHandle, uint32_t *ui32Flags)
return AM_HAL_STATUS_INVALID_HANDLE;
}

return UARTn(ui32Module)->FR;
//Correct code
*ui32Flags = (uint32_t)UARTn(ui32Module)->FR;
return AM_HAL_STATUS_SUCCESS;

//return UARTn(ui32Module)->FR; //Incorrect code?

} // am_hal_uart_flags_get()

//*****************************************************************************
Expand Down
22 changes: 1 addition & 21 deletions cores/arduino/ard_sup/ap3_uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class Uart : public HardwareSerial
uint32_t printf(const char *pcFmt, ...);
using Print::write; // pull in write(str) and write(buf, size) from Print

void rx_isr(void);
void uart_isr(void);

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

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

ap3_err_t set_config(HardwareSerial_Config_e HWSconfig);
ap3_err_t _begin(void); // call once all members + config structure are set up

// ap3_err_t initialize( void );

// SERCOM *sercom;
// RingBuffer rxBuffer;
// RingBuffer txBuffer;

// uint8_t uc_pinRX;
// uint8_t uc_pinTX;
// SercomRXPad uc_padRX;
// SercomUartTXPad uc_padTX;
// uint8_t uc_pinRTS;
// volatile uint32_t* pul_outsetRTS;
// volatile uint32_t* pul_outclrRTS;
// uint32_t ul_pinMaskRTS;
// uint8_t uc_pinCTS;

// SercomNumberStopBit extractNbStopBit(uint16_t config);
// SercomUartCharSize extractCharSize(uint16_t config);
// SercomParityMode extractParity(uint16_t config);
};

#endif // _AP3_UART_H_
91 changes: 73 additions & 18 deletions cores/arduino/ard_sup/uart/ap3_uart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ int Uart::available()

int Uart::availableForWrite()
{
// return _tx_buffer.availableForStore();
return 127; // todo:
return _tx_buffer.availableForStore();
}

int Uart::peek()
Expand All @@ -118,19 +117,47 @@ size_t Uart::write(const uint8_t data)
size_t Uart::write(const uint8_t *buffer, size_t size)
{
uint32_t ui32BytesWritten = 0;
uint32_t remaining = size;

// 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)
//FIFO on Apollo3 is 32 bytes

const am_hal_uart_transfer_t sUartWrite =
{
.ui32Direction = AM_HAL_UART_WRITE,
.pui8Data = (uint8_t *)buffer,
.ui32NumBytes = size,
.ui32TimeoutMs = AM_HAL_UART_WAIT_FOREVER,
.pui32BytesTransferred = (uint32_t *)&ui32BytesWritten,
};
am_hal_uart_transfer(_handle, &sUartWrite);
return ui32BytesWritten;
//If TX UART is sitting idle, load it. This will start the ISR TX handler as well.
uint32_t uartFlags;
am_hal_uart_flags_get(_handle, &uartFlags);
if (uartFlags & AM_HAL_UART_FR_TX_EMPTY)
{
uint32_t amtToSend = remaining;
if (amtToSend > AM_HAL_UART_FIFO_MAX)
amtToSend = AM_HAL_UART_FIFO_MAX;

remaining -= amtToSend;

//Transfer to local buffer
uint8_t tempTX[AM_HAL_UART_FIFO_MAX];
for (int x = 0; x < amtToSend; x++)
tempTX[x] = buffer[x];

const am_hal_uart_transfer_t sUartWrite =
{
.ui32Direction = AM_HAL_UART_WRITE,
.pui8Data = (uint8_t *)tempTX,
.ui32NumBytes = amtToSend,
.ui32TimeoutMs = AM_HAL_UART_WAIT_FOREVER,
.pui32BytesTransferred = (uint32_t *)&ui32BytesWritten,
};
am_hal_uart_transfer(_handle, &sUartWrite);
}

//Transfer any remaining bytes into ring buffer
for (int x = size - remaining; x < size; x++)
{
//If TX ring buffer is full, begin blocking
while (_tx_buffer.availableForStore() == 0)
delay(1);
_tx_buffer.store_char(buffer[x]);
}

return ui32BytesWritten; //Return number of bytes pushed to UART hardware
}

// Stop Bits
Expand Down Expand Up @@ -370,9 +397,9 @@ ap3_err_t Uart::_begin(void)

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

// Enable RX interrupts
// Enable TX and RX interrupts
NVIC_EnableIRQ((IRQn_Type)(UART0_IRQn + _instance));
am_hal_uart_interrupt_enable(_handle, (AM_HAL_UART_INT_RX));
am_hal_uart_interrupt_enable(_handle, (AM_HAL_UART_INT_RX | AM_HAL_UART_INT_TX));
am_hal_interrupt_master_enable();

// Register the class into the local list
Expand Down Expand Up @@ -487,7 +514,7 @@ ap3_err_t ap3_uart_pad_funcsel(uint8_t instance, ap3_uart_pad_type_e type, ap3_g
// Interrupt handler for the UART.
//
//*****************************************************************************
inline void Uart::rx_isr(void)
inline void Uart::uart_isr(void)
{

uint32_t ui32Status;
Expand Down Expand Up @@ -517,21 +544,49 @@ inline void Uart::rx_isr(void)
_rx_buffer.store_char(rx_c);
}
}

if (ui32Status & AM_HAL_UART_INT_TX)
{
//If bytes are sitting in TX buffer, load them into UART buffer for transfer
if (_tx_buffer.available())
{
uint32_t ui32BytesWritten = 0;

uint32_t amtToSend = _tx_buffer.available();
if (amtToSend > AM_HAL_UART_FIFO_MAX)
amtToSend = AM_HAL_UART_FIFO_MAX;

//Transfer to local buffer
uint8_t tempTX[AM_HAL_UART_FIFO_MAX];
for (int x = 0; x < amtToSend; x++)
tempTX[x] = _tx_buffer.read_char();

const am_hal_uart_transfer_t sUartWrite =
{
.ui32Direction = AM_HAL_UART_WRITE,
.pui8Data = (uint8_t *)tempTX,
.ui32NumBytes = (uint32_t)amtToSend,
.ui32TimeoutMs = AM_HAL_UART_WAIT_FOREVER,
.pui32BytesTransferred = (uint32_t *)&ui32BytesWritten,
};
am_hal_uart_transfer(_handle, &sUartWrite);
}
}
}

// Individual ISR implementations for the two UART peripherals on the Apollo3
extern "C" void am_uart_isr(void)
{
if (ap3_uart_handles[0] != NULL)
{
ap3_uart_handles[0]->rx_isr();
ap3_uart_handles[0]->uart_isr();
}
}

extern "C" void am_uart1_isr(void)
{
if (ap3_uart_handles[1] != NULL)
{
ap3_uart_handles[1]->rx_isr();
ap3_uart_handles[1]->uart_isr();
}
}