STM32 ADC1 DMA 사용방법1

CPU/STM32F103 2013. 2. 7. 23:29

STM32 ADC1 DMA 사용방법을 구현해 보겠씁니다.

ST example 의 설명입니다.

Example description

===================

This example describes how to use the ADC1 and DMA to transfer continuously 

converted data from ADC1 to memory.

The ADC1 is configured to converts continuously ADC channel14.

Each time an end of conversion occurs the DMA transfers, in circular mode, the

converted data from ADC1 DR register to the ADC_ConvertedValue variable.

The ADC1 clock is set to 14 MHz.


그 동안 인터럽트 모드 폴링모드만 써 보았는데..STM32는 DMA로 사용할수 있네요.

설정 자체는 상당히 긴데..하나씩 살펴 보겠씁니다.

하드웨어는 PC0(ADC10)에 가변저항이 연결되어 있습니다.


1. stm32f10x_conf.h 수정

#define _ADC

#define _ADC1


#define _DMA

#define _DMA1_Channel1

을 설정해야 해당 라이브러리를 사용할수 있습니다.


2. Project file에 stm32f10x_adc.c 와 stm32f10x_dma를 포함합니다.


3. Main 초기화

3.1 Clock설정

 /* Enable DMA1 clock */

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);


  /* Enable ADC1 and GPIOC clock */

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);

ADC를 사용하기 위해 ADC와 DMA 그리고 GPIOC 포트DP 클럭을 인가합니다.

3.1 PORT PIN IO 설정

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

GPIO_Init(GPIOC, &GPIO_InitStructure);

해당핀 PORT C의 0핀 즉 ADC10를 아나로그 입력으로 설정하다.


3.2 DMA 설정

1>#define ADC1_DR_Address    ((u32)0x4001244C)

2>vu16 ADCConvertedValue;

3>DMA_InitTypeDef DMA_InitStructure;


/* DMA1 channel1 configuration ----------------------------------------------*/

3>  DMA_DeInit(DMA1_Channel1);

4> DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;

5>  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADCConvertedValue;

6>  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

7> DMA_InitStructure.DMA_BufferSize = 1;

8>  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

9> DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;

10>  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

11> DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

12>  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

13> DMA_InitStructure.DMA_Priority = DMA_Priority_High;

14>  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

15>  DMA_Init(DMA1_Channel1, &DMA_InitStructure);


/* Enable DMA1 channel1 */

  DMA_Cmd(DMA1_Channel1, ENABLE);

내용이 상당히 많다..머 이렇게 많은지.

1> 레지스터 ADC_DR의 주소이다.

2> typedef volatile unsigned short vu16;

3>Deinitializes the DMAy Channelx registers to their default reset values.

4> DMA_InitTypeDef DMA_InitStructure; 라고 정의 되어있고

typedef struct

{

  u32 DMA_PeripheralBaseAddr;

  u32 DMA_MemoryBaseAddr;

  u32 DMA_DIR;

  u32 DMA_BufferSize;

  u32 DMA_PeripheralInc;

  u32 DMA_MemoryInc;

  u32 DMA_PeripheralDataSize;

  u32 DMA_MemoryDataSize;

  u32 DMA_Mode;

  u32 DMA_Priority;

  u32 DMA_M2M;

}DMA_InitTypeDef;

이렇게 정의 되어 있네요.

각각의 내용은 CPU내용을 참조해되는데 상당히 복잡하네요..요것은 다음에 다시 한번 살펴보기로 하고. 각각의 필드를 채우고 아래 함수를 콜 하네요.


/*******************************************************************************

* Function Name  : DMA_Init

* Description    : Initializes the DMAy Channelx according to the specified

*                  parameters in the DMA_InitStruct.

* Input          : - DMAy_Channelx: where y can be 1 or 2 to select the DMA and 

*                    x can be 1 to 7 for DMA1 and 1 to 5 for DMA2 to select the 

*                    DMA Channel.

*                  - DMA_InitStruct: pointer to a DMA_InitTypeDef structure that

*                    contains the configuration information for the specified

*                    DMA Channel.

* Output         : None

* Return         : None

******************************************************************************/

void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct)

{

  u32 tmpreg = 0;


  /* Check the parameters */

  assert_param(IS_DMA_ALL_PERIPH(DMAy_Channelx));

  assert_param(IS_DMA_DIR(DMA_InitStruct->DMA_DIR));

  assert_param(IS_DMA_BUFFER_SIZE(DMA_InitStruct->DMA_BufferSize));

  assert_param(IS_DMA_PERIPHERAL_INC_STATE(DMA_InitStruct->DMA_PeripheralInc));

  assert_param(IS_DMA_MEMORY_INC_STATE(DMA_InitStruct->DMA_MemoryInc));   

  assert_param(IS_DMA_PERIPHERAL_DATA_SIZE(DMA_InitStruct->DMA_PeripheralDataSize));

  assert_param(IS_DMA_MEMORY_DATA_SIZE(DMA_InitStruct->DMA_MemoryDataSize));

  assert_param(IS_DMA_MODE(DMA_InitStruct->DMA_Mode));

  assert_param(IS_DMA_PRIORITY(DMA_InitStruct->DMA_Priority));

  assert_param(IS_DMA_M2M_STATE(DMA_InitStruct->DMA_M2M));


/*--------------------------- DMAy Channelx CCR Configuration -----------------*/

  /* Get the DMAy_Channelx CCR value */

  tmpreg = DMAy_Channelx->CCR;

  /* Clear MEM2MEM, PL, MSIZE, PSIZE, MINC, PINC, CIRC and DIR bits */

  tmpreg &= CCR_CLEAR_Mask;

  /* Configure DMAy Channelx: data transfer, data size, priority level and mode */

  /* Set DIR bit according to DMA_DIR value */

  /* Set CIRC bit according to DMA_Mode value */

  /* Set PINC bit according to DMA_PeripheralInc value */

  /* Set MINC bit according to DMA_MemoryInc value */

  /* Set PSIZE bits according to DMA_PeripheralDataSize value */

  /* Set MSIZE bits according to DMA_MemoryDataSize value */

  /* Set PL bits according to DMA_Priority value */

  /* Set the MEM2MEM bit according to DMA_M2M value */

  tmpreg |= DMA_InitStruct->DMA_DIR | DMA_InitStruct->DMA_Mode |

            DMA_InitStruct->DMA_PeripheralInc | DMA_InitStruct->DMA_MemoryInc |

            DMA_InitStruct->DMA_PeripheralDataSize | DMA_InitStruct->DMA_MemoryDataSize |

            DMA_InitStruct->DMA_Priority | DMA_InitStruct->DMA_M2M;

  /* Write to DMAy Channelx CCR */

  DMAy_Channelx->CCR = tmpreg;


/*--------------------------- DMAy Channelx CNDTR Configuration ---------------*/

  /* Write to DMAy Channelx CNDTR */

  DMAy_Channelx->CNDTR = DMA_InitStruct->DMA_BufferSize;


/*--------------------------- DMAy Channelx CPAR Configuration ----------------*/

  /* Write to DMAy Channelx CPAR */

  DMAy_Channelx->CPAR = DMA_InitStruct->DMA_PeripheralBaseAddr;


/*--------------------------- DMAy Channelx CMAR Configuration ----------------*/

  /* Write to DMAy Channelx CMAR */

  DMAy_Channelx->CMAR = DMA_InitStruct->DMA_MemoryBaseAddr;

}

나머진 다음에

3.3  ADC 설정

ADC_InitTypeDef ADC_InitStructure;


/* ADC1 configuration ------------------------------------------------------*/

  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

  ADC_InitStructure.ADC_ScanConvMode = ENABLE;

  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

  ADC_InitStructure.ADC_NbrOfChannel = 1;

  ADC_Init(ADC1, &ADC_InitStructure);


  /* ADC1 regular channel14 configuration */ 

  ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);


  /* Enable ADC1 DMA */

  ADC_DMACmd(ADC1, ENABLE);

  

  /* Enable ADC1 */

  ADC_Cmd(ADC1, ENABLE);


  /* Enable ADC1 reset calibaration register */   

  ADC_ResetCalibration(ADC1);

  /* Check the end of ADC1 reset calibration register */

  while(ADC_GetResetCalibrationStatus(ADC1));


  /* Start ADC1 calibaration */

  ADC_StartCalibration(ADC1);

  /* Check the end of ADC1 calibration */

  while(ADC_GetCalibrationStatus(ADC1));

     

  /* Start ADC1 Software Conversion */ 

  ADC_SoftwareStartConvCmd(ADC1, ENABLE);

위와 같이 설정을 합니다.

여기도 상당히 내용이 많은데 일단 패스 .. 그럼 일단 입력된 아나로그 데이타가 변수 ADCConvertedValue 저장됩니다. 그럼 읽기만 하면 되는거죠.


/* ADC Init structure definition */

typedef struct

{

  u32 ADC_Mode;

  FunctionalState ADC_ScanConvMode; 

  FunctionalState ADC_ContinuousConvMode;

  u32 ADC_ExternalTrigConv;

  u32 ADC_DataAlign;

  u8 ADC_NbrOfChannel;

}ADC_InitTypeDef;


4. 사용법

printf("==== %d ====\r\n",ADCConvertedValue*3300/4096);

메인의 무한 루프에서 다음과 같이 뺑뺑이 돌리면서 값을 바꾸어 보았습니다. 5mV정도 흔들리고 값을 잘 나오네요... 뒤에 3300/4096은 3.3V일때 3300으로 표시하기 위하여 변환용으로 사용합니다.



어째든 DMA기능이 있으니 쓰기는 상당히 편리하네요.. 그냥 변수만 읽으면 되니 근데.값이 언제 바뀌는지 알수 없네요. 일반적으로 ADC컨버젼 끝나고 값저장하고 흔들리는것을 방지하기 위해 이전의 값들과 평균내는 방법을 사용하기도 하는데....위와 같이 사용하면 요 방법을 쓰기가 힘드네요..

좀더 고민해 보아야 겠습니다.

또한 여러 채널일때 설정도 좀 공부해야될것 같습니다.

그럼 다음 다체널 ADC를 시도 해보지요.


'CPU > STM32F103' 카테고리의 다른 글

STM32 SysTick 사용하기  (0) 2013.02.08
STM32 ADC2 Interrupt Mode 사용  (1) 2013.02.08
STM32 GPIO INPUT 사용하기  (0) 2013.02.07
STM32 UART DEBUG포트 사용하기  (0) 2013.02.07
STM32 GPIO 제어  (0) 2013.02.07