Page 1 of 2

A LED strip controller

Posted: Thu Aug 29, 2013 5:41 pm
by RoccoMarco
Hi every one.

I have started a new little project in order to find out how works an RGB led. Right now the software is pratically inexistent. I have writed just a few lines of code in order to test the circuit and RGB stripes made in China ;) (I have found out that the blue and the green labels on stipes are inverted). I'm using an STM32F303 Discovery board and obviously ChibiOS\RT

[youtube]oMMXDLboix0[/youtube]

Code: Select all

/*
    This file has been written by Guglielmi Rocco Marco.
    This is part of Led Stipes Controller project <http://www.chibios.org>.
*/

#include "ch.h"
#include "hal.h"


#define GPIO_S1_RED   ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIO_S1_GREEN ((GPIO_TypeDef *) GPIOD_BASE)
#define GPIO_S1_BLUE  ((GPIO_TypeDef *) GPIOB_BASE)

#define GPIO_S2_RED   ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIO_S2_GREEN ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIO_S2_BLUE  ((GPIO_TypeDef *) GPIOF_BASE)


#define S1_RED        6
#define S1_GREEN      9
#define S1_BLUE       1

#define S2_RED        1
#define S2_GREEN      9
#define S2_BLUE       10

static double duty = 0.2f;
static int period = 10000;

/*===========================================================================*/
/*                                THREADS                                    */
/*===========================================================================*/
static WORKING_AREA(waThdOut_1, 512);


static void clear_all(void){

  palClearPad(GPIOE, GPIOE_LED3_RED);
  palClearPad(GPIO_S1_RED, S1_RED);


  palClearPad(GPIOE, GPIOE_LED6_GREEN);
  palClearPad(GPIO_S1_GREEN, S1_GREEN);


  palClearPad(GPIOE, GPIOE_LED4_BLUE);
  palClearPad(GPIO_S1_BLUE, S1_BLUE);


  palClearPad(GPIOE, GPIOE_LED10_RED);
  palClearPad(GPIO_S2_RED, S2_RED);


  palClearPad(GPIOE, GPIOE_LED7_GREEN);
  palClearPad(GPIO_S2_GREEN, S2_GREEN);


  palClearPad(GPIOE, GPIOE_LED9_BLUE);
  palClearPad(GPIO_S2_BLUE, S2_BLUE);
}

static msg_t ThdOut_1(void *arg){
  (void) arg;
  while (TRUE){
    /*palClearPad(GPIOE, GPIOE_LED3_RED);
    palClearPad(GPIO_S1_RED, S1_RED);
    chThdSleepMilliseconds(5);*/
    clear_all();
    palSetPad(GPIOE, GPIOE_LED3_RED);
    palSetPad(GPIO_S1_RED, S1_RED);
    chThdSleepMilliseconds(1000);
    clear_all();
    palSetPad(GPIOE, GPIOE_LED6_GREEN);
    palSetPad(GPIO_S1_GREEN, S1_GREEN);
    chThdSleepMilliseconds(1000);
    clear_all();
    palSetPad(GPIOE, GPIOE_LED4_BLUE);
    palSetPad(GPIO_S1_BLUE, S1_BLUE);
    chThdSleepMilliseconds(1000);
    clear_all();
    palSetPad(GPIOE, GPIOE_LED10_RED);
    palSetPad(GPIO_S2_RED, S2_RED);
    chThdSleepMilliseconds(1000);
    clear_all();
    palSetPad(GPIOE, GPIOE_LED7_GREEN);
    palSetPad(GPIO_S2_GREEN, S2_GREEN);
    chThdSleepMilliseconds(1000);
    clear_all();
    palSetPad(GPIOE, GPIOE_LED9_BLUE);
    palSetPad(GPIO_S2_BLUE, S2_BLUE);
    chThdSleepMilliseconds(1000);
  }
return (msg_t) 0;
}

static msg_t ThdOut_2(void *arg){
  (void) arg;
  while (TRUE){
    //palClearPad(GPIOE, GPIOE_LED6_GREEN);
    //palClearPad(GPIO_S1_GREEN, S1_GREEN);
    chThdSleepMilliseconds(5);
  }
return (msg_t) 0;
}

