2015年6月3日水曜日

STM32のAD変換結果をDMA転送

連続変換モードがうまく動かせなかったので、DMAを使ってAD変換結果を変数に転送するようにした。

いつもながら、花岡ちゃんに花束を、を参考にさせてもらった。
ちょっとパクリすぎたかなとも思う(^ ^;

ソースコードは以下。






#include "stm32f4xx.h"
#include "mcp23s17.h"
#include "uart1.h"
#include "stm32f4dis.h"


volatile uint16_t adc_dma_data[4];
void ADC3_DMA_Config(void);

/* --------------------------------------
  time : 約1uSec,1000000=1sec
   -------------------------------------- */
void delay(uint32_t time){
  uint32_t t;
  volatile uint8_t i;
  
  for(i=0;i<24;i++){
    t = time;
    while(t--);
  }
} 

// -------------------------------------------------------------------
// systick 割込み(1msec毎に設定してある)
// stm32f4xx_it.c で呼び出している
// -------------------------------------------------------------------
volatile uint16_t time_sec=0;
volatile uint16_t time_msec=0;
void systick_1msec(void){
  static uint16_t cnt=0;
  
  cnt++;
  time_msec++;
  if(cnt>1000){
    time_msec=0;
    cnt=0;
 time_sec++;
  }
}

void Delay_ms(uint16_t msec){
  uint16_t cnt=0;
  
  cnt = time_msec;
  while(msec){
    if(cnt!=time_msec){
   cnt = time_msec;
   msec--;
 }
  }
}

// -------------------------------------------------------
// 
// -------------------------------------------------------
int main(void)
{
  SystemInit();
  stm32f4_init();   set_led(0x01);
  delay(10000);
  ADC3_DMA_Config();

  uart1_init(9600);

  // systick 設定(1msec)
  SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
  if(SysTick_Config(SystemCoreClock/1000)){
    while(1);                // error
  }
  
    ADC_RegularChannelConfig( ADC3, ADC_Channel_10, 1, ADC_SampleTime_56Cycles);
        ADC_SoftwareStartConv( ADC3 );              // AD変換開始

  while(1){
    // SW処理
    if(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_13)){
      //ボタンが押されて1になっていたら以下を実行
      GPIO_ResetBits(GPIOB,GPIO_Pin_7);     // 点灯
   while(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_13));  // ボタンを放したら以下を実行
    }else{
      GPIO_SetBits(GPIOB,GPIO_Pin_7);       // 消灯
    }
 // 1秒処理
  volatile static uint16_t time_tmp=0;

 if(time_tmp!=time_sec){
   set_led(0x04);
   time_tmp = time_sec;

        usart1_printf(\"%4d : AD ch1=%4d , ch2=0x%8X , ch3=%4d , ch4=%4d \\r\",
                 time_sec,adc_dma_data[0],adc_dma_data[1],adc_dma_data[2],adc_dma_data[3]);

   set_led(0x00);
 }
  }
  return 0;
}


void ADC3_DMA_Config(void)
{
  ADC_InitTypeDef       ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
  DMA_InitTypeDef       DMA_InitStructure;
  GPIO_InitTypeDef      GPIO_InitStructure;

  //必要なペリフェラルにクロック供給開始
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOC, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);

  //DMAの設定
  //送り元のアドレスを固定し、送り先をadc_dma_dataにしてアドレスをインクリメント、送るデータ数を4つに
  DMA_InitStructure.DMA_Channel = DMA_Channel_2;
  DMA_InitStructure.DMA_PeripheralBaseAddr   = (uint32_t)&ADC3->DR;
  DMA_InitStructure.DMA_Memory0BaseAddr      = (uint32_t)&adc_dma_data;
  DMA_InitStructure.DMA_DIR                  = DMA_DIR_PeripheralToMemory;
  DMA_InitStructure.DMA_BufferSize           = 4; //4チャンネルの変換結果を送るからデータ数は2(チャネルを増やしたらここを変える)
  DMA_InitStructure.DMA_PeripheralInc        = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc            = DMA_MemoryInc_Enable; //送り先アドレスをインクリメント
  DMA_InitStructure.DMA_PeripheralDataSize   = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize       = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode                 = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority             = DMA_Priority_High;
  DMA_InitStructure.DMA_FIFOMode             = DMA_FIFOMode_Disable;
  DMA_InitStructure.DMA_FIFOThreshold        = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst          = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst      = DMA_PeripheralBurst_Single;
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
  DMA_Cmd(DMA2_Stream0, ENABLE);

  //GPIOCの指定の入力をアナログに設定
  GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; //PC[3:0]を設定
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOC, &GPIO_InitStructure);

  //ADC3の基本設定
  ADC_CommonInitStructure.ADC_Mode             = ADC_Mode_Independent;
  ADC_CommonInitStructure.ADC_Prescaler        = ADC_Prescaler_Div2;
  ADC_CommonInitStructure.ADC_DMAAccessMode    = ADC_DMAAccessMode_Disabled;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
  ADC_CommonInit(&ADC_CommonInitStructure);

  //ADC3の変換モード設定。入力2本をスキャン変換モードで逐次変換
  ADC_InitStructure.ADC_Resolution           = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode         = ENABLE; //スキャン変換モードに
  ADC_InitStructure.ADC_ContinuousConvMode   = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_DataAlign            = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion      = 4; //入力を4本(チャネルを増やしたらここを変える)
  ADC_Init(ADC3, &ADC_InitStructure);

  //ADC3のアナログ入力を定義する
  ADC_RegularChannelConfig(ADC3, ADC_Channel_10, 1, ADC_SampleTime_3Cycles);
  ADC_RegularChannelConfig(ADC3, ADC_Channel_11, 2, ADC_SampleTime_3Cycles);
  ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 3, ADC_SampleTime_3Cycles);
  ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 4, ADC_SampleTime_3Cycles);

  //変換結果がDMA転送されるごとに、ADCは次の変換を開始するように設定
  ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);

  //ADC3のDMAを使えるようにする
  ADC_DMACmd(ADC3, ENABLE);

  //ADC3を使えるようにする
  ADC_Cmd(ADC3, ENABLE);
}




0 件のコメント:

コメントを投稿