From 9bd88c028c85ad07b652477c29d5ae81e513ca0d Mon Sep 17 00:00:00 2001 From: Leonardo Cavagnis Date: Wed, 15 Nov 2023 13:12:18 +0100 Subject: [PATCH 1/4] fix adc.begin() to correctly initialize channels according to selected pins --- src/AdvancedADC.cpp | 61 ++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/src/AdvancedADC.cpp b/src/AdvancedADC.cpp index e01c894..518a716 100644 --- a/src/AdvancedADC.cpp +++ b/src/AdvancedADC.cpp @@ -29,18 +29,19 @@ struct adc_descr_t { IRQn_Type dma_irqn; TIM_HandleTypeDef tim; uint32_t tim_trig; - uint32_t pin_alt; DMABufferPool *pool; DMABuffer *dmabuf[2]; }; +static uint32_t pin_alt[3] = {0, ALT0, ALT1}; + static adc_descr_t adc_descr_all[3] = { {{ADC1}, {DMA1_Stream1, {DMA_REQUEST_ADC1}}, DMA1_Stream1_IRQn, {TIM1}, ADC_EXTERNALTRIG_T1_TRGO, - 0, nullptr, {nullptr, nullptr}}, + nullptr, {nullptr, nullptr}}, {{ADC2}, {DMA1_Stream2, {DMA_REQUEST_ADC2}}, DMA1_Stream2_IRQn, {TIM2}, ADC_EXTERNALTRIG_T2_TRGO, - ALT0, nullptr, {nullptr, nullptr}}, + nullptr, {nullptr, nullptr}}, {{ADC3}, {DMA1_Stream3, {DMA_REQUEST_ADC3}}, DMA1_Stream3_IRQn, {TIM3}, ADC_EXTERNALTRIG_T3_TRGO, - ALT1, nullptr, {nullptr, nullptr}}, + nullptr, {nullptr, nullptr}}, }; static uint32_t ADC_RES_LUT[] = { @@ -121,13 +122,28 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl return 0; } + // Clear ALTx pin. + for (size_t i=0; ipool == nullptr) { - // Check if the first channel is connected to this ADC. - PinName pin = (PinName) (adc_pins[0] | descr->pin_alt); - instance = (ADCName) pinmap_peripheral(pin, PinMap_ADC); + for (size_t i=0; instance == ADC_NP && ipool == nullptr && ((ADC_TypeDef*)pinmap_peripheral(pin, PinMap_ADC) == descr->adc.Instance)) { + instance = (ADCName) pinmap_peripheral(pin, PinMap_ADC); + adc_pins[0] = pin; + } } } @@ -138,16 +154,27 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl } // Configure ADC pins. - for (size_t i=0; ipin_alt); - // All channels must share the same instance; if not, bail out - if (instance != pinmap_peripheral(adc_pins[i], PinMap_ADC)) { - return 0; + pinmap_pinout(adc_pins[0], PinMap_ADC); + uint8_t ch_init = 1; + for (size_t i=1; ipool = new DMABufferPool(n_samples, n_channels, n_buffers); if (descr->pool == nullptr) { From f1808b260145d92648e7d4dfce9c1a662ce853cb Mon Sep 17 00:00:00 2001 From: Leonardo Cavagnis Date: Fri, 24 Nov 2023 17:33:07 +0100 Subject: [PATCH 2/4] adding some error checking in adc begin() --- src/AdvancedADC.cpp | 9 +++++---- src/HALConfig.cpp | 8 +++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/AdvancedADC.cpp b/src/AdvancedADC.cpp index 518a716..44536d6 100644 --- a/src/AdvancedADC.cpp +++ b/src/AdvancedADC.cpp @@ -184,21 +184,22 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl descr->dmabuf[1] = descr->pool->allocate(); // Init and config DMA. - hal_dma_config(&descr->dma, descr->dma_irqn, DMA_PERIPH_TO_MEMORY); + if (hal_dma_config(&descr->dma, descr->dma_irqn, DMA_PERIPH_TO_MEMORY) < 0) return 0; // Init and config ADC. - hal_adc_config(&descr->adc, ADC_RES_LUT[resolution], descr->tim_trig, adc_pins, n_channels); + if (hal_adc_config(&descr->adc, ADC_RES_LUT[resolution], descr->tim_trig, adc_pins, n_channels) < 0) return 0; // Link DMA handle to ADC handle, and start the ADC. __HAL_LINKDMA(&descr->adc, DMA_Handle, descr->dma); - HAL_ADC_Start_DMA(&descr->adc, (uint32_t *) descr->dmabuf[0]->data(), descr->dmabuf[0]->size()); + if (HAL_ADC_Start_DMA(&descr->adc, (uint32_t *) descr->dmabuf[0]->data(), descr->dmabuf[0]->size()) != HAL_OK) return 0; // Re/enable DMA double buffer mode. hal_dma_enable_dbm(&descr->dma, descr->dmabuf[0]->data(), descr->dmabuf[1]->data()); // Init, config and start the ADC timer. hal_tim_config(&descr->tim, sample_rate); - HAL_TIM_Base_Start(&descr->tim); + if (HAL_TIM_Base_Start(&descr->tim) != HAL_OK) return 0; + return 1; } diff --git a/src/HALConfig.cpp b/src/HALConfig.cpp index 225029a..9fc10c9 100644 --- a/src/HALConfig.cpp +++ b/src/HALConfig.cpp @@ -195,8 +195,10 @@ int hal_adc_config(ADC_HandleTypeDef *adc, uint32_t resolution, uint32_t trigger adc->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; adc->Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR; - HAL_ADC_Init(adc); - HAL_ADCEx_Calibration_Start(adc, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED); + if (HAL_ADC_Init(adc) != HAL_OK + || HAL_ADCEx_Calibration_Start(adc, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED) != HAL_OK) { + return -1; + } ADC_ChannelConfTypeDef sConfig = {0}; sConfig.Offset = 0; @@ -209,7 +211,7 @@ int hal_adc_config(ADC_HandleTypeDef *adc, uint32_t resolution, uint32_t trigger uint32_t channel = STM_PIN_CHANNEL(function); sConfig.Rank = ADC_RANK_LUT[rank]; sConfig.Channel = __HAL_ADC_DECIMAL_NB_TO_CHANNEL(channel); - HAL_ADC_ConfigChannel(adc, &sConfig); + if (HAL_ADC_ConfigChannel(adc, &sConfig) != HAL_OK) return -1; } return 0; From 0bf0e0a2c847788d21600434777e7a999e4a061e Mon Sep 17 00:00:00 2001 From: Leonardo Cavagnis Date: Fri, 17 Nov 2023 16:34:26 +0100 Subject: [PATCH 3/4] Update docs/readme.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update docs/readme.md Update docs/readme.md Update docs/readme.md Update docs/readme.md update docs/readme.md: add multichannel description doc: update README.md doc: update doc/readme.md Co-Authored-By: Karl Söderby <35461661+karlsoderby@users.noreply.github.com> --- README.md | 40 ++---------- docs/readme.md | 166 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 168 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 0a2afda..f8b3fb8 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,7 @@ - + -`Arduino_AdvancedAnalog` 〰 -=========================== -[![Compile Examples status](https://github.com/arduino-libraries/Arduino_AdvancedAnalog/actions/workflows/compile-examples.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_AdvancedAnalog/actions/workflows/compile-examples.yml) -[![Spell Check status](https://github.com/arduino-libraries/Arduino_AdvancedAnalog/actions/workflows/spell-check.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_AdvancedAnalog/actions/workflows/spell-check.yml) -[![Sync Labels status](https://github.com/arduino-libraries/Arduino_AdvancedAnalog/actions/workflows/sync-labels.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_AdvancedAnalog/actions/workflows/sync-labels.yml) -[![Arduino Lint](https://github.com/arduino-libraries/Arduino_AdvancedAnalog/workflows/Arduino%20Lint/badge.svg)](https://github.com/arduino-libraries/Arduino_AdvancedAnalog/actions?workflow=Arduino+Lint) +# 〰️ Arduino AdvancedAnalog Library -Advanced Analog Library for Arduino Giga. +The Arduino AdvancedAnalog library is designed to offer high performance DAC/ADC applications on boards based on the STM32H7 microcontroller. -## :mag_right: Resources - -* [How to install a library](https://www.arduino.cc/en/guide/libraries) -* [Help Center](https://support.arduino.cc/) -* [Forum](https://forum.arduino.cc) - -## :bug: Bugs & Issues - -If you want to report an issue with this library, you can submit it to the [issue tracker](https://github.com/arduino-libraries/Arduino_AdvancedAnalog/issues) of this repository. Remember to include as much detail as you can about your hardware set-up, code and steps for reproducing the issue. Make sure you're using an original Arduino board. - -## :technologist: Development - -There are many ways to contribute: - -* Improve documentation and examples -* Fix a bug -* Test open Pull Requests -* Implement a new feature -* Discuss potential ways to improve this library - -You can submit your patches directly to this repository as Pull Requests. Please provide a detailed description of the problem you're trying to solve and make sure you test on real hardware. - -## :yellow_heart: Donations - -This open-source code is maintained by Arduino with the help of the community. We invest a considerable amount of time in testing code, optimizing it and introducing new features. Please consider [donating](https://www.arduino.cc/en/donate/) or [sponsoring](https://github.com/sponsors/arduino) to support our work, as well as [buying original Arduino boards](https://store.arduino.cc/) which is the best way to make sure our effort can continue in the long term. - -## Known issues -* ADC is running at the slowest possible clock (PCLK), should probably set up a PLL and change the clock source. +📖 For more information about this library please read the documentation [here](./docs/). \ No newline at end of file diff --git a/docs/readme.md b/docs/readme.md index 55cf3d8..3c01f87 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -1,12 +1,174 @@ # Arduino_AdvancedAnalog library -The **Arduino_AdvancedAnalog** library is designed for high performance DAC/ADC applications on boards based on the STM32H747XI microcontroller: +[![License](https://img.shields.io/badge/License-LGPLv2.1-blue.svg)](../LICENSE) + +The **Arduino_AdvancedAnalog** library is designed to offer high performance DAC/ADC applications on boards based on the STM32H747XI microcontroller: - [Arduino GIGA R1 WiFi](https://store.arduino.cc/products/giga-r1-wifi) - [Arduino Portenta H7](https://store.arduino.cc/products/portenta-h7) -To use this library: +## Features + +- ADC/DAC parameters fine tuning: resolution, channel number, queue number and size +- ADC acquisition with DMA in double buffering mode +- ADC Multichannel acquisition +- DAC Multichannel writing +- Storing ADC samples history in multiple queues +## Guides + +To learn more about using the DAC & ADC on the GIGA R1 WiFi, check out the [GIGA Advanced DAC/ADC Guide](https://docs.arduino.cc/tutorials/giga-r1-wifi/giga-audio). + +This includes examples such as audio playback from USB storage, generate sine waves and more. +## Usage + +### ADC + +To use this library for ADC applications, you must have a supported Arduino board and include the AdvancedAnalog library in your Arduino sketch. Here is a minimal example: + +```cpp +#include + +AdvancedADC adc1(A0); + +void setup() { + Serial.begin(9600); + + // Initialize ADC with: resolution, sample rate, number of samples per channel, queue depth + if (!adc1.begin(AN_RESOLUTION_16, 16000, 32, 64)) { + Serial.println("Failed to start ADC!"); + while (1); + } +} + +void loop() { + // Check if an ADC measurement is ready + if (adc1.available()) { + // Get read buffer + SampleBuffer buf = adc1.read(); + + // Print sample from read buffer + Serial.println(buf[0]); + + // Release read buffer + buf.release(); + } +} +``` + +#### ADC Multichannel (GIGA R1 WiFi) +This library supports concurrent usage of up to **three** ADCs (_ADC1_, _ADC2_ and _ADC3_). +Each ADC instance can handle up to **five** channels. + +**Note:** It's important to be aware that certain pins cannot be used across multiple ADCs or cannot share the same ADC. + +*Please ensure that you refer to tables below when configuring your project to avoid conflicts in pin assignments.* + +Below is a table illustrating the pin mapping for each ADC in **Arduino Giga R1 WiFi**: + +| Pin | ADC1 | ADC2 | ADC3 | +|-------|-------|-------|-------| +| A0 | X | X | | +| A1 | X | X | | +| A2 | X | X | | +| A3 | X | X | | +| A4 | X | X | | +| A5 | X | X | X | +| A6 | X | X | X | +| A7 | X | | | +| A8 | | | X | +| A9 | | | X | +| A10 | X | X | | +| A11 | X | X | | + +Here is a example for the Arduino GIGA R1 WiFi: + +```cpp +#include + +AdvancedADC adc_a(A0, A1); +/* Mapped to ADC1 */ + +AdvancedADC adc_b(A2); +/* Mapped to ADC2, because ADC1 is occupied by A0 and A1 */ +void setup() { +... ``` + +#### ADC Multichannel (Portenta H7) + +Below is a table illustrating the pin mapping for each ADC in **Portenta H7**: + +| Pin | ADC1 | ADC2 | ADC3 | +|-------|-------|-------|-------| +| A0 | X | X | | +| A1 | X | X | | +| A2 | | | X | +| A3 | | | X | +| A4 | X | X | X | +| A5 | X | X | | +| A6 | X | X | | +| A7 | X | X | | + +Here is an example for the Portenta H7: + +```cpp #include + +AdvancedADC adc_c(A2, A3, A4); +/* Mapped to ADC3 */ + +AdvancedADC adc_d(A5); +/* Mapped to ADC1 */ + +void setup() { +... ``` +### DAC + +To use this library for DAC application, you must have a supported Arduino board and include the AdvancedAnalog library in your Arduino sketch. Here is a minimal example for the Arduino GIGA R1 WiFi: + +```cpp +#include + +AdvancedDAC dac1(A12); + +void setup() { + Serial.begin(9600); + + // Initialize DAC with: resolution, sample rate, number of samples per channel, queue depth + if (!dac1.begin(AN_RESOLUTION_12, 8000, 32, 64)) { + Serial.println("Failed to start DAC!"); + while (1); + } +} + +void loop() { + if (dac1.available()) { + + // Get a free buffer for writing + SampleBuffer buf = dac1.dequeue(); + + // Write data to buffer (Even position: 0, Odd position: 0xFFF) + for (int i=0; i Date: Wed, 6 Dec 2023 10:41:49 +0100 Subject: [PATCH 4/4] fixes according to @iabdalkader review Update src/AdvancedADC.cpp Update src/AdvancedADC.cpp Update src/AdvancedADC.cpp Update src/AdvancedADC.cpp Update src/AdvancedADC.cpp Update src/AdvancedADC.cpp Update src/AdvancedADC.cpp Update src/AdvancedADC.cpp Update src/HALConfig.cpp Update src/AdvancedADC.cpp Update src/AdvancedADC.cpp Co-Authored-By: Ibrahim Abdelkader --- src/AdvancedADC.cpp | 52 +++++++++++++++++++++++++++++---------------- src/HALConfig.cpp | 4 +++- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/src/AdvancedADC.cpp b/src/AdvancedADC.cpp index 44536d6..ee4ae1f 100644 --- a/src/AdvancedADC.cpp +++ b/src/AdvancedADC.cpp @@ -22,6 +22,7 @@ #include "AdvancedADC.h" #define ADC_NP ((ADCName) NC) +#define ADC_PIN_ALT_MASK (uint32_t) (ALT0 | ALT1 ) struct adc_descr_t { ADC_HandleTypeDef adc; @@ -33,7 +34,7 @@ struct adc_descr_t { DMABuffer *dmabuf[2]; }; -static uint32_t pin_alt[3] = {0, ALT0, ALT1}; +static uint32_t adc_pin_alt[3] = {0, ALT0, ALT1}; static adc_descr_t adc_descr_all[3] = { {{ADC1}, {DMA1_Stream1, {DMA_REQUEST_ADC1}}, DMA1_Stream1_IRQn, {TIM1}, ADC_EXTERNALTRIG_T1_TRGO, @@ -124,25 +125,28 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl // Clear ALTx pin. for (size_t i=0; ipool == nullptr && ((ADC_TypeDef*)pinmap_peripheral(pin, PinMap_ADC) == descr->adc.Instance)) { - instance = (ADCName) pinmap_peripheral(pin, PinMap_ADC); - adc_pins[0] = pin; + 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; + } } } } @@ -157,11 +161,13 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl pinmap_pinout(adc_pins[0], PinMap_ADC); uint8_t ch_init = 1; for (size_t i=1; ipool = new DMABufferPool(n_samples, n_channels, n_buffers); @@ -184,21 +192,29 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl descr->dmabuf[1] = descr->pool->allocate(); // Init and config DMA. - if (hal_dma_config(&descr->dma, descr->dma_irqn, DMA_PERIPH_TO_MEMORY) < 0) return 0; + if (hal_dma_config(&descr->dma, descr->dma_irqn, DMA_PERIPH_TO_MEMORY) < 0) { + return 0; + } // Init and config ADC. - if (hal_adc_config(&descr->adc, ADC_RES_LUT[resolution], descr->tim_trig, adc_pins, n_channels) < 0) return 0; + if (hal_adc_config(&descr->adc, ADC_RES_LUT[resolution], descr->tim_trig, adc_pins, n_channels) < 0) { + return 0; + } // Link DMA handle to ADC handle, and start the ADC. __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; + if (HAL_ADC_Start_DMA(&descr->adc, (uint32_t *) descr->dmabuf[0]->data(), descr->dmabuf[0]->size()) != HAL_OK) { + return 0; + } // Re/enable DMA double buffer mode. hal_dma_enable_dbm(&descr->dma, descr->dmabuf[0]->data(), descr->dmabuf[1]->data()); // Init, config and start the ADC timer. hal_tim_config(&descr->tim, sample_rate); - if (HAL_TIM_Base_Start(&descr->tim) != HAL_OK) return 0; + if (HAL_TIM_Base_Start(&descr->tim) != HAL_OK) { + return 0; + } return 1; } diff --git a/src/HALConfig.cpp b/src/HALConfig.cpp index 9fc10c9..f6a7103 100644 --- a/src/HALConfig.cpp +++ b/src/HALConfig.cpp @@ -211,7 +211,9 @@ int hal_adc_config(ADC_HandleTypeDef *adc, uint32_t resolution, uint32_t trigger uint32_t channel = STM_PIN_CHANNEL(function); sConfig.Rank = ADC_RANK_LUT[rank]; sConfig.Channel = __HAL_ADC_DECIMAL_NB_TO_CHANNEL(channel); - if (HAL_ADC_ConfigChannel(adc, &sConfig) != HAL_OK) return -1; + if (HAL_ADC_ConfigChannel(adc, &sConfig) != HAL_OK) { + return -1; + } } return 0;