Hello!
I had an erratic circuit on my hands the day before, most likely to some dumb beginner's mistake, but I cant figure it out. Before you ask I don't have an oscilloscope to test it with (I am currently shopping for one).
I made a simple quick timer for a friend, that is supposed to beep regularly after 15 s or 30 s or 1 min intervals selected by a button press (for exercising). For that purpose I have:
a msp430g2432 uC,
a 10k pullup to !RST,
a pjezo buzzer connected to P1.4 and P1.5,
a button to P1.3,
a external watch crystal
I am using a breadboard.
The current code I am using:
#include <msp430.h>
#include <sys/types.h>
#define BUZZ1 BIT5
#define BUZZ2 BIT4
#define BUZZ_DIR P1DIR
#define BUZZ_OUT P1OUT
#define BTN_DIR P1DIR
#define BTN_IN P1IN
#define BTN_OUT P1OUT
#define BTN_REN P1REN
#define BTN BIT3
#define BEEP_LENGHT 200
#define BEEP_FREQ 200
#define BEEP_PAUSE 8000
#define TIMER_15S 1024 // 2s currently for testing
void initialize(void);
static void __inline__ delay(register uint16_t n);
void beep(int);
void start_timer(void);
void stop_timer(void);
int mode = 0;
int main(void)
{
delay(1);
initialize();
delay(1);
while (1) {
}
}
void initialize(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
BUZZ_OUT &= ~(BUZZ1 + BUZZ2); // off
BUZZ_DIR |= BUZZ1 + BUZZ2; // Set as output
BTN_DIR &= ~BTN; // Set input
BTN_REN |= BTN; // Enable pulldown
P1IES &= ~BTN; // low -> High is selected with IES.x = 0.
BTN_OUT &= ~BTN; // Set pulldown
P1IFG &= ~BTN; // To prevent an immediate interrupt, clear the flag for P1.3 before enabling the interrupt.
P1IE |= BTN; // Enable interrupts for P1.3
BCSCTL3 |= XCAP_3; //12.5pF cap- setting for 32768Hz crystal
delay(50000); // let crystal stabilize
BCSCTL1 |= DIVA_3; // ACLK/8
_BIS_SR(LPM3_bits + GIE); // Enter LPM3 w/ interrupt
}
static void __inline__ delay(register uint16_t n)
{
__asm__ __volatile__ (
"1: \n"
" dec %[n] \n"
" jne 1b \n"
: [n] "+r"(n)
);
}
void start_timer(void)
{
TACCR0 = 0; // Stop timer
TACTL = MC_0; // Halt timer
switch (mode) {
case 1:
TACCR0 = TIMER_15S; // 512 -> 1 sec, 30720 -> 1 min
break;
case 2:
TACCR0 = TIMER_15S * 2;
break;
case 3:
TACCR0 = TIMER_15S * 4;
break;
default :
beep(4);
return;
break;
}
TACTL = TASSEL_1 + ID_3 + MC_1 + TACLR; // ACLK, /8, upmode, clear timer
TACCTL0 = CCIE; // Enable interrupts for CCR0.
}
void stop_timer(void)
{
TACCR0 = 0; // Stop counting
TACTL = MC_0; // Halt timer
TACCTL0 &= ~CCIE; // Disable interrupts for CCR0.
}
void beep(int times)
{
int i;
BUZZ_OUT |= BUZZ1;
while (times>0) {
times--;
i = 0;
while (i<BEEP_LENGHT) {
i++;
BUZZ_OUT ^= BUZZ1 + BUZZ2;
delay(BEEP_FREQ);
}
delay(BEEP_PAUSE);
}
BUZZ_OUT &= ~(BUZZ1 + BUZZ2); // off
}
__attribute__((interrupt(TIMERA0_VECTOR)))
void Timer_A (void)
{
beep(mode);
}
__attribute__((interrupt(PORT1_VECTOR)))
void Btn_press(void)
{
stop_timer();
switch(P1IFG&BIT3) {
case BIT3:
P1IFG &= ~BIT3; // clear the interrupt flag
mode++;
if (mode>3) {
mode = 0;
break;
}
beep(mode);
if (mode != 0) {
start_timer();
}
break;
default:
P1IFG = 0; // probably unnecessary, but if another flag occurs
// in P1, this will clear it. No error handling is
// provided this way, though.
break;
}
delay(65000);
P1IFG &= ~BIT3; // clear the interrupt flag
}
I am powering it with a 3.3V from mains power supply that I made for another project, but latter I want to use a 3V button cell.
The circuit and code works more or less as it should, but ONLY when I am touching one of the power rails with my finger! If not, the uC just freezes and does no beeping.
My main hypotheses as of why it is happening, was that the power supply is too noisy and I acted as a smoothing capacitor, but I tried adding capacitors of various values to no effect and I have powered other uC projects from the same supply before.
Now I am only guessing.. to little noise to start the quartz crystal oscillating (I am suspicious that it doesn't work that way) that my body is inducing in the circuit as a antenna? - tried adding a long wire to power rail and wrapping it around noisy lamp. No.
Wrong loading capacitances for external watch crystal (I am using soft controlled 11pF ones from the MSP430, I have no idea what is the required values for my crystal) - tried changing it whit some 2.2pF parts in series. Nope (? I guess it should at least function, if with wrong frequency, and see no reason for it to work perfectly when I am touching the ) or 3.3V wire).
I suspect that the problem is connected to the fact that I am using deep sleep mode in my uC and waking up only to service timer interrupts (that is driven by the external crystal) and maybe something is incorrectly configured, but I have no clue how me touching the circuit can affect it in any way..
So, if someone can point me to a possible cause for this, please let me know!
(And sorry about the long write-up. I am not a native speaker and therefore very clumsy with English.)