This is only a preview of the June 2025 issue of Practical Electronics. You can view 0 of the 80 pages in the full issue. Articles in this series:
Items relevant to "Intelligent Dual Hybrid Power Supply, part one":
Articles in this series:
Articles in this series:
Articles in this series:
Articles in this series:
Items relevant to "Skill Tester 9000, Part 2":
Articles in this series:
|
Circuit Surgery
Regular clinic by Ian Bell
Topics in digital signal processing –
Implementing DSP on a microcontroller, part one
W
e are looking at various
topics related to digital signal
processing (DSP).
DSP covers a wide range of electronics
applications where signals are manipulated, analysed, generated, stored or
displayed as digital data but originate
from and/or are converted to real-world
signals for interaction with humans or
other parts of the physical world.
Fig.1 shows the key elements of a
generic DSP system with a signal path
from an analog input via digital processing to an analog output. This does not
necessarily represent every DSP system
(not all have all the parts shown), but
it serves as a reference for the various
subsystems we will look at.
In our discussions on DSP so far, we
have covered concepts relating to all the
stages in the generic DSP system in Fig.1.
The earlier articles focused on sampling, filtering and data conversion. Many
of the LTspice simulations used in them to
illustrate the ideas discussed can be easily
related to real circuit implementations,
even if we used idealised components
such as the behavioural sampler and
filters provided in the LTspice library.
Our more recent discussions on
digital filters have also used LTspice
simulations, but these are more abstract
– effectively just performing the filter
maths in LTspice so we can use LTspice’s
analysis functions to plot the filters’ responses. Real implementations require
some additional considerations, which
is what we will be looking at next.
There are two fundamental ways of
implementing a DSP function such as
filtering: directly in digital hardware, or
in software. We will look briefly at hardware, cover some general topics related to
implementing arithmetic operations and
then discuss software implementation
Analog
In
Antialiasing
filter
Sample and
hold
on a microcontroller in more depth, including an example filter.
Digital filtering in hardware
For the FIR filters we have been discussing, we can build a digital circuit
based on the structure shown in Fig.2.
This is the same structure used in recent
articles, except that the addition operations are shown as a single block. The
Δt delay blocks are implemented as a
shift register, while the multiply and
add blocks are implemented using multiplier and adder arithmetic circuits.
The coefficients (ai) can be held in registers (allowing them to be changed), or
hard-wired as fixed values if the filter
has a fixed response in the application.
The shift register is fed by the input
data (x[n]) and comprises a set of registers (the Δt blocks), each holding one
sample, so each register has the number
of bits needed to represent one sample
value. The shift register is clocked at the
sampling rate, so it presents a new set
of data to the multipliers and adders in
each cycle, which in turn produce the
current output value (y[n]).
The multipliers and adders could be
implemented as one large combinational (stateless) logic circuit; however, this
must deliver the correct output value
within one clock cycle (the sampling
period). Large combinational logic circuits can be slow, which would restrict
the maximum sample rate.
The speed is related to the number
of logic gates in the longest path from
input to output (assuming each gate has
about the same delay). One solution to
this is to insert registers into the combinational logic to reduce the path length.
This is called pipelining.
Fig.3 shows an example arithmetic circuit (simpler than the filter). This adds
Digital
ADC
Digital
processing
a0
x(n)
×
DAC
Reconstruction
filter
a0x(n)
a1
Δt
x(n–1)
×
a1x(n–1)
a2
Δt
x(n–2)
×
a2x(n–2)
Σ
aN–1
Analog
Fig.1: a generic digital signal processing (DSP) system structure.
34
four values to give the result R = D1 + D2
+ D3 + D4. Three combinational circuit
adders (Σ1 to Σ3) are used in a typical
‘tree’ structure to add the four values.
The input data is loaded in registers R1
to R4 in a given clock cycle. The adders
must deliver the result before the next
clock cycle, at which point the result is
loaded into register R5 at the same time
as the next input data loads in R1 to R4.
Fig.4 shows a pipelined version of the
circuit in Fig.3. Two additional registers
(RP1 and RP2) are inserted between the
adders. On the first clock cycle, after a
given set of data is loaded into R1 to
R4, the values D1+D2 and D3+D4 are
loaded into RP1 and RP2, respectively.
These intermediate results are input to
adder Σ3 to obtain the final result in the
R3 register on the following clock cycle.
Thus, the circuit in Fig.4 takes two
clock cycles to output the result, compared with the single cycle for the circuit
in Fig.3. The number of clock cycles required to produce a result is referred to
as the latency of the circuit.
The circuit in Fig.4 is faster than the
one in Fig.3 because the longest path
between registers is one adder rather
than two. Therefore, its maximum clock
speed is approximately twice that of
the non-pipelined version. This means
that although the clock cycle latency is
Out
Δt
Memory
x(n–N–1)
×
aN–1x(n–N–1)
Processing
Fig.2: a direct-form FIR filter sturcture.
Practical Electronics | June | 2025
y(n)
higher, it can process twice as much data
per second. In DSP terms, it can operate
at twice the sampling rate.
The structure in Fig.2 is called the
direct form, or canonical form, of the
FIR filter. It is the most straightforward
to understand, but it is not necessarily
the most effective in terms of circuit
size and speed. There are various approaches available to reduce the size of
the circuit structure and/or improve the
speed, such as the pipeline technique
described above.
Pipelining is widely applicable, but
there are also more specific techniques
for optimising the filter structures and
arithmetic circuits they use. These are
covered by a large body of academic literature and have names such as “common
subexpression elimination” and “coefficient grouping”.
Editor’s Note: DSPs typically use ‘carry-
lookahead adders’ (CLAs), which can
sum multiple values more efficiently
than the obvious approach. This and
other ‘speed up’ techniques may avoid
the need for pipelining.
CLAs can also be pipelined for greater speed. Larger, more complex designs,
such as floating point arithmetic circuits,
are more likely to need pipelining. The
details of these advanced techniques are
beyond the scope of this article.
Number formats
In both hardware and software DSP
implementations, the way that numerical values are represented is important.
For DSP in custom hardware, we have
to build the circuit to match the chosen
format.
In software it is usually a matter of
declaring the appropriate data type in
your code, but of course there is still
hardware involved. The processor and
its compatibility with a given number
format can have a significant impact on
performance.
Awareness of different number formats and their appropriateness for a
particular task, together with what is
best supported by any processor under
consideration, is important when designing a DSP system. This is a topic which
D1
D2
D3
D4
D
D
D
D
R1
R2
R3
R4
Q
Q
A
D2
B
A
Σ2
Q
D
S
Σ3
S
D
R5
Q
D
R
D3
D
S
B
CLK
(−1 )S ×1. M × 2( E−127 )
The “1.M” part is because mantissa
always has an assumed first bit of 1,
unless the exponent is at its minimum,
so this bit is not stored. The separate sign
bit means there are two zeros (+0 and -0).
An all-ones exponent is used for special cases, like errors leading to ‘not a
number’ (NaN) results and infinity. This
means the exponent range for normal
numbers is from -127 to +127.
Floating-point numbers have a much
larger dynamic range than fixed point, ie,
the range from smallest to largest value
representable with a given number of bits
is much bigger than for fixed point. This is
useful in DSP, as the values occurring in
calculations may vary over large ranges.
DSP will often require use of real
numbers (with a decimal point), not just
integers. There are two major options
for representing these in binary codes:
floating point and fixed point.
Fixed-point numbers scale values so
that they can be represented as integers.
For example, an 8-bit code can represent
unsigned integers from 0 to 255, but if
we scale it by 8, it can represent values
in steps of ⅛, from 0.125 to 31.875. This
means effectively the upper five bits are
D1
B
used for the integer part (0 to 31) and
the lower three bits for the fractional
part (0 to ⅞).
A binary word can be split in any
proportion between the integer and
fractional part. The Q notation is commonly used to define the format used;
for example, Q5.3 means five bits for the
integer and three for the fraction, as in
the example above, although Q5.3 would
usually imply a signed value (the same
splitting approach works fine for two’s
complement numbers).
Floating-point numbers are a form of
scientific notation (eg, 1.23 × 104) represented in binary code. Several floating
point formats have been used historically, but the one specified by the IEEE 754
standard is the most common.
The number has two key parts: the
mantissa (or significand), which is a
signed value that holds the digits of the
number (1.23 in the example), and the
exponent, which indicates the position
of the decimal (or binary) point (the 4
in the example above).
A 32-bit IEEE 754 number is referred
to as a single-precision value, while a
64-bit value is double precision. A singleprecision value comprises a sign bit (S),
an 8-bit exponent (E) and a 23-bit mantissa (M). The exponent is not signed,
but is stored with an offset (bias) of 127.
The value is given by:
Fixed and floating point
A
Σ1
Q
can get very detailed, so we will just
take a quick look at some of the basics.
The simplest numbers to deal with
are positive whole numbers (unsigned
integers), which are binary (base-2) numerical values. For example, decimal
3 is 0011 in 4-bit binary. For negative
numbers, one bit can be used for the
sign (ie, to indicate whether a number
is positive or negative).
However, this approach does not work
well when building integer arithmetic
circuits, and has the complication of
having two codes for zero (a positive
and negative ‘zero’).
Two’s complement is usually used
instead. The first bit still indicates the
sign, but only code 0000 represents zero.
Positive values up 2N–1 – 1 (for N bits)
have codes which are the same as unsigned binary. Negative numbers have
codes which are the same as that for the
unsigned number obtained by subtracting the value from 2N.
For example, in four-bits two’s complement, -2 has the same code as unsigned
16 – 2 = 14, that is, 1110 in binary. To
change the sign of a two’s complement
number, you invert all the bits and add 1.
One major advantage of two’s complement is that standard adder circuits can
be used with two’s complement numbers
if the final carry out is ignored. The numbers move through zero nicely when you
increment and decrement; for example
1111 is -1 in four bits. Adding one and
ignoring the carry to the fifth bit gives
0000 (zero) as expected.
In sign magnitude format, 1111 is -7,
so this does not work.
D4
D
R1
R2
R3
R4
Q
A
Σ1
Q
S
D
B
RP1
Q
A
Σ3
Q
B
A
Σ2
Q
B
S
D
RP2
S
D
R5
Q
R
Q
CLK
Fig.3: an example arithmetic circuit that sums four values. Fig.4: a pipelined version of the circuit in Fig.3 with added registers.
Practical Electronics | June | 2025
35
Fig.5: the STMicroelectronics B-L475E-IOT01A development board.
However, decimal values do not have
exact representation in binary floating point. This, together with rounding
errors, can lead to unexpected results.
For example, a direct comparison of two
floating-point numbers from different
calculations will often evaluate as false
due to very small differences, even if they
are ideally equal. However, appropriate
coding techniques can overcome this.
Adjacent fixed-point numbers (of a
given format) always have the same difference between them, whereas gaps vary
enormously with floating-point numbers,
depending on the exponent. This means
that floating point provides higher precision and smaller rounding errors over
large value ranges.
Therefore, floating point is generally
easier to use than fixed point for intensive calculations, as the latter may require
format manipulations to help maintain
precision. On the other hand, fixed-point
is simpler where the dynamic range is
known to be well constrained. Rounding and precision limitations create noise
in DSP signals similar to the random
noise inherent in analog circuits such
as amplifiers.
DSP is maths-intensive, so it is often
useful to employ floating point operations
in the code. This is very slow if the floating-point maths is performed using the
standard integer-based arithmetic hardware found in all processors. Processors
that have floating-point hardware to perform operations like add and multiply
achieve a significantly faster speed but
tend to be more expensive.
Microcontrollers
The hardware approach to DSP requires
either a custom IC (ASIC) design, which
is only viable for major manufacturers,
36
or an FPGA (Field Programmable Gate
Array) implementation. Low-cost FPGA
development is possible, but the learning curve is steep if you have not worked
with this technology before.
We will therefore concentrate on an
example of a microcontroller-based software implementation.
Most readers will already be familiar
with microcontrollers from the Cool Beans
column and the numerous Practical Electronics projects that feature them. DSP
can be implemented on just about any
microcontroller; however, basic devices
are very limited in what can be achieved.
Many microcontroller manufacturers
make devices suitable for DSP applications and either name them specifically to
indicate this (eg, dsPICs from Microchip)
or make DSP suitability prominent in their
marketing and datasheets. The following are examples of features which help
make microcontrollers suitable for DSP:
• A high clock speed/instruction processing rate.
• A larger word size (eg, 32-bit rather
than 8-bit processors).
• A hardware multiplier.
• A floating point unit (FPU), which
implements floating-point operations
(such as add and multiply) in hardware,
providing calculation speeds that are
orders of magnitude faster.
• A DSP instruction set. All processors
have machine code instructions for
basic arithmetic operations (such as
add and subtract). DSP instructions
extend the available operations to help
facilitate efficient DSP code. Examples
include multiply/accumulate and saturating addition (the result does not
overflow but sticks at the maximum
possible value). These can be used by
writing in assembly language or some
compilers (eg, C/C++) can use them to
create more optimal code.
• Internal cache memory. This is a
small, fast memory that stores copies
of frequently used memory data so the
processor does not have to wait for
memory access. All large processors
have caches, but basic microcontrollers
don’t necessarily.
• Good on-chip ADCs and DACs and possibly other on-chip analog peripherals
such as programmable gain amplifiers (PGAs). Systems requiring very
high-performance ADCs/DACs often
require separate devices, but on-chip
is very convenient and facilitates experimentation with a relatively minimal
development board. Most microcontrollers have ADCs, but DACs are less
common.
• Direct memory access (DMA) controllers. These facilitate data transfer
from/to peripherals such as ADCs and
DACs while the CPU is busy doing
calculations.
• Serial audio interfaces (SAIs) such as
Inter-Integrated Circuit Sound (I²S) and
Sony/Philips Digital Interface (S/PDIF).
• Software libraries supporting common
DSP functions.
An example microcontroller
The example we will discuss uses a
microcontroller from the popular STM32
family from ST Microelectronics (ST for
short). These are based on the widely
used Arm Cortex-M processor design.
There are many devices in this family,
which is divided into categories aimed
at high performance, mainstream, ultralow-power and wireless systems.
The specific chip used is the
STM32L475 80MHz 32-bit Cortex-M4
processor, which is from the low-power
category. Still, it ticks all boxes for the
DSP features listed above. This chip
comes on a development board, the BL475E-IOT01A Discovery kit (see Fig.5),
one of which I already had.
While suitable for DSP, the board is actually aimed at Internet of Things (IoT)
applications (hence the low power microcontroller). The B-L475E-IOT01A has
connectors that are compatible with the
Arduino Uno V3, so most shields can be
used with this board.
The STM32 ecosystem includes the
wide variety of processors just mentioned, and a range of development
boards from the minimal, small Blue Pill
boards via Nucleo and Discovery to the
feature-loaded Eval boards. The number
of features, and consequently cost, generally increases in the order just listed.
The B-L475E-IOT01A board has a lot
of features that are not required for our
DSP example, so a simpler board with
the same or similar processor would
Practical Electronics | June | 2025
suffice. The key requirements are an
on-chip ADC and DAC, FPU and DMA.
This month, we will discuss in general
terms what is needed to set up the DSP
project, provide some background on
the STM32 ecosystem as well as giving
some specific details for this board. Next
month, we will look at aspects of coding
the implementation in more detail.
As with many development boards, the
microcontroller can be programmed (and
debugged) from a PC or laptop via USB.
The ST system for this is called ST-Link,
and the hardware required is built into
many, but not all, of the development
boards (separate ST-Link programmers
are available). In some cases, the boards
are designed to allow the ST-Link part
to be snapped/cut off if it is no longer
needed.
Development tools
There are numerous software tools that
can be used to write code for, program
and debug STM32 devices. A straightforward option is to use the free Integrated
Development Environment (IDE) provided
by ST, which is called STM32CubeIDE.
This allows you to develop C/C++ code
and debug programs running on an attached development board.
STM32CubeIDE integrates another app
called STM32CubeMX, which provides
a graphical user interface for configuring
the hardware on a chosen processor (see
Fig.6) – the Device Configuration Tool.
We will mention key aspects of setting
up the example DSP project, but will not
provide complete step-by-step instructions. STM32CubeIDE is widely used, so
tutorials that show the basics are available online (for example, https://youtu.
be/Hffw-m9fuxc).
In general, if you do not know which
processor or board might be suitable for
a project, the IDE includes a part finder
where you can search for suitable choices by defining the features you require.
Code generation
The IDE allows you to select a board
from the list of available parts (those
made by ST). It will initialise a project
configured for the relevant board, after
which you can customise the configuration via the Device Configuration Tool
shown in Fig.6.
As with most IDEs, STM32CubeIDE
works in terms of projects, based on
folders in your file system. These folders will end up containing many files,
most of which you do not need to look
at, but it is important to maintain the integrity of the project structure used by
the software.
On most microcontrollers, each I/O
pin is connected to multiple on-chip
peripherals, such as ADCs, serial bus
Practical Electronics | June | 2025
Fig.6: the Device Configuration Tool in STM32CubeIDE.
interfaces and general-purpose digital
I/O (GPIO). Your code sets up which
pins will be used for what, and most
on-chip peripherals will have various
options and modes of operation which
have also to be configured in code.
There will also be some code required
for general processor initialisation (eg,
core clock speed and source). Importantly, when using a development board,
the processor and its I/O will need to be
configured to suit the board, even if not
all the features are being used.
Coding the initialisation and configuration manually can be tedious and
error-prone, but the Device Configuration
Tool allows you to set up the processor,
pin functions and peripheral options via
its GUI menus. On saving the Configuration Tool settings, the software writes
the details to a file with extension .ioc
in the project folder and generates the
code required to set up the microcontroller as specified.
Once you have initialised a project
in STM32CubeIDE, you end up with a
main.c file with the autogenerated code
in it. You now have a working project
that does nothing to use as a starting
point for adding the functionality you
need. Throughout the main.c file, there
are numerous comments of the form:
/* USER CODE BEGIN name */
…
/* USER CODE END name */
The name indicates the nature of the
code concerned. Places where the name
is a number are used for writing more
general code. You enter your code on
lines between a BEGIN comment and the
corresponding (same name) END comment. The BEGIN and END comments
must not be changed.
This ensures that the code will not
be overwritten (deleted) when an automatic code generation process is rerun
(eg, if the configuration is updated and
saved using the Device Configuration
Tool).
Software libraries
It is not just initial configuration that is
potentially difficult and time consuming
when developing code for microcontrollers. Other code is required to control
the complex on-chip hardware as programs execute. Usually, this involves
writing or reading from specific registers on the chip and requires detailed
knowledge of the microcontroller device
hardware.
As the hardware is fixed on a given
device, the same or very similar code
will be used in many projects, so it is
relatively straightforward for the microcontroller manufacturer to provide a
library of functions to facilitate straightforward use of the microcontroller.
These are referred to as APIs (application programming interfaces) – they
provide an interface between the user’s
code and the microcontroller hardware.
Many microcontroller devices from
a given manufacturer will provide the
same or similar functions, but the details of coding to achieve this may vary
(eg, different values in different registers). An API library can provide generic
and easy-to-use functions that work on
many devices.
37
Fig.7: a frequency response simulation of our digital filter.
Of course, each device may also have
more individual hardware features, accessed through APIs specific to that
device. This set of generic and easyto-use API functions is referred to as a
hardware abstraction layer (HAL).
They ‘abstract’ in that they hide the
specific details of the hardware, and
‘layer’ refers to the fact that they can be
visualised as being in-between the user
code and hardware. The term ‘driver’
may also be used to refer to software that
facilitates interaction with hardware.
The HAL driver APIs make coding
more productive, portable and less
error prone. The relevant library is
automatically available in projects
created by STM32CubeIDE. For the
STM32L475, documentation is provided in the STM32L4/L4+ HAL and
low-layer drivers user manual (UM1884,
see https://pemag.au/link/ac5h). Code
generated by the Configuration Tool
uses the HAL library.
Arm’s Common Microcontroller Software Interface Standard (CMSIS) DSP
library can be used with STM32CubeIDE,
but we will
not use this to implement the
ARD.D1-UART4_TX
exampleARD.D0-UART4_RX
filter to keep the set-up simple.
TheARD.D10-SPI_SSN/PWM
filter maths will be directly implemented in the project,
not hidden in a
ARD.D4
ARD.D7
library. It’s more educational
that way.
ARD.D13-SPI1_SCK/LED1
ARD.D12-SPI1_MISO
Making
measurements
ARD.D11-SPI1_MOSI/PWM
For an experimental implementation
SPBTLE-RF-RST
of a digital filter, we need to be able to
USB_OTG_FS_VBUS
supply
a test signal at the input and
USB_OTG_FS_ID
USB_N measure the input and output signals
USB_P so we can observe the effect the filter
has onSYS_JTMS-SWDIO
the signal. Ideally we want to
SYS_JTCK-SWCLK
be able
to plot the frequency response
ARD.D9-PWM
curve of the filter, similar to the plots
from the LTspice simulations in previous articles (see Fig.7).
This requires signal generation and
amplitude measurement over a suitable
frequency range.
Some oscilloscopes with built-in
signal generators can automatically plot
frequency responses. If not, a signal generator and oscilloscope can be used to
manually measure the gain at different
frequencies. However, to see the sharp
detail of frequency response, we need a
lot of data points, which could be very
time-consuming to gather manually.
A multimeter could also possibly be
used to measure signal voltage, but many
(particularly lower-cost models) only
measure AC voltages over a very limited frequency range, so they would not
be suitable. Devices that cover at least
the 20Hz-20kHz range with accuracy are
often termed ‘audio millivoltmeters’.
Fortunately, there is an alternative to
purchasing expensive test equipment;
it is possible to use the sound card on a
PC or
laptop as a signal generator/oscilU1A
23
35
loscope
combination using free
software
PA0/WKUP1
PB0
24
36
tools, PA1
some of which will plot
frequency
PB1
25
37
responses
PA2 automatically. PB2
89
26Sound cards have significant limitaPB3/SWO
PA3
90
29
PB4they can
tions PA4
as test equipment, but
91
30
PB5 range at
PA5
handle
AC signals in the audio
92
31
PA6 which is more or PB6
line level,
less what
93 is
32
PB7
PA7
needed here. So they are a viable option
95
67
PB8
PA8
that we will look at later.
96
68
PB9
PA9
69
47
PA10
PB10
70
48
System
PA11structure
PB11
71Our example filter implementation
51
PA12
PB12
72
52
will follow
the structure
of the gePA13/SWDIO
PB13
76
53
PB14
neric PA14/SWCLK
DSP system in Fig.1.
It is worth
77
54
PA15
PB15
considering exactly what we need and
how the blocks in Fig.1 map to the
development board, processor, and
what additional circuitry we might be
required.
We must decide which specific processor peripherals/pins to use (eg, which
ADC if the processor has several), and
if we are using a development board
with peripheral circuits on the board,
we need to check if they will influence
our implementation.
The first block in Fig.1 is the antialiasing filter. We do not need this for
measuring frequency responses with
sinewave inputs that do not exceed the
Nyquist frequency, as there is nothing
for the filter to remove.
The ADC block is implemented by an
ADC on the microcontroller. The sample-and-hold function is integrated into
the on-chip ADC. The sampling/ADC
conversion timing depends on the microcontroller hardware configuration,
and software written to control this,
which we will examine later.
The STM32L475 has three 12-bit
5Msps (megasamples per second) ADCs
on-chip with 16 input channels (possible
microcontroller pin connections) shared
between them (see the datasheet at
https://pemag.au/link/ac5i).
We need to check the development
board schematic to see which microcontroller pins are available as ADC
channels that are connected conveniently on the board and choose one to use.
For the board used here, ADC1 is
most convenient because it can be fed
from microcontroller pins PC0 to PC5,
which are connected in turn to the six
pins of the Arduino Uno header CN4
on the board
(labelled ARD-A5-ADC
ARD.D3-PWM/INT1_EXTI0
to ARD-A0-ADC).
No other circuitry is
ARD.D6-PWM
connected
to these pins.
ARD.D8
The relevant
parts of the 11-page board
SYS_JTDO-SWO
ARD.D5-PWM
schematic
are shown in Fig.8 (this was
extractedSPSGRF-915-SPI3_CSN
from the the user manual at
ST-LINK-UART1_TX
https://pemag.au/link/ac5j).
ST-LINK-UART1_RX
Figure 23. STM32L475VG microcontroller
ARD.A5-ADC
ARD.A4-ADC
ARD.A3-ADC
ARD.A2-ADC
ARD.A1-ADC
ARD.A0-ADC
VL53L0X_XSHUT
VL53L0X_GPIO1_EXTI7
15
16
17
18
33
34
63
64
PC0
PC1
PC2
PC3
PC4
PC5
PC6
PC7
PC8
PC9
PC10
PC11
PC12
PC13/WKUP2
PC14-OSC32_IN
PC15-OSC32_OUT
STM32L475VGTx
Fig.8: the ADC wiring on the B-L475E-IOT01A board from its user manual.
38
65
66
78
79
80
7
8
9
R8
2K
ADC configuration
The Device Configuration Tool can be
used to set which channel each ADC
will be fed
from. The default configuISM43362-BOOT0
ration of aISM43362-WAKEUP
new STM32CubeIDE project
R
LED2
for the B-L475E-IOT01A
board already
2K
SPSGRF-915-SDN
has pins PC0
to PC5 configured as possible ADC1 inputs. All that is needed
LSM3MDL_DRDY_EXTI8
for basic use
of the ADC is to enable the
LED3(WIFI) & LED4(BLE)
ADC1 channel that is connected to the
INTERNAL-SPI3_SCK
microcontroller
pin to be used.
INTERNAL-SPI3_MISO
We will
connect ADC1 channel 1
INTERNAL-SPI3_MOSI
(IN1) to pin
PC0 (CN4 header pin A5).
BUTTON_EXTI13
To configure the ADC, click on Analog
C14
in the Categories list inR12
the ConfiguraG
tion Tool to expand it, then click on
0Rconfiguration. 5.1pF
ADC1 to select ADC1 for
X2
In the Mode part of the ADC1 Mode and
NX3215SA-32
Practical Electronics | June | 2025 C15
G
5.1pF
Configuration section, select Singleended from the drop-down menu for
IN1 (see Fig.9).
Similar procedures are used to configure all the microcontroller hardware
used in a project. We will discuss other
ADC configuration options later.
The digital processing part of Fig.1
is performed by code running on the
microcontroller. The fundamental
requirement for this example is to implement the FIR filter maths on the
input signal.
The actual calculation is relatively
straightforward – multiplying by coefficients and summing the results.
However, the data must flow from the
ADC to the calculation, and the results to
the DAC in an efficient manner, with the
sampling occurring at the correct rate.
We will discuss the details of this later.
DAC configuration
The DAC is also internal to the microcontroller; the STM32L475 has a
12-bit DAC with two output channels.
®
The settling time is 3μs to ±0.5 LSB,
which would correspond to an update
rate of around 300kHz. This is slower
than the ADC, but more than enough
for audio output.
The DAC has a sample-and-hold mode,
which might seem confusing as sampleand-hold is usually associated with
ADCs. It refers to using a capacitor to
hold the DAC output voltage with the
DAC circuitry powered down when
the microcontroller is in a low-power
mode. It is not needed here (normal
mode is used).
As with the ADC, we need to look
at the board schematic to see how the
DAC is connected. The two output
channels are available on pins PA4 and
PA5. We will
CN2 use DAC1’s Channel 2 via
R3 1k
microcontroller
pin PA5. The signal is
1
labelled ARD.D13-SPI1_SCK/LED1
on
2
IOREF
NRST
3
the schematic.
3V3
3V3
4
The PA5 pin
is
connected to user LED1
5V
5V
5
on the development
GND board (see Fig.10).
6
GND
The signal 7from
the microcontroller is
VIN
N <11.5V
VIN
buffered by8an op
amp unity-gain amplifier (U21)Header
so the8X1_Female_SMD
LED will not load the
DAC output. If the microcontroller is
configured to use the DAC on pin PA5,
the DAC will see a 210kΩ grounded
load due to resistors R16 and R38.
The op amp and LED circuit can be
CN4desoldering solder bridge
isolated by
C
1 underside
A0
SB1 (on the
of the board),
A1
C
2 necessary
but this is not
to use the DAC.
A2
C
3
The ARD.D13-SPI1_SCK/LED1
signal
A3
C
4
A4 to the Arduino Uno
C
5
is also connected
A5(see Fig.11). This proC
header CN16 pin
Header
6X1_Female_SMD
vides a convenient
way to access the
DAC output signal.
The default configuration of the PA5
pin is as SPI1_SCK (SPI serial bus #1’s
Figure
RESET BUTTON
STM_NRST
Close
SB2
R19
1K
B1
C34
100nF
GND
C35
10pF
SW-PUSH-CMS_BLACK
GND
GND
100nF should be place close to the MCU
10pF and 1K should be place close to the button
Fig.9:V3
the ADC
mode configuration we will be using.
Figure 30. ARDUINO Uno
connector
AIN
POWER
UM2153 Rev 5
51/57
Practical Electronics | June | 2025
USER LED
The 2 LEDs are top side
C73
3V3
GND
100nF
ARD.D13-SPI1_SCK/LED1
Close
SB1
R16
5
U21
R18
VCC+
GND
10K
R38
200K
1
4
3
2
VCC-
LD1
1K
LED
GND
GREEN
GND
TSV631AILT
Fig.10: the LED circuitry connected to the PA5 pin on the B-L475E-IOT01A1 board.
CN1
SCL/D15 10 LED2
9
SDA/D14
8
AVDD
GND
GND 7
SCK/D13
6
MISO/D12
5
PWM/MOSI/D11
4
LED3(WIFI)
& LED4(BLE)
3
PWM/CS/D10
2
PWM/D9
D8
1
Header 10X1_Female_SMD
ARD.D15-I2C1_SCL
ARD.D14-I2C1_SDA
R20
LED
LD2 VDDA
330R
R2
ARD.D13-SPI1_SCK/LED1
ARD.D12-SPI1_MISO
R21
ARD.D11-SPI1_MOSI/PWM
ARD.D10-SPI_SSN/PWM
1K
ARD.D9-PWM
ARD.D8
R22
680R
0R
GND
GREEN
WIFI
C1
100nF
LED
LD3
GND
YELLOW
GND
LED
LD4
3V3
BLUE
FIg.11: the DAC1 (PA5) connection to the Arduino header on the B-L475E-IOT01A1.
BLE
The configuration panel allows other
clock signal). To use the DAC, we change
options for the DAC to be set, which we
the PA5 pin configuration
by clicking
CN3
will discuss in more detail later.
on it in the Device Configuration Tool
8
ARD.D7
D7
and selecting
the
DAC1_OUT2
option
7
ARD.D6-PWM
PWM/D6
PWM/D5
6 (see Fig.12).
ARD.D5-PWM
from the
pin menu
Pulses and power supplies
D4 it5is necessary to configARD.D4 When exploring the operation of the
Like the ADC,
PWM/D3
4
ARD.D3-PWM/INT1_EXTI0
ure the DAC.D2
In the
FIR filter and subsystems, such as the
3 Device Configuration
ARD.D2-INT0_EXTI14
TX/D1
2
ARD.D1-UART4_TX
Tool, click
on Analog
in the Categories
DAC and ADC, it is useful to have a
RX/D0 on1DAC1 to select it. In
ARD.D0-UART4_RX
list and click
separate digital output to provide a
Header
8X1_Female_SMD
the Mode panel,
change
OUT2 from
time marker for when certain actions
“Disable” to “only to external pin” –
take place. For example, a pulse to logic
this will enable the DAC and route its
1 can be produced each time software
output signal to the PA5 pin.
attempts to update the DAC output.
39
To do this, we need to choose a
pin to use as a general-purpose digital I/O and configure it as an output
(GPIO_OUTPUT).
The PB2 pin is suitable for this is – it
can be used as a GPIO and is only connected to the Arduino Uno header CN1
pin 1 on the development board. Therefore, it does not interact with any onboard
circuitry. As pin PB2 is configured as a
GPIO output by default, it is unnecessary
to use the Configuration Tool to set this up.
The final block in Fig.1 is the reconstruction filter. We can observe the DAC
output on an oscilloscope without using
a filter, and if we use a reasonably high
sampling rate compared with the signals,
a simple RC low-pass filter may provide
adequate filtering for basic measurements.
The B-L475E-IOT01A board can be
powered via the ST-Link USB connection and provides +3.3V and +5V on
the Arduino Uno connector.
The ADC input range and DAC output
range are determined by their reference
voltage inputs. On the B-L475E-IOT01A
board, the microcontroller’s VREF+ pin
is connected to the 3.3V analog power
supply (VDDA) and the VREF- pin is connected to ground (0V). This means the
ADC and DAC ranges are both 0 to 3.3V.
When using the board, we have to make
sure the signal input to the ADC does not
go outside the 0V to 3.3V range.
PE
Fig.12: the Device Configuration
Tool setting to make the PA5 pin
function DAC1_OUT2.
JTAG Connector Plugs Directly into PCB!!
No Header!
No Brainer!
Our patented range of Plug-of-Nails™ spring-pin cables plug directly
into a tiny footprint of pads and locating holes in your PCB, eliminating
the need for a mating header. Save Cost & Space on Every PCB!!
Solutions for: PIC . dsPIC . ARM . MSP430 . Atmel . Generic JTAG . Altera
Xilinx . BDM . C2000 . SPY-BI-WIRE . SPI / IIC . Altium Mini-HDMI . & More
www.PlugOfNails.com
Tag-Connector footprints as small as 0.02 sq. inch (0.13 sq cm)
40
Practical Electronics | June | 2025
|