Tiny AVR 1 Serisi - SPI

 SPI detayına girmeden master mod ile kullanmak için gerekli kütüphaneyi paylaşacağım. 

SPI


SPI biriminde ana çalışma modu olarak bir normal mod bir de tampon mod vardır. Normal mod bildiğiniz SPI çalışması şeklindedir. Tek bir data registeri vardır. Veriyi yazınca shift register ile veri kayrdırılır. Aynı anda slave tarafta da aynı işlem olur. Son olarak 8 bit tamamlanınca data registerinde slave veri okunur. Bu işlem tamamlanmadan gönderim için registere veri yazılamaz. Veri çakışması olur (WRCOL) ve hatalı gönderim olur. Benzer şekilde işlem sonunda gelen veri okunmadan tekrar gönderim yapılması slave verinin kaybolmasına neden olur.

Tampon mod ile kullanımda INTFLAGS registeri DREIF bayrak biti "0" olduğu sürece gönderim için data registerine veri yazılabilir. İlk yazılan DATA registerine yazılır ve gönderilir sonraki tampona yazılır. Gönderim tamamlanınca alınan veri RX tampona yazılır. İki gönderim sonrası bir okuma yapılmalıdır.

CTRLB registeri SSD biti SS pininin nasıl kullanılacağını belirler. SSD "0" ise SPI birimi SS pinini çoklu master mod slave geçiş için kullanabilir. SS pini giriş yapıldığında master olarak kullanmak için SS pini "1" (high) yapılmalıdır. SS "0" olduğunda slave moda geçiş yapılır. SS pini çıkış yapılırsa normal bir pin olarak kullanılabilir. SSD "1" ise SPI birimi SS pinini kullanamaz normal bir pin olarak kullanılır.

SPI Mod

SCK pini boşta "0" veya "1" olması (CPOL) ve SCK pini yükselen veya düşen kenarda veri örneklemesi (CPHA) durumuna göre dört farklı mod CTRLB registeri MODE biti ile ayarlanır.
Prescaler ve düşük ya da yüksek öncelikli bit sırası gibi ayarlar CTRLA registeriyle yapılır. 

Tiny AVR 1 Serisi - I2C (TWI)

 Bu yeni Attiny serisinde SPI ve I2C dışında kullanacağım bir birim kalmadı. AC ve DAC zaten oldukça basit ve hiç bir zaman kullanmam gerekmedi bu nedenle o konuları yazmayacağım. I2C atmega veya eski attiny serisine göre daha pratik. USI gibi her şeyi bizim yaptığımız bir donanıma göre çok üstün. Durum registeri biraz yetersiz. Atmega serisinde Status her adımı belirten bir yapıya sahipti. Veri transferinde hangi adımda olduğumuzu registeri okuyup anlayabiliyorduk. Bunda öyle değil o nedenle durum takibini bizim yapmamız gerekiyor. Atmegada her adım için sürekli register bit değişikliği yapıyorduk. Bu seride bu çok az. I2C nedir nasıl çalışır için eski konulara bakmak gerekecek. Burada sadece bu seride nasıl çalışır kısaca yazıp kütüphane paylaşacağım.

I2C

Birimin şeması bu şekildedir. Bir diğer fark I2C çalışma frekansı için gereken BAUD değerinin hesaplanmasıdır.

Tr (Trise) yükselen kenar süresidir ve ns olduğundan saniyeye çevirmek gerekir. Buna göre BAUD=(((float)F_CPU/F_SCL)/2)-(5+((((float)F_CPU*Trise)/1000)/1000)/2000) olur. BAUD ile I2C biriminin çalışma frekansını belirledikten sonra okuma/yazma kesmelerini açıp birimi çalıştırmak için MCTRLA registerinde ilgili bitleri ayarlıyoruz.

Start koşulu oluşturmak için MADDR registerine (okuma/yazma biti ekli şekilde) adresi yazmak yeterlidir. Hat boşta ve birim meşgul değilse start ve kesme oluşur. Yazma görevinde veri bitene kadar MDATA registerine gidecek veri yazılır. Bittiği zaman MCTRLB registeri MCMD biti ile stop ayarlanır. Okuma görevinde veri bitene kadar MCTRLB registerinde ACK gönderilecekse ACKACT biti "0" yapılmalı ve MCMD biti RECVTRANS ayarlanmalıdır. Okuma bitince NACK için ACKACT "1" yapılır ve stop koşulu oluşturulur. 

Bütün bunları kesme ile yapan bir uygulama notu yok. Ben eski çalışmalarıma uygun olarak yazdım. Status registeri çok detaylı bilgi vermediğinden durum takibini yazılımla yapmak zorunda kaldım. Çok uzatmadan tekrara düşmeden sadece kullanımı aktarmak istedim.

Kütüphane dosyası burada: TinyAVR-1/tiny1_i2c_master at main · haluks/TinyAVR-1 (github.com)

Örnek AHT10 uygulama

/*
 * attiny1614_i2c_master.c
 *
 * Created: 3.10.2023 16:38:01
 * Author : haluk
 */ 
 #define F_CPU 3333333
 #include <avr/io.h>
 #include <avr/interrupt.h>

#include <stdio.h>
#include "i2c_at1614_master.h"
#include "uart_at1614.h"
 #include <util/delay.h>
uint8_t aht_adr=0x38;//aht10adres
uint8_t aht_res=0xBA;//soft reset
uint8_t aht_init[]={0xE1,0x08,0x00};//init
uint8_t aht_trig[]={0xAC,0x33,0x00};//ölçüm başlatma
uint8_t aht_data[6];
uint32_t aht_temp=0;
uint32_t aht_hum=0;
float sicaklik=0.0;
float nem=0.0;
char str_data[64];
uint8_t okunan=0;
 uint8_t i=0; 
int main(void){
  i2c_init();
  uart_basla(Bd115200);
  //aht_adr=i2c_adres_scan();
  i2c_send_data(aht_adr,aht_res, N_REPEAT);//soft reset
  _delay_ms(1);
    i2c_send(aht_adr,aht_init,3, N_REPEAT);//init komutu  
  while (1) {      
    i2c_send(aht_adr,aht_trig,3,N_REPEAT);//ölçme tetik
    _delay_ms(150);//ölçüm aralığı
    i2c_read(aht_adr,6);// veri okuma  
    _delay_ms(10);//ölçüm aralığı  
    while (i2c_gelen()){//okunan veri alındı
    aht_data[i++]= i2c_oku();
    }
    i=0;
    aht_temp=((uint32_t)(aht_data[3]&0x0F)<<16)|((uint16_t)aht_data[4]<<8)|(aht_data[5]);
    aht_hum=(((uint32_t)aht_data[1]<<16)|((uint16_t)aht_data[2]<<8)|aht_data[3])>>4;
    sicaklik=((float)aht_temp/5242.88)- 50;//formülün sadeleştirilmiş hali
    nem=((float)aht_hum/10485.76);//formülün sadeleştirilmiş hali 
    sprintf(str_data,"\n%.2f--%.2f\n",sicaklik,nem);//sonuçları ekrana yazmak için
    uart_dizi(str_data);    
  
    }
}