stm32/dac: Add STM32H5 DAC support, with dma_nohal implementation.

Integrate DAC support for STM32H5.  Implement STM32H5 GPDMA driver. The DMA
driver is largely different from other STM32 variants.  To support the DAC
circular mode, memory based linked list DMA descriptors are used.

Signed-off-by: Rene Straub <rene@see5.ch>
This commit is contained in:
Rene Straub 2023-08-11 21:26:50 +02:00 committed by Damien George
parent 72ef2e6291
commit 08c661c930
3 changed files with 133 additions and 1 deletions

View File

@ -173,6 +173,8 @@ STATIC void dac_start_dma(uint32_t dac_channel, const dma_descr_t *dma_descr, ui
#if defined(STM32G4)
// For STM32G4, DAC registers have to be accessed by words (32-bit).
dma_align = DMA_MDATAALIGN_BYTE | DMA_PDATAALIGN_WORD;
#elif defined(STM32H5)
dma_align = 0;
#else
dma_align = DMA_MDATAALIGN_BYTE | DMA_PDATAALIGN_BYTE;
#endif
@ -180,6 +182,8 @@ STATIC void dac_start_dma(uint32_t dac_channel, const dma_descr_t *dma_descr, ui
#if defined(STM32G4)
// For STM32G4, DAC registers have to be accessed by words (32-bit).
dma_align = DMA_MDATAALIGN_HALFWORD | DMA_PDATAALIGN_WORD;
#elif defined(STM32H5)
dma_align = 0;
#else
dma_align = DMA_MDATAALIGN_HALFWORD | DMA_PDATAALIGN_HALFWORD;
#endif

View File

@ -185,6 +185,24 @@ static const DMA_InitTypeDef dma_init_struct_sdio = {
#endif
#if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC
#if defined(STM32H5)
// Default parameters to dma_init() for DAC tx
static const DMA_InitTypeDef dma_init_struct_dac = {
.Request = 0, // set by dma_init_handle
.BlkHWRequest = DMA_BREQ_SINGLE_BURST,
.Direction = DMA_MEMORY_TO_PERIPH,
.SrcInc = DMA_SINC_INCREMENTED,
.DestInc = DMA_DINC_FIXED,
.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE,
.DestDataWidth = DMA_DEST_DATAWIDTH_WORD,
.Priority = DMA_HIGH_PRIORITY,
.SrcBurstLength = 1,
.DestBurstLength = 1,
.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT0,
.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER,
.Mode = DMA_NORMAL, // DMA_NORMAL or DMA_PFCTRL (peripheral flow control mode)
};
#else
// Default parameters to dma_init() for DAC tx
static const DMA_InitTypeDef dma_init_struct_dac = {
#if defined(STM32F4) || defined(STM32F7)
@ -207,6 +225,7 @@ static const DMA_InitTypeDef dma_init_struct_dac = {
#endif
};
#endif
#endif
#if MICROPY_HW_ENABLE_DCMI
static const DMA_InitTypeDef dma_init_struct_dcmi = {
@ -715,6 +734,10 @@ const dma_descr_t dma_SPI_1_RX = { GPDMA1_Channel0, GPDMA1_REQUEST_SPI1_RX, dma_
const dma_descr_t dma_SPI_1_TX = { GPDMA1_Channel1, GPDMA1_REQUEST_SPI1_TX, dma_id_1, &dma_init_struct_spi_i2c };
const dma_descr_t dma_SPI_2_RX = { GPDMA1_Channel2, GPDMA1_REQUEST_SPI2_RX, dma_id_2, &dma_init_struct_spi_i2c };
const dma_descr_t dma_SPI_2_TX = { GPDMA1_Channel3, GPDMA1_REQUEST_SPI2_TX, dma_id_3, &dma_init_struct_spi_i2c };
#if MICROPY_HW_ENABLE_DAC
const dma_descr_t dma_DAC_1_TX = { GPDMA1_Channel4, GPDMA1_REQUEST_DAC1_CH1, dma_id_4, &dma_init_struct_dac };
const dma_descr_t dma_DAC_2_TX = { GPDMA1_Channel5, GPDMA1_REQUEST_DAC1_CH2, dma_id_5, &dma_init_struct_dac };
#endif
static const uint8_t dma_irqn[NSTREAM] = {
GPDMA1_Channel0_IRQn,
@ -1613,7 +1636,106 @@ void dma_nohal_start(const dma_descr_t *descr, uint32_t src_addr, uint32_t dst_a
dma->CCR |= DMA_CCR_EN;
}
#elif defined(STM32G0) || defined(STM32H5) || defined(STM32WB) || defined(STM32WL)
#elif defined(STM32H5)
// Fully setup GPDMA linked list entry
typedef struct _dma_ll_full_t {
__IO uint32_t CTR1;
__IO uint32_t CTR2;
__IO uint32_t CBR1;
__IO uint32_t CSAR;
__IO uint32_t CDAR;
__IO uint32_t CLLR;
} dma_ll_full_t;
// Align LL entry to 32 bytes to ensure it never crosses a 64 kB boundary
__ALIGNED(32) static __IO dma_ll_full_t lli1;
void dma_nohal_init(const dma_descr_t *descr, uint32_t config) {
DMA_Channel_TypeDef *dma = descr->instance;
const DMA_InitTypeDef *init = descr->init;
// Enable the DMA peripheral
dma_enable_clock(descr->id);
// - LSM = 0, normal linked list mode
// - No interrupts
// - Not suspended, out of reset, disabled
// - Priority as defined by user
dma->CCR = init->Priority;
uint32_t ctr1reg = 0;
ctr1reg |= init->SrcDataWidth;
ctr1reg |= init->SrcInc;
ctr1reg |= (((init->SrcBurstLength - 1) << DMA_CTR1_SBL_1_Pos)) & DMA_CTR1_SBL_1_Msk;
ctr1reg |= init->DestDataWidth;
ctr1reg |= init->DestInc;
ctr1reg |= (((init->DestBurstLength - 1) << DMA_CTR1_DBL_1_Pos)) & DMA_CTR1_DBL_1_Msk;
uint32_t ctr2reg = 0;
ctr2reg |= init->BlkHWRequest;
ctr2reg |= init->Direction;
ctr2reg |= init->Mode;
ctr2reg |= init->TransferEventMode;
ctr2reg |= init->TransferAllocatedPort;
uint32_t reqsel = descr->sub_instance;
ctr2reg |= (reqsel << DMA_CTR2_REQSEL_Pos) & DMA_CTR2_REQSEL_Msk;
dma->CBR1 = 0; // set length to zero, so that GPDMA engine fetches first LL entry immediately
dma->CSAR = 0;
dma->CDAR = 0;
// Attach linked list entry
dma->CLBAR = (uint32_t)(&lli1) & 0xffff0000UL; // upper 16 bits of linked list addresses
uint32_t cllrreg = 0;
cllrreg |= (DMA_CLLR_UT1 | DMA_CLLR_UT2 | DMA_CLLR_UB1 | DMA_CLLR_USA | DMA_CLLR_UDA | DMA_CLLR_ULL);
cllrreg |= (uint32_t)(&lli1) & 0x0000fffcUL; // lower 16 bits of linked list entry address
dma->CLLR = cllrreg;
// Setup linked list control registers. Length and addresses are set in dma_nohal_start()
lli1.CTR1 = ctr1reg;
lli1.CTR2 = ctr2reg;
if ((config & DMA_CIRCULAR) == DMA_CIRCULAR) {
lli1.CLLR = cllrreg; // pointer to itself for circular operation
} else {
lli1.CLLR = 0; // No next node, this is end of linked list chain
}
}
void dma_nohal_deinit(const dma_descr_t *descr) {
DMA_Channel_TypeDef *dma = descr->instance;
if ((dma->CCR & DMA_CCR_EN) == DMA_CCR_EN) {
// Suspend currently running channel. Wait until done, then reset to clear FIFOs.
dma->CCR |= DMA_CCR_SUSP;
uint32_t t0 = mp_hal_ticks_ms();
while ((dma->CSR & DMA_CSR_SUSPF) != DMA_CSR_SUSPF) {
if (mp_hal_ticks_ms() - t0 >= 100) {
// Timeout.. Abort to avoid blocking system forever
break;
}
}
dma->CCR |= DMA_CCR_RESET;
}
dma->CCR &= ~DMA_CCR_EN;
dma->CCR = 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;
lli1.CBR1 = (len << DMA_CBR1_BNDT_Pos) & DMA_CBR1_BNDT_Msk;
lli1.CSAR = src_addr;
lli1.CDAR = dst_addr;
dma->CCR |= DMA_CCR_EN;
}
#elif defined(STM32G0) || defined(STM32WB) || defined(STM32WL)
// These functions are currently not implemented or needed for this MCU.

View File

@ -28,6 +28,12 @@
typedef struct _dma_descr_t dma_descr_t;
#if defined(STM32H5)
// STM32H5 GPDMA doesn't feature circular mode directly, so define doesn't exist in
// stm32 driver header. Define it here to make users like DAC driver happy.
#define DMA_CIRCULAR 0x00000001
#endif
#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) || defined(STM32G0) || defined(STM32H5) || defined(STM32H7)
extern const dma_descr_t dma_I2C_1_RX;