Advice on sketch to sequence LEDs from HDD activity

Post here about your Arduino projects, get help - for Adafruit customers!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
twizted
 
Posts: 69
Joined: Tue Apr 28, 2009 3:35 pm

Advice on sketch to sequence LEDs from HDD activity

Post by twizted »

So, I'm working on a project for a friend and I've got the electronics part built and I've got the code that I thought would work fine and, for the most part it does...

The problem is that I'm not happy with the output and I'm just having some trouble wrapping my brain around the problem in such a way that I may come up with a good solution.

Basically the idea is for this to illuminate 32 LEDs in a sequence based on hard drive activity. Before someone says it, yes I realize the arduino is somewhat overkill for this basic part of the project but I also have other plans that involve serial communication with the PC in a possible future version. For now, this is all it does.

The reason I am not happy with the output is basically it does not really move from flickering the first LED in the display unless there is major drive activity like copying a file. Even watching a HD movie only flickers maybe the first two or three if I'm lucky. I'm sure there is a better way to achieve a better display but I'm just not seeing it.

Below I have included my sketch. I've commented everything I believe so you will know whats going on at each point...
It is probably not perfect but it works :)

Code: Select all

// Include Wire.h for I2C to the MCP23017
#include <Wire.h>
// Include Adafruit library for MCP23017
#include "Adafruit_MCP23017.h"

// Make object array for MCP23017's
Adafruit_MCP23017 mcpArray[2];

// HDD activity line  
int hddPin = 3;
// Start the LED scale at 100%
int activity = 32;

void setup() {  
  // Initialize the MCP23017's in the array
  mcpArray[0].begin(0);
  mcpArray[1].begin(1);

  // Start serial for debugging
  Serial.begin(9600);  
  
  // Set pinMode for ATmega328
  pinMode(hddPin, INPUT);
  pinMode(13, OUTPUT);

  // Set pinMode and illuminate LED for each MCP23017 
  for (int thisPin = 0; thisPin < 17; thisPin++)  {
    mcpArray[0].pinMode(thisPin, OUTPUT);
    mcpArray[0].digitalWrite((thisPin & 0x0F), HIGH);
    delay(10);
  }
  for (int thisPin = 0; thisPin < 17; thisPin++)  {
    mcpArray[1].pinMode(thisPin, OUTPUT);
    mcpArray[1].digitalWrite((thisPin & 0x0F), HIGH);
    delay(10);
  }
  
  // Simple serial output to indicate the void loop
  // is about to start and hold the LEDs HIGH for 5 seconds
  Serial.println("Program will start in 5 seconds...");
  delay(1000);
  Serial.println("4...");
  delay(1000);
  Serial.println("3...");
  delay(1000);
  Serial.println("2...");
  delay(1000);
  Serial.println("1...");
  delay(1000);
  Serial.println("STARTING Program!!");
}


void loop() {
  
  // while loop to sequence LEDs from 0 to 31 while
  // there is hard drive activity present and the 
  // activity is below 32
  while(digitalRead(hddPin)==0 && activity < 32){
    // Activate pin 13 (onboard LED) for debugging
    digitalWrite(13, HIGH);
    // Step activity variable +1 per loop
    activity++;
    // Activate pins 1 thru 16 of each MCP23017 
    // sequentially cascading from IC1 to IC2 respectively 
    mcpArray[activity>>4].digitalWrite((activity & 0x0F), HIGH);
    // IF statement to ramp up the speed of the loop
    // the closer it gets to being 100%
    if(activity > -1 && activity < 12){
      delay(30);
    }else if(activity > 12 && activity < 26){
      delay(15);
    } else {
      delay(10);
    }
    // Output to serial for debugging
    Serial.println(activity);
  }

  // while loop to sequence LEDs from 31 to 0 while
  // there is hard drive activity present and the 
  // activity is greater -1
  while(digitalRead(hddPin)==1 && activity > -1){
    // Deactivate pin 13 (onboard LED) for debugging
    digitalWrite(13, LOW);
    // Deactivate pins 16 thru 1 of each MCP23017 
    // sequentially cascading from IC2 to IC1 respectively
    mcpArray[activity>>4].digitalWrite((activity & 0x0F), LOW);
    // Short delay between each LED turning off
    delay(50);
    // Step activity variable -1 per loop
    activity--;
    // Output to serial for debugging
    Serial.println(activity);
  }
}
Anyway, advice on how to make this work better would be great...

