/****************************************************************************** * File: MCU_PIO_prg.c * Component: MCU_PIO * Description: Generic PIO driver implementation. Loads PIO programs into * instruction memory, calls program-specific init callbacks, * claims DMA channels, and provides blocking + async writes. * * Layer: MCU (hardware abstraction) *****************************************************************************/ #include "MCU_PIO.h" #include "MCU_PIO_priv.h" #include "MCU_PIO_cfg.h" #include "hardware/pio.h" #include "hardware/dma.h" /* ------------------------------------------------------------------------ */ /* RUNTIME STATE */ /* ------------------------------------------------------------------------ */ static MCU_PIO_tstrControl strControl; /* ========================================================================= */ /* INIT */ /* ========================================================================= */ STD_tenuResult MCU_PIO_enuInit(void) { STD_tenuResult enuResultLoc = STD_OK; u8 u8IndexLoc; for (u8IndexLoc = 0U; u8IndexLoc < (u8)MCU_PIO_NUM_INSTANCES; u8IndexLoc++) { const MCU_PIO_tstrConfig *pstrCfgLoc = &MCU_PIO_astrConfig[u8IndexLoc]; /* Load the PIO program into instruction memory */ u32 u32OffsetLoc = (u32)pio_add_program(pstrCfgLoc->pstrPio, pstrCfgLoc->pstrProgram); /* Call the program-specific init callback to configure the SM */ pstrCfgLoc->pfProgramInit(pstrCfgLoc->pstrPio, pstrCfgLoc->u8Sm, pstrCfgLoc->u8Pin, u32OffsetLoc); /* Claim a DMA channel for async FIFO writes. Reserved for the * lifetime of the application — never released. true = panic * if no channels available (misconfiguration, not a runtime error). */ strControl.as8DmaChannel[u8IndexLoc] = (s8)dma_claim_unused_channel(true); } return enuResultLoc; } /* ========================================================================= */ /* PUT BLOCKING (SINGLE WORD) */ /* ========================================================================= */ void MCU_PIO_vPutBlocking(u8 u8Instance, u32 u32Data) { const MCU_PIO_tstrConfig *pstrCfgLoc = &MCU_PIO_astrConfig[u8Instance]; /* Blocks until the TX FIFO has space, then writes the 32-bit word */ pio_sm_put_blocking(pstrCfgLoc->pstrPio, pstrCfgLoc->u8Sm, u32Data); } /* ========================================================================= */ /* PUT BUFFER ASYNC (DMA, NON-BLOCKING) */ /* ========================================================================= */ STD_tenuResult MCU_PIO_enuPutBufferAsync(u8 u8Instance, const u32 *pu32Data, u16 u16Count) { STD_tenuResult enuResultLoc = STD_OK; if (pu32Data == STD_NULL) { enuResultLoc = STD_NULL_POINTER_ERROR; } else { const MCU_PIO_tstrConfig *pstrCfgLoc = &MCU_PIO_astrConfig[u8Instance]; s8 s8ChLoc = strControl.as8DmaChannel[u8Instance]; dma_channel_config strCfgLoc = dma_channel_get_default_config((u32)s8ChLoc); /* 32-bit transfers — matches the PIO FIFO word size */ channel_config_set_transfer_data_size(&strCfgLoc, DMA_SIZE_32); /* Source: increment through the caller's buffer */ channel_config_set_read_increment(&strCfgLoc, true); /* Destination: PIO TX FIFO register (fixed address) */ channel_config_set_write_increment(&strCfgLoc, false); /* Pace by PIO TX FIFO DREQ — DMA only pushes when SM can accept */ channel_config_set_dreq(&strCfgLoc, pio_get_dreq(pstrCfgLoc->pstrPio, pstrCfgLoc->u8Sm, true)); /* Start the DMA transfer. Runs autonomously until u16Count words * have been pushed into the FIFO. Caller must keep pu32Data valid * until transfer completes. */ dma_channel_configure( (u32)s8ChLoc, &strCfgLoc, &pstrCfgLoc->pstrPio->txf[pstrCfgLoc->u8Sm], /* dest: PIO TX FIFO */ pu32Data, /* source: buffer */ u16Count, /* word count */ true /* start immediately */ ); } return enuResultLoc; }