static msg_t ThdOut_3(void *arg){
  (void) arg;
  while (TRUE){
    //palClearPad(GPIOE, GPIOE_LED4_BLUE);
    //palClearPad(GPIO_S1_BLUE, S1_BLUE);
    chThdSleepMilliseconds(5);
  }
return (msg_t) 0;
}

static msg_t ThdOut_4(void *arg){
  (void) arg;
  while (TRUE){
    //palClearPad(GPIOE, GPIOE_LED10_RED);
    //palClearPad(GPIO_S2_RED, S2_RED);
    chThdSleepMilliseconds(5);
  }
return (msg_t) 0;
}

static msg_t ThdOut_5(void *arg){
  (void) arg;
  while (TRUE){
    //palClearPad(GPIOE, GPIOE_LED7_GREEN);
    //palClearPad(GPIO_S2_GREEN, S2_GREEN);
    chThdSleepMilliseconds(5);
  }
return (msg_t) 0;
}

static msg_t ThdOut_6(void *arg){
  (void) arg;
  while (TRUE){
    //palClearPad(GPIOE, GPIOE_LED9_BLUE);
    //palClearPad(GPIO_S2_BLUE, S2_BLUE);
    chThdSleepMilliseconds(5);
  }
return (msg_t) 0;
}

/*===========================================================================*/
/*                              END OF THREADS                               */
/*===========================================================================*/

/*
 * Application entry point.
 */
int main(void) {
  /*
   * System initializations.
   * - HAL initialization, this also initializes the configured device drivers
   *   and performs the board-specific initializations.
   * - Kernel initialization, the main() function becomes a thread and the
   *   RTOS is active.
   */
  bool_t CHECK = TRUE;
  halInit();
  chSysInit();
  /*
   * PC6 is red channel of strip 1
   */
  palSetPadMode(GPIO_S1_RED, S1_RED, PAL_MODE_OUTPUT_PUSHPULL
                | PAL_STM32_OSPEED_HIGHEST);
  /*
   * PD9 is green channel of strip 1
   */
  palSetPadMode(GPIO_S1_GREEN, S1_GREEN, PAL_MODE_OUTPUT_PUSHPULL
                | PAL_STM32_OSPEED_HIGHEST);
  /*
   * PB1 is blue channel of strip 1
   */
  palSetPadMode(GPIO_S1_BLUE, S1_BLUE, PAL_MODE_OUTPUT_PUSHPULL
                | PAL_STM32_OSPEED_HIGHEST);

  /*
   * PC1 is red channel of strip 2
   */
  palSetPadMode(GPIO_S2_RED, S2_RED, PAL_MODE_OUTPUT_PUSHPULL
                | PAL_STM32_OSPEED_HIGHEST);

  /*
   * PB9 is green channel of strip 2
   */
  palSetPadMode(GPIO_S2_GREEN, S2_GREEN, PAL_MODE_OUTPUT_PUSHPULL
                | PAL_STM32_OSPEED_HIGHEST);

  /*
   * PF10 is blue channel of strip 2
   */
  palSetPadMode(GPIO_S2_BLUE, S2_BLUE, PAL_MODE_OUTPUT_PUSHPULL
                | PAL_STM32_OSPEED_HIGHEST);

  clear_all();

  chThdCreateStatic(waThdOut_1, sizeof(waThdOut_1), NORMALPRIO - 1,
                    ThdOut_1, NULL);
  chThdCreateStatic(waThdOut_2, sizeof(waThdOut_2), NORMALPRIO - 2,
                    ThdOut_2, NULL);
  chThdCreateStatic(waThdOut_3, sizeof(waThdOut_2), NORMALPRIO - 3,
                    ThdOut_3, NULL);
  chThdCreateStatic(waThdOut_4, sizeof(waThdOut_4), NORMALPRIO - 4,
                    ThdOut_4, NULL);
  chThdCreateStatic(waThdOut_5, sizeof(waThdOut_5), NORMALPRIO - 5,
                    ThdOut_5, NULL);
  chThdCreateStatic(waThdOut_6, sizeof(waThdOut_6), NORMALPRIO - 6,
                    ThdOut_6, NULL);

  while (TRUE) {
    if (CHECK){
      duty = (duty + 0.001);
      if (duty >= 0.990){
        CHECK = FALSE;
      }
    }
    else{
      duty = (duty - 0.001);
      if (duty <= 0.010){
        CHECK = TRUE;
      }
    }
    chThdSleepMilliseconds(5);
  }
  return (msg_t)0;
}



