Skip to content

Commit 0fcd53e

Browse files
Merge pull request #48 from leonardocavagnis/adc_config_fix
Fixing ADC initialization function to work properly on Portenta H7
2 parents 9e610e2 + 065318b commit 0fcd53e

File tree

4 files changed

+240
-62
lines changed

4 files changed

+240
-62
lines changed

Diff for: README.md

+4-36
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,7 @@
1-
<img src="https://content.arduino.cc/website/Arduino_logo_teal.svg" height="100" align="right" />
1+
22

3-
`Arduino_AdvancedAnalog`
4-
===========================
5-
[![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)
6-
[![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)
7-
[![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)
8-
[![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)
3+
# 〰️ Arduino AdvancedAnalog Library
94

10-
Advanced Analog Library for Arduino Giga.
5+
The Arduino AdvancedAnalog library is designed to offer high performance DAC/ADC applications on boards based on the STM32H7 microcontroller.
116

12-
## :mag_right: Resources
13-
14-
* [How to install a library](https://www.arduino.cc/en/guide/libraries)
15-
* [Help Center](https://support.arduino.cc/)
16-
* [Forum](https://forum.arduino.cc)
17-
18-
## :bug: Bugs & Issues
19-
20-
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.
21-
22-
## :technologist: Development
23-
24-
There are many ways to contribute:
25-
26-
* Improve documentation and examples
27-
* Fix a bug
28-
* Test open Pull Requests
29-
* Implement a new feature
30-
* Discuss potential ways to improve this library
31-
32-
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.
33-
34-
## :yellow_heart: Donations
35-
36-
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.
37-
38-
## Known issues
39-
* ADC is running at the slowest possible clock (PCLK), should probably set up a PLL and change the clock source.
7+
📖 For more information about this library please read the documentation [here](./docs/).

Diff for: docs/readme.md

+164-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,174 @@
11
# Arduino_AdvancedAnalog library
22

3-
The **Arduino_AdvancedAnalog** library is designed for high performance DAC/ADC applications on boards based on the STM32H747XI microcontroller:
3+
[![License](https://img.shields.io/badge/License-LGPLv2.1-blue.svg)](../LICENSE)
4+
5+
The **Arduino_AdvancedAnalog** library is designed to offer high performance DAC/ADC applications on boards based on the STM32H747XI microcontroller:
46
- [Arduino GIGA R1 WiFi](https://store.arduino.cc/products/giga-r1-wifi)
57
- [Arduino Portenta H7](https://store.arduino.cc/products/portenta-h7)
68

7-
To use this library:
9+
## Features
10+
11+
- ADC/DAC parameters fine tuning: resolution, channel number, queue number and size
12+
- ADC acquisition with DMA in double buffering mode
13+
- ADC Multichannel acquisition
14+
- DAC Multichannel writing
15+
- Storing ADC samples history in multiple queues
16+
## Guides
17+
18+
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).
19+
20+
This includes examples such as audio playback from USB storage, generate sine waves and more.
21+
## Usage
22+
23+
### ADC
24+
25+
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:
26+
27+
```cpp
28+
#include <Arduino_AdvancedAnalog.h>
29+
30+
AdvancedADC adc1(A0);
31+
32+
void setup() {
33+
Serial.begin(9600);
34+
35+
// Initialize ADC with: resolution, sample rate, number of samples per channel, queue depth
36+
if (!adc1.begin(AN_RESOLUTION_16, 16000, 32, 64)) {
37+
Serial.println("Failed to start ADC!");
38+
while (1);
39+
}
40+
}
41+
42+
void loop() {
43+
// Check if an ADC measurement is ready
44+
if (adc1.available()) {
45+
// Get read buffer
46+
SampleBuffer buf = adc1.read();
47+
48+
// Print sample from read buffer
49+
Serial.println(buf[0]);
50+
51+
// Release read buffer
52+
buf.release();
53+
}
54+
}
55+
```
56+
57+
#### ADC Multichannel (GIGA R1 WiFi)
58+
This library supports concurrent usage of up to **three** ADCs (_ADC1_, _ADC2_ and _ADC3_).
59+
Each ADC instance can handle up to **five** channels.
60+
61+
**Note:** It's important to be aware that certain pins cannot be used across multiple ADCs or cannot share the same ADC.
62+
63+
*Please ensure that you refer to tables below when configuring your project to avoid conflicts in pin assignments.*
64+
65+
Below is a table illustrating the pin mapping for each ADC in **Arduino Giga R1 WiFi**:
66+
67+
| Pin | ADC1 | ADC2 | ADC3 |
68+
|-------|-------|-------|-------|
69+
| A0 | X | X | |
70+
| A1 | X | X | |
71+
| A2 | X | X | |
72+
| A3 | X | X | |
73+
| A4 | X | X | |
74+
| A5 | X | X | X |
75+
| A6 | X | X | X |
76+
| A7 | X | | |
77+
| A8 | | | X |
78+
| A9 | | | X |
79+
| A10 | X | X | |
80+
| A11 | X | X | |
81+
82+
Here is a example for the Arduino GIGA R1 WiFi:
83+
84+
```cpp
85+
#include <Arduino_AdvancedAnalog.h>
86+
87+
AdvancedADC adc_a(A0, A1);
88+
/* Mapped to ADC1 */
89+
90+
AdvancedADC adc_b(A2);
91+
/* Mapped to ADC2, because ADC1 is occupied by A0 and A1 */
892
93+
void setup() {
94+
...
995
```
96+
97+
#### ADC Multichannel (Portenta H7)
98+
99+
Below is a table illustrating the pin mapping for each ADC in **Portenta H7**:
100+
101+
| Pin | ADC1 | ADC2 | ADC3 |
102+
|-------|-------|-------|-------|
103+
| A0 | X | X | |
104+
| A1 | X | X | |
105+
| A2 | | | X |
106+
| A3 | | | X |
107+
| A4 | X | X | X |
108+
| A5 | X | X | |
109+
| A6 | X | X | |
110+
| A7 | X | X | |
111+
112+
Here is an example for the Portenta H7:
113+
114+
```cpp
10115
#include <Arduino_AdvancedAnalog.h>
116+
117+
AdvancedADC adc_c(A2, A3, A4);
118+
/* Mapped to ADC3 */
119+
120+
AdvancedADC adc_d(A5);
121+
/* Mapped to ADC1 */
122+
123+
void setup() {
124+
...
11125
```
12126
127+
### DAC
128+
129+
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:
130+
131+
```cpp
132+
#include <Arduino_AdvancedAnalog.h>
133+
134+
AdvancedDAC dac1(A12);
135+
136+
void setup() {
137+
Serial.begin(9600);
138+
139+
// Initialize DAC with: resolution, sample rate, number of samples per channel, queue depth
140+
if (!dac1.begin(AN_RESOLUTION_12, 8000, 32, 64)) {
141+
Serial.println("Failed to start DAC!");
142+
while (1);
143+
}
144+
}
145+
146+
void loop() {
147+
if (dac1.available()) {
148+
149+
// Get a free buffer for writing
150+
SampleBuffer buf = dac1.dequeue();
151+
152+
// Write data to buffer (Even position: 0, Odd position: 0xFFF)
153+
for (int i=0; i<buf.size(); i++) {
154+
buf.data()[i] = (i % 2 == 0) ? 0: 0xFFF;
155+
}
156+
157+
// Write the buffer to DAC
158+
dac1.write(buf);
159+
}
160+
}
161+
```
162+
163+
## Examples
164+
- **[Advanced](../examples/Advanced):** This folder contains examples showing how to configure ADC/DAC to read/write data.
165+
- **[Beginner](../examples/Beginner):** This folder contains examples showing how to generate waveforms with DAC.
166+
167+
## API
168+
169+
The API documentation can be found [here](./api.md).
170+
171+
## License
172+
173+
This library is released under the [LGPLv2.1 license](../LICENSE).
174+

Diff for: src/AdvancedADC.cpp

+65-21
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,27 @@
2222
#include "AdvancedADC.h"
2323

2424
#define ADC_NP ((ADCName) NC)
25+
#define ADC_PIN_ALT_MASK (uint32_t) (ALT0 | ALT1 )
2526

2627
struct adc_descr_t {
2728
ADC_HandleTypeDef adc;
2829
DMA_HandleTypeDef dma;
2930
IRQn_Type dma_irqn;
3031
TIM_HandleTypeDef tim;
3132
uint32_t tim_trig;
32-
uint32_t pin_alt;
3333
DMABufferPool<Sample> *pool;
3434
DMABuffer<Sample> *dmabuf[2];
3535
};
3636

37+
static uint32_t adc_pin_alt[3] = {0, ALT0, ALT1};
38+
3739
static adc_descr_t adc_descr_all[3] = {
3840
{{ADC1}, {DMA1_Stream1, {DMA_REQUEST_ADC1}}, DMA1_Stream1_IRQn, {TIM1}, ADC_EXTERNALTRIG_T1_TRGO,
39-
0, nullptr, {nullptr, nullptr}},
41+
nullptr, {nullptr, nullptr}},
4042
{{ADC2}, {DMA1_Stream2, {DMA_REQUEST_ADC2}}, DMA1_Stream2_IRQn, {TIM2}, ADC_EXTERNALTRIG_T2_TRGO,
41-
ALT0, nullptr, {nullptr, nullptr}},
43+
nullptr, {nullptr, nullptr}},
4244
{{ADC3}, {DMA1_Stream3, {DMA_REQUEST_ADC3}}, DMA1_Stream3_IRQn, {TIM3}, ADC_EXTERNALTRIG_T3_TRGO,
43-
ALT1, nullptr, {nullptr, nullptr}},
45+
nullptr, {nullptr, nullptr}},
4446
};
4547

4648
static uint32_t ADC_RES_LUT[] = {
@@ -121,13 +123,31 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl
121123
return 0;
122124
}
123125

126+
// Clear ALTx pin.
127+
for (size_t i=0; i<n_channels; i++) {
128+
adc_pins[i] = (PinName) (adc_pins[i] & ~(ADC_PIN_ALT_MASK));
129+
}
130+
124131
// Find an ADC that can be used with these set of pins/channels.
125-
for (size_t i=0; instance == ADC_NP && i<AN_ARRAY_SIZE(adc_descr_all); i++) {
126-
descr = &adc_descr_all[i];
127-
if (descr->pool == nullptr) {
128-
// Check if the first channel is connected to this ADC.
129-
PinName pin = (PinName) (adc_pins[0] | descr->pin_alt);
130-
instance = (ADCName) pinmap_peripheral(pin, PinMap_ADC);
132+
for (size_t i=0; instance == ADC_NP && i<AN_ARRAY_SIZE(adc_pin_alt); i++) {
133+
// Calculate alternate function pin.
134+
PinName pin = (PinName) (adc_pins[0] | adc_pin_alt[i]); // First pin decides the ADC.
135+
136+
// Check if pin is mapped.
137+
if (pinmap_find_peripheral(pin, PinMap_ADC) == NC) {
138+
break;
139+
}
140+
141+
// Find the first free ADC according to the available ADCs on pin.
142+
for (size_t j=0; instance == ADC_NP && j<AN_ARRAY_SIZE(adc_descr_all); j++) {
143+
descr = &adc_descr_all[j];
144+
if (descr->pool == nullptr) {
145+
ADCName tmp_instance = (ADCName) pinmap_peripheral(pin, PinMap_ADC);
146+
if (descr->adc.Instance == ((ADC_TypeDef*) tmp_instance)) {
147+
instance = tmp_instance;
148+
adc_pins[0] = pin;
149+
}
150+
}
131151
}
132152
}
133153

@@ -138,14 +158,29 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl
138158
}
139159

140160
// Configure ADC pins.
141-
for (size_t i=0; i<n_channels; i++) {
142-
// Set the alternate pin names for this ADC instance.
143-
adc_pins[i] = (PinName) (adc_pins[i] | descr->pin_alt);
144-
// All channels must share the same instance; if not, bail out
145-
if (instance != pinmap_peripheral(adc_pins[i], PinMap_ADC)) {
146-
return 0;
161+
pinmap_pinout(adc_pins[0], PinMap_ADC);
162+
uint8_t ch_init = 1;
163+
for (size_t i=1; i<n_channels; i++) {
164+
for (size_t j=0; j<AN_ARRAY_SIZE(adc_pin_alt); j++) {
165+
// Calculate alternate function pin.
166+
PinName pin = (PinName) (adc_pins[i] | adc_pin_alt[j]);
167+
// Check if pin is mapped.
168+
if (pinmap_find_peripheral(pin, PinMap_ADC) == NC) {
169+
break;
170+
}
171+
// Check if pin is connected to the selected ADC.
172+
if (instance == pinmap_peripheral(pin, PinMap_ADC)) {
173+
pinmap_pinout(pin, PinMap_ADC);
174+
adc_pins[i] = pin;
175+
ch_init++;
176+
break;
177+
}
147178
}
148-
pinmap_pinout(adc_pins[i], PinMap_ADC);
179+
}
180+
181+
// All channels must share the same instance; if not, bail out.
182+
if (ch_init < n_channels) {
183+
return 0;
149184
}
150185

151186
// Allocate DMA buffer pool.
@@ -157,21 +192,30 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl
157192
descr->dmabuf[1] = descr->pool->allocate();
158193

159194
// Init and config DMA.
160-
hal_dma_config(&descr->dma, descr->dma_irqn, DMA_PERIPH_TO_MEMORY);
195+
if (hal_dma_config(&descr->dma, descr->dma_irqn, DMA_PERIPH_TO_MEMORY) < 0) {
196+
return 0;
197+
}
161198

162199
// Init and config ADC.
163-
hal_adc_config(&descr->adc, ADC_RES_LUT[resolution], descr->tim_trig, adc_pins, n_channels);
200+
if (hal_adc_config(&descr->adc, ADC_RES_LUT[resolution], descr->tim_trig, adc_pins, n_channels) < 0) {
201+
return 0;
202+
}
164203

165204
// Link DMA handle to ADC handle, and start the ADC.
166205
__HAL_LINKDMA(&descr->adc, DMA_Handle, descr->dma);
167-
HAL_ADC_Start_DMA(&descr->adc, (uint32_t *) descr->dmabuf[0]->data(), descr->dmabuf[0]->size());
206+
if (HAL_ADC_Start_DMA(&descr->adc, (uint32_t *) descr->dmabuf[0]->data(), descr->dmabuf[0]->size()) != HAL_OK) {
207+
return 0;
208+
}
168209

169210
// Re/enable DMA double buffer mode.
170211
hal_dma_enable_dbm(&descr->dma, descr->dmabuf[0]->data(), descr->dmabuf[1]->data());
171212

172213
// Init, config and start the ADC timer.
173214
hal_tim_config(&descr->tim, sample_rate);
174-
HAL_TIM_Base_Start(&descr->tim);
215+
if (HAL_TIM_Base_Start(&descr->tim) != HAL_OK) {
216+
return 0;
217+
}
218+
175219
return 1;
176220
}
177221

Diff for: src/HALConfig.cpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,10 @@ int hal_adc_config(ADC_HandleTypeDef *adc, uint32_t resolution, uint32_t trigger
195195
adc->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
196196
adc->Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
197197

198-
HAL_ADC_Init(adc);
199-
HAL_ADCEx_Calibration_Start(adc, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);
198+
if (HAL_ADC_Init(adc) != HAL_OK
199+
|| HAL_ADCEx_Calibration_Start(adc, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED) != HAL_OK) {
200+
return -1;
201+
}
200202

201203
ADC_ChannelConfTypeDef sConfig = {0};
202204
sConfig.Offset = 0;
@@ -209,7 +211,9 @@ int hal_adc_config(ADC_HandleTypeDef *adc, uint32_t resolution, uint32_t trigger
209211
uint32_t channel = STM_PIN_CHANNEL(function);
210212
sConfig.Rank = ADC_RANK_LUT[rank];
211213
sConfig.Channel = __HAL_ADC_DECIMAL_NB_TO_CHANNEL(channel);
212-
HAL_ADC_ConfigChannel(adc, &sConfig);
214+
if (HAL_ADC_ConfigChannel(adc, &sConfig) != HAL_OK) {
215+
return -1;
216+
}
213217
}
214218

215219
return 0;

0 commit comments

Comments
 (0)