/* * @file adc.c * @date Mar 14, 2024 * @author Francesco Gritti */ #include "mcu.h" #ifdef use_adc void ADC_COMP_IRQHandler (void) { if ((ADC1->ISR & ADC_ISR_OVR) != 0) { ADC1->ISR |= ADC_ISR_OVR; // clear interrupt flag ADC1->CR &= ~ADC_CR_ADSTART; // stop ADC } else if ((ADC1->ISR & ADC_ISR_EOS) != 0) { ADC1->ISR |= ADC_ISR_EOS; flib_printf ("conv end\n"); } else if ((ADC1->ISR & ADC_ISR_EOC) != 0) { ADC1->ISR |= ADC_ISR_EOC; u32 adcVal = ADC1->DR; flib_printf ("conv\n"); } } // NOTE: in case of ADC overrun error, the ADC is stopped and must // be re-initalized by clearing OVR flag. // when all data requested to the DMA have been transferred, the ADC // is automatically stopped void ADC_init (void) { // enable DMA and ADC clock RCC_ADC_CLK_ENABLE(); // NOTE: must clear ADSTART bit to set some registers ADC1->CR = 0x0000; ADC1->CFGR2 = (ADC_CLK << ADC_CFGR2_CKMODE_Pos); ADC1->CFGR1 = (ADC_CONV_MODE << ADC_CFGR1_CONT_Pos) | (ADC_OVRMOD << ADC_CFGR1_OVRMOD_Pos) | (ADC_EXTEN_EDGE << ADC_CFGR1_EXTEN_Pos) | (ADC_EXTSEL << ADC_CFGR1_EXTSEL_Pos) | (ADC_ALIGN_RIGHT << ADC_CFGR1_ALIGN_Pos) | (ADC_RES_12bit << ADC_CFGR1_RES_Pos); // enable end of sequence and end of conversion interrupt ADC1->IER = ADC_IER_EOCIE | ADC_IER_EOSIE; ADC1->SMPR = (ADC_SAMPLE_TIME << ADC_SMPR_SMP_Pos); // enable interrupt NVIC_EnableIRQ(ADC1_IRQn); NVIC_SetPriority(ADC1_IRQn, 2); ADC1->CR |= ADC_CR_ADEN_Msk; // wait until ADC is ready for conversion u32 startTick = flib_GetTick(); while ((ADC1->ISR & ADC_ISR_ADRDY) == 0) { if((flib_GetTick() - startTick) > 10) return; } } void ADC_StartConversion (void) { ADC1->CR |= ADC_CR_ADSTART; } void ADC_addChannelToScanList (u8 channel) { ADC1->CHSELR |= (1<CHSELR &= ~(1<CMAR = (uint32_t)(ADC_array); DMA1_Channel1->CNDTR = channels; ADC1->CR |= ADC_CR_ADSTART; // start converting and generating DMA requests } // configure DMA only. Conversion will be triggered lately by software or by hardware // through an event void ADC_configureDMA (u8 channels, u16 * ADC_array) { DMA1_Channel1->CMAR = (uint32_t)(ADC_array); DMA1_Channel1->CNDTR = channels; } u8 ADC_disable (void) { ADC1->CR |= ADC_CR_ADDIS_Msk; // wait until ADC is actually disabled u32 startTick = flib_GetTick(); while ((ADC1->CR & ADC_CR_ADDIS_Msk) != 0) { if((flib_GetTick() - startTick) > 10) return 0; } return 1; } u8 ADC_enable (void) { ADC1->CR |= ADC_CR_ADEN_Msk; // wait until ADC is ready for conversion u32 startTick = flib_GetTick(); while ((ADC1->ISR & ADC_ISR_ADRDY) == 0) { if((flib_GetTick() - startTick) > 10) return 0; } return 1; } #endif #ifdef use_adc_dma __attribute__((weak)) void adc_dma_transferCompleteCallback (void) { } __attribute__((weak)) void adc_dma_halfTransferCallback (void) { } void DMA1_CH1_IRQHandler (void) { if ((DMA1->ISR & DMA_ISR_GIF1) != 0) { // check for transfer complete if ((DMA1->ISR & DMA_ISR_TCIF1) != 0) { DMA1->IFCR |= DMA_IFCR_CTCIF1; DMA1_Channel1->CCR &= ~DMA_CCR_EN; // disable DMA channel adc_dma_transferCompleteCallback (); } // transfer half complete else if ((DMA1->ISR & DMA_ISR_HTIF1) != 0) { DMA1->IFCR |= DMA_IFCR_CHTIF1; adc_dma_halfTransferCallback (); } // error flag else if ((DMA1->ISR & DMA_ISR_TEIF1) != 0) { // channel EN bit automatically cleared on DMA error // cannot re-enable DMA channel before clearing error flag DMA1->IFCR |= DMA_IFCR_CTEIF1; // re-init ADC peripheral. Wait for software to call again acquisition ADC_init (); } } } void ADC_COMP_IRQHandler (void) { if ((ADC1->ISR & ADC_ISR_OVR) != 0) { ADC1->ISR |= ADC_ISR_OVR; // clear interrupt flag ADC1->CR &= ~ADC_CR_ADSTART; // stop ADC } } // NOTE: in case of ADC overrun error, the ADC is stopped and must // be re-initalized by clearing OVR flag. // when all data requested to the DMA have been transferred, the ADC // is automatically stopped void ADC_init (void) { // enable DMA and ADC clock RCC_DMA_CLK_ENABLE(); RCC_ADC_CLK_ENABLE(); // NOTE: must clear ADSTART bit to set some registers ADC1->CR = 0x0000; ADC1->CFGR2 = (ADC_CLK << ADC_CFGR2_CKMODE_Pos); ADC1->CFGR1 = (ADC_CONV_MODE << ADC_CFGR1_CONT_Pos) | (ADC_OVRMOD << ADC_CFGR1_OVRMOD_Pos) | (ADC_EXTEN_EDGE << ADC_CFGR1_EXTEN_Pos) | (ADC_EXTSEL << ADC_CFGR1_EXTSEL_Pos) | (ADC_ALIGN_RIGHT << ADC_CFGR1_ALIGN_Pos) | (ADC_RES_12bit << ADC_CFGR1_RES_Pos) | (ADC_DMA_MODE << ADC_CFGR1_DMACFG_Pos) | (ADC_DMA_EN << ADC_CFGR1_DMAEN_Pos); // disable all interrupt, it will be called by the DMA on transaction completed ADC1->IER = 0x00; ADC1->SMPR = (ADC_SAMPLE_TIME << ADC_SMPR_SMP_Pos); // configure DMA, enabled error, complete interrupts DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR)); DMA1_Channel1->CCR |= DMA_CCR_MINC | (DMA_MSIZE_16_bit << DMA_CCR_MSIZE_Pos) | (DMA_PSIZE_16_bit << DMA_CCR_PSIZE_Pos) | DMA_CCR_TEIE | DMA_CCR_TCIE ; // enable DMA interrupt needed for errors and transfer complete NVIC_EnableIRQ(DMA1_Channel1_IRQn); NVIC_SetPriority(DMA1_Channel1_IRQn, 2); // enable ADC interrupt needed to detect overrun error and // in that case to restart the ADC peripheral //NVIC_EnableIRQ(ADC1_IRQn); //NVIC_SetPriority(ADC1_IRQn, 2); ADC1->CR |= ADC_CR_ADEN_Msk; // wait until ADC is ready for conversion u32 startTick = flib_GetTick(); while ((ADC1->ISR & ADC_ISR_ADRDY) == 0) { if((flib_GetTick() - startTick) > 10) return; } } void ADC_addChannelToScanList (u8 channel) { ADC1->CHSELR |= (1<CHSELR &= ~(1<CCR &= ~DMA_CCR_EN; // disable DMA channel DMA1_Channel1->CMAR = (uint32_t)(ADC_array); DMA1_Channel1->CNDTR = channels; DMA1_Channel1->CCR |= DMA_CCR_EN; // enable DMA ADC1->CR |= ADC_CR_ADSTART; // start converting and generating DMA requests } // configure DMA only. Conversion will be triggered lately by software or by hardware // through an event void ADC_configureDMA (u8 channels, u16 * ADC_array) { DMA1_Channel1->CMAR = (uint32_t)(ADC_array); DMA1_Channel1->CNDTR = channels; } u8 ADC_disable (void) { ADC1->CR |= ADC_CR_ADDIS_Msk; // wait until ADC is actually disabled u32 startTick = flib_GetTick(); while ((ADC1->CR & ADC_CR_ADDIS_Msk) != 0) { if((flib_GetTick() - startTick) > 10) return 0; } return 1; } u8 ADC_enable (void) { ADC1->CR |= ADC_CR_ADEN_Msk; // wait until ADC is ready for conversion u32 startTick = flib_GetTick(); while ((ADC1->ISR & ADC_ISR_ADRDY) == 0) { if((flib_GetTick() - startTick) > 10) return 0; } return 1; } #endif