9 Commits

Author SHA1 Message Date
Ea-r-th
59e1003262 Made getADCRegister constexpr 2025-09-22 22:36:06 -07:00
Ea-r-th
3480cba21c Fixes 2025-09-22 22:17:59 -07:00
Ea-r-th
03dcfd6bbe Added analogRead to GPIO 2025-09-22 22:12:57 -07:00
Ea-r-th
8214617e3a ADC basic functionality finished 2025-09-22 19:47:15 -07:00
Ea-r-th
f980e62407 Finished ADC methods 2025-09-22 19:36:19 -07:00
Ea-r-th
9550b1b61d Set up ADC files 2025-09-21 14:01:47 -07:00
Ea-r-th
5b66b044b7 Merge branch 'main' of github.com:lucalizaranzu/Shmingo_HAL 2025-09-18 01:23:12 -07:00
Ea-r-th
05465086c4 Final I2C commit 2025-09-18 01:22:09 -07:00
Luca Lizaranzu
cfda94afc1 Merge pull request #1 from lucalizaranzu/I2C
I2C
2025-09-18 01:21:40 -07:00
20 changed files with 411 additions and 10 deletions

View File

@@ -38,6 +38,8 @@ set(PROJECT_INCLUDE_DIRECTORIES
SHAL/Include/Peripheral/UART/Reg
SHAL/Include/Peripheral/I2C
SHAL/Include/Peripheral/I2C/Reg
SHAL/Include/Peripheral/ADC
SHAL/Include/Peripheral/ADC/Reg
SHAL/Include/Peripheral/EXT/
${CMAKE_CURRENT_SOURCE_DIR}/SHAL/Include
)

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

@@ -0,0 +1,31 @@
//
// Created by Luca on 9/21/2025.
//
#ifndef SHMINGO_HAL_SHAL_ADC_REG_F072XB_H
#define SHMINGO_HAL_SHAL_ADC_REG_F072XB_H
#include "SHAL_CORE.h"
#include "SHAL_ADC_TYPES.h"
#define SHAL_ADC1 SHAL_ADC(1)
enum class ADC_Key : uint8_t{
S_ADC1,
NUM_ADC,
INVALID
};
constexpr 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

@@ -0,0 +1,66 @@
//
// Created by Luca on 9/21/2025.
//
#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 multiConvertSingle(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;
};
#define SHAL_ADC(x) ADCManager::getByIndex(x-1)
class ADCManager{
public:
static SHAL_ADC& get(ADC_Key key);
static SHAL_ADC& getByIndex(int index);
ADCManager() = delete;
private:
inline static SHAL_ADC m_ADCs[static_cast<uint8_t>(ADC_Key::NUM_ADC)] = {};
};
#endif //SHMINGO_HAL_SHAL_ADC_H

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,41 @@
//
// 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 {
CH0 = ADC_CHSELR_CHSEL0,
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

@@ -270,6 +270,79 @@ constexpr uint32_t getGPIOPortNumber(const GPIO_Key g){
__builtin_unreachable();
}
constexpr SHAL_GPIO_Port_Info getGPIOPortInfo(GPIO_Key key){
switch(key){
case GPIO_Key::A0:
case GPIO_Key::B0:
case GPIO_Key::C0:
return {0,ADC_Channel::CH0};
case GPIO_Key::A1:
case GPIO_Key::B1:
case GPIO_Key::C1:
return {1,ADC_Channel::CH1};
case GPIO_Key::A2:
case GPIO_Key::B2:
case GPIO_Key::C2:
return {2,ADC_Channel::CH2};
case GPIO_Key::A3:
case GPIO_Key::B3:
case GPIO_Key::C3:
return {3,ADC_Channel::CH3};
case GPIO_Key::A4:
case GPIO_Key::B4:
case GPIO_Key::C4:
return {4,ADC_Channel::CH4};
case GPIO_Key::A5:
case GPIO_Key::B5:
case GPIO_Key::C5:
return {5,ADC_Channel::CH5};
case GPIO_Key::A6:
case GPIO_Key::B6:
case GPIO_Key::C6:
return {6,ADC_Channel::CH6};
case GPIO_Key::A7:
case GPIO_Key::B7:
case GPIO_Key::C7:
return {7,ADC_Channel::CH7};
case GPIO_Key::A8:
case GPIO_Key::B8:
case GPIO_Key::C8:
return {8,ADC_Channel::CH8};
case GPIO_Key::A9:
case GPIO_Key::B9:
case GPIO_Key::C9:
return {9,ADC_Channel::CH9};
case GPIO_Key::A10:
case GPIO_Key::B10:
case GPIO_Key::C10:
return {10,ADC_Channel::CH10};
case GPIO_Key::A11:
case GPIO_Key::B11:
case GPIO_Key::C11:
return {11,ADC_Channel::CH11};
case GPIO_Key::A12:
case GPIO_Key::B12:
case GPIO_Key::C12:
return {12,ADC_Channel::CH12};
case GPIO_Key::A13:
case GPIO_Key::B13:
case GPIO_Key::C13:
return {13,ADC_Channel::CH13};
case GPIO_Key::A14:
case GPIO_Key::B14:
case GPIO_Key::C14:
return {14,ADC_Channel::CH14};
case GPIO_Key::A15:
case GPIO_Key::B15:
case GPIO_Key::C15:
return {15,ADC_Channel::CH15};
case GPIO_Key::NUM_GPIO:
case GPIO_Key::INVALID:
return {0,ADC_Channel::CH0};
}
__builtin_unreachable();
}
#endif //SHMINGO_HAL_SHAL_GPIO_REG_F072XB_H