Re: A LED strip controller

Posted: Sun Sep 01, 2013 6:28 pm
by RoccoMarco
Something more. Now i need a remote to control some light games

Code: Select all

/*
    This file has been written by Guglielmi Rocco Marco.
    This is part of Led Stipes Controller project <http://www.chibios.org>.
*/

#include "ch.h"
#include "hal.h"


struct ledstripe_s {
                    GPIO_TypeDef* RED_port;
                    GPIO_TypeDef* GREEN_port;
                    GPIO_TypeDef* BLUE_port;
                    int RED_pad;
                    int GREEN_pad;
                    int BLUE_pad;
                    int RED_intensity;
                    int GREEN_intensity;
                    int BLUE_intensity;
};
typedef struct ledstripe_s ledstripe_t;

static ledstripe_t stripes[2];
/*===========================================================================*/
/*                               FUNCTIONS                                   */
/*===========================================================================*/

/*static void clear_all(void){

  palClearPad(GPIOE, GPIOE_LED3_RED);
  palClearPad(GPIO_S1_RED, S1_RED);


  palClearPad(GPIOE, GPIOE_LED6_GREEN);
  palClearPad(GPIO_S1_GREEN, S1_GREEN);


  palClearPad(GPIOE, GPIOE_LED4_BLUE);
  palClearPad(GPIO_S1_BLUE, S1_BLUE);


  palClearPad(GPIOE, GPIOE_LED10_RED);
  palClearPad(GPIO_S2_RED, S2_RED);


  palClearPad(GPIOE, GPIOE_LED7_GREEN);
  palClearPad(GPIO_S2_GREEN, S2_GREEN);


  palClearPad(GPIOE, GPIOE_LED9_BLUE);
  palClearPad(GPIO_S2_BLUE, S2_BLUE);
}*/

static void StripesInit(void){
  /*
   * PC6 is red channel of strip 1
   * PD9 is green channel of strip 1
   * PB1 is blue channel of strip 1
   */
  stripes[0].RED_port = (GPIO_TypeDef*) GPIOC_BASE;
  stripes[0].GREEN_port = (GPIO_TypeDef*) GPIOD_BASE;
  stripes[0].BLUE_port = (GPIO_TypeDef*) GPIOB_BASE;
  stripes[0].RED_pad = 6;
  stripes[0].GREEN_pad = 9;
  stripes[0].BLUE_pad = 1;
  stripes[0].RED_intensity = 0;
  stripes[0].BLUE_intensity = 0;
  stripes[0].GREEN_intensity = 0;

  /*
   * PC1 is red channel of strip 2
   * PB9 is green channel of strip 2
   * PF10 is blue channel of strip 2
   */
  stripes[1].RED_port = (GPIO_TypeDef*) GPIOC_BASE;
  stripes[1].GREEN_port = (GPIO_TypeDef*) GPIOB_BASE;
  stripes[1].BLUE_port = (GPIO_TypeDef*) GPIOF_BASE;
  stripes[1].RED_pad = 1;
  stripes[1].GREEN_pad = 9;
  stripes[1].BLUE_pad = 10;
  stripes[1].RED_intensity = 0;
  stripes[1].BLUE_intensity = 0;
  stripes[1].GREEN_intensity = 0;

  /*
   * Setting pad for stripe number one
   */
  palSetPadMode(stripes[0].RED_port, stripes[0].RED_pad, PAL_MODE_OUTPUT_PUSHPULL
                | PAL_STM32_OSPEED_HIGHEST);
  palSetPadMode(stripes[0].GREEN_port, stripes[0].GREEN_pad, PAL_MODE_OUTPUT_PUSHPULL
                | PAL_STM32_OSPEED_HIGHEST);
  palSetPadMode(stripes[0].BLUE_port, stripes[0].BLUE_pad, PAL_MODE_OUTPUT_PUSHPULL
                | PAL_STM32_OSPEED_HIGHEST);
  /*
   * Setting pad for stripe number two
   */
  palSetPadMode(stripes[1].RED_port, stripes[1].RED_pad, PAL_MODE_OUTPUT_PUSHPULL
                | PAL_STM32_OSPEED_HIGHEST);
  palSetPadMode(stripes[1].GREEN_port, stripes[1].GREEN_pad, PAL_MODE_OUTPUT_PUSHPULL
                | PAL_STM32_OSPEED_HIGHEST);
  palSetPadMode(stripes[1].BLUE_port, stripes[1].BLUE_pad, PAL_MODE_OUTPUT_PUSHPULL
                | PAL_STM32_OSPEED_HIGHEST);
}
/*===========================================================================*/
/*                             END OF FUNCTIONS                              */
/*===========================================================================*/

