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);
}