つかうもの:STM32F1
今回はTIM4でタイミングを作り、ADC1を駆動、PB0のchを変換してDMA転送を行う。
ADC1をTIM4で駆動する場合、TIM4 OC4のエッジで変換が開始されるが、注意点として、OCのOutputStateはEnableにしなければいけない。
例えばTIMをトリガにDMA転送を行う場合、内部的にOCのエッジがあればいいので、OutputStateはDisableでも問題ない。しかし、ADCのトリガとして使うにはOutputStateはEnableにしなければ動かなかった。
たとえOutputStateをEnableにしても、GPIOをAFで初期化しなければOCが出力されることはない。GPIOをソフトウェアで入出力に使う分にも問題はないが、ペリフェラルで使うことはできなくなる。TIM4 OC4はPB9に接続されており、このピンはI2C1 SDAのリマップと、CAN TXのリマップに接続されている。特にCANは標準がUSBと同居しており、STBeeMiniで使う際はPB8/PB9にリマップする必要があるから、TIM4 OC4とは競合してしまう。もしかしたらTIM4 OC4をリマップしてPD15に移動すれば問題ないかもしれないが、そこまでは確認していない。
TIMでADCを駆動してDMA転送すれば、バッファが埋まるまではCPUからはノータッチで処理できるので、他の処理に専念することができる。YES DMA! NO タッチ!
// ADCの初期化 { RCC_ADCCLKConfig(RCC_PCLK2_Div6); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // GPIOの初期化 { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); } ADC_DeInit(ADC1); // ADC1の初期化 { ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T4_CC4; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); } ADC_ExternalTrigConvCmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while (ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1)); ADC_RegularChannelConfig(ADC1, ADC_Channel_8 /*PB0*/, 1, ADC_SampleTime_7Cycles5); } // TIMの初期化 { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); // タイマの初期化 72MHzで48kHz { TIM_TimeBaseInitTypeDef TIM_InitStructure; TIM_InitStructure.TIM_Period = 100 - 1; TIM_InitStructure.TIM_Prescaler = 15 - 1; TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_InitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM4, &TIM_InitStructure); } // OC4の初期化 OutputState=Enableに注意 { TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 1; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC4Init(TIM4, &TIM_OCInitStructure); } TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM4, ENABLE); } // DMAの初期化 { RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); DMA_DeInit(DMA1_Channel1); // DMAの初期化 { DMA_InitTypeDef DMA_InitStructure; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&ADC1->DR); DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(ADCbuff); DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = sizeof(ADCbuff) / sizeof(ADCbuff[0]); DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1, &DMA_InitStructure); } // NVICの初期化 { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 12; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); DMA_ITConfig(DMA1_Channel1, DMA_IT_HT, ENABLE); DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); } DMA_Cmd(DMA1_Channel1, ENABLE); }
void DMA1_Channel1_IRQHandler(void) { if (DMA_GetITStatus(DMA1_IT_HT1)) { DMA_ClearITPendingBit(DMA1_IT_HT1); } if (DMA_GetITStatus(DMA1_IT_TC1)) { DMA_ClearITPendingBit(DMA1_IT_TC1); } }
追記:2017/02/14
重要な"ADC_DMACmd(ADC1, ENABLE);"を書くのを忘れていた。DMA_Cmdの前辺りに書いておくように。
0 件のコメント:
コメントを投稿