commit 5313ee98d21ca70d98ea6592961c2f6419d07b59 Author: Mohamed Salem Date: Mon Apr 13 03:51:35 2026 +0200 Initial: MCU_UART hardware UART driver with DMA/ISR TX and ring buffer RX diff --git a/cfg/MCU_UART_cfg.c b/cfg/MCU_UART_cfg.c new file mode 100644 index 0000000..c490e8f --- /dev/null +++ b/cfg/MCU_UART_cfg.c @@ -0,0 +1,26 @@ +/****************************************************************************** + * File: MCU_UART_cfg.c + * Component: MCU_UART + * Description: Configuration array definition for the MCU_UART driver. + * + * Layer: MCU (hardware abstraction) - configuration + *****************************************************************************/ + +#include "MCU_UART.h" +#include "MCU_UART_cfg.h" + +const MCU_UART_tstrConfig MCU_UART_astrConfig[MCU_UART_NUM_INSTANCES] = +{ + [MCU_UART_INSTANCE_0] = + { + .u8TxPin = MCU_UART_0_TX_PIN, + .u8RxPin = MCU_UART_0_RX_PIN, + .u32BaudRate = MCU_UART_0_BAUD_RATE, + .enuDataBits = MCU_UART_0_DATA_BITS, + .enuStopBits = MCU_UART_0_STOP_BITS, + .enuParity = MCU_UART_0_PARITY, + .enuTxAsyncMode = MCU_UART_0_TX_ASYNC_MODE, + .pfTxCompleteCallback = MCU_UART_0_TX_COMPLETE_CALLBACK, + .enuRxAsyncMode = MCU_UART_0_RX_ASYNC_MODE, + }, +}; \ No newline at end of file diff --git a/cfg/MCU_UART_cfg.h b/cfg/MCU_UART_cfg.h new file mode 100644 index 0000000..9166a19 --- /dev/null +++ b/cfg/MCU_UART_cfg.h @@ -0,0 +1,51 @@ +/****************************************************************************** + * File: MCU_UART_cfg.h + * Component: MCU_UART + * Description: Configuration for the MCU_UART driver. Defines instances, + * pin assignments, baud rates, data format, TX/RX async modes, + * and RX buffer sizing. + * + * Layer: MCU (hardware abstraction) - configuration + *****************************************************************************/ + +#ifndef MCU_UART_CFG_H +#define MCU_UART_CFG_H + +#include "STD_TYPES.h" + +/* ------------------------------------------------------------------------ */ +/* INSTANCE ENUMERATION */ +/* ------------------------------------------------------------------------ */ + +typedef enum +{ + MCU_UART_INSTANCE_0 = 0U, + MCU_UART_NUM_INSTANCES +} MCU_UART_tenuInstance; + +/* ------------------------------------------------------------------------ */ +/* RX RING BUFFER SIZING */ +/* ------------------------------------------------------------------------ */ + +/** @brief Number of address bits for the RX ring buffer (2^N bytes). + * Must be power of 2 for DMA ring wrap. + * 5 = 32, 6 = 64, 7 = 128, 8 = 256. */ +#define MCU_UART_RX_BUFFER_SIZE_BITS 6U +#define MCU_UART_RX_BUFFER_SIZE (1U << MCU_UART_RX_BUFFER_SIZE_BITS) +#define MCU_UART_RX_BUFFER_MASK (MCU_UART_RX_BUFFER_SIZE - 1U) + +/* ------------------------------------------------------------------------ */ +/* INSTANCE 0 CONFIGURATION */ +/* ------------------------------------------------------------------------ */ + +#define MCU_UART_0_TX_PIN 0U +#define MCU_UART_0_RX_PIN 1U +#define MCU_UART_0_BAUD_RATE 115200U +#define MCU_UART_0_DATA_BITS MCU_UART_DATA_BITS_8 +#define MCU_UART_0_STOP_BITS MCU_UART_STOP_BITS_1 +#define MCU_UART_0_PARITY MCU_UART_PARITY_NONE +#define MCU_UART_0_TX_ASYNC_MODE MCU_UART_ASYNC_DMA +#define MCU_UART_0_TX_COMPLETE_CALLBACK STD_NULL +#define MCU_UART_0_RX_ASYNC_MODE MCU_UART_ASYNC_ISR + +#endif /* MCU_UART_CFG_H */ \ No newline at end of file diff --git a/inc/MCU_UART.h b/inc/MCU_UART.h new file mode 100644 index 0000000..283a327 --- /dev/null +++ b/inc/MCU_UART.h @@ -0,0 +1,124 @@ +/****************************************************************************** + * File: MCU_UART.h + * Component: MCU_UART + * Description: Public interface for the MCU UART driver component. + * + * TX: SendByte (blocking), SendBuffer (non-blocking DMA/ISR), + * SendBufferBlocking. + * RX: background ring buffer filled by ISR or DMA. + * ReadByte / ReadBuffer read from the buffer (non-blocking). + * + * Layer: MCU (hardware abstraction) + *****************************************************************************/ + +#ifndef MCU_UART_H +#define MCU_UART_H + +#include "STD_TYPES.h" + +/* ------------------------------------------------------------------------ */ +/* CONFIGURATION VALUE TYPES */ +/* ------------------------------------------------------------------------ */ + +typedef enum +{ + MCU_UART_PARITY_NONE = 0U, + MCU_UART_PARITY_EVEN, + MCU_UART_PARITY_ODD +} MCU_UART_tenuParity; + +typedef enum +{ + MCU_UART_DATA_BITS_5 = 5U, + MCU_UART_DATA_BITS_6 = 6U, + MCU_UART_DATA_BITS_7 = 7U, + MCU_UART_DATA_BITS_8 = 8U +} MCU_UART_tenuDataBits; + +typedef enum +{ + MCU_UART_STOP_BITS_1 = 1U, + MCU_UART_STOP_BITS_2 = 2U +} MCU_UART_tenuStopBits; + +typedef enum +{ + MCU_UART_ASYNC_DMA = 0U, + MCU_UART_ASYNC_ISR +} MCU_UART_tenuAsyncMode; + +/* ------------------------------------------------------------------------ */ +/* CONFIGURATION STRUCTURE */ +/* ------------------------------------------------------------------------ */ + +typedef struct +{ + u8 u8TxPin; + u8 u8RxPin; + u32 u32BaudRate; + MCU_UART_tenuDataBits enuDataBits; + MCU_UART_tenuStopBits enuStopBits; + MCU_UART_tenuParity enuParity; + MCU_UART_tenuAsyncMode enuTxAsyncMode; + STD_tpfCallbackFunc pfTxCompleteCallback; + MCU_UART_tenuAsyncMode enuRxAsyncMode; +} MCU_UART_tstrConfig; + +/* ------------------------------------------------------------------------ */ +/* TX PUBLIC API */ +/* ------------------------------------------------------------------------ */ + +STD_tenuResult MCU_UART_enuInit(void); + +STD_tenuResult MCU_UART_enuSendByte(u8 u8Instance, u8 u8Byte); + +STD_tenuResult MCU_UART_enuSendBuffer(u8 u8Instance, const u8 *pu8Data, u16 u16Length); + +STD_tenuResult MCU_UART_enuSendBufferBlocking(u8 u8Instance, const u8 *pu8Data, u16 u16Length); + +STD_tBool MCU_UART_bIsTxBusy(u8 u8Instance); + +/* ------------------------------------------------------------------------ */ +/* RX PUBLIC API */ +/* ------------------------------------------------------------------------ */ + +/** + * @brief Read one byte from the RX ring buffer (non-blocking). + * + * The ring buffer is filled in the background by ISR or DMA. + * Returns immediately — STD_OK with the byte, or STD_NOK if empty. + * + * @param u8Instance UART instance index. + * @param pu8Byte Pointer to store the received byte. + * @return STD_OK byte read, + * STD_NULL_POINTER_ERROR if pu8Byte is NULL, + * STD_NOK if ring buffer is empty. + */ +STD_tenuResult MCU_UART_enuReadByte(u8 u8Instance, u8 *pu8Byte); + +/** + * @brief Read up to u16MaxLength bytes from the RX ring buffer (non-blocking). + * + * Copies as many bytes as are currently available (up to u16MaxLength) + * into pu8Data. Reports the actual number of bytes read via pu16Read. + * Returns immediately even if fewer than u16MaxLength bytes are available. + * + * @param u8Instance UART instance index. + * @param pu8Data Pointer to output buffer. + * @param u16MaxLength Maximum bytes to read. + * @param pu16Read Pointer to store actual bytes read. Must not be NULL. + * @return STD_OK at least one byte read, + * STD_NULL_POINTER_ERROR if pu8Data or pu16Read is NULL, + * STD_NOK if ring buffer is empty (zero bytes read). + */ +STD_tenuResult MCU_UART_enuReadBuffer(u8 u8Instance, u8 *pu8Data, u16 u16MaxLength, u16 *pu16Read); + +/** + * @brief Check if the RX ring buffer has data. + * + * @param u8Instance UART instance index. + * @return STD_TRUE if at least one byte available, STD_FALSE if empty. + */ +STD_tBool MCU_UART_bIsRxDataAvailable(u8 u8Instance); + +#endif /* MCU_UART_H */ \ No newline at end of file diff --git a/prg/MCU_UART_prg.c b/prg/MCU_UART_prg.c new file mode 100644 index 0000000..89b1138 --- /dev/null +++ b/prg/MCU_UART_prg.c @@ -0,0 +1,421 @@ +/****************************************************************************** + * File: MCU_UART_prg.c + * Component: MCU_UART + * Description: TX: blocking + non-blocking (DMA or ISR) with callback. + * RX: ISR or DMA fills ring buffer in background. ReadByte + * and ReadBuffer read from the buffer non-blocking. + * + * Layer: MCU (hardware abstraction) + *****************************************************************************/ + +#include "MCU_UART.h" +#include "MCU_UART_priv.h" +#include "MCU_UART_cfg.h" + +#include "hardware/uart.h" +#include "hardware/gpio.h" +#include "hardware/dma.h" +#include "hardware/irq.h" + +/* ------------------------------------------------------------------------ */ +/* INSTANCE LOOKUP TABLE */ +/* ------------------------------------------------------------------------ */ + +static uart_inst_t * const apstrInstances[] = { uart0, uart1 }; + +/* ------------------------------------------------------------------------ */ +/* RUNTIME STATE */ +/* ------------------------------------------------------------------------ */ + +static MCU_UART_tstrControl strControl; + +/* ------------------------------------------------------------------------ */ +/* INTERNAL HELPERS */ +/* ------------------------------------------------------------------------ */ + +static void vCallTxCallback(u8 u8Instance) +{ + STD_tpfCallbackFunc pfCbLoc = MCU_UART_astrConfig[u8Instance].pfTxCompleteCallback; + + if (pfCbLoc != STD_NULL) + { + pfCbLoc(); + } +} + +/** @brief Get current RX head. DMA mode derives from hw write pointer. */ +static u16 u16GetRxHead(u8 u8Instance) +{ + u16 u16HeadLoc; + + if (MCU_UART_astrConfig[u8Instance].enuRxAsyncMode == MCU_UART_ASYNC_DMA) + { + s8 s8ChLoc = strControl.as8RxDmaChannel[u8Instance]; + u32 u32WrLoc = (u32)dma_channel_hw_addr((u32)s8ChLoc)->write_addr; + u32 u32BaseLoc = (u32)(&strControl.aau8RxBuffer[u8Instance][0]); + u16HeadLoc = (u16)((u32WrLoc - u32BaseLoc) & MCU_UART_RX_BUFFER_MASK); + } + else + { + u16HeadLoc = strControl.au16RxHead[u8Instance]; + } + + return u16HeadLoc; +} + +/* ------------------------------------------------------------------------ */ +/* TX DMA IRQ HANDLER (INSTANCE 0) */ +/* ------------------------------------------------------------------------ */ + +static void vTxDmaIrqHandler0(void) +{ + s8 s8ChLoc = strControl.as8TxDmaChannel[MCU_UART_INSTANCE_0]; + u32 u32StatusLoc = dma_channel_get_irq0_status((u32)s8ChLoc); + + if (u32StatusLoc != 0U) + { + dma_irqn_acknowledge_channel(0, (u32)s8ChLoc); + strControl.abTxBusy[MCU_UART_INSTANCE_0] = STD_FALSE; + vCallTxCallback((u8)MCU_UART_INSTANCE_0); + } +} + +/* ------------------------------------------------------------------------ */ +/* UART ISR HANDLER (RX + TX) */ +/* ------------------------------------------------------------------------ */ + +static void vUartIsrHandler(u8 u8Instance) +{ + uart_inst_t *pstrUartLoc = apstrInstances[u8Instance]; + + /* --- RX: drain FIFO into ring buffer --- */ + STD_tBool bReadableLoc = (uart_is_readable(pstrUartLoc) != 0) ? STD_TRUE : STD_FALSE; + + while (bReadableLoc == STD_TRUE) + { + u8 u8ByteLoc = (u8)uart_getc(pstrUartLoc); + u16 u16HeadLoc = strControl.au16RxHead[u8Instance]; + + strControl.aau8RxBuffer[u8Instance][u16HeadLoc] = u8ByteLoc; + strControl.au16RxHead[u8Instance] = (u16HeadLoc + 1U) & MCU_UART_RX_BUFFER_MASK; + + bReadableLoc = (uart_is_readable(pstrUartLoc) != 0) ? STD_TRUE : STD_FALSE; + } + + /* --- TX: fill FIFO from buffer (if TX ISR active) --- */ + STD_tBool bTxBusyLoc = strControl.abTxBusy[u8Instance]; + + if (bTxBusyLoc == STD_TRUE) + { + STD_tBool bFifoReady = (uart_is_writable(pstrUartLoc) != 0) ? STD_TRUE : STD_FALSE; + STD_tBool bDataLeft = (strControl.au16TxIndex[u8Instance] < strControl.au16TxLength[u8Instance]) ? STD_TRUE : STD_FALSE; + + while ((bFifoReady == STD_TRUE) && (bDataLeft == STD_TRUE)) + { + uart_putc_raw(pstrUartLoc, + strControl.apu8TxBuffer[u8Instance][strControl.au16TxIndex[u8Instance]]); + strControl.au16TxIndex[u8Instance]++; + + bFifoReady = (uart_is_writable(pstrUartLoc) != 0) ? STD_TRUE : STD_FALSE; + bDataLeft = (strControl.au16TxIndex[u8Instance] < strControl.au16TxLength[u8Instance]) ? STD_TRUE : STD_FALSE; + } + + if (bDataLeft == STD_FALSE) + { + uart_set_irqs_enabled(pstrUartLoc, false, true); + strControl.abTxBusy[u8Instance] = STD_FALSE; + vCallTxCallback(u8Instance); + } + } +} + +static void vUart0IrqHandler(void) +{ + vUartIsrHandler((u8)MCU_UART_INSTANCE_0); +} + +/* ========================================================================= */ +/* INIT */ +/* ========================================================================= */ + +STD_tenuResult MCU_UART_enuInit(void) +{ + STD_tenuResult enuResultLoc = STD_OK; + u8 u8IndexLoc; + + for (u8IndexLoc = 0U; u8IndexLoc < (u8)MCU_UART_NUM_INSTANCES; u8IndexLoc++) + { + strControl.apu8TxBuffer[u8IndexLoc] = STD_NULL; + strControl.au16TxLength[u8IndexLoc] = 0U; + strControl.au16TxIndex[u8IndexLoc] = 0U; + strControl.abTxBusy[u8IndexLoc] = STD_FALSE; + strControl.as8TxDmaChannel[u8IndexLoc] = -1; + strControl.au16RxHead[u8IndexLoc] = 0U; + strControl.au16RxTail[u8IndexLoc] = 0U; + strControl.as8RxDmaChannel[u8IndexLoc] = -1; + } + + for (u8IndexLoc = 0U; u8IndexLoc < (u8)MCU_UART_NUM_INSTANCES; u8IndexLoc++) + { + const MCU_UART_tstrConfig *pstrCfgLoc = &MCU_UART_astrConfig[u8IndexLoc]; + uart_inst_t *pstrUartLoc = apstrInstances[u8IndexLoc]; + + uart_init(pstrUartLoc, pstrCfgLoc->u32BaudRate); + gpio_set_function(pstrCfgLoc->u8TxPin, GPIO_FUNC_UART); + gpio_set_function(pstrCfgLoc->u8RxPin, GPIO_FUNC_UART); + uart_set_format(pstrUartLoc, + pstrCfgLoc->enuDataBits, + pstrCfgLoc->enuStopBits, + pstrCfgLoc->enuParity); + + /* TX async setup */ + if (pstrCfgLoc->enuTxAsyncMode == MCU_UART_ASYNC_DMA) + { + s8 s8ChLoc = (s8)dma_claim_unused_channel(true); + strControl.as8TxDmaChannel[u8IndexLoc] = s8ChLoc; + dma_channel_set_irq0_enabled((u32)s8ChLoc, true); + + if (u8IndexLoc == (u8)MCU_UART_INSTANCE_0) + { + irq_set_exclusive_handler(DMA_IRQ_0, vTxDmaIrqHandler0); + irq_set_enabled(DMA_IRQ_0, true); + } + } + + /* RX async setup */ + if (pstrCfgLoc->enuRxAsyncMode == MCU_UART_ASYNC_DMA) + { + s8 s8RxChLoc = (s8)dma_claim_unused_channel(true); + strControl.as8RxDmaChannel[u8IndexLoc] = s8RxChLoc; + + dma_channel_config strRxCfgLoc = dma_channel_get_default_config((u32)s8RxChLoc); + channel_config_set_transfer_data_size(&strRxCfgLoc, DMA_SIZE_8); + channel_config_set_read_increment(&strRxCfgLoc, false); + channel_config_set_write_increment(&strRxCfgLoc, true); + channel_config_set_dreq(&strRxCfgLoc, uart_get_dreq(pstrUartLoc, false)); + channel_config_set_ring(&strRxCfgLoc, true, MCU_UART_RX_BUFFER_SIZE_BITS); + + dma_channel_configure( + (u32)s8RxChLoc, + &strRxCfgLoc, + &strControl.aau8RxBuffer[u8IndexLoc][0], + &uart_get_hw(pstrUartLoc)->dr, + 0xFFFFFFFFU, + true + ); + } + else + { + if (u8IndexLoc == (u8)MCU_UART_INSTANCE_0) + { + irq_set_exclusive_handler(UART0_IRQ, vUart0IrqHandler); + irq_set_enabled(UART0_IRQ, true); + } + uart_set_irqs_enabled(pstrUartLoc, false, true); + } + } + + return enuResultLoc; +} + +/* ========================================================================= */ +/* SEND BYTE (BLOCKING) */ +/* ========================================================================= */ + +STD_tenuResult MCU_UART_enuSendByte(u8 u8Instance, u8 u8Byte) +{ + STD_tenuResult enuResultLoc = STD_OK; + + uart_putc_raw(apstrInstances[u8Instance], u8Byte); + + return enuResultLoc; +} + +/* ========================================================================= */ +/* SEND BUFFER (NON-BLOCKING) */ +/* ========================================================================= */ + +STD_tenuResult MCU_UART_enuSendBuffer(u8 u8Instance, const u8 *pu8Data, u16 u16Length) +{ + STD_tenuResult enuResultLoc = STD_OK; + STD_tBool bBusyLoc = strControl.abTxBusy[u8Instance]; + MCU_UART_tenuAsyncMode enuModeLoc = MCU_UART_astrConfig[u8Instance].enuTxAsyncMode; + + if (pu8Data == STD_NULL) + { + enuResultLoc = STD_NULL_POINTER_ERROR; + } + else if (bBusyLoc == STD_TRUE) + { + enuResultLoc = STD_NOK; + } + else + { + strControl.apu8TxBuffer[u8Instance] = pu8Data; + strControl.au16TxLength[u8Instance] = u16Length; + strControl.au16TxIndex[u8Instance] = 0U; + strControl.abTxBusy[u8Instance] = STD_TRUE; + + if (enuModeLoc == MCU_UART_ASYNC_DMA) + { + s8 s8ChLoc = strControl.as8TxDmaChannel[u8Instance]; + uart_inst_t *pstrUartLoc = apstrInstances[u8Instance]; + + dma_channel_config strCfgLoc = dma_channel_get_default_config((u32)s8ChLoc); + channel_config_set_transfer_data_size(&strCfgLoc, DMA_SIZE_8); + channel_config_set_read_increment(&strCfgLoc, true); + channel_config_set_write_increment(&strCfgLoc, false); + channel_config_set_dreq(&strCfgLoc, uart_get_dreq(pstrUartLoc, true)); + + dma_channel_configure( + (u32)s8ChLoc, &strCfgLoc, + &uart_get_hw(pstrUartLoc)->dr, pu8Data, u16Length, true); + } + else + { + uart_inst_t *pstrUartLoc = apstrInstances[u8Instance]; + STD_tBool bFifoReady = (uart_is_writable(pstrUartLoc) != 0) ? STD_TRUE : STD_FALSE; + STD_tBool bDataLeft = (strControl.au16TxIndex[u8Instance] < u16Length) ? STD_TRUE : STD_FALSE; + + while ((bFifoReady == STD_TRUE) && (bDataLeft == STD_TRUE)) + { + uart_putc_raw(pstrUartLoc, pu8Data[strControl.au16TxIndex[u8Instance]]); + strControl.au16TxIndex[u8Instance]++; + bFifoReady = (uart_is_writable(pstrUartLoc) != 0) ? STD_TRUE : STD_FALSE; + bDataLeft = (strControl.au16TxIndex[u8Instance] < u16Length) ? STD_TRUE : STD_FALSE; + } + + if (bDataLeft == STD_FALSE) + { + strControl.abTxBusy[u8Instance] = STD_FALSE; + vCallTxCallback(u8Instance); + } + else + { + uart_set_irqs_enabled(pstrUartLoc, true, true); + } + } + } + + return enuResultLoc; +} + +/* ========================================================================= */ +/* SEND BUFFER (BLOCKING) */ +/* ========================================================================= */ + +STD_tenuResult MCU_UART_enuSendBufferBlocking(u8 u8Instance, const u8 *pu8Data, u16 u16Length) +{ + STD_tenuResult enuResultLoc = STD_OK; + u16 u16IndexLoc; + + if (pu8Data == STD_NULL) + { + enuResultLoc = STD_NULL_POINTER_ERROR; + } + else + { + for (u16IndexLoc = 0U; u16IndexLoc < u16Length; u16IndexLoc++) + { + uart_putc_raw(apstrInstances[u8Instance], pu8Data[u16IndexLoc]); + } + vCallTxCallback(u8Instance); + } + + return enuResultLoc; +} + +/* ========================================================================= */ +/* TX BUSY CHECK */ +/* ========================================================================= */ + +STD_tBool MCU_UART_bIsTxBusy(u8 u8Instance) +{ + return strControl.abTxBusy[u8Instance]; +} + +/* ========================================================================= */ +/* READ BYTE (NON-BLOCKING) */ +/* ========================================================================= */ + +STD_tenuResult MCU_UART_enuReadByte(u8 u8Instance, u8 *pu8Byte) +{ + STD_tenuResult enuResultLoc = STD_OK; + + if (pu8Byte == STD_NULL) + { + enuResultLoc = STD_NULL_POINTER_ERROR; + } + else + { + u16 u16HeadLoc = u16GetRxHead(u8Instance); + u16 u16TailLoc = strControl.au16RxTail[u8Instance]; + + if (u16HeadLoc == u16TailLoc) + { + enuResultLoc = STD_NOK; + } + else + { + *pu8Byte = strControl.aau8RxBuffer[u8Instance][u16TailLoc]; + strControl.au16RxTail[u8Instance] = (u16TailLoc + 1U) & MCU_UART_RX_BUFFER_MASK; + } + } + + return enuResultLoc; +} + +/* ========================================================================= */ +/* READ BUFFER (NON-BLOCKING) */ +/* ========================================================================= */ + +STD_tenuResult MCU_UART_enuReadBuffer(u8 u8Instance, u8 *pu8Data, u16 u16MaxLength, u16 *pu16Read) +{ + STD_tenuResult enuResultLoc = STD_OK; + + if ((pu8Data == STD_NULL) || (pu16Read == STD_NULL)) + { + enuResultLoc = STD_NULL_POINTER_ERROR; + } + else + { + u16 u16HeadLoc = u16GetRxHead(u8Instance); + u16 u16TailLoc = strControl.au16RxTail[u8Instance]; + u16 u16CountLoc = 0U; + + while ((u16HeadLoc != u16TailLoc) && (u16CountLoc < u16MaxLength)) + { + pu8Data[u16CountLoc] = strControl.aau8RxBuffer[u8Instance][u16TailLoc]; + u16TailLoc = (u16TailLoc + 1U) & MCU_UART_RX_BUFFER_MASK; + u16CountLoc++; + } + + strControl.au16RxTail[u8Instance] = u16TailLoc; + *pu16Read = u16CountLoc; + + if (u16CountLoc == 0U) + { + enuResultLoc = STD_NOK; + } + } + + return enuResultLoc; +} + +/* ========================================================================= */ +/* RX DATA AVAILABLE CHECK */ +/* ========================================================================= */ + +STD_tBool MCU_UART_bIsRxDataAvailable(u8 u8Instance) +{ + STD_tBool bResultLoc = STD_FALSE; + u16 u16HeadLoc = u16GetRxHead(u8Instance); + u16 u16TailLoc = strControl.au16RxTail[u8Instance]; + + if (u16HeadLoc != u16TailLoc) + { + bResultLoc = STD_TRUE; + } + + return bResultLoc; +} \ No newline at end of file diff --git a/prg/MCU_UART_priv.h b/prg/MCU_UART_priv.h new file mode 100644 index 0000000..59178c1 --- /dev/null +++ b/prg/MCU_UART_priv.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * File: MCU_UART_priv.h + * Component: MCU_UART + * Description: Private header — control struct and extern config array. + * + * Layer: MCU (hardware abstraction) - internal use only + *****************************************************************************/ + +#ifndef MCU_UART_PRIV_H +#define MCU_UART_PRIV_H + +#include "MCU_UART.h" +#include "MCU_UART_cfg.h" + +extern const MCU_UART_tstrConfig MCU_UART_astrConfig[MCU_UART_NUM_INSTANCES]; + +typedef struct +{ + /* TX state */ + const u8 *apu8TxBuffer[MCU_UART_NUM_INSTANCES]; + u16 au16TxLength[MCU_UART_NUM_INSTANCES]; + u16 au16TxIndex[MCU_UART_NUM_INSTANCES]; + STD_tBool abTxBusy[MCU_UART_NUM_INSTANCES]; + s8 as8TxDmaChannel[MCU_UART_NUM_INSTANCES]; + + /* RX ring buffer — filled by ISR or DMA in the background */ + u8 aau8RxBuffer[MCU_UART_NUM_INSTANCES][MCU_UART_RX_BUFFER_SIZE] + __attribute__((aligned(MCU_UART_RX_BUFFER_SIZE))); + u16 au16RxHead[MCU_UART_NUM_INSTANCES]; + u16 au16RxTail[MCU_UART_NUM_INSTANCES]; + s8 as8RxDmaChannel[MCU_UART_NUM_INSTANCES]; +} MCU_UART_tstrControl; + +#endif /* MCU_UART_PRIV_H */