/*===========================================================================*/
/*                                THREADS                                    */
/*===========================================================================*/
static WORKING_AREA(waThdOut_1, 512);
static WORKING_AREA(waThdOut_2, 512);
static WORKING_AREA(waThdOut_3, 512);
static WORKING_AREA(waThdOut_4, 512);
static WORKING_AREA(waThdOut_5, 512);
static WORKING_AREA(waThdOut_6, 512);

static msg_t ThdOut_1(void *arg){
  (void) arg;
  while (TRUE){
    if (stripes[0].RED_intensity <= 0){
      palClearPad(GPIOE, GPIOE_LED3_RED);
      palClearPad(stripes[0].RED_port, stripes[0].RED_pad);
    }
    else if (stripes[0].RED_intensity >= 100){
      palSetPad(GPIOE, GPIOE_LED3_RED);
      palSetPad(stripes[0].RED_port, stripes[0].RED_pad);
    }
    else{
      palSetPad(GPIOE, GPIOE_LED3_RED);
      palSetPad(stripes[0].RED_port, stripes[0].RED_pad);
      chThdSleepMicroseconds(stripes[0].RED_intensity * 100);
      palClearPad(GPIOE, GPIOE_LED3_RED);
      palClearPad(stripes[0].RED_port, stripes[0].RED_pad);
      chThdSleepMicroseconds(10000 - (stripes[0].RED_intensity * 100));
    }
    chThdSleepMicroseconds(100);
  }
return (msg_t) 0;
}

static msg_t ThdOut_2(void *arg){
  (void) arg;
  while (TRUE){
    if (stripes[0].GREEN_intensity <= 0){
      palClearPad(GPIOE, GPIOE_LED6_GREEN);
      palClearPad(stripes[0].GREEN_port, stripes[0].GREEN_pad);
    }
    else if (stripes[0].GREEN_intensity >= 100){
      palSetPad(GPIOE, GPIOE_LED6_GREEN);
      palSetPad(stripes[0].GREEN_port, stripes[0].GREEN_pad);
    }
    else{
      palSetPad(GPIOE, GPIOE_LED6_GREEN);
      palSetPad(stripes[0].GREEN_port, stripes[0].GREEN_pad);
      chThdSleepMicroseconds(stripes[0].GREEN_intensity * 100);
      palClearPad(GPIOE, GPIOE_LED6_GREEN);
      palClearPad(stripes[0].GREEN_port, stripes[0].GREEN_pad);
      chThdSleepMicroseconds(10000 - (stripes[0].GREEN_intensity * 100));
    }
    chThdSleepMicroseconds(100);
  }
return (msg_t) 0;
}

static msg_t ThdOut_3(void *arg){
  (void) arg;
  while (TRUE){
    if (stripes[0].BLUE_intensity <= 0){
      palClearPad(GPIOE, GPIOE_LED4_BLUE);
      palClearPad(stripes[0].BLUE_port, stripes[0].BLUE_pad);
    }
    else if (stripes[0].BLUE_intensity >= 100){
      palSetPad(GPIOE, GPIOE_LED4_BLUE);
      palSetPad(stripes[0].BLUE_port, stripes[0].BLUE_pad);
    }
    else{
      palSetPad(GPIOE, GPIOE_LED4_BLUE);
      palSetPad(stripes[0].BLUE_port, stripes[0].BLUE_pad);
      chThdSleepMicroseconds(stripes[0].BLUE_intensity * 100);
      palClearPad(GPIOE, GPIOE_LED4_BLUE);
      palClearPad(stripes[0].BLUE_port, stripes[0].BLUE_pad);
      chThdSleepMicroseconds(10000 - (stripes[0].BLUE_intensity * 100));
    }
    chThdSleepMicroseconds(100);
  }
return (msg_t) 0;
}

static msg_t ThdOut_4(void *arg){
  (void) arg;
  while (TRUE){
    if (stripes[1].RED_intensity <= 0){
      palClearPad(GPIOE, GPIOE_LED10_RED);
      palClearPad(stripes[1].RED_port, stripes[1].RED_pad);
    }
    else if (stripes[1].RED_intensity >= 100){
      palSetPad(GPIOE, GPIOE_LED10_RED);
      palSetPad(stripes[1].RED_port, stripes[1].RED_pad);
    }
    else{
      palSetPad(GPIOE, GPIOE_LED10_RED);
      palSetPad(stripes[1].RED_port, stripes[1].RED_pad);
      chThdSleepMicroseconds(stripes[1].RED_intensity * 100);
      palClearPad(GPIOE, GPIOE_LED10_RED);
      palClearPad(stripes[1].RED_port, stripes[1].RED_pad);
      chThdSleepMicroseconds(10000 - (stripes[1].RED_intensity * 100));
    }
    chThdSleepMicroseconds(100);
  }
return (msg_t) 0;
}

static msg_t ThdOut_5(void *arg){
  (void) arg;
  while (TRUE){
    if (stripes[1].GREEN_intensity <= 0){
      palClearPad(GPIOE, GPIOE_LED7_GREEN);
      palClearPad(stripes[1].GREEN_port, stripes[1].GREEN_pad);
    }
    else if (stripes[1].GREEN_intensity >= 100){
      palSetPad(GPIOE, GPIOE_LED7_GREEN);
      palSetPad(stripes[1].GREEN_port, stripes[1].GREEN_pad);
    }
    else{
      palSetPad(GPIOE, GPIOE_LED7_GREEN);
      palSetPad(stripes[1].GREEN_port, stripes[1].GREEN_pad);
      chThdSleepMicroseconds(stripes[1].GREEN_intensity * 100);
      palClearPad(GPIOE, GPIOE_LED7_GREEN);
      palClearPad(stripes[1].GREEN_port, stripes[1].GREEN_pad);
      chThdSleepMicroseconds(10000 - (stripes[1].GREEN_intensity * 100));
    }
    chThdSleepMicroseconds(100);
  }
return (msg_t) 0;
}

static msg_t ThdOut_6(void *arg){
  (void) arg;
  while (TRUE){
    if (stripes[1].BLUE_intensity <= 0){
      palClearPad(GPIOE, GPIOE_LED9_BLUE);
      palClearPad(stripes[1].BLUE_port, stripes[1].BLUE_pad);
    }
    else if (stripes[1].BLUE_intensity >= 100){
      palSetPad(GPIOE, GPIOE_LED9_BLUE);
      palSetPad(stripes[1].BLUE_port, stripes[1].BLUE_pad);
    }
    else{
      palSetPad(GPIOE, GPIOE_LED9_BLUE);
      palSetPad(stripes[1].BLUE_port, stripes[1].BLUE_pad);
      chThdSleepMicroseconds(stripes[1].BLUE_intensity * 100);
      palClearPad(GPIOE, GPIOE_LED9_BLUE);
      palClearPad(stripes[1].BLUE_port, stripes[1].BLUE_pad);
      chThdSleepMicroseconds(10000 - (stripes[1].BLUE_intensity * 100));
    }
    chThdSleepMicroseconds(100);
  }
return (msg_t) 0;
}

/*===========================================================================*/
/*                              END OF THREADS                               */
/*===========================================================================*/

/*
 * Application entry point.
 */
int main(void) {
  /*
   * System initializations.
   * - HAL initialization, this also initializes the configured device drivers
   *   and performs the board-specific initializations.
   * - Kernel initialization, the main() function becomes a thread and the
   *   RTOS is active.
   */
  halInit();
  chSysInit();
  StripesInit();


  chThdCreateStatic(waThdOut_1, sizeof(waThdOut_1), NORMALPRIO - 1,
                    ThdOut_1, NULL);
  chThdCreateStatic(waThdOut_2, sizeof(waThdOut_2), NORMALPRIO - 2,
                    ThdOut_2, NULL);
  chThdCreateStatic(waThdOut_3, sizeof(waThdOut_2), NORMALPRIO - 3,
                    ThdOut_3, NULL);
  chThdCreateStatic(waThdOut_4, sizeof(waThdOut_4), NORMALPRIO - 4,
                    ThdOut_4, NULL);
  chThdCreateStatic(waThdOut_5, sizeof(waThdOut_5), NORMALPRIO - 5,
                    ThdOut_5, NULL);
  chThdCreateStatic(waThdOut_6, sizeof(waThdOut_6), NORMALPRIO - 6,
                    ThdOut_6, NULL);

  while (TRUE) {
    chThdSleepMilliseconds(250);
    stripes[0].RED_intensity = 40 ;
    stripes[0].GREEN_intensity = 0;
    stripes[0].BLUE_intensity = 100;

    stripes[1].RED_intensity = 0 ;
    stripes[1].GREEN_intensity++;
    stripes[1].BLUE_intensity = 0;


  }
  return (msg_t)0;
}



Re: A LED strip controller

Posted: Sun Sep 01, 2013 6:31 pm
by Tectu
RoccoMarco wrote:Now i need a remote to control some light games

Did someone say 'touchscreen'? :D

Also, could you link to those RGB stripes? I am still searching for some cheap stuff.


~ Tectu

Re: A LED strip controller

Posted: Sun Sep 01, 2013 9:18 pm
by RoccoMarco
the cheapest, you know me :) I hope this can't be considered spam
RGB led stripes (30 leds\m)

Right now i'm implementing a sketch with processing2 in order to control the system using serialoverusb. I have ordered a couple of IR receiver TSOP32238

Re: A LED strip controller

Posted: Tue Sep 03, 2013 2:13 pm
by RoccoMarco
Something new. This is the last work with LED, I promise. The next would be something more useful.

[youtube]C_2B0P5zvEY[/youtube]


Image
I have Implemented a "remote" for the RGB led stipes's controller already introduced using Processing2 and SerialOverUSB (The next step would be IR). The code is attached.


Image
This is circuit: substancially every channel is push-pull realized with bjt. According to BD140\BD139 datasheet every channel can supply 18W max (@ 12V) (If you need more collector current you have to change bjt). Every push-pull is controlled by a GPIO of the STM32F3 but the power is supplied by external power supply. You need 3 ch for every RGB led stip or a ch for a monocromatic. My code is not optimized. I have realized a software PWM in order to modulate led's intensity and I had to change system tick to use chThdSleepMicroseconds(), but it is possible to use TIM for a PWM avoiding this problem and reducing number of threads necessary to a proper functionality.

Re: A LED strip controller

Posted: Tue Sep 03, 2013 3:24 pm
by Eddie
RoccoMarco wrote:This is circuit: substancially every channel is push-pull realized with bjt. According to BD140\BD139 datasheet every channel can supply 18W max (@ 12V) (If you need more collector current you have to change bjt). Every push-pull is controlled by a GPIO of the STM32F3 but the power is supplied by external power supply. You need 3 ch for every RGB led stip or a ch for a monocromatic. My code is not optimized. I have realized a software PWM in order to modulate led's intensity and I had to change system tick to use chThdSleepMicroseconds(), but it is possible to use TIM for a PWM avoiding this problem and reducing number of threads necessary to a proper functionality.


This circuit schematic is bad! In logic 1 from STM32F3 the current flow from power source +12V to ground. PNP transistor is still open.
What is the temperature of the transistor at low brightness?

Re: A LED strip controller

Posted: Tue Sep 03, 2013 3:48 pm
by Giovanni
Shame on you Rocco :D

Giovanni

Re: A LED strip controller

Posted: Tue Sep 03, 2013 3:56 pm
by RoccoMarco
Giovanni wrote:Shame on you Rocco :D

Giovanni

my fault. :(

Re: A LED strip controller

Posted: Tue Sep 03, 2013 5:13 pm
by Tectu
How are we going to punish him, Giovanni? :twisted:


~ Tectu

Re: A LED strip controller

Posted: Tue Sep 03, 2013 6:34 pm
by RoccoMarco
@Giovanni, I'm leaving to atone my fault. I have to go... don't try to stop me! hahahaha holy shit, too much theory too few practical and I haven't spent enough time to think. However this stupid controller needs to translate my theory in pratical and to understand other things. So thanks Eddie for your feedback, I appreciate it so much. I'll post a better solution in the evening. @Tectu :mrgreen: