0:11
welcome to controllers tech this is
0:14
another video in stm32 register based
0:18
and today we will be looking into dma
0:21
dma is a vast topic and that's why i
0:24
have decided to split it into few parts
0:27
today we will cover the adc in f446 with
0:32
but without the interrupt this dma will
0:35
be set up in the circular mode
0:37
and it will be always running in the
0:40
and what better peripheral can we use
0:45
we can let the conversion to take place
0:48
and whenever we need the value we can
0:52
this is not that simple in any other
0:56
i2c or anything else where we need to
0:59
process every data we get
1:01
so this is why i decided to go with adc
1:05
after this i will cover peripheral
1:07
interrupt in the next video
1:09
and later i will combine them and make a
1:11
final video on dma with interrupt
1:16
today we will also see the internal
1:24
let's start with kyle id then and create
1:40
i am using f446re for this video
1:47
select the cm sys core and the device
1:56
let's add the main file to this project
2:00
and create a main function along with
2:08
now the usual thing we will copy the
2:12
and the delay libraries these libraries
2:15
are covered in the previous videos
2:17
so watch them if you haven't
2:23
add the libraries in the project also
2:28
include them in the main file so that we
2:31
can use the functions here
2:37
we are done with our initial setup now
2:40
since i am using adc here i will just
2:43
use the code from my previous adc video
2:47
this is the main file from that video
2:49
and we only need the initialization
2:52
enable and start functions from here
3:00
let me walk you through quickly first of
3:03
all we enable the adc
3:08
since i am using pa1 and pa4 pins for
3:13
i am enabling clock for the gpioa
3:22
after that we set the prescaler for the
3:30
we enable the scan mode because we want
3:34
channels here also the resolution is set
3:40
then the setting for continuous
3:44
next is the sampling time for the
3:47
and channel 4. let's see the reference
3:51
because this will be useful for the
3:53
temperature sensor also
4:03
here the sample time register 2 can be
4:06
used to set the sample time for channel
4:16
and register 1 can be used for the
4:25
now since we are using channels 1 and 4
4:29
we are interested in these two sections
4:32
i will set the random time here since
4:35
the setting for these two channels don't
4:38
the sampling time will be useful when we
4:42
the temperature sensor later in the
4:45
i am keeping the three cycles
4:48
so i need to write zero zero zero in the
4:52
and the twelfth position
4:58
this can be done by writing 7 and then
5:06
next is the number of channels that we
5:23
this can be set up in the sequence
5:25
register 1 and bits 20 to 23 configures
5:29
if we write 0 here that would mean that
5:31
we want to convert 1 channel
5:34
so i am writing 1 in these bits because
5:36
i want to convert two channels for now
5:39
then we are setting the analog mode for
5:43
this was the setup from the previous
5:45
code now we will do some more addition
6:00
you can read here in the manual about
6:02
how to use adc with dma
6:09
anyway let's go to the registers
6:19
here is our bit of interest this is in
6:22
the adc control register 2.
6:28
bit 8 is the dma and we will enable it
6:33
bit9 is dds it basically specifies
6:36
if we want the continuous dma conversion
6:40
we will enable this one also
6:46
so let's enable the dma for the adc
6:55
also enable the continuous request
6:58
now we need to set the order for the
7:00
channels what i mean is
7:03
we need to set in what sequence the
7:05
channels should be converted
7:07
which conversion should happen first and
7:09
which should happen last
7:11
this can be done in the sequence
7:15
these sequence registers can set the
7:16
conversion sequence for up to 16
7:20
this sequencing starts from the sequence
7:24
and here you can see the sequence 1 that
7:26
means which channel will be converted
7:30
all we have to do here is just write the
7:32
channel number in the respective
7:35
for sequence 1 and sequence 2 we have to
7:39
modify bits starting at 0
7:47
here i am setting sequence 1 for channel
7:56
and sequence 2 for channel 4.
8:03
this is it for the adc modification
8:06
we will enable the adc later
8:14
here we don't need this anymore since we
8:17
are already using sequences for all the
8:27
now let's initialize the dma
8:38
f446 have 2 dma and combined they have
8:50
dma transfers can be peripheral to
8:54
memory to peripheral and memory to
9:06
memory basically three things happens
9:09
during the dma transfer
9:12
data is copied from the peripheral
9:14
register or from a memory location
9:17
data is copied into the memory location
9:20
or into the peripheral register
9:23
and the counter decreases this counter
9:26
keeps the record of how much more data
9:28
is needed to be copied
9:34
here we have the dma mapping requests
9:38
we can choose the stream based on what
9:40
peripheral we are using
9:43
since i am using adc one have to choose
9:46
and channel zero of dma2
10:03
we are definitely going to use the
10:06
and as you can see in the circular mode
10:09
the counter value gets updated on its
10:12
so the data transfer continues forever
10:32
let's see the registers first we have
10:42
it's called lower because it can handle
10:44
the stream 0 to stream
10:46
3. this register will be used
10:49
when we will include the interrupt with
10:51
dma which we are not doing today
10:54
then high interrupt status register
10:56
handles the streams 4 to 7.
11:02
interrupt flag clear registers are used
11:05
to clear those interrupt flags
11:07
set in the interrupt status registers
11:16
now we have reached the stream
11:17
configuration register
11:23
but before that let's enable the dma2
11:36
it's the bit 22 in the rcca
11:56
now we will configure the stream let's
11:59
start from the least significant
12:01
bit bit zero enables the stream
12:05
we will do this in the end we are not
12:09
so these bits are of no use here
12:12
the fifth bit is peripheral flow
12:16
we want the dma to control things so we
12:21
then we have to select the direction of
12:24
we are copying the data from adc to the
12:26
memory so the direction will be
12:29
peripheral to memory next is the
12:33
and we will enable it let's set these
12:40
we will set the data direction
12:46
dma stream 0 and in the control register
12:50
we will set 0 zero in the sixth and the
13:08
circular bit is bit eight set the
13:11
circular mode for the dma
13:18
then we have peripheral increment we
13:21
will not increment the peripheral
13:23
as we are copying the data from the data
13:27
and yes we do want to increment the
13:31
after each transfer this way the buffer
13:34
will automatically increment
13:36
and the next data will be saved in new
13:42
so write a one in the tenth position
13:55
next is the peripheral data size
13:58
as i am using 12 bit adc i need to use
14:01
16-bit data size here
14:07
and the same for the memory data size
14:10
so we will write a 1 in the 11th
14:12
position and the 13th position
14:35
then we don't need all these bits for
14:45
at last we have the channel selection if
14:48
you remember i am using channel 0 for
14:52
and that's why i need to write 0 in the
15:00
this is it for the dma initialization
15:04
now we will configure this dma
15:10
this function will take three parameters
15:14
the source address the destination
15:17
and the size of the data this should be
15:22
let's see the reference manual again
15:27
next register is the ndtr
15:31
this is a 16-bit register and here we
15:34
set the size of the data
15:36
that needs to be transferred through the
15:39
if you remember in the beginning we saw
15:41
that after each transfer
15:43
the value here will decrease and once it
15:46
the dma transfer will stop
15:50
also we can only update this if the
15:54
and that's why we haven't enabled the
16:05
let's set the size in the ndtr register
16:16
next in line is the peripheral address
16:20
here we write the address of the
16:22
peripheral register where we want to
16:25
or copy the data into in this case
16:36
we are copying the data from the adc
16:40
so the peripheral address will be the
16:47
similarly there is memory address where
16:49
we are copying the data into
16:52
and in this case it's the destination
16:57
if you notice here we have two different
17:00
memory address registers
17:02
but this one can only be used in the
17:06
and that's why we are not using it today
17:09
so that's all for the dma configuration
17:14
now finally we will enable the dma by
17:17
setting the bit zero of the control
17:25
this finishes up the dma configuration
17:28
now let's define an array to store the
17:33
in the main function we will start with
17:35
system clock configuration
17:38
configure the timer for the delay
17:41
initialize the adc and initialize the
17:45
now we will call the dma configuration
17:49
first we need the source address the
17:52
source is the data register of the adc
17:55
where we are copying the data from
17:58
destination is the array
18:00
that we created and we want to transfer
18:08
i should have enabled the adc after the
18:15
and now after everything is set we will
18:19
to start the dma transfer
18:32
okay everything looks set so build it
18:40
we have zero errors so let's go ahead
18:50
the controller is running at 180
19:11
i am adding the rx data to the watch
19:23
i need to change this data type here
19:30
okay so i have connected the channel 1
19:33
and channel 4 to the 3.3 volts
19:37
the readings are as expected
19:47
and now i have connected the channel 4
19:50
and channel 1 to the 3.3 volts
19:54
so the things works pretty well the dma
19:57
will keep getting the data from the adc
20:01
and this data will be stored in the
20:03
buffer we can use the buffer at any
20:06
in the code and there we will always
20:08
have the latest values to process
20:11
this you will see in a while when we
20:13
will do the temperature sensor
20:15
i want to show you guys one more thing
20:18
let's put a break point here
20:24
we are at the breakpoint now pay
20:28
the dma is already enabled and also the
20:32
but the values are not updating this is
20:35
because i haven't started the adc
20:37
yet and now the moment we start the adc
20:41
the values will be stored this is
20:44
something useful in adc
20:46
since it have a feature to control the
20:50
but if we are using something like uart
20:52
we don't have any start condition in
20:56
and in that case as soon as you enable
20:59
the data transfer will start to debug
21:04
you can look at the dma peripheral as i
21:08
0 only s0 registers will be relevant
21:12
you can see the ndtr is 1 and if we step
21:16
over its value decreases since we are
21:19
circular mode this value will not reach
21:26
this is it about this part now we will
21:30
the internal temperature sensor this
21:33
will be a kind of application of the dma
21:36
let's see the data sheet again and this
21:38
time we will look for the temperature
21:41
it is channel 18 of the adc
21:47
here are the steps to use the
21:51
we need to enable the channel 18
21:54
then configure the sampling time for the
21:57
channel and it should be higher than the
21:59
one specified in the data sheet
22:01
then we have to set this t s v r e f e
22:05
to wake the sensor the rest of these
22:08
steps are already taken care of
22:11
so we need to only focus on these
22:19
remember the sequence register we have
22:21
already set the sequence of the two
22:23
dc channels now we will set the sequence
22:26
for the channel number 18
22:28
that is the temperature sensor basically
22:32
we just have to write the channel number
22:35
so we will write the 18 in the 10th
22:55
now the sampling time as given in the
22:59
the minimum time needs to be 10
23:03
so we must select the conversion time
23:10
also note that the adc one is connected
23:14
and since my setup runs at maximum clock
23:17
the apb clock is also running at 90
23:28
i wrote one article about calculating
23:31
and the conversion time for the adc
23:44
here is that formula and we will use
23:53
also note that the sampling time we can
23:57
is limited to these values
24:02
in my setup i have used the prescaler of
24:06
to divide the apb2 clock
24:18
this will bring it down to 22.5
24:23
now if i choose the 144 cycles
24:26
the conversion time comes around 7
24:30
this is less than the value in the data
24:38
for 480 cycles it comes around
24:42
22 microseconds this is way higher than
24:46
the data sheet value
24:47
but i guess we can work with it you
24:50
should modify the prescaler also
24:52
to keep the time close to the value in
24:56
we need to write 7 in the 24th position
25:00
since we are setting it for channel 18.
25:22
now we need to set this bit in the ccr
25:29
here it is the bit number 23
25:36
so let's write 1 in the 23rd position
25:40
we just need to do one last thing
25:44
the number of conversions were set to 2
25:46
and we will change it to 3 now
26:14
let's copy the formula from the data
26:28
here v senses the voltage corresponding
26:41
v 25 is given in the data sheet and it's
26:52
we are receiving three values now
27:00
average slope is 2.5 milli volts per
27:08
change it to volts let's define the
27:11
temperature variable
27:19
we have a warning anyway let's move on
27:40
you can see the temperature is around 36
27:44
i wouldn't call it perfect but this is
27:48
it should be around 33 or 34.
27:51
this could be due to the conversion time
27:53
i took because it was more than double
27:56
of that in the date sheet
27:58
that's why i said that you should also
28:01
prescaler also and try to keep the
28:03
conversion time close to that value
28:06
anyway you can see the adc values from
28:09
all three channels are updating
28:12
the last value is for the temperature
28:14
sensor because we have set the sequence
28:16
3 for it so it will be converted and
28:20
in the third place this is it for the
28:24
i hope things were clear there are minor
28:27
changes in the f103 controller
28:30
and i think you can handle them if you
28:32
have watched the video properly
28:35
if you want me to cover the urtma in
28:39
leave the comments below this was the
28:43
so the dma will keep running in the
28:45
background without affecting the cpu
28:48
i will also include the non-circular
28:50
mode settings in the final code
28:53
there you can just call the dma whenever
28:56
and after all the conversion is finished
29:00
automatically check the final code for
29:04
this is it for now leave comments in
29:09
you can download the code from the link
29:13
keep watching and have a nice day ahead