0:09
hello and welcome to controllers Tech
0:12
this is the fourth video in the stdm 32
0:15
wat series and today we will continue
0:18
receiving the data but using the dma we
0:21
have covered how to receive data using
0:23
the blocking mode and using the
0:25
interrupt in the previous video today we
0:29
will use the dma to do the same dma is
0:32
mostly used to receive large data so
0:35
that the CPU can handle the rest of the
0:38
tasks I will demonstrate this in today's
0:41
video where we will receive some large
0:43
data files via the U using the dma we
0:47
will continue with the same project from
0:49
the previous video let's open the ioc
0:53
file to make changes in the
0:55
configuration the basic configuration
0:57
will remain the same with board rate of
1:00
115200 eight data bits One Stop bit and
1:04
no par we need to add the dma so open
1:09
the dma settings and add the U RX dma we
1:13
will keep the mode normal for now and
1:15
the data width is set to bite I have
1:18
already explained these configurations
1:20
in the video number two make sure that
1:23
the dma interrupt is enabled in the nvic
1:27
tab click save to generate the
1:30
project let me clear the code from the
1:33
previous video first I am leaving this
1:36
led blinking as it is so as to make sure
1:39
the CPU is handling another task at
1:41
usual rate we will first see a simple
1:44
receiving using the dma let's define our
1:48
RX data buffer of 20 bytes to store the
1:51
received data in the main function we
1:54
will receive data using the function H
1:57
youart reive dma the param parameters
2:00
are the uart instance the receive buffer
2:03
and the size here I am only receiving 10
2:06
bytes of data the dma comes with two
2:11
interrupts one is triggered when half of
2:13
the total data is received and another
2:16
one triggers when the complete data is
2:18
received in our case the receive
2:21
complete call back is called when all 10
2:23
bytes are received and the half receive
2:26
complete call back will be called when
2:28
five bytes of data has been received
2:30
received let's define two counters to
2:33
check if the respective call back has
2:34
been called or not inside the half
2:38
receive call back we will increment the
2:41
counter similarly inside the receive
2:44
complete call back we will increment the
2:46
fall counter the dma is being used in
2:50
the normal mode so it gets disabled
2:52
after all the 10 bytes have been
2:55
received so we need to make the call
2:57
again inside the receive complete call
3:00
function all right let's build and debug
3:03
the project now we will use the same
3:07
configuration in the serial
3:09
software the board rate is
3:12
115200 with one stop bit and no
3:15
par I am going to send one bit at a time
3:18
and you can observe the RX data buffer
3:24
debugger that's also at both the
3:31
each data BTE is automatically stored in
3:33
the next position in the buffer now I
3:36
have sent for data bytes and both the
3:38
counters are still zero with the fifth
3:41
data bite the half counter sets to one
3:45
this is because half the data has been
3:47
received and this is why the half
3:49
transfer call back is called let's
3:52
continue sending the data now all the 10
3:55
bytes have been received and this is why
3:58
the receive complete call back back is
4:00
called and hence the full counter is
4:03
incremented we restart the dma reception
4:06
at this point and therefore the new data
4:08
is stored from the beginning of the RX
4:10
data buffer the half counter increments
4:14
again after receiving five data bytes
4:16
and the full counter increments after
4:20
bytes we can send all 10 bytes at once
4:24
and both the counters will
4:26
increment so you can see how the dma
4:30
works we can utilize these half transfer
4:33
and full transfer call backs to transfer
4:35
the received data to another buffer or
4:38
to some file we will see this in a
4:42
while now I am going to demonstrate
4:44
different reception methods under some
4:47
scenarios you can modify these methods
4:52
requirement I mentioned in the beginning
4:54
that the dma is mostly used when we want
4:57
to receive large data via the uart
5:00
I have prepared some bin files which we
5:04
uart the file names are their actual
5:07
size in bytes and they just contain some
5:10
numbers inside them this makes it easier
5:13
for us to track if all the data has been
5:16
received let's assume a scenario where
5:19
we want to receive certain data and
5:21
store it in a buffer also we can Define
5:25
the buffer large enough to store the
5:26
entire data we still need to know the
5:30
size of the data in advance so we will
5:32
first send the size of the data this
5:36
variable will keep track of if the size
5:38
has been received or not the size
5:41
variable will store the size of the
5:43
incoming data since we are receiving all
5:47
the data in our main buffer we don't
5:49
need the half receive call back we will
5:52
first receive the four bytes data for
5:54
the size and once all the four bytes
5:57
have been received the receive complete
5:59
call call back will be
6:00
called the same call back will be called
6:03
when we finish receiving all the data
6:06
bytes so we need to write conditions
6:09
which separate the reception of the size
6:11
data from the actual data the size
6:15
received variable is set to zero in the
6:17
beginning which means that the size data
6:19
has not been received yet so if this
6:23
variable is zero and the receive
6:25
complete call back is called it means
6:27
that the 4 bytes size data has been
6:31
received we will extract the size value
6:35
bytes the value 48 is the offset between
6:39
the number and its character
6:41
equivalent we receive characters in the
6:44
U communication so we need to subtract
6:47
48 to get the number equivalent of the
6:49
character now we have got the size of
6:52
the data which is going to come next set
6:55
the size received variable to one so
6:58
that this Loop doesn't run again and set
7:01
the dma to receive the required number
7:03
of data as I mentioned we are receiving
7:07
the four bytes of size data in the
7:09
beginning now the receive complete call
7:12
back will be called again when all the
7:14
data bytes have been received and then
7:17
we will set the size received variable
7:19
to zero and again start receiving four
7:22
data bytes for the size basically we
7:25
receive the size data and set the dma to
7:28
receive the the required number of bytes
7:31
once all the data bytes have been
7:33
received we set the dma to receive the
7:36
size data again this Loop will continue
7:39
to run forever this entire scenario only
7:42
works given that our sender sends the
7:44
size first and the receive MCU has
7:47
enough space to store all the received
7:50
data let's build and debug the project
7:58
now all right let's select the data
8:02
file I am going to send 2 kiloby of data
8:06
we need to send the size first here it
8:10
got received in the RX data buffer now
8:15
file you can see the RX data buffer has
8:18
been updated with new
8:20
values we will check the numbers at the
8:23
start and end of the buffer the data
8:30
let's open the binary file to check this
8:33
here you can see the data starts with
8:38
0994 we have received a total of 2048
8:42
bytes so let's check the data at the
8:49
35215 it is the same as what we have at
8:51
the end of the file so we have received
8:56
once now let's select another binary
9:00
send this file contains 2044 bytes so
9:09
size we have received it in the RX data
9:12
buffer let's send the data
9:22
now at the start we have 086
9:26
72 Let's cross check it with the binary
9:29
file here we have the same numbers in
9:36
beginning at the end of the RX data
9:39
buffer we have the numbers
9:43
1355 these are the same numbers which
9:45
are present at the end of the file
9:48
also so we were able to receive a large
9:51
amount of data using the
9:53
dma this whole process can only work if
9:56
the MCU has enough space to store all
9:59
the data received in a single
10:01
buffer but what if the data to be
10:04
received is very large and we can't
10:06
afford to store it in a single buffer I
10:09
am talking about the situation where you
10:11
probably want to receive an audio file
10:14
or a video file via the uart and store
10:17
it in the SD card or the flash
10:20
storage here we do not want to create a
10:22
buffer to store files in megabytes as
10:25
mostly the MCU does not have the space
10:27
for it so we will now see how to handle
10:31
situations like this let's define the RX
10:35
data buffer which can only store 256
10:39
once now to keep things simple I am
10:43
defining another buffer which can store
10:45
4 kiloby of data think of this buffer as
10:49
the space in the SD card or flash
10:51
storage where we want to store our file
10:55
the code will remain the same just
10:57
instead of updating the buffer you need
10:59
to update the file I will explain this
11:03
in the end let's define variables to
11:06
keep track if the half transfer and full
11:08
transfer call backs have been triggered
11:11
the index variable will keep track of
11:13
how many bytes have been written to the
11:15
main buffer we still need to receive the
11:19
size data so we need these two
11:22
variables we will first write the half
11:24
transfer complete call back we are now
11:28
receiving the data in the circular mode
11:31
so the dmaa can't be stopped in the
11:33
middle we will first receive the four
11:36
bytes of the size data and then continue
11:39
receiving the main data the half
11:42
received call back will be called when
11:43
we have received 128 bytes in total
11:47
including the size data since the size
11:50
data is always received at the beginning
11:52
of the buffer we can extract the size in
11:55
the half transfer callback
11:57
function it's still still is present in
11:59
the first four bytes of the RX data
12:02
buffer after extracting the size reset
12:05
the index variable to
12:08
zero now we will copy the main data
12:11
which starts from the fourth position in
12:13
the RX data buffer into the final buffer
12:16
out of 128 bytes four bytes were used by
12:20
the size data so we only need to copy
12:24
124 bytes now instead of copying the
12:28
data to the buffer you can create a file
12:30
in the SD card and copy 124 bytes to
12:34
that file now let's reset the first half
12:38
of the RX data buffer Now update the
12:41
index variable to indicate how many data
12:44
bites have been handled
12:46
already the size received variable is
12:48
set to one so that we don't enter this
12:51
loop again now once the third set of 128
12:55
bytes are received we will enter this
12:58
call back again again this time we will
13:01
update the final buffer with 128 bytes
13:04
from the RX data buffer clear the first
13:08
half of the RX data buffer and update
13:12
variable each time the half transfer
13:14
callback is called the HDC will be set
13:17
to one and the FTC will be reset to zero
13:21
now when the second half of the RX data
13:24
buffer is received the receive complete
13:26
call back will be called here we will
13:29
simply copy the data starting from the
13:32
128th position in the RX data buffer and
13:35
store it in the final buffer then clear
13:39
the second half of the RX data buffer
13:41
and update the index variable we will
13:44
also rest the HDC variable and set the
13:47
FDC variable this entire structure works
13:51
well if the total data is in the
13:55
256 but let's assume that if we are
13:57
receiving 2 60 bytes the half and full
14:01
transfer callbacks will be called once
14:04
and the remaining four bytes will be
14:05
stored in the first half of the RX data
14:08
buffer since we haven't received
14:11
128 bytes the call back won't be called
14:15
to handle this situation we will write
14:18
the reset of the code in the while loop
14:21
remember that we still have the size of
14:23
the incoming data so we will check the
14:25
difference between the size and the
14:29
our code will only execute if this
14:31
difference is less than
14:34
128 this is because the difference can
14:36
be large in the beginning and this means
14:39
that we are still receiving the data
14:42
when the difference is less than
14:44
128 this means that the last few bytes
14:46
have been received and the call back
14:49
hasn't been called further we will check
14:51
if the variable HDC is set if it is set
14:56
that means the HDC call back was called
14:58
and the extra bytes are in the second
15:00
half of the RX data buffer so we will
15:03
copy the remaining data to the final
15:05
buffer and update the value of the index
15:08
variable remember that we clear the RX
15:11
data buffer after copying data from it
15:14
so the string copy function works just
15:16
fine you can also use mem copy function
15:20
and copy the remaining bytes into the
15:22
final buffer as shown in the image now
15:25
let's reset the size received variable
15:28
so that the entire process can start
15:30
from the beginning reset the HTC
15:33
variable also the dma is in the circular
15:37
mode so it will continue storing the
15:39
data into the next position in the RX
15:42
data buffer we need to stop the dma
15:45
first and then receive the data again so
15:48
that it can start receiving from the
15:50
beginning similarly if the FDC variable
15:53
is set to one which means that the FDC
15:56
call back was called and the extra FES
15:58
are in the first half of the RX data
16:01
buffer so we will copy the remaining
16:03
data from the beginning of the RX data
16:06
buffer and update the value of the index
16:09
variable if we receive the data in the
16:13
256 the index variable will be equal to
16:17
size in this case we will check one more
16:20
condition if either of the HTC or FTC
16:23
variables were set this is because the
16:26
index variable is equal to the size in
16:29
the beginning or when all the data is
16:32
received so we want to avoid those
16:35
scenarios here here we don't need to
16:38
copy anything but we will reset the
16:40
variables and start the dma
16:46
again we have few warnings and that is
16:49
because the string copy function takes
16:51
the character pointer as the
16:53
parameter let me typ cast these
16:59
all right let's build and debug the
17:02
project now let me add the final buffer
17:09
expression also at the index variable
17:12
and the size variable let's send the
17:16
2,200 bytes we will send the size first
17:21
and then send the file the index
17:25
256 which means we only received 2 256
17:30
bytes well this is because I haven't
17:32
enabled the circular mode in the dma
17:35
configuration let me quickly enable
17:41
it let's build and debug
17:51
again we have received
17:54
2,200 bytes now let's check if the data
17:58
received is correct the data starts with
18:06
2399 we have it here in the beginning
18:09
there were a total of
18:11
2,200 bytes so we should see the last
18:17
2,199 this is not the data we were
18:20
expecting here here it is ending at
18:24
2203 basically we have the shift of four
18:27
bytes in the final buffer this is
18:30
because I made a mistake here since we
18:33
are copying the 124 bytes to the final
18:36
buffer the index value will increment by
18:44
again I will send the same file
18:51
again here you can see the data ends at
18:56
2,199 now let's send another file
19:05
now this file contains 2044 bytes and
19:09
combining the four bytes of size the
19:11
total data is 248 bytes a multiple of
19:16
256 we have received all the data
19:19
successfully let's try sending another
19:25
file here we have received 2,000
19:29
176 bytes so the data reception works
19:33
well with dma in circular mode too as I
19:36
mentioned earlier the final buffer is
19:39
defined just for the testing purpose you
19:42
can instead copy this received data
19:44
directly to the file in the SD card or
19:47
some flash memory all you need to do is
19:51
instead of this mem copy function use
19:53
another function to update the file the
19:56
parameters could remain the same
19:59
I will make a video to demonstrate this
20:01
in future this is it for the video I
20:05
hope you understood how the dma is used
20:07
to receive the data via the uart I will
20:11
continue the uart series and in the next
20:13
video we will see the idle line
20:15
interrupt and dma you can download the
20:19
code from the link in the description
20:22
leave comments in case of any doubt keep
20:25
watching and have a nice day ahead