Featured Post

Beolover SyncDrive: DC Platter Motor Replacement for Beogram 4002 and 4004 (Type 551x and 552x)

Late Beogram 4002 and the 4004 (Types 551x and 552x), which have DC platter motors instead of the earlier synchronous AC motors usually suff...

Friday, October 17, 2014

Beomaster 6000 4-Channel (2702): LED Based Scale Illumination (Pt.3) - Circuits and Arduino Code

This post is part 3 of the documentation of my efforts to replace the incandescent light bulbs of the Beomaster 6000 4-Channel that I was restoring. For a description of the hardware discussed here, please visit this page.
Probably the most difficult aspect of this effort was to provide the Arduino and the Neopixel LEDs with a stabilized 5V supply. After many trials, it turned out that a simple half-wave rectifier in combination with a DC/DC converter directly hooked into the AC power supply of the Beomaster was the best solution. Here is a picture of the circuit:



































The circuit is connected to one of the AC leads from the transformer in the Beomaster 6000 (red circle). The current returns into the '-19V' rail of the Beomaster power supply circuit (blue circle).
The nine diodes drop the 40V amplitude to a safe level for the 7824 regulator, while providing half-wave rectification of the AC wave. From the smoothened AC wave via C1 (220uF) the 7824 produces a stabilized 24V at its output, which is fed into  a TR05S05 DC/DC converter that makes a stabilized 5V output voltage. This potential is then fed into the Advanced Light Source (ALS) circuit that drives the Neopixel LED strings for the scale illumination.

The relevant connection points to the Beomaster 6000 power supply circuit are shown here:


























Connecting the return to the -19V rail of the Beomaster puts the GND rail of the ALS at 0V relative to the 40V AC amplitude.

This diagram shows the ALS circuit (this circuit omits the crystal as well as the ISP port that needs to be implemented to program the Atmega328p):






















The Atmega328p controls the FM dial and Control LED strings based on the two nominally 18V inputs from the Beomaster, which normally control the incandescent light bulbs in either display.

These 18V signals are at about 40V above GND relative to the Atmega328p, hence the large voltage dividers (51k/1k) in the two inputs. The transistors are necessary since the 18V potentials only relax to the internal ground of the Beomaster when the displays are off, i.e. the voltage change at the input is only from 40V to about 20V. Transistors were implemented to translate this change into a digital 5 -> 0 transition at the Atmega328p pins. This enabled to use the two external interrupts of the Atmega chip for triggering the switching of the display LEDs.

Below is the commented Arduino code. The NeoPixel library does all the heavy lifting for driving the LED strings, and the sleep library enables the use of the power saving modes of the Atmega. This was crucial since the tuner section of the Beomaster proved quite sensitive to the digital emissions of the Atmega. The use of interrupts in combination with sleep modes enabled to limit the Atmega activity to a few ms per display illumination change (during which the Beomaster goes on 'mute' anyway), essentially eliminating any interference with the tuner of the Beomaster 6000.

***************code start ***************************************************


#include <Adafruit_NeoPixel.h>//library that provides the methods for running the neopixels
#include <avr/sleep.h>//this AVR library contains the methods that controls the sleep modes

#define Tuner_PIN 8        // Tuner strip Data Out
#define Controlstrip_Pin 7 //Controls strip Data Out

#define Tuner_scalelight_pin 3//This ext interrupt pin (INT1) goes low via the transistor if the tuner is turned on
#define Controllight_pin 2//This interrupt pin (INT0)  goes low via the transistor if the controls are to be lit up.

//these RGB setting give an 'incandescent' emission of the LEDs:

byte red=255;//255
byte blue=2;//2
byte green=196;//196

// New instances of NeoPixel class
Adafruit_NeoPixel Tunerstrip = Adafruit_NeoPixel(4, Tuner_PIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel Controlstrip = Adafruit_NeoPixel(6, Controlstrip_Pin, NEO_GRB + NEO_KHZ800);

void setup()//this is the setup routine that is executed after initial power up
{
  delay(500);//wait until things stabilize after turn on
  //Serial.begin(9600);
  pinMode(Tuner_scalelight_pin,INPUT);
  pinMode(Controllight_pin,INPUT);
  ADCSRA |= (0<<ADEN); //disable ADC
  Tunerstrip.begin();
  Tunerstrip.show(); // Initialize all pixels to 'off'
  Controlstrip.begin();
  for (int i=0; i <= 6; i++){
  Controlstrip.setPixelColor(i, red, green, blue);        //turn the controls pixels on (the beomaster goes into standby "ON" by default after turing it on at the mains switch.
  }
  Controlstrip.show(); //set pixels
}

void loop()
{

  digitalWrite(13,LOW);   // turn LED off to indicate sleep
 
 
    sleep_enable();
    attachInterrupt(0, controlsISR, CHANGE);//Set pin 2 as interrupt and attach Interrupt Service Routine (ISR)
    attachInterrupt(1, tunerISR, CHANGE);//Set pin 3 as interrupt and attach Interrupt Service Routine (ISR)
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);//define power down sleep mode
    digitalWrite(13,LOW);   // turn LED off to indicate sleep

    MCUCR |= (1<<BODS) | (1<<BODSE);// turn brown out detection off (from:http://forum.arduino.cc/index.php/topic,50109.0.html)
    MCUCR &= ~(1<<BODSE);  // must be done right before sleep
    sleep_cpu();//Set sleep enable (SE) bit, this puts the ATmega to sleep
    //Serial.println("just woke up!");//When it wakes up due to the interrupt the program continues with the instruction following sleep_cpu()
    digitalWrite(13,HIGH);   // turn LED on to indicate wake up
    delay(1000);


  if (digitalRead(Tuner_scalelight_pin)==LOW)//LOW due to transistor; FM scale "ON"
    {
      for (int i=0; i <= 3; i++){
      Tunerstrip.setPixelColor(i, red, green, blue);        //turn the pixels on
      }
      Tunerstrip.show();
    }
  if (digitalRead(Tuner_scalelight_pin)==HIGH)//HIGH due to transistor; FM scale "OFF"
    {
      for (int i=0; i <= 3; i++){
      Tunerstrip.setPixelColor(i, 0);        //turn the pixels off
      }
      Tunerstrip.show();
    }
 
  if (digitalRead(Controllight_pin)==HIGH)//HIGH due to transistor; Stand by "OFF"
    {
      for (int i=5; i >=0; i--){
      Controlstrip.setPixelColor(i, 20, 20, 0);        //turn the pixels off
      }
      Controlstrip.show();
    }  

  if (digitalRead(Controllight_pin)==LOW)//LOW due to transistor; Stand by "ON"
    {
      for (int i=0; i <= 5; i++){
      Controlstrip.setPixelColor(i, red, green, blue);        //turn the pixels on
      }
      Controlstrip.show();
    }
}

***************Interrupt service routines (ISR)**********************************
void tunerISR()//ISR
{
  sleep_disable();//this is important. It is possible that the interrupt is called between executing "attachInterrupt(...)" and sleep_CPU() in the main loop
                  //if that happens without the sleep_disable() in the ISR, the ISR would be called, the interrupt detached and the device put to sleep.
                  //since the interrupt would be disabled at that point, there would be no way to wake the device up anymore.
                  //by putting sleep_disable() in the ISR, sleep_cpu() would not be effective during that loop, i.e. the main loop would run one more time
                  //and then properly attach the interrupt before hitting the sleep_cpu() a second time. At that point the device would go to sleep, but
                  //the interrupt would now be activated, i.e. wake-up can be induced.
  detachInterrupt(1);//disable INT1. This effectively debounces the interrupt mechanism to prevent multiple interrupt calls.

}

void controlsISR()//ISR
{
  sleep_disable();//this is important. It is possible that the interrupt is called between executing "attachInterrupt(...)" and sleep_CPU() in the main loop
                  //if that happens without the sleep_disable() in the ISR, the ISR would be called, the interrupt detached and the device put to sleep.
                  //since the interrupt would be disabled at that point, there would be no way to wake the device up anymore.
                  //by putting sleep_disable() in the ISR, sleep_cpu() would not be effective during that loop, i.e. the main loop would run one more time
                  //and then properly attach the interrupt before hitting the sleep_cpu() a second time. At that point the device would go to sleep, but
                  //the interrupt would now be activated, i.e. wake-up can be induced.
  detachInterrupt(0);//disable INT0. This effectively debounces the interrupt mechanism to prevent multiple interrupt calls.



***************code end ***************************************************

4 comments:

  1. hello, only a little idea. the 1N400x diodes in series can be replaced by a high power zener ziode.in reverse.
    if you have 40v and connect the zener diode in serie with the cathod connected at the 40v side you get 40 - Vzener at the anode side.
    you must choose a high power zener diode because it power dissipation will be Vz * I
    example 5.1V with 100mA give approx. 500mW
    Genesis.

    ReplyDelete
    Replies
    1. You are right. I chose to use the diode sequence to distribute the heat load more evenly across the heat sink...the circuit draws almost 400mA when all neopixels are on.

      Delete
  2. ok ;) but a big diode with leads can be fixed on the casing as a heatsink :)
    but I understand :)
    Franck.

    ReplyDelete
  3. There are many roads to Rome...;-) The particular road chosen also depends on what parts one has in the drawer...;-). Are you fixing up a 6000 (2702)?

    ReplyDelete

Comments and suggestions are welcome!