Skip to content

Add ADC Dual Mode support with new AdvancedADCDual class #64

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 163 additions & 31 deletions src/AdvancedADC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,42 +115,73 @@ DMABuffer<Sample> &AdvancedADC::read() {
return NULLBUF;
}

int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers) {
int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers,bool do_start,uint8_t adcNum) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers,bool do_start,uint8_t adcNum) {
int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers,bool do_start, uint8_t adc_num) {

Space between args, and No camel case please.


ADCName instance = ADC_NP;

// Sanity checks.
if (resolution >= AN_ARRAY_SIZE(ADC_RES_LUT) || (descr && descr->pool)) {
return 0;
}

//if ADC specified is more than the number of available ADC bail out
if(adcNum>AN_ARRAY_SIZE(adc_pin_alt))
{
descr = nullptr;
return 0;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if(adcNum>AN_ARRAY_SIZE(adc_pin_alt))
{
descr = nullptr;
return 0;
}
if (adcNum > AN_ARRAY_SIZE(adc_pin_alt)) {
descr = nullptr;
return 0;
}

Spaces between operators, bracket on the same line as function/if.


// Clear ALTx pin.
for (size_t i=0; i<n_channels; i++) {
adc_pins[i] = (PinName) (adc_pins[i] & ~(ADC_PIN_ALT_MASK));
}

// Find an ADC that can be used with these set of pins/channels.
for (size_t i=0; instance == ADC_NP && i<AN_ARRAY_SIZE(adc_pin_alt); i++) {
// Calculate alternate function pin.
PinName pin = (PinName) (adc_pins[0] | adc_pin_alt[i]); // First pin decides the ADC.

// Check if pin is mapped.
if (pinmap_find_peripheral(pin, PinMap_ADC) == NC) {
break;
}
// If ADC not specified find an ADC that can be used with these set of pins/channels.
if(adcNum==0)
{
for (size_t i=0; instance == ADC_NP && i<AN_ARRAY_SIZE(adc_pin_alt); i++) {
// Calculate alternate function pin.
PinName pin = (PinName) (adc_pins[0] | adc_pin_alt[i]); // First pin decides the ADC.

// Find the first free ADC according to the available ADCs on pin.
for (size_t j=0; instance == ADC_NP && j<AN_ARRAY_SIZE(adc_descr_all); j++) {
descr = &adc_descr_all[j];
if (descr->pool == nullptr) {
ADCName tmp_instance = (ADCName) pinmap_peripheral(pin, PinMap_ADC);
if (descr->adc.Instance == ((ADC_TypeDef*) tmp_instance)) {
instance = tmp_instance;
adc_pins[0] = pin;
// Check if pin is mapped.
if (pinmap_find_peripheral(pin, PinMap_ADC) == NC) {
break;
}

// Find the first free ADC according to the available ADCs on pin.
for (size_t j=0; instance == ADC_NP && j<AN_ARRAY_SIZE(adc_descr_all); j++) {
descr = &adc_descr_all[j];
if (descr->pool == nullptr) {
ADCName tmp_instance = (ADCName) pinmap_peripheral(pin, PinMap_ADC);
if (descr->adc.Instance == ((ADC_TypeDef*) tmp_instance)) {
instance = tmp_instance;
adc_pins[0] = pin;
selectedADC=j;
}
}
}
}
}
else if(adcNum>0) //if ADC specified use that ADC to try to map first channel
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
else if(adcNum>0) //if ADC specified use that ADC to try to map first channel
} else if (adcNum > 0) { //if ADC specified use that ADC to try to map first channel

{
PinName pin = (PinName) (adc_pins[0] | adc_pin_alt[adcNum-1]);

// Check if pin is mapped.
if (pinmap_find_peripheral(pin, PinMap_ADC) == NC) {
return 0;
}

descr = &adc_descr_all[adcNum-1];
if (descr->pool == nullptr) {
ADCName tmp_instance = (ADCName) pinmap_peripheral(pin, PinMap_ADC);
if (descr->adc.Instance == ((ADC_TypeDef*) tmp_instance)) {
instance = tmp_instance;
adc_pins[0] = pin;
}
}
selectedADC=adcNum; //Store selected number
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
selectedADC=adcNum; //Store selected number
selected_adc = adc_num; //Store selected number

}

if (instance == ADC_NP) {
// Couldn't find a free ADC/descriptor.
descr = nullptr;
Expand All @@ -159,11 +190,40 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl

// Configure ADC pins.
pinmap_pinout(adc_pins[0], PinMap_ADC);
uint8_t ch_init = 1;
for (size_t i=1; i<n_channels; i++) {
for (size_t j=0; j<AN_ARRAY_SIZE(adc_pin_alt); j++) {

//If ADC was not specified ensure the remaining channels are mappable to same ADC
if(adcNum==0)
{
uint8_t ch_init = 1;
for (size_t i=1; i<n_channels; i++) {
for (size_t j=0; j<AN_ARRAY_SIZE(adc_pin_alt); j++) {
// Calculate alternate function pin.
PinName pin = (PinName) (adc_pins[i] | adc_pin_alt[j]);
// Check if pin is mapped.
if (pinmap_find_peripheral(pin, PinMap_ADC) == NC) {
break;
}
// Check if pin is connected to the selected ADC.
if (instance == pinmap_peripheral(pin, PinMap_ADC)) {
pinmap_pinout(pin, PinMap_ADC);
adc_pins[i] = pin;
ch_init++;
break;
}
}
}
// All channels must share the same instance; if not, bail out.
if (ch_init < n_channels) {
return 0;
}
}
else if(adcNum>0) //If specific ADC was requested ensure all other channels map to that same ADC
{
uint8_t ch_init = 1;
for (size_t i=1; i<n_channels; i++) {

// Calculate alternate function pin.
PinName pin = (PinName) (adc_pins[i] | adc_pin_alt[j]);
PinName pin = (PinName) (adc_pins[i] | adc_pin_alt[adcNum-1]);
// Check if pin is mapped.
if (pinmap_find_peripheral(pin, PinMap_ADC) == NC) {
break;
Expand All @@ -173,21 +233,22 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl
pinmap_pinout(pin, PinMap_ADC);
adc_pins[i] = pin;
ch_init++;
break;
}
}
// All channels must share the same instance; if not, bail out.
if (ch_init < n_channels) {
return 0;
}
}

// All channels must share the same instance; if not, bail out.
if (ch_init < n_channels) {
return 0;
}



// Allocate DMA buffer pool.
descr->pool = new DMABufferPool<Sample>(n_samples, n_channels, n_buffers);
if (descr->pool == nullptr) {
return 0;
}

//Allocate two DMA buffers for double buffering
descr->dmabuf[0] = descr->pool->allocate();
descr->dmabuf[1] = descr->pool->allocate();

Expand All @@ -202,7 +263,7 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl
}

// Link DMA handle to ADC handle, and start the ADC.
__HAL_LINKDMA(&descr->adc, DMA_Handle, descr->dma);
__HAL_LINKDMA(&descr->adc, DMA_Handle, descr->dma);
if (HAL_ADC_Start_DMA(&descr->adc, (uint32_t *) descr->dmabuf[0]->data(), descr->dmabuf[0]->size()) != HAL_OK) {
return 0;
}
Expand All @@ -212,12 +273,24 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl
hal_dma_enable_dbm(&descr->dma, descr->dmabuf[0]->data(), descr->dmabuf[1]->data());
HAL_NVIC_EnableIRQ(descr->dma_irqn);

if(do_start)
{
return(start(sample_rate));
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if(do_start)
{
return(start(sample_rate));
}
if (do_start) {
return start(sample_rate);
}

No return() please.

return 1;
}

int AdvancedADC::start(uint32_t sample_rate)
{
// Init, config and start the ADC timer.
hal_tim_config(&descr->tim, sample_rate);

//Start Timer and ADC Capture. If Dual Mode was enabled, then this will also start ADC2
if (HAL_TIM_Base_Start(&descr->tim) != HAL_OK) {
return 0;
}

return 1;
}

Expand All @@ -227,11 +300,70 @@ int AdvancedADC::stop()
return 1;
}

void AdvancedADC::clear()
{
descr->pool->flush();
}

AdvancedADC::~AdvancedADC()
{
dac_descr_deinit(descr, true);
}

int AdvancedADCDual::begin(AdvancedADC *in1, AdvancedADC *in2,uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers)
{
adcIN1=in1;
adcIN2=in2;

int result=0;

//Configure first pin on ADC1
result=adcIN1->begin(resolution,sample_rate,n_samples,n_buffers,1,&(adc_pins_unmapped[0]),false,1);
if(result!=1)
{
return(0);
}
//Configure all other pins on ADC2
result=adcIN2->begin(resolution,sample_rate,n_samples,n_buffers,n_channels-1,&(adc_pins_unmapped[1]),false,2);
if(result!=1)
{
return(0);
}

result=hal_enable_dual_mode();

result=adcIN1->start(sample_rate);

if(result!=1)
{
return(0);
}

return(1);

}

int AdvancedADCDual:: stop()
{
if(adcIN1!=nullptr)
{
adcIN1->stop();
}
if(adcIN2!=nullptr)
{
adcIN2->stop();
}
//Always disable dual mode when stopped
int result=hal_disable_dual_mode();
return(1);

}

AdvancedADCDual::~AdvancedADCDual()
{
int result=stop();
}

extern "C" {
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *adc) {
adc_descr_t *descr = adc_descr_get(adc->Instance);
Expand Down
61 changes: 58 additions & 3 deletions src/AdvancedADC.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class AdvancedADC {
size_t n_channels;
adc_descr_t *descr;
PinName adc_pins[AN_MAX_ADC_CHANNELS];
bool dualMode;
uint8_t selectedADC;

public:
template <typename ... T>
Expand All @@ -41,21 +43,74 @@ class AdvancedADC {
for (auto p : {p0, args...}) {
adc_pins[n_channels++] = analogPinToPinName(p);
}
dualMode=false;
selectedADC=0;
}
AdvancedADC(): n_channels(0), descr(nullptr) {}
~AdvancedADC();
bool available();
SampleBuffer read();
int begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers);
int begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers, size_t n_pins, pin_size_t *pins) {
int begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers, bool do_start=true,uint8_t adcNum=0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers, bool do_start=true,uint8_t adcNum=0);
int begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers, bool start=true, uint8_t adc_instance=0);

int begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers, size_t n_pins, pin_size_t *pins, bool start=true,uint8_t fixed_adc=0) {
if (n_pins > AN_MAX_ADC_CHANNELS) n_pins = AN_MAX_ADC_CHANNELS;
for (size_t i = 0; i < n_pins; ++i) {
adc_pins[i] = analogPinToPinName(pins[i]);
}

n_channels = n_pins;
return begin(resolution, sample_rate, n_samples, n_buffers);
return begin(resolution, sample_rate, n_samples, n_buffers,start,fixed_adc);
}

void clear();

int start(uint32_t sample_rate);

//void setADCDualMode(bool dm);
//int enableDualMode();
//int disableDualMode();

Comment on lines +68 to +72
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
//void setADCDualMode(bool dm);
//int enableDualMode();
//int disableDualMode();

int stop();
};

class AdvancedADCDual {
private:
size_t n_channels;
pin_size_t adc_pins_unmapped[AN_MAX_ADC_CHANNELS];
AdvancedADC *adcIN1;
AdvancedADC *adcIN2;
Comment on lines +80 to +81
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
AdvancedADC *adcIN1;
AdvancedADC *adcIN2;
AdvancedADC &adc1;
AdvancedADC &adc2;

Those should be passed by reference.

public:

//For now ADC1 will always be one pin, and ADC2 will sample the rest
template <typename ... T>
AdvancedADCDual(pin_size_t p0, T ... args):n_channels(0), adcIN1(nullptr), adcIN2(nullptr){
static_assert(sizeof ...(args) < AN_MAX_ADC_CHANNELS+1,
"A maximum of 5 channels can be sampled successively.");
static_assert (sizeof ...(args) >=2,
"At least two channels are required for Dual Mode ADC.");
for (auto p : {p0, args...}) {
adc_pins_unmapped[n_channels++] = p;
}
}

AdvancedADCDual(): n_channels(0), adcIN1(nullptr), adcIN2(nullptr)
{
}
~AdvancedADCDual();

int begin(AdvancedADC *in1, AdvancedADC *in2,uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers);
int begin(AdvancedADC *in1, AdvancedADC *in2,uint32_t resolution, uint32_t sample_rate,
size_t n_samples, size_t n_buffers, size_t n_pins, pin_size_t *pins) {
if (n_pins > AN_MAX_ADC_CHANNELS) n_pins = AN_MAX_ADC_CHANNELS;
if(n_pins<2) //Cannot run Dual mode with less than two input pins
return(0);
for (size_t i = 0; i < n_pins; ++i) {
adc_pins_unmapped[i] = pins[i];
Serial.println("Pin: "+String(pins[i]));
}
n_channels = n_pins;
return begin(in1, in2, resolution, sample_rate, n_samples, n_buffers);
}
int stop();
};

#endif /* ARDUINO_ADVANCED_ADC_H_ */
Loading
Loading