Finish project

This commit is contained in:
Ea-r-th
2025-11-11 19:51:21 -08:00
parent b50e7c25f6
commit ec0fea608b
7 changed files with 152 additions and 110 deletions

View File

@@ -83,14 +83,14 @@ static inline SHAL_ADC_Control_Reg getADCControlReg(ADC_Key key) {
static inline SHAL_ADC_Config_Reg getADCConfigReg(ADC_Key key) { static inline SHAL_ADC_Config_Reg getADCConfigReg(ADC_Key key) {
SHAL_ADC_Config_Reg res = {nullptr, ADC_CFGR_CONT, ADC_CFGR_RES_Pos, ADC_CFGR_ALIGN_Pos}; SHAL_ADC_Config_Reg res = {nullptr, ADC_CFGR_CONT, ADC_CFGR_RES_Pos, ADC_CFGR_ALIGN_Pos, ADC_CFGR_CONT_Msk};
res.reg = &(ADC_TABLE[static_cast<uint8_t>(key)]->CFGR); res.reg = &(ADC_TABLE[static_cast<uint8_t>(key)]->CFGR);
return res; return res;
} }
static inline SHAL_ADC_ISR_Reg getADCISRReg(ADC_Key key){ static inline SHAL_ADC_ISR_Reg getADCISRReg(ADC_Key key){
SHAL_ADC_ISR_Reg res = {nullptr, ADC_ISR_EOC, ADC_ISR_EOS, ADC_ISR_ADRDY}; SHAL_ADC_ISR_Reg res = {nullptr, ADC_ISR_EOC, ADC_ISR_EOS, ADC_ISR_ADRDY, ADC_ISR_OVR};
res.reg = &(ADC_TABLE[static_cast<uint8_t>(key)]->ISR); res.reg = &(ADC_TABLE[static_cast<uint8_t>(key)]->ISR);
return res; return res;

View File

@@ -39,6 +39,7 @@ struct SHAL_ADC_Config_Reg {
uint32_t resolution_offset; uint32_t resolution_offset;
uint32_t alignment_offset; uint32_t alignment_offset;
uint32_t continuous_mode_mask;
}; };
//Register for all ADC data //Register for all ADC data
@@ -53,6 +54,7 @@ struct SHAL_ADC_ISR_Reg {
uint32_t end_of_conversion_mask; uint32_t end_of_conversion_mask;
uint32_t end_of_sequence_mask; uint32_t end_of_sequence_mask;
uint32_t ready_mask; uint32_t ready_mask;
uint32_t overrun_mask;
}; };
//Register controlling the clock source for the ADC //Register controlling the clock source for the ADC

View File

@@ -17,15 +17,15 @@
//Build enum map of available SHAL_GPIO pins //Build enum map of available SHAL_GPIO pins
enum class GPIO_Key : uint8_t { enum class GPIO_Key : uint8_t {
A0, A0 = 0,
A1, A1 = 1,
A2, A2 = 2,
A3, A3 = 3,
A4, A4 = 4,
A5, A5 = 5,
A6, A6 = 6,
A7, A7 = 7,
A8, A8 = 8,
A9, A9,
A10, A10,
A11, A11,
@@ -124,7 +124,7 @@ constexpr uint32_t getGPIOPortNumber(const GPIO_Key g){
static inline SHAL_GPIO_Mode_Register getGPIOModeRegister(const GPIO_Key key){ static inline SHAL_GPIO_Mode_Register getGPIOModeRegister(const GPIO_Key key){
volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->MODER; volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->MODER;
uint32_t offset = 2 * static_cast<uint8_t>(key) % 16; uint32_t offset = 2 * (static_cast<uint8_t>(key) % 16);
return {reg,offset}; return {reg,offset};
} }
@@ -158,7 +158,7 @@ static inline SHAL_GPIO_Output_Type_Register getGPIOOutputTypeRegister(const GPI
static inline SHAL_GPIO_Output_Data_Register getGPIOOutputDataRegister(const GPIO_Key key){ static inline SHAL_GPIO_Output_Data_Register getGPIOOutputDataRegister(const GPIO_Key key){
volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->ODR; volatile uint32_t* reg = &GPIO_TABLE[static_cast<uint8_t>(key) / 16]->ODR;
uint32_t offset = static_cast<uint8_t>(key) % 16; uint32_t offset = (static_cast<uint8_t>(key) % 16);
return {reg,offset}; return {reg,offset};
} }

View File

@@ -21,7 +21,7 @@ public:
/// Initializes a timer /// Initializes a timer
/// \param prescaler The amount of times the base clock has to cycle before the timer adds one to the count /// \param prescaler The amount of times the base clock has to cycle before the timer adds one to the count
/// \param autoReload The number of timer counts before the count is reset and IRQ is called /// \param autoReload The number of timer counts before the count is reset and IRQ is called
void init(uint32_t prescaler, uint32_t autoReload); void init(uint16_t prescaler, uint16_t autoReload);
//Starts the counter //Starts the counter
void start(); void start();

View File

@@ -72,29 +72,44 @@ SHAL_Result SHAL_ADC::calibrate() {
} }
uint16_t SHAL_ADC::singleConvertSingle(SHAL_ADC_Channel channel, SHAL_ADC_SampleTime time) { uint16_t SHAL_ADC::singleConvertSingle(SHAL_ADC_Channel channel, SHAL_ADC_SampleTime time) {
auto data_reg = getADCDataReg(m_ADCKey);
auto ISR_reg = getADCISRReg(m_ADCKey);
auto config_reg = getADCConfigReg(m_ADCKey);
auto data_reg = getADCDataReg(m_ADCKey); //Where our output will be stored SHAL_clear_bitmask(config_reg.reg, config_reg.continuous_mode_mask);
auto sampleTimeReg = getADCChannelSamplingTimeRegister(m_ADCKey,channel); auto sampleTimeReg = getADCChannelSamplingTimeRegister(m_ADCKey, channel);
SHAL_set_bits(sampleTimeReg.reg, 3, static_cast<uint8_t>(time), sampleTimeReg.channel_offset);
SHAL_set_bits(sampleTimeReg.reg,3,static_cast<uint8_t>(time),sampleTimeReg.channel_offset); //Set sample time register TODO un-hardcode bit width? addADCChannelToSequence(channel, 0);
if(setADCSequenceAmount(1) == SHAL_Result::ERROR) { return 0; }
addADCChannelToSequence(channel,0); //Use index 0 to convert channel if(enable() != SHAL_Result::OKAY) {
if(setADCSequenceAmount(1) == SHAL_Result::ERROR){return 0;} //Since we're using single convert, convert 1 channel
if(enable() != SHAL_Result::OKAY){
return 0; return 0;
} }
startConversion(); //Start ADC conversion // CRITICAL: Clear ALL relevant flags before starting
SHAL_apply_bitmask(ISR_reg.reg, ISR_reg.end_of_sequence_mask);
auto ISR_reg = getADCISRReg(m_ADCKey); SHAL_apply_bitmask(ISR_reg.reg, ISR_reg.end_of_conversion_mask);
if(ISR_reg.overrun_mask) {
if(!SHAL_WAIT_FOR_CONDITION_US(((*ISR_reg.reg & ISR_reg.end_of_sequence_mask) != 0),500)){ //Wait for conversion SHAL_apply_bitmask(ISR_reg.reg, ISR_reg.overrun_mask);
return 0; //Failed
} }
return *data_reg.reg; volatile uint16_t dummy = *data_reg.reg;
(void)dummy;
startConversion();
if(!SHAL_WAIT_FOR_CONDITION_US(((*ISR_reg.reg & ISR_reg.end_of_conversion_mask) != 0), 2000)) {
return 0;
}
uint16_t result = *data_reg.reg;
SHAL_apply_bitmask(ISR_reg.reg, ISR_reg.end_of_conversion_mask);
SHAL_apply_bitmask(ISR_reg.reg, ISR_reg.end_of_sequence_mask);
return result;
} }
SHAL_Result SHAL_ADC::multiConvertSingle(SHAL_ADC_Channel* channels, const int numChannels, uint16_t* result, SHAL_ADC_SampleTime time) { SHAL_Result SHAL_ADC::multiConvertSingle(SHAL_ADC_Channel* channels, const int numChannels, uint16_t* result, SHAL_ADC_SampleTime time) {
@@ -259,27 +274,23 @@ SHAL_Result SHAL_ADC::setADCSequenceAmount(uint32_t amount) {
} }
SHAL_Result SHAL_ADC::addADCChannelToSequence(SHAL_ADC_Channel channel, uint32_t index) { SHAL_Result SHAL_ADC::addADCChannelToSequence(SHAL_ADC_Channel channel, uint32_t index) {
if(!isValid()) { return SHAL_Result::ERROR; }
if(!isValid()){return SHAL_Result::ERROR;}
auto sequenceRegisters = getADCSequenceRegisters(m_ADCKey); auto sequenceRegisters = getADCSequenceRegisters(m_ADCKey);
auto channelNum = static_cast<uint8_t>(channel); auto channelNum = static_cast<uint8_t>(channel);
uint32_t bitSection = (index + 1) % 5; //Need a new variable since SQR1 has its data bits shifted up by one section to make room for the L section uint32_t bitSection = (index + 1) % 5;
uint32_t sequenceRegNumber = (index + 1) / 5; uint32_t sequenceRegNumber = (index + 1) / 5;
volatile uint32_t* sequenceReg = sequenceRegisters.regs[sequenceRegNumber]; volatile uint32_t* sequenceReg = sequenceRegisters.regs[sequenceRegNumber];
uint32_t bitSectionOffset = sequenceRegisters.offsets[bitSection]; uint32_t bitSectionOffset = sequenceRegisters.offsets[bitSection];
if(sequenceRegNumber != 0){ // Clear only the specific 5 bits we're setting, not the entire register
*sequenceReg = 0; //Clear previous conversions uint32_t clearMask = ~(0x1F << bitSectionOffset);
} *sequenceReg &= clearMask;
else{
*sequenceReg &= 0x0000000F;
}
SHAL_set_bits(sequenceReg,5,channelNum,bitSectionOffset); // Set the new channel number
*sequenceReg |= (channelNum << bitSectionOffset);
return SHAL_Result::OKAY; return SHAL_Result::OKAY;
} }

View File

@@ -50,7 +50,7 @@ void Timer::enableInterrupt() {
NVIC_EnableIRQ(getTimerIRQn(m_key)); //Enable the IRQn in the NVIC NVIC_EnableIRQ(getTimerIRQn(m_key)); //Enable the IRQn in the NVIC
} }
void Timer::init(uint32_t prescaler, uint32_t autoReload) { void Timer::init(uint16_t prescaler, uint16_t autoReload) {
SHAL_TIM_RCC_Register rcc = getTimerRCC(m_key); SHAL_TIM_RCC_Register rcc = getTimerRCC(m_key);
SHAL_apply_bitmask(rcc.reg,rcc.enable_mask); SHAL_apply_bitmask(rcc.reg,rcc.enable_mask);

View File

@@ -2,25 +2,28 @@
#include "SHAL.h" #include "SHAL.h"
#define NUM_CHANNELS 8 #define NUM_CHANNELS 6
// Physical order on right-side header: A0, A1, A3, A4, A5, A6, A7
SHAL_ADC_Channel channels[NUM_CHANNELS] = { SHAL_ADC_Channel channels[NUM_CHANNELS] = {
SHAL_ADC_Channel::CH5, SHAL_ADC_Channel::CH5,
SHAL_ADC_Channel::CH6, SHAL_ADC_Channel::CH6,
SHAL_ADC_Channel::CH8, SHAL_ADC_Channel::CH8,
SHAL_ADC_Channel::CH9, SHAL_ADC_Channel::CH9,
SHAL_ADC_Channel::CH10, SHAL_ADC_Channel::CH10,
SHAL_ADC_Channel::CH11,
SHAL_ADC_Channel::CH12, SHAL_ADC_Channel::CH12,
SHAL_ADC_Channel::CH7
}; };
uint16_t vals[NUM_CHANNELS] = {0,0,0,0,0,0,0,0}; bool isDeviceOn = false;
bool shouldToggleDeviceState = true;
bool shouldCheckSensorThresholds = true;
uint16_t vals[NUM_CHANNELS] = {0,0,0,0,0,0};
uint8_t currentSensor = 0; uint8_t currentSensor = 0;
bool isAlarmBeeping = false; bool isAlarmBeeping = false;
uint16_t sensorThresholds[NUM_CHANNELS]; uint16_t sensorThresholds[NUM_CHANNELS] = {0,0,0,0,0,0};
int buzzer_beepCount = 0; int buzzer_beepCount = 0;
bool isBeepingForCalibration = false; bool isBeepingForCalibration = false;
@@ -39,7 +42,9 @@ void getSensorData(){
if(currentSensor == (NUM_CHANNELS - 1) && currentCycle == cyclesPerPrint - 1){ if(currentSensor == (NUM_CHANNELS - 1) && currentCycle == cyclesPerPrint - 1){
char buff[125]; char buff[125];
sprintf(buff, "5:%d,6:%d,8:%d,9:%d,10:%d,11:%d,12:%d,7:%d\r\n", vals[0],vals[1],vals[2],vals[3],vals[4],vals[5],vals[6],vals[7]); // Print in the same order as the channels[] array (physical order)
sprintf(buff, "A0:%u,A1:%u,A3:%u,A4:%u,A5:%u,A6:%u\r\n",
vals[0], vals[1], vals[2], vals[3], vals[4], vals[5]);
SHAL_UART2.sendString(buff); SHAL_UART2.sendString(buff);
} }
@@ -49,7 +54,9 @@ void getSensorData(){
} }
void startBeeping(){ void startBeeping(){
SHAL_TIM6.init(4000000,400); //PWM switcher - standard error beeping rate
SHAL_TIM6.setPrescaler(4000);
SHAL_TIM6.setARR(200);
SHAL_TIM6.start(); SHAL_TIM6.start();
} }
@@ -63,60 +70,63 @@ void stopBeeping(){
void checkSensorThresholds(){ void checkSensorThresholds(){
//bool sensorsRequirementsTemp = areSensorRequirementsMetCurrent; TODO uncomment all of this bool localFlag = true;
/*
for(int i = 0; i < NUM_CHANNELS; i++){ for(int i = 0; i < NUM_CHANNELS; i++){
if(vals[i] < sensorThresholds[i]){ if(vals[i] < sensorThresholds[i]){
areSensorRequirementsMetCurrent = false; //All sensors must be valid areSensorRequirementsMetCurrent = false; //Conditions not met
localFlag = false;
if(sensorsRequirementsTemp){ //Requirements were met before and aren't now, so start beeping timer
SHAL_TIM15.start();
PIN(B5).setHigh();
}
break; break;
} }
} }
if(localFlag){
areSensorRequirementsMetCurrent = true;
}
if(areSensorRequirementsMetCurrent){ if(areSensorRequirementsMetCurrent){
if(!areSensorRequirementsMetPrevious){
SHAL_TIM1.stop();
SHAL_TIM6.stop();
SHAL_TIM15.stop(); SHAL_TIM15.stop();
PIN(A9).setLow();
stopBeeping(); stopBeeping();
} }
*/
//Copied from loop TODO remove this once real functionality is implemented
if(!areSensorRequirementsMetCurrent){
if(areSensorRequirementsMetPrevious) {
PIN(B5).setHigh();
SHAL_TIM15.start();
} }
}
//--------------------------------------------------------------------------------
else{ else{
PIN(B5).setLow(); if(areSensorRequirementsMetPrevious){
SHAL_TIM15.start();
if(!areSensorRequirementsMetPrevious) { //Transition from not met -> met PIN(A9).setHigh();
SHAL_TIM15.stop();
stopBeeping();
} }
} }
areSensorRequirementsMetPrevious = areSensorRequirementsMetCurrent;
} }
void calibrateThresholds(){ void calibrateThresholds(){
for(int i = 0; i < 6; i++){ // Read every channel once and set threshold to 80% of reading
uint16_t sensorVal = SHAL_ADC1.singleConvertSingle(channels[currentSensor]); for(int i = 0; i < NUM_CHANNELS; i++){
sensorThresholds[i] = (sensorVal / 5) * 4; uint16_t sensorVal = vals[i];
if(sensorVal < 50){
sensorVal = 0;
} }
else{
sensorVal = sensorVal - 50;
}
sensorThresholds[i] = sensorVal;
}
char buff[125];
// Print in the same order as the channels[] array (physical order)
sprintf(buff, "Thresholds calibrated to: A0:%u,A1:%u,A3:%u,A4:%u,A5:%u,A6:%u\r\n",
sensorThresholds[0], sensorThresholds[1], sensorThresholds[2], sensorThresholds[3], sensorThresholds[4], sensorThresholds[5]);
SHAL_UART2.sendString(buff);
} }
void PWMToggle(){ void PWMToggle(){
//Flash light //Flash light
PIN(B5).toggle(); PIN(A9).toggle();
SHAL_TIM15.stop(); //Stop timer for allowed time off sensors SHAL_TIM15.stop(); //Stop timer for allowed time off sensors
@@ -125,7 +135,9 @@ void PWMToggle(){
buzzer_beepCount = 0; buzzer_beepCount = 0;
SHAL_TIM6.stop(); //Reset timer 6 SHAL_TIM6.stop(); //Reset timer 6
SHAL_TIM1.stop(); //Stop buzzer SHAL_TIM1.stop(); //Stop buzzer
SHAL_TIM6.init(4000000,400);
SHAL_TIM6.setPrescaler(4000);
SHAL_TIM6.setARR(400);
} }
if(!isAlarmBeeping){ if(!isAlarmBeeping){
@@ -140,7 +152,7 @@ void PWMToggle(){
void buttonHoldCallback(){ void buttonHoldCallback(){
PIN(B5).toggle(); shouldCheckSensorThresholds = false; //Dont check sensor thresholds yet, ensure that calibration beep happens
SHAL_TIM7.stop(); //Stop this timer SHAL_TIM7.stop(); //Stop this timer
@@ -149,87 +161,104 @@ void buttonHoldCallback(){
buzzer_beepCount = 0; buzzer_beepCount = 0;
isBeepingForCalibration = true; isBeepingForCalibration = true;
SHAL_TIM6.init(4000000,80); SHAL_TIM6.init(4000,50);
SHAL_TIM6.start(); SHAL_TIM6.start();
calibrateThresholds(); calibrateThresholds();
SHAL_TIM1.start(); SHAL_TIM1.start();
SHAL_TIM2.start(); //Restart value checks SHAL_TIM2.start(); //Restart value checks
shouldToggleDeviceState = false;
shouldCheckSensorThresholds = true;
} }
int main() { int main() {
SHAL_init(); SHAL_init();
SHAL_UART2.init(UART_Pair_Key::Tx2A2_Rx2A3); //SHAL_UART2.init(UART_Pair_Key::Tx2A2_Rx2A3);
SHAL_UART2.begin(115200); //SHAL_UART2.begin(115200);
PIN(A0).setPinMode(PinMode::ANALOG_MODE); PIN(A0).setPinMode(PinMode::ANALOG_MODE);
PIN(A1).setPinMode(PinMode::ANALOG_MODE); PIN(A1).setPinMode(PinMode::ANALOG_MODE);
//PIN(A2).setPinMode(PinMode::ANALOG_MODE); PIN(A3).setPinMode(PinMode::ANALOG_MODE);
//PIN(A3).setPinMode(PinMode::ANALOG_MODE);
PIN(A4).setPinMode(PinMode::ANALOG_MODE); PIN(A4).setPinMode(PinMode::ANALOG_MODE);
PIN(A5).setPinMode(PinMode::ANALOG_MODE); PIN(A5).setPinMode(PinMode::ANALOG_MODE);
PIN(A6).setPinMode(PinMode::ANALOG_MODE); PIN(A6).setPinMode(PinMode::ANALOG_MODE);
PIN(A7).setPinMode(PinMode::ANALOG_MODE); PIN(A7).setPinMode(PinMode::ANALOG_MODE);
PIN(B5).setPinMode(PinMode::OUTPUT_MODE);
PIN(B6).setPinMode(PinMode::INPUT_MODE); PIN(B6).setPinMode(PinMode::INPUT_MODE);
PIN(A9).setPinMode(PinMode::OUTPUT_MODE);
PIN(B0).setAlternateFunction(GPIO_Alternate_Function_Mapping::B0_TIM1CH2N);
SHAL_TIM2.init(4000000,400); PIN(A8).setPinMode(PinMode::OUTPUT_MODE);
PIN(A8).setInternalResistor(InternalResistorType::NO_PULL);
SHAL_TIM2.init(4000,200);
SHAL_TIM2.setCallbackFunc(getSensorData); SHAL_TIM2.setCallbackFunc(getSensorData);
SHAL_TIM2.enableInterrupt(); SHAL_TIM2.enableInterrupt();
SHAL_TIM2.start(); SHAL_TIM2.start();
PIN(B0).setAlternateFunction(GPIO_Alternate_Function_Mapping::B0_TIM1CH2N);
SHAL_TIM1.init(0,2400); //PWM signal SHAL_TIM1.init(0,2400); //PWM signal
SHAL_TIM1.setPWMMode(SHAL_Timer_Channel::CH2,SHAL_TIM_Output_Compare_Mode::PWMMode1,SHAL_Timer_Channel_Main_Output_Mode::Polarity_Normal,SHAL_Timer_Channel_Complimentary_Output_Mode::Polarity_Reversed); SHAL_TIM1.setPWMMode(SHAL_Timer_Channel::CH2,SHAL_TIM_Output_Compare_Mode::PWMMode1,SHAL_Timer_Channel_Main_Output_Mode::Polarity_Normal,SHAL_Timer_Channel_Complimentary_Output_Mode::Polarity_Reversed);
SHAL_TIM1.setPWMDutyCycle(900); SHAL_TIM1.setPWMDutyCycle(900);
SHAL_TIM6.init(4000000,400); //PWM switcher SHAL_TIM6.init(4000,500); //PWM switcher
SHAL_TIM6.setCallbackFunc(PWMToggle); SHAL_TIM6.setCallbackFunc(PWMToggle);
SHAL_TIM6.enableInterrupt(); SHAL_TIM6.enableInterrupt();
SHAL_TIM7.init(4000000,4500); SHAL_TIM7.init(4000,3000); //Calibrate timer
SHAL_TIM7.setCallbackFunc(buttonHoldCallback); SHAL_TIM7.setCallbackFunc(buttonHoldCallback);
SHAL_TIM7.enableInterrupt(); SHAL_TIM7.enableInterrupt();
SHAL_TIM15.init(4000000,5000); //1 second SHAL_TIM15.init(4000,5000); //5 seconds
SHAL_TIM15.setCallbackFunc(startBeeping); SHAL_TIM15.setCallbackFunc(startBeeping);
SHAL_TIM15.enableInterrupt(); SHAL_TIM15.enableInterrupt();
SHAL_UART2.sendString("Hello3\r\n");
while (true) { //TODO set to use button for simulating off sensor, uncomment for real functionality while (true) { //TODO set to use button for simulating off sensor, uncomment for real functionality
if(PIN(B6).digitalRead() != 1){ if(PIN(B6).digitalRead() != 1){
areSensorRequirementsMetCurrent = false;
/* if(prevIsCalibrateButtonHigh){
if(!prevIsCalibrateButtonHigh){
SHAL_TIM7.start(); SHAL_TIM7.start();
} }
prevIsCalibrateButtonHigh = true; prevIsCalibrateButtonHigh = false;
*/
} }
else{ else{
areSensorRequirementsMetCurrent = true; if(!prevIsCalibrateButtonHigh){
if(shouldToggleDeviceState){
if(!isDeviceOn){ //Turn device on
PIN(A8).setHigh();
isDeviceOn = true;
}
else{ //Turn device off
PIN(A8).setLow();
PIN(A9).setLow();
isDeviceOn = false;
areSensorRequirementsMetCurrent = true;
areSensorRequirementsMetPrevious = true;
stopBeeping();
}
}
shouldToggleDeviceState = true;
/*
if(prevIsCalibrateButtonHigh){
//Button released
SHAL_TIM7.stop(); SHAL_TIM7.stop();
} }
prevIsCalibrateButtonHigh = false; prevIsCalibrateButtonHigh = true;
*/
} }
if(isDeviceOn && shouldCheckSensorThresholds){
checkSensorThresholds(); checkSensorThresholds();
}
areSensorRequirementsMetPrevious = areSensorRequirementsMetCurrent;
} }
} }