| /**************************************************************************** |
| * arch/arm/src/stm32/stm32_dac.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <stdio.h> |
| #include <sys/types.h> |
| #include <stdint.h> |
| #include <stdbool.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <debug.h> |
| |
| #include <arch/board/board.h> |
| #include <nuttx/irq.h> |
| #include <nuttx/analog/dac.h> |
| |
| #include "arm_internal.h" |
| #include "chip.h" |
| #include "stm32.h" |
| #include "stm32_dac.h" |
| #include "stm32_rcc.h" |
| #include "stm32_dma.h" |
| #include "stm32_syscfg.h" |
| |
| #ifdef CONFIG_DAC |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| /* RCC reset ****************************************************************/ |
| |
| #if defined(HAVE_IP_DAC_V1) |
| # define STM32_RCC_RSTR STM32_RCC_APB1RSTR |
| # define RCC_RSTR_DAC1RST RCC_APB1RSTR_DAC1RST |
| # define RCC_RSTR_DAC2RST RCC_APB1RSTR_DAC2RST |
| #elif defined(HAVE_IP_DAC_V2) |
| # define STM32_RCC_RSTR STM32_RCC_AHB2RSTR |
| # define RCC_RSTR_DAC1RST RCC_AHB2RSTR_DAC1RST |
| # define RCC_RSTR_DAC2RST RCC_AHB2RSTR_DAC2RST |
| # define RCC_RSTR_DAC3RST RCC_AHB2RSTR_DAC3RST |
| # define RCC_RSTR_DAC4RST RCC_AHB2RSTR_DAC4RST |
| #endif |
| |
| /* Configuration ************************************************************/ |
| |
| /* Up to 2 DAC interfaces for up to 3 channels are supported |
| * |
| * NOTE: STM32_NDAC tells how many channels chip supports. |
| * ST is not consistent in the naming of DAC interfaces, so we |
| * introduce our own naming convention. We distinguish DAC1 and DAC2 |
| * only if the chip has two separate areas in memory map to support DAC |
| * channels. |
| */ |
| |
| #if STM32_NDAC < 3 |
| # warning |
| # undef CONFIG_STM32_DAC2CH1 |
| # undef CONFIG_STM32_DAC2CH1_DMA |
| # undef CONFIG_STM32_DAC2CH1_TIMER |
| # undef CONFIG_STM32_DAC2CH1_TIMER_FREQUENCY |
| #endif |
| |
| #if STM32_NDAC < 2 |
| # warning |
| # undef CONFIG_STM32_DAC1CH2 |
| # undef CONFIG_STM32_DAC1CH2_DMA |
| # undef CONFIG_STM32_DAC1CH2_TIMER |
| # undef CONFIG_STM32_DAC1CH2_TIMER_FREQUENCY |
| #endif |
| |
| #if STM32_NDAC < 1 |
| # warning |
| # undef CONFIG_STM32_DAC1CH1 |
| # undef CONFIG_STM32_DAC1CH1_DMA |
| # undef CONFIG_STM32_DAC1CH1_TIMER |
| # undef CONFIG_STM32_DAC1CH1_TIMER_FREQUENCY |
| #endif |
| |
| /* Sanity checking */ |
| |
| #ifdef CONFIG_STM32_DAC1 |
| # if !defined(CONFIG_STM32_DAC1CH1) && !defined(CONFIG_STM32_DAC1CH2) |
| # error "DAC1 enabled but no channel was selected" |
| # endif |
| #endif |
| |
| #ifdef CONFIG_STM32_DAC2 |
| # if !defined(CONFIG_STM32_DAC2CH1) |
| # error "DAC2 enabled but no channel was selected" |
| # endif |
| #endif |
| |
| #ifdef CONFIG_STM32_DAC3 |
| # if !defined(CONFIG_STM32_DAC3CH1) && !defined(CONFIG_STM32_DAC3CH2) |
| # error "DAC3 enabled but no channel was selected" |
| # endif |
| #endif |
| |
| #ifdef CONFIG_STM32_DAC4 |
| # if !defined(CONFIG_STM32_DAC4CH1) && !defined(CONFIG_STM32_DAC4CH2) |
| # error "DAC4 enabled but no channel was selected" |
| # endif |
| #endif |
| |
| /* DMA configuration. */ |
| |
| #if defined(CONFIG_STM32_DAC1CH1_DMA) || defined(CONFIG_STM32_DAC1CH2_DMA) || \ |
| defined(CONFIG_STM32_DAC2CH1_DMA) |
| # if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) |
| # ifndef CONFIG_STM32_DMA2 |
| # warning "STM32 F1/F3 DAC DMA support requires CONFIG_STM32_DMA2" |
| # undef CONFIG_STM32_DAC1CH1_DMA |
| # undef CONFIG_STM32_DAC1CH2_DMA |
| # undef CONFIG_STM32_DAC2CH1_DMA |
| # endif |
| # elif defined(CONFIG_STM32_STM32F33XX) |
| # ifndef CONFIG_STM32_DMA1 |
| # warning "STM32 F334 DAC DMA support requires CONFIG_STM32_DMA1" |
| # undef CONFIG_STM32_DAC1CH1_DMA |
| # undef CONFIG_STM32_DAC1CH2_DMA |
| # undef CONFIG_STM32_DAC2CH1_DMA |
| # endif |
| # elif defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F4XXX) |
| # ifndef CONFIG_STM32_DMA1 |
| # warning "STM32 F4 DAC DMA support requires CONFIG_STM32_DMA1" |
| # undef CONFIG_STM32_DAC1CH1_DMA |
| # undef CONFIG_STM32_DAC1CH2_DMA |
| # undef CONFIG_STM32_DAC2CH1_DMA |
| # endif |
| # else |
| # warning "No DAC DMA information for this STM32 family" |
| # undef CONFIG_STM32_DAC1CH1_DMA |
| # undef CONFIG_STM32_DAC1CH2_DMA |
| # undef CONFIG_STM32_DAC2CH1_DMA |
| # endif |
| #endif |
| |
| #if defined(CONFIG_STM32_DAC1CH1_HRTIM_TRG1) || defined(CONFIG_STM32_DAC1CH1_HRTIM_TRG2) |
| # define DAC1CH1_HRTIM |
| #endif |
| #if defined(CONFIG_STM32_DAC1CH2_HRTIM_TRG1) || defined(CONFIG_STM32_DAC1CH2_HRTIM_TRG2) |
| # define DAC1CH2_HRTIM |
| #endif |
| #if defined(CONFIG_STM32_DAC2CH1_HRTIM_TRG3) |
| # define DAC2CH1_HRTIM |
| #endif |
| |
| /* If DMA is selected, then a timer and output frequency must also be |
| * provided to support the DMA transfer. The DMA transfer could be |
| * supported by and EXTI trigger, but this feature is not currently |
| * supported by the driver. |
| */ |
| |
| #if defined(CONFIG_STM32_DAC1CH1_DMA) && !defined(DAC1CH1_HRTIM) && \ |
| !defined(CONFIG_STM32_DAC1CH1_DMA_EXTERNAL) |
| # if !defined(CONFIG_STM32_DAC1CH1_TIMER) |
| # warning "A timer number must be specified in CONFIG_STM32_DAC1CH1_TIMER" |
| # undef CONFIG_STM32_DAC1CH1_DMA |
| # undef CONFIG_STM32_DAC1CH1_TIMER_FREQUENCY |
| # elif !defined(CONFIG_STM32_DAC1CH1_TIMER_FREQUENCY) |
| # warning "A timer frequency must be specified in CONFIG_STM32_DAC1CH1_TIMER_FREQUENCY" |
| # undef CONFIG_STM32_DAC1CH1_DMA |
| # undef CONFIG_STM32_DAC1CH1_TIMER |
| # endif |
| #endif |
| |
| #if defined(CONFIG_STM32_DAC1CH2_DMA) && !defined(DAC1CH2_HRTIM) && \ |
| !defined(CONFIG_STM32_DAC1CH2_DMA_EXTERNAL) |
| # if !defined(CONFIG_STM32_DAC1CH2_TIMER) |
| # warning "A timer number must be specified in CONFIG_STM32_DAC1CH2_TIMER" |
| # undef CONFIG_STM32_DAC1CH2_DMA |
| # undef CONFIG_STM32_DAC1CH2_TIMER_FREQUENCY |
| # elif !defined(CONFIG_STM32_DAC1CH2_TIMER_FREQUENCY) |
| # warning "A timer frequency must be specified in CONFIG_STM32_DAC1CH2_TIMER_FREQUENCY" |
| # undef CONFIG_STM32_DAC1CH2_DMA |
| # undef CONFIG_STM32_DAC1CH2_TIMER |
| # endif |
| #endif |
| |
| #if defined(CONFIG_STM32_DAC2CH1_DMA) && !defined(DAC2CH1_HRTIM) && \ |
| !defined(CONFIG_STM32_DAC2CH1_DMA_EXTERNAL) |
| # if !defined(CONFIG_STM32_DAC2CH1_TIMER) |
| # warning "A timer number must be specified in CONFIG_STM32_DAC2CH1_TIMER" |
| # undef CONFIG_STM32_DAC2CH1_DMA |
| # undef CONFIG_STM32_DAC2CH1_TIMER_FREQUENCY |
| # elif !defined(CONFIG_STM32_DAC2CH1_TIMER_FREQUENCY) |
| # warning "A timer frequency must be specified in CONFIG_STM32_DAC2CH1_TIMER_FREQUENCY" |
| # undef CONFIG_STM32_DAC2CH1_DMA |
| # undef CONFIG_STM32_DAC2CH1_TIMER |
| # endif |
| #endif |
| |
| /* DMA **********************************************************************/ |
| |
| /* DMA channels and interface values differ for the F1 and F4 families */ |
| |
| #undef HAVE_DMA |
| #if defined(CONFIG_STM32_DAC1CH1_DMA) || defined(CONFIG_STM32_DAC1CH2_DMA) || \ |
| defined(CONFIG_STM32_DAC2CH1_DMA) |
| # if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) || \ |
| defined(CONFIG_STM32_STM32F33XX) |
| # define HAVE_DMA 1 |
| # define DAC_DMA 2 |
| # if defined(CONFIG_STM32_DAC1CH1) && !defined(CONFIG_STM32_DAC1CH1_DMA_EXTERNAL) |
| # define DAC1CH1_DMA_CHAN DMACHAN_DAC1_CH1 |
| # endif |
| # if defined(CONFIG_STM32_DAC1CH2) && !defined(CONFIG_STM32_DAC1CH2_DMA_EXTERNAL) |
| # define DAC1CH2_DMA_CHAN DMACHAN_DAC1_CH2 |
| # endif |
| # if defined(CONFIG_STM32_DAC2CH1) && !defined(CONFIG_STM32_DAC2CH1_DMA_EXTERNAL) |
| # define DAC2CH1_DMA_CHAN DMACHAN_DAC2_CH1 |
| # endif |
| # elif defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F4XXX) |
| # define HAVE_DMA 1 |
| # define DAC_DMA 1 |
| # if defined(CONFIG_STM32_DAC1CH1) && !defined(CONFIG_STM32_DAC1CH1_DMA_EXTERNAL) |
| # define DAC1CH1_DMA_CHAN DMAMAP_DAC1 |
| # endif |
| # if defined(CONFIG_STM32_DAC1CH2) && !defined(CONFIG_STM32_DAC1CH2_DMA_EXTERNAL) |
| # define DAC1CH2_DMA_CHAN DMAMAP_DAC1 |
| # endif |
| # if defined(CONFIG_STM32_DAC2CH1) && !defined(CONFIG_STM32_DAC2CH1_DMA_EXTERNAL) |
| # define DAC2CH1_DMA_CHAN DMAMAP_DAC2 |
| # endif |
| # endif |
| #endif |
| |
| /* Timer configuration. The STM32 supports 8 different trigger for DAC |
| * output: |
| * |
| * TSEL SOURCE DEVICES |
| * ---- ----------------------- ------------------------------------- |
| * 000 Timer 6 TRGO event ALL |
| * 001 Timer 3 TRGO event STM32 F1 Connectivity Line and STM32 F3 |
| * Timer 8 TRGO event Other STM32 F1 and all STM32 F4 |
| * 010 Timer 7 TRGO event ALL |
| * 011 Timer 5 TRGO event ALL |
| * Timer 15 TRGO event STM32 F3 |
| * HRTIM1_DACTRG1 event STM32F33XX (DAC1 only) |
| * 100 Timer 2 TRGO event ALL |
| * 101 Timer 4 TRGO event ALL |
| * HRTIM1_DACTRG2 event STM32F33XX (DAC1 only) |
| * HRTIM1_DACTRG3 event STM32F33XX (DAC2 only) |
| * 110 EXTI line9 ALL |
| * 111 SWTRIG Software control ALL |
| * |
| * This driver does not support the EXTI trigger. |
| */ |
| |
| /* DMA transfer from DMA buffer to DAC register can also be triggered by an |
| * external to the DAC block events. In this case, the DAC trigger (TEN bit) |
| * must be reset and board configuration must provide DACxCHy_DMA_CHAN. |
| */ |
| |
| #undef NEED_TIM6 |
| #undef NEED_TIM3 |
| #undef NEED_TIM8 |
| #undef NEED_TIM7 |
| #undef NEED_TIM5 |
| #undef NEED_TIM2 |
| #undef NEED_TIM4 |
| |
| #ifdef CONFIG_STM32_DAC1CH1_DMA |
| # if defined(CONFIG_STM32_DAC1CH1_DMA_EXTERNAL) |
| # elif defined(CONFIG_STM32_DAC1CH1_HRTIM_TRG1) |
| # ifndef CONFIG_STM32_HRTIM_DAC |
| # error "CONFIG_STM32_HRTIM_DAC required for DAC1CH1" |
| # endif |
| # define DAC1CH1_TSEL_VALUE DAC_CR_TSEL_HRT1TRG1 |
| # elif defined(CONFIG_STM32_DAC1CH1_HRTIM_TRG2) |
| # ifndef CONFIG_STM32_HRTIM_DAC |
| # error "CONFIG_STM32_HRTIM_DAC required for DAC1CH2" |
| # endif |
| # define DAC1CH1_TSEL_VALUE DAC_CR_TSEL_HRT1TRG2 |
| # elif CONFIG_STM32_DAC1CH1_TIMER == 6 |
| # ifndef CONFIG_STM32_TIM6_DAC |
| # error "CONFIG_STM32_TIM6_DAC required for DAC1CH1" |
| # endif |
| # define NEED_TIM6 |
| # define DAC1CH1_TSEL_VALUE DAC_CR_TSEL_TIM6 |
| # define DAC1CH1_TIMER_BASE STM32_TIM6_BASE |
| # define DAC1CH1_TIMER_PCLK_FREQUENCY STM32_PCLK1_FREQUENCY |
| # elif CONFIG_STM32_DAC1CH1_TIMER == 3 && defined(CONFIG_STM32_CONNECTIVITYLINE) |
| # ifndef CONFIG_STM32_TIM3_DAC |
| # error "CONFIG_STM32_TIM3_DAC required for DAC1CH1" |
| # endif |
| # define NEED_TIM3 |
| # define DAC1CH1_TSEL_VALUE DAC_CR_TSEL_TIM3 |
| # define DAC1CH1_TIMER_BASE STM32_TIM3_BASE |
| # define DAC1CH1_TIMER_PCLK_FREQUENCY STM32_PCLK1_FREQUENCY |
| # elif CONFIG_STM32_DAC1CH1_TIMER == 8 && !defined(CONFIG_STM32_CONNECTIVITYLINE) |
| # ifndef CONFIG_STM32_TIM8_DAC |
| # error "CONFIG_STM32_TIM8_DAC required for DAC1CH1" |
| # endif |
| # define NEED_TIM8 |
| # define DAC1CH1_TSEL_VALUE DAC_CR_TSEL_TIM8 |
| # define DAC1CH1_TIMER_BASE STM32_TIM8_BASE |
| # define DAC1CH1_TIMER_PCLK_FREQUENCY STM32_PCLK2_FREQUENCY |
| # elif CONFIG_STM32_DAC1CH1_TIMER == 7 |
| # ifndef CONFIG_STM32_TIM7_DAC |
| # error "CONFIG_STM32_TIM7_DAC required for DAC1CH1" |
| # endif |
| # define NEED_TIM7 |
| # define DAC1CH1_TSEL_VALUE DAC_CR_TSEL_TIM7 |
| # define DAC1CH1_TIMER_BASE STM32_TIM7_BASE |
| # elif CONFIG_STM32_DAC1CH1_TIMER == 5 |
| # ifndef CONFIG_STM32_TIM5_DAC |
| # error "CONFIG_STM32_TIM5_DAC required for DAC1CH1" |
| # endif |
| # define NEED_TIM5 |
| # define DAC1CH1_TSEL_VALUE DAC_CR_TSEL_TIM5 |
| # define DAC1CH1_TIMER_BASE STM32_TIM5_BASE |
| # define DAC1CH1_TIMER_PCLK_FREQUENCY STM32_PCLK1_FREQUENCY |
| # elif CONFIG_STM32_DAC1CH1_TIMER == 2 |
| # ifndef CONFIG_STM32_TIM2_DAC |
| # error "CONFIG_STM32_TIM2_DAC required for DAC1CH1" |
| # endif |
| # define NEED_TIM2 |
| # define DAC1CH1_TSEL_VALUE DAC_CR_TSEL_TIM2 |
| # define DAC1CH1_TIMER_BASE STM32_TIM2_BASE |
| # define DAC1CH1_TIMER_PCLK_FREQUENCY STM32_PCLK1_FREQUENCY |
| # elif CONFIG_STM32_DAC1CH1_TIMER == 4 |
| # ifndef CONFIG_STM32_TIM4_DAC |
| # error "CONFIG_STM32_TIM4_DAC required for DAC1CH1" |
| # endif |
| # define NEED_TIM4 |
| # define DAC1CH1_TSEL_VALUE DAC_CR_TSEL_TIM4 |
| # define DAC1CH1_TIMER_BASE STM32_TIM4_BASE |
| # define DAC1CH1_TIMER_PCLK_FREQUENCY STM32_PCLK1_FREQUENCY |
| # else |
| # error "Unsupported CONFIG_STM32_DAC1CH1_TIMER" |
| # endif |
| #else |
| # define DAC1CH1_TSEL_VALUE DAC_CR_TSEL_SW |
| #endif |
| |
| #if defined(NEED_TIM2) || defined(NEED_TIM3) || defined(NEED_TIM4) || \ |
| defined(NEED_TIM5) || defined(NEED_TIM6) || defined(NEED_TIM7) || \ |
| defined(NEED_TIM8) |
| # define HAVE_TIMER |
| #endif |
| |
| #ifdef CONFIG_STM32_DAC1CH2_DMA |
| # if defined(CONFIG_STM32_DAC1CH2_DMA_EXTERNAL) |
| # elif defined(CONFIG_STM32_DAC1CH2_HRTIM_TRG1) |
| # ifndef CONFIG_STM32_HRTIM_DAC |
| # error "CONFIG_STM32_HRTIM_DAC required for DAC1CH2" |
| # endif |
| # define DAC1CH2_TSEL_VALUE DAC_CR_TSEL_HRT1TRG1 |
| # elif defined(CONFIG_STM32_DAC1CH2_HRTIM_TRG2) |
| # ifndef CONFIG_STM32_HRTIM_DAC |
| # error "CONFIG_STM32_HRTIM_DAC required for DAC1CH2" |
| # endif |
| # define DAC1CH2_TSEL_VALUE DAC_CR_TSEL_HRT1TRG2 |
| # elif CONFIG_STM32_DAC1CH2_TIMER == 6 |
| # ifndef CONFIG_STM32_TIM6_DAC |
| # error "CONFIG_STM32_TIM6_DAC required for DAC1CH2" |
| # endif |
| # define DAC1CH2_TSEL_VALUE DAC_CR_TSEL_TIM6 |
| # define DAC1CH2_TIMER_BASE STM32_TIM6_BASE |
| # define DAC1CH2_TIMER_PCLK_FREQUENCY STM32_PCLK1_FREQUENCY |
| # elif CONFIG_STM32_DAC1CH2_TIMER == 3 && defined(CONFIG_STM32_CONNECTIVITYLINE) |
| # ifndef CONFIG_STM32_TIM3_DAC |
| # error "CONFIG_STM32_TIM3_DAC required for DAC1CH2" |
| # endif |
| # define DAC1CH2_TSEL_VALUE DAC_CR_TSEL_TIM3 |
| # define DAC1CH2_TIMER_BASE STM32_TIM3_BASE |
| # define DAC1CH2_TIMER_PCLK_FREQUENCY STM32_PCLK1_FREQUENCY |
| # elif CONFIG_STM32_DAC1CH2_TIMER == 8 && !defined(CONFIG_STM32_CONNECTIVITYLINE) |
| # ifndef CONFIG_STM32_TIM8_DAC |
| # error "CONFIG_STM32_TIM8_DAC required for DAC1CH2" |
| # endif |
| # define DAC1CH2_TSEL_VALUE DAC_CR_TSEL_TIM8 |
| # define DAC1CH2_TIMER_BASE STM32_TIM8_BASE |
| # define DAC1CH2_TIMER_PCLK_FREQUENCY STM32_PCLK2_FREQUENCY |
| # elif CONFIG_STM32_DAC1CH2_TIMER == 7 |
| # ifndef CONFIG_STM32_TIM7_DAC |
| # error "CONFIG_STM32_TIM7_DAC required for DAC1CH2" |
| # endif |
| # define DAC1CH2_TSEL_VALUE DAC_CR_TSEL_TIM7 |
| # define DAC1CH2_TIMER_BASE STM32_TIM7_BASE |
| # define DAC1CH2_TIMER_PCLK_FREQUENCY STM32_PCLK1_FREQUENCY |
| # elif CONFIG_STM32_DAC1CH2_TIMER == 5 |
| # ifndef CONFIG_STM32_TIM5_DAC |
| # error "CONFIG_STM32_TIM5_DAC required for DAC1CH2" |
| # endif |
| # define DAC1CH2_TSEL_VALUE DAC_CR_TSEL_TIM5 |
| # define DAC1CH2_TIMER_BASE STM32_TIM5_BASE |
| # define DAC1CH2_TIMER_PCLK_FREQUENCY STM32_PCLK1_FREQUENCY |
| # elif CONFIG_STM32_DAC1CH2_TIMER == 2 |
| # ifndef CONFIG_STM32_TIM2_DAC |
| # error "CONFIG_STM32_TIM2_DAC required for DAC1CH2" |
| # endif |
| # define DAC1CH2_TSEL_VALUE DAC_CR_TSEL_TIM2 |
| # define DAC1CH2_TIMER_BASE STM32_TIM2_BASE |
| # define DAC1CH2_TIMER_PCLK_FREQUENCY STM32_PCLK1_FREQUENCY |
| # elif CONFIG_STM32_DAC1CH2_TIMER == 4 |
| # ifndef CONFIG_STM32_TIM4_DAC |
| # error "CONFIG_STM32_TIM4_DAC required for DAC1CH2" |
| # endif |
| # define DAC1CH2_TSEL_VALUE DAC_CR_TSEL_TIM4 |
| # define DAC1CH2_TIMER_BASE STM32_TIM4_BASE |
| # define DAC1CH2_TIMER_PCLK_FREQUENCY STM32_PCLK1_FREQUENCY |
| # else |
| # error "Unsupported CONFIG_STM32_DAC1CH2_TIMER" |
| # endif |
| #else |
| # define DAC1CH2_TSEL_VALUE DAC_CR_TSEL_SW |
| #endif |
| |
| #ifdef CONFIG_STM32_DAC2CH1_DMA |
| # if defined(CONFIG_STM32_DAC2CH1_DMA_EXTERNAL) |
| # elif defined(CONFIG_STM32_DAC2CH1_HRTIM_TRG3) |
| # ifndef CONFIG_STM32_HRTIM_DAC |
| # error "CONFIG_STM32_HRTIM_DAC required for DAC2CH1" |
| # endif |
| # define DAC2CH1_TSEL_VALUE DAC_CR_TSEL_HRT1TRG3 |
| # elif CONFIG_STM32_DAC2CH1_TIMER == 6 |
| # ifndef CONFIG_STM32_TIM6_DAC |
| # error "CONFIG_STM32_TIM6_DAC required for DAC2CH1" |
| # endif |
| # define DAC2CH1_TSEL_VALUE DAC_CR_TSEL_TIM6 |
| # define DAC2CH1_TIMER_BASE STM32_TIM6_BASE |
| # define DAC2CH1_TIMER_PCLK_FREQUENCY STM32_PCLK1_FREQUENCY |
| # elif CONFIG_STM32_DAC2CH1_TIMER == 3 && defined(CONFIG_STM32_CONNECTIVITYLINE) |
| # ifndef CONFIG_STM32_TIM3_DAC |
| # error "CONFIG_STM32_TIM3_DAC required for DAC2CH1" |
| # endif |
| # define DAC2CH1_TSEL_VALUE DAC_CR_TSEL_TIM3 |
| # define DAC2CH1_TIMER_BASE STM32_TIM3_BASE |
| # define DAC2CH1_TIMER_PCLK_FREQUENCY STM32_PCLK1_FREQUENCY |
| # elif CONFIG_STM32_DAC2CH1_TIMER == 8 && !defined(CONFIG_STM32_CONNECTIVITYLINE) |
| # ifndef CONFIG_STM32_TIM8_DAC |
| # error "CONFIG_STM32_TIM8_DAC required for DAC2CH1" |
| # endif |
| # define DAC2CH1_TSEL_VALUE DAC_CR_TSEL_TIM8 |
| # define DAC2CH1_TIMER_BASE STM32_TIM8_BASE |
| # define DAC2CH1_TIMER_PCLK_FREQUENCY STM32_PCLK2_FREQUENCY |
| # elif CONFIG_STM32_DAC2CH1_TIMER == 7 |
| # ifndef CONFIG_STM32_TIM7_DAC |
| # error "CONFIG_STM32_TIM7_DAC required for DAC2CH1" |
| # endif |
| # define DAC2CH1_TSEL_VALUE DAC_CR_TSEL_TIM7 |
| # define DAC2CH1_TIMER_BASE STM32_TIM7_BASE |
| # define DAC2CH1_TIMER_PCLK_FREQUENCY STM32_PCLK1_FREQUENCY |
| # elif CONFIG_STM32_DAC2CH1_TIMER == 5 |
| # ifndef CONFIG_STM32_TIM5_DAC |
| # error "CONFIG_STM32_TIM5_DAC required for DAC2CH1" |
| # endif |
| # define DAC2CH1_TSEL_VALUE DAC_CR_TSEL_TIM5 |
| # define DAC2CH1_TIMER_BASE STM32_TIM5_BASE |
| # define DAC2CH1_TIMER_PCLK_FREQUENCY STM32_PCLK1_FREQUENCY |
| # elif CONFIG_STM32_DAC2CH1_TIMER == 2 |
| # ifndef CONFIG_STM32_TIM2_DAC |
| # error "CONFIG_STM32_TIM2_DAC required for DAC2CH1" |
| # endif |
| # define DAC2CH1_TSEL_VALUE DAC_CR_TSEL_TIM2 |
| # define DAC2CH1_TIMER_BASE STM32_TIM2_BASE |
| # define DAC2CH1_TIMER_PCLK_FREQUENCY STM32_PCLK1_FREQUENCY |
| # elif CONFIG_STM32_DAC2CH1_TIMER == 4 |
| # ifndef CONFIG_STM32_TIM4_DAC |
| # error "CONFIG_STM32_TIM4_DAC required for DAC2CH1" |
| # endif |
| # define DAC2CH1_TSEL_VALUE DAC_CR_TSEL_TIM4 |
| # define DAC2CH1_TIMER_BASE STM32_TIM4_BASE |
| # define DAC2CH1_TIMER_PCLK_FREQUENCY STM32_PCLK1_FREQUENCY |
| # else |
| # error "Unsupported CONFIG_STM32_DAC2CH1_TIMER" |
| # endif |
| #else |
| # define DAC2CH1_TSEL_VALUE DAC_CR_TSEL_SW |
| #endif |
| |
| /* We need index which describes when HRTIM is selected as trigger. |
| * It will be used to skip timer configuration where needed. |
| */ |
| |
| #define TIM_INDEX_HRTIM 255 |
| |
| #if defined(DAC1CH1_HRTIM) || defined(DAC1CH2_HRTIM) || defined(DAC2CH1_HRTIM) |
| # define HAVE_HRTIM |
| #endif |
| |
| /* DMA buffers default size */ |
| |
| #if !defined(CONFIG_STM32_DAC1CH1_DMA_BUFFER_SIZE) && defined(CONFIG_STM32_DAC1CH1_DMA) |
| # error "DAC1CH1 buffer size must be provided" |
| #endif |
| #if !defined(CONFIG_STM32_DAC1CH2_DMA_BUFFER_SIZE) && defined(CONFIG_STM32_DAC1CH2_DMA) |
| # error "DAC1CH2 buffer size must be provided" |
| #endif |
| #if !defined(CONFIG_STM32_DAC2CH1_DMA_BUFFER_SIZE) && defined(CONFIG_STM32_DAC2CH1_DMA) |
| # error "DAC2CH1 buffer size must be provided" |
| #endif |
| |
| /* Calculate timer divider values based upon DACn_TIMER_PCLK_FREQUENCY and |
| * CONFIG_STM32_DACn_TIMER_FREQUENCY. |
| */ |
| |
| #warning "Missing Logic" |
| |
| /* DMA stream/channel configuration */ |
| |
| #if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F4XXX) |
| # define DAC_DMA_CONTROL_WORD (DMA_SCR_MSIZE_16BITS | \ |
| DMA_SCR_PSIZE_16BITS | \ |
| DMA_SCR_MINC | \ |
| DMA_SCR_CIRC | \ |
| DMA_SCR_DIR_M2P) |
| #else |
| # define DAC_DMA_CONTROL_WORD (DMA_CCR_MSIZE_16BITS | \ |
| DMA_CCR_PSIZE_16BITS | \ |
| DMA_CCR_MINC | \ |
| DMA_CCR_CIRC | \ |
| DMA_CCR_DIR) |
| #endif |
| |
| /**************************************************************************** |
| * Private Types |
| ****************************************************************************/ |
| |
| /* This structure represents the internal state of the single STM32 DAC |
| * block |
| */ |
| |
| struct stm32_dac_s |
| { |
| uint8_t init : 1; /* True, the DAC block has been initialized */ |
| }; |
| |
| /* This structure represents the internal state of one STM32 DAC channel */ |
| |
| struct stm32_chan_s |
| { |
| 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 */ |
| uint8_t text : 1; /* True, DMA triggering from external source */ |
| uint8_t timer; /* Timer number 2-8 */ |
| #endif |
| uint8_t intf; /* DAC zero-based interface number (0 or 1) */ |
| uint32_t pin; /* Pin configuration */ |
| #ifdef HAVE_IP_DAC_V2 |
| uint32_t mode; /* DAC channel mode */ |
| #endif |
| uint32_t dro; /* Data output register */ |
| uint32_t cr; /* Control register */ |
| uint32_t tsel; /* CR trigger select value */ |
| #ifdef HAVE_IP_DAC_V2 |
| uint32_t sr; /* Status register */ |
| uint32_t mcr; /* Mode Control register */ |
| #endif |
| #ifdef HAVE_DMA |
| uint16_t dmachan; /* DMA channel needed by this DAC */ |
| uint16_t buffer_len; /* DMA buffer length */ |
| DMA_HANDLE dma; /* Allocated DMA channel */ |
| # ifdef HAVE_TIMER |
| uint32_t tbase; /* Timer base address */ |
| uint32_t tfrequency; /* Timer frequency */ |
| # endif |
| uint16_t *dmabuffer; /* DMA transfer buffer */ |
| #endif |
| }; |
| |
| /**************************************************************************** |
| * Private Function Prototypes |
| ****************************************************************************/ |
| |
| /* DAC Register access */ |
| |
| #ifdef HAVE_TIMER |
| static uint32_t tim_getreg(struct stm32_chan_s *chan, int offset); |
| static void tim_putreg(struct stm32_chan_s *chan, int offset, |
| uint32_t value); |
| static void tim_modifyreg(struct stm32_chan_s *chan, int offset, |
| uint32_t clearbits, uint32_t setbits); |
| #endif |
| |
| /* Interrupt handler */ |
| |
| #if 0 /* defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F4XXX) */ |
| static int dac_interrupt(int irq, void *context, void *arg); |
| #endif |
| |
| /* DAC methods */ |
| |
| static void dac_reset(struct dac_dev_s *dev); |
| static int dac_setup(struct dac_dev_s *dev); |
| static void dac_shutdown(struct dac_dev_s *dev); |
| static void dac_txint(struct dac_dev_s *dev, bool enable); |
| static int dac_send(struct dac_dev_s *dev, struct dac_msg_s *msg); |
| static int dac_ioctl(struct dac_dev_s *dev, int cmd, unsigned long arg); |
| |
| /* Initialization */ |
| |
| #ifdef HAVE_DMA |
| # ifdef HAVE_TIMER |
| static int dac_timinit(struct stm32_chan_s *chan); |
| # endif |
| static int dma_remap(struct stm32_chan_s *chan); |
| static void dma_bufferinit(struct stm32_chan_s *chan, uint16_t *buffer, |
| uint16_t len); |
| #endif |
| static int dac_chaninit(struct stm32_chan_s *chan); |
| static int dac_blockinit(void); |
| |
| /**************************************************************************** |
| * Private Data |
| ****************************************************************************/ |
| |
| static const struct dac_ops_s g_dacops = |
| { |
| .ao_reset = dac_reset, |
| .ao_setup = dac_setup, |
| .ao_shutdown = dac_shutdown, |
| .ao_txint = dac_txint, |
| .ao_send = dac_send, |
| .ao_ioctl = dac_ioctl, |
| }; |
| |
| #ifdef CONFIG_STM32_DAC1 |
| #ifdef CONFIG_STM32_DAC1CH1 |
| /* Channel 1: DAC1 channel 1 */ |
| |
| #ifdef CONFIG_STM32_DAC1CH1_DMA |
| uint16_t dac1ch1_buffer[CONFIG_STM32_DAC1CH1_DMA_BUFFER_SIZE]; |
| #endif |
| |
| static struct stm32_chan_s g_dac1ch1priv = |
| { |
| .intf = 0, |
| .pin = GPIO_DAC1_OUT1, |
| #ifdef HAVE_IP_DAC_V2 |
| .mode = CONFIG_STM32_DAC1CH1_MODE; |
| #endif |
| .dro = STM32_DAC1_DHR12R1, |
| .cr = STM32_DAC1_CR, |
| #ifdef HAVE_IP_DAC_V2 |
| .sr = STM32_DAC1_SR, |
| .mcr = STM32_DAC1_MCR, |
| #endif |
| #ifdef CONFIG_STM32_DAC1CH1_DMA |
| .hasdma = 1, |
| .dmachan = DAC1CH1_DMA_CHAN, |
| .buffer_len = CONFIG_STM32_DAC1CH1_DMA_BUFFER_SIZE, |
| .dmabuffer = dac1ch1_buffer, |
| # ifdef CONFIG_STM32_DAC1CH1_DMA_EXTERNAL |
| .text = 1, |
| # else |
| .text = 0, |
| .tsel = DAC1CH1_TSEL_VALUE, |
| # ifdef DAC1CH1_HRTIM |
| .timer = TIM_INDEX_HRTIM, |
| # else |
| .timer = CONFIG_STM32_DAC1CH1_TIMER, |
| .tbase = DAC1CH1_TIMER_BASE, |
| .tfrequency = CONFIG_STM32_DAC1CH1_TIMER_FREQUENCY, |
| # endif |
| # endif |
| #endif |
| }; |
| |
| static struct dac_dev_s g_dac1ch1dev = |
| { |
| .ad_ops = &g_dacops, |
| .ad_priv = &g_dac1ch1priv, |
| }; |
| #endif /* CONFIG_STM32_DAC1CH1 */ |
| |
| #ifdef CONFIG_STM32_DAC1CH2 |
| /* Channel 2: DAC1 channel 2 */ |
| |
| #ifdef CONFIG_STM32_DAC1CH2_DMA |
| uint16_t dac1ch2_buffer[CONFIG_STM32_DAC1CH2_DMA_BUFFER_SIZE]; |
| #endif |
| |
| static struct stm32_chan_s g_dac1ch2priv = |
| { |
| .intf = 1, |
| .pin = GPIO_DAC1_OUT2, |
| #ifdef HAVE_IP_DAC_V2 |
| .mode = CONFIG_STM32_DAC1CH2_MODE << 16; |
| #endif |
| .dro = STM32_DAC1_DHR12R2, |
| .cr = STM32_DAC1_CR, |
| #ifdef HAVE_IP_DAC_V2 |
| .sr = STM32_DAC1_SR, |
| .mcr = STM32_DAC1_MCR, |
| #endif |
| #ifdef CONFIG_STM32_DAC1CH2_DMA |
| .hasdma = 1, |
| .dmachan = DAC1CH2_DMA_CHAN, |
| .buffer_len = CONFIG_STM32_DAC1CH2_DMA_BUFFER_SIZE, |
| .dmabuffer = dac1ch2_buffer, |
| # ifdef CONFIG_STM32_DAC1CH2_DMA_EXTERNAL |
| .text = 1, |
| # else |
| .text = 0, |
| .tsel = DAC1CH2_TSEL_VALUE, |
| # ifdef DAC1CH2_HRTIM |
| .timer = TIM_INDEX_HRTIM, |
| # else |
| .timer = CONFIG_STM32_DAC1CH2_TIMER, |
| .tbase = DAC1CH2_TIMER_BASE, |
| .tfrequency = CONFIG_STM32_DAC1CH2_TIMER_FREQUENCY, |
| # endif |
| # endif |
| #endif |
| }; |
| |
| static struct dac_dev_s g_dac1ch2dev = |
| { |
| .ad_ops = &g_dacops, |
| .ad_priv = &g_dac1ch2priv, |
| }; |
| #endif /* CONFIG_STM32_DAC1CH2 */ |
| |
| #endif /* CONFIG_STM32_DAC1 */ |
| |
| #ifdef CONFIG_STM32_DAC2 |
| #ifdef CONFIG_STM32_DAC2CH1 |
| /* Channel 3: DAC2 channel 1 */ |
| |
| #ifdef CONFIG_STM32_DAC2CH1_DMA |
| uint16_t dac2ch1_buffer[CONFIG_STM32_DAC2CH1_DMA_BUFFER_SIZE]; |
| #endif |
| |
| static struct stm32_chan_s g_dac2ch1priv = |
| { |
| .intf = 2, |
| .pin = GPIO_DAC2_OUT1, |
| #ifdef HAVE_IP_DAC_V2 |
| .mode = CONFIG_STM32_DAC2CH1_MODE; |
| #endif |
| .dro = STM32_DAC2_DHR12R1, |
| .cr = STM32_DAC2_CR, |
| #ifdef HAVE_IP_DAC_V2 |
| .sr = STM32_DAC2_SR, |
| .mcr = STM32_DAC2_MCR, |
| #endif |
| #ifdef CONFIG_STM32_DAC2CH1_DMA |
| .hasdma = 1, |
| .dmachan = DAC2CH1_DMA_CHAN, |
| .buffer_len = CONFIG_STM32_DAC2CH1_DMA_BUFFER_SIZE, |
| .dmabuffer = dac2ch1_buffer, |
| # ifdef CONFIG_STM32_DAC2CH1_DMA_EXTERNAL |
| .text = 1, |
| # else |
| .text = 0, |
| .tsel = DAC2CH1_TSEL_VALUE, |
| # ifdef DAC2CH1_HRTIM |
| .timer = TIM_INDEX_HRTIM, |
| # else |
| .timer = CONFIG_STM32_DAC2CH1_TIMER, |
| .tbase = DAC2CH1_TIMER_BASE, |
| .tfrequency = CONFIG_STM32_DAC2CH1_TIMER_FREQUENCY, |
| # endif |
| # endif |
| #endif |
| }; |
| |
| static struct dac_dev_s g_dac2ch1dev = |
| { |
| .ad_ops = &g_dacops, |
| .ad_priv = &g_dac2ch1priv, |
| }; |
| #endif /* CONFIG_STM32_DAC2CH1 */ |
| #endif /* CONFIG_STM32_DAC2 */ |
| |
| #ifdef CONFIG_STM32_DAC3 |
| #ifdef CONFIG_STM32_DAC3CH1 |
| /* Channel 4: DAC3 channel 1 */ |
| |
| #ifdef CONFIG_STM32_DAC3CH1_DMA |
| # error "STM32_DAC3 DMA not supported" |
| #endif |
| |
| static struct stm32_chan_s g_dac3ch1priv = |
| { |
| .intf = 4, |
| .dro = STM32_DAC3_DHR12R1, |
| #ifdef HAVE_IP_DAC_V2 |
| .mode = CONFIG_STM32_DAC3CH1_MODE; |
| #endif |
| .cr = STM32_DAC3_CR, |
| #ifdef HAVE_IP_DAC_V2 |
| .sr = STM32_DAC3_SR, |
| .mcr = STM32_DAC3_MCR, |
| #endif |
| }; |
| |
| static struct dac_dev_s g_dac3ch1dev = |
| { |
| .ad_ops = &g_dacops, |
| .ad_priv = &g_dac3ch1priv, |
| }; |
| #endif /* CONFIG_STM32_DAC3CH1 */ |
| |
| #ifdef CONFIG_STM32_DAC3CH2 |
| /* Channel 5: DAC3 channel 1 */ |
| |
| #ifdef CONFIG_STM32_DAC3CH2_DMA |
| # error "STM32_DAC3 DMA not supported" |
| #endif |
| |
| static struct stm32_chan_s g_dac3ch2priv = |
| { |
| .intf = 5, |
| .dro = STM32_DAC3_DHR12R2, |
| #ifdef HAVE_IP_DAC_V2 |
| .mode = CONFIG_STM32_DAC3CH2_MODE << 16, |
| #endif |
| .cr = STM32_DAC3_CR, |
| #ifdef HAVE_IP_DAC_V2 |
| .sr = STM32_DAC3_SR, |
| .mcr = STM32_DAC3_MCR, |
| #endif |
| }; |
| |
| static struct dac_dev_s g_dac3ch2dev = |
| { |
| .ad_ops = &g_dacops, |
| .ad_priv = &g_dac3ch2priv, |
| }; |
| #endif /* CONFIG_STM32_DAC3CH2 */ |
| #endif /* CONFIG_STM32_DAC3 */ |
| |
| static struct stm32_dac_s g_dacblock; |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: stm32_dac_modify_cr |
| * |
| * Description: |
| * Modify the contents of the DAC control register. |
| * |
| * Input Parameters: |
| * priv - Driver state instance |
| * clearbits - Bits in the control register to be cleared |
| * setbits - Bits in the control register to be set |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static inline void stm32_dac_modify_cr(struct stm32_chan_s *chan, |
| uint32_t clearbits, uint32_t setbits) |
| { |
| unsigned int shift; |
| |
| /* DAC1 channels 1 and 2 share the STM32_DAC[1]_CR control register. DAC2 |
| * channel 1 (and perhaps channel 2) uses the STM32_DAC2_CR control |
| * register. In either case, bit 0 of the interface number provides the |
| * correct shift. |
| * |
| * Bit 0 = 0: Shift = 0 |
| * Bit 0 = 1: Shift = 16 |
| */ |
| |
| shift = (chan->intf & 1) << 4; |
| modifyreg32(chan->cr, clearbits << shift, setbits << shift); |
| } |
| |
| #ifdef HAVE_TIMER |
| |
| /**************************************************************************** |
| * Name: tim_getreg |
| * |
| * Description: |
| * Read the value of an DMA timer register. |
| * |
| * Input Parameters: |
| * chan - A reference to the DAC block status |
| * offset - The offset to the register to read |
| * |
| * Returned Value: |
| * The current contents of the specified register |
| * |
| ****************************************************************************/ |
| |
| static uint32_t tim_getreg(struct stm32_chan_s *chan, int offset) |
| { |
| return getreg32(chan->tbase + offset); |
| } |
| |
| /**************************************************************************** |
| * Name: tim_putreg |
| * |
| * Description: |
| * Read the value of an DMA timer register. |
| * |
| * Input Parameters: |
| * chan - A reference to the DAC block status |
| * offset - The offset to the register to read |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void tim_putreg(struct stm32_chan_s *chan, int offset, |
| uint32_t value) |
| { |
| putreg32(value, chan->tbase + offset); |
| } |
| |
| /**************************************************************************** |
| * Name: tim_modifyreg |
| * |
| * Description: |
| * Modify the value of an DMA timer register. |
| * |
| * Input Parameters: |
| * priv - Driver state instance |
| * offset - The timer register offset |
| * clearbits - Bits in the control register to be cleared |
| * setbits - Bits in the control register to be set |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void tim_modifyreg(struct stm32_chan_s *chan, int offset, |
| uint32_t clearbits, uint32_t setbits) |
| { |
| modifyreg32(chan->tbase + offset, clearbits, setbits); |
| } |
| #endif /* HAVE_TIMER */ |
| |
| /**************************************************************************** |
| * Name: dac_interrupt |
| * |
| * Description: |
| * DAC interrupt handler. The STM32 F4 family supports a only a DAC |
| * underrun interrupt. |
| * |
| * Input Parameters: |
| * |
| * Returned Value: |
| * OK |
| * |
| ****************************************************************************/ |
| |
| #if 0 /* defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F4XXX) */ |
| static int dac_interrupt(int irq, void *context, void *arg) |
| { |
| #warning "Missing logic" |
| return OK; |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: dac_reset |
| * |
| * Description: |
| * Reset the DAC channel. Called early to initialize the hardware. This |
| * is called, before dac_setup() and on error conditions. |
| * |
| * NOTE: DAC reset will reset both DAC channels! |
| * |
| * Input Parameters: |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void dac_reset(struct dac_dev_s *dev) |
| { |
| irqstate_t flags; |
| |
| /* Reset only the selected DAC channel; the other DAC channel must remain |
| * functional. |
| */ |
| |
| flags = enter_critical_section(); |
| |
| #warning "Missing logic" |
| |
| leave_critical_section(flags); |
| } |
| |
| /**************************************************************************** |
| * Name: dac_setup |
| * |
| * Description: |
| * Configure the DAC. This method is called the first time that the DAC |
| * device is opened. This will occur when the port is first opened. |
| * This setup includes configuring and attaching DAC interrupts. |
| * Interrupts are all disabled upon return. |
| * |
| * Input Parameters: |
| * |
| * Returned Value: |
| * Zero on success; a negated errno value on failure. |
| * |
| ****************************************************************************/ |
| |
| static int dac_setup(struct dac_dev_s *dev) |
| { |
| #warning "Missing logic" |
| return OK; |
| } |
| |
| /**************************************************************************** |
| * Name: dac_shutdown |
| * |
| * Description: |
| * Disable the DAC. This method is called when the DAC device is closed. |
| * This method reverses the operation the setup method. |
| * |
| * Input Parameters: |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void dac_shutdown(struct dac_dev_s *dev) |
| { |
| #warning "Missing logic" |
| } |
| |
| /**************************************************************************** |
| * Name: dac_txint |
| * |
| * Description: |
| * Call to enable or disable TX interrupts. |
| * |
| * Input Parameters: |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void dac_txint(struct dac_dev_s *dev, bool enable) |
| { |
| #warning "Missing logic" |
| } |
| |
| /**************************************************************************** |
| * Name: dac_dmatxcallback |
| * |
| * Description: |
| * DMA callback function. |
| * |
| * Input Parameters: |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| #ifdef HAVE_DMA |
| static void dac_dmatxcallback(DMA_HANDLE handle, uint8_t isr, void *arg) |
| { |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: dac_send |
| * |
| * Description: |
| * Set the DAC output. |
| * |
| * Input Parameters: |
| * |
| * Returned Value: |
| * Zero on success; a negated errno value on failure. |
| * |
| ****************************************************************************/ |
| |
| static int dac_send(struct dac_dev_s *dev, struct dac_msg_s *msg) |
| { |
| struct stm32_chan_s *chan = dev->ad_priv; |
| |
| /* Enable DAC Channel */ |
| |
| #if defined(CONFIG_STM32_STM32F33XX) |
| /* For STM32F33XX we have to set BOFF/OUTEN bit for DAC1CH2 and DAC2CH1 |
| * REVISIT: what if we connect DAC internally with comparator ? |
| */ |
| |
| if (chan->intf > 0) |
| { |
| stm32_dac_modify_cr(chan, 0, DAC_CR_EN | DAC_CR_BOFF); |
| } |
| else |
| #endif |
| { |
| stm32_dac_modify_cr(chan, 0, DAC_CR_EN); |
| } |
| |
| #if defined(HAVE_IP_DAC_V2) |
| /* Check channelx ready status bit */ |
| |
| uint32_t regval; |
| uint32_t dac = (chan->intf >> 1); |
| do |
| { |
| regval = getreg32(chan->sr); |
| } |
| while (!(regval & DAC_SR_DACRDY(dac))); |
| #endif |
| |
| #ifdef HAVE_DMA |
| if (chan->hasdma) |
| { |
| /* Configure the DMA stream/channel. |
| * |
| * - Channel number |
| * - Peripheral address |
| * - Direction: Memory to peripheral |
| * - Disable peripheral address increment |
| * - Enable memory address increment |
| * - Peripheral data size: half word |
| * - Mode: circular??? |
| * - Priority: ? |
| * - FIFO mode: disable |
| * - FIFO threshold: half full |
| * - Memory Burst: single |
| * - Peripheral Burst: single |
| */ |
| |
| stm32_dmasetup(chan->dma, chan->dro, (uint32_t)chan->dmabuffer, |
| chan->buffer_len, DAC_DMA_CONTROL_WORD); |
| |
| /* Enable DMA */ |
| |
| stm32_dmastart(chan->dma, dac_dmatxcallback, chan, false); |
| |
| /* Enable DMA for DAC Channel */ |
| |
| stm32_dac_modify_cr(chan, 0, DAC_CR_DMAEN); |
| } |
| else |
| #endif |
| { |
| /* Non-DMA transfer */ |
| |
| #if defined(HAVE_IP_DAC_V1) |
| putreg16(msg->am_data, chan->dro); |
| #else |
| putreg32(msg->am_data, chan->dro); |
| #endif |
| dac_txdone(dev); |
| } |
| |
| /* Reset counters (generate an update). Only when timer is not HRTIM */ |
| |
| #ifdef HAVE_TIMER |
| if (chan->timer != TIM_INDEX_HRTIM) |
| { |
| tim_modifyreg(chan, STM32_GTIM_EGR_OFFSET, 0, GTIM_EGR_UG); |
| } |
| #endif |
| |
| return OK; |
| } |
| |
| /**************************************************************************** |
| * Name: dac_ioctl |
| * |
| * Description: |
| * All ioctl calls will be routed through this method. |
| * |
| * Input Parameters: |
| * |
| * Returned Value: |
| * Zero on success; a negated errno value on failure. |
| * |
| ****************************************************************************/ |
| |
| static int dac_ioctl(struct dac_dev_s *dev, int cmd, unsigned long arg) |
| { |
| struct stm32_chan_s *chan = dev->ad_priv; |
| int ret = OK; |
| |
| switch (cmd) |
| { |
| #ifdef HAVE_DMA |
| case IO_DMABUFFER_INIT: |
| { |
| uint16_t *buffer = (uint16_t *)arg; |
| |
| /* The caller is responsible for providing buffer with |
| * suitable length equal to CONFIG_STM32_DACxCHy_DMA_BUFFER_SIZE |
| */ |
| |
| dma_bufferinit(chan, buffer, chan->buffer_len * sizeof(buffer)); |
| break; |
| } |
| #endif |
| |
| default: |
| { |
| aerr("ERROR: Unknown cmd: %d\n", cmd); |
| ret = -ENOTTY; |
| break; |
| } |
| } |
| |
| UNUSED(chan); |
| return ret; |
| } |
| |
| #ifdef HAVE_DMA |
| |
| /**************************************************************************** |
| * Name: dma_bufferinit |
| ****************************************************************************/ |
| |
| static void dma_bufferinit(struct stm32_chan_s *chan, uint16_t *buffer, |
| uint16_t len) |
| { |
| memcpy(chan->dmabuffer, buffer, len); |
| } |
| |
| /**************************************************************************** |
| * Name: dma_remap |
| ****************************************************************************/ |
| |
| static int dma_remap(struct stm32_chan_s *chan) |
| { |
| #if defined(CONFIG_STM32_STM32F33XX) || defined(CONFIG_STM32_STM32F30XX) || \ |
| defined(CONFIG_STM32_STM32F37XX) |
| uint32_t regval = 0; |
| |
| switch (chan->intf) |
| { |
| case 0: |
| { |
| /* Remap DMA1CH3 to DAC1CH1 */ |
| |
| regval |= SYSCFG_CFGR1_DAC1CH1_DMARMP; |
| |
| /* Remap DAC trigger for STM32F33XX if needed */ |
| |
| # ifdef CONFIG_STM32_STM32F33XX |
| # if defined(CONFIG_STM32_DAC1CH1_HRTIM_TRG1) |
| modifyreg32(STM32_SYSCFG_CFGR3, 0, SYSCFG_CFGR3_DAC1_TRIG3_RMP); |
| # elif defined(CONFIG_STM32_DAC1CH1_HRTIM_TRG2) |
| modifyreg32(STM32_SYSCFG_CFGR3, 0, SYSCFG_CFGR3_DAC1_TRIG5_RMP); |
| # endif |
| # endif |
| break; |
| } |
| |
| case 1: |
| { |
| /* Remap DMA1CH4 to DAC1CH2 */ |
| |
| regval |= SYSCFG_CFGR1_DAC1CH2_DMARMP; |
| |
| /* Remap DAC trigger for STM32F33XX if needed */ |
| |
| # ifdef CONFIG_STM32_STM32F33XX |
| # if defined(CONFIG_STM32_DAC1CH2_HRTIM_TRG1) |
| modifyreg32(STM32_SYSCFG_CFGR3, 0, SYSCFG_CFGR3_DAC1_TRIG3_RMP); |
| # elif defined(CONFIG_STM32_DAC1CH2_HRTIM_TRG2) |
| modifyreg32(STM32_SYSCFG_CFGR3, 0, SYSCFG_CFGR3_DAC1_TRIG5_RMP); |
| # endif |
| # endif |
| break; |
| } |
| |
| case 2: |
| { |
| /* Remap DMA1CH5 to DAC2CH1 */ |
| |
| regval |= SYSCFG_CFGR1_DAC2CH1_DMARMP; |
| break; |
| } |
| |
| default: |
| { |
| return -EINVAL; |
| } |
| } |
| |
| modifyreg32(STM32_SYSCFG_BASE, 0, regval); |
| |
| #endif |
| |
| return OK; |
| } |
| |
| /**************************************************************************** |
| * Name: dac_timinit |
| * |
| * Description: |
| * Initialize the timer that drivers the DAC DMA for this channel using |
| * the pre-calculated timer divider definitions. |
| * |
| * Input Parameters: |
| * chan - A reference to the DAC channel state data |
| * |
| * Returned Value: |
| * Zero on success; a negated errno value on failure. |
| * |
| ****************************************************************************/ |
| |
| #ifdef HAVE_TIMER |
| static int dac_timinit(struct stm32_chan_s *chan) |
| { |
| uint32_t pclk; |
| uint32_t prescaler; |
| uint32_t timclk; |
| uint32_t reload; |
| uint32_t regaddr; |
| uint32_t setbits; |
| |
| /* Configure the time base: Timer period, prescaler, clock division, |
| * counter mode (up). |
| */ |
| |
| /* Enable the timer. At most, two of the following cases (pulse the |
| * default) will be enabled |
| */ |
| |
| regaddr = STM32_RCC_APB1ENR; |
| |
| switch (chan->timer) |
| { |
| #ifdef NEED_TIM2 |
| case 2: |
| setbits = RCC_APB1ENR_TIM2EN; |
| pclk = BOARD_TIM2_FREQUENCY; |
| break; |
| #endif |
| #ifdef NEED_TIM3 |
| case 3: |
| setbits = RCC_APB1ENR_TIM3EN; |
| pclk = BOARD_TIM3_FREQUENCY; |
| break; |
| #endif |
| #ifdef NEED_TIM4 |
| case 4: |
| setbits = RCC_APB1ENR_TIM4EN; |
| pclk = BOARD_TIM4_FREQUENCY; |
| break; |
| #endif |
| #ifdef NEED_TIM5 |
| case 5: |
| setbits = RCC_APB1ENR_TIM5EN; |
| pclk = BOARD_TIM5_FREQUENCY; |
| break; |
| #endif |
| #ifdef NEED_TIM6 |
| case 6: |
| setbits = RCC_APB1ENR_TIM6EN; |
| pclk = BOARD_TIM6_FREQUENCY; |
| break; |
| #endif |
| #ifdef NEED_TIM7 |
| case 7: |
| setbits = RCC_APB1ENR_TIM7EN; |
| pclk = BOARD_TIM7_FREQUENCY; |
| break; |
| #endif |
| #ifdef NEED_TIM8 |
| case 8: |
| regaddr = STM32_RCC_APB2ENR; |
| setbits = RCC_APB2ENR_TIM8EN; |
| pclk = BOARD_TIM8_FREQUENCY; |
| break; |
| #endif |
| default: |
| aerr("ERROR: Could not enable timer\n"); |
| return -EINVAL; |
| } |
| |
| /* Enable the timer. */ |
| |
| modifyreg32(regaddr, 0, setbits); |
| |
| /* Calculate optimal values for the timer prescaler and for the timer |
| * reload register. If 'frequency' is the desired frequency, then |
| * |
| * reload = timclk / frequency |
| * timclk = pclk / presc |
| * |
| * Or, |
| * |
| * reload = pclk / presc / frequency |
| * |
| * There are many solutions to this, but the best solution will be the one |
| * that has the largest reload value and the smallest prescaler value. |
| * That is the solution that should give us the most accuracy in the timer |
| * control. Subject to: |
| * |
| * 0 <= presc <= 65536 |
| * 1 <= reload <= 65535 |
| * |
| * So presc = pclk / 65535 / frequency would be optimal. |
| * |
| * Example: |
| * |
| * pclk = 42 MHz |
| * frequency = 100 Hz |
| * |
| * prescaler = 42,000,000 / 65,535 / 100 |
| * = 6.4 (or 7 -- taking the ceiling always) |
| * timclk = 42,000,000 / 7 |
| * = 6,000,000 |
| * reload = 6,000,000 / 100 |
| * = 60,000 |
| */ |
| |
| prescaler = (pclk / chan->tfrequency + 65534) / 65535; |
| if (prescaler < 1) |
| { |
| prescaler = 1; |
| } |
| else if (prescaler > 65536) |
| { |
| prescaler = 65536; |
| } |
| |
| timclk = pclk / prescaler; |
| |
| reload = timclk / chan->tfrequency; |
| if (reload < 1) |
| { |
| reload = 1; |
| } |
| else if (reload > 65535) |
| { |
| reload = 65535; |
| } |
| |
| /* Set the reload and prescaler values */ |
| |
| tim_putreg(chan, STM32_GTIM_ARR_OFFSET, (uint16_t)reload); |
| tim_putreg(chan, STM32_GTIM_PSC_OFFSET, (uint16_t)(prescaler - 1)); |
| |
| /* Count mode up, auto reload */ |
| |
| tim_modifyreg(chan, STM32_GTIM_CR1_OFFSET, 0, GTIM_CR1_ARPE); |
| |
| /* Selection TRGO selection: update */ |
| |
| tim_modifyreg(chan, STM32_GTIM_CR2_OFFSET, GTIM_CR2_MMS_MASK, |
| GTIM_CR2_MMS_UPDATE); |
| |
| /* Update DMA request enable ???? */ |
| #if 0 |
| tim_modifyreg(chan, STM32_GTIM_DIER_OFFSET, 0, GTIM_DIER_UDE); |
| #endif |
| |
| /* Enable the counter */ |
| |
| tim_modifyreg(chan, STM32_GTIM_CR1_OFFSET, 0, GTIM_CR1_CEN); |
| return OK; |
| } |
| #endif |
| #endif /* HAVE_DMA */ |
| |
| /**************************************************************************** |
| * Name: dac_chaninit |
| * |
| * Description: |
| * Initialize the DAC channel. |
| * |
| * Input Parameters: |
| * chan - A reference to the DAC channel state data |
| * |
| * Returned Value: |
| * Zero on success; a negated errno value on failure. |
| * |
| ****************************************************************************/ |
| |
| static int dac_chaninit(struct stm32_chan_s *chan) |
| { |
| uint16_t clearbits; |
| uint16_t setbits; |
| #if defined(HAVE_IP_DAC_V2) |
| uint32_t regval; |
| #endif |
| #ifdef HAVE_TIMER |
| int ret; |
| #endif |
| |
| /* Is the selected channel already in-use? */ |
| |
| if (chan->inuse) |
| { |
| /* Yes.. then return EBUSY */ |
| |
| return -EBUSY; |
| } |
| |
| /* Configure the DAC output pin: |
| * |
| * DAC -" Once the DAC channelx is enabled, the corresponding GPIO pin |
| * (PA4 or PA5) is automatically connected to the analog converter output |
| * (DAC_OUTx). In order to avoid parasitic consumption, the PA4 or PA5 pin |
| * should first be configured to analog (AIN)". |
| */ |
| |
| /* Only DAC1 and DAC2 have external pins */ |
| |
| if (chan->intf < 4) |
| { |
| stm32_configgpio(chan->pin); |
| } |
| |
| /* DAC channel configuration: |
| * |
| * - Set the trigger selection based upon the configuration. |
| * - Set wave generation == None. |
| * - Enable the output buffer. |
| */ |
| |
| /* Disable before change */ |
| |
| stm32_dac_modify_cr(chan, DAC_CR_EN, 0); |
| |
| clearbits = DAC_CR_TSEL_MASK | |
| DAC_CR_MAMP_MASK | |
| DAC_CR_WAVE_MASK; |
| #if defined (HAVE_IP_DAC_V1) |
| clearbits |= DAC_CR_BOFF; |
| #endif |
| |
| setbits = |
| chan->tsel | /* Set trigger source (SW or timer TRGO event) */ |
| DAC_CR_MAMP_AMP1 | /* Set waveform characteristics */ |
| DAC_CR_WAVE_DISABLED; /* Set wave generation disabled */ |
| #if defined (HAVE_IP_DAC_V1) |
| setbits |= DAC_CR_BOFF_EN; /* Enable output buffer */ |
| #endif |
| |
| stm32_dac_modify_cr(chan, clearbits, setbits); |
| |
| #if defined(HAVE_IP_DAC_V2) |
| /* High frequency interface mode selection */ |
| |
| if (STM32_SYSCLK_FREQUENCY > 160000000) |
| { |
| regval = DAC_MCR_HFSEL_AHB_160MHz; |
| } |
| else if (STM32_SYSCLK_FREQUENCY > 80000000) |
| { |
| regval = DAC_MCR_HFSEL_AHB_80MHz; |
| } |
| else |
| { |
| regval = DAC_MCR_HFSEL_DISABLED; |
| } |
| |
| /* DAC mode selection */ |
| |
| regval |= chan->mode; |
| |
| putreg32(regval, chan->mcr); |
| #endif |
| |
| #ifdef HAVE_DMA |
| /* Determine if DMA is supported by this channel */ |
| |
| if (chan->hasdma) |
| { |
| /* Remap DMA request if necessary */ |
| |
| dma_remap(chan); |
| |
| /* DAC trigger enable if not external triggering */ |
| |
| if (!chan->text) |
| { |
| stm32_dac_modify_cr(chan, 0, DAC_CR_TEN); |
| } |
| |
| /* Allocate a DMA channel */ |
| |
| chan->dma = stm32_dmachannel(chan->dmachan); |
| if (!chan->dma) |
| { |
| aerr("ERROR: Failed to allocate a DMA channel\n"); |
| return -EBUSY; |
| } |
| |
| /* Configure the timer that supports the DMA operation |
| * Do nothing if HRTIM is selected as trigger. |
| * All necessary configuration is done in the HRTIM driver. |
| */ |
| |
| #ifdef HAVE_TIMER |
| if (chan->timer != TIM_INDEX_HRTIM) |
| { |
| ret = dac_timinit(chan); |
| if (ret < 0) |
| { |
| aerr("ERROR: Failed to initialize the DMA timer: %d\n", ret); |
| return ret; |
| } |
| } |
| #endif |
| } |
| #endif |
| |
| /* Mark the DAC channel "in-use" */ |
| |
| chan->inuse = 1; |
| return OK; |
| } |
| |
| /**************************************************************************** |
| * Name: dac_blockinit |
| * |
| * Description: |
| * Initialize the DAC block. |
| * |
| * Input Parameters: |
| * |
| * Returned Value: |
| * Zero on success; a negated errno value on failure. |
| * |
| ****************************************************************************/ |
| |
| static int dac_blockinit(void) |
| { |
| irqstate_t flags; |
| uint32_t regval; |
| |
| /* Has the DAC block already been initialized? */ |
| |
| if (g_dacblock.init) |
| { |
| /* Yes.. then return success We only have to do this once */ |
| |
| return OK; |
| } |
| |
| /* Put the entire DAC block in reset state */ |
| |
| flags = enter_critical_section(); |
| regval = getreg32(STM32_RCC_RSTR); |
| #ifdef CONFIG_STM32_DAC1 |
| regval |= RCC_RSTR_DAC1RST; |
| #endif |
| #ifdef CONFIG_STM32_DAC2 |
| regval |= RCC_RSTR_DAC2RST; |
| #endif |
| #ifdef CONFIG_STM32_DAC3 |
| regval |= RCC_RSTR_DAC3RST; |
| #endif |
| putreg32(regval, STM32_RCC_RSTR); |
| |
| /* Take the DAC out of reset state */ |
| |
| #ifdef CONFIG_STM32_DAC1 |
| regval &= ~RCC_RSTR_DAC1RST; |
| #endif |
| #ifdef CONFIG_STM32_DAC2 |
| regval &= ~RCC_RSTR_DAC2RST; |
| #endif |
| #ifdef CONFIG_STM32_DAC3 |
| regval &= ~RCC_RSTR_DAC3RST; |
| #endif |
| putreg32(regval, STM32_RCC_RSTR); |
| leave_critical_section(flags); |
| |
| /* Mark the DAC block as initialized */ |
| |
| g_dacblock.init = 1; |
| return OK; |
| } |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: stm32_dacinitialize |
| * |
| * Description: |
| * Initialize the DAC. |
| * |
| * Input Parameters: |
| * intf - The DAC interface number. |
| * |
| * Returned Value: |
| * Valid DAC device structure reference on success; a NULL on failure. |
| * |
| * Assumptions: |
| * 1. Clock to the DAC block has enabled, |
| * 2. Board-specific logic has already configured |
| * |
| ****************************************************************************/ |
| |
| struct dac_dev_s *stm32_dacinitialize(int intf) |
| { |
| struct dac_dev_s *dev; |
| struct stm32_chan_s *chan; |
| int ret; |
| |
| #ifdef CONFIG_STM32_DAC1CH1 |
| if (intf == 1) |
| { |
| ainfo("DAC1-1 Selected\n"); |
| dev = &g_dac1ch1dev; |
| } |
| else |
| #endif /* CONFIG_STM32_DAC1CH1 */ |
| #ifdef CONFIG_STM32_DAC1CH2 |
| if (intf == 2) |
| { |
| ainfo("DAC1-2 Selected\n"); |
| dev = &g_dac1ch2dev; |
| } |
| else |
| #endif /* CONFIG_STM32_DAC1CH2 */ |
| #ifdef CONFIG_STM32_DAC2CH1 |
| if (intf == 3) |
| { |
| ainfo("DAC2-1 Selected\n"); |
| dev = &g_dac2ch1dev; |
| } |
| else |
| #endif /* CONFIG_STM32_DAC2CH1 */ |
| #ifdef CONFIG_STM32_DAC3CH1 |
| if (intf == 4) |
| { |
| ainfo("DAC3-1 Selected\n"); |
| dev = &g_dac3ch1dev; |
| } |
| else |
| #endif /* CONFIG_STM32_DAC3CH1 */ |
| #ifdef CONFIG_STM32_DAC3CH2 |
| if (intf == 5) |
| { |
| ainfo("DAC3-2 Selected\n"); |
| dev = &g_dac3ch2dev; |
| } |
| else |
| #endif /* CONFIG_STM32_DAC3CH2 */ |
| { |
| aerr("ERROR: No such DAC interface: %d\n", intf); |
| return NULL; |
| } |
| |
| /* Make sure that the DAC block has been initialized */ |
| |
| ret = dac_blockinit(); |
| if (ret < 0) |
| { |
| aerr("ERROR: Failed to initialize the DAC block: %d\n", ret); |
| return NULL; |
| } |
| |
| /* Configure the selected DAC channel */ |
| |
| chan = dev->ad_priv; |
| ret = dac_chaninit(chan); |
| if (ret < 0) |
| { |
| aerr("ERROR: Failed to initialize DAC channel %d: %d\n", intf, ret); |
| return NULL; |
| } |
| |
| return dev; |
| } |
| |
| #endif /* CONFIG_DAC */ |