I've also attached two photos of the device... yes, its suppose to resemble a tachometer :)
Attachments
2012-05-29-19.11.jpg
2012-05-29-19.11.jpg (115.15 KiB) Viewed 1871 times
2012-05-22-19.53.jpg
2012-05-22-19.53.jpg (134.93 KiB) Viewed 1871 times

User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

Re: Advice on sketch to sequence LEDs from HDD activity

Post by adafruit_support_bill »

decrease the delays in your loop.

User avatar
philba
 
Posts: 387
Joined: Mon Dec 19, 2011 6:59 pm

Re: Advice on sketch to sequence LEDs from HDD activity

Post by philba »

So, basically, you are looking at an input pin to determine HDD activity level. If the HDD pin is "flickering", you might be having sampling problems. Your approach of having 2 serial loops, one up and one down seems like it will be hard to get good results.

I think you want 2 parallel processes going on: one continuously records HDD activity and the other periodically updates the led display. I would use an interrupt handler to determine the ratio of on to off time on a continuous basis (say for each 200 mS interval) and save it in a variable. The main loop would look at this variable every 200 mS (or what ever period works) and adjust the LED display. I would figure out what the max value would be and normalize your display for that.

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Advice on sketch to sequence LEDs from HDD activity

Post by adafruit_support_rick »

The reason I am not happy with the output is basically it does not really move from flickering the first LED in the display unless there is major drive activity like copying a file. Even watching a HD movie only flickers maybe the first two or three if I'm lucky. I'm sure there is a better way to achieve a better display but I'm just not seeing it.
Actually, that's pretty much what I would expect to see. Disk drives really shouldn't be all that busy, even when streaming a movie.

I think what may be compounding your problem is your method for sampling disk activity. I'm not sure what hddpin is measuring, but, whatever it is, it's going to be happening a lot faster than your loop is going to be cycling. You've got delays, digitalWrites, array accesses, Serial.print - all that stuff takes time, and so it could easily be that you're only counting <wild_guess>maybe 10%</wild_guess> of the disk activity.

I think maybe you haven't really defined what it is you're measuring. I'll guess that you want to be measuring time, but that's not really what your code is doing, because it's trying to do all those other things simultaneously.

If I was going to do this, I would think about using the Input Capture feature of digital pin 8. Basically, you connect your hdd signal to pin 8, configure pin 8 as an input, and set up Timer 1 to start ticking. Whenever an edge transition occurs on pin 8 - high-to-low or low-to-high, Timer 1 will save its current count in a register, reset to zero, and give you an interrupt. The ATmega328 data sheet has more details about how to set up input capture.

By looking at the count, you can know exactly how long the activity on pin 8 lasted. You can put together a direct measure of the hddpin duty cycle.

Next, I think about some sort of running average to smooth out the hddpin readings into a more human time-scale. A good way to do this is to just keep track of your maximum reading. You'll be updating your LEDs at regular intervals according to your MAX value. Each time you update the LEDs, decrement MAX a little bit. In the absence of disk activity, MAX will slowly decay down to zero (maybe over the duration of a second). When new activity comes in, compare it with MAX and keep the larger number.

You might also get a more dramatic-looking display by scaling your LED readout logarithmically, rather than linearly. Low levels of disk activity will deflect your meter proportionally more than high levels.

If you're not ready to get into the Input Capture stuff, you might still want to set up a plain old timer interrupt. You could easily handle timer interrupts at 5 kHz or more. The interrupt service routine samples hddpin, and can be very simple. Something like this might work for you:

Code: Select all

