2

I am trying to make an RGB LED with Fan Controller for PCs. It is an Open Sourced project. But I want to implement RTOS using this implementation of it as a function in it, namely rollColor(), takes a lot of cycles.

The data the Arduino uses comes from the Serial. The Serial data has to wait until the function rollColor() completes. This function also has a delay and total runtime of this function is approximately 20 Seconds.

This is the original code, in which RTOS is not implemented: nonRTOS

Now I don't want to give a consecutive 20 seconds of execution time to a single function, but time slices would be good.

Now this falls under (RT)OS category and I would like to utilize this library but I seem to be unable to do that as there is not much documentation to begin with. The code I have come up with is this:

#include <Arduino_FreeRTOS.h>
#include <LCD.h>
#include <LiquidCrystal_SR.h>

#define FAN1 3
#define FAN2 5

#define LEDR 6
#define LEDG 9
#define LEDB 10

#define LCD_DT 14
#define LCD_CK 15
#define LCD_EN 16

#define E_FAN1 0
#define E_FAN1 1

#define SAMPLE 100

#define E_RGB_START 2
#define E_RGB_END 502

LiquidCrystal_SR lcd(LCD_DT, LCD_CK, LCD_EN);

int led[2][6];
int led_type = 0;
int led_bright = 0;
int fan[2] = {50, 50};
int load[3];
int temp[2];
int gradient[SAMPLE][3];

bool fchange = false;
bool lchange = false;

void TaskPrintLCD( void *pvParameters );
void TaskRGBCycle( void *pvParameters );
void TaskFanSpeed( void *pvParameters );

void setup() {
  Serial.begin(57600);
  xTaskCreate(
    TaskPrintLCD
    ,  (const portCHAR *)"Print_To_LCD"  // A name just for humans
    ,  128  // This stack size can be checked & adjusted by reading the Stack Highwater
    ,  NULL
    ,  2  // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,  NULL );
  xTaskCreate(
    TaskRGBCycle
    ,  (const portCHAR *)"Cycle_RGB_Colors"  // A name just for humans
    ,  128  // This stack size can be checked & adjusted by reading the Stack Highwater
    ,  NULL
    ,  3  // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,  NULL );
  xTaskCreate(
    TaskFanSpeed
    ,  (const portCHAR *)"Set_Fan_Speed"  // A name just for humans
    ,  128  // This stack size can be checked & adjusted by reading the Stack Highwater
    ,  NULL
    ,  1  // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,  NULL );
}

void loop() {

}

void TaskPrintLCD(void *pvParameters) {
  (void) pvParameters;
  Serial.println("LCD Settings...");
  lcd.begin(20, 4);
  for (;;) {
    printCPUUsage(load[0]);
    printGPUUsage(load[1]);
    printRAMUsage(load[2]);
    printTemps(temp[0], temp[1]);
  }
}

void TaskFanSpeed(void *pvParameters) {
  Serial.println("System Started...");
  Serial.println("Setting Pins...");
  pinMode(FAN1, OUTPUT);
  pinMode(FAN2, OUTPUT);
  (void) pvParameters;
  for (;;) {
    if (fchange) {
      Serial.println("SETTING FAN SPEED");
      int speed1 = ((fan[0] * 256) / 100 ) - 1;
      int speed2 = ((fan[1] * 256) / 100 ) - 1;
      fchange = false;
    }
  }
}

void TaskRGBCycle(void *pvParameters) {
  (void) pvParameters;
  pinMode(LEDR, OUTPUT);
  pinMode(LEDG, OUTPUT);
  pinMode(LEDB, OUTPUT);
  for (;;) {
    if (led_type == 1) {
      //ROLLCOLOR() FUNCTION START
      Serial.println("ROLLING GRADIENT START...");
      for (int i = 0; i < SAMPLE; i++) {
        analogWrite(LEDR, gradient[i][0]);
        analogWrite(LEDG, gradient[i][1]);
        analogWrite(LEDB, gradient[i][2]);
        vTaskDelay(100 / portTICK_PERIOD_MS);
      }
      for (int i = SAMPLE - 1; i >= 0; i--) {
        analogWrite(LEDR, gradient[i][0]);
        analogWrite(LEDG, gradient[i][1]);
        analogWrite(LEDB, gradient[i][2]);
        vTaskDelay(100 / portTICK_PERIOD_MS);
      }
      //ROLL COLOR FUNCTION END
      Serial.println("ROLLING GRADIENT END...");
    } else {
      analogWrite(LEDR, led_bright);
    }
  }
}

void serialEvent() {
  Serial.readStringUntil('*');
  while (String main = Serial.readStringUntil('>')) {
    Serial.println("IN WHILE");
    Serial.println(main);
    if (main == "") {
      break;
    }
    String data;
    if (main == "leds") {
      lchange = true;
      int type = Serial.readStringUntil(':').toInt();
      led_type = type;
      if (type == 1) {
        Serial.println("LED TYPE: " + led_type);
        for (int i = 0; i < 6; i++) {
          data = Serial.readStringUntil(',');
          Serial.println(data);
          if (i < 3) {
            led[0][i] = data.toInt();
          } else {
            led[1][i - 3] = data.toInt();
          }
          data = "";
        }
        generateGradient();
      } else {
        led_bright = Serial.readStringUntil(',').toInt();
      }
      Serial.readStringUntil(';');
    } else if (main == "fans") {
      fchange = true;
      for (int i = 0; i < 2; i++) {
        data = Serial.readStringUntil(',');
        fan[i] = data.toInt();
        data = "";
      }
      Serial.readStringUntil(';');
    } else if (main == "stat") {
      for (int i = 0; i < 2; i++) {
        data = Serial.readStringUntil(':');
        if (data == "load") {
          for (int j = 0; j < 3; j++) {
            data = Serial.readStringUntil(',');
            load[j] = data.toInt();
            data = "";
          }
          Serial.readStringUntil(';');
        } else if (data == "temp") {
          for (int j = 0; j < 2; j++) {
            data = Serial.readStringUntil(',');
            temp[j] = data.toInt();
            data = "";
          }
          Serial.readStringUntil(';');
        }
      }
    }
  }
}

void printCPUUsage(int usage) {
  int loc;
  int i;
  lcd.setCursor(0, 0);
  lcd.print("CPU% ");
  for (i = 1; i <= ceil(usage / 10); i++) {
    lcd.write(255);
  }
  for (i; i <= 10; i++) {
    lcd.print(" ");
  }
  lcd.print(" ");
  if (usage > 99) {
    lcd.print(usage);
  } else {
    lcd.print(" ");
    lcd.print(usage);
  }
  lcd.print("%");
}

void printGPUUsage(int usage) {
  int loc;
  int i;
  lcd.setCursor(0, 1);
  lcd.print("GPU% ");
  for (i = 1; i <= ceil(usage / 10); i++) {
    lcd.write(255);
  }
  for (i; i <= 10; i++) {
    lcd.print(" ");
  }
  lcd.print(" ");
  if (usage > 99) {
    lcd.print(usage);
  } else {
    lcd.print(" ");
    lcd.print(usage);
  }
  lcd.print("%");
}

void printRAMUsage(int usage) {
  int loc;
  int i;
  lcd.setCursor(0, 2);
  lcd.print("RAM% ");
  for (i = 1; i <= ceil(usage / 10); i++) {
    lcd.write(255);
  }
  for (i; i <= 10; i++) {
    lcd.print(" ");
  }
  lcd.print(" ");
  if (usage > 99) {
    lcd.print(usage);
  } else {
    lcd.print(" ");
    lcd.print(usage);
  }
  lcd.print("%");
}

void printTemps(int cputemp, int gputemp) {
  lcd.setCursor(0, 3);
  lcd.print("TEMP ");
  lcd.print("CPU ");
  if (cputemp < 100) {
    lcd.print(" ");
  }
  lcd.print(cputemp);
  lcd.print(" GPU ");
  if (gputemp < 100) {
    lcd.print(" ");
  }
  lcd.print(gputemp);
}

void generateGradient() {
  Serial.println("GENERATING GRADIENT...");
  float m[3];
  int r, g, b;
  m[0] = (led[1][0] - led[0][0]) / SAMPLE;
  m[1] = (led[1][1] - led[0][1]) / SAMPLE;
  m[2] = (led[1][2] - led[0][2]) / SAMPLE;
  for (int i = 0; i < SAMPLE; i++) {
    r = ceil(m[0] * i) + led[0][0];
    g = ceil(m[1] * i) + led[0][1];
    b = ceil(m[2] * i) + led[0][2];
    gradient[i][0] = r;
    gradient[i][1] = g;
    gradient[i][2] = b;
  }
  lchange = false;
  Serial.println("GRADIENT GENERATED...");
}

To me this code seems complete, but there is nothing from Arduino end, no LCD print nothing. I may be doing something wrong, but I don't know what, so please advice.

If you have any other better alternative please advise that too.

PS: I wrote this in two sittings so there might be something amiss so please feel free to edit or ask any questions for clarification.

3
  • 1
    Your printXXXusage functions could all be rolled into one function with an extra parameter in, this would mean you would only have to fix errors (if there are any) once. As to your problem it sounds like you should use interrupts and I don't know if you can do it with RTOS. Commented Jan 23, 2017 at 13:17
  • @Matt yeah... I can.. but i will do that once this time division is done. BTW there are 3 timers and all of them are being used for the PWM Signals so what interrupt can I use for time division or slices?
    – echo_salik
    Commented Jan 23, 2017 at 13:21
  • @Matt BTW forgot to mention, there are no errors in the nonRTOS code, only this implementation which I am not sure if I am implementing correctly.
    – echo_salik
    Commented Jan 23, 2017 at 18:16

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.