Finished ADC methods

This commit is contained in:
Ea-r-th
2025-09-22 19:36:19 -07:00
parent 9550b1b61d
commit f980e62407
16 changed files with 235 additions and 19 deletions

View File

@@ -22,6 +22,13 @@ void SHAL_init();
//Universal structs and defines ---------------------------
enum class SHAL_Result{
OKAY,
ERROR
};
typedef bool (*condition_fn_t)(void);
#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))
//Currently configures systick to count down in microseconds
void systick_init();

View File

@@ -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

View File

@@ -9,12 +9,22 @@
#include "SHAL_ADC_TYPES.h"
enum class ADC_Key{
enum class ADC_Key : uint8_t{
S_ADC1,
NUM_ADC,
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

View File

@@ -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

View File

@@ -5,13 +5,41 @@
#ifndef 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 {
friend class ADCManager;
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:
SHAL_ADC() = default;
ADC_Key m_ADCKey = ADC_Key::INVALID;
};
@@ -23,9 +51,13 @@ class ADCManager{
public:
static SHAL_ADC& get(ADC_Key key);
ADCManager() = delete;
private:
inline static SHAL_ADC m_ADCs[static_cast<uint8_t>(ADC_Key::NUM_ADC)] = {};
};

View 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

View 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

View File

@@ -1,3 +1,103 @@
//
// 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;
}
}