Contribute
Register

Kiwi's Next Project - iMac G5

Status
Not open for further replies.
Even when the NUC is off? Like a 5VSB?
Hi iCubeFan

Not sure I understand your question. If your are looking for a 5v standby from a nuc, yes this might be possible. Remember that those pins are designed to drive LEDs directly which require Resistors to limit current. So you may find you have limited current and a reduced voltage. Depending on your load it may or may not work.

If you have a digital voltmeter, measure the voltage under load.

Also note the Haswell NUC has a custom solutions header, with official 5v standby.

In my build I won't need it since the G5 ATX PSU has 5v standby.
 
Hi iCubeFan

Not sure I understand your question. If your are looking for a 5v standby from a nuc, yes this might be possible.

Hi Kiwi,

I read MacTester's comment about pin 2 and I thought It would be possible to use it for the Cube's power switch . However it doesn't seem to work.( White LED constantly glows when I plug the NUC to the Mains and the switch doesn't react to the finger touch).

Cheers
iCubeFan
 
Part 6 - iMac Fan Details

Here are some details of the 2 iMac G5 fans I will reuse.

Fans are variable voltage from about 3.3V to 12V. The voltage controls the speed, rather than PWM signal on PC Fans. Below 3.3 V fans would not have sufficient power to startup, but would continue to run if already spinning. These are similar to fans in PowerMac G5.

Here is another thread http://www.tonymacx86.com/powermac-g5/69889-info-g5-fans.html on the topic of G5 fans which provides some background.

My description is thus:
  • Speed V - Black/Grey - Voltage (high current) between 3.3V an 12V that powers the fan. The voltage determines the fan speed. Below 3.3V the fan will not start reliably
  • GND - Black - Self Explanatory
  • 12V - Brown - Provides 12V (low current) to power fan electronics.
  • Tach - Grey - Tachometer (not investigated)
There are two primary exhaust fans that will be reused, here are the pinouts. I will not reuse the intake fan, for that I will rely on the NUC fan.

iMac%20G5%20Fan%20Pinouts.png


I did some testing of the fans to see what power was needed, here is the result, and also some further diagrams of pinouts. Current goes up to 200ma at 9V, or 1.8watts. At this speed the fans are quite loud.

EDIT: Thanks to a post by Esterhernd I have realised that the colour of the SpeedV wire is Black/Grey, not Black as I have stated below.

iMac%20G5%20Fan%20Pinots%20and%20Power.png


More to follow...
 
Part 7 - Microcontroller

Introducing my Micro-controller, the Arduino. So sorry no PIC AXE here, but I hope by the end of this project you will see the reasons for my choice.


Basically it is very similar to PICAXE, it is a system on a chip with RAM, and flash storage, it has pins that provide Input and output, offers PWM and capitative input, it is programmed by USB, it has a single thread that executes a setup and loop routines.

It differs mainly in its C++ language, and form factor which has a surface mounted chip on a small PCB. The PCB has all the necessary discrete components mainly for power regulation, and crystal clock.

I choose this after careful consideration over PICAXE. Some of my factors were
  1. Capability - These chips seem to offer many inputs and outputs as standard, good amount of memory, etc. The C++ language offers much better level of functionality.
  2. Component Count - One Device will be all I need, Yes I know it is bigger that PICAXE
  3. USB - Has USB built in so don’t have to connect this up myself. I need USB to provide brightness control.
  4. Preference - As a SW developer going back to a Basic language seem like to much of a backward step to me. You will see some of the advantages of C++ latter on, e.g. Libraries and classes
  5. Open source & Community - With lots of contributed code and libraries for doing lots of stuff.
The model was chosen very specifically having the ATmega32U4 chip because of a behaviour it has (or rather doest have) regarding automatic reset. Most Arduino boards do a Reset when a serial connection is established, the ATmega32U4 doesn’t. You can read more in the following two links.

http://arduino.cc/en/Main/arduinoBoardLeonardo
http://arduino.cc/en/Guide/ArduinoLeonardoMicro?from=Guide.ArduinoLeonardo
Note: The Leonardo is the reference design for this chip

Here are the boards that I bought, the larger one is for development purposes, the smaller one will be the actual one I put in the G5.

Arduino%20Pics.jpg

More to follow...
 
Part 8a - Fan Control

To implement fan speed control I need to convert a PWM signal into a voltage. I found a circuit that uses an LM317 voltage regulator with PWM used to control output. The advantage of this is the LM317 is specifically designed for the purpose, so has all the protection built in, i.e. short circuit, temperature overload, current limiting, etc. I can also supply 1.5 amps which is more than enough for my purpose.

