TLC5940 ile pwm

TLC5940Merhaba, uzun zaman oldu ne bloğuma nede kendime pek zaman ayıramıyorum bu aralar. Sebep belkide motosikletimi satmış olmam olabilir.
Malum bir hexapod işine girdim yazıyı takip ediyorsunuzdur diye umuyorum. Projede kullanılacak olan 18 adet RC servo yu kullanabilmek için 18, 20ms lik peryoda sahip pwm in üretilmesi gerekiyor. bunu doğrudan stm32f4discovery kitten alabilirim. ama bu bana 18 adet pin in buraya ayrılması demektir ki yokluk gören 8051 ile 16f84 ile çalışmak zorunda kalan bizim kuşak için pek uygun olmaz.

Aramalarım sonucu TI nin PWM Led driver nın bu iş için uygun olacağını düşündüm. Örnekleride bolca mevcut ama genelde Ardunio (hep yanlış yazarım şimdide doğrumu yanlış mı bilmiyorum) . Bu PWM sürücülerden iki çeşidini denedim TLC5947 ve TLC5940. İkisi arasındaki farklar aşağıda sıralanmıştır.

TLC5940 TLC5947
Data Vin (Min) (V) 3 3
Data Vin (Max) (V) 5.5 5.5
Output Channels 16 24    
Analog Dimming Steps 64
Data Input Serial Serial
Data Transfer Rate (Typ) (MHz) 30 30
Ch to Ch Accuracy (Typ) (+/- %) 1 2
Per Channel PWM Steps 4096 4096
Per Channel Drive (mA) 120 30
LED Voltage (Max) (V) 17 30
Special Features Fault Reporting  Internal GS Clock 
LED Open Detection Thermal Shutdown
Power Good/Error Flag
Operating Temperature Range (C) -40 to 85 -40 to 85

iki sürücüyü birbirinden ayıran fark, kanal sayıları ve PWM in üretilmesi için gerekli olan GSCLK in internal yada external olmasıdır. Benim projemde 50hz lik bir Pwm e ihtiyaç duyduğumdan tlc 5940 seçmiş bulunmaktayım.
 
Aşağıda kodları verilen sürücü ile ilk etapta 50hz lik bir pwm oluşturmadım. Basitce SPI arayüzünden bilgileri gönderdim ve GSCLK üreteke bu PWM i çıkıştaki ledlerde gözlemledim.

 #include <stm32f4xx.h>
 #include <stm32f4xx_rcc.h>
 #include <stm32f4xx_gpio.h>
 #include <stm32f4xx_tim.h>
 #include <stm32f4xx_spi.h>
 #include <misc.h>
 #define TLC_RCC_AHB1 RCC_AHB1Periph_GPIOB
 #define TLC5940_GPIO GPIOB
 #define PIN_BLANK GPIO_Pin_5
 #define PIN_VPRG GPIO_Pin_9
 #define PIN_XLAT GPIO_Pin_6
 #define PIN_GSCLK GPIO_Pin_3
 int timer_update=0;
 #define COUNT_TLC 1
void init_tim7(void){
 TIM_TimeBaseInitTypeDef TIM_TBInitStruct;
 NVIC_InitTypeDef NVIC_InitStructure;
 RCC_APB1PeriphClockCmd(RCC_APB1ENR_TIM7EN,ENABLE); // Timer saat kaynağını aç
 TIM_TBInitStruct.TIM_Prescaler =8299; // ÖnBölücü (PSC) değeri 4199
 TIM_TBInitStruct.TIM_Period =9; // Otomatik geri yükleme (ARR) eşiği 1
 TIM_TimeBaseInit(TIM7,&TIM_TBInitStruct); // Timeri init et
 TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE); // Timer Update olayında interrupt istesin.
 NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 NVIC_Init(&NVIC_InitStructure);
 TIM_Cmd(TIM7, ENABLE);// Timeri başlat
}
void TIM7_IRQHandler(void){
 TIM7->SR=0;
 GPIOD->ODR ^= GPIO_Pin_12;
 timer_update +=1;
}
void init_SPI1(void){
 GPIO_InitTypeDef GPIO_InitStruct;
 SPI_InitTypeDef SPI_InitStruct;
 // enable clock for used IO pins
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOD| TLC_RCC_AHB1, ENABLE);
 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_All;
 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
 GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
 GPIO_Init(GPIOD, &GPIO_InitStruct);
 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_All;
 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
 GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
 GPIO_Init(TLC5940_GPIO, &GPIO_InitStruct);
 /* configure pins used by SPI1
 * PA5 = SCK
 * PA6 = MISO
 * PA7 = MOSI
 */
 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5;
 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
 GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
 GPIO_Init(GPIOA, &GPIO_InitStruct);
 // connect SPI1 pins to SPI alternate function
 GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
 GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
 GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
 // enable clock for used IO pins
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
 /* Configure the chip select pin
 in this case we will use PE7 */
 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
 GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
 GPIO_Init(GPIOE, &GPIO_InitStruct);
 GPIOE->BSRRL |= GPIO_Pin_7; // set PE7 high
 // enable peripheral clock
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
 /* configure SPI1 in Mode 0
 * CPOL = 0 --> clock is low when idle
 * CPHA = 0 --> data is sampled at the first edge
 */
 SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines
 SPI_InitStruct.SPI_Mode = SPI_Mode_Master; // transmit in master mode, NSS pin has to be always high
 SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide
 SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; // clock is low when idle
 SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // data sampled at first edge
 SPI_InitStruct.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set; // set the NSS management to internal and pull internal NSS high
 SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; // SPI frequency is APB2 frequency / 4
 SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first
 SPI_Init(SPI1, &SPI_InitStruct);
 SPI_Cmd(SPI1, ENABLE); // enable SPI1
}
/* This funtion is used to transmit and receive data
 * with SPI1
 * data --> data to be transmitted
 * returns received value
 */
uint8_t SPI1_send(uint8_t data){
 SPI_I2S_SendData(SPI1,data);
 //SPI1->DR = data; // write data to be transmitted to the SPI data register
 while( !(SPI1->SR & SPI_I2S_FLAG_TXE) ); // wait until transmit complete
 while( !(SPI1->SR & SPI_I2S_FLAG_RXNE) ); // wait until receive complete
 while( SPI1->SR & SPI_I2S_FLAG_BSY ); // wait until SPI is not busy anymore
 return SPI1->DR; // return received data from SPI data register
}
void _delay(int value){
 while(value--)
 {
 }
}
void Blank_Pulse(){
 GPIO_SetBits(TLC5940_GPIO,PIN_BLANK);
 GPIO_ResetBits(TLC5940_GPIO,PIN_BLANK);
 //TLC5940_GPIO->ODR |=BLANK_PIN;
 //TLC5940_GPIO->ODR &=0x00000000;
}
void Xlat_Pulse(){
 GPIO_SetBits(TLC5940_GPIO,PIN_XLAT);
 GPIO_ResetBits(TLC5940_GPIO,PIN_XLAT);
 //TLC5940_GPIO->ODR |=XLAT_PIN;
 //TLC5940_GPIO->ODR &=0x00000000;
}
void GSCLK_Pulse(){
 GPIO_SetBits(TLC5940_GPIO,PIN_GSCLK);
 GPIO_ResetBits(TLC5940_GPIO,PIN_GSCLK);
 //TLC5940_GPIO->ODR |=GSCLK_PIN;
 //TLC5940_GPIO->ODR &=0x00000000;
}
//CHECK CORE CLK
void MCO2_INIT(){
 GPIO_InitTypeDef GPIO_InitStructure;
 // Output HSE clock (8 MHz) on MCO pin (PC9)
 RCC_MCO2Config(RCC_MCO2Source_SYSCLK, RCC_MCO2Div_5);
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
 GPIO_StructInit(&GPIO_InitStructure);
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
 GPIO_Init(GPIOC, &GPIO_InitStructure);
 GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_MCO);
}
int main(void){
 SystemInit(); //168mhz
 init_tim7();
 init_SPI1();
 MCO2_INIT();
 uint_fast8_t n;
 //LED0
 u16 data[COUNT_TLC* 16]={0x0000 ,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000};
 GPIO_ResetBits(TLC5940_GPIO,PIN_VPRG);
 while(1){
 GPIO_SetBits(GPIOD,GPIO_Pin_12);
 while(timer_update>3){
 data[15] +=16;
 data[14] -=16;
 if (data[15]>4095) {
 data[15]=0;
 }
 GPIO_SetBits(TLC5940_GPIO,PIN_BLANK);
 for(n=0; n<(COUNT_TLC* 16); n=n+2)
 {
 SPI1_send(data[n]>>4);
 SPI1_send((data[n]<<4) | (data[n+1])>>8);
 SPI1_send(data[n+1]);
 }
 GPIOE->BSRRL |= GPIO_Pin_7; // set PE7 (CS) high
 GPIO_ResetBits(GPIOD,GPIO_Pin_12);
 GPIOE->BSRRH |= GPIO_Pin_7;
 _delay(1);
 GPIO_SetBits(TLC5940_GPIO,PIN_XLAT);
 _delay(1);
 GPIO_ResetBits(TLC5940_GPIO,PIN_BLANK);
 GPIO_ResetBits(TLC5940_GPIO,PIN_XLAT);
 _delay(1);
 timer_update=0;
 }
 int i;
 //generate GSCLK
 for (i = 0; i < 4096; i++){
 TLC5940_GPIO->BSRRL = PIN_GSCLK;
 TLC5940_GPIO->BSRRH = PIN_GSCLK;
 }
 Blank_Pulse();
 }
}

 

Bir Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Google fotoğrafı

Google hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d blogcu bunu beğendi: