Skip to content

Commit

Permalink
Merge pull request #108 from RIT-EVT/feature/tmb5932/MultiADC
Browse files Browse the repository at this point in the history
FWT-45 adding Multiple Actually Dangerous Commits (Multi ADC Support)
  • Loading branch information
tmb5932 authored Dec 6, 2024
2 parents b67f79b + 203571a commit 8429056
Show file tree
Hide file tree
Showing 10 changed files with 448 additions and 158 deletions.
7 changes: 5 additions & 2 deletions include/core/io/ADC.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
namespace core::io {

// Forward declarations:
// The different pins are hardware specific. Forware declarationsto allow
// The different pins are hardware specific. Forward declarations to allow
// at compilation time the decision of which pins should be used.
enum class Pin;
enum class ADCPeriph;

class ADC {

Expand All @@ -18,7 +19,7 @@ class ADC {
*
* @param[in] pin The pin to setup for ADC
*/
ADC(Pin pin);
ADC(Pin pin, ADCPeriph adcPeriph);

/**
* Reads the current voltage in volts on the ADC
Expand Down Expand Up @@ -46,6 +47,8 @@ class ADC {
protected:
/// The pin the ADC is attached to
Pin pin;
/// The internal ADC being used
ADCPeriph adcPeriph;
};

} // namespace core::io
Expand Down
2 changes: 2 additions & 0 deletions include/core/io/pin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ namespace core::io {
* these values.
*/
enum class Pin {
INVALID = -1, // THIS INTENTIONALLY DOES NOT POINT TO A PIN. Used as a default value, so the default value is
// no longer PA_O (a real pin)
PA_0 = 0x00,
PA_1 = 0x01,
PA_2 = 0x02,
Expand Down
26 changes: 25 additions & 1 deletion include/core/io/platform/f3xx/ADCf3xx.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@

namespace core::io {

enum class ADCPeriph {
ONE
};

class ADCf3xx : public ADC {
public:
/**
* Setup the given pin for ADC usage
*
* @param[in] pin The pin to setup for ADC
*/
ADCf3xx(Pin pin);
ADCf3xx(Pin pin, ADCPeriph adcPeriph);

float read();

Expand All @@ -41,6 +45,17 @@ class ADCf3xx : public ADC {
static uint16_t buffer[MAX_CHANNELS];
static DMA_HandleTypeDef halDMA;

/**
* Bit packed struct to contain the channel along with the ADC peripherals the channel supports
*
* adc1: 1 bit. Support for ADC1 peripheral. 1 for supported, 0 for not supported.
* channel: 5 bits. The STM32 ADC channel value with said supported ADC peripherals
*/
struct Channel_Support {
uint8_t adc1 : 1;
uint8_t channel : 5;
};

/**
* Initialize the HAL ADC handler. This should only have to be run once
*/
Expand All @@ -58,6 +73,15 @@ class ADCf3xx : public ADC {
* was added to the ADC starting at 1
*/
void addChannel(uint8_t rank);

/**
* Check if the channel that is being initialized supports the ADC peripheral that it is being initialized on.
*
* @param periph the ADC peripheral being used
* @param channelStruct the struct of the channel with supports to test
* @return true if channel is supported by the ADC peripheral, false otherwise
*/
static bool checkSupport(ADCPeriph periph, Channel_Support channelStruct);
};

} // namespace core::io
Expand Down
117 changes: 101 additions & 16 deletions include/core/io/platform/f4xx/ADCf4xx.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,21 @@

namespace core::io {

enum class ADCPeriph {
ONE,
TWO,
THREE
};

class ADCf4xx : public ADC {
public:
/**
* Setup the given pin for ADC usage
*
* @param[in] pin The pin to setup for ADC
* @param[in] adcPeriph The ADC peripheral being used
*/
ADCf4xx(Pin pin);
ADCf4xx(Pin pin, ADCPeriph adcPeriph);

float read();

Expand All @@ -25,40 +32,118 @@ class ADCf4xx : public ADC {

private:
// Max number of channels supported by the ADC
static constexpr uint8_t MAX_CHANNELS = 15;
static constexpr uint8_t MAX_CHANNELS = 16;
// Number of supported ADC Peripherals
static constexpr uint8_t NUM_ADCS = 3;
// Positive reference voltage of the ADC. Needs to be updated based on the hardware configuration
static constexpr float VREF_POS = 3.3;
// Max value for a 12 bit ADC reading (2^12 - 1)
static constexpr uint32_t MAX_RAW = 4095;
/// This is static since the STM32F3xx only had a single ADC which
/// supports multiple channels, so I made this one only use a single ADC.
/// The F446re has 3 12 bit ADC's. Currently not able to use the other 2.
/// The ADC will be initialized once then each channel will be added on.
static ADC_HandleTypeDef halADC;
/// Static list of all channels supported by the ADC
static Pin channels[MAX_CHANNELS];
/// Buffer for DMA where each spot represents the value read in from a
/// channel
static uint16_t buffer[MAX_CHANNELS];
static DMA_HandleTypeDef halDMA;
// Flag to indicate if the timer has been initialized
static bool timerInit;
// Timer handle for TIM8, used to configure and control the timer instance
static TIM_HandleTypeDef htim8;

/**
* Structure to represent the state of an ADC instance.
*
* This structure holds the configuration and current state for an ADC instance, including the
* HAL handle for the ADC and DMA, channel configurations, and data buffers for readings.
*
* halADC: HAL handle for configuring and controlling the ADC peripheral.
* rank: The ADC channel rank in the sequence (starts at 1).
* isADCInit: Flag to indicate whether the ADC has been initialized.
* channels: Array of pins mapped to ADC channels. Initialized to all Pin::INVALID.
* The array size is defined by MAX_CHANNELS.
* buffer: Array to store ADC values for each channel, indexed according to the channels array.
* Each entry corresponds to a specific ADC channel.
* halDMA: HAL handle for configuring and controlling DMA for the ADC.
*/
struct ADC_State {
ADC_HandleTypeDef halADC = {0};
uint8_t rank = 1;
bool isADCInit = false;
Pin channels[MAX_CHANNELS] = {Pin::INVALID,
Pin::INVALID,
Pin::INVALID,
Pin::INVALID,
Pin::INVALID,
Pin::INVALID,
Pin::INVALID,
Pin::INVALID,
Pin::INVALID,
Pin::INVALID,
Pin::INVALID,
Pin::INVALID,
Pin::INVALID,
Pin::INVALID,
Pin::INVALID,
Pin::INVALID};
uint16_t buffer[MAX_CHANNELS] = {0};
DMA_HandleTypeDef halDMA = {0};
};

/**
* Initialize the HAL ADC handler. This should only have to be run once
* Bit packed struct to contain the channel along with the ADC peripherals the channel supports
*
* adc1: 1 bit. Support for ADC1 peripheral. 1 for supported, 0 for not supported.
* adc2: 1 bit. Support for ADC2 peripheral. 1 for supported, 0 for not supported.
* adc3: 1 bit. Support for ADC3 peripheral. 1 for supported, 0 for not supported.
* channel: 5 bits. The STM32 ADC channel value with said supported ADC peripherals
*/
struct Channel_Support {
uint8_t adc1 : 1;
uint8_t adc2 : 1;
uint8_t adc3 : 1;
uint8_t channel : 5;
};

// Array of all ADC peripheral states
static ADC_State adcArray[NUM_ADCS];
// The ADC peripheral state of the current object
ADC_State& adcState;
// The number ADC peripheral which is being used in the current object
uint8_t adcNum;

/**
* Check if the channel that is being initialized supports the ADC peripheral that it is being initialized on.
*
* @param periph the ADC peripheral being used
* @param channelStruct the struct of the channel with supports to test
* @return true if channel is supported by the ADC peripheral, false otherwise
*/
static bool checkSupport(ADCPeriph periph, Channel_Support channelStruct);

/**
* Return the ADC number that is in use
*
* @return The adc number that is being used in this specific object
*/
static uint8_t getADCNum(ADCPeriph periph);

/**
* Initialize the HAL ADC handler
*/
void initADC(uint8_t num_channels);

/**
* Initialize the HAL DMA for the ADC, should only have to be run once
* Initialize the HAL DMA for the ADC
*/
void initDMA();

/**
* Adds an ADC channel to the HAL ADC device.
* Add an ADC channel to the HAL ADC device.
*
* @param rank The "rank" which represents the order in which the channel
* was added to the ADC starting at 1
*/
void addChannel(uint8_t rank);

/**
* Initialize Timer 8 to send Update Events, which the ADC listens for to do a conversion
* aka controls ADC conversion frequency
*/
static void initTimer();
};

} // namespace core::io
Expand Down
6 changes: 3 additions & 3 deletions include/core/manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,14 +147,14 @@ namespace core::io {
* @param[in] pin The pin to use with the ADC
*/
#ifdef ADC_SUPPORTED
template<Pin pin>
template<Pin pin, ADCPeriph adcPeriph = ADCPeriph::ONE>
ADC& getADC() {
#ifdef STM32F4xx
static ADCf4xx adc(pin);
static ADCf4xx adc(pin, adcPeriph);
return adc;
#endif
#ifdef STM32F3xx
static ADCf3xx adc(pin);
static ADCf3xx adc(pin, adcPeriph);
return adc;
#endif
}
Expand Down
30 changes: 19 additions & 11 deletions samples/adc/multi_adc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <core/io/ADC.hpp>
#include <core/io/UART.hpp>
#include <core/manager.hpp>
#include <core/utils/log.hpp>
#include <core/utils/time.hpp>

namespace io = core::io;
Expand All @@ -17,23 +18,30 @@ int main() {

io::UART& uart = io::getUART<io::Pin::UART_TX, io::Pin::UART_RX>(9600);

// Set up the logger to catch errors in ADC creation
core::log::LOGGER.setUART(&uart);
core::log::LOGGER.setLogLevel(core::log::Logger::LogLevel::INFO);

uart.printf("Starting ADC test\r\n");

time::wait(500);

io::ADC& adc0 = io::getADC<io::Pin::PA_0>();
io::ADC& adc1 = io::getADC<io::Pin::PA_1>();
io::ADC& adc0 = io::getADC<io::Pin::PA_0, io::ADCPeriph::ONE>();
io::ADC& adc1 = io::getADC<io::Pin::PC_4, io::ADCPeriph::ONE>();

while (1) {
uart.printf("--------------------\r\n");
uart.printf("ADC0 : %d mV\r\n", static_cast<uint32_t>(adc0.read() * 1000));
uart.printf("ADC0: %d%%\r\n", static_cast<uint32_t>(adc0.readPercentage() * 100));
uart.printf("ADC0 raw: %d\r\n\r\n", adc0.readRaw());

uart.printf("ADC1 : %d mV\r\n", static_cast<uint32_t>(adc1.read() * 1000));
uart.printf("ADC1: %d%%\r\n", static_cast<uint32_t>(adc1.readPercentage() * 100));
uart.printf("ADC1 raw: %d\r\n", adc1.readRaw());
uart.printf("--------------------\r\n\r\n");
core::log::LOGGER.log(core::log::Logger::LogLevel::INFO, "--------------------");
core::log::LOGGER.log(
core::log::Logger::LogLevel::INFO, "ADC0 : %d mV", static_cast<uint32_t>(adc0.read() * 1000));
core::log::LOGGER.log(
core::log::Logger::LogLevel::INFO, "ADC0: %d%%", static_cast<uint32_t>(adc0.readPercentage() * 100));
core::log::LOGGER.log(core::log::Logger::LogLevel::INFO, "ADC0 raw: %d", adc0.readRaw());
core::log::LOGGER.log(
core::log::Logger::LogLevel::INFO, "ADC1 : %d mV", static_cast<uint32_t>(adc1.read() * 1000));
core::log::LOGGER.log(
core::log::Logger::LogLevel::INFO, "ADC1: %d%%", static_cast<uint32_t>(adc1.readPercentage() * 100));
core::log::LOGGER.log(core::log::Logger::LogLevel::INFO, "ADC1 raw: %d", adc1.readRaw());
core::log::LOGGER.log(core::log::Logger::LogLevel::INFO, "--------------------\r\n");
time::wait(500);
}
}
19 changes: 13 additions & 6 deletions samples/adc/single_adc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <core/io/ADC.hpp>
#include <core/io/UART.hpp>
#include <core/manager.hpp>
#include <core/utils/log.hpp>
#include <core/utils/time.hpp>

namespace io = core::io;
Expand All @@ -17,18 +18,24 @@ int main() {

io::UART& uart = io::getUART<io::Pin::UART_TX, io::Pin::UART_RX>(9600);

// Set up the logger to catch errors in ADC creation
core::log::LOGGER.setUART(&uart);
core::log::LOGGER.setLogLevel(core::log::Logger::LogLevel::INFO);

uart.printf("Starting ADC test\r\n");

time::wait(500);

io::ADC& adc0 = io::getADC<io::Pin::PA_0>();
io::ADC& adc0 = io::getADC<io::Pin::PA_0, io::ADCPeriph::ONE>();

while (1) {
uart.printf("--------------------\r\n");
uart.printf("ADC0 : %d mV\r\n", static_cast<uint32_t>(adc0.read() * 1000));
uart.printf("ADC0: %d%%\r\n", static_cast<uint32_t>(adc0.readPercentage() * 100));
uart.printf("ADC0 raw: %d\r\n\r\n", adc0.readRaw());
uart.printf("--------------------\r\n\r\n");
core::log::LOGGER.log(core::log::Logger::LogLevel::INFO, "--------------------");
core::log::LOGGER.log(
core::log::Logger::LogLevel::INFO, "ADC0 : %d mV", static_cast<uint32_t>(adc0.read() * 1000));
core::log::LOGGER.log(
core::log::Logger::LogLevel::INFO, "ADC0: %d%%", static_cast<uint32_t>(adc0.readPercentage() * 100));
core::log::LOGGER.log(core::log::Logger::LogLevel::INFO, "ADC0 raw: %d", adc0.readRaw());
core::log::LOGGER.log(core::log::Logger::LogLevel::INFO, "--------------------\r\n");
time::wait(500);
}
}
4 changes: 1 addition & 3 deletions src/core/io/ADC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

namespace core::io {

ADC::ADC(Pin pin) {
this->pin = pin;
}
ADC::ADC(Pin pin, ADCPeriph adcPeriph) : pin(pin), adcPeriph(adcPeriph) {}

} // namespace core::io
Loading

0 comments on commit 8429056

Please sign in to comment.