mirror of
https://github.com/apache/nuttx.git
synced 2026-10-07 22:35:22 +00:00
arch/arm/stm32: Add DAC low-level operations support.
Add CONFIG_STM32_DAC_LL_OPS support to the common STM32 DAC driver (stm32_dac_m3m4_v1). This provides low-level ops (llops) and helper macros (DAC_ENABLE, DAC_WRITE_DRO, DAC_START_DMA, DAC_STOP_DMA, DAC_DUMP_REGS) matching the existing interface in stm32l4 and stm32h7. This allows real-time control applications (such as power converters, inverters, and function generators) to operate the DAC peripheral directly without char driver VFS overhead. Assisted-by: Antigravity:gemini-3.8-flash Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
This commit is contained in:
parent
8df6e2a3f4
commit
adffae71df
2 changed files with 295 additions and 5 deletions
|
|
@ -30,6 +30,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <nuttx/debug.h>
|
||||
|
|
@ -560,6 +561,9 @@ struct stm32_dac_s
|
|||
|
||||
struct stm32_chan_s
|
||||
{
|
||||
#ifdef CONFIG_STM32_DAC_LL_OPS
|
||||
const struct stm32_dac_ops_s *llops; /* Low-level DAC ops */
|
||||
#endif
|
||||
uint8_t inuse : 1; /* True, the driver is in use and not available */
|
||||
#ifdef HAVE_DMA
|
||||
uint8_t hasdma : 1; /* True, this channel supports DMA */
|
||||
|
|
@ -632,6 +636,17 @@ static void dma_bufferinit(struct stm32_chan_s *chan, uint16_t *buffer,
|
|||
static int dac_chaninit(struct stm32_chan_s *chan);
|
||||
static int dac_blockinit(void);
|
||||
|
||||
#ifdef CONFIG_STM32_DAC_LL_OPS
|
||||
static void dac_dumpregs(struct stm32_chan_s *priv);
|
||||
static void dac_llops_enable(struct stm32_dac_dev_s *dev, bool enabled);
|
||||
static void dac_llops_writedro(struct stm32_dac_dev_s *dev, uint16_t data);
|
||||
#ifdef HAVE_DMA
|
||||
static void dac_llops_startdma(struct stm32_dac_dev_s *dev);
|
||||
static void dac_llops_stopdma(struct stm32_dac_dev_s *dev);
|
||||
#endif
|
||||
static void dac_llops_dumpregs(struct stm32_dac_dev_s *dev);
|
||||
#endif /* CONFIG_STM32_DAC_LL_OPS */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
|
@ -646,6 +661,21 @@ static const struct dac_ops_s g_dacops =
|
|||
.ao_ioctl = dac_ioctl,
|
||||
};
|
||||
|
||||
/* Publicly visible DAC lower-half operations */
|
||||
|
||||
#ifdef CONFIG_STM32_DAC_LL_OPS
|
||||
static const struct stm32_dac_ops_s g_dac_llops =
|
||||
{
|
||||
.enable = dac_llops_enable,
|
||||
.write_dro = dac_llops_writedro,
|
||||
#ifdef HAVE_DMA
|
||||
.start_dma = dac_llops_startdma,
|
||||
.stop_dma = dac_llops_stopdma,
|
||||
#endif
|
||||
.dump_regs = dac_llops_dumpregs
|
||||
};
|
||||
#endif /* CONFIG_STM32_DAC_LL_OPS */
|
||||
|
||||
#ifdef CONFIG_STM32_DAC1
|
||||
#ifdef CONFIG_STM32_DAC1CH1
|
||||
/* Channel 1: DAC1 channel 1 */
|
||||
|
|
@ -656,10 +686,13 @@ uint16_t dac1ch1_buffer[CONFIG_STM32_DAC1CH1_DMA_BUFFER_SIZE];
|
|||
|
||||
static struct stm32_chan_s g_dac1ch1priv =
|
||||
{
|
||||
#ifdef CONFIG_STM32_DAC_LL_OPS
|
||||
.llops = &g_dac_llops,
|
||||
#endif
|
||||
.intf = 0,
|
||||
.pin = GPIO_DAC1_OUT1,
|
||||
#ifdef HAVE_IP_DAC_V2
|
||||
.mode = CONFIG_STM32_DAC1CH1_MODE;
|
||||
.mode = CONFIG_STM32_DAC1CH1_MODE,
|
||||
#endif
|
||||
.dro = STM32_DAC1_DHR12R1,
|
||||
.cr = STM32_DAC1_CR,
|
||||
|
|
@ -704,10 +737,13 @@ uint16_t dac1ch2_buffer[CONFIG_STM32_DAC1CH2_DMA_BUFFER_SIZE];
|
|||
|
||||
static struct stm32_chan_s g_dac1ch2priv =
|
||||
{
|
||||
#ifdef CONFIG_STM32_DAC_LL_OPS
|
||||
.llops = &g_dac_llops,
|
||||
#endif
|
||||
.intf = 1,
|
||||
.pin = GPIO_DAC1_OUT2,
|
||||
#ifdef HAVE_IP_DAC_V2
|
||||
.mode = CONFIG_STM32_DAC1CH2_MODE << 16;
|
||||
.mode = CONFIG_STM32_DAC1CH2_MODE << 16,
|
||||
#endif
|
||||
.dro = STM32_DAC1_DHR12R2,
|
||||
.cr = STM32_DAC1_CR,
|
||||
|
|
@ -755,10 +791,13 @@ uint16_t dac2ch1_buffer[CONFIG_STM32_DAC2CH1_DMA_BUFFER_SIZE];
|
|||
|
||||
static struct stm32_chan_s g_dac2ch1priv =
|
||||
{
|
||||
#ifdef CONFIG_STM32_DAC_LL_OPS
|
||||
.llops = &g_dac_llops,
|
||||
#endif
|
||||
.intf = 2,
|
||||
.pin = GPIO_DAC2_OUT1,
|
||||
#ifdef HAVE_IP_DAC_V2
|
||||
.mode = CONFIG_STM32_DAC2CH1_MODE;
|
||||
.mode = CONFIG_STM32_DAC2CH1_MODE,
|
||||
#endif
|
||||
.dro = STM32_DAC2_DHR12R1,
|
||||
.cr = STM32_DAC2_CR,
|
||||
|
|
@ -805,10 +844,13 @@ static struct dac_dev_s g_dac2ch1dev =
|
|||
|
||||
static struct stm32_chan_s g_dac3ch1priv =
|
||||
{
|
||||
#ifdef CONFIG_STM32_DAC_LL_OPS
|
||||
.llops = &g_dac_llops,
|
||||
#endif
|
||||
.intf = 4,
|
||||
.dro = STM32_DAC3_DHR12R1,
|
||||
#ifdef HAVE_IP_DAC_V2
|
||||
.mode = CONFIG_STM32_DAC3CH1_MODE;
|
||||
.mode = CONFIG_STM32_DAC3CH1_MODE,
|
||||
#endif
|
||||
.cr = STM32_DAC3_CR,
|
||||
#ifdef HAVE_IP_DAC_V2
|
||||
|
|
@ -833,6 +875,9 @@ static struct dac_dev_s g_dac3ch1dev =
|
|||
|
||||
static struct stm32_chan_s g_dac3ch2priv =
|
||||
{
|
||||
#ifdef CONFIG_STM32_DAC_LL_OPS
|
||||
.llops = &g_dac_llops,
|
||||
#endif
|
||||
.intf = 5,
|
||||
.dro = STM32_DAC3_DHR12R2,
|
||||
#ifdef HAVE_IP_DAC_V2
|
||||
|
|
@ -893,6 +938,33 @@ static inline void stm32_dac_modify_cr(struct stm32_chan_s *chan,
|
|||
modifyreg32(chan->cr, clearbits << shift, setbits << shift);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_STM32_DAC_LL_OPS
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dac_dumpregs
|
||||
****************************************************************************/
|
||||
|
||||
static void dac_dumpregs(struct stm32_chan_s *priv)
|
||||
{
|
||||
uint32_t base = priv->cr - STM32_DAC_CR_OFFSET;
|
||||
|
||||
ainfo("CR: 0x%08" PRIx32 " SWTRGR: 0x%08" PRIx32
|
||||
" SR: 0x%08" PRIx32
|
||||
#ifdef HAVE_IP_DAC_V2
|
||||
" MCR: 0x%08" PRIx32
|
||||
#endif
|
||||
"\n",
|
||||
getreg32(base + STM32_DAC_CR_OFFSET),
|
||||
getreg32(base + STM32_DAC_SWTRIGR_OFFSET),
|
||||
getreg32(base + STM32_DAC_SR_OFFSET)
|
||||
#ifdef HAVE_IP_DAC_V2
|
||||
, getreg32(base + STM32_DAC_MCR_OFFSET)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_STM32_DAC_LL_OPS */
|
||||
|
||||
#ifdef HAVE_TIMER
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -1130,6 +1202,7 @@ static int dac_send(struct dac_dev_s *dev, struct dac_msg_s *msg)
|
|||
|
||||
uint32_t regval;
|
||||
uint32_t dac = (chan->intf >> 1);
|
||||
|
||||
do
|
||||
{
|
||||
regval = getreg32(chan->sr);
|
||||
|
|
@ -1268,7 +1341,7 @@ static int dma_remap(struct stm32_chan_s *chan)
|
|||
|
||||
regval |= SYSCFG_CFGR1_DAC1CH1_DMARMP;
|
||||
|
||||
/* Remap DAC trigger for STM32F33XX if needed */
|
||||
/* Remap DAC trigger for STM32F33XX if needed */
|
||||
|
||||
# ifdef CONFIG_STM32_STM32F33XX
|
||||
# if defined(CONFIG_STM32_DAC1CH1_HRTIM_TRG1)
|
||||
|
|
@ -1702,6 +1775,166 @@ static int dac_blockinit(void)
|
|||
return OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_STM32_DAC_LL_OPS
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dac_llops_enable
|
||||
*
|
||||
* Description:
|
||||
* Enable or disable DAC channel.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Pointer to the DAC device structure.
|
||||
* enabled - True to enable, false to disable.
|
||||
*
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void dac_llops_enable(struct stm32_dac_dev_s *dev, bool enabled)
|
||||
{
|
||||
struct stm32_chan_s *priv = (struct stm32_chan_s *)dev;
|
||||
|
||||
/* Enable/disable DAC Channel */
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
stm32_dac_modify_cr(priv, 0, DAC_CR_EN);
|
||||
}
|
||||
else
|
||||
{
|
||||
stm32_dac_modify_cr(priv, DAC_CR_EN, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dac_llops_writedro
|
||||
*
|
||||
* Description:
|
||||
* Write data to DAC data output register.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Pointer to the DAC device structure.
|
||||
* data - Value to write to the data holding register.
|
||||
*
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void dac_llops_writedro(struct stm32_dac_dev_s *dev, uint16_t data)
|
||||
{
|
||||
struct stm32_chan_s *priv = (struct stm32_chan_s *)dev;
|
||||
|
||||
#if defined(HAVE_IP_DAC_V1)
|
||||
putreg16(data, priv->dro);
|
||||
#else
|
||||
putreg32(data, priv->dro);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dac_llops_startdma
|
||||
*
|
||||
* Description:
|
||||
* Start DMA transfer for DAC channel.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Pointer to the DAC device structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_DMA
|
||||
static void dac_llops_startdma(struct stm32_dac_dev_s *dev)
|
||||
{
|
||||
struct stm32_chan_s *priv = (struct stm32_chan_s *)dev;
|
||||
|
||||
/* Configure the DMA stream/channel */
|
||||
|
||||
stm32_dmasetup(priv->dma, priv->dro, (uint32_t)priv->dmabuffer,
|
||||
priv->buffer_len, DAC_DMA_CONTROL_WORD);
|
||||
|
||||
/* Start the DMA */
|
||||
|
||||
stm32_dmastart(priv->dma, dac_dmatxcallback, priv, false);
|
||||
|
||||
/* Enable DMA for DAC Channel */
|
||||
|
||||
stm32_dac_modify_cr(priv, 0, DAC_CR_DMAEN);
|
||||
|
||||
#ifdef HAVE_TIMER
|
||||
/* Reset timer counters and enable counter */
|
||||
|
||||
if (priv->timer != TIM_INDEX_HRTIM)
|
||||
{
|
||||
tim_modifyreg(priv, STM32_GTIM_EGR_OFFSET, 0, GTIM_EGR_UG);
|
||||
tim_modifyreg(priv, STM32_GTIM_CR1_OFFSET, 0, GTIM_CR1_CEN);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dac_llops_stopdma
|
||||
*
|
||||
* Description:
|
||||
* Stop DMA transfer for DAC channel.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Pointer to the DAC device structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void dac_llops_stopdma(struct stm32_dac_dev_s *dev)
|
||||
{
|
||||
struct stm32_chan_s *priv = (struct stm32_chan_s *)dev;
|
||||
|
||||
/* Stop the DMA */
|
||||
|
||||
stm32_dmastop(priv->dma);
|
||||
|
||||
/* Disable DMA for DAC Channel */
|
||||
|
||||
stm32_dac_modify_cr(priv, DAC_CR_DMAEN, 0);
|
||||
|
||||
#ifdef HAVE_TIMER
|
||||
if (priv->timer != TIM_INDEX_HRTIM)
|
||||
{
|
||||
tim_modifyreg(priv, STM32_GTIM_CR1_OFFSET, GTIM_CR1_CEN, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* HAVE_DMA */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dac_llops_dumpregs
|
||||
*
|
||||
* Description:
|
||||
* Dump DAC registers.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Pointer to the DAC device structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void dac_llops_dumpregs(struct stm32_dac_dev_s *dev)
|
||||
{
|
||||
struct stm32_chan_s *priv = (struct stm32_chan_s *)dev;
|
||||
|
||||
dac_dumpregs(priv);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_STM32_DAC_LL_OPS */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@
|
|||
#if defined(CONFIG_STM32_HAVE_IP_DAC_M3M4_V1) || \
|
||||
defined(CONFIG_STM32_HAVE_IP_DAC_M3M4_V2)
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "chip.h"
|
||||
#include "hardware/stm32_dac.h"
|
||||
|
||||
|
|
@ -92,6 +94,19 @@
|
|||
# undef CONFIG_STM32_TIM14_DAC
|
||||
#endif
|
||||
|
||||
/* Low-level ops helpers ****************************************************/
|
||||
|
||||
#define DAC_ENABLE(dac,d) \
|
||||
(dac)->llops->enable(dac,d)
|
||||
#define DAC_WRITE_DRO(dac,d) \
|
||||
(dac)->llops->write_dro(dac,d)
|
||||
#define DAC_START_DMA(dac) \
|
||||
(dac)->llops->start_dma(dac)
|
||||
#define DAC_STOP_DMA(dac) \
|
||||
(dac)->llops->stop_dma(dac)
|
||||
#define DAC_DUMP_REGS(dac) \
|
||||
(dac)->llops->dump_regs(dac)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
|
@ -103,6 +118,48 @@ enum dac_io_cmds
|
|||
IO_DMABUFFER_INIT = 0,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_STM32_DAC_LL_OPS
|
||||
|
||||
/* This structure provides the publicly visible representation of the
|
||||
* "lower-half" DAC driver structure.
|
||||
*/
|
||||
|
||||
struct stm32_dac_dev_s
|
||||
{
|
||||
/* Publicly visible portion of the "lower-half" DAC driver structure */
|
||||
|
||||
const struct stm32_dac_ops_s *llops;
|
||||
|
||||
/* Require cast-compatibility with private "lower-half" DAC structure */
|
||||
};
|
||||
|
||||
/* Low-level operations for DAC */
|
||||
|
||||
struct stm32_dac_ops_s
|
||||
{
|
||||
/* Enable / Disable DAC */
|
||||
|
||||
void (*enable)(struct stm32_dac_dev_s *dev, bool enabled);
|
||||
|
||||
/* Write DRO */
|
||||
|
||||
void (*write_dro)(struct stm32_dac_dev_s *dev, uint16_t data);
|
||||
|
||||
/* Start DMA */
|
||||
|
||||
void (*start_dma)(struct stm32_dac_dev_s *dev);
|
||||
|
||||
/* Stop DMA */
|
||||
|
||||
void (*stop_dma)(struct stm32_dac_dev_s *dev);
|
||||
|
||||
/* Dump DAC regs */
|
||||
|
||||
void (*dump_regs)(struct stm32_dac_dev_s *dev);
|
||||
};
|
||||
|
||||
#endif /* CONFIG_STM32_DAC_LL_OPS */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue