STM32 USART DMA - FabLabSeoul/WingProject GitHub Wiki
์ด ๊ธ์ Stm32 Value line discovery ๋ณด๋ ์ ์ฉ ๊ธ์ด๋ค.
์๋ฆฌ์ผํต์ ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ํฌ๊ฒ ์ธ๊ฐ์ง๋ก ๋๋ ์ ์๋ค. ํ๋๋ ํ๋๊ทธ ๊ฐ์ ํ์ธํ๋ฉด์ while
๋ฌธ์ผ๋ก ํ๋ก๊ทธ๋๋ฐํ๋ ๋ฐฉ๋ฒ์ด ์๊ณ (ํํ ํด๋ง์ด๋ผ๊ณ ํ๋ค), ๋ ๋ฒ์งธ๋ ์ธํฐ๋ฝํธ๋ฅผ ์ค์ ํด ์ ๋ณด๋ฅผ ์ฃผ๊ณ ๋ฐ์ ๋๋ง๋ค ์ธํฐ๋ฝํธ์์ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ด ์๋ค. ๊ทธ๋ฆฌ๊ณ ๋ง์ง๋ง์ผ๋ก ์ด ๊ธ์์ ์ค๋ช
ํ DMA๋ฐฉ์์ด ์๋ค. ์ด ๋ฐฉ๋ฒ์ ์์๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋ง๋ค์ด ์๋ฆฌ์ผํต์ ์ผ๋ก ์ฃผ๊ณ ๋ฐ๋ ์ ๋ณด๋ค์ ๋ฉ๋ชจ๋ฆฌ๋ก ๊ด๋ฆฌํ๋ ๋ฐฉ์์ด๋ค. ํ์์ด ์๋ ๋ง์ ์ข
๋ฅ์ ์ ๋ณด๋ค์ ์ฃผ๊ณ ๋ฐ์๋ ค๋ฉด ์ด๋ฌํ DMA ๋ฐฉ์์ด ํจ์จ์ ์ด๋ค.
์์ค์ฝ๋๋ STM32\stm32vldiscovery_package\Project\Examples\Serial_DMA ํด๋์ ์๋ค. ์ด ์์ ๋ USART1 PA10,9(Rx,Tx) ํฌํธ๋ฅผ ์ด์ฉํด์ ์๋ฆฌ์ผ ํต์ ์ ํ๋ค. ๋จผ์ ํน์ ๋ฌธ์์ด์ ์ก์ ํ๊ณ , ์ผ์ ์ด์์ ๊ฐฏ์๋งํผ ์ ๋ ฅ์ ๋ฐ์, ๋ฐ์ ๋ฌธ์๋ฅผ ๊ทธ๋๋ก ์ก์ ํ๋ค. ์ด๋ ๊ฒ ๊ณ์ ๋ฐ๋ณตํ๋ค.
DMA(Direct Memory Access) CPU๋ฅผ ๊ฑฐ์น์ง์๊ณ , ์์ฒด ์ปจํธ๋กค๋ฌ์์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ ์๋๊ฐ ๋น ๋ฅด๋ค.
I2Cํต์ ์ด๋ DAC, ADC ๋ชจ๋์์๋ DMA๋ฅผ ์ฌ์ฉํ๋ค. ์ผ๋ฐ์ ์ผ๋ก ์ฌ๋ฌ ์ ๋ณด๋ฅผ ํ๋์ ๋ชจ๋์์ ์ฒ๋ฆฌํ ๋ DMA๋ฅผ ์ฌ์ฉํ๋ค. ์๋ฆฌ์ผ ํต์ ๋ํ ๋ง์ฐฌ๊ฐ์ง๋ค. Rx,Tx๋ก ์ฃผ๊ณ ๋ฐ๋ ์ ๋ณด๋ค์ ๋ฒํผ์ ๋ด์ ์ฒ๋ฆฌํด์ผํ๊ธฐ ๋๋ฌธ์ด๋ค.
DMA์ ๋ํ ์์ธํ ๋ด์ฉ์ ๋งค๋ด์ผ์ ์ฐธ๊ณ ํ์. ๋ธ๋ญ๋ค์ด์ด๊ทธ๋จ๊ณผ ๋ ์ง์คํฐ ์ ๋ณด๋ฅผ ๋ณด์ฌ์ฃผ๋๋ฐ, ํ๋์จ์ด์ ๋ฅํตํ ์ฌ๋์ด ์๋๋ผ๋ฉด ์ดํดํ๊ธฐ ์ฝ์ง์์ ์ค๋ช ๋ค์ด๋ค. ์ผ๋จ ์ฝ๋๋ฅผ ๋ณด๋ฉด์ ์ค๋ช ์ ํ๊ฒ ๋ค.
Stm32F10x ๊ณ์ด์ MCU๋ USART1, USART2 ๋ ๊ฐ์ USART๋ชจ๋์ด ์๋ค. USART1์ ํฌํธ๋ ์ผ๋ฐ์ ์ผ๋ก PA10,9 (Rx,Tx)๋ก ํ๋ค. USART2์ ํฌํธ๋ PA3,2(Rx,Tx) ๋ค. remappingํ๋ฉด ํฌํธ๋ฅผ ๋ฐ๊ฟ ์ ์๋ค.
GPIO ํด๋ญ์ ์ด๊ธฐํํ๊ณ , ํฌํธ ์์ฑ์ ์ค์ ํ๋ ๊ฒ์ ์ผ๋ฐ์ ์ธ USART์ค์ ๊ณผ ๋ค๋ฅผ๋ฐ ์๋ค. Stm32 UART๋ฌธ์์ ๋์ ์๋ค. USART์์ DMA๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ถ๊ฐ์ ์ผ๋ก USART_DMACmd()
ํจ์์ DMA_Cmd()
ํจ์๋ฅผ ์ฌ์ฉํ๋ค.
GPIO ์ด๊ธฐํ
USART1์ ์ด๊ธฐํ ํ๋ค. PA10,9(Rx,Tx)ํฌํธ๋ฅผ ์ค์ ํ๊ณ , ํด๋ญ์ ์ค์ ํ๋ค. DMA๋ฅผ ์ฌ์ฉํ ๊ฒ์ด๋ DMAํด๋ญ๋ ์ค์ ํ๋ค.
void main()
{
/* System Clocks Configuration */
RCC_Configuration();
/* Configure the GPIO ports */
GPIO_Configuration();
/* Configure the DMA */
DMA_Configuration();
}
void RCC_Configuration(void)
{
// DMA clock enable
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
// Enable GPIO clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure USART1 Rx as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure USART1 Tx as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
DMA ์ด๊ธฐํ
DMA๋ฅผ ์ด๊ธฐํ ํ๋ค. DMA1_Channel4 ์ฑ๋์ Tx๋ก DMA1_Channel5๋ฅผ Rx๋ก ์ค์ ํ๋ค. ์ด ์ฑ๋์ ์ด๋ฏธ ์ ํด์ ธ ์์ผ๋ ๋ค๋ฅธ๊ฒ์ ์ธ ์ ์๋ค. ๋ค์๋งํ๋ฉด USART1_TX ๋ DMA1_Channel4 ์ฑ๋์ด์ด์ผ ํ๊ณ , USART1_RX๋ DMA1_Channel5 ๋ก ์ ํด์ ธ ์๋ค.
DMA1_Channel5์ DMA_Mode๊ฐ DMA_Mode_Circular
์ธ ๊ฒ์ ์ฃผ๋ชฉํ์. ์ ๋ณด๊ฐ ๋ฒํผ๋ฅผ ๋์ด๊ฐ๋ ์ฒ์์ผ๋ก ๋ค์ ๋์์ค๋, ์ฃผ๊ธฐ์ ์ผ๋ก ๋ฒํผ๋ฅผ ๊ฐ์ ธ์ค๋ฉด ๋ฌธ์ ์์ด ์๋ฆฌ์ผ ํต์ ์ ํ ์ ์๋ค. ๋๋จธ์ง ํ๋๊ทธ๋ค์ ๋งค๋ด์ผ์ ์ฐธ์กฐํ์.
DMA1_Channel4๋ ์ฐ๊ธฐ๋ฒํผ๊ฐ ๋๋ฉฐ, TxBuffer1[]์ ์ ๋ณด๋ฅผ USART1->DR ๋ ์ง์คํฐ์ ์ฃผ๊ธฐ์ ์ผ๋ก ์ฐ๋ ์ญํ ์ ํ๋ค. ์ด๋ ๊ฒ๋๋ฉด TxBuffer1[]์ ์ฅ๋ ์ ๋ณด๊ฐ ์๋ฆฌ์ผ์ ํตํด ์ก์ ๋๊ฒ ๋๋ค. DMA1_Channel5๋ ์ฝ๊ธฐ๋ฒํผ๊ฐ ๋๋ฉฐ, USART1->DR ๋ ์ง์คํฐ์ ์ ๋ณด๋ฅผ ์ฝ์ด RxBuffer1[]์ ์ฃผ๊ธฐ์ ์ผ๋ก ์ฐ๋ ์ญํ ์ ํ๋ค. ์ด๋ ๊ฒ๋๋ฉด ์๋ฆฌ์ผํต์ ์ผ๋ก ๋์ด์จ ์ ๋ณด๊ฐ RxBuffer1[]์ ์ ์ฅ๋๊ฒ ๋๋ค. ํต์ ์ ๋ง๋ฌด๋ฆฌ๋ TxBufferSize1๋งํผ ์ฐ๊ฑฐ๋(DMA1_Channel4), ๋ฐ์ผ๋ฉด(DMA1_Channel5) ์ข ๋ฃ๋๊ฒ ๋๋ค.
#define TxBufferSize1 (countof(TxBuffer1) - 1)
#define countof(a) (sizeof(a) / sizeof(*(a)))
uint8_t TxBuffer1[] = "USART DMA Interrupt: USARTy -> USARTz using DMA Tx and Rx Flag";
uint8_t RxBuffer1[TxBufferSize1];
uint8_t NbrOfDataToRead = TxBufferSize1;
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
// USARTy_Tx_DMA_Channel (triggered by USARTy Tx event) Config
DMA_DeInit(DMA1_Channel4);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer1;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = TxBufferSize1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
// USARTy_Rx_DMA_Channel (triggered by USARTy Rx event) Config
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)RxBuffer1;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = TxBufferSize1;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
}
USART ์ด๊ธฐํ
USART1 ์ต์
์ ์ค์ ํ๊ณ , ํ์ฑํ ํ๋ค. USART_DMACmd()
ํจ์์ DMA_Cmd()
ํจ์๋ก DMA๋ฅผ ์ค์ ํ๊ณ , ํ์ฑํ ํ๋ค.
DMA_Cmd(DMA1_Channel4, ENABLE);
๊ฐ ์คํ๋๋ ์๊ฐ ์๋ฆฌ์ผ ์ก์ ์ ์์ํ๋ค.
// USART1 ์ด๊ธฐํ
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
// Enable USART1 DMA TX request
USART_DMACmd(USART1, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);
// Enable USART1
USART_Cmd(USART1, ENABLE);
// Enable USART1 DMA TX, RX Channel
DMA_Cmd(DMA1_Channel4, ENABLE);
DMA_Cmd(DMA1_Channel5, ENABLE);
๋งค์ธ๋ฃจํ
TxBuffer1[] ์ ๋ณด๋ฅผ ์๋ฆฌ์ผ ์ก์ ํ๊ณ , RxBuffer1[]์ ์ ๋ณด๋ฅผ ์ ์ฅํ๊ณ ์๋ค. DMA_GetFlagStatus()
ํจ์๋ DMA ์ํ๋ฅผ ์ป์ด์ค๋ ํจ์๋ค. DMA_GetFlagStatus(DMA1_FLAG_TC4)
์ฝ๋๋ DMA1_Channel4๊ฐ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋ชจ๋ ๋ณต์ฌํ๋์ง๋ฅผ ์์๋ณด๋ ํจ์๋ค. TC๋ transmit complete์ ์ฝ์๋ค. DMA_GetFlagStatus(DMA1_FLAG_TC5)
์ฝ๋๋ ๋ง์ฐฌ๊ฐ์ง๋ค.
์ก์์ ์ด ๋ชจ๋ ๋๋ฌ์ผ๋ฉด, ๋ฐ์ ์ ๋ณด๊ฐ RxBuffer1์ ์ ์ฅ๋์ด ์์ํ ๋, ๊ทธ ์ ๋ณด๋ฅผ ๊ทธ๋๋ก TxBuffer1์ ์ ์ฅํ๊ณ , ๋ค์ ์ก์ ํ๋ค.
์ฃผ์ํด์ผ ๋ ์ ์ DMA๊ฐ ์๊ธฐ์ญํ ์ด ๋๋๋ฉด ์ ๋ณด๊ฐ ๋ณ๊ฒฝ๋์ด ์๋ค๋ ์ ์ด๋ค. ์ผ๋จ ์ก์์ ํฌ๊ธฐ ๊ฐ์ด ๋ฐ๋ ์ํ์ด๊ณ , baseAddress๋ ๋ฐ๋์ํ๋ค. ์ด ๊ฐ์ ์๋๋๋ก ๋ณต๊ตฌํ ๋ค์ DMA_Cmd()
ํจ์๋ก ์ฌํ์ฑํ ํ๋ฉด๋๋ค.
๊ทธ๋ฆฌ๊ณ DMA transfer๋ฅผ ์งํํ๋ฉด์ ์ฌ๋ฌ ํ๋๊ทธ๊ฐ ์ค์ ๋์๋ ๊ฒ์ DMA_ClearITPendingBit()
ํจ์๋ก ์ด๊ธฐํํ๋ค.
while(1)
{
int i=0;
while (DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
{
}
// Wait until USARTy RX DMA1 Channel Transfer Complete
while (DMA_GetFlagStatus(DMA1_FLAG_TC5) == RESET)
{
}
// TxBufferSize1 ๊ธธ์ด ๋งํผ ์๋ฆฌ์ผ ์
๋ ฅ์ ๋ฐ์ ํ์ ๋๊ฐ์ ๋ฌธ์์ด์ ๋ค์ ๋ณด๋ธ๋ค.
// ๊ทธ๋ฆฌ๊ณ , ๋ค์ ์๋ฆฌ์ผ์
๋ ฅ์ ๋ค์ด ์ฌ ๋ ๊น์ง ๋๊ธฐํ๋ค.
for (i=0; i < TxBufferSize1; ++i)
{
TxBuffer1[ i] = RxBuffer1[ i];
}
DMA_ClearITPendingBit(DMA1_IT_TC4);
DMA_ClearITPendingBit(DMA1_IT_TC5);
DMA_Cmd(DMA1_Channel4, DISABLE);
uartStartTxDMA(DMA1_Channel4);
}
void uartStartTxDMA(DMA_Channel_TypeDef *txDMAChannel)
{
txDMAChannel->CMAR = (uint32_t)TxBuffer1;
txDMAChannel->CNDTR = TxBufferSize1;
DMA_Cmd(txDMAChannel, ENABLE);
}