DERS 10: Stm32f4 ile SPI kullanımı (LIS302DL 3 eksen motion sensör ile)

Bu dersimizde stm32f4 ile SPI (Serial Peripheral Interface) kullanımına giriş yapacağız. SPI çalışma mantığını ele aldıktan sonra stm32f407 discovery geliştirme kartının üzerindeki 3 eksen motion sensörü kullanacağız ve sensörden okunan verileri USART aracılığıyla bilgisayara göndereceğiz.

► SPI nedir?

► SPI nasıl kullanılır?

► lis302dl hakkında

► stm32f407 discovery board SPI ve USART ayarları

SPI, motorola firmasının kendi mikro denetleyicileri için geliştirdiği, sonrasında standart olarak benimsenip diğer mikro denetleyici üreten firmalar tarafından da kullanılmaya başlanan çift yönlü haberleşebilme altyapısına sahip olan senkron bir seri haberleşme protokolüdür. Dataların taşındığı iki adet data hattı, haberleşmeyi başlatan/durduran bir clock hattı ve slave cihazı seçen bir CS(chip select) hattı olmak üzere toplamda 4 hattan oluşmaktadır.

SPI haberleşmesinde tek slave cihaz için bağlantı aşağıdaki gibidir

spi

MOSI: Master Out Slave In hattı, master cihaza bağlı olan slave cihazlara data gönderirken kullandığı hattır. Slave cihazlar kendilerine gönderilen dataları bu hat üzerinden alır.

MISO: Master In Slave Out hattı, slave cihazların master cihaza data gönderirken kullandığı hattır. Master cihaz ayarlanan faz ve polariteye göre bu hat üzerinden slave cihazdan datayı alır.

CLK: SPI haberleşmesinde senkronluğu sağlayan saat sinyalinin bulunduğu hattır. Saat sinyalleri sadece master cihazlar tarafından üretilir ve üretilen saat darbelerine göre kendisine MISO hattı üzerinden gönderilen dataları ayarlanan faz ve polariteye göre alır.

CS/SS: Birden fazla haberleşilecek slave cihaz var ise, master cihazın hangi slave cihaza veri göndereceğini seçmek için kullanılan hattır. Örneğin 1 master 8 slave cihazdan oluşan bir sistemde, master cihaz bağlanmak istediği slave cihazın CS/SS pinini lojik 0 seviyesine çeker ve diğer cihazların CS/SS pinleri lojik 1 seviyesinde kalır. Master cihazın gönderdiği data MOSI hattından tüm slave cihazlara gider ancak sadece CS/SS pini lojik0 da olan cihaz datayı alır.

 

SPI haberleşmesinde 1 master 3 slave cihaz için bağlantı aşağıdaki gibidir.

SPI1

SPI haberleşmesinde, datayı alan cihazlar gönderilen datayı uygun faz ve polaritede alırlar. SPI birimini bulunduran her mikro denetleyicide faz ve polariteyi seçmek için CPOL (clock polarity) ve CPHA (clock phase) bitleri bulunmaktadır. SPI bus’larında kullanılacak clock formatı CPOL ve CPHA bitlerine bağlı olarak toplamda 4 durumda olabilmektedir. Bu durumlar spi haberleşmesi yapılırken kesinlikle seçilmek zorundadır. 4 genel durum aşağıdaki gibidir.

spi_mode

CPOL parametresi CLK hattının inverted yada non-inverted olmasına, CPHA parametresi ise örneklemenin ötelenip ötelenmediğine bağlıdır. CPHA = 0 iken data clcok’un ilk köşesinde, CPHA = 1 iken ise clock’un 2. köşesinde örneklenir. Bu 4 duruma ait detaylı grafikler aşağıdaki gibidir.
mode1 mode2 mode3

mode4

 

LIS302DL ±2g/±8g dijital çıkış veren lineer ivme sensörüdür. C yada SPI arayüzleri ile kullanılabilmektedir(daha fazla bilgi için sensör datasheet dosyasını inceleyebilirsiniz.). LIS302DL sensörü stm32f407 geliştirme kartı üzerinde SPI hattına bağlanmıştır.

stm

Stm32f407 geliştirme kartının şematik dosyasından alınan ekran görüntüsüne göre, LIS302DL sensörünün işlemciye hangi pinler üzerinden bağlı olduğunu görmekteyiz. Pin tanımlaması yaparken bu pinleri baz almamız gerekmektedir. Başka bir modülü SPI ile kullanmak isterseniz işlemcide SPI olarak kullanabileceğiniz diğer pinlere bağlantı yapabilirsiniz (Hangi pinlerin SPI hattına sahip olduğunu öğrenmek için önceki derslerde anlatılan Alternate Function kısmına göz atabilirsiniz.)

mems spi_pin

Sensörden veri okumak ve sensöre veri yazmak için sensörün register adreslerini bilmemiz gerekmektedir.

lıs_register

Kod yazmaya geçmeden önce son olarak stm32f4xx_spi.c kütüphanesininde How to use this driver notunu okuyoruz ve yapılması gerekenleri öğreniyoruz.

spi_lib

♣ Artık kod yazmaya hazırız. Öncelikle Structure ve Clock ayarları ardında SPI ve USART pin ayarları yapılmalı. Bu ayarlamalardan sonra SPI ve USART fonksiyonları yazılıp herhangi bir terminal programı ile sensörden ölçülen değerler görüntülenebilir. (USART ayarları ve Board-TTL bağlantısı için USART dersine bakabilirsiniz.)

 

#include "stm32f4xx.h" // Device header
#include <stdio.h>
int x,y;
int k;
SPI_InitTypeDef SPI_InitTypeStructure;
GPIO_InitTypeDef GPIO_InitTypeStructure;
USART_InitTypeDef USART_InitStructure;
char str[50];
uint32_t i = 0;
void USART_Puts(USART_TypeDef* USARTx, volatile char *s)
{
while(*s)
{
while(!(USARTx ->SR & 0x00000040));
USART_SendData(USARTx, *s);
*s++;
}
}
uint8_t SPI_Rx(uint8_t adress)
{
GPIO_ResetBits(GPIOE,GPIO_Pin_3); //CS pini lojik 0 a çekildi
adress=0x80|adress; // okuma islemi yapilacak
while(!SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE));
SPI_I2S_SendData(SPI1,adress);
while(!SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE));
SPI_I2S_ReceiveData(SPI1);
while(!SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE));
SPI_I2S_SendData(SPI1,0x00);
while(!SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE));
GPIO_SetBits(GPIOE,GPIO_Pin_3); //CS pini lojik 1 e çekildi
return SPI_I2S_ReceiveData(SPI1);
}
void usart_ayar(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitTypeStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitTypeStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitTypeStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitTypeStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitTypeStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, & GPIO_InitTypeStructure);
GPIO_PinAFConfig(GPIOA , GPIO_PinSource2, GPIO_AF_USART2);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART2,& USART_InitStructure);
USART_Cmd(USART2, ENABLE);
}
void ayarlar(void)
{
/* Structure ve Clock Ayarlari */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOD| RCC_AHB1Periph_GPIOE , ENABLE);
/* D portu Led ayarlari */
GPIO_InitTypeStructure.GPIO_Pin=GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitTypeStructure.GPIO_Mode=GPIO_Mode_OUT;
GPIO_InitTypeStructure.GPIO_OType=GPIO_OType_PP;
GPIO_Init(GPIOD, &GPIO_InitTypeStructure);
GPIO_InitTypeStructure.GPIO_Pin=GPIO_Pin_3;
GPIO_InitTypeStructure.GPIO_Mode=GPIO_Mode_OUT;
GPIO_InitTypeStructure.GPIO_OType=GPIO_OType_PP;
GPIO_Init(GPIOE, &GPIO_InitTypeStructure);
/* SPI SCK-MOSI-MISO pin Ayarlari */
GPIO_InitTypeStructure.GPIO_Pin=GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitTypeStructure.GPIO_Mode=GPIO_Mode_AF;
GPIO_InitTypeStructure.GPIO_OType=GPIO_OType_PP;
GPIO_Init(GPIOA, &GPIO_InitTypeStructure);
/* GPIO AF pin Ayarlari */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1); // sck pin
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1); // mosi pin
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1); // miso pin
/* SPI Ayarlari */
SPI_InitTypeStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_2;
SPI_InitTypeStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;
SPI_InitTypeStructure.SPI_Mode=SPI_Mode_Master;
SPI_InitTypeStructure.SPI_DataSize=SPI_DataSize_8b;
SPI_InitTypeStructure.SPI_FirstBit=SPI_FirstBit_MSB;
SPI_InitTypeStructure.SPI_CPOL=SPI_CPOL_High;
SPI_InitTypeStructure.SPI_CPHA=SPI_CPHA_2Edge;
SPI_InitTypeStructure.SPI_NSS=SPI_NSS_Soft|SPI_NSSInternalSoft_Set;
SPI_Init(SPI1,&SPI_InitTypeStructure);
SPI_Cmd(SPI1, ENABLE);
GPIO_SetBits(GPIOE,GPIO_Pin_3); //CS pini lojik 1 seviyesine çekildi
}
int main()
{
ayarlar();
usart_ayar();
while(1)
{
x=SPI_Rx(0x29);
y=SPI_Rx(0x2B);
sprintf(str,"x=%d , y=%d\n", x, y);
USART_Puts(USART2,str);
}
}

Yorum

  1. By sya

    Cevapla

    • By Oğuzhan Gültekin

      Cevapla

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir