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.
pull/1/head
Damien George 2019-04-24 15:51:19 +10:00
parent 27d22d8712
commit aa7b32c811
6 changed files with 226 additions and 182 deletions

View File

@ -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 \

View File

@ -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));
}
// 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);
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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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