Monday, August 18, 2008

Saturday, March 8, 2008

Arduino & the ISD4002

I've been taking an engineering class this semester that focuses on designing electronics that produce music. We're all using the Arduino microcontroller platform, and one of our tasks is to get the ISD4002 chip (a sound recorder) communicating with the Arduino through SPI. I haven't been able to find any evidence of the ISD4002 chip working with the Arduino on Google, so hopefully this code will be useful to someone.

The following program first initializes SPI, Serial, and the ISD chip. The flow of the main loop is:
Record for 10 sec --> Pause 2 sec --> Play for 10 sec --> Pause for 2 sec.


#define DATAOUT 11 // MOSI
#define DATAIN 12 // MISO
#define SPICLOCK 13 // SCK
#define SLAVESELECT 10 // SS

#define ISD_OPCODE_POWERUP B00100
#define ISD_OPCODE_SETPLAY B00111
#define ISD_OPCODE_PLAY B01111
#define ISD_OPCODE_SETREC B00101
#define ISD_OPCODE_REC B01101
#define ISD_OPCODE_STOP B01100
#define ISD_OPCODE_POWERDOWN B00000
#define ISD_POWERUP_DELAY 25

char spi_transfer(volatile char data) {
SPDR = data;
while (!(SPSR & (1<<SPIF))) { }
return SPDR;
}

void spi_init() {
byte clr;
pinMode(DATAOUT, OUTPUT);
pinMode(DATAIN, INPUT);
pinMode(SPICLOCK, OUTPUT);
pinMode(SLAVESELECT, OUTPUT);

digitalWrite(SLAVESELECT, HIGH); // Disable device

SPCR = (1<<SPE)|(1<<MSTR);
clr=SPSR;
clr=SPDR;
delay(10);
}

void isd_send_command(unsigned char command, unsigned int address) {
digitalWrite(SLAVESELECT, LOW);
spi_transfer(address & 0xff);
spi_transfer(((address & 0xff00) >> 3) | command);
digitalWrite(SLAVESELECT, HIGH);
}

void isd_powerdown() {
Serial.println("Powering down...");
isd_send_command(ISD_OPCODE_POWERDOWN, 0);
}

void isd_powerup() {
Serial.println("Powering up...");
isd_send_command(ISD_OPCODE_POWERUP, 0);
delay(ISD_POWERUP_DELAY);
}

void isd_play(unsigned int address) {
Serial.println("Playing...");
isd_send_command(ISD_OPCODE_SETPLAY, address);
isd_send_command(ISD_OPCODE_PLAY, 0);
}

void isd_record(unsigned int address) {
Serial.println("Recording...");
isd_send_command(ISD_OPCODE_SETREC, address);
isd_send_command(ISD_OPCODE_REC, 0);
}

void isd_stop() {
Serial.println("Stopping...");
isd_send_command(ISD_OPCODE_STOP, 0);
}

void setup() {
spi_init();
Serial.begin(9600);
isd_powerup();
}

void loop() {
isd_record(0);
delay(10000);

isd_stop();
delay(2000);

isd_play(0);
delay(10000);

isd_stop();
delay(2000);
}

Friday, January 4, 2008

XRandR Drawer

I do pretty much all of my computer work on my laptop. The mobility is great, but tasks that require a lot of screen real-estate, such as using eclipse, can be a real pain on a small screen. Thus, I use an external LCD when I'm at my desk. Back when I used Windows, it was a breeze to extend your desktop, and it's not too bad in Linux once you figure out your xorg.conf file.

Since my current laptop sports an Intel graphics chipset, one of the things I've been able to fully take advantage of is xrandr, which essentially lets you change your xorg configuration on the fly. This is great because it's very simple to use, doesn't require root access, and lets you make changes without restarting your X server (something extremely handy when you move around a lot).

There are a few programs that provide a GUI for xrandr, but from my experiences with them, they all seem to be buggy or hard to use. This lack of a simple way to control your external monitor led me to create my own: by adding a drawer and a few custom application launchers to your gnome panel, you can create a simple and fast way to manipulate your screen(s).

Here are the shortcuts that I use:
  • "External Monitor to the Left"
    xrandr --output VGA --auto --left-of LVDS
  • "External Monitor to the Right"
    xrandr --output VGA --auto --right-of LVDS
  • "Clone Main Screen"
    xrandr --output VGA --auto --same-as LVDS
  • "No External Monitor"
    xrandr --output VGA --off
It's as simple as that. I believe that nvidia-settings has similar command-line functionality, so people with nvidia cards can do this too.