View File

@@ -10,9 +10,7 @@
#include <cassert>
#include "SHAL_EXTI_CALLBACK.h"
#include "SHAL_ADC.h"
//Abstraction of SHAL_GPIO registers
@@ -26,6 +24,11 @@ public:
void setHigh();
void setLow();
/// Uses the ADC to read an analog voltage value
/// \param sampleTime The amount of clock cycles to use for the ADC
/// \return ADC result
uint16_t analogRead(ADC_SampleTime sampleTime = ADC_SampleTime::C239);
void setPinMode(PinMode mode) volatile;
void setAlternateFunction(GPIO_Alternate_Function AF) volatile;
@@ -39,6 +42,8 @@ public:
void useAsExternalInterrupt(TriggerMode mode, EXTICallback callback);
private:
friend class GPIOManager;
@@ -60,7 +65,7 @@ private:
#define GET_GPIO(key) GPIOManager::get(key)
#define GPIO_A
#define SET_ANALOGREAD_ADC(x) GPIOManager::setGPIOADC(x)
//Manages instances of SHAL_GPIO objects
class GPIOManager{
@@ -69,6 +74,9 @@ public:
static SHAL_GPIO& get(GPIO_Key);
static SHAL_ADC getGPIOADC(){ return m_GPIO_ADC;}
static void setGPIOADC(SHAL_ADC adc){m_GPIO_ADC = adc;}
GPIOManager() = delete;
@@ -76,6 +84,8 @@ private:
inline static SHAL_GPIO m_gpios[AVAILABLE_PORTS][PINS_PER_PORT] = {{}};
inline static SHAL_ADC m_GPIO_ADC = SHAL_ADC(1);
};

View File

@@ -6,6 +6,7 @@
#define SHAL_GPIO_TYPES_H
#include "SHAL_CORE.h"
#include "SHAL_ADC.h"
struct SHAL_EXTIO_Register{
volatile uint32_t* EXT_ICR;
@@ -23,6 +24,11 @@ struct SHAL_Peripheral_Register {
unsigned long offset;
};
struct SHAL_GPIO_Port_Info{
uint8_t number;
ADC_Channel ADCChannel;
};
enum class PinMode : uint8_t{
INPUT_MODE = 0x00,
OUTPUT_MODE = 0x01,
@@ -67,5 +73,4 @@ enum class TriggerMode : uint8_t{
};
#endif //SHMINGO_HAL_SHAL_GPIO_TYPES_H

View File

@@ -12,5 +12,8 @@
#include "SHAL_GPIO.h"
#include "SHAL_UART.h"
#include "SHAL_I2C.h"
#include "SHAL_ADC.h"
#endif

View File

@@ -0,0 +1,115 @@
//
// 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::multiConvertSingle(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;
}
}
SHAL_ADC &ADCManager::get(ADC_Key key) {
return m_ADCs[static_cast<uint8_t>(key)];
}
SHAL_ADC& ADCManager::getByIndex(int index) {
if(index < static_cast<int>(ADC_Key::NUM_ADC)){
return m_ADCs[index];
}
return m_ADCs[0];
}

View File

@@ -107,6 +107,13 @@ void SHAL_GPIO::useAsExternalInterrupt(TriggerMode mode, EXTICallback callback)
__enable_irq(); //Enable IRQ just in case
}
uint16_t SHAL_GPIO::analogRead(ADC_SampleTime sampleTime) {
ADC_Channel channel = getGPIOPortInfo(m_GPIO_KEY).ADCChannel;
return GPIOManager::getGPIOADC().singleConvertSingle(channel,sampleTime);
}
SHAL_GPIO& GPIOManager::get(GPIO_Key key) {

View File

@@ -1,7 +1,7 @@
#include "SHAL.h"
#include "stm32f0xx.h"
#include <stdlib.h>
#include <cstdlib>
void c3Interrupt(){
SHAL_UART2.sendString("Begin\r\n");
@@ -66,8 +66,6 @@ int main() {
PIN(A4).setPinMode(PinMode::OUTPUT_MODE);
PIN(A5).setPinMode(PinMode::OUTPUT_MODE);
SHAL_delay_ms(3000); //Wait 100 ms from datasheet
uint8_t cmd = 0x71;