diff --git a/src/ADC/ADC.c b/src/ADC/ADC.c new file mode 100644 index 0000000..be0ff82 --- /dev/null +++ b/src/ADC/ADC.c @@ -0,0 +1,112 @@ +/* + * Author: username + * Date: 2024 + * filename: ADC.c + * description: module_purpose + */ + +#ifndef __AVR_ATtiny404__ +#define __AVR_ATtiny404__ +#endif + +#include "ADC.h" +#include "RegEdit.h" +#include "avr/io.h" + +#define MAX_PIN_NUM 7 + +static bool IsInvalidPin(uint8_t pin_num){ + if(pin_num > MAX_PIN_NUM){ + return true; + } + return false; +} + + +void ADC_Setup(void) +{ + //Clears control register A for ADC0 + RegEdit_SetNum((void *) &ADC0.CTRLA, 0x00); + + //Sets The sample accumulation number to 32. + RegEdit_SetNum((void *) &ADC0.CTRLB, 0x5); + + //Sets the voltage reference to VDD or VCC. + RegEdit_SetBit((void *) &ADC0.CTRLC, 4); + + //Sets the pre-scalar for the adc sample rate. + RegEdit_SetBit((void *) &ADC0.CTRLC, 2); + + //Setup an Initalization delay. + RegEdit_OR_Num((void *) &ADC0.CTRLD, (2<<5)); + + //Set the bit for ADC variation during readings. + RegEdit_SetBit((void *) &ADC0.CTRLD, 4); +} + +void ADC_Init(uint8_t pin_num) +{ + + if(IsInvalidPin(pin_num)){return;} + + + //set the direction to input + RegEdit_ClearBit((void *) &PORTA.DIR, pin_num); + + //Disable the pull-up resistor + RegEdit_ClearBit((void *) &PORTA.OUT, pin_num); + + //Disable input buffer + //We do some kinda nasty address addition but it saves + //memory and means we don't need a switch statment. + RegEdit_SetBit( + (void *) (&PORTA.PIN0CTRL)+pin_num, + PORT_ISC_INPUT_DISABLE_gc + ); + +} + + +void ADC_Enable(void) +{ + //Set the enable bit in the CTRLA register + RegEdit_SetBit((void *) &ADC0.CTRLA, 0); +} + + +void ADC_Disable() +{ + //Clear the enable ADC flag + RegEdit_ClearBit((void *) &ADC0.CTRLA, 0); +} + + +void ADC_SetPin(uint8_t pin_num) +{ + if(IsInvalidPin(pin_num)){return;} + RegEdit_ClearRegister((void *) &ADC0.MUXPOS); + RegEdit_SetNum((void *) &ADC0.MUXPOS, pin_num); +} + + +uint16_t ADC_ReadValue_Impl(uint8_t pin_num) +{ + RegEdit_SetNum((void *) &ADC0.COMMAND, ADC_STCONV_bm); + + /* Wait until ADC conversion done */ + while ( !(ADC0.INTFLAGS & ADC_RESRDY_bm) ) + { + ; + } + + /* Clear the interrupt flag by writing 1: */ + ADC0.INTFLAGS = ADC_RESRDY_bm; + + uint16_t adc_val = (uint16_t) ADC0.RES; + adc_val = adc_val >> 5; + return adc_val; +} + + +//Set the default for the function pointer. +uint16_t (*ADC_ReadValue)(uint8_t pin_num) = ADC_ReadValue_Impl; diff --git a/src/ADC/ADC.h b/src/ADC/ADC.h new file mode 100644 index 0000000..3792eab --- /dev/null +++ b/src/ADC/ADC.h @@ -0,0 +1,74 @@ +/** + * @brief Interface to the AVR ADC hardware. + * @details This file is... + * @author Jake G + * @date 2024 + * @copyright None + * @file ADC.h + */ + +#ifndef ADC_H +#define ADC_H + +#include +#include + + + +/** + * @brief Initializes the AVR hardware in order to accept + * Input for ADC usage. + * @param pin_num The number of the pin 0-7 you are initializing. + * + * This function only makes use of PORTA by default. It sets the direction + * register to input, disables the pull-up resistor and also diables interrupts + * alongside the input buffer(digital). + * + * This in turn helps reduce noise when using the ADC. + * + */ +void ADC_Init(uint8_t pin_num); + + +/** + * @brief Enables the ADC + */ +void ADC_Enable(void); + + +/** + * @brief Disables the ADC + */ +void ADC_Disable(); + + +/** + * @brief Reads ADC value into variable + * + * @param pin_num The bin number of the ADC pin being read. + * + * This function depends on the ADC already being initialized and enabled + * before being called. + */ +extern uint16_t (*ADC_ReadValue)(uint8_t pin_num); + +/** + * @brief Sets up the ADC + * + * This function sets up the ADC to take and accumulate 32 samples. It also + * sets the inital delay to 32 ADC clock cycles, and sets the VREF to VDD or + * VCC. + * + * This function should only need to be called once. + */ +void ADC_Setup(void); + + +/** + * @brief Sets the pin used in the MUX for ADC0. + * + * @param pin_num The number of the pin in Port A. + */ +void ADC_SetPin(uint8_t pin_num); + +#endif //ADC_H diff --git a/src/ADC/CMakeLists.txt b/src/ADC/CMakeLists.txt new file mode 100644 index 0000000..3b39d8c --- /dev/null +++ b/src/ADC/CMakeLists.txt @@ -0,0 +1,17 @@ +add_library(ADC STATIC + ADC.c +) +target_include_directories(ADC PUBLIC + ${CMAKE_CURRENT_LIST_DIR} +) + +if(UNIT_TESTING) + target_link_libraries(ADC + MockRegEdit + ) + +else() + target_link_libraries(ADC + RegEdit + ) +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 49ebd28..96e9ac1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -57,3 +57,6 @@ add_subdirectory(timer) add_subdirectory(SuperLoop) add_subdirectory(Relays) +add_subdirectory(zero_cross_detection) +add_subdirectory(ADC) +add_subdirectory(load) diff --git a/src/load/CMakeLists.txt b/src/load/CMakeLists.txt new file mode 100644 index 0000000..a61e227 --- /dev/null +++ b/src/load/CMakeLists.txt @@ -0,0 +1,18 @@ +add_library(load STATIC + load.c +) +target_include_directories(load PUBLIC + ${CMAKE_CURRENT_LIST_DIR} +) + +if(UNIT_TESTING) + target_link_libraries(load + MockRegEdit + MockADC + ) +else() + target_link_libraries(load + RegEdit + ADC + ) +endif() diff --git a/src/load/load.c b/src/load/load.c new file mode 100644 index 0000000..66787ff --- /dev/null +++ b/src/load/load.c @@ -0,0 +1,75 @@ +/* + * Author: Jake G + * Date: 2024 + * filename: load.c + * description: module_purpose + */ + +#ifndef __AVR_ATtiny404__ +#define __AVR_ATtiny404__ +#endif + + +#include +#include "load.h" + + +#ifndef UNIT_TESTING + #include "ADC.h" + #include "RegEdit.h" +#else + #include "MockADC/MockADC.h" + #include "MockRegEdit.h" +#endif + + + +//These two arrays allow us to track the A and B ports to know when +//one has been disabled before. +static bool porta_disabled[8] = {0}; +static bool portb_disabled[8] = {0}; + + +static bool valid_load(uint16_t val) +{ + if(val > 527 && val < 1000) { + return true; + } + return false; +} + +void Load_HandleLoadPortA(uint8_t adc_pin, uint8_t out_pin) +{ + ADC_Init(adc_pin); + ADC_Enable(); + ADC_SetPin(adc_pin); + uint16_t val = ADC_ReadValue(adc_pin); + + ADC_Disable(); + if(valid_load(val) && !porta_disabled[adc_pin]){ + RegEdit_SetBit((void *) &PORTA.DIR, out_pin); + RegEdit_SetBit((void *) &PORTA.OUT, out_pin); + } + else{ + RegEdit_ClearBit((void *) &PORTA.OUT, out_pin); + porta_disabled[adc_pin] = true; + } +} + +void Load_HandleLoadPortB(uint8_t adc_pin, uint8_t out_pin) +{ + ADC_Init(adc_pin); + ADC_Enable(); + ADC_SetPin(adc_pin); + uint16_t val = ADC_ReadValue(adc_pin); + + ADC_Disable(); + if(valid_load(val) && !portb_disabled[adc_pin]){ + RegEdit_SetBit((void *) &PORTB.DIR, out_pin); + RegEdit_SetBit((void *) &PORTB.OUT, out_pin); + } + else{ + RegEdit_ClearBit((void *) &PORTB.OUT, out_pin); + portb_disabled[adc_pin] = true; + } +} diff --git a/src/load/load.h b/src/load/load.h new file mode 100644 index 0000000..1b3112f --- /dev/null +++ b/src/load/load.h @@ -0,0 +1,32 @@ +/** + * @brief Module for handling the ADC input from the load pins. + * @details This file holds the functions for reading the ADC values. + * @author Jake G + * @date 2024 + * @copyright None + * @file load.h + */ + +#ifndef LOAD_H +#define LOAD_H + +/** + * @brief Low Threshold + * + */ +#define LOWTHRESH 527 + +/** + * @brief High Threshold + * + */ +#define HIGHTHRESH 1000 + +void Load_HandleLoadPortA(uint8_t adc_pin, uint8_t out_pin); +void Load_HandleLoadPortB(uint8_t adc_pin, uint8_t out_pin); + +void Load_HandlePinLoads(void); + + +#endif /* LOAD_H */ + diff --git a/src/zero_cross_detection/CMakeLists.txt b/src/zero_cross_detection/CMakeLists.txt new file mode 100644 index 0000000..e0db991 --- /dev/null +++ b/src/zero_cross_detection/CMakeLists.txt @@ -0,0 +1,17 @@ +add_library(zero_cross_detection STATIC + zero_cross_detection.c +) +target_include_directories(zero_cross_detection PUBLIC + ${CMAKE_CURRENT_LIST_DIR} +) + + +if(UNIT_TESTING) + target_link_libraries(zero_cross_detection + MockADC + ) +else() + target_link_libraries(zero_cross_detection + ADC + ) +endif() diff --git a/src/zero_cross_detection/zero_cross_detection.c b/src/zero_cross_detection/zero_cross_detection.c new file mode 100644 index 0000000..7b81e1e --- /dev/null +++ b/src/zero_cross_detection/zero_cross_detection.c @@ -0,0 +1,54 @@ +/* + * Author: Jake G + * Date: 2024 + * filename: zero_cross_detection.c + * description: + */ + +#include "zero_cross_detection.h" + +#define TRIGGERVAL 512 + +#ifndef UNIT_TESTING +#include "ADC.h" +#else +#include "MockADC/MockADC.h" +#endif + +#define ZCD_PIN 0x07 + +void ZCD_Setup(void) +{ + ADC_Init(ZCD_PIN); + ADC_SetPin(ZCD_PIN); + ADC_Enable(); +} + +bool ZCD_IsTriggered() +{ + uint16_t first, second; + ZCD_Setup(); + first = ADC_ReadValue(ZCD_PIN); + ADC_Disable(); + + ZCD_Setup(); + second = ADC_ReadValue(ZCD_PIN); + ADC_Disable(); + + if(second < TRIGGERVAL){ + return false; + } + if(second < first){ + return false; + } + return true; +} + +void ZCD_Poll(void) +{ + while(true){ + if(ZCD_IsTriggered()){ + break; + } + } +} diff --git a/src/zero_cross_detection/zero_cross_detection.h b/src/zero_cross_detection/zero_cross_detection.h new file mode 100644 index 0000000..16bf9af --- /dev/null +++ b/src/zero_cross_detection/zero_cross_detection.h @@ -0,0 +1,49 @@ +/** + * @file zero_cross_detection.h + * @author Jake G + * @date 16 June 2024 + * @brief File contains the zero cross detection functions + * + * This file holds all the code/functions needed to read the value of the AC + * waveform. It uses the trigger value from the `config.h` file to evaluate the + * state. + * + * This module depends on the ADC.h module to get readings from the ADC + * hardware. + */ + +#ifndef ZERO_CROSS_DETECTION +#define ZERO_CROSS_DETECTION + +#include +#include + +/** + * @brief Zero Cross Detection Setup + * + * Sets up the hardware to read the values coming from the AC input waveform. + * + */ +void ZCD_Setup(void); +//int ZCD_Setup(volatile uint8_t *ddrx, uint8_t *port, uint8_t pin); + + +/** + * @brief Checks if ZCD should trigger on value + * + * The function checks for a positive edge first using the ZCD_IsPositiveEdge + * function. If a positive edge was found, then it takes an addition set of + * samples and averages them; only triggering(returning true) in the case + * that the average is higher than the previous sample. + */ +bool ZCD_IsTriggered(void); + + +/** + * @brief Function blocks execution until ZCD is triggered. + * + */ +void ZCD_Poll(void); + + +#endif //ZERO_CROSS_DETECTION