Finished ADC methods
This commit is contained in:
@@ -22,6 +22,13 @@ void SHAL_init();
|
|||||||
|
|
||||||
//Universal structs and defines ---------------------------
|
//Universal structs and defines ---------------------------
|
||||||
|
|
||||||
|
enum class SHAL_Result{
|
||||||
|
OKAY,
|
||||||
|
ERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef bool (*condition_fn_t)(void);
|
typedef bool (*condition_fn_t)(void);
|
||||||
|
|
||||||
#define SHAL_WAIT_FOR_CONDITION_US(cond, timeout_us) \
|
#define SHAL_WAIT_FOR_CONDITION_US(cond, timeout_us) \
|
||||||
@@ -31,7 +38,6 @@ typedef bool (*condition_fn_t)(void);
|
|||||||
SHAL_wait_for_condition_ms([&](){ return (cond); }, (timeout_ms))
|
SHAL_wait_for_condition_ms([&](){ return (cond); }, (timeout_ms))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Currently configures systick to count down in microseconds
|
//Currently configures systick to count down in microseconds
|
||||||
void systick_init();
|
void systick_init();
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Luca on 9/21/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHMINGO_HAL_SHAL_ADC_REG_H
|
|
||||||
#define SHMINGO_HAL_SHAL_ADC_REG_H
|
|
||||||
|
|
||||||
#endif //SHMINGO_HAL_SHAL_ADC_REG_H
|
|
||||||
@@ -9,12 +9,22 @@
|
|||||||
#include "SHAL_ADC_TYPES.h"
|
#include "SHAL_ADC_TYPES.h"
|
||||||
|
|
||||||
|
|
||||||
enum class ADC_Key{
|
enum class ADC_Key : uint8_t{
|
||||||
|
|
||||||
S_ADC1,
|
S_ADC1,
|
||||||
NUM_ADC,
|
NUM_ADC,
|
||||||
INVALID
|
INVALID
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ADC_TypeDef* getADCRegister(ADC_Key key){
|
||||||
|
switch(key){
|
||||||
|
case ADC_Key::S_ADC1:
|
||||||
|
return ADC1;
|
||||||
|
|
||||||
|
case ADC_Key::NUM_ADC:
|
||||||
|
case ADC_Key::INVALID:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
#endif //SHMINGO_HAL_SHAL_ADC_REG_F072XB_H
|
#endif //SHMINGO_HAL_SHAL_ADC_REG_F072XB_H
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Luca on 9/21/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHMINGO_HAL_SHAL_ADC_TYPES_H
|
|
||||||
#define SHMINGO_HAL_SHAL_ADC_TYPES_H
|
|
||||||
|
|
||||||
#endif //SHMINGO_HAL_SHAL_ADC_TYPES_H
|
|
||||||
@@ -5,13 +5,41 @@
|
|||||||
#ifndef SHMINGO_HAL_SHAL_ADC_H
|
#ifndef SHMINGO_HAL_SHAL_ADC_H
|
||||||
#define SHMINGO_HAL_SHAL_ADC_H
|
#define SHMINGO_HAL_SHAL_ADC_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "SHAL_CORE.h"
|
||||||
|
#include "SHAL_ADC_REG.h"
|
||||||
|
|
||||||
class SHAL_ADC {
|
class SHAL_ADC {
|
||||||
|
|
||||||
|
friend class ADCManager;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
SHAL_Result init();
|
||||||
|
|
||||||
|
SHAL_Result calibrate();
|
||||||
|
|
||||||
|
/// Performs analog to digital conversion on a single channel, one time
|
||||||
|
/// \param channel Channel to be converted
|
||||||
|
/// \param time ADC_SampleTime - amount of clock cycles per conversion
|
||||||
|
/// \return resulting value
|
||||||
|
uint16_t singleConvertSingle(ADC_Channel channel, ADC_SampleTime time = ADC_SampleTime::C239);
|
||||||
|
|
||||||
|
/// Performs analog to digital conversion on multiple channels, one time
|
||||||
|
/// \param channels Pointer to an array of channels to convert
|
||||||
|
/// \param numChannels Number of channels to convert
|
||||||
|
/// \param result Pointer to store converted channel results in
|
||||||
|
/// \param time ADC_SampleTime - amount of clock cycles per conversion
|
||||||
|
void singleConvertSingle(ADC_Channel* channels, const int numChannels, uint16_t* result, ADC_SampleTime time = ADC_SampleTime::C239);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
SHAL_ADC() = default;
|
||||||
|
|
||||||
|
ADC_Key m_ADCKey = ADC_Key::INVALID;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -23,9 +51,13 @@ class ADCManager{
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
static SHAL_ADC& get(ADC_Key key);
|
||||||
|
|
||||||
|
ADCManager() = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
inline static SHAL_ADC m_ADCs[static_cast<uint8_t>(ADC_Key::NUM_ADC)] = {};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
44
SHAL/Include/Peripheral/ADC/SHAL_ADC_REG.h
Normal file
44
SHAL/Include/Peripheral/ADC/SHAL_ADC_REG.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
//
|
||||||
|
// Created by Luca on 9/21/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SHMINGO_HAL_SHAL_ADC_REG_H
|
||||||
|
#define SHMINGO_HAL_SHAL_ADC_REG_H
|
||||||
|
|
||||||
|
#if defined(STM32F030x6)
|
||||||
|
#include "stm32f030x6.h"
|
||||||
|
#elif defined(STM32F030x8)
|
||||||
|
#include "stm32f030x8.h"
|
||||||
|
#elif defined(STM32F031x6)
|
||||||
|
#include "stm32f031x6.h"
|
||||||
|
#elif defined(STM32F038xx)
|
||||||
|
#include "stm32f038xx.h"
|
||||||
|
#elif defined(STM32F042x6)
|
||||||
|
#include "stm32f042x6.h"
|
||||||
|
#elif defined(STM32F048xx)
|
||||||
|
#include "stm32f048xx.h"
|
||||||
|
#elif defined(STM32F051x8)
|
||||||
|
#include "stm32f051x8.h"
|
||||||
|
#elif defined(STM32F058xx)
|
||||||
|
#include "stm32f058xx.h"
|
||||||
|
#elif defined(STM32F070x6)
|
||||||
|
#include "stm32f070x6.h"
|
||||||
|
#elif defined(STM32F070xB)
|
||||||
|
#include "stm32f070xb.h"
|
||||||
|
#elif defined(STM32F071xB)
|
||||||
|
#include "stm32f071xb.h"
|
||||||
|
#elif defined(STM32F072xB)
|
||||||
|
#include "SHAL_ADC_REG_F072xB.h"
|
||||||
|
#elif defined(STM32F078xx)
|
||||||
|
#include "stm32f078xx.h"
|
||||||
|
#elif defined(STM32F091xC)
|
||||||
|
#include "stm32f091xc.h"
|
||||||
|
#elif defined(STM32F098xx)
|
||||||
|
#include "stm32f098xx.h"
|
||||||
|
#elif defined(STM32F030xC)
|
||||||
|
#include "stm32f030xc.h"
|
||||||
|
#else
|
||||||
|
#error "Please select first the target STM32F0xx device used in your application (in stm32f0xx.h file)"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //SHMINGO_HAL_SHAL_ADC_REG_H
|
||||||
40
SHAL/Include/Peripheral/ADC/SHAL_ADC_TYPES.h
Normal file
40
SHAL/Include/Peripheral/ADC/SHAL_ADC_TYPES.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
//
|
||||||
|
// Created by Luca on 9/21/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SHMINGO_HAL_SHAL_ADC_TYPES_H
|
||||||
|
#define SHMINGO_HAL_SHAL_ADC_TYPES_H
|
||||||
|
|
||||||
|
enum class ADC_Channel : uint32_t {
|
||||||
|
CH1 = ADC_CHSELR_CHSEL1,
|
||||||
|
CH2 = ADC_CHSELR_CHSEL2,
|
||||||
|
CH3 = ADC_CHSELR_CHSEL3,
|
||||||
|
CH4 = ADC_CHSELR_CHSEL4,
|
||||||
|
CH5 = ADC_CHSELR_CHSEL5,
|
||||||
|
CH6 = ADC_CHSELR_CHSEL6,
|
||||||
|
CH7 = ADC_CHSELR_CHSEL7,
|
||||||
|
CH8 = ADC_CHSELR_CHSEL8,
|
||||||
|
CH9 = ADC_CHSELR_CHSEL9,
|
||||||
|
CH10 = ADC_CHSELR_CHSEL10,
|
||||||
|
CH11 = ADC_CHSELR_CHSEL11,
|
||||||
|
CH12 = ADC_CHSELR_CHSEL12,
|
||||||
|
CH13 = ADC_CHSELR_CHSEL13,
|
||||||
|
CH14 = ADC_CHSELR_CHSEL14,
|
||||||
|
CH15 = ADC_CHSELR_CHSEL15,
|
||||||
|
CHTemp = ADC_CHSELR_CHSEL16,
|
||||||
|
CHRef = ADC_CHSELR_CHSEL17,
|
||||||
|
CHBat = ADC_CHSELR_CHSEL18
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ADC_SampleTime : uint32_t {
|
||||||
|
C2 = 0x00, //1.5 cycles per sample
|
||||||
|
C7 = 0x01, //7.5 cycles
|
||||||
|
C13 = 0x02, //13.5 cycles
|
||||||
|
C28 = 0x03, //28.5 cycles
|
||||||
|
C41 = 0x04, //41.5 cycles
|
||||||
|
C55 = 0x05, //55.5 cycles
|
||||||
|
C71 = 0x06, //71.5 cycles
|
||||||
|
C239 = 0x07 //239.5 cycles
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //SHMINGO_HAL_SHAL_ADC_TYPES_H
|
||||||
@@ -1,3 +1,103 @@
|
|||||||
//
|
//
|
||||||
// Created by Luca on 9/21/2025.
|
// Created by Luca on 9/21/2025.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include "SHAL_ADC.h"
|
||||||
|
|
||||||
|
//Can hard code registers on F0 because all F0 devices have only one ADC, and use only one clock
|
||||||
|
SHAL_Result SHAL_ADC::init() {
|
||||||
|
|
||||||
|
if(m_ADCKey == ADC_Key::INVALID || m_ADCKey == ADC_Key::NUM_ADC){
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ADC_TypeDef* ADC_reg = getADCRegister(m_ADCKey);
|
||||||
|
|
||||||
|
|
||||||
|
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; //Enable clock
|
||||||
|
RCC->CR2 |= RCC_CR2_HSI14ON; //Start peripheral oscillator
|
||||||
|
|
||||||
|
if(!SHAL_WAIT_FOR_CONDITION_US(((RCC->CR2 & RCC_CR2_HSI14RDY) != 0),50)){ //Wait for clock OKAY
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ADC_reg->ISR & ADC_ISR_ADRDY) != 0){ //Set ADRDY to 0
|
||||||
|
ADC_reg->ISR |= ADC_ISR_ADRDY;
|
||||||
|
}
|
||||||
|
|
||||||
|
ADC_reg->CR |= ADC_CR_ADEN; //Enable
|
||||||
|
|
||||||
|
if(!SHAL_WAIT_FOR_CONDITION_US(((ADC_reg->ISR & ADC_ISR_ADRDY) != 0),50)){ //Wait for disable
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(calibrate() != SHAL_Result::OKAY){ //Calibrate
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SHAL_Result::OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAL_Result SHAL_ADC::calibrate() {
|
||||||
|
|
||||||
|
if(m_ADCKey == ADC_Key::INVALID || m_ADCKey == ADC_Key::NUM_ADC){
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ADC_TypeDef* ADC_reg = getADCRegister(m_ADCKey);
|
||||||
|
|
||||||
|
if((ADC_reg->CR & ADC_CR_ADEN) != 0){ //Clear ADEN (enable)
|
||||||
|
ADC_reg->CR |= ADC_CR_ADDIS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!SHAL_WAIT_FOR_CONDITION_US(((ADC_reg->CR & ADC_CR_ADEN) == 0),50)){ //Wait for disable
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ADC_reg->CFGR1 &= ~ADC_CFGR1_DMAEN; //Clear DMAEN
|
||||||
|
ADC_reg->CR |= ADC_CR_ADCAL; //Launch calibration by setting ADCAL
|
||||||
|
|
||||||
|
if(!SHAL_WAIT_FOR_CONDITION_US(((ADC_reg->CR & ADC_CR_ADCAL) == 0),50)){ //Wait for calibration
|
||||||
|
return SHAL_Result::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SHAL_Result::OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t SHAL_ADC::singleConvertSingle(ADC_Channel channel, ADC_SampleTime time) {
|
||||||
|
|
||||||
|
ADC_TypeDef* ADC_reg = getADCRegister(m_ADCKey);
|
||||||
|
|
||||||
|
ADC->CCR |= ADC_CCR_VREFEN | ADC_CCR_TSEN; //Enable VREFINT and Temp sensor in global ADC struct
|
||||||
|
|
||||||
|
ADC_reg->CHSELR = static_cast<uint32_t>(channel); //Enable channel for conversion
|
||||||
|
ADC_reg->SMPR |= static_cast<uint32_t>(time); //Set sampling time
|
||||||
|
|
||||||
|
if(!SHAL_WAIT_FOR_CONDITION_US(((ADC_reg->ISR & ADC_ISR_EOC) != 0),500)){ //Wait for conversion
|
||||||
|
return 0; //Failed
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t result = ADC_reg->DR;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHAL_ADC::singleConvertSingle(ADC_Channel* channels, const int numChannels, uint16_t* result, ADC_SampleTime time) {
|
||||||
|
ADC_TypeDef* ADC_reg = getADCRegister(m_ADCKey);
|
||||||
|
|
||||||
|
ADC->CCR |= ADC_CCR_VREFEN | ADC_CCR_TSEN; //Enable VREFINT and Temp sensor in global ADC struct
|
||||||
|
|
||||||
|
for(int i = 0; i < numChannels; i++){ //Enable all channels
|
||||||
|
ADC_reg->CHSELR = static_cast<uint32_t>(channels[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ADC_reg->SMPR |= static_cast<uint32_t>(time); //Set sampling time
|
||||||
|
|
||||||
|
|
||||||
|
for(int i = 0; i < numChannels; i++){
|
||||||
|
if(!SHAL_WAIT_FOR_CONDITION_US(((ADC_reg->ISR & ADC_ISR_EOC) != 0),500)){ //Wait for conversion
|
||||||
|
continue; //Failed
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = ADC_reg->DR;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user