Selasa, 27 September 2016

Analog Digital COnverter ADC dan Serial Communication USART pada STM32F4 Discovery

Kali ini, saya akan membahas sedikit tentang ADC yang ada pada STM32F4 Discovery board. ADC yang digunakan disini adalah 12bit, sehingga lumayan presisi lah untuk sensor sensor tertentu seperti loadcell atau sensor lain. STM32 mempunyai 3 buah ADC inbuilt, yang dimana tiap ADC dimultiplex dengan 16 channel. Jadi totalnya, STM32F4 mempunyai 48 ADC channel. Konfigurasi pin I/O yang bisa digunakan untuk ADC adalah seperti dibawah ini.


Sumber : www.stm32f4-discovery.net/2014/04/library-06-ad-converter-on-stm32f4xx/

Tentunya biasanya kita tidaka akan menggunakan itu semua. Tapi ada bebrapa aplikasi tertentu yang sepertinya akan menggunakan banyak ADC, tapi kayaknya tidak usah dibahas. hehehe. Tapi sepertinya yang perlu digaris bawahi adalah resolusi dari ADC ini yang lumayan tinggi, yaitu 12 bit, atau hitungan desimal nya bisa 4095. Seumpama saja kita mempunyai tegangan referensi STM32F4, yaitu 3.3v, maka kita bisa mendeteksi perubahan tegangan 0.0008 volt. Kayaknya bagus untuk DSP kan. 

 Langsung saja lah, kita akan bahas cara penggunaanya. Disini saya fokus pada ADC nya, untuk USART nya, akan dibahas dilain postingan. Disini, saya akan menggunakan ADC dengan mode DMA. kenapa mode DMA? karena mode DMA (Direct Memory Access) tidak terlalu membebani CPU. Jadi, register dari pembacaan ADC akan langsung dicopy ke memory/variable yang telah kita deklarasikan sendiri. Selain tidak membebani CPU, seharusnya penggunaan ADC juga akan bekerja lebih cepat karena tidak perlu masuk CPU, tapi langsung direct transfer memory. Mode ini cocok untuk pengolahan sinyal dengan frekwensi yang tinggi. 

Berikut script inisialisasi ADC mode DMA.

void ADC3_CH2_DMA_Config(void)
{
  ADC_InitTypeDef       ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
  DMA_InitTypeDef       DMA_InitStructure;
  GPIO_InitTypeDef      GPIO_InitStructure;
  /* Enable ADC3, DMA2 and GPIO clocks ****************************************/
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
  /* DMA2 Stream0 channel2 configuration **************************************/
  DMA_InitStructure.DMA_Channel = DMA_Channel_2;
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS;
  //ADC3Converted value adalah variable yang saya deklarasikan sendiri. 
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC3ConvertedValue;  
  //Ini adalah mode ADC kita, yaitu DMA
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
  DMA_InitStructure.DMA_BufferSize = 1;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
  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);
  /* Configure ADC3 Channel2 pin as analog input ******************************/
  // konfigurasi pin yang kita pakai harap dilihat di table channel ADC, sehingga kita bisa memilih
  // pin yang free, yang bisa kita gunakan untuk ADC.

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  /* ADC Common Init **********************************************************/
  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 Init ****************************************************************/
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion = 1;
  ADC_Init(ADC3, &ADC_InitStructure);
  /* ADC3 regular channel2 configuration *************************************/
  ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 1, ADC_SampleTime_3Cycles);
 /* Enable DMA request after last transfer (Single-ADC mode) */
  ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);
  /* Enable ADC3 DMA */
  ADC_DMACmd(ADC3, ENABLE);
  /* Enable ADC3 */
  ADC_Cmd(ADC3, ENABLE);
}

Dari Script diatas, bisa dilihat bahwa  saya menggunakan variabel "ADC3ConvertedValue" untuk menyimpan limpahan data dari DMA stream yang berisi data pembacaan memory "ADC3_DR_ADDRESS" yang berisi nilai pembacaan ADC.

Jika ada yang bertanya apakah saya membuat semua ini sendiri, jawabanya "tentu tidak semua". Enaknya CoIDE adalah, kita diberi examplae dari component yang ada CoIDE. Dan sepertinya semuanya bekerja dengan baik. Tapi tentu saja ada beberapa yang perlu disesuaikan dengan keperluan, berhubung setiap project harus disesuaikan dengan kebutuhanya masing masing. Berikut adalah hasil akhir dari dari pembacaan ADC di hyperterminal.



Silahkan lihat video di youtube untuk lebih jelasnya.


Karena kodingannya lumayan panjang, saya tidak menuliskan kodenya disini, karena akan menuh menuhin halaman. Untuk file lengkapnya, silakan download disini.

Sekian terima kasih, kalau ada kritik dan sar, silakan ditulis dibawah ya.

1 komentar:

zzztu mengatakan...

file codenya gabisa di download