STM32F4 ve StdPeriph ile CANBUS Interrupt kullanımı

STM32F4 ve StdPeriph ile CANBUS Interrupt kullanımı

Herkese merhabalar, bu yazımızda sizlere STM32F4 serisi mikro işlemciler ile CAN BUS haberleşmeden bahsedeğiz. CAN BUS haberleşmeyi Interrupt kullanarak ve Std Periph kütüphanesi kullanarak yapacağız. Uygulamada STM32F4-Discovery kartını kullanacağız.

Şimdi ilk olarak Basitçe CAN BUS nedir sorusunun cevabı ile başlayalım.

CAN bütün bağlı olan bütün cihazların birbirileriyle haberleşmesini sağlayan bir haberleşme protokolüdür. CAN ifadesinin açılımı Controller Are Networkdür.

CAN teknolojisi Bosch otomotiv tarafından, araçlardaki kablo yükünü azaltmak ve araçtaki sistemleri birbirinden ayırmak için tasarlanmıştır. Eskiden eğer bir sensörde bir hata oluşursa, bu hata bütün sistemlerin haberleşmesini etkilemekteydi. CAN BUS ile bütün sistemler birbirinden ayrılmış durumda ve bireysel olarak çalışmaktadırlar. Haberleşmek için ise verilerini CAN hattına göndermektedirler. Bu sayede bir arıza oluğunda sadece o sensörde hata meydana geliyor ve diğerlerini etkilemiyor.

CANBUS protokolünde hata ayıklama işlemi çok daha basit durumdadır. Çünkü herbir cihazın kendine ait bir kimlik bilgisi olur ve bu sayede arızanın kaynağını rahatça bulabilmekteyiz. Cihazlar CAN BUS hattına verilerini yüklerken bu kimlik bilgileriyle yüklemektedir.

CAN BUS haberleşme ile çok uzak mesafelere güvenli bir şekilde veri gönderilebilir.

Hadi biraz şov yapalım ve kodlama kısmına geçelim.

İlk olarak veri gönderebilmek ve alabilmek için gerekli değişkenlerimizi ve yapılarımızı oluşturalım.


//CAN BUS cihaz id numarası
uint16_t canbus_device_id = 0xaf;

// Can Transmit Message Nesnesi
CanTxMsg TxMessage;

// Can Receive Message Nesnesi
CanRxMsg RxMessage;

//Aşağıdaki verileri canbus verisini tutmak için kullanacağız
char canbusData_id[2];
char canbusData_0 [2];
char canbusData_1 [2];
char canbusData_2 [2];
char canbusData_3 [2];
char canbusData_4 [2];
char canbusData_5 [2];
char canbusData_6 [2];
char canbusData_7 [2];
Şimdi sırada CANBUS mesajını gönderebilmek için gereken metodu yazalım. Bu metodda mesajın id numarasını, DLC değerini ve veri paketlerini oluşturacağız. Ardından mesaj verisini CANBUS hattında yükleyeceğiz.
MAX Standart CAN BUS id değeri : 0x07ff (2047) olabilir.

Aşağıdaki kod bloğunda bu işlemi görebilirsiniz :


void CanWriteData( uint16_t canbus_device_id, 	uint16_t d0,	uint16_t d1,	uint16_t d2,	uint16_t d3,	uint16_t d4,	uint16_t d5,	uint16_t d6,	uint16_t d7){

	//İlk olarak can bus cihaz id değerini ve standart canbus haberleşmesini belirledik
	TxMessage.StdId = canbus_device_id;
	TxMessage.RTR 	= CAN_RTR_DATA;
	TxMessage.IDE 	= CAN_ID_STD;
	//Daha sonra kaçtane mesaj paketi göndereceğimizi belirledik.
	TxMessage.DLC 	= 8;

	//Gönderilecek CANBUS verilerini Can Transmit Message yapısına yükledik.
	TxMessage.Data[0] = d0;    
	TxMessage.Data[1] = d1;    
	TxMessage.Data[2] = d2;    
	TxMessage.Data[3] = d3;    
	TxMessage.Data[4] = d4;    
	TxMessage.Data[5] = d5;    
	TxMessage.Data[6] = d6;    
	TxMessage.Data[7] = d7;    
	
	//Son olarak yukarıda hazırladığımız mesaj paketini gönderdik.
	//Bu metodla birlikte oluşturulan mesaj paketi CAN hattında yüklenecektir.
	CAN_Transmit(CAN1,&TxMessage);
}

Yukarıda gördüğünüz üzere transmit için gereken metodumuzu yazdık.

Yazının başında dediğim gibi bu uygulamada interrupt kullanacağız. CAN verisini interrupt kullanarak alacağız ve ilgili Receive Message değişkenine atayacağız.

Burada kullanacak olduğumuz method Std Periphal kütüphanelerinde __weak olarak tanımlanmış olan CAN1_RX0_IRQHandler metodudur.

Biz bu metodu main.c dosyamızda yeniden tanımladığımızda weak özelliği ezilecek ve kesme oluştuğunda bu metod çalışacak. Bu metodu oluşturduktan sonra main fonksiyonu içerisinde NVIC ile interrupt yapılandırmasını oluşturacağız.

Burada dikkat edilmesi gereken nokta bu fonksiyonun isminin değiştirilmemesidir. Kütüphane dosyasında aynı isimle yazılmaya özen gösterilmelidir.

void CAN1_RX0_IRQHandler(void)
{

    //Kesme oluştuğunda verinin hazır olduğunu anlayabiliriz.
    //CAN1 donanımı ile CANBUS hattındaki CAN verisini alıp RxMessage değişkenimize atama yapılıyor
    CAN_Receive( CAN1, 0, &RxMessage);
 
 //Aşağıda RxMessage verisini gerekli değişkenlere atıyoruz.
//Gördüğünüz üzere mesajın id değerini ve mesaj içeriğini almış olduk
 canbusData_id[0]   = RxMessage.StdId;
 canbusData_0[0]    = RxMessage.Data[0];
 canbusData_1[0] = RxMessage.Data[1];
 canbusData_2[0] = RxMessage.Data[2];
 canbusData_3[0] = RxMessage.Data[3];
 canbusData_4[0] = RxMessage.Data[4];
 canbusData_5[0] = RxMessage.Data[5];
 canbusData_6[0] = RxMessage.Data[6];
 canbusData_7[0] = RxMessage.Data[7]; 

//Artık bu CAN verisini mainprogramda ihtiyaç olan yerlerde kullanabilmekteyiz. 
 
}
Artık son olarak CAN BUS kesmelerini kullanabilmek adına NVIC yapılandırmasını oluşturacağız. Bu işlemi main fonksiyonu içerisinde yapacağız.

Hadi biraz main fonksiyonumuza göz atalım.

İlk olarak kodu parça parça anlatıp en son bütünüyle paylaşacağım.


    CAN_InitStructure.CAN_TTCM = DISABLE;
    CAN_InitStructure.CAN_ABOM = DISABLE;
    CAN_InitStructure.CAN_AWUM = DISABLE;
    CAN_InitStructure.CAN_NART = DISABLE;
    CAN_InitStructure.CAN_RFLM = DISABLE;
    CAN_InitStructure.CAN_TXFP = DISABLE;

    CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
    //42Mhz CAN1 donanımının bağlı olduğu APB1 busın frekansı
    // 42 / 2* ( 12 + 8 + 1 ) = 1MBaud 
    CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
    CAN_InitStructure.CAN_BS1 = CAN_BS1_12tq;
    CAN_InitStructure.CAN_BS2 = CAN_BS2_8tq;
    CAN_InitStructure.CAN_Prescaler = 2; 
 
    CAN_Init(CAN1, &CAN_InitStructure);

Burada bus haberleşme frekansını 1 MBaud olarak belirledik. Burada bus frekansı ile birlikte SJW, BS1, BS2 ve ön bölücü değerleri ile hesaplayarak frekans ayarını yapmış olduk. Datasheet dökümanına göre STM32F407 işlemcisi APB1 bus frekansı 42 MHz değerindedir.

Hesaplama eşitliği aşağıdaki gibidir :
BusFrequency / Prescaler * ( BS1 + BS2 + SJW ) .

Sırada interrupt yapılandırması var.


    // FIFO 0 mesaj kesmesini aktifleştirme 
    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
 
    NVIC_InitTypeDef  NVIC_InitStructure;

    NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

İlk olarak CANBUS için FIFO özelliğini özelliğini aktifleştirdik. FIFO ile veriler geliş sırasıyla işlenecektir. İlk gelen ilk işlenmiş olacaktır. Yani veri geldikçe kuyruğa eklenecektir.

FIFO : First In First Out anlamına gelmektedir.

Buraya kadar anlatılanlar ile CANBUS kullanımını göstermiş olduk

Aşağıda main fonksiyonunun bütün içeriğini görebilirsiniz.


int main()
{
 //İlk olarak CAN bus üzerinde APB1'i aktifleştirelim.
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
 //Ve GPIO Bus'ını aktifleştirelim.
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
 
 //CAN bus haberkelşmesi için gereken pinleri ayarlayalım ve aktifleştirelim.
 GPIO_InitTypeDef GPIO_InitStructure;
//GPIO_Mode_AF Olarak seçmemiz önemlidir.
//Bu sayede pinleri input ve output dışında alternatif işler içinde kullanabileceğiz
 GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
 GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
 GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1;
 GPIO_Init(GPIOD, &GPIO_InitStructure);
 
//Alternate olarak ayarlanan pinleri CAN1 haberleşmesi için ayarlıyoruz
 GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_CAN1);
 GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_CAN1); 
 
 //Ardından CAN BUS yapılarını oluşturup ayarlamaları yapıyoruz
 CAN_InitTypeDef CAN_InitStructure;
 CAN_FilterInitTypeDef CAN_FilterInitStructure;
 
     //İlk olarak esetlemek iyidir ve DeInıt yapıyoruz
    CAN_DeInit(CAN1);
    CAN_StructInit(&CAN_InitStructure);

    CAN_InitStructure.CAN_TTCM = DISABLE;
    CAN_InitStructure.CAN_ABOM = DISABLE;
    CAN_InitStructure.CAN_AWUM = DISABLE;
    CAN_InitStructure.CAN_NART = DISABLE;
    CAN_InitStructure.CAN_RFLM = DISABLE;
    CAN_InitStructure.CAN_TXFP = DISABLE;
    CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
    // 42 / 2* ( 12 + 8 + 1 ) = 1MBaud 
    CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
    CAN_InitStructure.CAN_BS1 = CAN_BS1_12tq;
    CAN_InitStructure.CAN_BS2 = CAN_BS2_8tq;
    CAN_InitStructure.CAN_Prescaler = 2; 
 
    CAN_Init(CAN1, &CAN_InitStructure);

    /* CAN filter yapılandırması*/
    //Veriye herhangi bir filtre koymadığım için bütün filtre mask değerleri 0 yaptım
    CAN_FilterInitStructure.CAN_FilterNumber = 0;
    CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
    CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
    CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
    CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
    CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0;
    CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
    CAN_FilterInit(&CAN_FilterInitStructure);

    //FIFO0 CAN1 için aktifleştirdim.
    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
 

    //Interrupt yapılandırmasını hazırlayalım
    NVIC_InitTypeDef  NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);


    while(1)
    {
       //Call above method to send a canbus data
       Can1WriteData(0x01, 0x12,0x31,0x1A,0x00,0x00,0x00, 0x56 ,0x25 );
       //And wait for some time to prevent flooding te bus
       while(65000--); 
    }
 
}

Bu yazımızda bu kadar Bizi takip etmeyi unutmayın

İyi çalışmalar ve CAN BUS haberleşmeleri dilerim.

Burak Hamdi TUFAN…


Tags


Share this Post

Send with Whatsapp

Post a Comment

Success! Your comment sent to post. It will be showed after confirmation.
Error! There was an error sending your comment.

Comments

  • There is no comment. Be the owner of first comment...