It turns out that lots of MBP models have a well-known issue with the headphone port, and this can cause the internal speakers to become disabled. Actually, they’re disabled as a side-effect of digital output being enabled. The headphone port is used for both electrical and optical connections, and the internal switch managing this can sometimes enter the “optical connector present” state for no apparent reason.

Here’s one thread describing this issue, and Google turns out many more.

However, the reason that I’m writing this is that my machine (2010 17″ MBP) seems to suffer from a variation of this problem. All descriptions of the issue I found were rather old, and in all cases it was reported that the red light (ie. the optical signal stream) was turned on when the internal speakers were disabled. On my machine, the red light was visible only some of the time.

Doing a software update, a reboot and even an SMC reset did not help. I eventually fixed the issue by moving the headphone jack slowly in and out of the port while wiggling it a little bit. It took maybe 15 tries before it worked…

To monitor your (lack of) progress, open the System Preferences, go to the Sound pane and select the Output tab.

  • In the broken state, the topmost item will read “Digital Output” and a red light may or may not be visible from the headphone socket
  • When the headphone jack is inserted, this should change to “Headphones”
  • The non-broken state is “Internal Speakers”. This is when you have managed to clear the switch (HW or SW, I don’t know) that is stuck in the “optical connector present” state.

My first AVR-based project

August 16, 2008

I have always been fascinated by electronics. As a child, I tore apart several rather expensive appliances to see how they worked. Much to my parents’ grief, of course.

However, since I got into software development, I haven’t given it much thought. Moving several levels of abstraction away from the hardware, your focus shifts quickly to completely different areas.

But recently, this project caught my attention for some reason. So even though I ended up implementing it completely differently, I couldn’t stop thinking about the potential of being able to write code for tiny, cheap embedded processors.

I’m not sure why I have never thought of this before. I have considered writing software for PDAs, but they’re pretty expensive, and the platform choices are poor. Windows Mobile is a joke, and Palm OS is not very appealing either.

So I decided to take a big step closer to the iron. Knowing nothing about the state of this field, I simply googled for a few starting points. I ended up buying the very cool USBtinyISP programmer kit (and absolutely enjoyed the process of assembling it).

Also, I got the ATtiny26 development board from Active Robots.

This last item, I have later discovered, is probably somewhat outdated. What you want for electronics prototyping these days is the Arduino.

Anyway, the great thing about the ATtiny is that it’s cheap (the processor itself is about $4) and it doesn’t consume a lot of power.

OK, so what did I do for my debut project? Nothing very interesting, I’m afraid. I wrota a program that simply morses a sentence using the LED built into the development board. I used the GNU toolchain (avr-libc et al) for writing the program and avrdude for flashing it onto the processor. Works great on both Linux and OSX.

In action, this is what it looks like:

And yes, I realize that the quality of the video is too crappy to distinguish the pulses.

Here is the complete source code for this project:

#include
#include
#include
#include
#include

/*
 * The morse alphabet.
 *
 * 0: Short pulse
 * 1: Long pulse
 */
const char ltr_a[] PROGMEM = "01";
const char ltr_b[] PROGMEM = "1000";
const char ltr_c[] PROGMEM = "1010";
const char ltr_d[] PROGMEM = "100";
const char ltr_e[] PROGMEM = "0";
const char ltr_f[] PROGMEM = "0010";
const char ltr_g[] PROGMEM = "110";
const char ltr_h[] PROGMEM = "0000";
const char ltr_i[] PROGMEM = "00";
const char ltr_j[] PROGMEM = "0111";
const char ltr_k[] PROGMEM = "101";
const char ltr_l[] PROGMEM = "0100";
const char ltr_m[] PROGMEM = "11";
const char ltr_n[] PROGMEM = "10";
const char ltr_o[] PROGMEM = "111";
const char ltr_p[] PROGMEM = "0110";
const char ltr_q[] PROGMEM = "1101";
const char ltr_r[] PROGMEM = "010";
const char ltr_s[] PROGMEM = "000";
const char ltr_t[] PROGMEM = "1";
const char ltr_u[] PROGMEM = "001";
const char ltr_v[] PROGMEM = "0001";
const char ltr_w[] PROGMEM = "011";
const char ltr_x[] PROGMEM = "1001";
const char ltr_y[] PROGMEM = "1011";
const char ltr_z[] PROGMEM = "1100";

PGM_P alphabet[26] PROGMEM = {
    ltr_a,ltr_b,ltr_c,ltr_d,ltr_e,ltr_f,ltr_g,ltr_h,ltr_i,ltr_j,ltr_k,
    ltr_l,ltr_m,ltr_n,ltr_o,ltr_p,ltr_q,ltr_r,ltr_s,ltr_t,ltr_u,ltr_v,
    ltr_w,ltr_x,ltr_y,ltr_z
};

void sleep_msecs(int msecs)
{
   /*
    * The argument to _delay_ms must be constant (ie. known at compile-time).
    */
   int i;
   for(i = 0; i < msecs; i++){
      _delay_ms(1);
   }
}

void set_led_state(int state)
{
   PORTB = (state == 1) ? _BV(6) : _BV(0);
}

/*
 * Emit single pulse
 *
 * Length choices are:
 * 0: short
 * 1: long
 */
void emit_pulse(int length)
{
   set_led_state(1);
   sleep_msecs((length == 1) ? 210 : 60);
   set_led_state(0);
   sleep_msecs(100);
}

/*
 * Emit a sequence of pulses, eg. "1000" for the letter "b".
 */
void emit_pulses(char *pulse_str)
{
   int pulse_str_len = strlen(pulse_str);
   int i2;
   for (i2 = 0; i2 < pulse_str_len; i2++) {
      emit_pulse(pulse_str[i2] == '1');
   }
}

void emit_letter(char l)
{
   if (l == ' ') {
      sleep_msecs(700);
      return;
   }

   char *buf = malloc(8 * sizeof(char));

   int index = l - 'a';
   PGM_P p;
   memcpy_P(&p, &alphabet[index], sizeof(PGM_P));
   strcpy_P(buf, p);
   emit_pulses(buf);
   free(buf);
}

void morse_msg(const char *msg)
{
   int len = strlen(msg);
   int i;
   for (i = 0; i < len; ++i) {
      emit_letter(msg[i]);
      sleep_msecs(350);
   }
}

void do_morse(const char *msg)
{
   for(;;){
      morse_msg(msg);
      sleep_msecs(2500);
   }
}

int main(void)
{
   /* Init IO */
   DDRB = _BV(6); /* make the LED pin an output */

   do_morse("er der mon mere kaffe");

   /* Not reached */
   return 0;
}

In case you’re wondering, the morsed message, “er der mon mere kaffe”, is danish for “I wonder if there’s any more coffee”. Indeed, the first thing that sprang to mind when I finally got the software working.

Follow

Get every new post delivered to your Inbox.