STM32F042-Drivers-Pub/adc.c

321 lines
6.9 KiB
C
Raw Normal View History

2024-05-02 10:18:04 +00:00
/*
* @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<<channel);
}
void ADC_removeChannelFromScanList (u8 channel) {
ADC1->CHSELR &= ~(1<<channel);
}
// configure DMA and start conversion
void ADC_startConversionDMA (u8 channels, u16 * ADC_array) {
DMA1_Channel1->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<<channel);
}
void ADC_removeChannelFromScanList (u8 channel) {
ADC1->CHSELR &= ~(1<<channel);
}
// configure DMA and start conversion
void ADC_startConversionDMA (u8 channels, u16 * ADC_array) {
DMA1_Channel1->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