stm32/dac: Rework DAC driver to use direct register access.
This patch makes the DAC driver simpler and removes the need for the ST HAL. As part of it, new helper functions are added to the DMA driver, which also use direct register access instead of the ST HAL. Main changes to the DAC interface are: - The DAC uPy object is no longer allocated dynamically on the heap, rather it's statically allocated and the same object is retrieved for subsequent uses of pyb.DAC(<id>). This allows to access the DAC objects without resetting the DAC peripheral. It also means that the DAC is only reset if explicitly passed initialisation parameters, like "bits" or "buffering". - The DAC.noise() and DAC.triangle() methods now output a signal which is full scale (previously it was a fraction of the full output voltage). - The DAC.write_timed() method is fixed so that it continues in the background when another peripheral (eg SPI) uses the DMA (previously the DAC would stop if another peripheral finished with the DMA and shut the DMA peripheral off completely). Based on the above, the following backwards incompatibilities are introduced: - pyb.DAC(id) will now only reset the DAC the first time it is called, whereas previously each call to create a DAC object would reset the DAC. To get the old behaviour pass the bits parameter like: pyb.DAC(id, bits). - DAC.noise() and DAC.triangle() are now full scale. To get previous behaviour (to change the amplitude and offset) write to the DAC_CR (MAMP bits) and DAC_DHR12Rx registers manually.
This commit is contained in:
parent
27d22d8712
commit
aa7b32c811
|
@ -296,8 +296,6 @@ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
|
|||
hal_adc.c \
|
||||
hal_adc_ex.c \
|
||||
hal_cortex.c \
|
||||
hal_dac.c \
|
||||
hal_dac_ex.c \
|
||||
hal_dma.c \
|
||||
hal_flash.c \
|
||||
hal_flash_ex.c \
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
* Copyright (c) 2013-2019 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -70,15 +70,6 @@
|
|||
#define DAC DAC1
|
||||
#endif
|
||||
|
||||
STATIC DAC_HandleTypeDef DAC_Handle;
|
||||
|
||||
void dac_init(void) {
|
||||
memset(&DAC_Handle, 0, sizeof DAC_Handle);
|
||||
DAC_Handle.Instance = DAC;
|
||||
DAC_Handle.State = HAL_DAC_STATE_RESET;
|
||||
HAL_DAC_Init(&DAC_Handle);
|
||||
}
|
||||
|
||||
#if defined(TIM6)
|
||||
STATIC void TIM6_Config(uint freq) {
|
||||
// Init TIM6 at the required frequency (in Hz)
|
||||
|
@ -131,27 +122,97 @@ STATIC uint32_t TIMx_Config(mp_obj_t timer) {
|
|||
}
|
||||
}
|
||||
|
||||
STATIC void dac_deinit(uint32_t dac_channel) {
|
||||
DAC->CR &= ~(DAC_CR_EN1 << dac_channel);
|
||||
#if defined(STM32H7) || defined(STM32L4)
|
||||
DAC->MCR = (DAC->MCR & ~(DAC_MCR_MODE1_Msk << dac_channel)) | (DAC_OUTPUTBUFFER_DISABLE << dac_channel);
|
||||
#else
|
||||
DAC->CR |= DAC_CR_BOFF1 << dac_channel;
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC void dac_config_channel(uint32_t dac_channel, uint32_t trig, uint32_t outbuf) {
|
||||
DAC->CR &= ~(DAC_CR_EN1 << dac_channel);
|
||||
uint32_t cr_off = DAC_CR_DMAEN1 | DAC_CR_MAMP1 | DAC_CR_WAVE1 | DAC_CR_TSEL1 | DAC_CR_TEN1;
|
||||
uint32_t cr_on = trig;
|
||||
#if defined(STM32H7) || defined(STM32L4)
|
||||
DAC->MCR = (DAC->MCR & ~(DAC_MCR_MODE1_Msk << dac_channel)) | (outbuf << dac_channel);
|
||||
#else
|
||||
cr_off |= DAC_CR_BOFF1;
|
||||
cr_on |= outbuf;
|
||||
#endif
|
||||
DAC->CR = (DAC->CR & ~(cr_off << dac_channel)) | (cr_on << dac_channel);
|
||||
}
|
||||
|
||||
STATIC void dac_set_value(uint32_t dac_channel, uint32_t align, uint32_t value) {
|
||||
uint32_t base;
|
||||
if (dac_channel == DAC_CHANNEL_1) {
|
||||
base = (uint32_t)&DAC->DHR12R1;
|
||||
} else {
|
||||
base = (uint32_t)&DAC->DHR12R2;
|
||||
}
|
||||
*(volatile uint32_t*)(base + align) = value;
|
||||
}
|
||||
|
||||
STATIC void dac_start(uint32_t dac_channel) {
|
||||
DAC->CR |= DAC_CR_EN1 << dac_channel;
|
||||
}
|
||||
|
||||
STATIC void dac_start_dma(uint32_t dac_channel, const dma_descr_t *dma_descr, uint32_t dma_mode, uint32_t bit_size, uint32_t dac_align, size_t len, void *buf) {
|
||||
uint32_t dma_align;
|
||||
if (bit_size == 8) {
|
||||
dma_align = DMA_MDATAALIGN_BYTE | DMA_PDATAALIGN_BYTE;
|
||||
} else {
|
||||
dma_align = DMA_MDATAALIGN_HALFWORD | DMA_PDATAALIGN_HALFWORD;
|
||||
}
|
||||
|
||||
uint32_t base;
|
||||
if (dac_channel == DAC_CHANNEL_1) {
|
||||
base = (uint32_t)&DAC->DHR12R1;
|
||||
} else {
|
||||
base = (uint32_t)&DAC->DHR12R2;
|
||||
}
|
||||
|
||||
dma_nohal_deinit(dma_descr);
|
||||
dma_nohal_init(dma_descr, DMA_MEMORY_TO_PERIPH | dma_mode | dma_align);
|
||||
dma_nohal_start(dma_descr, (uint32_t)buf, base + dac_align, len);
|
||||
|
||||
DAC->CR |= DAC_CR_EN1 << dac_channel;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings
|
||||
|
||||
typedef enum {
|
||||
DAC_STATE_RESET,
|
||||
DAC_STATE_WRITE_SINGLE,
|
||||
DAC_STATE_BUILTIN_WAVEFORM,
|
||||
DAC_STATE_DMA_WAVEFORM, // should be last enum since we use space beyond it
|
||||
} pyb_dac_state_t;
|
||||
|
||||
typedef struct _pyb_dac_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint32_t dac_channel; // DAC_CHANNEL_1 or DAC_CHANNEL_2
|
||||
const dma_descr_t *tx_dma_descr;
|
||||
mp_hal_pin_obj_t pin; // pin_A4 or pin_A5
|
||||
uint8_t dac_channel; // DAC_CHANNEL_1 or DAC_CHANNEL_2
|
||||
uint8_t bits; // 8 or 12
|
||||
uint8_t state;
|
||||
uint8_t outbuf_single;
|
||||
uint8_t outbuf_waveform;
|
||||
} pyb_dac_obj_t;
|
||||
|
||||
STATIC pyb_dac_obj_t pyb_dac_obj[2];
|
||||
|
||||
STATIC void pyb_dac_reconfigure(pyb_dac_obj_t *self, uint32_t cr, uint32_t outbuf, uint32_t value) {
|
||||
bool restart = false;
|
||||
const uint32_t cr_mask = DAC_CR_DMAEN1 | DAC_CR_MAMP1 | DAC_CR_WAVE1 | DAC_CR_TSEL1 | DAC_CR_TEN1 | DAC_CR_EN1;
|
||||
if (((DAC->CR >> self->dac_channel) & cr_mask) != (cr | DAC_CR_EN1)) {
|
||||
const dma_descr_t *tx_dma_descr;
|
||||
if (self->dac_channel == DAC_CHANNEL_1) {
|
||||
tx_dma_descr = &dma_DAC_1_TX;
|
||||
} else {
|
||||
tx_dma_descr = &dma_DAC_2_TX;
|
||||
}
|
||||
dma_nohal_deinit(tx_dma_descr);
|
||||
dac_config_channel(self->dac_channel, cr, outbuf);
|
||||
restart = true;
|
||||
}
|
||||
dac_set_value(self->dac_channel, DAC_ALIGN_12B_R, value);
|
||||
if (restart) {
|
||||
dac_start(self->dac_channel);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pyb_dac_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_dac_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "DAC(%u, bits=%u)",
|
||||
|
@ -170,7 +231,13 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp
|
|||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
// GPIO configuration
|
||||
mp_hal_pin_config(self->pin, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0);
|
||||
mp_hal_pin_obj_t pin;
|
||||
if (self->dac_channel == DAC_CHANNEL_1) {
|
||||
pin = pin_A4;
|
||||
} else {
|
||||
pin = pin_A5;
|
||||
}
|
||||
mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0);
|
||||
|
||||
// DAC peripheral clock
|
||||
#if defined(STM32F4) || defined(STM32F7)
|
||||
|
@ -183,20 +250,8 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp
|
|||
#error Unsupported Processor
|
||||
#endif
|
||||
|
||||
// stop anything already going on
|
||||
__HAL_RCC_DMA1_CLK_ENABLE();
|
||||
DMA_HandleTypeDef DMA_Handle;
|
||||
/* Get currently configured dma */
|
||||
dma_init_handle(&DMA_Handle, self->tx_dma_descr, DMA_MEMORY_TO_PERIPH, (void*)NULL);
|
||||
// Need to deinit DMA first
|
||||
DMA_Handle.State = HAL_DMA_STATE_READY;
|
||||
HAL_DMA_DeInit(&DMA_Handle);
|
||||
|
||||
HAL_DAC_Stop(&DAC_Handle, self->dac_channel);
|
||||
if ((self->dac_channel == DAC_CHANNEL_1 && DAC_Handle.DMA_Handle1 != NULL)
|
||||
|| (self->dac_channel == DAC_CHANNEL_2 && DAC_Handle.DMA_Handle2 != NULL)) {
|
||||
HAL_DAC_Stop_DMA(&DAC_Handle, self->dac_channel);
|
||||
}
|
||||
// Stop the DAC in case it was already running
|
||||
DAC->CR &= ~(DAC_CR_EN1 << self->dac_channel);
|
||||
|
||||
// set bit resolution
|
||||
if (args[0].u_int == 8 || args[0].u_int == 12) {
|
||||
|
@ -218,9 +273,6 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp
|
|||
self->outbuf_waveform = DAC_OUTPUTBUFFER_DISABLE;
|
||||
}
|
||||
|
||||
// reset state of DAC
|
||||
self->state = DAC_STATE_RESET;
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
|
@ -251,25 +303,25 @@ STATIC mp_obj_t pyb_dac_make_new(const mp_obj_type_t *type, size_t n_args, size_
|
|||
}
|
||||
}
|
||||
|
||||
pyb_dac_obj_t *dac = m_new_obj(pyb_dac_obj_t);
|
||||
dac->base.type = &pyb_dac_type;
|
||||
|
||||
uint32_t dac_channel;
|
||||
if (dac_id == 1) {
|
||||
dac->pin = pin_A4;
|
||||
dac->dac_channel = DAC_CHANNEL_1;
|
||||
dac->tx_dma_descr = &dma_DAC_1_TX;
|
||||
dac_channel = DAC_CHANNEL_1;
|
||||
} else if (dac_id == 2) {
|
||||
dac->pin = pin_A5;
|
||||
dac->dac_channel = DAC_CHANNEL_2;
|
||||
dac->tx_dma_descr = &dma_DAC_2_TX;
|
||||
dac_channel = DAC_CHANNEL_2;
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "DAC(%d) doesn't exist", dac_id));
|
||||
}
|
||||
|
||||
pyb_dac_obj_t *dac = &pyb_dac_obj[dac_id - 1];
|
||||
dac->base.type = &pyb_dac_type;
|
||||
dac->dac_channel = dac_channel;
|
||||
|
||||
if (dac->bits == 0 || n_args > 1 || n_kw > 0) {
|
||||
// configure the peripheral
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
pyb_dac_init_helper(dac, n_args - 1, args + 1, &kw_args);
|
||||
}
|
||||
|
||||
// return object
|
||||
return MP_OBJ_FROM_PTR(dac);
|
||||
|
@ -284,21 +336,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_dac_init_obj, 1, pyb_dac_init);
|
|||
/// Turn off the DAC, enable other use of pin.
|
||||
STATIC mp_obj_t pyb_dac_deinit(mp_obj_t self_in) {
|
||||
pyb_dac_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
if (self->dac_channel == DAC_CHANNEL_1) {
|
||||
DAC_Handle.Instance->CR &= ~DAC_CR_EN1;
|
||||
#if defined(STM32H7) || defined(STM32L4)
|
||||
DAC->MCR = (DAC->MCR & ~(7 << DAC_MCR_MODE1_Pos)) | 2 << DAC_MCR_MODE1_Pos;
|
||||
#else
|
||||
DAC_Handle.Instance->CR |= DAC_CR_BOFF1;
|
||||
#endif
|
||||
} else {
|
||||
DAC_Handle.Instance->CR &= ~DAC_CR_EN2;
|
||||
#if defined(STM32H7) || defined(STM32L4)
|
||||
DAC->MCR = (DAC->MCR & ~(7 << DAC_MCR_MODE2_Pos)) | 2 << DAC_MCR_MODE2_Pos;
|
||||
#else
|
||||
DAC_Handle.Instance->CR |= DAC_CR_BOFF2;
|
||||
#endif
|
||||
}
|
||||
dac_deinit(self->dac_channel);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_dac_deinit_obj, pyb_dac_deinit);
|
||||
|
@ -313,19 +351,9 @@ STATIC mp_obj_t pyb_dac_noise(mp_obj_t self_in, mp_obj_t freq) {
|
|||
// set TIM6 to trigger the DAC at the given frequency
|
||||
TIM6_Config(mp_obj_get_int(freq));
|
||||
|
||||
if (self->state != DAC_STATE_BUILTIN_WAVEFORM) {
|
||||
// configure DAC to trigger via TIM6
|
||||
DAC_ChannelConfTypeDef config;
|
||||
config.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
|
||||
config.DAC_OutputBuffer = self->outbuf_waveform;
|
||||
HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
|
||||
self->state = DAC_STATE_BUILTIN_WAVEFORM;
|
||||
}
|
||||
|
||||
// set noise wave generation
|
||||
HAL_DACEx_NoiseWaveGenerate(&DAC_Handle, self->dac_channel, DAC_LFSRUNMASK_BITS10_0);
|
||||
HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_12B_L, 0x7ff0);
|
||||
HAL_DAC_Start(&DAC_Handle, self->dac_channel);
|
||||
// Configure DAC in noise mode with trigger via TIM6
|
||||
uint32_t cr = DAC_LFSRUNMASK_BITS11_0 | DAC_CR_WAVE1_0 | DAC_TRIGGER_T6_TRGO;
|
||||
pyb_dac_reconfigure(self, cr, self->outbuf_waveform, 0);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
@ -343,19 +371,9 @@ STATIC mp_obj_t pyb_dac_triangle(mp_obj_t self_in, mp_obj_t freq) {
|
|||
// set TIM6 to trigger the DAC at the given frequency
|
||||
TIM6_Config(mp_obj_get_int(freq));
|
||||
|
||||
if (self->state != DAC_STATE_BUILTIN_WAVEFORM) {
|
||||
// configure DAC to trigger via TIM6
|
||||
DAC_ChannelConfTypeDef config;
|
||||
config.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
|
||||
config.DAC_OutputBuffer = self->outbuf_waveform;
|
||||
HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
|
||||
self->state = DAC_STATE_BUILTIN_WAVEFORM;
|
||||
}
|
||||
|
||||
// set triangle wave generation
|
||||
HAL_DACEx_TriangleWaveGenerate(&DAC_Handle, self->dac_channel, DAC_TRIANGLEAMPLITUDE_1023);
|
||||
HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_12B_R, 0x100);
|
||||
HAL_DAC_Start(&DAC_Handle, self->dac_channel);
|
||||
// Configure DAC in triangle mode with trigger via TIM6
|
||||
uint32_t cr = DAC_TRIANGLEAMPLITUDE_4095 | DAC_CR_WAVE1_1 | DAC_TRIGGER_T6_TRGO;
|
||||
pyb_dac_reconfigure(self, cr, self->outbuf_waveform, 0);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
@ -367,20 +385,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_dac_triangle_obj, pyb_dac_triangle);
|
|||
STATIC mp_obj_t pyb_dac_write(mp_obj_t self_in, mp_obj_t val) {
|
||||
pyb_dac_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
if (self->state != DAC_STATE_WRITE_SINGLE) {
|
||||
DAC_ChannelConfTypeDef config;
|
||||
config.DAC_Trigger = DAC_TRIGGER_NONE;
|
||||
config.DAC_OutputBuffer = self->outbuf_single;
|
||||
HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
|
||||
self->state = DAC_STATE_WRITE_SINGLE;
|
||||
}
|
||||
|
||||
// DAC output is always 12-bit at the hardware level, and we provide support
|
||||
// for multiple bit "resolutions" simply by shifting the input value.
|
||||
HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_12B_R,
|
||||
mp_obj_get_int(val) << (12 - self->bits));
|
||||
|
||||
HAL_DAC_Start(&DAC_Handle, self->dac_channel);
|
||||
uint32_t cr = DAC_TRIGGER_NONE;
|
||||
uint32_t value = mp_obj_get_int(val) << (12 - self->bits);
|
||||
pyb_dac_reconfigure(self, cr, self->outbuf_single, value);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
@ -432,83 +441,24 @@ mp_obj_t pyb_dac_write_timed(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
|
|||
dac_trigger = TIMx_Config(args[1].u_obj);
|
||||
}
|
||||
|
||||
__HAL_RCC_DMA1_CLK_ENABLE();
|
||||
|
||||
DMA_HandleTypeDef DMA_Handle;
|
||||
/* Get currently configured dma */
|
||||
dma_init_handle(&DMA_Handle, self->tx_dma_descr, DMA_MEMORY_TO_PERIPH, (void*)NULL);
|
||||
/*
|
||||
DMA_Cmd(DMA_Handle->Instance, DISABLE);
|
||||
while (DMA_GetCmdStatus(DMA_Handle->Instance) != DISABLE) {
|
||||
}
|
||||
|
||||
DAC_Cmd(self->dac_channel, DISABLE);
|
||||
*/
|
||||
|
||||
/*
|
||||
// DAC channel configuration
|
||||
DAC_InitTypeDef DAC_InitStructure;
|
||||
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T7_TRGO;
|
||||
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
|
||||
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_1; // unused, but need to set it to a valid value
|
||||
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
|
||||
DAC_Init(self->dac_channel, &DAC_InitStructure);
|
||||
*/
|
||||
|
||||
// Need to deinit DMA first
|
||||
DMA_Handle.State = HAL_DMA_STATE_READY;
|
||||
HAL_DMA_DeInit(&DMA_Handle);
|
||||
|
||||
if (self->bits == 8) {
|
||||
DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
} else {
|
||||
DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
|
||||
DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
|
||||
}
|
||||
DMA_Handle.Init.Mode = args[2].u_int;
|
||||
HAL_DMA_Init(&DMA_Handle);
|
||||
dac_config_channel(self->dac_channel, DAC_CR_DMAEN1 | dac_trigger, self->outbuf_waveform);
|
||||
|
||||
const dma_descr_t *tx_dma_descr;
|
||||
if (self->dac_channel == DAC_CHANNEL_1) {
|
||||
__HAL_LINKDMA(&DAC_Handle, DMA_Handle1, DMA_Handle);
|
||||
tx_dma_descr = &dma_DAC_1_TX;
|
||||
} else {
|
||||
__HAL_LINKDMA(&DAC_Handle, DMA_Handle2, DMA_Handle);
|
||||
}
|
||||
|
||||
DAC_Handle.Instance = DAC;
|
||||
DAC_Handle.State = HAL_DAC_STATE_RESET;
|
||||
HAL_DAC_Init(&DAC_Handle);
|
||||
|
||||
if (self->state != DAC_STATE_DMA_WAVEFORM + dac_trigger) {
|
||||
DAC_ChannelConfTypeDef config;
|
||||
config.DAC_Trigger = dac_trigger;
|
||||
config.DAC_OutputBuffer = self->outbuf_waveform;
|
||||
HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
|
||||
self->state = DAC_STATE_DMA_WAVEFORM + dac_trigger;
|
||||
tx_dma_descr = &dma_DAC_2_TX;
|
||||
}
|
||||
|
||||
uint32_t align;
|
||||
if (self->bits == 8) {
|
||||
HAL_DAC_Start_DMA(&DAC_Handle, self->dac_channel,
|
||||
(uint32_t*)bufinfo.buf, bufinfo.len, DAC_ALIGN_8B_R);
|
||||
align = DAC_ALIGN_8B_R;
|
||||
} else {
|
||||
HAL_DAC_Start_DMA(&DAC_Handle, self->dac_channel,
|
||||
(uint32_t*)bufinfo.buf, bufinfo.len / 2, DAC_ALIGN_12B_R);
|
||||
align = DAC_ALIGN_12B_R;
|
||||
bufinfo.len /= 2;
|
||||
}
|
||||
|
||||
/*
|
||||
// enable DMA stream
|
||||
DMA_Cmd(DMA_Handle->Instance, ENABLE);
|
||||
while (DMA_GetCmdStatus(DMA_Handle->Instance) == DISABLE) {
|
||||
}
|
||||
|
||||
// enable DAC channel
|
||||
DAC_Cmd(self->dac_channel, ENABLE);
|
||||
|
||||
// enable DMA for DAC channel
|
||||
DAC_DMACmd(self->dac_channel, ENABLE);
|
||||
*/
|
||||
|
||||
//printf("DMA: %p %lu\n", bufinfo.buf, bufinfo.len);
|
||||
dac_start_dma(self->dac_channel, tx_dma_descr, args[2].u_int, self->bits, align, bufinfo.len, bufinfo.buf);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
|
|
@ -26,8 +26,6 @@
|
|||
#ifndef MICROPY_INCLUDED_STM32_DAC_H
|
||||
#define MICROPY_INCLUDED_STM32_DAC_H
|
||||
|
||||
void dac_init(void);
|
||||
|
||||
extern const mp_obj_type_t pyb_dac_type;
|
||||
|
||||
#endif // MICROPY_INCLUDED_STM32_DAC_H
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Damien P. George
|
||||
* Copyright (c) 2015-2019 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -29,6 +29,7 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/mphal.h"
|
||||
#include "systick.h"
|
||||
#include "dma.h"
|
||||
#include "irq.h"
|
||||
|
@ -729,3 +730,100 @@ static void dma_idle_handler(uint32_t tick) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(STM32F0) || defined(STM32L4)
|
||||
|
||||
void dma_nohal_init(const dma_descr_t *descr, uint32_t config) {
|
||||
DMA_Channel_TypeDef *dma = descr->instance;
|
||||
|
||||
// Enable the DMA peripheral
|
||||
dma_enable_clock(descr->id);
|
||||
|
||||
// Set main configuration register
|
||||
dma->CCR =
|
||||
descr->init->Priority // PL
|
||||
| descr->init->MemInc // MINC
|
||||
| descr->init->PeriphInc // PINC
|
||||
| config // MSIZE | PSIZE | CIRC | DIR
|
||||
;
|
||||
|
||||
// Select channel that the DMA stream uses
|
||||
#if defined(STM32F0)
|
||||
if (dma < DMA2_Channel1) {
|
||||
__HAL_DMA1_REMAP(descr->sub_instance);
|
||||
} else {
|
||||
__HAL_DMA2_REMAP(descr->sub_instance);
|
||||
}
|
||||
#else
|
||||
DMA_Request_TypeDef *dma_ctrl = (void*)(((uint32_t)dma & ~0xff) + (DMA1_CSELR_BASE - DMA1_BASE)); // DMA1_CSELR or DMA2_CSELR
|
||||
uint32_t channel_number = (((uint32_t)dma & 0xff) - 0x08) / 20; // 0 through 6
|
||||
uint32_t channel_pos = channel_number * 4;
|
||||
dma_ctrl->CSELR = (dma_ctrl->CSELR & ~(0xf << channel_pos)) | (descr->sub_instance << channel_pos);
|
||||
#endif
|
||||
}
|
||||
|
||||
void dma_nohal_deinit(const dma_descr_t *descr) {
|
||||
DMA_Channel_TypeDef *dma = descr->instance;
|
||||
dma->CCR &= ~DMA_CCR_EN;
|
||||
dma->CCR = 0;
|
||||
dma->CNDTR = 0;
|
||||
dma_deinit(descr);
|
||||
}
|
||||
|
||||
void dma_nohal_start(const dma_descr_t *descr, uint32_t src_addr, uint32_t dst_addr, uint16_t len) {
|
||||
DMA_Channel_TypeDef *dma = descr->instance;
|
||||
dma->CNDTR = len;
|
||||
dma->CPAR = dst_addr;
|
||||
dma->CMAR = src_addr;
|
||||
dma->CCR |= DMA_CCR_EN;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void dma_nohal_init(const dma_descr_t *descr, uint32_t config) {
|
||||
DMA_Stream_TypeDef *dma = descr->instance;
|
||||
|
||||
// Enable the DMA peripheral
|
||||
dma_enable_clock(descr->id);
|
||||
|
||||
// Set main configuration register
|
||||
const DMA_InitTypeDef *init = descr->init;
|
||||
dma->CR =
|
||||
descr->sub_instance // CHSEL
|
||||
| init->MemBurst // MBURST
|
||||
| init->PeriphBurst // PBURST
|
||||
| init->Priority // PL
|
||||
| init->MemInc // MINC
|
||||
| init->PeriphInc // PINC
|
||||
| config // MSIZE | PSIZE | CIRC | DIR
|
||||
;
|
||||
|
||||
// Set FIFO control register
|
||||
dma->FCR =
|
||||
init->FIFOMode // DMDIS
|
||||
| init->FIFOThreshold // FTH
|
||||
;
|
||||
}
|
||||
|
||||
void dma_nohal_deinit(const dma_descr_t *descr) {
|
||||
DMA_Stream_TypeDef *dma = descr->instance;
|
||||
dma->CR &= ~DMA_SxCR_EN;
|
||||
uint32_t t0 = mp_hal_ticks_ms();
|
||||
while ((dma->CR & DMA_SxCR_EN) && mp_hal_ticks_ms() - t0 < 100) {
|
||||
}
|
||||
dma->CR = 0;
|
||||
dma->NDTR = 0;
|
||||
dma->FCR = 0x21;
|
||||
dma_deinit(descr);
|
||||
}
|
||||
|
||||
void dma_nohal_start(const dma_descr_t *descr, uint32_t src_addr, uint32_t dst_addr, uint16_t len) {
|
||||
DMA_Stream_TypeDef *dma = descr->instance;
|
||||
dma->CR &= ~DMA_SxCR_DBM;
|
||||
dma->NDTR = len;
|
||||
dma->PAR = dst_addr;
|
||||
dma->M0AR = src_addr;
|
||||
dma->CR |= DMA_SxCR_EN;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -86,4 +86,8 @@ void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint3
|
|||
void dma_deinit(const dma_descr_t *dma_descr);
|
||||
void dma_invalidate_channel(const dma_descr_t *dma_descr);
|
||||
|
||||
void dma_nohal_init(const dma_descr_t *descr, uint32_t config);
|
||||
void dma_nohal_deinit(const dma_descr_t *descr);
|
||||
void dma_nohal_start(const dma_descr_t *descr, uint32_t src_addr, uint32_t dst_addr, uint16_t len);
|
||||
|
||||
#endif // MICROPY_INCLUDED_STM32_DMA_H
|
||||
|
|
|
@ -721,10 +721,6 @@ soft_reset:
|
|||
servo_init();
|
||||
#endif
|
||||
|
||||
#if MICROPY_HW_ENABLE_DAC
|
||||
dac_init();
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_NETWORK
|
||||
mod_network_init();
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue