mcu_pio/prg/MCU_PIO_prg.c

115 lines
4.7 KiB
C

/******************************************************************************
* 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;
}