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 all 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
99 changes: 87 additions & 12 deletions src/AdvancedADC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,14 @@ DMABuffer<Sample> &AdvancedADC::read() {
return NULLBUF;
}

int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers) {
ADCName instance = ADC_NP;
int AdvancedADC::getAssignedADC()
{
return(selected_adc);
}

int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers, bool do_start) {

ADCName instance = ADC_NP;
// Sanity checks.
if (resolution >= AN_ARRAY_SIZE(ADC_RES_LUT) || (descr && descr->pool)) {
return 0;
Expand All @@ -128,7 +133,9 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl
adc_pins[i] = (PinName) (adc_pins[i] & ~(ADC_PIN_ALT_MASK));
}

// Find an ADC that can be used with these set of pins/channels.

// If ADC not specified 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.
Expand All @@ -146,11 +153,12 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl
if (descr->adc.Instance == ((ADC_TypeDef*) tmp_instance)) {
instance = tmp_instance;
adc_pins[0] = pin;
selected_adc=j+1;
}
}
}
}

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

// Configure ADC pins.
pinmap_pinout(adc_pins[0], PinMap_ADC);

//If ADC was not specified ensure the remaining channels are mappable to same 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++) {
Expand All @@ -177,17 +187,18 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl
}
}
}

// 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 +213,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,26 +223,90 @@ 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));
}

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;
}

int AdvancedADC::stop()
{
int AdvancedADC::stop(){

dac_descr_deinit(descr, true);

return 1;
}

AdvancedADC::~AdvancedADC()
{
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);
if(result!=1 || adcIN1->getAssignedADC()!=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);
if(result!=1 || adcIN2->getAssignedADC()!=2)
{
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
62 changes: 59 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 selected_adc;

public:
template <typename ... T>
Expand All @@ -41,21 +43,75 @@ class AdvancedADC {
for (auto p : {p0, args...}) {
adc_pins[n_channels++] = analogPinToPinName(p);
}
dualMode=false;
selected_adc=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 getAssignedADC();
int begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers, bool do_start=true);
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) {
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);
}

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_ */
26 changes: 18 additions & 8 deletions src/HALConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,18 @@ int hal_tim_config(TIM_HandleTypeDef *tim, uint32_t t_freq) {
sConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;

if (tim->Instance == TIM1) {
__HAL_RCC_TIM1_CLK_ENABLE();
__HAL_RCC_TIM1_CLK_ENABLE();
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
__HAL_RCC_TIM1_CLK_ENABLE();
__HAL_RCC_TIM1_CLK_ENABLE();

Please remove any spaces you added.

} else if (tim->Instance == TIM2) {
__HAL_RCC_TIM2_CLK_ENABLE();
} else if (tim->Instance == TIM3) {
} else if (tim->Instance == TIM3) {
__HAL_RCC_TIM3_CLK_ENABLE();
} else if (tim->Instance == TIM4) {
} else if (tim->Instance == TIM4) {
__HAL_RCC_TIM4_CLK_ENABLE();
} else if (tim->Instance == TIM5) {
} else if (tim->Instance == TIM5) {
__HAL_RCC_TIM5_CLK_ENABLE();
} else if (tim->Instance == TIM6) {
} else if (tim->Instance == TIM6) {
__HAL_RCC_TIM6_CLK_ENABLE();
}
}

// Init and config the timer.
__HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);
Expand Down Expand Up @@ -167,10 +167,20 @@ static uint32_t ADC_RANK_LUT[] = {
ADC_REGULAR_RANK_1, ADC_REGULAR_RANK_2, ADC_REGULAR_RANK_3, ADC_REGULAR_RANK_4, ADC_REGULAR_RANK_5
};

int hal_enable_dual_mode() {
LL_ADC_SetMultimode(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_MULTI_DUAL_REG_SIMULT);
return(1);
}

int hal_disable_dual_mode() {
LL_ADC_SetMultimode(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_MULTI_INDEPENDENT);
return(1);
}

int hal_adc_config(ADC_HandleTypeDef *adc, uint32_t resolution, uint32_t trigger, PinName *adc_pins, uint32_t n_channels) {
// Set ADC clock source.
__HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP);

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

Please remove extra spaces that you added.

// Enable ADC clock
if (adc->Instance == ADC1) {
__HAL_RCC_ADC12_CLK_ENABLE();
Expand Down Expand Up @@ -206,7 +216,7 @@ int hal_adc_config(ADC_HandleTypeDef *adc, uint32_t resolution, uint32_t trigger
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5;

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

for (size_t rank=0; rank<n_channels; rank++) {
uint32_t function = pinmap_function(adc_pins[rank], PinMap_ADC);
uint32_t channel = STM_PIN_CHANNEL(function);
Expand Down
2 changes: 2 additions & 0 deletions src/HALConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,7 @@ void hal_dma_update_memory(DMA_HandleTypeDef *dma, void *addr);
int hal_dac_config(DAC_HandleTypeDef *dac, uint32_t channel, uint32_t trigger);
int hal_adc_config(ADC_HandleTypeDef *adc, uint32_t resolution, uint32_t trigger, PinName *adc_pins, uint32_t n_channels);
int hal_i2s_config(I2S_HandleTypeDef *i2s, uint32_t sample_rate, uint32_t mode, bool mck_enable);
int hal_enable_dual_mode();
int hal_disable_dual_mode();

#endif // __HAL_CONFIG_H__
Loading