From f112ffa1e6e4a2e3bc3c6754f2e6ed7de030c12f Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Fri, 1 May 2015 16:03:03 +0000 Subject: DAC driver *almost* done. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@7934 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/ports/STM32/LLD/DACv1/dac_lld.c | 364 ++++++++++++++++++--------------- os/hal/ports/STM32/LLD/DACv1/dac_lld.h | 288 +++++++++++++------------- 2 files changed, 346 insertions(+), 306 deletions(-) (limited to 'os/hal/ports/STM32/LLD/DACv1') diff --git a/os/hal/ports/STM32/LLD/DACv1/dac_lld.c b/os/hal/ports/STM32/LLD/DACv1/dac_lld.c index 116cbdd3f..929867c85 100644 --- a/os/hal/ports/STM32/LLD/DACv1/dac_lld.c +++ b/os/hal/ports/STM32/LLD/DACv1/dac_lld.c @@ -30,43 +30,53 @@ /* Driver local definitions. */ /*===========================================================================*/ +/* Because ST headers naming inconsistencies.*/ #if !defined(DAC1) #define DAC1 DAC -#define rccEnableDAC1 rccEnableDAC -#define rccDisableDAC1 rccDisableDAC #endif -#define DAC_CHN1_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_DAC_CHN1_DMA_STREAM, \ - STM32_DAC_CHN1_DMA_CHN) +#define DAC1_CH1_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_DAC1_CH1_DMA_STREAM, \ + STM32_DAC1_CH1_DMA_CHN) -#define DAC_CHN2_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_DAC_CHN2_DMA_STREAM, \ - STM32_DAC_CHN2_DMA_CHN) - -#define DAC_CHN3_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_DAC_CHN3_DMA_STREAM, \ - STM32_DAC_CHN3_DMA_CHN) +#define DAC1_CH2_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_DAC1_CH2_DMA_STREAM, \ + STM32_DAC1_CH2_DMA_CHN) + +#define DAC2_CH1_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_DAC2_CH1_DMA_STREAM, \ + STM32_DAC2_CH1_DMA_CHN) + +#define DAC2_CH2_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_DAC2_CH2_DMA_STREAM, \ + STM32_DAC2_CH2_DMA_CHN) + +#define CHANNEL_DATA_OFFSET 12 /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ -/** @brief CHN1 driver identifier.*/ -#if STM32_DAC_USE_CHN1 || defined(__DOXYGEN__) +/** @brief DAC1 CH1 driver identifier.*/ +#if STM32_DAC_USE_DAC1_CH1 || defined(__DOXYGEN__) DACDriver DACD1; #endif -/** @brief CHN2 driver identifier.*/ -#if STM32_DAC_USE_CHN2 || defined(__DOXYGEN__) +/** @brief DAC1 CH2 driver identifier.*/ +#if (STM32_DAC_USE_DAC1_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__) DACDriver DACD2; #endif -/** @brief CHN3 driver identifier.*/ -#if STM32_DAC_USE_CHN3 || defined(__DOXYGEN__) +/** @brief DAC2 CH1 driver identifier.*/ +#if STM32_DAC_USE_DAC2_CH1 || defined(__DOXYGEN__) DACDriver DACD3; #endif +/** @brief DAC2 CH2 driver identifier.*/ +#if (STM32_DAC_USE_DAC2_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__) +DACDriver DACD4; +#endif + /*===========================================================================*/ /* Driver local variables. */ /*===========================================================================*/ @@ -83,26 +93,20 @@ DACDriver DACD3; */ static void dac_lld_serve_tx_interrupt(DACDriver *dacp, uint32_t flags) { -#if defined(STM32_DAC_DMA_ERROR_HOOK) - (void)dacp; if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { /* DMA errors handling.*/ - //~ _dac_isr_error_code(dacp, flags); + _dac_isr_error_code(dacp, DAC_ERR_DMAFAILURE); } else { if ((flags & STM32_DMA_ISR_HTIF) != 0) { /* Half transfer processing.*/ - //~ _dac_isr_half_code(dacp); + _dac_isr_half_code(dacp); } if ((flags & STM32_DMA_ISR_TCIF) != 0) { /* Transfer complete processing.*/ - //~ _dac_isr_full_code(dacp); + _dac_isr_full_code(dacp); } } -#else - (void)dacp; - (void)flags; -#endif } /*===========================================================================*/ @@ -120,46 +124,56 @@ static void dac_lld_serve_tx_interrupt(DACDriver *dacp, uint32_t flags) { */ void dac_lld_init(void) { -#if STM32_DAC_USE_CHN1 +#if STM32_DAC_USE_DAC1_CH1 dacObjectInit(&DACD1); DACD1.dac = DAC1; - DACD1.tim = STM32_TIM6; - DACD1.irqprio = STM32_DAC_CHN1_IRQ_PRIORITY; - DACD1.dma = STM32_DMA_STREAM(STM32_DAC_CHN1_DMA_STREAM); - DACD1.dmamode = STM32_DMA_CR_CHSEL(DAC_CHN1_DMA_CHANNEL) | \ - STM32_DMA_CR_PL(STM32_DAC_CHN1_DMA_PRIORITY) | \ - STM32_DMA_CR_DIR_M2P | \ - STM32_DMA_CR_DMEIE | \ - STM32_DMA_CR_TEIE | \ - STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE; + DACD1.dma = STM32_DMA_STREAM(STM32_DAC1_CH1_DMA_STREAM); + DACD1.dmamode = STM32_DMA_CR_CHSEL(DAC1_CH1_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_DAC1_CH1_DMA_PRIORITY) | + STM32_DMA_CR_MINC | + STM32_DMA_CR_CIRC | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | + STM32_DMA_CR_HTIE | STM32_DMA_CR_TCIE; #endif -#if STM32_DAC_USE_CHN2 +#if STM32_DAC_USE_DAC1_CH2 dacObjectInit(&DACD2); DACD2.dac = DAC1; - DACD2.tim = STM32_TIM7; - DACD2.irqprio = STM32_DAC_CHN2_IRQ_PRIORITY; - DACD2.dma = STM32_DMA_STREAM(STM32_DAC_CHN2_DMA_STREAM); - DACD2.dmamode = STM32_DMA_CR_CHSEL(DAC_CHN2_DMA_CHANNEL) | \ - STM32_DMA_CR_PL(STM32_DAC_CHN2_DMA_PRIORITY) | \ - STM32_DMA_CR_DIR_M2P | \ - STM32_DMA_CR_DMEIE | \ - STM32_DMA_CR_TEIE | \ - STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE; + DACD2.dma = STM32_DMA_STREAM(STM32_DAC1_CH2_DMA_STREAM); + DACD2.dmamode = STM32_DMA_CR_CHSEL(DAC1_CH2_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_DAC1_CH2_DMA_PRIORITY) | + STM32_DMA_CR_MINC | + STM32_DMA_CR_CIRC | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | + STM32_DMA_CR_HTIE | STM32_DMA_CR_TCIE; #endif -#if STM32_DAC_USE_CHN3 +#if STM32_DAC_USE_DAC2_CH1 dacObjectInit(&DACD3); DACD3.dac = DAC2; - DACD3.tim = STM32_TIM18; - DACD3.irqprio = STM32_DAC_CHN3_IRQ_PRIORITY; - DACD3.dma = STM32_DMA_STREAM(STM32_DAC_CHN3_DMA_STREAM); - DACD3.dmamode = STM32_DMA_CR_CHSEL(DAC_CHN3_DMA_CHANNEL) | \ - STM32_DMA_CR_PL(STM32_DAC_CHN2_DMA_PRIORITY) | \ - STM32_DMA_CR_DIR_M2P | \ - STM32_DMA_CR_DMEIE | \ - STM32_DMA_CR_TEIE | \ - STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE; + DACD3.dma = STM32_DMA_STREAM(STM32_DAC2_CH1_DMA_STREAM); + DACD3.dmamode = STM32_DMA_CR_CHSEL(DAC2_CH1_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_DAC2_CH1_DMA_PRIORITY) | + STM32_DMA_CR_MINC | + STM32_DMA_CR_CIRC | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | + STM32_DMA_CR_HTIE | STM32_DMA_CR_TCIE; +#endif + +#if STM32_DAC_USE_DAC2_CH2 + dacObjectInit(&DACD4); + DACD4.dac = DAC2; + DACD4.dma = STM32_DMA_STREAM(STM32_DAC2_CH2_DMA_STREAM); + DACD4.dmamode = STM32_DMA_CR_CHSEL(DAC2_CH2_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_DAC2_CH2_DMA_PRIORITY) | + STM32_DMA_CR_MINC | + STM32_DMA_CR_CIRC | + STM32_DMA_CR_DIR_M2P | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | + STM32_DMA_CR_HTIE | STM32_DMA_CR_TCIE; #endif } @@ -171,93 +185,110 @@ void dac_lld_init(void) { * @notapi */ void dac_lld_start(DACDriver *dacp) { - uint32_t arr, regshift, trgo, dataoffset; + uint32_t cr, regshift, dataoffset; bool b; - /* If in stopped state then enables the DAC and DMA clocks.*/ - if (dacp->state == DAC_STOP) { -#if STM32_DAC_USE_CHN1 + +#if STM32_DAC_USE_DAC1_CH1 if (&DACD1 == dacp) { - rccEnableDAC1(FALSE); - /* DAC1 CR data is at bits 0:15 */ - regshift = 0; + if (dacp->state == DAC_STOP) { + b = dmaStreamAllocate(dacp->dma, STM32_DAC1_CH1_IRQ_PRIORITY, + (stm32_dmaisr_t)dac_lld_serve_tx_interrupt, + (void *)dacp); + osalDbgAssert(!b, "stream already allocated"); + + rccEnableDAC1(false); + } + + /* Channel-specific parameters.*/ dataoffset = 0; - /* Timer setup */ - rccEnableTIM6(FALSE); - rccResetTIM6(); - trgo = STM32_DAC_CR_TSEL_TIM6; - } + regshift = 0; + } #endif -#if STM32_DAC_USE_CHN2 + +#if STM32_DAC_USE_DAC1_CH2 if (&DACD2 == dacp) { - rccEnableDAC1(FALSE); - /* DAC2 CR data is at bits 16:31 */ + if (dacp->state == DAC_STOP) { + b = dmaStreamAllocate(dacp->dma, STM32_DAC1_CH2_IRQ_PRIORITY, + (stm32_dmaisr_t)dac_lld_serve_tx_interrupt, + (void *)dacp); + osalDbgAssert(!b, "stream already allocated"); + rccEnableDAC1(false); + } + + /* Channel-specific parameters.*/ + dataoffset = CHANNEL_DATA_OFFSET; regshift = 16; - dataoffset = &dacp->dac->DHR12R2 - &dacp->dac->DHR12R1; - /* Timer setup */ - rccEnableTIM7(FALSE); - rccResetTIM7(); - trgo = STM32_DAC_CR_TSEL_TIM7; } #endif -#if STM32_DAC_USE_CHN3 + +#if STM32_DAC_USE_DAC2_CH1 if (&DACD3 == dacp) { - rccEnableDAC2(FALSE); - /* DAC3 CR data is at bits 0:15 */ - regshift = 0; + if (dacp->state == DAC_STOP) { + b = dmaStreamAllocate(dacp->dma, STM32_DAC2_CH1_IRQ_PRIORITY, + (stm32_dmaisr_t)dac_lld_serve_tx_interrupt, + (void *)dacp); + osalDbgAssert(!b, "stream already allocated"); + rccEnableDAC2(false); + } + + /* Channel-specific parameters.*/ dataoffset = 0; - /* Timer setup */ - rccEnableTIM18(FALSE); - rccResetTIM18(); - trgo = STM32_DAC_CR_TSEL_TIM18; + regshift = 0; } #endif -#if STM32_DAC_USE_CHN1 || STM32_DAC_USE_CHN2 || STM32_DAC_USE_CHN3 - dacp->clock = STM32_TIMCLK1; - arr = (dacp->clock / dacp->config->frequency); - osalDbgAssert((arr <= 0xFFFF), - "invalid frequency"); - - /* Timer configuration.*/ - dacp->tim->CR1 = 0; /* Initially stopped. */ - dacp->tim->PSC = 0; /* Prescaler value. */ - dacp->tim->DIER = 0; - dacp->tim->ARR = arr; - dacp->tim->EGR = TIM_EGR_UG; /* Update event. */ - dacp->tim->CR2 &= (uint16_t)~TIM_CR2_MMS; - dacp->tim->CR2 |= (uint16_t)TIM_CR2_MMS_1; /* Enable TRGO updates. */ - dacp->tim->CNT = 0; /* Reset counter. */ - dacp->tim->SR = 0; /* Clear pending IRQs. */ - /* Update Event IRQ enabled. */ - /* Timer start.*/ - dacp->tim->CR1 = TIM_CR1_CEN; - - /* DAC configuration */ - dacp->dac->CR |= ( (dacp->dac->CR & ~STM32_DAC_CR_MASK) | \ - (STM32_DAC_CR_EN | STM32_DAC_CR_DMAEN | dacp->config->cr_flags) ) << regshift; - - /* DMA setup. */ - b = dmaStreamAllocate(dacp->dma, - dacp->irqprio, - (stm32_dmaisr_t)dac_lld_serve_tx_interrupt, - (void *)dacp); - osalDbgAssert(!b, "stream already allocated"); - switch (dacp->config->dhrm) { - /* Sets the DAC data register */ - case DAC_DHRM_12BIT_RIGHT: - dmaStreamSetPeripheral(dacp->dma, &dacp->dac->DHR12R1 + dataoffset); - dacp->dmamode = (dacp->dmamode & ~STM32_DMA_CR_SIZE_MASK) | - STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; - break; - case DAC_DHRM_12BIT_LEFT: - dmaStreamSetPeripheral(dacp->dma, &dacp->dac->DHR12L1 + dataoffset); - dacp->dmamode = (dacp->dmamode & ~STM32_DMA_CR_SIZE_MASK) | - STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; - break; - case DAC_DHRM_8BIT_RIGHT: - dmaStreamSetPeripheral(dacp->dma, &dacp->dac->DHR8R1 + dataoffset); - dacp->dmamode = (dacp->dmamode & ~STM32_DMA_CR_SIZE_MASK) | - STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE; - break; + +#if STM32_DAC_USE_DAC2_CH2 + if (&DACD3 == dacp) { + if (dacp->state == DAC_STOP) { + b = dmaStreamAllocate(dacp->dma, STM32_DAC2_CH2_IRQ_PRIORITY, + (stm32_dmaisr_t)dac_lld_serve_tx_interrupt, + (void *)dacp); + osalDbgAssert(!b, "stream already allocated"); + rccEnableDAC2(false); + } + + /* Channel-specific parameters.*/ + dataoffset = CHANNEL_DATA_OFFSET; + regshift = 16; + } +#endif + + /* DAC configuration.*/ +#if STM32_DAC_DUAL_MODE == FALSE + cr = DAC_CR_DMAEN1 | (dacp->config->cr_tsel << 3) | + DAC_CR_TEN1 | DAC_CR_EN1; + dacp->dac->CR = (dacp->dac->CR & ~(0x0000FFFF << regshift)) | + (cr << regshift); +#else + /* TODO: Dual.*/ +#endif + +#if STM32_DAC_DUAL_MODE == FALSE + switch (dacp->config->dhrm) { + /* Sets the DAC data register */ + case DAC_DHRM_12BIT_RIGHT: + dmaStreamSetPeripheral(dacp->dma, &dacp->dac->DHR12R1 + dataoffset); + dacp->dmamode = (dacp->dmamode & ~STM32_DMA_CR_SIZE_MASK)| + STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; + *(&dacp->dac->DHR12R1 + dataoffset) = (uint32_t)dacp->config->sample; + break; + case DAC_DHRM_12BIT_LEFT: + dmaStreamSetPeripheral(dacp->dma, &dacp->dac->DHR12L1 + dataoffset); + dacp->dmamode = (dacp->dmamode & ~STM32_DMA_CR_SIZE_MASK)| + STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; + *(&dacp->dac->DHR12L1 + dataoffset) = (uint32_t)dacp->config->sample; + break; + case DAC_DHRM_8BIT_RIGHT: + dmaStreamSetPeripheral(dacp->dma, &dacp->dac->DHR8R1 + dataoffset); + dacp->dmamode = (dacp->dmamode & ~STM32_DMA_CR_SIZE_MASK)| + STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE; + *(&dacp->dac->DHR8R1 + dataoffset) = (uint32_t)dacp->config->sample; + break; + default: + chDbgAssert(false, "unexpected DAC mode"); + break; + } +#else #if defined(STM32_HAS_DAC_CHN2) && STM32_HAS_DAC_CHN2 case DAC_DHRM_12BIT_RIGHT_DUAL: dmaStreamSetPeripheral(dacp->dma, &dacp->dac->DHR12RD); @@ -275,11 +306,7 @@ void dac_lld_start(DACDriver *dacp) { STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE; break; #endif - } - - dacp->dac->CR |= trgo << regshift; /* Enable timer trigger */ #endif - } } /** @@ -294,54 +321,65 @@ void dac_lld_stop(DACDriver *dacp) { /* If in ready state then disables the DAC clock.*/ if (dacp->state == DAC_READY) { - /* DMA disable.*/ + /* DMA channel released.*/ dmaStreamRelease(dacp->dma); -#if STM32_DAC_USE_CHN1 +#if STM32_DAC_USE_DAC1_CH1 if (&DACD1 == dacp) { - dacp->dac->CR &= ~STM32_DAC_CR_EN; /* DAC1 disable.*/ + dacp->dac->CR &= ~DAC_CR_EN1; + + if ((dacp->dac->CR & DAC_CR_EN2) == 0U) { + rccDisableDAC1(false); + } } #endif -#if STM32_DAC_USE_CHN2 + +#if STM32_DAC_USE_DAC1_CH2 if (&DACD2 == dacp) { - dacp->dac->CR &= ~STM32_DAC_CR_EN << 16; /* DAC1 disable.*/ - } -#endif -#if STM32_DAC_USE_CHN3 - if (&DACD3 == dacp) { - dacp->dac->CR &= ~STM32_DAC_CR_EN; /* DAC2 disable.*/ - rccDisableDAC2(FALSE); /* DAC Clock disable.*/ - } -#endif - dacp->tim->CR1 &= ~TIM_CR1_CEN; /* Disable associated timer */ - dacp->state = DAC_STOP; + dacp->dac->CR &= ~DAC_CR_EN2; - if (!(DAC1->CR & (STM32_DAC_CR_EN | STM32_DAC_CR_EN << 16))) { - /* DAC Clock disable only if all channels are off.*/ - rccDisableDAC1(FALSE); + if ((dacp->dac->CR & DAC_CR_EN1) == 0U) { + rccDisableDAC1(false); + } } +#endif } } /** - * @brief Sends data over the DAC bus. - * @details This asynchronous function starts a transmit operation. - * @post At the end of the operation the configured callback is invoked. + * @brief Starts a DAC conversion. + * @details Starts an asynchronous conversion operation. * * @param[in] dacp pointer to the @p DACDriver object - * @param[in] n number of words to send - * @param[in] txbuf the pointer to the transmit buffer * * @notapi */ void dac_lld_start_conversion(DACDriver *dacp) { - osalDbgAssert(dacp->samples, - "dacp->samples is NULL pointer"); + dmaStreamSetMemory0(dacp->dma, dacp->samples); dmaStreamSetTransactionSize(dacp->dma, dacp->depth); - dmaStreamSetMode(dacp->dma, dacp->dmamode | STM32_DMA_CR_EN | - STM32_DMA_CR_CIRC); + dmaStreamSetMode(dacp->dma, dacp->dmamode | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | + STM32_DMA_CR_HTIE | STM32_DMA_CR_TCIE); + dmaStreamEnable(dacp->dma); +} + + +/** + * @brief Stops an ongoing conversion. + * @details This function stops the currently ongoing conversion and returns + * the driver in the @p DAC_READY state. If there was no conversion + * being processed then the function does nothing. + * + * @param[in] dacp pointer to the @p DACDriver object + * + * @iclass + */ +void dac_lld_stop_conversion(DACDriver *dacp) { + + dmaStreamDisable(dacp->dma); } + #endif /* HAL_USE_DAC */ /** @} */ diff --git a/os/hal/ports/STM32/LLD/DACv1/dac_lld.h b/os/hal/ports/STM32/LLD/DACv1/dac_lld.h index 9cf6158c3..f63d64139 100644 --- a/os/hal/ports/STM32/LLD/DACv1/dac_lld.h +++ b/os/hal/ports/STM32/LLD/DACv1/dac_lld.h @@ -33,43 +33,6 @@ /* Driver constants. */ /*===========================================================================*/ -#define STM32_DAC_CR_EN DAC_CR_EN1 -#define STM32_DAC_CR_DMAEN DAC_CR_DMAEN1 -#define STM32_DAC_CR_TEN DAC_CR_TEN1 - -#define STM32_DAC_CR_MASK (uint32_t)0x00000FFE - -#define STM32_DAC_CR_BOFF_ENABLE (uint32_t)0x00000000 -#define STM32_DAC_CR_BOFF_DISABLE DAC_CR_BOFF1 - -#define STM32_DAC_CR_TSEL_NONE (uint32_t)0x00000000 -#define STM32_DAC_CR_TSEL_TIM2 DAC_CR_TEN1 | DAC_CR_TSEL1_2 -#define STM32_DAC_CR_TSEL_TIM4 DAC_CR_TEN1 | DAC_CR_TEN0 | DAC_CR_TSEL1_2 -#define STM32_DAC_CR_TSEL_TIM5 DAC_CR_TEN1 | DAC_CR_TEN0 | DAC_CR_TSEL1_1 -#define STM32_DAC_CR_TSEL_TIM6 DAC_CR_TEN1 -#define STM32_DAC_CR_TSEL_TIM7 DAC_CR_TEN1 | DAC_CR_TSEL1_1 -#define STM32_DAC_CR_TSEL_TIM3 DAC_CR_TEN1 | DAC_CR_TSEL1_0 -#define STM32_DAC_CR_TSEL_TIM18 DAC_CR_TEN1 | DAC_CR_TSEL1_0 | DAC_CR_TSEL1_1 -#define STM32_DAC_CR_TSEL_EXT_IT9 DAC_CR_TEN1 | DAC_CR_TEN1 | DAC_CR_TSEL1_2 -#define STM32_DAC_CR_TSEL_SOFT DAC_CR_TEN1 | DAC_CR_TEN0 | DAC_CR_TSEL1_1 | DAC_CR_TSEL1_2 - -#define STM32_DAC_CR_WAVE_NONE (uint32_t)0x00000000 -#define STM32_DAC_CR_WAVE_NOISE DAC_CR_WAVE1_0 -#define STM32_DAC_CR_WAVE_TRIANGLE DAC_CR_WAVE1_1 - -#define STM32_DAC_MAMP_1 (uint32_t)0x00000000 -#define STM32_DAC_MAMP_3 DAC_CR_MAMP1_0 -#define STM32_DAC_MAMP_7 DAC_CR_MAMP1_1 -#define STM32_DAC_MAMP_15 DAC_CR_MAMP1_0 | DAC_CR_MAMP1_1 -#define STM32_DAC_MAMP_31 DAC_CR_MAMP1_2 -#define STM32_DAC_MAMP_63 DAC_CR_MAMP1_0 | DAC_CR_MAMP1_2 -#define STM32_DAC_MAMP_127 DAC_CR_MAMP1_1 | DAC_CR_MAMP1_2 -#define STM32_DAC_MAMP_255 DAC_CR_MAMP1_0 | DAC_CR_MAMP1_1 | DAC_CR_MAMP1_2 -#define STM32_DAC_MAMP_511 DAC_CR_MAMP1_3 -#define STM32_DAC_MAMP_1023 DAC_CR_MAMP1_0 | DAC_CR_MAMP1_3 -#define STM32_DAC_MAMP_2047 DAC_CR_MAMP1_1 | DAC_CR_MAMP1_3 -#define STM32_DAC_MAMP_4095 DAC_CR_MAMP1_0 | DAC_CR_MAMP1_1 | DAC_CR_MAMP1_2 - /*===========================================================================*/ /* Driver pre-compile time settings. */ /*===========================================================================*/ @@ -79,122 +42,131 @@ * @{ */ /** - * @brief DAC CHN1 driver enable switch. - * @details If set to @p TRUE the support for DAC CHN1 is included. - * @note The default is @p TRUE. + * @brief Enables the DAC dual mode. + * @note In dual mode DAC second channels cannot be accessed individually. */ -#if !defined(STM32_DAC_USE_CHN1) || defined(__DOXYGEN__) -#define STM32_DAC_USE_CHN1 FALSE +#if !defined(STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__) +#define STM32_DAC_DUAL_MODE FALSE #endif /** - * @brief DAC CHN2 driver enable switch. - * @details If set to @p TRUE the support for DAC CHN2 is included. - * @note The default is @p TRUE. + * @brief DAC1 CH1 driver enable switch. + * @details If set to @p TRUE the support for DAC1 channel 1 is included. + * @note The default is @p FALSE. */ -#if !defined(STM32_DAC_USE_CHN2) || defined(__DOXYGEN__) -#define STM32_DAC_USE_CHN2 FALSE +#if !defined(STM32_DAC_USE_DAC1_CH1) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC1_CH1 FALSE #endif /** - * @brief DAC CHN3 driver enable switch. - * @details If set to @p TRUE the support for DAC CHN3 is included. - * @note The default is @p TRUE. + * @brief DAC1 CH2 driver enable switch. + * @details If set to @p TRUE the support for DAC1 channel 2 is included. + * @note The default is @p FALSE. */ -#if !defined(STM32_DAC_USE_CHN3) || defined(__DOXYGEN__) -#define STM32_DAC_USE_CHN3 FALSE +#if !defined(STM32_DAC_USE_DAC1_CH2) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC1_CH2 FALSE #endif /** - * @brief DAC CHN1 interrupt priority level setting. + * @brief DAC2 CH1 driver enable switch. + * @details If set to @p TRUE the support for DAC2 channel 1 is included. + * @note The default is @p FALSE. */ -#if !defined(STM32_DAC_CHN1_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_DAC_CHN1_IRQ_PRIORITY 10 +#if !defined(STM32_DAC_USE_DAC2_CH1) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC2_CH1 FALSE #endif /** - * @brief DAC CHN2 interrupt priority level setting. + * @brief DAC2 CH2 driver enable switch. + * @details If set to @p TRUE the support for DAC2 channel 2 is included. + * @note The default is @p FALSE. */ -#if !defined(STM32_DAC_CHN2_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_DAC_CHN2_IRQ_PRIORITY 10 +#if !defined(STM32_DAC_USE_DAC2_CH2) || defined(__DOXYGEN__) +#define STM32_DAC_USE_DAC2_CH2 FALSE #endif /** - * @brief DAC CHN3 interrupt priority level setting. + * @brief DAC1 CH1 interrupt priority level setting. */ -#if !defined(STM32_DAC_CHN3_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_DAC_CHN3_IRQ_PRIORITY 10 +#if !defined(STM32_DAC1_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC1_CH1_IRQ_PRIORITY 10 #endif /** - * @brief DAC CHN1 DMA priority (0..3|lowest..highest). + * @brief DAC1 CH2 interrupt priority level setting. */ -#if !defined(STM32_DAC_CHN1_DMA_PRIORITY) || defined(__DOXYGEN__) -#define STM32_DAC_CHN1_DMA_PRIORITY 2 +#if !defined(STM32_DAC1_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC1_CH2_IRQ_PRIORITY 10 #endif /** - * @brief DAC CHN2 DMA priority (0..3|lowest..highest). + * @brief DAC2 CH1 interrupt priority level setting. */ -#if !defined(STM32_DAC_CHN2_DMA_PRIORITY) || defined(__DOXYGEN__) -#define STM32_DAC_CHN2_DMA_PRIORITY 2 +#if !defined(STM32_DAC2_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC2_CH1_IRQ_PRIORITY 10 #endif /** - * @brief DAC CHN3 DMA priority (0..3|lowest..highest). + * @brief DAC2 CH2 interrupt priority level setting. */ -#if !defined(STM32_DAC_CHN3_DMA_PRIORITY) || defined(__DOXYGEN__) -#define STM32_DAC_CHN2_DMA_PRIORITY 2 +#if !defined(STM32_DAC2_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC2_CH2_IRQ_PRIORITY 10 #endif /** - * @brief DAC DMA error hook. + * @brief DAC1 CH1 DMA priority (0..3|lowest..highest). */ -#if !defined(STM32_DAC_DMA_ERROR_HOOK) || defined(__DOXYGEN__) -#define STM32_DAC_DMA_ERROR_HOOK(dacp) osalSysHalt() +#if !defined(STM32_DAC1_CH1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC1_CH1_DMA_PRIORITY 2 #endif /** - * @brief DMA stream used for DAC CHN1 TX operations. - * @note This option is only available on platforms with enhanced DMA. + * @brief DAC1 CH2 DMA priority (0..3|lowest..highest). */ -#if !defined(STM32_DAC_CHN1_DMA_STREAM) || defined(__DOXYGEN__) -#define STM32_DAC_CHN1_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) +#if !defined(STM32_DAC1_CH2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC1_CH2_DMA_PRIORITY 2 #endif /** - * @brief DMA stream used for DAC CHN2 TX operations. - * @note This option is only available on platforms with enhanced DMA. + * @brief DAC2 CH1 DMA priority (0..3|lowest..highest). */ -#if !defined(STM32_DAC_CHN2_DMA_STREAM) || defined(__DOXYGEN__) -#define STM32_DAC_CHN2_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) +#if !defined(STM32_DAC2_CH1_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC2_CH1_DMA_PRIORITY 2 #endif /** - * @brief DMA stream used for DAC CHN3 TX operations. - * @note This option is only available on platforms with enhanced DMA. + * @brief DAC2 CH2 DMA priority (0..3|lowest..highest). */ -#if !defined(STM32_DAC_CHN3_DMA_STREAM) || defined(__DOXYGEN__) -#define STM32_DAC_CHN3_DMA_STREAM STM32_DMA_STREAM_ID(1, 5) +#if !defined(STM32_DAC2_CH2_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DAC2_CH2_DMA_PRIORITY 2 #endif /*===========================================================================*/ /* Derived constants and error checks. */ /*===========================================================================*/ -#if STM32_DAC_USE_CHN1 && !STM32_HAS_DAC_CHN1 -#error "DAC CHN1 not present in the selected device" +#if STM32_DAC_USE_DAC1_CH1 && !STM32_HAS_DAC1_CH1 +#error "DAC1 CH1 not present in the selected device" +#endif + +#if STM32_DAC_USE_DAC1_CH2 && !STM32_HAS_DAC1_CH2 +#error "DAC1 CH2 not present in the selected device" +#endif + +#if STM32_DAC_USE_DAC2_CH1 && !STM32_HAS_DAC2_CH1 +#error "DAC2 CH1 not present in the selected device" #endif -#if STM32_DAC_USE_CHN2 && !STM32_HAS_DAC_CHN2 -#error "DAC CHN2 not present in the selected device" +#if STM32_DAC_USE_DAC2_CH2 && !STM32_HAS_DAC2_CH2 +#error "DAC2 CH2 not present in the selected device" #endif -#if STM32_DAC_USE_CHN3 && !STM32_HAS_DAC_CHN3 -#error "DAC CHN3 not present in the selected device" +#if (STM32_DAC_USE_DAC1_CH2 || STM32_DAC_USE_DAC2_CH2) && STM32_DAC_DUAL_MODE +#error "DACx CH2 cannot be used independently in dual mode" #endif -#if !STM32_DAC_USE_CHN1 && !STM32_DAC_USE_CHN2 && !STM32_DAC_USE_CHN3 +#if !STM32_DAC_USE_DAC1_CH1 && !STM32_DAC_USE_DAC1_CH2 && \ + !STM32_DAC_USE_DAC2_CH1 && !STM32_DAC_USE_DAC2_CH2 #error "DAC driver activated but no DAC peripheral assigned" #endif @@ -202,32 +174,41 @@ reassign streams to different channels.*/ #if STM32_ADVANCED_DMA /* Check on the presence of the DMA streams settings in mcuconf.h.*/ -#if STM32_DAC_USE_CHN1 && !defined(STM32_DAC_CHN1_DMA_STREAM) -#error "DAC1 CHN1 DMA stream not defined" +#if STM32_DAC_USE_DAC1_CH1 && !defined(STM32_DAC1_CH1_DMA_STREAM) +#error "DAC1 CH1 DMA stream not defined" +#endif + +#if STM32_DAC_USE_DAC1_CH2 && !defined(STM32_DAC1_CH2_DMA_STREAM) +#error "DAC1 CH2 DMA stream not defined" #endif -#if STM32_DAC_USE_CHN2 && !defined(STM32_DAC_CHN2_DMA_STREAM) -#error "DAC1 CHN2 DMA stream not defined" +#if STM32_DAC_USE_DAC2_CH1 && !defined(STM32_DAC2_CH1_DMA_STREAM) +#error "DAC2 CH1 DMA stream not defined" #endif -#if STM32_DAC_USE_CHN3 && !defined(STM32_DAC_CHN3_DMA_STREAM) -#error "DAC1 CHN3 DMA stream not defined" +#if STM32_DAC_USE_DAC2_CH2 && !defined(STM32_DAC2_CH2_DMA_STREAM) +#error "DAC2 CH2 DMA stream not defined" #endif /* Check on the validity of the assigned DMA channels.*/ -#if STM32_DAC_USE_CHN1 && \ - !STM32_DMA_IS_VALID_ID(STM32_DAC_CHN1_DMA_STREAM, STM32_DAC_CHN1_DMA_MSK) -#error "invalid DMA stream associated to DAC CHN1" +#if STM32_DAC_USE_DAC1_CH1 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC1_CH1_DMA_STREAM, STM32_DAC1_CH1_DMA_MSK) +#error "invalid DMA stream associated to DAC1 CH1" #endif -#if STM32_DAC_USE_CHN2 && \ - !STM32_DMA_IS_VALID_ID(STM32_DAC_CHN2_DMA_STREAM, STM32_DAC_CHN2_DMA_MSK) -#error "invalid DMA stream associated to DAC CHN2" +#if STM32_DAC_USE_DAC1_CH2 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC1_CH2_DMA_STREAM, STM32_DAC1_CH2_DMA_MSK) +#error "invalid DMA stream associated to DAC1 CH2" #endif -#if STM32_DAC_USE_CHN3 && \ - !STM32_DMA_IS_VALID_ID(STM32_DAC_CHN3_DMA_STREAM, STM32_DAC_CHN3_DMA_MSK) -#error "invalid DMA stream associated to DAC CHN3" +#if STM32_DAC_USE_DAC2_CH1 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC2_CH1_DMA_STREAM, STM32_DAC2_CH1_DMA_MSK) +#error "invalid DMA stream associated to DAC2 CH1" +#endif + +#if STM32_DAC_USE_DAC2_CH2 && \ + !STM32_DMA_IS_VALID_ID(STM32_DAC2_CH2_DMA_STREAM, STM32_DAC2_CH2_DMA_MSK) +#error "invalid DMA stream associated to DAC2 CH2" #endif #endif /* STM32_ADVANCED_DMA */ @@ -249,19 +230,45 @@ typedef struct DACDriver DACDriver; */ typedef uint16_t dacsample_t; +/** + * @brief Possible DAC failure causes. + * @note Error codes are architecture dependent and should not relied + * upon. + */ +typedef enum { + DAC_ERR_DMAFAILURE = 0, /**< DMA operations failure. */ + DAC_ERR_UNDERFLOW = 1 /**< DAC overflow condition. */ +} dacerror_t; + /** * @brief DAC notification callback type. * * @param[in] dacp pointer to the @p DACDriver object triggering the + * @param[in] buffer pointer to the next semi-buffer to be filled + * @param[in] n number of buffer rows available starting from @p buffer * callback */ -typedef void (*daccallback_t)(DACDriver *dacp); +typedef void (*daccallback_t)(DACDriver *dacp, + const dacsample_t *buffer, + size_t n); +/** + * @brief ADC error callback type. + * + * @param[in] dacp pointer to the @p DACDriver object triggering the + * callback + * @param[in] err ADC error code + */ +typedef void (*dacerrorcallback_t)(DACDriver *adcp, dacerror_t err); + +/** + * @brief Samples alignment and size mode. + */ typedef enum { DAC_DHRM_12BIT_RIGHT = 0, DAC_DHRM_12BIT_LEFT = 1, DAC_DHRM_8BIT_RIGHT = 2, -#if STM32_HAS_DAC_CHN2 && !defined(__DOXYGEN__) +#if STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__) DAC_DHRM_12BIT_RIGHT_DUAL = 3, DAC_DHRM_12BIT_LEFT_DUAL = 4, DAC_DHRM_8BIT_RIGHT_DUAL = 5 @@ -273,18 +280,18 @@ typedef enum { */ typedef struct { /** - * @brief Number of DAC channels. + * @brief Number of DAC channels. */ uint32_t num_channels; /** - * @brief Operation complete callback or @p NULL. + * @brief Operation complete callback or @p NULL. */ daccallback_t end_cb; /** - * @brief Error handling callback or @p NULL. + * @brief Error handling callback or @p NULL. */ - daccallback_t error_cb; - + dacerrorcallback_t error_cb; + /* End of the mandatory fields.*/ } DACConversionGroup; /** @@ -292,18 +299,21 @@ typedef struct { */ typedef struct { /** - * @brief Timer frequency in Hz. + * @brief Initial sample to be presented on outputs. */ - uint32_t frequency; + dacsample_t sample; /* End of the mandatory fields.*/ /** * @brief DAC data holding register mode. */ dacdhrmode_t dhrm; /** - * @brief DAC initialization data. + * @brief DAC initialization data. + * @note This field contains the (not shifted) value to be put into the + * TSEL field of the DAC CR register during initialization. All + * other fields are handled internally. */ - uint32_t cr_flags; + uint32_t cr_tsel; } DACConfig; /** @@ -311,34 +321,34 @@ typedef struct { */ struct DACDriver { /** - * @brief Driver state. + * @brief Driver state. */ dacstate_t state; /** - * @brief Conversion group. + * @brief Conversion group. */ const DACConversionGroup *grpp; /** - * @brief Samples buffer pointer. + * @brief Samples buffer pointer. */ const dacsample_t *samples; /** - * @brief Samples buffer size. + * @brief Samples buffer size. */ uint16_t depth; /** - * @brief Current configuration data. + * @brief Current configuration data. */ const DACConfig *config; #if DAC_USE_WAIT || defined(__DOXYGEN__) /** - * @brief Waiting thread. + * @brief Waiting thread. */ thread_reference_t thread; #endif /* DAC_USE_WAIT */ #if DAC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) /** - * @brief Mutex protecting the bus. + * @brief Mutex protecting the bus. */ mutex_t mutex; #endif /* DAC_USE_MUTUAL_EXCLUSION */ @@ -347,29 +357,17 @@ struct DACDriver { #endif /* End of the mandatory fields.*/ /** - * @brief Pointer to the DAC registers block. + * @brief Pointer to the DAC registers block. */ DAC_TypeDef *dac; /** - * @brief Pointer to the TIMx registers block. - */ - stm32_tim_t *tim; - /** - * @brief The Timer IRQ priority. - */ - uint32_t irqprio; - /** - * @brief Transmit DMA stream. + * @brief Transmit DMA stream. */ const stm32_dma_stream_t *dma; /** - * @brief TX DMA mode bit mask. + * @brief TX DMA mode bit mask. */ uint32_t dmamode; - /** - * @brief Timer base clock. - */ - uint32_t clock; }; /*===========================================================================*/ @@ -380,18 +378,22 @@ struct DACDriver { /* External declarations. */ /*===========================================================================*/ -#if STM32_DAC_USE_CHN1 && !defined(__DOXYGEN__) +#if STM32_DAC_USE_DAC1_CH1 && !defined(__DOXYGEN__) extern DACDriver DACD1; #endif -#if STM32_DAC_USE_CHN2 && !defined(__DOXYGEN__) +#if STM32_DAC_USE_DAC1_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__) extern DACDriver DACD2; #endif -#if STM32_DAC_USE_CHN3 && !defined(__DOXYGEN__) +#if STM32_DAC_USE_DAC2_CH1 && !defined(__DOXYGEN__) extern DACDriver DACD3; #endif +#if STM32_DAC_USE_DAC2_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__) +extern DACDriver DACD4; +#endif + #ifdef __cplusplus extern "C" { #endif -- cgit v1.2.3