1024x768


Credit where credit is due, I found this circuit http://powerelectronics.com/thermal-management/voltage-regulators-rev-pwm-based-fan-control. The article goes into the theory of operation, you can read about it there.

The only addition to the circuit is the feedback of output voltage back to an input pin of my micro controller. You will see how this in the code implementation. I needed the two resisters to divide the voltage in half, so it falls within the 5V limit of the Arduino.

And the

Code:
#include <SimpleTimer.h>

// A general purpose timer, and some misc constants
SimpleTimer timer = SimpleTimer();

// Other Variables
float currentPWM = 150; // Roughly equal to 3.3v
float targetVOLT = 3.3; // current target voltage to match

// Pin Assignments
const int FAN_CONTROL_POUT = 5;
const int FAN_OUTPUT_V = 1;

void setup () {
  
  // setup pin outp
  pinMode(FAN_CONTROL_POUT,OUTPUT);
 
  // a timer that simulates reading a temp, and setting Voltage
  timer.setInterval(1000,voltageController);

  // setup a timer that runs every 20 ms - For Fan Speed
  timer.setInterval(20,fanCallback);
}

void loop () {

  // Let the timer run backgound tasks
  timer.run(); 
}

void voltageController() {

  // Simulates setting the voltage to a value
  // latter this will be based on reading a temperature
  targetVOLT = targetVOLT + 0.1;  
  if (targetVOLT>10.0) targetVOLT=3.3;
}

void fanCallback( ) {
  
  // read the current output voltage
  float currentVolt = readVoltage(FAN_OUTPUT_V) * 2.0;
  
  // compare it to target, and set new PWM
  if ( targetVOLT < currentVolt ) {
    currentPWM = currentPWM + 1;
  } else if ( targetVOLT > currentVolt ) {
    currentPWM = currentPWM - 1;
  }
  
  // write the PWM to the output port.
  analogWrite(FAN_CONTROL_POUT,currentPWM);
}

float readVoltage( int sensorPin ) {
  
 //get voltage reading from the input
 int reading = analogRead(sensorPin);  
 
 // converting that reading to voltage, for 3.3v arduino use 3.3
 return ( 5.0 * reading ) / 1023.0; 
}

Here are some explanations:
  • SimpleTimer - Is a contributed library that provides a way of setting up timers, a form of co-operative multitasking.
  • Setup - The setup routine is similar to init: on a PICAXE. The setInterval(T,F) call sets up a timer to run every T milliseconds, calling function F. I have two timers which I describe below
  • Loop - The main repeated loop of execution, similar to main: on the PICAXE. Here I just call SimpleTimer, allowing it to call my two methods as needed.
  • VoltageController - This is a simulation setting the target Voltage based on some input, in a full implementation this would probably be by reading a temperature sensor, in my example I just ramp the voltage.
  • FanCallback - This is the method that actually set the PWM output. It does this by adjusting the PWM value based on difference between the actual measured Voltage output and the target voltage. I only adjust the PWM by a value of 1 on each call, but because this method is called every 20ms it can quickly adjust the fan speeds, but also acts to dampen big changes in speed.

Here is a picture of it all wired up. You can see the G5 PSU used to provide the 12V input for the Fans. and BTW it worked first time.

Arduino%20Fan%20Speed%20Control.jpg


Thats it for the moment.

:)
 
+1 on that. This is one of the most accurately documented threads I've seen to date.


Wow!
 
Part 8b - Screen Brightness Control

Thanks for the comments guys. Here is the next small update

Got my screen brightness control working. It is done in two parts
  • A application running on the Mac provides a brightness slider control as a menu with a very similar appearance to the Volume Control menu. The app connects to the Arduino via serial interface and sends simple commands allowing the brightness to be adjusted, e.g. BW50 sets brightness to 50%.
  • The Arduino (code below) receives these commands and sets a PWM value on one of the output pins. I have connected it to a LED just as a demonstration. Clearly this will be connected to the LCD Inverter when complete.
The short youtube video shows it in action, you can see the breadboard with LED sitting on top of the monitor.

[video=youtube_share;5WEgXJ5NaZs]http://youtu.be/5WEgXJ5NaZs[/video]​

Code:
#include <SimpleTimer.h>

// A general purpose timer, and some misc constants
SimpleTimer timer = SimpleTimer();

//
// PIN ASSIGNMENTS
//

// Inverter Brigtness
const int INVERTER_POUT = 9; // PWM OUTPUT

// PWM Output Pin For Fan
const int FAN_CONTROL_POUT = 10; // PWM OUTPUT Fan Speed Control