uint8_t activity = 0;
ISR(xxx_VECT)
{
   if ((digitalRead(hddPin)) && (activity < 31)){
       activity = (activity + 1) & ;
   }
   else if (activity > 0) {
      activity--;
   }
}
(warning: don't change the value of 'activity' anyplace else!)

User avatar
twizted
 
Posts: 69
Joined: Tue Apr 28, 2009 3:35 pm

Re: Advice on sketch to sequence LEDs from HDD activity

Post by twizted »

Sorry I should have said in the first post that the signal I am reading from the HDD output of the motherboard is an active-low output tied to pin 3 which is being pulled high via a 10K resistor.

I'm trying to follow what you said Driver but I'm not sure I'm following... I will try to integrate that snippet into my code later today when I get back home but I've never used interrupts before so this is completely new ground for me.

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Advice on sketch to sequence LEDs from HDD activity

Post by adafruit_support_rick »

The bottom line is that you want to measure the duty cycle of your hdd pin independently of managing your LEDs. As soon as you try to mix the two operations, you will skew your hdd activity measurements.

The thing that makes microcontrollers different from regular computers is that mcu's have all sorts of built-in features that allow them to do more than one thing at a time. Once you embrace that idea, you can really make these things sing. The major feature of mcu's are timers, and the AVR timers are marvelous, powerful things.

The arduino environment is kind of a bridge between regular programming and mcu programming. It gives you easy access to the I/O features, but it doesn't take you all the way. It still encourages you to program in a linear, sequential manner. To get the most out of an mcu, you have to think in parallel, to try to identify operations that can be performed independently, simultaneously, and preferably in hardware.

In your task, thinking in parallel leads to the realization that monitoring the hdd and managing the LEDs are two independent processes. One process produces a number representing duty-cycle, and the other process turns that number into a pattern of LEDs. Either of them should be able to run happily without knowing or caring anything about what the other is doing.

Rule of thumb in mcu programming: if you see "delay(nnnn);" in your code, you are probably doing something wrong.

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Advice on sketch to sequence LEDs from HDD activity

Post by adafruit_support_mike »

First of all, that's a nice build. Congrats. I don't recognize the laminate though. What are you using?

WRT the code, the conditions that drive your while() loops are kind of arcane.. the combination of delays, hdd pin values, and 'activity' variable values looks hard to predict.

Personally, I'd reduce 'activity' to a simple counter:

Code: Select all

void loop () {
    if (digitalRead( hddPin )) {
        activity = (activity <= 31) ? activity + 1 : 31;
    } else {
        activity = (activity >= 0) ? activity + 1 : 0;
    }
    
    int i;
    for (i=0 ; i <= activity ; i++) {
        //  send these LEDs HIGH
    }
    for (i=activity+1 ; i < 32 ; i++) {
        //  send these LEDs LOW
    }
    delay(50);
}
It'll increase as long as hddPin stays high, and decrease as long as hddPin is low. In effect, it integrates the last 32 values of hddPin that it's seen.

You can play with the way you read the input, modify the activity level, or map activity levels to the LEDs, but that will all fit in the general framework above.

User avatar
twizted
 
Posts: 69
Joined: Tue Apr 28, 2009 3:35 pm

Re: Advice on sketch to sequence LEDs from HDD activity

Post by twizted »

Ugh... I'm still not seeing it... I've tried integrating both solutions but given my limited knowledge of interrupts and concurrent threads with arduino I'm not having much luck...

User avatar
philba
 
Posts: 387
Joined: Mon Dec 19, 2011 6:59 pm

Re: Advice on sketch to sequence LEDs from HDD activity

Post by philba »

do you have access to a logic analyzer? I'd get a trace of the state of the hdd pin for various scenarios. The traces will show you what you need to measure. It's possible that the duty cycle of the signal is really low. Instead of measuring time on vs time off, I would try counting pulses in a specific period.

You don't necessarily need to use interrupts but they make the problem much easier to handle. Doing it without interrupts means that you will need to loop really fast checking the hdd pin. So loop with no delay looking for transitions on the hdd pin. Your loop for counting pulses would look somthing like this:

Code: Select all

setup(){
    nexttime = millis()+sampleperiod;
    pulsecount = 0;
}
loop() (
    hdd_pinvalue = digitalread(hdd_pin);
    if(hdd_pinvalue != hdd_previous) pulsecount++;
    hdd_previous = hdd_pinvalue;
    if(millis()> nexttime) {
        nexttime = millis()+sampleperiod;
        display(pulsecount);
        pulsecount = 0;
    }
}
This is easy enough to modify to count time on or time off. Note that the code double counts pulses but that's easy enough to handle in the display code. Moving the code that displays the count on the LEDs to a separate routine will help you better understand your program structure and allow you to unit test the display code. Also, you will lose pulses when you are off displaying the count.

Now, about interrupts. Look at this page, your code would be only slightly more complex. http://arduino.cc/en/Reference/AttachInterrupt

User avatar
twizted
 
Posts: 69
Joined: Tue Apr 28, 2009 3:35 pm

Re: Advice on sketch to sequence LEDs from HDD activity

Post by twizted »

@[email protected] - I used some standard cheap single sided PC Board from allelectronics.com which was white (if not a little off white) and I dyed it using standard Rit fabric dye from Walmart

Anyway, as for the project... I've abandoned the HDD activity aspect of it in lieu of the difficulty in catching any useful data from the hard drive activity header on the motherboard. I have instead opted to just use my FTDI programming breakout as a permanent fixture on the unit to provide both power and a serial connection and I've modified a sketch to send data to the unit from LCD Smartie with CPU usage/load to be displayed. I'm going to make a video in a bit to post on youtube which I will link back here for you to check out if you wish. Thank you all for the information and help.

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Advice on sketch to sequence LEDs from HDD activity

Post by adafruit_support_mike »

Twizted wrote:@[email protected] - I used some standard cheap single sided PC Board from allelectronics.com which was white (if not a little off white) and I dyed it using standard Rit fabric dye from Walmart
Neat trick. I plan to steal that shamelessly in future projects. ;-)

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Advice on sketch to sequence LEDs from HDD activity

