Chapter 17 - Hongjayeong-02/Basic_SoC_implementation GitHub Wiki
CPU๊ฐ ์ง์ for๋ฌธ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณต์ฌํ์ง ์๊ณ , DMA2 Stream0 hardware๊ฐ source array๋ฅผ destination array๋ก ๋ณต์ฌํ๋๋ก ๊ตฌ์ฑํ๋ค.
sensor_data_arr
{892, 731, 1234, 90, 23}
โ
โ DMA2 Stream0
โผ
temp_data_arr
{892, 731, 1234, 90, 23}์ ์ก ์๋ฃ ํ:
DMA Transfer Complete
โ
TCIF0 = 1
โ
DMA2_Stream0_IRQHandler()
โ
g_transfer_cmplt = 1
โ
UART ๊ฒฐ๊ณผ ์ถ๋ ฅ์ด๋ฒ ์ค์ต:
DMA : DMA2
Stream : Stream0
Mode : Memory-to-Memory
Data Size : 16-bit
Source : sensor_data_arr[]
Dest : temp_data_arr[]
Length : 5
Interrupt : Transfer Complete / Transfer ErrorCPU๊ฐ ์ง์ ๋ฐฐ์ด์ ๋ณต์ฌํ๋ค๋ฉด:
for (int i = 0; i < BUFFER_SIZE; i++)
{
temp_data_arr[i] = sensor_data_arr[i];
}๋์์:
CPU
โ
Read Source
โ
Write Destination
โ
Read Source
โ
Write Destination
โ
...์ฆ ๋ฐ์ดํฐ ์ด๋์ CPU๊ฐ ์ง์ ์ํํ๋ค.
DMA๋ฅผ ์ฌ์ฉํ๋ฉด:
CPU
โ
DMA ์ค์
โ
Start
โ
DMA Hardware
โโโ Read Source
โโโ Write Destination
โโโ Read Source
โโโ Write Destination
โโโ ...
CPU
โ ๋ค๋ฅธ ์์
๊ฐ๋ฅ
์ด ๋๋ค.
STM32F439ZI์๋ DMA controller๊ฐ ์กด์ฌํ๊ณ ๊ฐ controller๋ ์ฌ๋ฌ Stream์ ๊ฐ์ง๋ค.
์ด๋ฒ ์ค์ต:
DMA2
โโโ Stream0๋ฅผ ์ฌ์ฉํ๋ค.
DMA transfer์ ๊ธฐ๋ณธ ์์:
Source Address
Destination Address
Data Count
Data Width
Transfer Direction
Address Increment
Interrupt์ด ์ค์ ๋๋ฉด hardware๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ง์ ์ด๋ํ๋ค.
์ด๋ฒ ์ฝ๋์์ ํต์ฌ:
DMA2_Stream0->CR
DMA2_Stream0->NDTR
DMA2_Stream0->PAR
DMA2_Stream0->M0AR
DMA2_Stream0->FCR
DMA2->LISR
DMA2->LIFCR
์ญํ :
| Register | ์ญํ |
|---|---|
| CR | Direction, size, increment, interrupt, enable |
| NDTR | ์ ์กํ data ๊ฐ์ |
| PAR | Source address |
| M0AR | Destination address |
| FCR | FIFO configuration |
| LISR | Stream0 interrupt status |
| LIFCR | Stream0 interrupt flag clear |
Project:
Inc/
โโโ dma.h
โโโ uart.h
Src/
โโโ dma.c
โโโ uart.c
โโโ main.c
#ifndef DMA_H__
#define DMA_H__
#include <stdint.h>
#include "stm32f4xx.h"
/*
- Configure DMA2 Stream0 for:
-
-
Memory โ Memory
-
- transfer.
-
- Data width:
-
-
16-bit
-
- Source / destination address:
-
-
automatically incremented.
*/
void dma2_mem2mem_config(void);
/*
- Start one DMA transfer.
-
- src_buff:
-
source address
-
- dest_buff:
-
destination address
-
- len:
-
number of 16-bit data items
*/
void dma_transfer_start(
uint32_t src_buff,
uint32_t dest_buff,
uint32_t len
);
#endif
#include "dma.h"
/*
- ============================================================
- DMA Register Definitions
- ============================================================
*/
/*
- RCC AHB1ENR:
-
- Enable DMA2 peripheral clock.
*/
#define DMA2EN RCC_AHB1ENR_DMA2EN
/*
- DMA Stream Control Register EN bit.
-
- EN = 1
- โ Stream active
-
- EN = 0
- โ Stream disabled
*/
#define DMA_SCR_EN DMA_SxCR_EN
/*
- Memory Increment Mode.
-
- After each transfer:
-
- destination address += data size
*/
#define DMA_SCR_MINC DMA_SxCR_MINC
/*
- Peripheral Increment Mode.
-
- In memory-to-memory mode,
- PAR is used as the source address.
-
- Therefore PINC causes the source address
- to increase after every transfer.
*/
#define DMA_SCR_PINC DMA_SxCR_PINC
/*
- Transfer Complete Interrupt Enable.
*/
#define DMA_SCR_TCIE DMA_SxCR_TCIE
/*
- Transfer Error Interrupt Enable.
*/
#define DMA_SCR_TEIE DMA_SxCR_TEIE
/*
- Disable Direct Mode.
-
- DMDIS = 1
-
- โ FIFO mode enabled.
*/
#define DMA_SFCR_DMDIS DMA_SxFCR_DMDIS
/*
- Stream0 Transfer Complete flag.
*/
#define LISR_TCIF0 DMA_LISR_TCIF0
/*
- Stream0 Transfer Error flag.
*/
#define LISR_TEIF0 DMA_LISR_TEIF0
/*
- Clear Stream0 Transfer Complete flag.
*/
#define LIFCR_CTCIF0 DMA_LIFCR_CTCIF0
/*
- Clear Stream0 Transfer Error flag.
*/
#define LIFCR_CTEIF0 DMA_LIFCR_CTEIF0
/*
- ============================================================
- DMA2 Stream0 Configuration
- ============================================================
*/
void dma2_mem2mem_config(void)
{
/*
* --------------------------------------------------------
* Step 1. Enable DMA2 Clock
* --------------------------------------------------------
*
* DMA2 registers cannot be used until
* the AHB1 peripheral clock is enabled.
*/
RCC->AHB1ENR |= DMA2EN;
/*
* --------------------------------------------------------
* Step 2. Disable Stream Before Configuration
* --------------------------------------------------------
*
* DMA configuration fields must not be modified
* while the stream is enabled.
*
* Writing CR = 0 requests Stream0 disable.
*/
DMA2_Stream0->CR = 0U;
/*
* IMPORTANT:
*
* Hardware may need a short time to actually
* complete the disable operation.
*
* Therefore wait until EN really becomes 0.
*/
while ((DMA2_Stream0->CR & DMA_SCR_EN) != 0U)
{
}
/*
* --------------------------------------------------------
* Step 3. Memory Data Size = 16-bit
* --------------------------------------------------------
*
* MSIZE<span>[1:0]</span>:
*
* 00 โ 8-bit
* 01 โ 16-bit
* 10 โ 32-bit
*
* Set:
*
* bit13 = 1
* bit14 = 0
*
* โ 16-bit
*/
DMA2_Stream0->CR |= (1U << 13);
DMA2_Stream0->CR &= ~(1U << 14);
/*
* --------------------------------------------------------
* Step 4. Source Data Size = 16-bit
* --------------------------------------------------------
*
* PSIZE<span>[1:0]</span>:
*
* In memory-to-memory mode PAR is used
* for the source address.
*
* 01 โ 16-bit
*/
DMA2_Stream0->CR |= (1U << 11);
DMA2_Stream0->CR &= ~(1U << 12);
/*
* --------------------------------------------------------
* Step 5. Destination Address Increment
* --------------------------------------------------------
*
* MINC = 1
*
* Destination:
*
* temp_data_arr<span>[0]</span>
* โ
* temp_data_arr<span>[1]</span>
* โ
* temp_data_arr<span>[2]</span>
* โ
* ...
*/
DMA2_Stream0->CR |= DMA_SCR_MINC;
/*
* --------------------------------------------------------
* Step 6. Source Address Increment
* --------------------------------------------------------
*
* PINC = 1
*
* Source:
*
* sensor_data_arr<span>[0]</span>
* โ
* sensor_data_arr<span>[1]</span>
* โ
* sensor_data_arr<span>[2]</span>
* โ
* ...
*/
DMA2_Stream0->CR |= DMA_SCR_PINC;
/*
* --------------------------------------------------------
* Step 7. Select Memory-to-Memory Direction
* --------------------------------------------------------
*
* DIR<span>[1:0]</span>:
*
* 00 โ Peripheral-to-Memory
* 01 โ Memory-to-Peripheral
* 10 โ Memory-to-Memory
*
* Therefore:
*
* bit6 = 0
* bit7 = 1
*/
DMA2_Stream0->CR &= ~(1U << 6);
DMA2_Stream0->CR |= (1U << 7);
/*
* --------------------------------------------------------
* Step 8. Enable Transfer Complete Interrupt
* --------------------------------------------------------
*
* When NDTR reaches zero after successful
* transfer:
*
* TCIF0 = 1
*
* and an interrupt is generated.
*/
DMA2_Stream0->CR |= DMA_SCR_TCIE;
/*
* --------------------------------------------------------
* Step 9. Enable Transfer Error Interrupt
* --------------------------------------------------------
*
* If a transfer error occurs:
*
* TEIF0 = 1
*/
DMA2_Stream0->CR |= DMA_SCR_TEIE;
/*
* --------------------------------------------------------
* Step 10. Enable FIFO Mode
* --------------------------------------------------------
*
* DMDIS = 1
*
* Direct Mode Disabled
* โ FIFO Mode Enabled
*/
DMA2_Stream0->FCR |= DMA_SFCR_DMDIS;
/*
* --------------------------------------------------------
* Step 11. FIFO Threshold = Full
* --------------------------------------------------------
*
* FTH<span>[1:0]</span> = 11
*
* FIFO threshold:
*
* Full
*/
DMA2_Stream0->FCR |= (1U << 0);
DMA2_Stream0->FCR |= (1U << 1);
/*
* --------------------------------------------------------
* Step 12. Enable Stream0 IRQ in NVIC
* --------------------------------------------------------
*
* DMA transfer completion/error can now
* generate a Cortex-M interrupt.
*/
NVIC_EnableIRQ(DMA2_Stream0_IRQn);
}
void dma_transfer_start(
uint32_t src_buff,
uint32_t dest_buff,
uint32_t len
)
{
/*
* --------------------------------------------------------
* Step 1. Set Source Address
* --------------------------------------------------------
*
* In this Mem-to-Mem configuration:
*
* PAR
*
* is used as the SOURCE address.
*
* Example:
*
* &sensor_data_arr[0]
*/
DMA2_Stream0->PAR = src_buff;
/*
* --------------------------------------------------------
* Step 2. Set Destination Address
* --------------------------------------------------------
*
* M0AR:
*
* Memory 0 Address Register
*
* points to the destination buffer.
*
* Example:
*
* &temp_data_arr<span>[0]</span>
*/
DMA2_Stream0->M0AR = dest_buff;
/*
* --------------------------------------------------------
* Step 3. Set Number of Data Items
* --------------------------------------------------------
*
* NDTR:
*
* Number of Data To Transfer
*
* BUFFER_SIZE = 5
*
* Because data width is 16-bit:
*
* this means:
*
* 5 ร 16-bit values
*/
DMA2_Stream0->NDTR = len;
/*
* --------------------------------------------------------
* Step 4. Enable DMA Stream
* --------------------------------------------------------
*
* EN = 1
*
* As soon as the stream is enabled,
* DMA hardware begins the transfer.
*/
DMA2_Stream0->CR |= DMA_SCR_EN;
}
#define BUFFER_SIZE 5U
/*
- Source buffer.
-
- Stored in initialized data memory.
*/
uint16_t sensor_data_arr[BUFFER_SIZE] =
{
892,
731,
1234,
90,
23
};
/*
- Destination buffer.
-
- DMA will fill this array.
-
- CPU does NOT execute:
-
-
temp_data_arr<span>[i]</span> = sensor_data_arr<span>[i]</span>;
*/
uint16_t temp_data_arr[BUFFER_SIZE];
/*
- Set by DMA ISR.
-
- main() waits for this flag.
-
- volatile is mandatory because:
-
-
main() reads it
-
ISR writes it
*/
volatile uint8_t g_transfer_cmplt = 0U;
#include <stdint.h>
#include "dma.h"
#include "uart.h"
#define BUFFER_SIZE 5U
/*
- ============================================================
- Source Buffer
- ============================================================
*/
uint16_t sensor_data_arr[BUFFER_SIZE] =
{
892,
731,
1234,
90,
23
};
/*
- ============================================================
- Destination Buffer
- ============================================================
-
- Before DMA:
-
-
not yet copied
-
- After DMA:
-
-
{892, 731, 1234, 90, 23}
*/
uint16_t temp_data_arr[BUFFER_SIZE];
/*
- ============================================================
- DMA Completion Flag
- ============================================================
-
- ISR:
-
writes this variable.
-
- main:
-
reads this variable.
*/
volatile uint8_t g_transfer_cmplt = 0U;
/*
- Existing practice used uart_print_uint16()
- for decimal output.
-
- If this helper is already present in uart.c,
- use the project version directly.
*/
void uart_print_uint16(uint16_t value);
int main(void)
{
/*
* --------------------------------------------------------
* Step 1. Initialize Completion Flag
* --------------------------------------------------------
*/
g_transfer_cmplt = 0U;
/*
* --------------------------------------------------------
* Step 2. Initialize USART3
* --------------------------------------------------------
*
* DMA copy result will be printed through UART.
*/
uart_init();
/*
* --------------------------------------------------------
* Step 3. Configure DMA2 Stream0
* --------------------------------------------------------
*
* Configuration:
*
* Memory-to-Memory
* Source increment
* Destination increment
* 16-bit โ 16-bit
* TC interrupt
* TE interrupt
*/
dma2_mem2mem_config();
/*
* --------------------------------------------------------
* Step 4. Start DMA Transfer
* --------------------------------------------------------
*
* Source:
*
* sensor_data_arr
*
* Destination:
*
* temp_data_arr
*
* Length:
*
* 5
*/
dma_transfer_start(
(uint32_t)sensor_data_arr,
(uint32_t)temp_data_arr,
BUFFER_SIZE
);
/*
* --------------------------------------------------------
* Step 5. Wait for DMA Completion
* --------------------------------------------------------
*
* DMA hardware is transferring the data.
*
* When transfer completes:
*
* DMA2_Stream0_IRQHandler()
*
* sets:
*
* g_transfer_cmplt = 1
*
* NOTE:
*
* This busy-wait is used only to make this
* educational test simple.
*
* In a real application the CPU could perform
* other work while DMA is running.
*/
while (g_transfer_cmplt == 0U)
{
}
/*
* --------------------------------------------------------
* Step 6. Print Destination Buffer
* --------------------------------------------------------
*
* If DMA worked correctly:
*
* temp_data_arr[]
*
* must exactly match:
*
* sensor_data_arr[]
*/
for (uint32_t i = 0U;
i < BUFFER_SIZE;
i++)
{
uart_write_string("Temp buffer<span>[");
uart_print_uint16((uint16_t)i);
uart_write_string("]</span>: ");
uart_print_uint16(temp_data_arr<span>[i]</span>);
uart_write_string("\r\n");
}
/*
* Clear software completion flag after verification.
*/
g_transfer_cmplt = 0U;
/*
* Test complete.
*/
while (1)
{
}
}
void DMA2_Stream0_IRQHandler(void)
{
/*
* ========================================================
* Transfer Complete
* ========================================================
/
if ((DMA2->LISR & LISR_TCIF0) != 0U)
{
/
* Tell main():
*
* DMA transfer completed successfully.
*/
g_transfer_cmplt = 1U;
/*
* Clear Transfer Complete Flag.
*
* DMA interrupt clear registers use:
*
* Write 1 to Clear
*
* Direct assignment is preferable for W1C
* style registers when clearing a specific flag.
*/
DMA2->LIFCR = LIFCR_CTCIF0;
}
/*
* ========================================================
* Transfer Error
* ========================================================
*/
if ((DMA2->LISR & LISR_TEIF0) != 0U)
{
/*
* Transfer Error occurred.
*
* This basic exercise only clears the flag.
*
* A real system could additionally:
*
* set error flag
* retry transfer
* log the failure
*/
DMA2->LIFCR = LIFCR_CTEIF0;
}
}
์๋ณธ ์ค์ต ๊ธฐ๋ก์:
DMA2->LIFCR |= LIFCR_CTCIF0;
DMA2->LIFCR |= LIFCR_CTEIF0;ํํ์๋ค.
ํ์ง๋ง interrupt clear register๋ ํน์ bit์ 1์ ์จ์ flag๋ฅผ clearํ๋ ๊ตฌ์กฐ๋ค.
๊ทธ๋์ Wiki ์ต์ข ๋ณธ์์๋:
DMA2->LIFCR = LIFCR_CTCIF0;์ฒ๋ผ clearํ๋ ค๋ bit๋ง ์ง์ writeํ๋ ํํ๋ก ์ ๋ฆฌํ๋ค.
Ch14์:
EXTI->PR = LINE13;๊ณผ ๊ฐ์ W1C register handling ์์น์ด๋ค.
์ด๊ธฐ ์ํ:
sensor_data_arr
[0] 892
[1] 731
[2] 1234
[3] 90
[4] 23
DMA registers:
PAR
โ
sensor_data_arr[0]
M0AR
โ
temp_data_arr[0]
NDTR
โ
5
Transfer ์์:
DMA Stream EN = 1
โ์ฒซ ๋ฒ์งธ data:
Read 892
from Source
โ
Write 892
to Destination
โ
PINC
Source Address + 2 bytes
MINC
Destination Address + 2 bytes
NDTR
5 โ 4
๋ค์:
731
โ
1234
โ
90
โ
23๋ง์ง๋ง:
NDTR
1 โ 0
โ
Transfer Complete
โ
TCIF0 = 1๋ง์ฝ increment๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค๋ฉด:
Source Address
always same
Destination Address
always same
๊ฐ ๋๋ค.
๊ทธ๋ฌ๋ฉด ์ฌ๋ฌ array element๋ฅผ ์์๋๋ก ๋ณต์ฌํ ์ ์๋ค.
์ด๋ฒ ์ค์ :
DMA2_Stream0->CR |= DMA_SCR_PINC;
DMA2_Stream0->CR |= DMA_SCR_MINC;๋๋ฌธ์:
16-bit transfer
2 bytes
์ฉ address๊ฐ ์ด๋ํ๋ค.
Source:
&arr[0]
โ +2
&arr[1]
โ +2
&arr[2]
Destination๋ ๋์ผํ๋ค.
๋ฐฐ์ด type:
uint16_t์ด๋ค.
์ฆ element ํ๋:
16 bits
2 bytes
๋ฐ๋ผ์ DMA:
PSIZE = 16-bit
MSIZE = 16-bit๋ก ๋ง์ถ๋ค.
Source Element
16-bit
โ DMA
Destination Element
16-bit
data width๊ฐ source variable type๊ณผ ๋ง์์ผ ํ๋ค.
์ค์:
DMA2_Stream0->NDTR = 5;๋:
5 bytes๋ผ๋ ๋ป์ด ์๋๋ค.
ํ์ฌ transfer width๊ฐ:
16-bit์ด๋ฏ๋ก:
5 data items
ร
2 bytes
10 bytes
๋ฅผ ์ ์กํ๋ค.
์ฆ:
NDTR
Number of Transfer Items
์ด๋ค.
DMA stream์ด active ์ํ์ผ ๋๋ ์ฌ๋ฌ configuration field๋ฅผ ์์ ํ ์ ์๋ค.
๊ทธ๋์:
DMA2_Stream0->CR = 0U;
while (DMA2_Stream0->CR & DMA_SCR_EN)
{
}
์ ์ํํ๋ค.
ํ๋ฆ:
Request Disable
โ
Hardware finishing current operation
โ
EN still 1
โ
Wait
โ
EN = 0
โ
Now configuration can changeCh15 RTC์ ready flag, Ch16 IWDG์ PVU/RVU์ ๊ฐ์ pattern์ด๋ค.
Write Hardware Control
โ
Wait Until Hardware Confirms
โ
Continuevolatile uint8_t g_transfer_cmplt;main:
while (!g_transfer_cmplt)
{
}ISR:
g_transfer_cmplt = 1U;์ฆ:
main context
โ
shared variable
โ
interrupt context๊ตฌ์กฐ๋ค.
volatile์ด ์๋ค๋ฉด compiler๋ main๋ง ๋ณด๊ณ :
์ด loop ์์์
g_transfer_cmplt๋ฅผ ๋ฐ๊พธ๋ ์ฝ๋๊ฐ ์๋๋ฐ?๋ผ๊ณ ํ๋จํด memory๋ฅผ ๋ฐ๋ณตํด์ ์ฝ์ง ์๋ ์ต์ ํ๋ฅผ ํ ๊ฐ๋ฅ์ฑ์ด ์๋ค.
volatile์:
์ด ๋ณ์๋ CPU ์คํ ํ๋ฆ ๋ฐ์ ์์ธ์ ์ํด
์ธ์ ๋ ๋ณ๊ฒฝ๋ ์ ์๋ค๊ณ compiler์๊ฒ ์๋ ค์ค๋ค.
ํ์ฌ:
while (!g_transfer_cmplt)
{
}๋ก ๊ธฐ๋ค๋ฆฐ๋ค.
๊ทธ๋ฌ๋ฉด:
DMA๋ฅผ ์จ๋๊ณ CPU๊ฐ ๊ธฐ๋ค๋ฆฌ๋๋ฐ ๋ฌด์จ ์๋ฏธ๊ฐ ์์ง?
๋ผ๋ ์๋ฌธ์ด ์๊ธธ ์ ์๋ค.
๋ง๋ค.
์ด ์ฝ๋๋ DMA ๋์ ๊ฒ์ฆ์ฉ ๋จ์ ์ค์ต์ด๋ค.
์ค์ ํ์ฉ:
dma_transfer_start(...);
while (1)
{
/*
* ๋ค๋ฅธ sensor ์ฒ๋ฆฌ
* communication
* control algorithm
* state machine
*/
if (g_transfer_cmplt)
{
/*
* DMA result processing
*/
}
}
ํํ๊ฐ ๋ ์ ์ ํ๋ค.
ํต์ฌ์ DMA๊ฐ:
CPU instruction ์์ด
data transfer ์์ฒด๋ฅผ ์ํํ ์ ์๋ค๋ ๊ฒ์ด๋ค.
DMA Transfer
โ
NDTR reaches 0
โ
TCIF0 = 1
โ
DMA2_Stream0_IRQn
โ
NVIC
โ
DMA2_Stream0_IRQHandler()
โ
g_transfer_cmplt = 1
โ
TCIF0 Clear
โ
ReturnISR์๋ if๊ฐ ๋ ๊ฐ ์๋ค.
if (TCIF0)
{
}
if (TEIF0)
{
}
Transfer Complete์ ์ ์ข ๋ฃ.
Transfer Error์ ์ก ์ค error ๋ฐ์.
๋์ ์๋ฏธ๊ฐ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ๋ ๋ฆฝ์ ์ผ๋ก ๊ฒ์ฌํ๋ค.
Source:
sensor_data_arr
[0] = 892
[1] = 731
[2] = 1234
[3] = 90
[4] = 23
์ค์ UART ์ถ๋ ฅ:
Temp buffer[0]: 892
Temp buffer[1]: 731
Temp buffer[2]: 1234
Temp buffer[3]: 90
Temp buffer[4]: 23์ฆ:
Source
Destination
๋ฅผ ์ค์ board์์ ํ์ธํ๋ค.
๋ฐ๋ผ์:
DMA Memory-to-Memory Transfer
PASS์ด๋ค.
Debugger๋ฅผ ์ฌ์ฉํ๋ค๋ฉด DMA ์ :
sensor_data_arr
892
731
1234
90
23
temp_data_arr
0
0
0
0
0
๋ฅผ ํ์ธํ๋ค.
DMA ํ:
temp_data_arr
892
731
1234
90
23
์ผ๋ก ๋ฐ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์ด ๊ฒฝ์ฐ CPU code์๋:
temp_data_arr[i] = sensor_data_arr[i];๊ฐ ํ ์ค๋ ์๋ค๋ ๊ฒ์ด ํต์ฌ์ด๋ค.
์ด๋ฒ chapter์์๋ ๊ตฌํํ์ง ์์์ง๋ง ADC์ DMA๋ฅผ ์ฐ๊ฒฐํ๋ฉด:
Analog Input
โ
ADC
โ
ADC->DR
โ
DMA
โ
Buffer[]๊ตฌ์กฐ๊ฐ ๋๋ค.
CPU๊ฐ ๋งค conversion๋ง๋ค:
adc_read();ํ์ง ์์๋ ๋๋ค.
๋ณดํต continuous ADC acquisition์์๋:
Peripheral-to-Memory
+
Circular Mode๋ฅผ ๋ง์ด ์ฌ์ฉํ๋ค.
๊ฐ๋ :
ADC Sample
โ
Buffer[0]
ADC Sample
โ
Buffer[1]
...
Buffer End
โ
Back to Buffer[0]
UART TX:
Memory Buffer
โ
DMA
โ
USART->DR
โ
TX๋ฐฉํฅ:
Memory-to-PeripheralUART RX:
USART->DR
โ
DMA
โ
Memory Buffer๋ฐฉํฅ:
Peripheral-to-MemoryUART peripheral ์์ฒด์์๋ DMA request๋ฅผ enableํด์ผ ํ๋ค.
์:
USART CR3
DMAT / DMAR์ด๋ฒ chapter์์๋ ๊ฐ๋ ๋ง ๋ค๋ฃจ๊ณ ์ค์ ๊ตฌํ์ ํ์ง ์์๋ค.
์ค์ ์ค์ต:
Build : PASS
Download : PASS
Run : PASS
DMA Copy : PASSProgram size:
text = 1640 bytes
data = 12 bytes
bss = 2572 bytes์ด๋ฒ์๋ ์ด๊ธฐ๊ฐ์ด ์กด์ฌํ๋ global array:
uint16_t sensor_data_arr[5] =
{
892,
731,
1234,
90,
23
};๊ฐ ์๋ค.
ํฌ๊ธฐ:
5
ร
2 bytes
10 bytes
์ถ๊ฐ ์ด๊ธฐํ data ๋ฐ alignment์ ์ํฅ๊น์ง ํฌํจ๋์ด ์ค์ต build์์๋:
.data = 12 bytes๊ฐ ๊ธฐ๋ก๋๋ค.
๋ฐ๋ฉด:
uint16_t temp_data_arr[5];์ฒ๋ผ ์ด๊ธฐ๊ฐ์ด ์๋ global variable์ .bss ์์ญ์ ๋ฐฐ์น๋๋ค.
make clean
makeExpected:
text = 1640
data = 12
bss = 2572Debugger:
DMA2_Stream0->CR
DMA2_Stream0->FCRํ์ธ:
DIR = Memory-to-Memory
PINC = 1
MINC = 1
PSIZE = 16-bit
MSIZE = 16-bit
TCIE = 1
TEIE = 1
ํ์ธ:
DMA2_Stream0->PARโ sensor_data_arr ์ฃผ์์ ์ผ์น.
DMA2_Stream0->M0ARโ temp_data_arr ์ฃผ์์ ์ผ์น.
์ ์ก ์ :
NDTR = 5์ ์ก ์ค:
5
โ
4
โ
3
โ
2
โ
1
โ
0์ ์ก ์๋ฃ:
NDTR = 0Breakpoint:
void DMA2_Stream0_IRQHandler(void)์ ์ก ์๋ฃ ์ ISR์ ์ง์ ํ๋์ง ํ์ธํ๋ค.
Watch:
DMA2->LISR
g_transfer_cmpltExpected:
TCIF0
0 โ 1
g_transfer_cmplt
0 โ 1
Expected:
temp_data_arr[0] = 892
temp_data_arr[1] = 731
temp_data_arr[2] = 1234
temp_data_arr[3] = 90
temp_data_arr[4] = 23images/ch17_build.png
images/ch17_dma_registers.png
images/ch17_addresses.png
images/ch17_ndtr.png
images/ch17_dma_isr.png
images/ch17_memory_before.png
images/ch17_memory_after.png
images/ch17_uart_result.png๊ฐ์ฅ ์ข์ evidence:
Source Array
+
PAR / M0AR
+
NDTR = 5 โ 0
+
TC Interrupt
+
Destination Array
+
UART Result์ด๋ค.
CPU
โ
DMA Configuration
โ
Source Address
Destination Address
Length
Direction
Size
โ
DMA Enable
โ
Hardware Data Transfer
โ
TC Interrupt
โ
CPU NotificationDMA๋ CPU ๋์ data movement๋ฅผ ์ํํ๋ hardware๋ค.
์ด๋ฒ ์ค์ต์
DMA2 Stream0์ Memory-to-Memory transfer๋ฅผ ์ฌ์ฉํ๋ค.source์ destination์ ๋ชจ๋
uint16_t์ด๋ฏ๋ก PSIZE/MSIZE๋ฅผ 16-bit๋ก ์ค์ ํ๋ค.PINC์MINC๋ฅผ enableํ์ฌ ์์ชฝ address๋ฅผ ์๋ ์ฆ๊ฐ์ํจ๋ค.PAR๋ ์ด๋ฒ Mem-to-Mem ์ค์ ์์ source address๋ก ์ฌ์ฉํ๋ค.M0AR์ destination address๋ค.NDTR=5๋ 5byte๊ฐ ์๋๋ผ 5๊ฐ์ 16-bit transfer item์ ์๋ฏธํ๋ค.Stream ์ค์ ์
EN=0์ ๋ฐ๋์ ํ์ธํ๋ค.Transfer Complete์ Transfer Error interrupt๋ฅผ ๊ฐ๊ฐ enableํ๋ค.
g_transfer_cmplt๋ ISR๊ณผ main์ด ๊ณต์ ํ๋ฏ๋กvolatile์ด๋ค.์ค์ board์์
{892, 731, 1234, 90, 23}์ด ์ ํํ ๋ณต์ฌ๋๋ ๊ฒ์ ํ์ธํ๋ค.ADC/UART DMA๋ ์ด๋ฒ chapter์์๋ ๊ฐ๋ ๋ง ๋ค๋ฃจ๊ณ ์ค์ ๊ตฌํํ์ง ์์๋ค.