Jump to content
43oh

Strotoscobic guitar tuner/small devboard


Recommended Posts

-- Update 10.11.2011 --

Okay I finally had a change to test it with a real guitar and found some pretty bad hindsights on the code, They have now been corrected and at least one guitar was tuned succesfully with the device

 

 

 

This is my entry for the August POTM, I will update details here.

 

Okay so it's a small strotoscobic guitar tuner/development board for msp430 in 14 pin tssop package. It provides 6 charlieplexed leds and two high intensity leds for strobe effect/whatever, I used msp430g2211 because I had two on hand but I think any 14 pin msp430 should work.

 

The main idea here was just to test seeedstudios fusion pcb service so I needed a small 5x5cm board and somehow I decided this kind of tuner would be nice, I have seen atleast few avr based ones so it is not a new idea in any way but this is the first msp430 based one that I know of. The device seems to work nicely but since I do not own nor can I play guitar it has not yet been tested =). Im not sure how accurate the frequency needs to be but I think it should be accurate enough for ballpark tuning and I will test it at some point.

 

The design itself is pretty simple and if I would do it again there are few improvements to be made, firstly the high intensity leds could be directly connected to pwm outputs as now only ccr0 is used and I do wonder what I was thinking when I made the board =). Also as there is one extra pin maybe adding more leds by charlieplexing would have been nice. Also the resistor values for both the big leds and the charlieplexed ones must be chosen according to the used parts and some testing is propably needed. I made two and tweaked the values a bit because as can be seen from the action shot this version has very dim indicator leds and the large ones are really bright.

 

Here's a rendered view of the device

post-3273-135135506122_thumb.png

and bad photos of front, back and "action" shot

post-3273-135135506107_thumb.jpg

post-3273-135135505833_thumb.jpg

post-3273-135135505825_thumb.jpg

 

And the code:

I have tried to make it very low power on sleep but I think it can still be improved for example by larger pull-up resistors etc. I measured it at less than 1uA but the meter I had can't really measure currents so low so it can be a lot less. In use the current consumption jumps to bit less than 20mA but that can be changed by increasing the led current limiting resistors and the strobe leds are very bright reds so there is room to improve the design.

   // #include 
   // #include 
   // #include 
#include 
#include 


   /* Defines for charlieplexed leds */
   #define LED1 P1DIR &= ~BIT2; P1DIR |= 0x3; P1OUT &= ~BIT0; P1OUT |= BIT1
   #define LED2 P1DIR &= ~BIT2; P1DIR |= 0x3; P1OUT &= ~BIT1; P1OUT |= BIT0
   #define LED3 P1DIR &= ~BIT0; P1DIR |= 0x6; P1OUT &= ~BIT1; P1OUT |= BIT2
   #define LED4 P1DIR &= ~BIT0; P1DIR |= 0x6; P1OUT &= ~BIT2; P1OUT |= BIT1
   #define LED5 P1DIR &= ~BIT1; P1DIR |= 0x5; P1OUT &= ~BIT0; P1OUT |= BIT2
   #define LED6 P1DIR &= ~BIT1; P1DIR |= 0x5; P1OUT &= ~BIT2; P1OUT |= BIT0

   /* note period in us/2  */
#define E2 (12134/2)       // 82.407 Hz
   #define A2 (9090/2)             // 110.00 Hz
   #define D3 (6810/2)             // 146.83 Hz
   #define G3 (5102/2)             // 196.00 Hz
   #define B3 (4050/2)             // 246.94 Hz
   #define E4 (3034/2)             // 329.63 Hz

   //#define F_CPU 1000000 // Cpu speed is 1Mhz which is easily enough for this application
   #define POWER_ON_COUNT 15

   void wait(int cycles)
   {

       unsigned int i;
       volatile int j;
       for(i=0; i        {
           j++;
       }

   }

   void SetupHardware(void);
   void SetupTimer(void);
   inline void sleep_prepare(void);
   void Set_DCO(unsigned int Delta);

   volatile unsigned char calibrate=0;
   volatile unsigned int calibtime=0;
   volatile unsigned int sleeptime;
   volatile unsigned int period = E2;
   volatile unsigned char mode;
   volatile unsigned char btn_flag = 1;
   volatile unsigned int wakeup_flag;
volatile unsigned int toglestate = 0;
volatile unsigned int ledofftime = (E2 >> 1);


   int main(void)
   {

       SetupHardware(); // Init hardware
       wait(0xfffe); // Small delay before calibration
       Set_DCO(244); // Calibrate 1Mhz
       SetupTimer();   // Init TIMERA
       eint(); // Enable interrupts
       while(1)
       {


           if(btn_flag)  // Button was pressed
           {
               btn_flag = 0; // Clear button pressed flag
               if(calibrate)
               {
                   calibrate = 0;
				wait(0xfffe); // Small delay before calibration
                   Set_DCO(244); // Calibrate DCO with external crystal
                   SetupTimer(); // Set timerA back to application use.
               }
               switch(mode)  // Change mode if needed
               {
               case 0:
                   period = E2;
                   LED1;
                   break;
               case 1:
                   period = A2;
                   LED2;
                   break;
               case 2:
                   period = D3;
                   LED3;
                   break;
               case 3:
                   period = G3;
                   LED4;
                   break;
               case 4:
                   period = B3;
                   LED5;
                   break;
               case 5:
                   period = E4;
                   LED6;
                   break;

               }
			ledofftime = period >> 2; // shuts down the leds so the duty cycle is ~12.5%
			TACCR0 = period;
			TACCR1 = ledofftime;
              _BIS_SR(LPM0_bits + GIE); // Shut down cpu, only interrupts and timers using SMCLK needed
           }

       }
       return 0;
   }

   interrupt (WDT_VECTOR) Watchdog_timer_interrupt(void)
   {
       sleeptime++; // Increase shutdown timer
       if(sleeptime > 30)  // If 30 seconds have elapsed go to sleep
       {
           sleeptime = 0;
           sleep_prepare(); // Prepare hardware for low power mode
           wakeup_flag = 1; // Set flag to notify that LPM was active
           _BIS_SR_IRQ(LPM4_bits + GIE); // Enter LPM4 with interrupts
       }

   }

   interrupt (TIMERA0_VECTOR) TimerInterrupt(void) //Timer CCR0 interrupt
   {
	if(toglestate)
	{
		P1OUT |= BIT4;
	}
	else
	{
		P1OUT |= BIT5;
	}
	toglestate = !toglestate;
   }

interrupt (TIMERA1_VECTOR) LedOffInterrupt(void)
{
switch( TAIV )
{
	case 2: // CCR1 interrupt
		P1OUT &= ~(BIT4 | BIT5);
		break;
	default:
		break;
}

}

   interrupt (PORT1_VECTOR) Sw12Interrupt(void)
   {
       sleeptime = 0;
       switch(P1IFG&0xC0)
       {
       case BIT6:
           P1IFG = 0x0;
           btn_flag = 1;
           if(!wakeup_flag)
           {
               if(++mode > 5)
               {
                   mode = 0;
               }
           }
           break;
       case BIT7:
           P1IFG = 0x0;
           btn_flag = 1;
           break;
       default:
           btn_flag = 1;
           P1IFG = 0x0;
           break;
       }
       if(wakeup_flag && btn_flag)
       {
           calibtime++; // Increase calibration constant, calibrate device every POWER_ON_COUNT boots
           WDTCTL = WDT_ADLY_1000 ;  //WDT interval mode on ACLK for 1000ms
           IE1 |= WDTIE; // Enable watchdog interval interrupt
           wakeup_flag = 0;
           if(calibtime > POWER_ON_COUNT)
           {
               calibrate = 1;
           }
           _BIC_SR_IRQ(LPM4_bits); // Exit LPM4 mode
       }
       // Exit LPM0 mode to run main loop, could use LPM3 etc but leds take
       // so much power that it's basically a moot point.
       _BIC_SR_IRQ(LPM0_bits);
   }

   inline void sleep_prepare(void)
   {
       P1DIR = ~(BIT6 | BIT7); // Set everything but button inputs to output
       P1OUT = (BIT6 | BIT7); // Set SW1 and SW2 pull-up resistors high
       WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
       IE1 &= ~WDTIE; // Disable watchdog interrupt
   }

   void SetupHardware(void)
   {
       WDTCTL = WDT_ADLY_1000 ;  //WDT interval mode on ACLK 1000ms
       BCSCTL1 = CALBC1_1MHZ; //Calibrated 1Mhz clock
       DCOCTL = CALDCO_1MHZ;
       IE1 |= WDTIE; // Enable watchdog interval interrupt
       BCSCTL3 |= XCAP_3; // Crystal oscillator load capacitor setting, 12.5pf
       P1DIR |= (BIT4 | BIT5); // Set HC led pin directions to output
       P1OUT &= ~(BIT4 | BIT5);
       P1DIR &= ~(BIT6 | BIT7); // Set SW1 and SW2 pins to input
       P1REN |= (BIT6 | BIT7); // Enable SW1 and SW2 pull-up resistors
       P1OUT |= (BIT6 | BIT7); // Set SW1 and SW2 pin pull-up resistors high;
       P1IES |= (BIT6 | BIT7); // Set SW1 and SW2 interrupt on high->low transition
       P1IE |= (BIT6 | BIT7); //Enable SW1 and SW2 interrupts
   }
   void SetupTimer(void)
   {
       TACTL = TASSEL_2 + ID_0 + MC_1 ; // set timer to 1Mhz and continuous mode
       TACCR0 = period;
TACCR1 = ledofftime;
TAR = 0;
       TACCTL0 = CM_0 + CCIE + CCIFG; // Enable CCR0 interrupts
TACCTL1 = CM_0 + CCIE + CCIFG; // Enable CCR0 interrupts
   }



   /* Calbiration code from DCO calibration thread page 2 by zeke, only modified to stop watchdog interval
   timer and to start it again in the end*/
   //--------------------------------------------------------------------------
   void Set_DCO(unsigned int Delta) // Set DCO to F_CPU
   //--------------------------------------------------------------------------
   {
       unsigned int Compare, Oldcapture = 0;
       WDTCTL = WDTPW + WDTHOLD;
       IE1 &= ~WDTIE;
       BCSCTL1 |= DIVA_3; // ACLK = LFXT1CLK/8
       TACCTL0 = CM_1 + CCIS_1 + CAP; // CAP, ACLK
       TACTL = TASSEL_2 + MC_2 + TACLR; // SMCLK, cont-mode, clear

       while (1)
       {
           while (!(CCIFG & TACCTL0)); // Wait until capture occured
           TACCTL0 &= ~CCIFG; // Capture occured, clear flag
           Compare = TACCR0; // Get current captured SMCLK
           Compare = Compare - Oldcapture; // SMCLK difference
           Oldcapture = TACCR0; // Save current captured SMCLK

           if (Delta == Compare)
               break; // If equal, leave "while(1)"
           else if (Delta < Compare)
           {
               DCOCTL--; // DCO is too fast, slow it down
               if (DCOCTL == 0xFF) // Did DCO roll under?
                   if (BCSCTL1 & 0x0f)
                       BCSCTL1--; // Select lower RSEL
           }
           else
           {
               DCOCTL++; // DCO is too slow, speed it up
               if (DCOCTL == 0x00) // Did DCO roll over?
                   if ((BCSCTL1 & 0x0f) != 0x0f)
                       BCSCTL1++; // Sel higher RSEL
           }
       }
       TACCTL0 = 0; // Stop TACCR0
       TACTL = 0; // Stop Timer_A
       BCSCTL1 &= ~DIVA_3; // ACLK = LFXT1CLK
       WDTCTL = WDT_ADLY_1000 ;  //WDT interval mode on ACLK for 1000ms
       IE1 |= WDTIE; // Enable watchdog interval interrupt
   }

 

Also attached is project zip file which SHOULD include everything and also the gerbers I sent to seeed. Let me know if I forgot some files from the package

 

BOM for the parts I used:

resistors and caps as usual.

32.768KHz crystal: digikey part 539-9032-ND

mosfets were BSS123 and BSS138 (I made two of these and for some reason used different parts in them but either one will work fine) digikey part BSS123CT-ND and BSS138W-FDICT-ND

Battery holder digikey part BAT-HLD-001-ND

Buttons: Mouser part 101-TS6111T1602-EV

Large leds: digikey part 754-1274-ND

small leds were some random green 0805 smd:s

msp430tuner.zip

Link to post
Share on other sites

I'll take a guess and you can tell me how close I am.

 

The two LEDs are strobed at the specific frequency to tune a string. For example, A = 440Hz.

 

So then you point the LEDs at the second thickest string and pluck it. Then tune the string until its standing wave matches the strobing of the LEDs.

 

How close am I? :angel:

Link to post
Share on other sites

By the way, I think you should take a drive down to your nearest guitar shop and sit down with a guitar and try it out.

 

I bet you any money that if the store manager sees what you've got there that he'll be begging you to make some for him to sell.

Link to post
Share on other sites

gwdeveloper: The rendering is from Autodesk inventor, I just made the parts quickly and combined them to create that mockup. The coloring was done in Inkscape but I could have used the settings of the inventor for that too but I was just playing around and only have access to inventor at works because my laptop is too slow for it and running linux =)

 

 

zeke: Yes thats exactly how it works, you just select the string with SW1 and pluck the string and point the leds to it. There is a commercial one that works just like this also, I just do not remember the maker at the moment.

Link to post
Share on other sites
  • 1 month later...

Definitely make a how-to-use video, that be the biggest thing. Saw something similar on hackaday the other day, but that involved putting rgb leds beneath the strings, which is a bit better as you don't have to worry about correctly positioning the board so it points at the strings while you pluck the string (a bit awkward).

 

http://hackaday.com/2010/11/03/rgb-stro ... ar-tuning/

Link to post
Share on other sites

Thanks for the people who voted for me in the POTM,I would make a video but as I don't own a guitar it is a bit difficult =), I did measure another one I made with msp430f2012 using oscilloscope and the frequencies were quite nicely what they should be.

Oh and yes the name is a typo and I did not check whether it was the correct spelling so my bad.

Link to post
Share on other sites
Oh and yes the name is a typo and I did not check whether it was the correct spelling so my bad.

Congratulations! I was waiting for a confirmation on the spelling as you used it twice in your writeup. I'll have to correct the blog. nobody also mentioned it.

 

You also get a chance to have your PCB made by DP. However, I'll have to confirm it. He did mention it.

Link to post
Share on other sites

Great project, Andy. We have written a blog post about it. Check it out at the official MSP430 blog at E2E TI portal.

 

Since I am a new user, I am unable to provide a straight link. But you can navigate through google by searching for "the official MSP430 blog" and looking for your project blog post there.

 

Enjoy! And remember to keep us at TI updated with any future projects!

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...