Bare-Metal STM32: ADC’lerle Analog Bir Dokunuş Ekleme


Analogdan Dijitale Dönüştürücü (ADC) özünde basit bir cihazdır: belirli bir aralıkta bir analog voltajı ölçerek ve ölçülen seviyeyi dijital bir değere dönüştürerek bu ölçüm değerini kodumuzda kullanabiliriz. Mikrodenetleyicilerde gömülü ADC’lerin kullanımı sayesinde, bir potansiyometre üzerindeki ayarın ölçülmesinden, MCU’nun dahili sıcaklık ve voltaj sensörleri de dahil olmak üzere sensörlerde bir analog çıkış hattının okunmasına kadar birçok temel kullanım durumunu ele alabiliriz.

STM32 MCU’larda bulunan ADC’ler, 12 ila 16 bit arasında bir çözünürlüğe sahiptir ve birincisi en yaygın türdür. Bir ADC, bu çözünürlüğü azaltmak, belirli bir örnekleme hızı ayarlamak ve tam ADC çevre birimine bağlı olarak çok modlu bir yapılandırma ayarlamak için yapılandırılabilir. STM32 MCU’lar en az tek bir ADC çevre birimine sahipken, bazılarında birden fazla bulunur. Bu yazıda, STM32 MCU’lardaki ADC’lerin temel özelliklerinin, özellikle F0’da bulunan ADC’lerin ve çoğu F3 ailesi MCU’da bulunan ADC5_V1_1 tipinin nasıl yapılandırılacağına ve kullanılacağına bir göz atacağız.

İşleri Ayarlama

STM32F0 ADC blok şeması (RM0091, 13.4).
STM32F0 ADC blok şeması (RM0091, 13.4).

Bir ADC cihazını yapılandırırken dikkat edilmesi gereken üç temel öğe vardır:

  1. Saatini Sıfırlama ve Saat Kontrolü (RCC) etkinleştirme kaydında etkinleştirme.
  2. ADC cihazının kalibre edilmesi.
  3. Bir ADC ortak saat kaynağı seçme.

İlk öğe, STM32’deki diğer herhangi bir çevresel aygıtta olduğu gibi standart prosedür olduğu için açık olmalıdır. Buna rağmen, bazı STM32 MCU’larda burada biraz sorun var. Özellikle F334 gibi MCU’larda, iki ADC cihazı (ADC1 ve ADC2) aynı saat alanını kullanır (ADC12 içinde biraz RCC_AHBENR Kayıt ol).

Çevresel saat etki alanı etkinleştirildiğinde, kendi kendini kalibre etme rutinini çalıştırmaya geçebiliriz. Bu isteğe bağlı olmakla birlikte, fabrika tarafından sağlanan kalibrasyon faktörlerinin uygulanması, örneklenen değerlerin doğruluğunu büyük ölçüde artırır.

kalibrasyon

Kalibrasyon rutininin çalıştırılması, ADC çevre birimini ayarlamak için depolanmış bir kalibrasyon faktörü uygular. Bu kalibrasyon faktörü imalat sırasında ölçülür ve programlanır. Kalibrasyon rutininin çalıştırılması, ADC çevre biriminin saatinin etkinleştirilmesini (RCC’de) ancak kapalı olmasını gerektirir (ADEN biraz). F0’da ve uyumlu MCU’larda kalibrasyon, daha sonra aşağıdakine yazılarak başlatılır: ADCAL içinde biraz ADC_CR kontrol ederek kayıt olun ve kalibrasyonun tamamlanmasını bekleyin. ADCAL bit değeri:


ADC1->CR |= ADC_CR_ADCAL;
while ((ADC1->CR & ADC_CR_ADCAL) != 0) { }

F3 cihazlarında prosedür çok benzerdir, ancak aynı zamanda önce cihazda ADC’nin voltaj regülatörünü etkinleştirmemizi de gerektirir. Örneğin:


ADC1->CR &= ~ADC_CR_ADVREGEN;
ADC1->CR |= ADC_CR_ADVREGEN_0; 

ile yakalandı ADVREGEN register değeri, değiştirirken her zaman 0x00’dan geçmesi gerektiğidir, bu yüzden ilk önce onu kaldırmamız gerekiyor. Voltaj regülatörünü devreye aldıktan sonra regülatör çıkış süresinin oturması için 10 mikrosaniye beklememiz gerekiyor. Bununla birlikte, daha önce F0 için açıklandığı gibi ADCAL prosedürünü gerçekleştirebiliriz.

Saat Kaynağı

STM32F334 ADC saat şeması.  (RM0364, 13.3.3)
STM32F334 ADC saat şeması. (RM0364, 13.3.3)

ADC saat kaynağı esasen senkron (AHB- veya APB-türetilmiş) veya asenkron (saat-domeni yeniden senkronizasyonlarından bağımsız) arasındaki seçimdir. Genellikle asenkron kaynağı seçmek güvenli bir seçenektir, örneğin STM32F0 için değeri ayarlayarak CKMODE içinde ADC_CFGR2 ve yüksek hızlı ADC saatini etkinleştirme (burada 14 MHz HSI saati):


ADC1->CFGR2 &= ~ADC_CFGR2_CKMODE;
RCC->CR2 |= RCC_CR2_HSI14ON;
while ((RCC->CR2 & RCC_CR2_HSI14RDY) == 0) { }

Burada önemli olan, devam etmeden önce saat kaynağının stabilize olmasını beklemektir. F0 üzerindeki HSI14 saati ile bu, HSI14RDY ayarlanacak bit RCC_CR2.

Senkronize, veriyolundan türetilmiş bir saat modu kullanmak da bir seçenektir, örneğin F334 MCU’larda bölücüsüz AHB saati:


ADC1_2_COMMON_BASE->CCR |= ADC_CCR_CKMODE_1;

Seçilen saat modu ve önceki görevler de listeden çıkarıldığında, bir dizi sırasında örneklemek istediğimiz kanalların konfigürasyonuna geçebiliriz.

Kanal Yapılandırması

STM32F334'ün ADC1 ve ADC2 kanal bağlantısı.  (RM0364, 13.3.4)
STM32F334’ün ADC1 ve ADC2 kanal bağlantısı. (RM0364, 13.3.4)

Her ADC, bir dizi sabit harici (GPIO bağlantılı) kanal ve ek sayıda dahili kanal adı verilen bir dizi analog giriş kanalına bağlanır. Bu son kanallar dahili sıcaklık sensörüne bağlanır (Vsense), dahili voltaj referansı (Vrafint), batarya voltajı (Vbat) ve F334 MCU’larda Vopamp2 gömülü bir işlemsel yükseltici için ikinci ADC çevre biriminin 17. kanalında.

Bir kanalın yapılandırılma şekli, F0 ve F3 ailelerinin ADC’lerinin önemli ölçüde ayrılmaya başladığı yerdir. F0’a bakarsak, ADC1’in kanallarını yapılandırmak, ADC_CHSELR’de kanalı aktif olarak ayarlayarak ve ardından örnekleme süresini ayarlayarak gerçekleştirilir. Örneğin, 1 (GPIO) ve 16 (Vsense) kanallarını yapılandırırsak, şunu elde ederiz:


ADC_BASE->CCR |= ADC_CCR_TSEN;
ADC1->CHSELR |= (1 << 1); 
ADC1->CHSELR |= (1 << 16); 
ADC1->SMPR = 7;

Bu, kanal seçim kaydında kanal 1 ve 16’yı aktif olarak ayarlar ve örnekleme süresini maksimum uzunluğa ayarlar (0b111). Kanal 16 (Vsense) için bu, Vsense (239.5 ADC döngüleri) örneklemesi için önerilen örnekleme uzunluğudur. F0 ADC’lerde örnekleme süresi tüm kanallar için aynı olduğundan, burada gerekli olan en uzun örnekleme süresini seçmemiz gerekiyor.

Ayrıca etkinleştirmemiz gerektiğini unutmayın. TSEN biraz ortak ADC_CCR Bu kanalı etkinleştirmek için kaydolun. Aynısı, diğer dahili kanallar için de geçerlidir. VREFINT ve VBAT bitler aynı register içindedir. Son olarak, analog giriş için kullanmak istediğimiz GPIO pininde analog modu etkinleştirmemiz gerektiğini unutmayın.

Ardından, aynı kanalları yapılandırmanın bir F334 cihazında nasıl göründüğüne bakalım:


ADC1_2_COMMON_BASE->CCR |= ADC_CCR_TSEN;
ADC1->SQR1 = 1;
ADC1->SQR1 |= (1 << 6);
ADC1->SQR2 |= (16 << (6 * 2));
ADC1->SMPR2 |= (7 << (3 * 6));

