Monday, November 26, 2012

PCB - 3 Channel PWM LED Driver

I have been working for sometime on my LED drivers to enable me to have independent control of the 30 x 3W LEDs required to create various lighting effects for my aquarium lighting fixture.

Credit where its due, the design of this board is thanks to Magpie, my electronics knowledge is no where good enough to pull something this complicated off. I have spent a fair bit of time playing with the layout, learning how to use KiCad, understanding the circuit and selecting the correct parts for the board.

The board design has to address certain issues inherent with using PWM and the attributed noise it creates. To help combat this the board is laid out in a way that minimises track length between certain components and the use of what is known as Kelvin connections. The Kelvin connections are used to accurately measure current against the ground to get accurate readings.

The problem that can occur from poor design and layout (which I am yet to have any proof of until I test a board) are EM interference with other devises, flicker and inefficient power usage.

This board uses a micro with c code to very quickly take current readings and adjust the output value in order to maintain a stable and reliable output.

My first attempt is currently in production with Seeed so I expect to get my boards in the next few weeks. I have just ordered an Atten 858D+ rework station and am in the processes of ordering my components with digikey.

Here is a 3d view of the board design, the boards have 3 channels, each capable of supporting 1 3W Led and I will be using 10 of these boards.


Tuesday, October 23, 2012

Washing Up



Here's a little mix I did whilst I was meant to be washing up.

Enjoy!

Sunday, September 2, 2012

Netduino - Optocoupler testing

I have finally had chance to spend a few minutes on the last part of my relay control board, this part demonstrates the use of an optocoupler along with PWM to control a 12 volt LED. My next test will be to use this circuit with a computer fan in order to provide the fan control for my relay enclosure.

This circuit is very straight forward, it uses a 4N35M octocoupler, an LED and 2 resistors. There is a 1k resistor between the digital out of the netduino and pin 1 on the octo and another to match the LED. I am using a 12 volt 1 amp power supply in this example.



using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

namespace CIRC_08
{
public class Program
{
static PWM pwm = new PWM(Pins.GPIO_PIN_D5);

public static void Main()
{
while (true)
{
for (int sensorValue = 1; sensorValue < 101; sensorValue++) { Debug.Print(sensorValue.ToString()); pwm.SetDutyCycle((uint)sensorValue); Thread.Sleep(100); } for (int sensorValue = 100; sensorValue > 2; sensorValue--)
{
Debug.Print(sensorValue.ToString());
pwm.SetDutyCycle((uint)sensorValue);
Thread.Sleep(100);
}

pwm.SetDutyCycle(0);
Thread.Sleep(10000);
}
}

}
}

Tuesday, June 26, 2012

Netduino - Update Relay Control Board Mock-Up

I have finally managed to get my relay control board prototype working. What this allows me to do is control the relays with 12 volts and also to light a 12v LED to display which relays are on.

I am currently using a 74HC595 to provide the control logic to switch the transistors on and off. The next stage is to control the fans using PWM, I also need to add a DS18B20 that will connect in to my 1-wire bus. The temperature sensor will be used to control the speed of the fans, I may in fact used 2 temperature sensors to control the 2 fans independently for each of the heat sinks.

As I now have a Netduino GO I am working towards modularising my main aquarium control board. The first thing I want to modularise is this control board so it will work with the GO bus. I am hoping that the STM8 will provide enough IO to control the transistors and also PWM for the 2 fans. It would also be amazing if there was a spare serial port so I can create a 1-wire bus on the same board, but I have a fair bit of learning to do before I can get started with the STM8S103F2P6 chips I've got.

Here is a little video showing the shift registers switching the transistors on and off that control the LEDs.


Sunday, June 24, 2012

Alpha Numeric Counter

Hi,

Here is a little Alpha numeric counter I have written that will either continue counting or will return the next value.


public string AlphaNum(string val)
        {
            StringBuilder sb = new StringBuilder(val);
            bool incNext = false;
            for (int n = sb.Length; n > 0; n--)
            {
                if (n == sb.Length || incNext)
                {
                    char nextChar;
                    char letter = Convert.ToChar(sb.ToString(n - 1, 1));
                    if (letter == '9')
                    {
                        incNext = true;
                        nextChar = 'A';
                    }
                    else if (letter == 'Z')
                    {
                        if (n - 2 > -1)
                        {
                            if (sb.ToString(n - 2, 1) != "Z")
                            {
                                incNext = true;
                                nextChar = '0';
                            }
                            else
                            {
                                incNext = true;
                                nextChar = 'Z';
                            }
                        }
                        else
                        {
                            incNext = true;
                            nextChar = 'Z';
                        }
                    }
                    else
                    {
                        nextChar = (char)(((int)letter) + 1);
                        incNext = false;
                    }
                    sb.Remove(n - 1, 1).Insert(n - 1, nextChar.ToString());
                }
            }
            return sb.ToString();
        }

Thursday, April 12, 2012

Netduino - Quick update...

I am still testing my aquarium control board, I have found a ground issue that is affecting the shift registers and in turn the TLC5940s. This is something that may take a while to solve and probably a lot of continuity testing and a bit of solder work.

My overall testing is going well at the moment, I have my shift register fully tested and working, bar the above ground issue. The realtime clock is working thanks to a little help from Stefan. Nevyn has lent my an oscilloscope while I find one, this has been great as I have started to learn how to use a scope and how to interpret the results which will be helpful for when I get one. The scope was a necessity in order to test the oscillator circuit and the TLCs PWM output. So far I have managed to find a few faults in the soldering of the oscillator and TLC circuits, I now have a square wave coming out of the oscilator, a saw tooth on the BLANK signal (which may need looking at) and I have managed to get an LED to light on the TLCs. Sadly this doesn't round of the testing of the TLCs and oscillator as the LED was kind of strobing along to the "Breath" code rather than smoothly diming in and out with a constant light. Again this may be related to the ground issue, but I have a feeling I need to further test the clock and BLANK signals.

BREAKING NEWS!!!

I have just ordered the new Netduino Go, the shield base and the touch screen display from Nwazet.

Can't wait!

Wednesday, March 28, 2012

Netduino - Prototype testing

This is just a quick update...

I am currently going through testing each part of my main control board to make sure it all works together. Hopefully all is well, but to make perfectly sure, despite some of my testing before I finished soldering everything up, I am going through every component again.

During the build I did a lot of continuity testing to make sure there were no broken tracks or joins that shouldn't exist. Powering the entire board didn't result in anything dramatic like smoke or fire, so I'm taking that as a good thing.

The main elements of the board to test in the initial phase are:

RTC
Shift Registers
TLCs

This covers the main functions and until all are working with code there’s no point moving on to the rest. I have most recently been trying out the TLC5940s for the first time. On first test with Nevyn's sample code nothing happened, on further investigation I remember that I delegated some of the logic for BLANK and VPRG to the multiplexed GPIOs, provided by the 74HC595s. I did a little bit of code reworking to incorporate Stefan's MultiSPI library and his shift register libraries and tried again. Unfortunately the code still failed and I think it is to do with the way I am trying to call the logic pins provided by the 595's. I will update further on this once I work out what is going wrong.

So far that’s 2 fails out of the 3, however thanks to some help from Stefan and no thanks to some confusion whilst soldering, I got the RTC back up and running.

Here is some sample code based on Fabien’s RTC library:


using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
using netduino.helpers.Hardware;

namespace RTC
{
public class Program
{
public static void Main()
{
var clock = new DS1307();
DateTime CurrTime = DateTime.Now;
// Set the clock to some arbitrary date / time
clock.Set(CurrTime);

// Make sure the clock is running
clock.Halt(false);
while(true)
{
// Test reading RTC clock registers
Debug.Print(clock.Get().ToString());
Thread.Sleep(1000);
}

}
}
}




using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

namespace netduino.helpers.Hardware {
///


/// This class implements a complete driver for the Dallas Semiconductors / Maxim DS1307 I2C real-time clock: http://pdfserv.maxim-ic.com/en/ds/DS1307.pdf
///

public class DS1307 : IDisposable
{
[Flags]
// Defines the frequency of the signal on the SQW interrupt pin on the clock when enabled
public enum SQWFreq { SQW_1Hz, SQW_4kHz, SQW_8kHz, SQW_32kHz, SQW_OFF };

[Flags]
// Defines the logic level on the SQW pin when the frequency is disabled
public enum SQWDisabledOutputControl { Zero, One };

// Real time clock I2C address
public const int DS1307_I2C_ADDRESS = 0x68;
// I2C bus frequency for the clock
public const int DS1307_I2C_CLOCK_RATE_KHZ = 100;

// Allow 10ms timeouts on all I2C transactions
public const int DS1307_I2C_TRANSACTION_TIMEOUT_MS = 10;

// Start / End addresses of the date/time registers
public const byte DS1307_RTC_START_ADDRESS = 0x00;
public const byte DS1307_RTC_END_ADDRESS = 0x06;

// Square wave frequency generator register address
public const byte DS1307_SQUARE_WAVE_CTRL_REGISTER_ADDRESS = 0x07;

// Start / End addresses of the user RAM registers
public const byte DS1307_RAM_START_ADDRESS = 0x08;
public const byte DS1307_RAM_END_ADDRESS = 0x3f;

// Total size of the user RAM block
public const byte DS1307_RAM_SIZE = 56;

// Instance of the I2C clock
I2CDevice clock;

public DS1307() {
clock = new I2CDevice(new I2CDevice.Configuration(DS1307_I2C_ADDRESS, DS1307_I2C_CLOCK_RATE_KHZ));
}

///


/// Gets the date / time in 24 hour format.
///

/// A DateTime object
public DateTime Get() {
byte[] clockData = new byte [7];

// Read time registers (7 bytes from DS1307_RTC_START_ADDRESS)
var transaction = new I2CDevice.I2CTransaction[] {
I2CDevice.CreateWriteTransaction(new byte[] {DS1307_RTC_START_ADDRESS}),
I2CDevice.CreateReadTransaction(clockData)
};

if (clock.Execute(transaction, DS1307_I2C_TRANSACTION_TIMEOUT_MS) == 0) {
throw new Exception("I2C transaction failed");
}

Debug.Print(clockData[4].ToString() + "/" + clockData[5].ToString() + "/" + clockData[4].ToString());

return new DateTime(
BcdToDec(clockData[6]) + 2000, // year
BcdToDec(clockData[5]), // month
BcdToDec(clockData[4]), // day
BcdToDec(clockData[2] & 0x3f), // hours over 24 hours
BcdToDec(clockData[1]), // minutes
BcdToDec(clockData[0] & 0x7f) // seconds
);
}

///


/// Sets the time on the clock using the datetime object. Milliseconds are not used.
///

///
A DateTime object used to set the clockpublic void Set(DateTime dt) {
var transaction = new I2CDevice.I2CWriteTransaction[] {
I2CDevice.CreateWriteTransaction(new byte[] {
DS1307_RTC_START_ADDRESS,
DecToBcd(dt.Second),
DecToBcd(dt.Minute),
DecToBcd(dt.Hour),
DecToBcd((int)dt.DayOfWeek),
DecToBcd(dt.Day),
DecToBcd(dt.Month),
DecToBcd(dt.Year - 2000)} )
};

if (clock.Execute(transaction, DS1307_I2C_TRANSACTION_TIMEOUT_MS) == 0) {
throw new Exception("I2C write transaction failed");
}
}

///


/// Enables / Disables the square wave generation function of the clock.
/// Requires a pull-up resistor on the clock's SQW pin.
///

///
Desired frequency or disabled///
Logical level of output pin when the frequency is disabled (zero by default)public void SetSquareWave(SQWFreq Freq, SQWDisabledOutputControl OutCtrl = SQWDisabledOutputControl.Zero)
{
byte SqwCtrlReg = (byte) OutCtrl;

SqwCtrlReg <<= 3; // bit 7 defines the square wave output level when disabled // bit 6 & 5 are unused if (Freq != SQWFreq.SQW_OFF) { SqwCtrlReg |= 1; } SqwCtrlReg <<= 4; // bit 4 defines if the oscillator generating the square wave frequency is on or off. // bit 3 & 2 are unused SqwCtrlReg |= (byte) Freq; // bit 1 & 0 define the frequency of the square wave WriteRegister(DS1307_SQUARE_WAVE_CTRL_REGISTER_ADDRESS, SqwCtrlReg); } ///


/// Halts / Resumes the time-keeping function on the clock.
/// Calling this function preserves the value of the seconds register.
///

///
True: halt, False: resumepublic void Halt(bool halt) {
var seconds = this[DS1307_RTC_START_ADDRESS];

if (halt) {
seconds |= 0x80; // Set bit 7
}
else {
seconds &= 0x7f; // Reset bit 7
}

WriteRegister(DS1307_RTC_START_ADDRESS, seconds);
}

///


/// Writes to the clock's user RAM registers as a block
///

///
A byte buffer of size DS1307_RAM_SIZEpublic void SetRAM(byte[] buffer) {
if (buffer.Length != DS1307_RAM_SIZE) {
throw new ArgumentOutOfRangeException("Invalid buffer length");
}

// Allocate a new buffer large enough to include the RAM start address byte and the payload
var TrxBuffer = new byte[sizeof(byte) /*Address byte*/ + DS1307_RAM_SIZE];

// Set the RAM start address
TrxBuffer[0] = DS1307_RAM_START_ADDRESS;

// Copy the user buffer after the address
buffer.CopyTo(TrxBuffer, 1);

// Write to the clock's RAM
var transaction = new I2CDevice.I2CWriteTransaction[] {I2CDevice.CreateWriteTransaction(TrxBuffer)};

if (clock.Execute(transaction, DS1307_I2C_TRANSACTION_TIMEOUT_MS) == 0) {
throw new Exception("I2C write transaction failed");
}
}

///


/// Reads the clock's user RAM registers as a block.
///

/// A byte array of size DS1307_RAM_SIZE containing the user RAM data
public byte[] GetRAM() {
var ram = new byte[DS1307_RAM_SIZE];

var transaction = new I2CDevice.I2CTransaction[] {
I2CDevice.CreateWriteTransaction(new byte[] {DS1307_RAM_START_ADDRESS}),
I2CDevice.CreateReadTransaction(ram)
};

if (clock.Execute(transaction, DS1307_I2C_TRANSACTION_TIMEOUT_MS) == 0) {
throw new Exception("I2C transaction failed");
}

return ram;
}

///


/// Reads an arbitrary RTC or RAM register
///

///
Register address between 0x00 and 0x3f/// The value of the byte read at the address
public byte this[byte address] {
get {
if (address > DS1307_RAM_END_ADDRESS) {
throw new ArgumentOutOfRangeException("Invalid register address");
}

var value = new byte[1];

// Read the RAM register @ the address
var transaction = new I2CDevice.I2CTransaction[] {
I2CDevice.CreateWriteTransaction(new byte[] {address}),
I2CDevice.CreateReadTransaction(value)
};

if (clock.Execute(transaction, DS1307_I2C_TRANSACTION_TIMEOUT_MS) == 0) {
throw new Exception("I2C transaction failed");
}

return value[0];
}
}

///


/// Writes an arbitrary RTC or RAM register
///

///
Register address between 0x00 and 0x3f///
The value of the byte to write at that addresspublic void WriteRegister(byte address, byte val) {
if (address > DS1307_RAM_END_ADDRESS) {
throw new ArgumentOutOfRangeException("Invalid register address");
}

var transaction = new I2CDevice.I2CWriteTransaction[] {
I2CDevice.CreateWriteTransaction(new byte[] {address, (byte) val})
};

if (clock.Execute(transaction, DS1307_I2C_TRANSACTION_TIMEOUT_MS) == 0) {
throw new Exception("I2C write transaction failed");
}
}

///


/// Takes a Binary-Coded-Decimal value and returns it as an integer value
///

///
BCD encoded value/// An integer value
protected int BcdToDec(int val) {
return ((val / 16 * 10) + (val % 16));
}

///


/// Takes a Decimal value and converts it into a Binary-Coded-Decimal value
///

///
Value to be converted/// A BCD-encoded value
protected byte DecToBcd(int val) {
return (byte)((val / 10 * 16) + (val % 10));
}

///


/// Releases clock resources
///

public void Dispose() {
clock.Dispose();
}
}
}


The next group of things to test after I get the shift registers and TLCs working will be:

SD
Wi-Fi
Serial Mux
LCD
PH
1-Wire (Waiting on 4.2 release with 1-wire support)
Auto temp probe registering 1-wire network.

Thursday, March 22, 2012

Netduino - High Power LED drivers

I am currently working on a high power LED driver; this will be used to drive my aquarium lighting.

So a brief overall spec:

The aquarium lighting rig will allow for individual control of the LEDs, this will allow for lighting effects such as cloud cover, seasons, lunar/solar cycles and lightening.

These effects along with the overall lux, colour and contrast will be achieved by having control over the LEDs individually. There will be 3 watt white Cree's, Royal Blues, Red and Greens. This combination will allow for both day and moon light and the reds and greens will allow me to adjust the colour warmth.

In total there will be 30 Leds:

14 x 3W White Cree
10 x 3W Royal Blue
3 x 3W Red
3 x 3W Green

The LEDs will be mounted on a 3mm aluminium sheet, evenly spaced, with various lenses to create an even colour and lux distribution.

The LED drivers will need to be extremely efficient i.e. above 90%, the design Magpie is proposing should achieve over 95% efficiency when used with 6 LEDs in a chain. As I will be using only 1 LED per chain this will be slightly less efficient but I am hopeful that I will still achieve at least 90%.

I will give some more specific details about the drivers and the overall build as I have more information. Currently I have the LEDs and some inductors for building the drivers, so the next steps will be to get the rest of the parts I need and in the mean time I will be testing the TLC5940s which will be providing the PWM control for the LED drivers.

Wednesday, February 29, 2012

Netduino - Project Update

My prototype control board is now completely soldered up now.

I still need to do some testing, but I have powered it all up and it didn't set on fire, so I'm hoping all is well.

The main improvement is that the TLC59040s are fully soldered up.

I'm going to test all the various functions over the next month and will also be purchasing the various components I need for my LED drivers, relay enclosure and relay control board.

Here are a few pictures of the control board so far...



Wednesday, February 22, 2012

Relay Enclosure

I have been working on a relay enclosure for a little while, the main aims of this part of the project is to safely and to an electrical safe standard, design and build a high power relay enclosure.

The enclosure has been designed using 25amp SSR relays and 10amp rated IEC sockets. I have used 2.5 guage solid core cable and all of the IEC are fused, with the input one also having a switch.

For the low power control of the relays, I am currently designing a dip switch configurable option to choose whether transistors are normally open or normally closed for each channel. This will allow me to have a fail save for the various equipment that needs powering, even if the control board fails. For example heating and pumps will always need power, where as air pumps and lights may be less critical to life support.

Thermal management has been a key focus in the design of the relay enclosure, to take care of this aspect I have used a vented steel case, 2 large heat sinks and 2 pc fans. The temperature of each heat sink will be monitored using DS18B20 or similar temperature sensors on the 1-wire bus. The readings from these sensors will allow me to control fan speed and if necessary turn of relays if they are over heating.

The enclosure has 6 panel mounted LEDs at the front, this will indicate which relays are on, whilst fan speed will be displayed on the main controller LCD along with the temperatures. The 3.3v logic from the shift registers will be used to control transistors which will control the 12v supply that will be used to swith the relays. Whilst the 3.3v is enough to directly control the relays, I want to provide some isolation from the netduino and also take some of the power power burden of the netduino's regulators.

Below is a picture which shows my mains wiring, as you can see I am using the WAGO terminals to distribute the mains supply. I have cut all the IEC holes and have already set my switched, fused input socket, but am yet to order the 6x fused output sockets. All of the mains power is being kept at the top of the enclosure in the middle, this will be seperated with some blank pcb from the low power control board which will go at the bottom between the relays and will held keep the main away from the case should a connection become loose (which I can assure you it won't). Also the case itself will be earthed for added protection.


I will will post an update shortly once I have finished designing the control circuit.