ADXL345 Analog Devices tarafından üretilen ivme ölçer entegresidir. ±2g, ±4g, ±8g ve ±16g aralıklarında 13-bite varan çözünürlükte ivme değerleri okunabilir. Veri çıkış hızı maksimum 3200hz'dir. İletişim I²C, 3-Wire SPI ve 4-Wire SPI üzerinden yapılabilir. Bu uygulamada 3-Wire SPI ile entegre ile iletişim kurulmuştur. Zamanlama diyagramı aşağıda gösterilmiştir.
Diyagramda gösterilen ilk byte'ın 7. biti, okuma ya da yazma yapılacağını belirten R/W bitidir, 6. bit ise 1 byte'dan fazla okuma ya da yazma yapılacağını belirten bittir, geriye kalan 6 bit ise erişim yapılacak registerin adresidir. 1 byte'dan fazla okuma ya da yazma yapılacağı zaman CS sinyali '1' konumuna gelene kadar iletişim devam eder. Bu sırada SCLK sinyali sürekli üretilir. Bir sonraki erişimde adres değeri otomatikman 1 artar. Bu sayede ivme değerleri okunurken her seferinde register adresinin gönderilmesi gerekmez.
1600hz ya da 3200hz veri hızı için SPI hızının 2Mhz'e eşit ya da daha yüksek olması gerekmektedir. Bu uygulamada veri hızı 3200hz ve SPI hızı 4.16Mhz olarak seçilmiştir.
Tasarımın VHDL kodu:
--Kütüphaneler library IEEE; use IEEE.STD_LOGIC_1164.ALL; USE ieee.numeric_std.ALL; entity ADXL345 is port(Clk, Reset : in std_logic; --Clk ve Reset girişi INT : in std_logic; --ADXL345'in kesme girişi nCS, SCLK : out std_logic; --ADXL345'in CS ve SCLK çıkışları SDIO : inout std_logic; --ADXL345'in SDIO hattı NewData : out std_logic; --Yeni veri sinyali --Bu sinyalin yükselen kenarı ile --yeni verinin geldiği anlaşılır. XAxis, YAxis, ZAxis : out std_logic_vector(11 downto 0)); --Her bir eksendeki ivme. --3200Hz ve Full-çözünürlük ile --maxsimum 12-bitlik veri elde edilebilir. end ADXL345; architecture Behavioral of ADXL345 is --ADXL345'in bazı registerleri ve adresleri constant BW_RATE : std_logic_vector(7 downto 0) := X"2C"; constant POWER_CTL : std_logic_vector(7 downto 0) := X"2D"; constant INT_ENABLE : std_logic_vector(7 downto 0) := X"2E"; constant DATA_FORMAT : std_logic_vector(7 downto 0) := X"31"; constant DATAX0 : std_logic_vector(7 downto 0) := X"32"; --Start sinyali --'1' konumuna geçirildiğnde Address, Data, ... sinyallerine --göre iletişim gerçekleştirilir. İletişim bittiğinde --'0' konumuna geçirilir. signal Start : std_logic := '0'; --SDIO ve SCLK kontrol sinyalleri signal SCLKSignal : std_logic := '1'; signal SDIOSignal : std_logic; --SDIO sinyalinin yönü --'1' konumunda SDIO sinyali Hi-Z konumundadır ve hat --ADXL345 tarafından kontrol edilir (Giriş). --'0' konumunda SDIO sinyali, SDIOSignal sinyali tarafında --kontrol edilir (Çıkış). signal SDIODirection : std_logic := '1'; --Okunacak ya da yazılacak registerin adresi signal Address : std_logic_vector(7 downto 0); --Yazma için gönderilen veri signal Data : std_logic_vector(7 downto 0); --Okunacak ya da yazılacak byte sayısı signal Bytes : integer range 0 to 7 := 0; --Kalan okunacak ya da yazılacak byte sayısı signal RemainingBytes : integer range 0 to 7 := 0; --Alnan veri signal ReceivedData : std_logic_vector(47 downto 0); --Gönderilen ilk byte signal FirstByte : std_logic_vector(7 downto 0); --Gönderilen ilk byte'ın 7. biti R/W bitidir. --Okuma ya da yazma yapılacağını belirtir. alias RW is FirstByte(7); --Gönderilen ilk byte'ın 6. Multiple-Byte bitidir. --Bu bit '1' konumunda ise 1 byte'dan fazla veri --yazılacağını ya da okunacağının belirtir. --Veri sayısı Bytes değişkeni ile belirlenir. alias MB is FirstByte(6); begin --Gönderilen ilk byte'ın ilk 6 biti adresdir. FirstByte(5 downto 0) <= Address(5 downto 0); --Alınan veri her bir eksen için parçalara ayrılır. XAxis(3 downto 0) <= ReceivedData(47 downto 44); XAxis(11 downto 4) <= ReceivedData(39 downto 32); YAxis(3 downto 0) <= ReceivedData(31 downto 28); YAxis(11 downto 4) <= ReceivedData(23 downto 16); ZAxis(3 downto 0) <= ReceivedData(15 downto 12); ZAxis(11 downto 4) <= ReceivedData(7 downto 0); --SCLK için clock bölücü process --50Mhz / 12 = 4.16Mhz SPI hızı process(Clk) variable ClkCnt : integer range 0 to 15 := 0; begin if rising_edge(Clk) then if ClkCnt < 5 then ClkCnt := ClkCnt + 1; else ClkCnt := 0; SCLKSignal <= not SCLKSignal; end if; end if; end process; --İletişimin ve entegrenin ayarlarının yapıldığı process process(SCLKSignal, Clk, SDIO, Start, Address, SDIOSignal) --SPI iletişiminin adım sayacı variable State : integer range 0 to 31 := 0; --Program sayacı variable ProgState : integer range 0 to 15 := 0; begin if falling_edge(SCLKSignal) then --Eğer 1'den fazla byte veri okunacaksa ya da yazılacaksa, --0. adımda okunacak byte sayısı kalan byte sayısına aktarılır. if State = 0 and MB = '1' then RemainingBytes <= Bytes; end if; --17. adımda, birden fazla byte veri okunacaksa ya da yazılacaksa --10. adıma geri dönülür. if State = 17 and RemainingBytes > 0 and MB = '1' then State := 10; --Okunacak kalan byte sayısı 1 azaltılır. RemainingBytes <= RemainingBytes - 1; --İletişim sayacı 19 dan küçükse, SCLKSignal'in düşen kenarı --ile 1 arttırılır. elsif State < 19 and Start = '1' then State := State + 1; --Değilse başa dönülür. else State := 0; end if; end if; --SPI haberleşme işlemleri if rising_edge(Clk) and Start = '1' then --nCS ve SCLK '1' konumunda olduğunda dolayı hat boşta if State = 0 then SCLK <= '1'; SDIODirection <= '0'; SDIOSignal <= '1'; nCS <= '1'; --nCS, '0' konumuna geçirilerek iletişimin başlayacağı gösterilir. elsif State = 1 then SCLK <= '1'; SDIODirection <= '0'; SDIOSignal <= '1'; nCS <= '0'; --SCLK hattına 4.16Mh'lik SPI clock'u bağlanır. --SDIO hattından da ilk byte gönderilir. elsif (State > 1) and (State < 10) then SCLK <= SCLKSignal; SDIOSignal <= FirstByte(9 - State); SDIODirection <= '0'; nCS <= '0'; --Registere yazma ya da registerden okuma yapılan döngü. elsif (State > 9) and (State < 18) then SCLK <= SCLKSignal; SDIODirection <= RW; --Yazma işlemi yapılacaksa SDIO hattından veri gönderilir. if RW = '0' then SDIOSignal <= Data(17 - State); end if; nCS <= '0'; --SCLK, '1' konumuna getirilerek iletişim durdurulur. elsif State = 18 then SCLK <= '1'; SDIODirection <= '0'; SDIOSignal <= '1'; nCS <= '0'; --nCS, '0' konumuna getirilerek iletişim sonlandırılır. elsif State = 19 then SCLK <= '1'; SDIODirection <= '0'; SDIOSignal <= '1'; nCS <= '1'; Start <= '0'; end if; end if; --Okuma işlemi yapılacaksa SCLK'nın yükselen kenarı ile --örnekleme yapılır. if (State > 9) and (State < 18) and RW = '1' then if rising_edge(SCLKSignal) then ReceivedData(17 - State + RemainingBytes * 8) <= SDIO; end if; end if; --Program --Konfigürasyonun ve kesme kontrolünün yapıldığı bölüm if rising_edge(Clk) then --3-Wire SPI, +-16g ölçüm aralığı ve Left Justified if ProgState = 0 and (Start = '0') and (State = 0) then RW <= '0'; Address <= DATA_FORMAT; Data <= X"4F"; MB <= '0'; Bytes <= 0; Start <= '1'; ProgState := 1; --Standby modundan çık --Full çözünürlük elsif ProgState = 1 and (Start = '0') and (State = 0) then RW <= '0'; Address <= POWER_CTL; Data <= X"08"; MB <= '0'; Bytes <= 0; Start <= '1'; ProgState := 2; --Saniyede 3200Hz veri çıkışı elsif ProgState = 2 and (Start = '0') and (State = 0) then RW <= '0'; Address <= BW_RATE; Data <= X"FF"; MB <= '0'; Bytes <= 0; Start <= '1'; ProgState := 3; --DataReady kesmesi aktif elsif ProgState = 3 and (Start = '0') and (State = 0) then RW <= '0'; Address <= INT_ENABLE; Data <= X"80"; MB <= '0'; Bytes <= 0; Start <= '1'; ProgState := 4; --Kesme oluştu mu kontrol et elsif ProgState = 4 and (Start = '0') then --INT sinyali '1' ise yani kesme gerçekleşmiş ise --bir sonraki adıma geç ve NewData sinyalini '0' a çek. if INT = '1' then ProgState := 5; NewData <= '0'; --INT sinyali '0' ise NewData sinyalini '1' konumunda --tut ve bu döngüde kal. else ProgState := 4; NewData <= '1'; end if; --Registerler üzerinde işlem yapılmayacağında dolayı --Start biti '0' a çekilir. Start <= '0'; --İvme verilerini oku. --DATAX0 adresinden başlayarak sırayla 6 veri oku. elsif ProgState = 5 and (Start = '0') and (State = 0) then RW <= '1'; Address <= DATAX0; Data <= X"00"; MB <= '1'; Bytes <= 5; Start <= '1'; ProgState := 4; end if; end if; end process; --SDIODirection sinyaline göre SDIO sinyalinin --durumunun belirlenmesi. with SDIODirection select SDIO <= 'Z' when '1', SDIOSignal when others; end Behavioral;