void setup () {

  // setup and init EEPROM, on first invocation.
  setupDevice();

  // Setup Brightness Controller
  setupInverter();

  // Setup Serial command processor
  setupCommand();
}

void loop () {

  // serial ports for command processing
  loopCommand();
  
  // Let the timer run backgound tasks
  timer.run(); 
}

//
// DEVICE
//

/**
 * Setup the device if not initialised
 */
void setupDevice() {

  // Inverter Brigtness
  pinMode(INVERTER_POUT,OUTPUT);
}

//
// SCREEN BRIGHTNESS
//

int brightness = 0; // current brightne
boolean inverterActive = false;
const int BRIGHTNESS_INC = 10; // todo put this in eeprom

void setupInverter() {
  // get the inital brightness
  brightness = 50;
  
  // activeate the inverter
  activateInverter();
}

void activateInverter() {
  if (!inverterActive) {
    inverterActive = true;
    setInverterPWMBrightness();
  }
}

void deactivateInverter() {
  if (inverterActive) {
    inverterActive = false;
    setInverterPWMBrightness();
  }
}

void setBrightness(int bright) {
  brightness = bright;
  setInverterPWMBrightness();
}

int getBrightness() {
  return brightness;
}

int increaseBrightness() {
  setBrightness(brightness+BRIGHTNESS_INC);
  return getBrightness();
}

int decreaseBrightness() {
  setBrightness(brightness-BRIGHTNESS_INC);
  return getBrightness();
}

// Internally called function
void setInverterPWMBrightness() {
  if (inverterActive) {
    analogWrite(INVERTER_POUT,brightness);
  } else {
    analogWrite(INVERTER_POUT,0);
  }
}

//
// USB SERIAL CONTROL
//

static const char CR = 13;
static const char LF = 10;

// String input from command prompt
// static String command = String(""); 

void setupCommand() {

  //Initialize serial:
  Serial.begin(9600); 
}

void loopCommand() {

  static char serData[32]; // Buffer 
  static int count = 0;

  // if serial port not ready (Leonardo only).
  // dont try to process commands
  if(!Serial) return; 

  while(Serial.available() > 0) {

    // read a byte. and add to the buffer
    char inByte = Serial.read();
    
    // if th read failed
    if (inByte == -1) {
      break;
    
    // if EOL
    } else if ( inByte == CR || inByte == LF ) {
      
      // terminate the buffer
      serData[count++]=0;

      //Convert The array to a String
      String command = String(serData);
      
      // process the command
      processCommand(command);
      
      // clear the command buffer
      count=0;
    
    // protect against overrun of buffer
    } else if (count<30) {  
      serData[count++]=inByte;
    }  
  }
}

/**
 * Brightness increase BI  
 * Brightness decrease BD
 * READ BRIGness BR -> (000-255)
 * WRITE Brightness BW(000-255)
 */
void processCommand(String cmd) {
  
    
  String subCmd = cmd.substring(0,2);
  String extraCmd = cmd.substring(2);
  
  if (subCmd.equals("BI")) {
    Serial.println( increaseBrightness() );
    
  } else if (subCmd.equals("BD")) {
    Serial.println( decreaseBrightness() );
    
  } else if (subCmd.equals("BR")) {
    Serial.println( getBrightness() );
    
  } else if (subCmd.equals("BW")) {
    setBrightness( extraCmd.toInt() );
  }
}
// END

Happy Hacking

Kiwi
 
Wow, this looks very good, bravo! :clap:

Did you write the OS X app in Xcode?

Question: are the arduino microcontrollers "multitasking-able"? The picaxe devices aren't and this can be very laborious, because every usage of a time stops the whole program.

MacTester
 
Wow, this looks very good, bravo! :clap:

Did you write the OS X app in Xcode?

Question: are the arduino microcontrollers "multitasking-able"? The picaxe devices aren't and this can be very laborious, because every usage of a time stops the whole program.

MacTester
Yes the OS X app was written in Xcode. I did have some help though, my code was based on the following, that actually does brightness on a real Mac laptop.

http://www.alecjacobson.com/weblog/?p=1127

Answer: No in the modern sense, there are no Threads, a call to delay() will still halt everything else. But YES you can "simulate multitasking", here is the basic principle.

http://arduino.cc/en/Tutorial/BlinkWithoutDelay

This approach is called co-operative multitasking, and what early operating systems (<Win95 <OSX) used. The SimpleTimer library is an implementation of this. Using this library I still can't call delay(), but don't need to.

http://playground.arduino.cc/Code/SimpleTimer
 
Status
Not open for further replies.
Back
Top