#include "STM32F4xx.h"
#include "stdio.h"
unsigned char WAdr,RAdr;
char RxBuf[128];
char TxBuf[128];
unsigned char timer_update=0;
uint16_t adc_val[4];
uint8_t ch_index =0;
/*********************************************************************************
CPU frekansi 168Mhz
AHB frekansi 84 Mhz
APB frekansi 42 Mhz
*********************************************************************************/
void SystemInit()
{
unsigned int i;
for (i=0;i<0x00100000;i++); // OSC oturtma ve kurtarma rutini
RCC->CFGR |= 0x00009400; // AHB ve APB hizlarini max degerlere set edelim
RCC->CR |= 0x00010000; // HSE Xtal osc calismaya baslasin
while (!(RCC->CR & 0x00020000));// Xtal osc stabil hale gelsin
RCC->PLLCFGR = 0x07402A04; // PLL katsayilarini M=4, N=168, P=2 ve Q=7 yapalim 168 Mhz
RCC->CR |= 0x01000000; // PLL calismaya baslasin (Rehber Sayfa 95)
while(!(RCC->CR & 0x02000000)); // Pll hazir oluncaya kadar bekle
FLASH->ACR = 0x00000605; // Flash ROM icin 5 Wait state secelim ve ART yi aktif edelim (Rehber Sayfa 55)
RCC->CFGR |= 0x00000002; // Sistem Clk u PLL uzerinden besleyelim
while ((RCC->CFGR & 0x0000000F) != 0x0000000A); // Besleninceye kadar bekle
RCC->AHB1ENR |= 0x0000001F; // GPIO A,B,C,D,E clock'u aktif edelim
GPIOD->MODER = 0x55550000; // GPIOD nin 15, 14, 13, 12, 11, 10, 9, 8 pinleri cikis tanimlandi (LEDler icin)
GPIOD->OSPEEDR= 0xFFFFFFFF; // GPIOD nin tum cikislari en yuksek hizda kullanacagiz
RCC->APB1ENR|=0x00000020; // Timer7 CLK'u aktif edelim (84 Mhz)
TIM7->CR1=0x0080; // Otomatik Reload
TIM7->PSC =839; // Prescaler degerimiz 839, Count frekansimiz = fCK_PSC / (Yuklenen Deger + 1) 84E6 / (840) = 100 KHz
TIM7->ARR =5; // Counter, Decimal 1 olunca basa donsun. Her 20 mikrosaniye de bir timer int olusacak.
TIM7->DIER=0x0001; // Update Int enable
NVIC->ISER[1] = 0X00800000; // NVIC de Timer 7 interrupta izin verelim
TIM7->CR1|=0x0001; // Counter Enable
GPIOB->MODER |= 0x0000000F; // B0 ve B1 analog
GPIOC->MODER |= 0x00000F00; // C4 ve C5 analog
RCC->APB2ENR|=0x00000100; // ADC saat kaynağını aktif ettik.
ADC1->CR1 |=0x00000120; // ADC scan modunda çalışacak. Interrupt aktif.
NVIC_EnableIRQ(ADC_IRQn); // NVIC ADC kesmesini aktif ettik.
ADC1->SQR1 |= (3 << 20); // Kaç kanalı tarayacağımızı bildiriyoruz. 20..23 bitler; 4 kanal
ADC1->SQR3 |= 8; // Çevrime ilk girecek kanal 8. (PB0)
ADC1->SQR3 |= (9 << 5); // Çevrime 2. sırada girecek kanal 9. (PB1)
ADC1->SQR3 |= (14 << 10); // Çevrime 3. sırada girecek kanal 14. (PC4)
ADC1->SQR3 |= (15 << 15); // Çevrime 4. sırada girecek kanal 15. (PC5)
ADC1->SMPR1 |=0xFFFFFFFF; // En düşük çevirim hızı.
ADC1->SMPR2 |=0xFFFFFFFF; // En düşük çevirim hızı.
ADC1->CR2 |=0x00000403; // AD converter'i açtık. Sürekli çevirim yapacağız.
// Her kanal çevrimi bittiğinde EOC set olacak.
}
/********************************************************************************************************
ADC KESME RUTİNİ
**********************************************************************************************************/
void ADC_IRQHandler()
{
if(ADC1->SR & 0x0002){
ADC1->SR &= ~0x0002;
adc_val[ch_index] = ADC1->DR;
if(++ch_index > 3)ch_index=0;
}
}
/*********************************************************************************
USART3 modulunu kullanarak asenkron haberlesme (Hata kontrolu yapilmiyor)
*********************************************************************************/
void USART3_IRQHandler()
{
volatile int Sts;
Sts=USART3->SR;
RxBuf[WAdr]=USART3->DR;
WAdr=(WAdr+1)&0x7F;
}
void UsartInit()
{
WAdr=0;RAdr=0;
// USART3 MODULUNU AKTIF HALE GETIRELIM
RCC->APB1ENR|=0x00040000; // USART3 Clk Enable (Rehber Sayfa 113)
RCC->APB1RSTR|=0x00040000; // USART3 Resetlendi
GPIOB->AFR[1]=0x07777700; // PB10..PB14 pinleri USART3 ile alakalandirildi (Hard Sayfa 49)
GPIOB->MODER|=0x2AA00000; // GPIOB 10..14 icin alternatif fonksiyon tanimi (Rehber Sayfa 148)
// USART3 MODULUNU AYARLAYALIM // 1 Start, 8 Data, 1 Stop, No parity (Default degerler)
RCC->APB1RSTR&=~0x00040000; // USART3 Reseti kaldiralim
// USART3->SR&=~0X03FF; // Status registeri silelim
USART3->BRR=0X1112; // 9600 Baud
USART3->CR1|=0x0000202C; // USART3 enable
NVIC->ISER[1]|=0x80; // NVIC da USART3 interrupta izin verelim
}
void SendChar(char Tx)
{
while(!(USART3->SR&0x80)); // TX Buffer dolu ise bekle (Rehber Sayfa 646)
USART3->DR=Tx;
}
void SendTxt(char *Adr)
{
while(*Adr)
{
SendChar(*Adr);
Adr++;
}
}
char DataReady()
{
return(WAdr-RAdr);
}
char ReadChar()
{
char Dat;
Dat=RxBuf[RAdr];
RAdr=(RAdr+1)&0x7F;
return(Dat);
}
void TIM7_IRQHandler()
{
TIM7->SR=0;
timer_update=1;
}
// Rx ve TX pinlerini (GPIOB10 ve GPIOB11) birbirine baglarsaniz gonderdiginiz datalar geri gelecektir
int main()
{
unsigned int ledtime;
UsartInit();
SendTxt("PicProje");
ADC1->CR2 |=0x40000000; // ADC çevrimini başlattık.
while(1){
if(timer_update){
timer_update=0;
if(++ledtime > 5000){
ledtime =0;
GPIOD->ODR ^= 0x0000008000;
sprintf(TxBuf,"ch0:%d ch1:%d ch2:%d ch3:%d\r",adc_val[0],adc_val[1],adc_val[2],adc_val[3]);
SendTxt(TxBuf);
}
}
};
}
Register açıklamaları:
RCC->APB2ENR|=0x00000100; // ADC saat kaynağını aktif ettik.
Artk her donanım için clk kaynağını aktif etmemiz gerektiğini , aktif olmadıkları zaman güç tüketiminin düştüğünü biliyoruz. Bu yüzden bunun detayına girmiyorum.
ADC1->CR1 |=0x00000120;
ADC scan modunda çalışacak.CR1 registerinin 8. biti scan modu açma kapama biti.
Eğer scan modu açıksa , kaç tane kanalın taranmasını istediysek o kadar kanalın çevrimi sırayla yapılır. Tüm kanallar bitince çevirim durur.
CR1 registeri 5. biti kesme izni. ADC'ye kesme izni verdik.
NVIC_EnableIRQ(ADC_IRQn);
NVIC ADC kesmesini aktif ettik.
ADC1->SQR1 |= (3 << 20); // Kaç kanalı tarayacağımızı bildiriyoruz. 20..23 bitler; 4 kanal
ADC1->SQR3 |= 8; // Çevrime ilk girecek kanal 8. (PB0)
ADC1->SQR3 |= (9 << 5); // Çevrime 2. sırada girecek kanal 9. (PB1)
ADC1->SQR3 |= (14 << 10); // Çevrime 3. sırada girecek kanal 14. (PC4)
ADC1->SQR3 |= (15 << 15); // Çevrime 4. sırada girecek kanal 15. (PC5)
SQR registerleri hangi kanalın hangi sırayla çevirime gireceğini seçmemizi sağlar. Register 5'er bitlik alanlara ayrılmıştır. Her bir SQR registeri 6 tane kanalın sıralamasını seçmemize izin verir. SQR3 registeri ilk 6 sıra, SQR2 7- 11 arası SQR1 de 12-15 arası olmak üzere toplam 16 kanalın sırasını seçmemize olanak verir.
SQR1 reg isterini diğer SQR registerlerinden ayıran özellik ise, Bu registerin 20-21-221 ve 23. bitlerinden scan modda kaç kanalın taranacağını seçebiliyor olmamızdır.
ADC1->SMPR1 |=0xFFFFFFFF; // En düşük çevirim hızı.
ADC1->SMPR2 |=0xFFFFFFFF; // En düşük çevirim hızı.
ADC'yi en düşük çevirim hızında çalıştırıyoruz. SMPR registerleri her kanal için ayrı ayrı çevirim hızı belirleme imkanı veriyor. Her kanal için 3 bit ayrılmış.
Eğer yüksek hız kullanılırsa interrupt, hatta DMA kullanmak gerek. Aksi durumda siz daha DR registerini okuyamadan yeni veri geliyor.
ADC1->CR2 |=0x00000403; // AD converter'i açtık. Sürekli çevirim yapacağız.
// Her kanal çevrimi bittiğinde EOC set olacak.
CR2 registerinin ilk biti ADON bitidir. ADC'yi açma ve kapatmaya yarar. Burada dikkat edilmesi gereken şey ADC ON yapıldıktan sonra stabil olması için bir süre geçmesi gerekliliğidir. Stabil olduktan sonra çevirimi başlatmak gerek. Rehberde bununla ilgili açıklama var.
CR2 registerinin 1. biti ise continious mode seçim bitidir. Eğer 0 ise single 1 ise Continious modda çalışır.
CR2 registerinin 10. biti(EOCS) EOC (End of conversion) modunu seçer. Eğer bu bit 0 ise, tüm kanallar tarandıktan sonra EOC bitiset edilir. Bu bit 1 olursa her kanalın örneklemesi bittiğinde EOC biti set edilir.
ADC1->CR2 |=0x40000000; // ADC çevrimini başlattık.
CR2 registerinin 3. biti çevirimi başlatır. Continious mode seçili olduğu için bir kez başlatmak yeterlidir. Eğer single modda olsaydık. çevirim bittikten sonra başlatmak için yeniden set etmemiz gerekecekti.
Teşekkürler.
ADC ayarları için alternatif
#include "STM32F4xx.h"
#include "stdio.h"
#include "STM32F4xx_adc.h"
#include "STM32F4xx_GPIO.h"
unsigned char WAdr,RAdr;
char RxBuf[128];
char TxBuf[128];
unsigned char timer_update=0;
uint16_t adc_val[4];
uint8_t ch_index =0;
/*********************************************************************************
CPU frekansi 168Mhz
AHB frekansi 84 Mhz
APB frekansi 42 Mhz
*********************************************************************************/
void SystemInit()
{
... // diğer başlangıç kodları
PB->MODER.p0 = PORT_ANALOG;
PB->MODER.p1 = PORT_ANALOG;
PC->MODER.p4 = PORT_ANALOG;
PC->MODER.p5 = PORT_ANALOG;
RCC->APB2ENR|=0x00000100; // ADC saat kaynağını aktif ettik.
AD1->CR1.SCAN = ADC_SCAN_ENABLE; // scan modunu açtık
AD1->CR1.EOCIE = ADC_INTERRUPT_ENABLE; // interrupt izni verdik.
NVIC_EnableIRQ(ADC_IRQn); // NVIC ADC kesmesini aktif ettik.
AD1->SQR1.L = 3; //4 kanal tarayacağız
AD1->SQR3.SQ1 = 8; //Çevrime ilk girecek kanal 8. (PB0)
AD1->SQR3.SQ2 = 9; //Çevrime 2. sırada girecek kanal 9. (PB1)
AD1->SQR3.SQ3 = 14; //Çevrime 3. sırada girecek kanal 14. (PC4)
AD1->SQR3.SQ4 = 15; //Çevrime 4. sırada girecek kanal 15. (PC5)
AD1->SMPR2.SMP8 = ADC_SMPTIME_480_CYCLES; // 8. kanal en düşük hız
AD1->SMPR2.SMP9 = ADC_SMPTIME_480_CYCLES; // 9. kanal en düşük hız
AD1->SMPR1.SMP14 = ADC_SMPTIME_480_CYCLES; // 14. kanal en düşük hız
AD1->SMPR1.SMP15 = ADC_SMPTIME_480_CYCLES; // 15. kanal en düşük hız
AD1->CR2.ADON = ADC_ON; // ADC'yi açtık
AD1->CR2.CONT = ADC_CONTINIOUS_CONVERSION; // sürekli çevirim yapacağız.
AD1->CR2.EOCS = ADC_EOC_MODE_CHANNEL; // EOC biti her kanalın çevrimi bittiğinde set edilecek.
}
/********************************************************************************************************
ADC KESME RUTİNİ
**********************************************************************************************************/
void ADC_IRQHandler()
{
if(AD1->SR.EOC){
AD1->SR.EOC=0;
adc_val[ch_index] = AD1->DR;
if(++ch_index > 3)ch_index=0;
}
}
Hocam Burayı Biraz Açarmısınız
ADC ayar derken, sadece ADC okuma amaçlımı burası. (USART tan gönderme felan yapmadığınızdan mı böyle yazdınız ? )
DMA ile cok kanallı okuma ornegi de yapabilir miyiz? Ben degerleri aldıgım halde surekli olarak alamadım .Diger normal okuma yoluyla surekli okudugum halde DMA ile sadece Bir kez deger okumaktayım. Yardımlarınızı bekliyorum .
Alıntı yapılan: alisoy - 08 Ekim 2012, 20:50:54
Ben degerleri aldıgım halde surekli olarak alamadım .Diger normal okuma yoluyla surekli okudugum halde DMA ile sadece Bir kez deger okumaktayım. Yardımlarınızı bekliyorum .
Sürekli okuma için ADC Continuous modda ve DMA Circular modda olmalı .
ADC->CR2 DDS de set edilmeli .
ilk aklıma bunlar geldi.
Alıntı yapılan: muhittin_kaplan - 08 Ekim 2012, 19:59:53
Hocam Burayı Biraz Açarmısınız
ADC ayar derken, sadece ADC okuma amaçlımı burası. (USART tan gönderme felan yapmadığınızdan mı böyle yazdınız ? )
ADC register ayarları için yazdığım headerin kullanımını gösteriyor.
Kendi headeri ile
ADC1->SQR1 |= (3 << 20); // Kaç kanalı tarayacağımızı bildiriyoruz. 20..23 bitler; 4 kanal
Alternatif header ile
AD1->SQR1.L = 3; //4 kanal tarayacağız
Alıntı YapDMA ile cok kanallı okuma ornegi de yapabilir miyiz? Ben degerleri aldıgım halde surekli olarak alamadım .Diger normal okuma yoluyla surekli okudugum halde DMA ile sadece Bir kez deger okumaktayım. Yardımlarınızı bekliyorum .
@GreeN bir yorum getirmiş. DMA ile ilgili bir çalışma yapmadım şu ana kadar. Bir ara fırsat bulduğumda ilgileneceğim.
yaptıgım kod su sekilde . Circuler modu aktif ediyorum .
void ADC_DMA_ayarla()
{
int i;
DMA2_Stream4->CR&=0xFFFFFFFE;
RCC->APB2ENR|=0x00000100; // ADC1 saat kaynagini aktif ettik.
RCC->AHB1ENR |= 0x00400000; // DMA2 clock'u aktif edelim
RCC->AHB1RSTR|= 0x00400000; // DMA2 resetleyelim
for(i=0;i<0x1FF;i++); // Azcik bekleyelim
RCC->AHB1RSTR&=~0x00400000; // DMA2 reseti kaldiralim
// GPIOB->MODER |= 0x0000000C; //ADC1 kanal 9
GPIOC->MODER |= 0x00000003; //ADC1 kanal 10
DMA2_Stream4->CR &= ~0x00000001;
//DMA2_Stream4->CR |= 0x01800000;
DMA2_Stream4->CR |= 0x00002900;
DMA2_Stream4->PAR = (int)&ADC1->DR; // peripheral Base adress secilir.
DMA2_Stream4->M0AR = (uint32_t) & ADCConvertedValue;
DMA2_Stream4->FCR&=~0xFFFFFF40;
DMA2_Stream4->NDTR = 2; // 2 pin okuayacag1z.
DMA2_Stream4->CR =0x01E05501;
//DMA2_Stream4->CR |= 0x00030000; //DMA oncelik yuksek
DMA2_Stream4->CR |= 0x00000001; //DMA aciyoruz.
NVIC_EnableIRQ(DMA2_Stream4_IRQn); // DMA kesme aktif
ADC1->CR1 |=0x00000100; // ADC scan modunda çal1sacak.
ADC1->CR2 |= 0x00000002; //continuous modda
// ADC1->CR2 |= 0x200000000; // external trigeer ac1ldi;
ADC1->SQR1 |= 0x00500000; // 2 tane okuyacag1z
ADC1->SQR3 |= 0x000009A; // hangi sirada olacagi
// ADC1->SQR3 |= 0x0000000A; // Çevrime ilk girecek kanal 10. (PC0)
ADC1->SMPR1 =1;
ADC1->CR1 |= 0x00000020; // end of convertion da kesme uretmesi için
ADC1->CR2 |= 0x00000100; // DMA istegi act1k;
ADC1->CR2 |= (1 << 30); // donusumu baslat
ADC1->CR2 |= 0x00000001; // ADC act1k;
// NVIC->ISER[0] |= 0x00040000; // ADC için kesmeyi actik
NVIC_EnableIRQ (ADC_IRQn);
}
void ADC_IRQHandler()
{
GPIOD->ODR ^= 0x00008000;
if (ADC1->SR & (1<<1))
{
deger = (ADC1->DR) & 0xFFF; // Buradaki deger surekli guncellenmesine ragmen DMA daki ADCConvertedValue degeri sadece 1 kez guncelleniyor.
ADC1->SR &= ~(1<<1);
ADC1->SR=0;
}
}
Multi adc modunda son transferden sonra dma nın enable edilmesi lazım,
/
* Enable DMA request after last transfer (multi-ADC mode)
ADC->CCR |= ((uint32_t)0x00002000)
Teskkurler hemen deniyorum yarın :)
Jak çıkışından ses alabilen var mı bu stm32f4'te ??
Amplifikatör bağlayıp yapıyoruz ama sonuçta bi ses çıkışı için jak koymuşlar neden kullanamıyoruz bunu veya da nasıl kullanıyoruz bilen var mı ?
O çıkış CS43L22 Audio dac / D class amplifier çipine bağlı. Eğer bu çipin nasıl çalıştığını biliyorsanız, kulaklık çıkışını kullanabilirsiniz.
mesaj birleştirme:: 24 Kasım 2012, 14:37:12
STM32F4Discovery için ST'nin yayınladığı örneklerde ses çıkışı ile ilgili örnek var.
Evet gayet temiz bir ses çıkışı var.
O örnekleri nereden bulabiliriz hocam acaba ?
http://www.st.com/stonline/stappl/resourceSelector/app?page=resourceSelector&doctype=FIRMWARE&SubClassID=1521 (http://www.st.com/stonline/stappl/resourceSelector/app?page=resourceSelector&doctype=FIRMWARE&SubClassID=1521)
STM32F4DISCOVERYBoard firmware pack.
Teşekkürler sağolasın kolay gelsin :)
ADC1->SQR1 |= (3 << 20); // Kaç kanalı tarayacağımızı bildiriyoruz. 20..23 bitler; 4 kanal
ADC1->SQR3 |= 8; // Çevrime ilk girecek kanal 8. (PB0)
ADC1->SQR3 |= (9 << 5); // Çevrime 2. sırada girecek kanal 9. (PB1)
ADC1->SQR3 |= (14 << 10); // Çevrime 3. sırada girecek kanal 14. (PC4)
ADC1->SQR3 |= (15 << 15); // Çevrime 4. sırada girecek kanal 15. (PC5)
bu kısmı anlamadım, RM0090 dan bakıyorum ama ADC1->SQR3 kısmının anlatıldığı yerde portun nasıl seçileceğini anlamadım.
Port seçimi yapamıyorsun. Her kanal bir porta bağlı. Alternatif fonksiyon tablosuna baktığında , hangi kanalın hangi portla ilişkili olduğunu görebilirsin.
Örneğin PA2 ADC1,2 ve 3 için 2. kanal girişi (Rehber : 44). Eğer bu portu kullanıyorsan , ADC kanalı olarak 2 seçmek zorundasın.
Stm32 serisinde donanımsal ortalama alıcı mevcut mu?
STM32 lerde donanımsal ortalama alan bir yapılanma yok. Ancak 2 nin katları kadar sayıda aldığınız adc örneğini topladığınızda , toplam değeri gerektiği kadar sağa kaydırarak bölme işlemini işlemciyi yormadan halletme imkanı mevcut. En pratik yol bu, Hall effect ve encoder gibi özelleşmiş bir kısım timer portlarında yazılımsal filteler mevcut, ancak bu portların kabiliyetleri sınırlı...
CS43L22 dac entegresini kullanabilen varmı acaba birde verilen linkten ulaşamadım stnin sitesinde neden bulamıyorum ben hiç birşeyi ingilizcemin yetersizliğinden sanırım