Post by adafruit_support_rick »

Twizted wrote:I've abandoned the HDD activity aspect of it in lieu of the difficulty in catching any useful data from the hard drive activity header on the motherboard.
Ah. Too bad. I had some ideas about that….

User avatar
twizted
 
Posts: 69
Joined: Tue Apr 28, 2009 3:35 pm

Re: Advice on sketch to sequence LEDs from HDD activity

Post by twizted »

feel free... I read about it long ago... There are several tutorials out there now for it... http://goo.gl/tucp6

I've used this method for several PCBs I've made in the past including PCBs I had manufactured with solder mask...
I've attached a pic of the back of one since I still had some laying around :)
Attachments
2012-06-05 18.01.45.jpg
2012-06-05 18.01.45.jpg (106.51 KiB) Viewed 1785 times

User avatar
twizted
 
Posts: 69
Joined: Tue Apr 28, 2009 3:35 pm

Re: Advice on sketch to sequence LEDs from HDD activity

Post by twizted »

driverblock wrote:
Twizted wrote:I've abandoned the HDD activity aspect of it in lieu of the difficulty in catching any useful data from the hard drive activity header on the motherboard.
Ah. Too bad. I had some ideas about that….
Sorry :(

I just had to get it working for the project asap and he had mentioned CPU usage as so I went with that instead... I am still interested in the hard drive activity aspect of it but I am going to have to make another board.. Although, I am going to make it using SMT parts this time and probably include several breakout headers for more pins of the ATmega328

User avatar
cstratton
 
Posts: 294
Joined: Wed Sep 29, 2010 3:52 pm

Re: Advice on sketch to sequence LEDs from HDD activity

Post by cstratton »

I think the comments about perhaps expecting more HDD activity than there really is may be spot on. If the drive manages to do what is needed with an extremely intense but extremely short burst of activity every few seconds, how do you want to display that? Even if you manage to detect it, is "stretching" it to a more human timescale appropriate? Any read-ahead buffering (at least any at the OS level) is going to limit what you get to see here, too.

An experiment you might try would be to write a temporary sketch which is a pulse-width timer. Basically, every time the activity line goes active, start a timer, then when it stops measure the difference. Dump this out the serial channel to a PC which is logging, pull the values into a spreadsheet or something and make a nice histogram. See if there is data that is useful for you idea - or as you may unfortunately find, not really.

Another thing you might try is using either this metering sketch or your existing code during a more intense operation - say dd the raw device file to /dev/zero, run a backup, or play a movie from an uncompressed file.

Another approach would be to collect your data by instrumenting some internal part of the operating system kernel, and just pushing a value through the serial channel to the arduino to indicate what it should display on its "tachometer". This would handle the buffering case better, and might let you do things like implement a logarithmic scale as well as weighting / relaxing over time.

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino”