Proje Tasarımı

Başlatan X-Fi, 27 Kasım 2012, 08:56:22

X-Fi

Arkadaşlar keil üzerinde proje oluşturuyorum bir proje oluştururken izlemem gereken yöntemleri geliştirmeye karar verdim.

Bir projeyi nasıl dallandırdığımı anlatayım.

Elimizdeki yazılımı yapılacak boardun şemasından yararlanarak define kütüpanesi oluşturuyorum. Bunu bir örnekle anlatayım.

stm32fxxx_x_Board_Vx.h dosyası oluşturup pinlerin tek tek adreslerini bellirlediğim bir isme atıyorum bu sayede pin değişikliklerinden kodumuz etkilenmiyor bunu hepimiz kullanıyoruz. Aşağıdaki 2 adet basit donanim ve 2 adet COM örneği üzerinden giderek konuyu açıklayayım;

typedef enum 
{
     LED1      = 0,
     BUTONA    = 1

} Pin_TypeDef;

#define  	PINn	  2	 

/* PwrMon Led tanimlamasi */
#define  Led1_Pin        	  		GPIO_Pin_6
#define  Led1_Port	  	  		GPIOC
#define  Led1_Clk	  	  		RCC_AHBPeriph_GPIOC

/*  Menu Buton tanimlamasi (Exti-2) */
#define  ButonA_Pin   			GPIO_Pin_13
#define  ButonA_Port			GPIOC
#define  ButonA_Clk			RCC_AHBPeriph_GPIOC

typedef enum 
{
  COM1   = 0, 
  COM2   = 1 

} COM_TypeDef;  

#define  	COMn	  2	 

/*  GSM usart Com Pin tanimlamasi */
#define STM_COM1                        USART1
#define STM_COM1_CLK                    RCC_APB2Periph_USART1

#define STM_COM1_TX_PIN                 GPIO_Pin_9
#define STM_COM1_TX_GPIO_PORT           GPIOA
#define STM_COM1_TX_GPIO_CLK            RCC_AHBPeriph_GPIOA
#define STM_COM1_TX_SOURCE              GPIO_PinSource9
#define STM_COM1_TX_AF                  GPIO_AF_USART1

#define STM_COM1_RX_PIN                 GPIO_Pin_10
#define STM_COM1_RX_GPIO_PORT           GPIOA
#define STM_COM1_RX_GPIO_CLK            RCC_AHBPeriph_GPIOA
#define STM_COM1_RX_SOURCE              GPIO_PinSource10
#define STM_COM1_RX_AF                  GPIO_AF_USART1

#define STM_COM1_IRQn                   USART1_IRQn

/*  Debug Com Pin tanimlamasi */
#define STM_COM2                        USART2
#define STM_COM2_CLK                    RCC_APB1Periph_USART2

#define STM_COM2_TX_PIN                 GPIO_Pin_2
#define STM_COM2_TX_GPIO_PORT           GPIOA
#define STM_COM2_TX_GPIO_CLK            RCC_AHBPeriph_GPIOA
#define STM_COM2_TX_SOURCE              GPIO_PinSource2
#define STM_COM2_TX_AF                  GPIO_AF_USART2

#define STM_COM2_RX_PIN                 GPIO_Pin_3
#define STM_COM2_RX_GPIO_PORT           GPIOA
#define STM_COM2_RX_GPIO_CLK            RCC_AHBPeriph_GPIOA
#define STM_COM2_RX_SOURCE              GPIO_PinSource3
#define STM_COM2_RX_AF                  GPIO_AF_USART2

#define STM_COM2_IRQn                   USART2_IRQn


Bu şekilde tüm donanımlarin pinlerini tanımladık typedef atadık.

stm32fxxx_x_Board_Vx.c dosayasında ise atamalarını yaptığım basit donanimdaki pinlerin kullanım için fonksiyonlarını yazıyorum.
örnek;

GPIO_TypeDef* GPIO_PORT[PINn] = {Led1_Port,ButonA_Port};
const uint16_t GPIO_PIN[PINn] = {Led1_Pin,ButonA_Pin};
const uint32_t GPIO_CLK[PINn] = {Led1_Clk,ButonA_Clk};
	
USART_TypeDef* COM_USART[COMn] = {STM_COM1,STM_COM2}; 

GPIO_TypeDef* COM_TX_PORT[COMn] = {STM_COM1_TX_GPIO_PORT,STM_COM2_TX_GPIO_PORT};
GPIO_TypeDef* COM_RX_PORT[COMn] = {STM_COM1_RX_GPIO_PORT,STM_COM2_RX_GPIO_PORT};
const uint32_t COM_USART_CLK[COMn] = {STM_COM1_CLK,STM_COM2_CLK};
const uint32_t COM_TX_PORT_CLK[COMn] = {STM_COM1_TX_GPIO_CLK,STM_COM2_TX_GPIO_CLK};
const uint32_t COM_RX_PORT_CLK[COMn] = {STM_COM1_RX_GPIO_CLK,STM_COM2_RX_GPIO_CLK};
const uint16_t COM_TX_PIN[COMn] = {STM_COM1_TX_PIN,STM_COM2_TX_PIN};
const uint16_t COM_RX_PIN[COMn] = {STM_COM1_RX_PIN,STM_COM2_RX_PIN};
const uint8_t COM_TX_PIN_SOURCE[COMn] = {STM_COM1_TX_SOURCE,STM_COM2_TX_SOURCE};
const uint8_t COM_RX_PIN_SOURCE[COMn] = {STM_COM1_RX_SOURCE,STM_COM2_RX_SOURCE};
const uint8_t COM_TX_AF[COMn] = {STM_COM1_TX_AF,STM_COM2_TX_AF};
const uint8_t COM_RX_AF[COMn] = {STM_COM1_RX_AF,STM_COM2_RX_AF};

/****************************************************/
void COM_Init(COM_TypeDef COM, USART_InitTypeDef* USART_InitStruct)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  /* Enable GPIO clock */
  RCC_AHBPeriphClockCmd(COM_TX_PORT_CLK[COM] | COM_RX_PORT_CLK[COM], ENABLE);

	if(COM == 0)
  /* Enable USART-1	clock */
  RCC_APB2PeriphClockCmd(COM_USART_CLK[COM], ENABLE); 
  else
	/* Enable USART-2-3-4-5	clock */
	RCC_APB1PeriphClockCmd(COM_USART_CLK[COM], ENABLE); 
	
  /* Connect PXx to USARTx_Tx */
  GPIO_PinAFConfig(COM_TX_PORT[COM], COM_TX_PIN_SOURCE[COM], COM_TX_AF[COM]);

  /* Connect PXx to USARTx_Rx */
  GPIO_PinAFConfig(COM_RX_PORT[COM], COM_RX_PIN_SOURCE[COM], COM_RX_AF[COM]);
  
  /* Configure USART Tx as alternate function push-pull */
  GPIO_InitStructure.GPIO_Pin = COM_TX_PIN[COM];
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(COM_TX_PORT[COM], &GPIO_InitStructure);
    
  /* Configure USART Rx as alternate function push-pull */
  GPIO_InitStructure.GPIO_Pin = COM_RX_PIN[COM];
  GPIO_Init(COM_RX_PORT[COM], &GPIO_InitStructure);

  /* USART configuration */
  USART_Init(COM_USART[COM], USART_InitStruct);
    
  /* Enable USART */
  USART_Cmd(COM_USART[COM], ENABLE);
}
/****************************************************/
void Pin_Output(Pin_TypeDef Pin)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  
  /* Enable the pin Clock */
  RCC_AHBPeriphClockCmd(GPIO_CLK[Pin], ENABLE);

  /* Configure the pin */
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN[Pin];
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
  GPIO_Init(GPIO_PORT[Pin], &GPIO_InitStructure);
}
/****************************************************/
void Pin_Input(Pin_TypeDef Pin)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  
  /* Enable the Pin Clock */
  RCC_AHBPeriphClockCmd(GPIO_CLK[Pin], ENABLE);

  /* Configure the GPIO_LED pin */
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN[Pin];
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIO_PORT[Pin], &GPIO_InitStructure);
}
/****************************************************/
void Pin_High(Pin_TypeDef Pin)
{
	  GPIO_PORT[Pin]->BSRRL = GPIO_PIN[Pin];
}	
/****************************************************/
void Pin_Low(Pin_TypeDef Pin)
{
	  GPIO_PORT[Pin]->BSRRH = GPIO_PIN[Pin];
}	
/****************************************************/
void Pin_Toggle(Pin_TypeDef Pin)
{
	 GPIO_PORT[Pin]->ODR ^= GPIO_PIN[Pin];
}	
/****************************************************/
uint32_t Pin_Get(Pin_TypeDef Pin)
{
  return GPIO_ReadInputDataBit(GPIO_PORT[Pin], GPIO_PIN[Pin]);
}	
/****************************************************/
.
.
.


Daha sonra bir define header daha oluşturuyorum stm32fxxx_define.h onada donanımının program içerisinde kullanacağim isimlerini atıyorum.

#define       Led_PwrMon   LED1
#define       Buton_Menu   BUTONA

#define       Gsm_Com   COM1 
#define       Debug_Com    COM2

#define       Gsm_Com_Source   STM_COM1
#define       Debug_Com_Source   STM_COM2


Burdan sonra Kullanim şu şekilde .

  USART_InitStructure.USART_BaudRate = 9600;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

  COM_Init(Gsm_Com, &USART_InitStructure);

     Print_Com=Gsm_Com_Source;
     printf("COM-1: Merhaba Dunya\n\r");
		
  USART_InitStructure.USART_BaudRate = 115200;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

  COM_Init(Debug_Com, &USART_InitStructure);

     Print_Com=Debug_Com_Source;
     printf("COM-2: Merhaba Dunya\n\r");

    Pin_Output(Led_PwrMon);

    Pin_Input(Buton_Menu);

    if(Pin_Get(Buton_Menu))Pin_High(Led_PwrMon);
    else                    Pin_Low(Led_PwrMon);




Bu şekilde basit donanimlari kullaniyoruz. Örneğin LCD, EEprom gibi donanimlarda da kendi kütüpanelerini yazıyorum onların tanimlamalarinida stm32fxxx_x_board_Vx.h dosyasında yapıyorum init fonksiyonlarıni kütüpane içinde halledip takılıp çıkarılabilmesini kolay hale getiriyorum. Zaten harici donanımların kütüpaneleri çok kafa karıştırmıyor asıl kafa karıştıran led, buton, buzzer gibi sürülmesi basit olan elemanlar. Biyerden sonra kodu okunmaz hale getiren bu donanımları nasıl kullandığınızı merak ediyorum.

Keil eval board gibi çok donanımlı büyük projelerde gördüğüm yapı bu şekilde microdan macroya doğru gidiyor. Benim asıl amacım kodun anlaşılırlığını arttırmak sonradan kütüpaneler dallandıkça kıyı köşeye kod ekleyerek çözmek istemiyorum ki bu yazılımı verdiğim biri benim kaldığım yerden devam edebilmeli.

Sizlerin bu konudaki tecrübelerinizden faydalanmak isterim.
http://www.coskunergan.dev/    (Yürümekle varılmaz, lakin varanlar yürüyenlerdir.)

Burak B

Ek olarak kullandığın boardlara ait kütüphaneleri ayrı "Boards" klasörlerinde toparlayabilirsin. Mesela  ben genelde STM32 v.s. ile çalışırken;

PC
- API
- GUI
- Setup
- ...

Firmware
- Boards   (Boardlara özgü kütüphaneleri oluşturup buraya koyarım. )
- Libraries ( MCU ailesine özgü Kütüphaneler, CMSIS, StdPeripheral, v.s.)
- Project  (MDK-ARM, IAR, v.s.)
    - src  (Main, IT, System, v.s.)
    - inc  (Main, IT, System, v.s.)
    - MDK-ARM  (Project Template)
    - IAR            (Project Template)
- Third Party (LwIP, FatFs, GL, PC Utils, v.s.)


gibi bir klasör yapısı kullanırım. Ayrıca Subversion v.b. ile bunları takip etmek gibi alışkanlıklarda önemli birşey.
Board tanımlama kütüphanelerinde kullanılan derleyiciye özgü #define blokları da tanımlanabilir. Böylece farklı MCU lar için örneğin NXP ve STM32 basit bir
#define MCU_STM32 tanımı ile aynı kütüphaneyi kullanma imkanı doğar.
"... a healthy dose of paranoia leads to better systems." Jack Ganssle

X-Fi

Hocam anladığım kadarıyla guruplamaları doğru yapmaktan söz ediyorsunuz haklısınız faydası olacaktır. ifdef, endif komutlarını kullanıyorum ancak çok aktif değil.

Subversion konusunu biraz açabilirmisiniz. Ne gibi artıları oluyor. Bununla ilgili kaynak varmı elinizde.
http://www.coskunergan.dev/    (Yürümekle varılmaz, lakin varanlar yürüyenlerdir.)

Burak B

#3
Subversiyon konusunu şöyle anlatayım;
Benim bir notebookum var birde  masaüstü PC var evde. Bir proje geliştiriyorum. Bir arkadaşımda bende yardımcı olayım sana dedi. Tamam dedim çıktık yola. Ben evdeki PC ye projenin dizin yapısını oluşturuyorum ve bunu SVN sunucusuna repository olarak ekliyorum. Şimdi notebookuma geliyorum Tortouise SVN kuruyorum. Bir klasör oluşturuyorum ve ProjeX diye isimlendiriyorum. Sonra bu klasöre sağ tıklayıp checkout diyorum. Açılan pencereden evdeki  PC ye kurduğum SVN server üzerindeki ilgili projenin repository adresini veriyorum. İşlemi onayladığımda ProjeX klasöründe bu projenin bir çalışma kopyası oluşuyor. Bu işlemi arkadaşımda kendi notebookunda yapıyor. Bu işlem bir kereye mahsus. Şimdi ben projenin (atıyorum) GUI sini geliştirmeye başlıyorum. Arkadaşım API yi geliştiriyor. Ben kod yazıp  IDE üzerinden (Visual Studio v.s.) "commit" ettiğimde. SVN bir revizyon numarası ile yaptığım değişiklikleri repository üzerinde işliyor.  Arkadşımda kodunu bağımsız biçimde yazıyor commit ediyor v.s. ben ne yaptığını bilyorum veya bilmiyorum önemli değil. Ben notebookumu tekrar açıp makine başına oturunca "Update" diyorum en son yapılan değişiklikler ile benim çalışma kopyamı güncelliyor. Böylece senkron bir geliştirme ortamı oluyor. Aslında daha detaylı bir yapısı var burda anlatmak la olmaz. İnternetten araştırmak daha makbul senin açından. Hiç alakasız bir PC' ye gittiğimde orayada bir çalışma kopyası oluşturup kod yazabilirim veya internete açabilirim v.s.

Tortoise SVN  - Aynı şekilde GIT Repository olanıda var. Tek başına her işinizi görüyor aslında. IDE ye çokta ihtiyaç olmuyor. IDE' ler için SVN eklentileri de mevcut. Mesela Visual Studio, Atmel Studio, MPLAB(biraz eksik ama destek var) gibi...



"... a healthy dose of paranoia leads to better systems." Jack Ganssle