Showing posts with label PCB. Show all posts
Showing posts with label PCB. Show all posts

Monday, November 2, 2015

RN52 hardware

Here's ver 2 of the hardware


I've already made a v3, to fix a problem with the USB plug on the bottom (for RN52 firmware upgrades). Firmware upgrades will be rare, and in fact, future upgrades will be done via UART pins, so the USB plug is for RN52 modules with old firmware (v1.10 & older). v1.16 and above will use UART for upgrades.

Karlis has done a smashing job on the software side! The module doesn't drop out at all now, steering wheel controls work with both iPhone and Android phones, and he's also integrated bluetooth sync connect & disconnect controls via the head unit (IHU).

There are still some bugs he wants to work out, and of course, getting artist/track info on the SID is on the to-do list :)

You'll also notice the 3.5mm jack at the top. That's for the Mic input to the RN52, which Karlis & I are planning on using the vehicle's On-Star mic. So once we figure out the best way to do that, he even has the code setup to bring Siri up for a long button press :) So eventually, you'll be able to wire in the car's mic to a 3.5mm plug, and plug that into the module, and be able to talk to Siri at the press of a button (or no button if your phone is charging or you have 6S)!

Feel free to ask questions in the comments; Karlis said he'd try to answer software questions for me :)

And no, I'm not planning on making/selling them. Do you know how much work that would be for me for all of you?! But I can help guide you along the way :)

Wednesday, September 16, 2015

New bluetooth module; RN52

So I've been working with a buddy (Karlis) about getting a better working module. He's determined that the BC05B module I was using isn't a very good module. It's a total PITA to work with, and has very limited documentation.

He suggested that we go with a RN52 module by Microchip.

He's done a lot of testing, and I've laid out a new pcb for that module.

Karlis has also done extensive testing and determined that the CANBUS code had a lot of bugs in it, which he's kindly fixed; Thanks Karlis!!

Prototypes are being built, then tested, then should be released for everyone else to use :)

Saturday, May 17, 2014

Working bluetooth prototype!

Here's my working prototype bluetooth module. I'm using the BC05B bluetooth module, which works great.

It still has a lot of bugs, and I may have to redesign/add some things.

PROS:

  1. steering wheel controls for next track & beginning of song/previous track!
  2. 1 device for bluetooth audio/control; NO WIRES!
  3. sound quality is very good (IMHO)
  4. module connects to the last-known-connected device automatically, if it's within range (i.e., if my iPhone 5 was the last device that the module was connected to before I left the car, when I return to the car, it automatically connects when I'm back within range)
  5. when switching to aux mode, the currently connected device starts playing automatically
  6. when switching to radio mode, the currently playing, connected device stops playing (hits the pause button for you so you don't "lose your place" in the track)


CONS:
  1. The volume turns on at medium; i'm trying to get the device to turn the volume up full at power on but no luck yet
  2. still not 100% sure on the pairing sequence for to this module:

  • pairing a new-to-the-module device
  • pairing a new-to-the-module device when the module is currently connected to a different device
  • connecting a known device to the module
  • connecting a known device to the module when the module is currently connected to a diff device

No artist/track info available yet (that i'm aware of) for displaying on the SID; will look into this after I get all the other bugs worked out.

The bottom of my pcb is my attempt to get the volume to turn up at power on, but it's not working, I think because of software...could be the 4066 chip I piggy-backed on top of the other :)

Right now, I have the SRC button on the steering wheel set to put the module into discoverable mode (this only works if you're in Aux/CD changer mode, so you can still use SRC to change between FM1, FM2, and AM1). This has worked pretty good so far between switching connected devices; i.e., when my wife wants to play her music through the car, I hit the SRC button while playing my music, it disconnects from my phone, stops the music [the head unit kicks out of aux mode, back to the radio], the module goes into discoverable mode, she connects to it, and I hit CD twice to get back to aux mode, and it automatically starts playing the last thing she was listening to.

enough talk, pictures!



Tuesday, August 6, 2013

New PCB & code

So I did some more redesigning and played with the code again. I moved away from the priority SID text because it prevented my Night Panel from working.

Here's a link to my public OSHPark.com profile. You can order PCBs (in multiples of 3) for ~$30, shipped. They're excellent quality. I'll get some pictures up soon of a newly finished board.

Also, this version uses the original CD Changer harness plug so no more splicing wires!! Literally, plug-n-play.

So right now there are several options. The board & code still supports iPod steering wheel controls, but it doesn't sound like many people need/care/want that. I'm not going to remove that, but it sounds like most people just want an audio source, and a universal one at that.

I can just put a 3.5mm stereo jack in the case and you can run a long 3.5mm male to male cable from the trunk to the dash (under the door sills and such). This should work pretty well.

Or one could install a bluetooth module in the unit, much like my car does. I made sure there were 5v and GND pins available in case anyone wanted to power a bluetooth module up.

// ----------------------------------------------
// SECUDUINO
// http://secuduino.blogspot.com/
// By Igor Real
// 16/05/2011
//
// Saab CDC Changer Emulator
// http://BlueSaab.blogspot.com/
// By Seth Evans
// 29 July 2013
// ----------------------------------------------

#include <CAN.h>

int cdbutton = 0;
int toggleshuffle = 1;
int mute = 0;
int CDCcmd[] = {
  0xE0,0x00,0x3F,0x31,0xFF,0xFF,0xFF,0xD0};
int ninefivecmd[] = {
  0x62,0x00,0x00,0x16,0x01,0x02,0x00,0x00};
int beep[] = {
  0x80,0x04,0x00,0x00,0x00,0x00,0x00,0x00};
int playipod[] = {
  0xFF,0x55,0x04,0x02,0x00,0x00,0x01,0xF9};
int playpauseipod[] = {
  0xFF,0x55,0x03,0x02,0x00,0x01,0xFA};
int stopipod[] = {
  0xFF,0x55,0x04,0x02,0x00,0x00,0x02,0xF8};
int next[] = {
  0xFF,0x55,0x03,0x02,0x00,0x08,0xF3};
int prev[] = {
  0xFF,0x55,0x03,0x02,0x00,0x10,0xEB};
int shuffle[] = {
  0xFF,0x55,0x04,0x02,0x00,0x00,0x80,0x7A};
int repeat[] = {
  0xFF,0x55,0x05,0x02,0x00,0x00,0x00,0x01,0xF8};
int buttonRelease[] = {
  0xFF,0x55,0x03,0x02,0x00,0x00,0xFB};

void setup() {
  // set up CAN
  CAN.begin(47);  // Saab I-Bus is 47.619kbps
  Serial.begin(9600);
  //cdbutton = 0;
  //toggleshuffle = 1;
  CAN_TxMsg.header.rtr=0;     // this value never changes
  CAN_TxMsg.header.length=8;  // this value never changes
  // not sure if this is needed; pauses program before it loops
  Serial.println("9-5 Test Code 2");
  delay(2000);
}

void loop() {
  //cdbutton = 1;
  //PrintBus();
  // CDC code needs sent every second or less so all loops
  // running added together need to take less than 1000ms
  // but no more or the car won't "see" the CDC
  CDC();
  for (int i = 0; i <= 860; i++) {
    if (CAN.CheckNew()) {
      CAN_TxMsg.data[0]++;
      CAN.ReadFromDevice(&CAN_RxMsg);
      //PrintBus();
      if (CAN_RxMsg.id==0x6A1) {
        CAN_TxMsg.id=0x6A2;     // CD Changer
        for (int c = 0; c < 8; c++) {
          CAN_TxMsg.data[c]=ninefivecmd[c];
        }
        CAN.send(&CAN_TxMsg);
      }

      if (CAN_RxMsg.id==0x3C0) {
        if (CAN_RxMsg.data[0]==0x80) {
          switch (CAN_RxMsg.data[1]) {
          case 0x24:
            cdbutton = 1;
            for (int j = 0; j < 8; j++) {
              CAN_TxMsg.id=0x430;
              CAN_TxMsg.data[j]=beep[j];
            }
            CAN.send(&CAN_TxMsg);
            for (int j = 0; j < 8; j++) {
              Serial.write(byte(playipod[j]));
            }
            delay(3);
            //Serial.println("Release");
            for (int i = 0; i < 7; i++) {
              Serial.write(byte(buttonRelease[i]));
            }
            break;
          case 0x14:
            cdbutton = 0;  
            for (int a = 0; a <=2; a++) {
              for (int j = 0; j < 8; j++) {
                CAN_TxMsg.id=0x430;
                CAN_TxMsg.data[j]=beep[j];
              }
              CAN.send(&CAN_TxMsg);
            }
            for (int j = 0; j < 8; j++) {
              Serial.write(byte(stopipod[j]));
            }
            delay(3);
            //Serial.println("Release");
            for (int i = 0; i < 7; i++) {
              Serial.write(byte(buttonRelease[i]));
            }
            //Serial.println("Radio");
            break;
          }
          if (cdbutton == 1) {
            switch (CAN_RxMsg.data[1]) {
            case 0x59: // NXT button signal
              for (int j = 0; j < 7; j++) {
                Serial.write(byte(playpauseipod[j]));
              }
              break;
            case 0x76: // Long press of CD/RDM button
              if (toggleshuffle > 3) {
                toggleshuffle = 1;
              }
              switch (toggleshuffle) {
              case 1:
                for (int j = 0; j < 9; j++) {
                  Serial.write(byte(repeat[j]));
                }
                break;
              case 2:
                for (int j = 0; j < 9; j++) {
                  Serial.write(byte(repeat[j]));
                }
                break;
              case 3:
                for (int j = 0; j < 9; j++) {
                  Serial.write(byte(repeat[j]));
                }
                for (int j = 0; j < 8; j++) {
                  Serial.write(byte(shuffle[j]));
                }
                break;
              }
              toggleshuffle++;
              //break;
            case 0xB1: // Audio mute on?
              for (int j = 0; j < 8; j++) {
                Serial.write(byte(stopipod[j]));
              }
              break;
            case 0xB0: // Audio mute off?
              for (int j = 0; j < 8; j++) {
                Serial.write(byte(playipod[j]));
              }
              break;
            case 0x35: // Seek next (Seek+)?
              for (int j = 0; j < 7; j++) {
                Serial.write(byte(next[j]));
              }
              break;
            case 0x36: // Seek previous (Seek-)?
              for (int j = 0; j < 7; j++) {
                Serial.write(byte(prev[j]));
              }
              break;
            }
            delay(3);
            //Serial.println("Release");
            for (int i = 0; i < 7; i++) {
              Serial.write(byte(buttonRelease[i]));
            }
          }
        }
      }
      if (CAN_RxMsg.id==0x290) {
        if (CAN_RxMsg.data[0]==0x80) {
          if (cdbutton == 1) {
            switch (CAN_RxMsg.data[2]) {
              //case 0x04: // NXT button on wheel
              //for (int j = 0; j < 9; j++) {
              //Serial.write(byte(repeat[j]));
              //}
              //break;
            case 0x10: // Seek+ button on wheel
              //Serial.println("Next");
              for (int j = 0; j < 7; j++) {
                Serial.write(byte(next[j]));
              }
              break;
            case 0x08: // Seek- button on wheel
              //Serial.println("Prev");
              for (int k = 0; k < 7; k++) {
                Serial.write(byte(prev[k]));
              }
              break;
            }
            delay(3);
            //Serial.println("Release");
            for (int i = 0; i < 7; i++) {
              Serial.write(byte(buttonRelease[i]));
            }
          }
        }
      }
    }
    delay(1);
  }
  if (cdbutton==1) {
    //Serial.println("iPod ON");
    iPodOn();
  }
  else {
    //Serial.println("iPod OFF");
    //iPodOff();
    //delay(400);
  }
}

void CDC() {
  CAN_TxMsg.id=0x3C8;     // CD Changer
  for (int c = 0; c < 8; c++) {
    CAN_TxMsg.data[c]=CDCcmd[c];
  }
  CAN.send(&CAN_TxMsg);
}

void iPodOn() {
  // This loop takes 50ms
  CAN_TxMsg.id=0x328;     // SID audio text
  CAN_TxMsg.data[0]=0x42; // message 2
  CAN_TxMsg.data[1]=0x96;
  CAN_TxMsg.data[2]=0x02; // Row 2
  CAN_TxMsg.data[3]=0x20; // _
  CAN_TxMsg.data[4]=0x3C; // <
  CAN_TxMsg.data[5]=0x42; // B
  CAN_TxMsg.data[6]=0x6C; // l
  CAN_TxMsg.data[7]=0x75; // u
  CAN.send(&CAN_TxMsg);
  delay(10);

  CAN_TxMsg.data[0]=0x01; // message 1
  CAN_TxMsg.data[3]=0x65; // e
  CAN_TxMsg.data[4]=0x74; // t
  CAN_TxMsg.data[5]=0x6F; // o
  CAN_TxMsg.data[6]=0x6F; // o
  CAN_TxMsg.data[7]=0x74; // t
  CAN.send(&CAN_TxMsg);
  delay(10);

  CAN_TxMsg.data[0]=0x00; // message 0
  CAN_TxMsg.data[3]=0x68; // h
  CAN_TxMsg.data[4]=0x3E; // >
  CAN_TxMsg.data[5]=0x20; //
  CAN_TxMsg.data[6]=0x20; //
  CAN_TxMsg.data[7]=0x20; //
  CAN.send(&CAN_TxMsg);
  delay(10);

  CAN_TxMsg.id=0x348;     // audio text control
  CAN_TxMsg.data[0]=0x11; // 11
  CAN_TxMsg.data[1]=0x02; // Row 2?
  CAN_TxMsg.data[2]=0x05; // 05
  CAN_TxMsg.data[3]=0x18; // priority 18?
  CAN_TxMsg.data[4]=0x00;
  CAN_TxMsg.data[5]=0x00;
  CAN_TxMsg.data[6]=0x00;
  CAN_TxMsg.data[7]=0x00;
  CAN.send(&CAN_TxMsg);
  delay(10);

  /*CAN_TxMsg.id=0x368;     // SID text priority
   CAN_TxMsg.data[0]=0x02; // Row 2
   CAN_TxMsg.data[1]=0x18; // priority 18?
   CAN_TxMsg.data[2]=0x00;
   CAN_TxMsg.data[3]=0x00;
   CAN_TxMsg.data[4]=0x00;
   CAN_TxMsg.data[5]=0x00;
   CAN_TxMsg.data[6]=0x00;
   CAN_TxMsg.data[7]=0x00;
   CAN.send(&CAN_TxMsg);
   delay(10);
   */
}

void PrintBus() {
  if (CAN_RxMsg.id==0x6A2) {
  //if (CAN_RxMsg.data[0]==0x80) {
    Serial.print(CAN_RxMsg.id,HEX);
    Serial.print(";");
    for (int i = 0; i < 8; i++) {
      Serial.print(CAN_RxMsg.data[i],HEX);
      Serial.print(";");
    }
    Serial.println("");
  }
}

Saturday, July 20, 2013

Populated board

Thought I would show what a fully populated board looks like when it's ready to be put into the box (minus wires).

Wednesday, June 5, 2013

New board design

I decided to fix up the board design. I added a jumper underneath the 328P socket, but I added all the holes for the unused pins on all the DIP sockets, so no more cutting off pins! :)

REMEMBER : This view of the board is the BOTTOM, so all the components go on the other side, and that means you have to watch out for pin 1 on all the ICs! It's a little confusing, even for me. I just hold the board like it looks below and hold the IC in the air, as it were going to match the image, and then flip the two over, and it should have the proper orientation. It also helps a lot to watch for the pin 1 indicator; the indentation in the sockets.

The reason I designed the board like this is because it makes it easier for me to manufacture the boards. I mill them out, and of course the side you mill has to be "up", so this way I don't have to reverse the file when I export it out to the routing program.

Schematic file
Board file