321 lines
6.9 KiB
C
321 lines
6.9 KiB
C
/*
|
|
* @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
|
|
|
|
|