Skip to content

Commit 708477a

Browse files
More Analog IO content
1 parent 09b955c commit 708477a

3 files changed

Lines changed: 48 additions & 8 deletions

File tree

docs/api-reference/platform/Callback.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ auto lambdaHandler = [&](uint8_t code, char const * message) {
9494
};
9595
```
9696

97-
We can do that by just passing in the lambda variable:
97+
We can do that by just passing in the lambda variable to the callback constructor:
9898

9999
```cpp
100100
addEventHandler(mbed::callback(lambdaHandler));
@@ -171,10 +171,13 @@ void passEventToOtherClass(SomeOtherClass & instance, uint8_t code) {
171171
You could do this with a lambda like so:
172172
173173
```cpp
174-
EventHandler handler([&](uint8_t code, char const * message) { return passEventToOtherClass(otherInstance, code); });
174+
auto handler = [&](uint8_t code, char const * message) {
175+
return passEventToOtherClass(otherInstance, code);
176+
};
177+
addEventHandler(mbed::callback(handler));
175178
```
176179

177-
## Example
180+
## Worked Example
178181

179182
Suppose you have an ADC class which reads data from hardware, and you want that data to be passed to a low-pass filter each time a new sample is available. There are multiple ADCs and multiple low-pass filters, so you cannot use global functions. This could be implemented in the following manner:
180183

docs/how-to-use/analog-io.md

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,53 @@ SAR ADCs are a good compromise option as they can be made with fairly high resol
3131

3232
The large majority of Mbed microcontrollers that have ADCs use SAR ADCs, so it's important to understand both the hardware and the software configuration in order to see how accurate your analog inputs really are.
3333

34-
#### Voltage References
34+
#### Voltage References and ADC Readings
35+
36+
All ADCs have a reference voltage, which is generally the highest analog voltage that you expect to work with in a system. All ADC readings are generated as a percent of this reference voltage. Some microcontrollers have a dedicated reference voltage input, while others use the analog VDD voltage, or an internally generated reference.
37+
38+
For example, suppose you have a 12-bit ADC and it produces a reading of 1000 counts. You'd first convert this to a percentage by dividing `1000 / (2^12 - 1)`, giving 0.244 (24.4%). Then, you would multiply that by the reference voltage to obtain the actual input voltage. If your reference voltage is 3.3V, this ADC reading would convert to about 0.805V.
39+
40+
!!! note "Reference Voltage Value"
41+
On Mbed, the value of the reference voltage is often available through the `MBED_CONF_TARGET_DEFAULT_ADC_VREF` definition, though this is not set up for every target yet.
42+
43+
If you are creating a custom target, be sure to override the `target.default-adc-vref` setting based on the board so that Mbed knows what the reference voltage is!
3544

3645
#### Accuracy/ENOB
3746

47+
There are many different ways to express ADC accuracy, and a full description would be too long for this document. However, it is important to understand the basics in order to determine if the onboard ADC on your Mbed target is appropriate for your needs. To that end, there are at least three concepts you should be aware of when assessing ADC accuracy:
48+
49+
- **Offset Error** is how far off the reading could be from the actual voltage due to analog inaccuracy in the ADC. Offset error generally refers to error that is constant for a given part under given conditions -- it doesn't change based on the input voltage and can be calibrated out.
50+
- For example, if you had a 12-bit ADC with an offset error of +-5 bits, then that means the error due to offset could be +-0.12%, or +-4.0mV (assuming a 3.3V ADC)
51+
- **Integral Non-Linearity** (or INL) is the maximum error that can be introduced by non-linearity of the ADC, after correcting for offset error. Like offset error, INL is usually expressed in bits or percent full scale range. Unlike offset error, INL cannot be calibrated out as it depends on the input voltage being read.
52+
- **Effective Number of Bits** (or ENOB) is the number of bits of an *ideal* ADC that the ADC on your part actually has. ENOB is calculated by factoring in offset and INL together, along with other ADC error sources like noise, differential nonlinearity, and sampling clock jitter. One way to think about ENOB is that if you were to reduce your samples to only ENOB bits, you would not see any measurable ADC errors at all.
53+
- For example, the RP2040 has a 12-bit ADC on paper, but only has an ENOB of 8.7 bits. This means that if you care about the ~four lowest bits of each measurement, you will need to understand and contend with the various internal error sources of the ADC.
54+
55+
For many simple applications, it is true that these errors are small compared to the overall range and resolution of the ADC. However, for anything requiring even moderate precision, it is worth taking a careful look at these parameters in your chip datasheet before continuing with your design. Internal ADCs in microcontrollers are often designed for speed and compactness, at the detriment of accuracy at noise. If you need accurate analog sensing in your design, you may wish to consider using an external ADC instead.
56+
57+
For even more explanation of ADC errors, see [here](https://www.tek.com/en/blog/understanding-enob).
58+
3859
#### Conversion Time
60+
61+
Analog to digital converts generally experience a tradeoff between conversion time and resolution (specifically, ENOB). For SAR ADCs, this is because the ADC operates using a binary search, so the more bits it needs to binary search, the longer it needs to run. And for all types of ADCs, a longer conversion time provides the ability to average multiple samples, decreasing noise (and therefore increasing ENOB).
62+
63+
Unfortunately, Mbed OS does not currently have an API to configure ADC settings such as averaging and number of bits, so this is set in the HAL layer and not modifiable by the user. Settings vary for each target, but *generally* the following is used:
64+
65+
* Averaging disabled, if present
66+
* Highest possible bit resolution used
67+
* Other settings configured for highest possible conversion speed (i.e. fastest clock available provided to the ADC)
68+
69+
!!! note
70+
We would love to add an API by which these settings can be configured, so keep a lookout!
71+
72+
In ARM microcontrollers, *generally speaking*, the ADC runs at between 100ksps and 1Msps, and the conversion time will be in the low double digit range.
73+
3974
#### Aliasing
4075
### Using `AnalogIn`
4176
## Analog Outputs
4277
### DAC Basics
4378

4479
!!! note "Don't confuse analog outputs with PWM!"
45-
It's common to confuse a "true" analog output (a DAC) with a PWM output. These are not the same thing! A true analog output outputs an actual analog voltage, while a PWM output outputs a square wave that averages out into an analog voltage. It is possible to approximage an analog voltage using a PWM output, but you would need an external filtering circuit, and this comes with other downsides (limited current sourcing capability, voltage ripple, etc). Meanwhile, an actual DAC just gives you an exact analog voltage, no muss, no fuss.
80+
It's common to confuse a "true" analog output (a DAC) with a PWM output. These are not the same thing! A true analog output outputs an actual analog voltage, while a PWM output outputs a square wave that averages out into an analog voltage. It is possible to approximate an analog voltage using a PWM output, but you would need an external filtering circuit, and this comes with other downsides (limited current sourcing capability, voltage ripple, etc). Meanwhile, an actual DAC just gives you an exact analog voltage, no muss, no fuss.
4681

4782
And yet... the Arduino framework continues to mislead people about this to this day by referring to setting a PWM as an "[analog write](https://docs.arduino.cc/language-reference/en/functions/analog-io/analogWrite/)".
4883

docs/how-to-use/io-basics.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# I/O Pin Basics
1+
# I/O Pins
22

33
Inputs and outputs, usually shortened to I/O, are the bread and butter of microcontroller functionality. Sure, you have your more complex busses and signals like I2C and PWM, but, at the end of the day, a lot of times you just need to read or write a signal on a pin.
44

@@ -11,7 +11,7 @@ Generally speaking, there are four kinds of I/O:
1111
- Analog inputs (ADCs)
1212
- Analog outputs (DACs)
1313

14-
Mbed has several different classes that allow access to these functions, and we'll go through them all in this how-to guide.
14+
Mbed has several different classes that allow access to these functions, and we'll go through them all here.
1515

1616
## Digital I/O
1717
### Digital Outputs (`DigitalOut`)
@@ -208,7 +208,7 @@ int main()
208208
{
209209
// note: This assumes that the button needs a pullup -- some boards may need a pull down or something else!
210210
InterruptIn buttonIn(BUTTON1, PullUp);
211-
buttonIn.rise(onRisingEdge);
211+
buttonIn.rise(mbed::callback(onRisingEdge));
212212

213213
while(true)
214214
{
@@ -228,3 +228,5 @@ In this example, we pass the `onRisingEdge` function as a callback to the interr
228228
!!! warning "Debouncing"
229229
If using an InterruptIn to read a button in a real project, you will need some form of debouncing circuit between the button and the MCU. This is because mechanical buttons are very noisy and can generate multiple edges when pressed. If you don't filter these out, these edges could cause the interrupt to trigger constantly and monopolize your CPU!
230230

231+
Also note that the `InterruptIn::fall()` function is available if you would like to set a falling-edge interrupt instead. Both rising and falling interrupts can be set on the same pin, and Mbed will execute the correct one depending on what happened to the pin. However, note that if both types of edge occur in quick succession (microseconds apart), only some targets are able to log both these events and call both callbacks. Other targets (including all STM32 chips) only have a single interrupt register for both edge types, so they will only execute the callback corresponding to the second edge.
232+

0 commit comments

Comments
 (0)