Burada da etkinleştirmemiz gerekiyor TSEN bit, ancak bir örnekleme dizisinin kurulma şekli daha karmaşıktır. Temel olarak SQR1 vasıtasıyla SQR4 kayıtlar, dizide örneklenecek ardışık kanal numaralarını içerir ve ilk giriş ADC_SQR1 tüm dizideki kanal sayısını içerir (0 ile bir kanal anlamına gelir).

Aksi takdirde varsayılan ayarlar kullanılarak bu şekilde yapılandırılan kanallarla, diziyi başlatmaya hazırız.

Bir Dizi Çalıştırma

Bir diziye başlamadan önce, emin olmak istiyoruz ADRDY içinde ADC_ISR register 0’dır. Bu bize yeni bir diziyi güvenle başlatabileceğimizi bildirir. Ardından, ayarlayarak cihazı etkinleştiriyoruz ADEN içinde ADC_CR hedef ADC çevre birimine kaydolun. Cihaz artık sıralama başlangıcı için hazırdır.

adresine yazdığımız zaman ADSTART biraz ADC_CR register, ADC’nin örneklemeye başlamasına neden olur, bu varsayılan olarak tek bir dizidir, yani durmadan önce her aktif kanalı bir kez örnekleyecektir. Bir kanal örneklendiğinde, bunu EOC (Dönüşüm Sonu) bitini bekleyerek tespit edebiliriz. ADC_CR ayarlamak için kayıt olun. Bu bit ‘1’ olduğunda, örneklenen değeri ADC_DR EOC bitini sıfırlayacak olan kayıt. Tüm dizi tamamlandığında, EOSEQ içinde ADC_ISR Ayarlanacak.

Örneklenen Değerlerin İşlenmesi

Örneklenen değer, 0 ile MCU’nun analog giriş voltajı ne olursa olsun arasında bir sayı olacaktır. Bu genellikle 3,3 VDC’dir, yani milivolt ölçtüğümüzde kabaca 0 – 3.300 aralığında bir değer elde ederiz. Bu, bu değeri doğrusal bir şekilde etkileyeceğinden, örneğin harici bir potansiyometrenin durumunu algılamayı kolaylaştırır. Dahili sıcaklık sensörü gibi bir şey için anlamlı bir sayı elde etmek için birkaç hesaplama yapmamız gerekiyor.

Belirli MCU’nun veri sayfasına bakarken, sıcaklık sensörü için iki kalibrasyon değeri için bellek adresi sağlanır. F042 MCU için bunlar 30°C için 0x1FFFF7B8 ve 110°C için 0x1FFFF7C2’dir. Vsense için elde ettiğimiz 12 bitlik değeri ham sıcaklık olarak alıyoruz (bir int16_t değişken) ve referans kılavuzunda verilen formüle takın:


int32_t temperature = 0;
temperature = (((int16_t) raw) - *TEMP30_CAL_ADDR);
temperature = temperature * (int32_t)(110 - 30);
temperature = temperature / (int32_t)(*TEMP110_CAL_ADDR - *TEMP30_CAL_ADDR);
temperature = temperature + 30;

Başvurulan STM32F042 MCU için bu, aygıt yazılımı görüntüsünü cihaza yazdıktan kısa bir süre sonra yaklaşık 28°C oda sıcaklığıyla yaklaşık 36°C’lik bir sıcaklık verir. STM32 cihazlarının dahili sıcaklık sensörünün çok hassas olduğu garanti edilmese de, sağlanan kalibrasyon değerleri kullanılarak cihazın sağlığını ölçmek için yeterince iyi olan birkaç derece içinde doğru olması gerekir.

Sadece başlangıç

Yukarıdakiler, elbette STM32 MCU’larda bulundukları için ADC çevre birimlerine yalnızca kısa bir giriş sağlar. Yalnızca tek bir ADC kullandık ve örnekleme çözünürlüğünü, veri hizalamasını vb. varsayılan değerlerinde bıraktık. Kesintilerin kullanımı, sürekli mod ve çoklu ADC F3 MCU’ların çok modlu çalışması ile birlikte gelecek bir makalede bu seçeneklere daha ayrıntılı bakacağız.

Ne olursa olsun, şimdiye kadar sağlanan bilgilerle ADC ile ilgili birçok temel görevi gerçekleştirmek ve operasyonlarının arkasındaki bazı temelleri anlamak mümkün olmalıdır.



Kaynak : https://hackaday.com/2022/06/29/bare-metal-stm32-adding-an-analog-touch-with-adcs/

Yorum yapın