My deadly code the destroys every chip it touches.

I am using arduino duemilanove w/atmega328.

I have some code i am writing that responds to a GSM module by sending the AT command to send the text message "hello" to a certain number, using the PDU format.

I also have some code that puts the atmega328 to sleep for about 8 seconds using the watchdog timer and is woken up by an externally triggered interrupt.

Both worked fine in many many tests in isolation, but when i tried to combine the the two, so that my arduino tells the GSM to send a text if it receives one, even if it was asleep at the time is when the trouble happens.

When i upload the following will happen, the LED attached to D13 will start flashing very rapidly, i can no longer load any new programs onto the board, not even blink, i get the following error if i try:

avrdude: stk500_getsync(): not in sync: resp=0x15
avrdude: stk500_disable(): protocol error, expect=0x14, resp=0x78

This has happened on three different atmega328 chips, it will occur either as soon as i upload my dodgy program, or the program will run and work, successively sending sms to a phone but if i cut power to the arduino by removing the USB cable to the computer, the problem occurs.

I can reburn the bootloader to fix the chips i've been told but this isn't what is important, what i really need to know is what is so wrong with my code that it ruins every chip that it touches? What programming crime have i commited here? I really have no idea...

#include <avr/sleep.h>
#include <avr/wdt.h>

#ifndef cbi
	#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif

#ifndef sbi
	#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif	

int sms_ready = 0; //change to 0 when not testing!!!
int de_holder = 0;

int octets_send = 18; //for now leave at 18 for test code "hello"

int pin_wake = 2;

volatile boolean watchdog_expired = 1; //see "Example of MMIO In C" on the page http://en.wikipedia.org/wiki/Volatile_variable for volatile to make sense

void setup(void)
{
	Serial.begin(9600);
	
	attachInterrupt(0,sms_received,LOW); //the GSM will send a pin low for 120ms when a sms is received, it will b connected to interupt pin0 (Dpin2)
	
	pinMode(pin_wake,INPUT);
	
	cbi(SMCR,SE);      // sleep enable, power down mode
	cbi(SMCR,SM0);     // power down mode
	sbi(SMCR,SM1);     // power down mode
	cbi(SMCR,SM2);     // power down mode	

	setup_watchdog(9);
	
	//instruction set here(?)
	//0000, read tank
}

void loop(void)
{	
	if(watchdog_expired == 1)
	{
		watchdog_expired = 0;	
		
		//---actual program in here---//
		check_sms();
		//----------------------------//
		
		int i;
		for(i = 2; i <= 13 ; i++)
		{
			pinMode(i,INPUT); 	// set all ports to input to save power
		}

		system_sleep();
	}	
}

//------------------------------------------------------------------------------------------------//
//tank end specific functions                                                                     //
//------------------------------------------------------------------------------------------------//

//AT+CMGL=<stat>[,<mode>]
//<stat>:	0, received unread
//		1, received read
//		2, stored unsent
//		3, stored sent
//		4, all
//
//<mode>:	0, normal
//		1, do not change status of specified sms record (i think this means it will leave an unread message as unread despite having just read it)

void check_sms(void)
{
	if(sms_ready == 1)
	{
		Serial.print("\r"); //so that any noise that might have reaching the GSM Rx is removed
		delay(1000);
		octets_send = 18/*chungs code*/; //for now leave at 18 for test code "hello"
		Serial.print("AT+CMGS=");
		Serial.print(octets_send,DEC);
		Serial.print("\r");
		delay(1000); //waiting for OK response from modem
		Serial.print("0001000B811634527505F8000005E8329BFD06"); //ugly re-encoded HEX for the GSM to send back to server/phone //for now its code to send a text to specific person
		delay(1000);
		Serial.print(0x1A,BYTE); //ctrl+Z
		delay(4000);
		sms_ready = 0;
	}
}

//interrupt handler: when an sms is received
void sms_received(void)
{
	if(de_holder == 0)
	{
		//don't forget to timer based functions in here like serial.print, delay etc can be put in the interrupt function
		sms_ready = 1;	
		watchdog_expired = 1;
		de_holder = 1;
	}	
}

//friends phone numbers in PDU format:
//i ommited this in this forum post for obvious reasons
//
//sample texts:
//E8329BFD06 hello

//int cnt;

//------------------------------------------------------------------------------------------------//
//sleep/watchdog functions                                                                        //
//------------------------------------------------------------------------------------------------//
// set system into the sleep state 
// system wakes up when watchdog is timed out
void system_sleep(void) 
{
	/* 	
	The 5 different modes are:
	SLEEP_MODE_IDLE         -the least power savings
	SLEEP_MODE_ADC
	SLEEP_MODE_PWR_SAVE
	SLEEP_MODE_STANDBY
	SLEEP_MODE_PWR_DOWN     -the most power savings
     	*/
	
	cbi(ADCSRA,ADEN);                    	// switch Analog to Digitalconverter OFF

	set_sleep_mode(SLEEP_MODE_PWR_DOWN);	// sleep mode is set here
	sleep_enable();

	/*
	In the function call attachInterrupt(A, B, C)
	A   can be either 0 or 1 for interrupts on pin 2 or 3.   
	B   Name of a function you want to execute at interrupt for A.
	C   Trigger mode of the interrupt pin. can be:
	
	LOW        a low level triggers
	CHANGE     a change in level triggers
	RISING     a rising edge of a level triggers	
	FALLING    a falling edge of a level triggers

	In all but the IDLE sleep modes only LOW can be used.
	*/	

	attachInterrupt(0,sms_received,LOW); 	// use interrupt 0 (pin 2) and run function
                                       		// go_to_loop when pin 2 gets LOW 
	de_holder = 0;
	sleep_mode();                        	// System sleeps here						}THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
	sleep_disable();                     	// System continues execution here when watchdog timed out	}THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP

	sbi(ADCSRA,ADEN);                    	// switch Analog to Digitalconverter ON
}

void setup_watchdog(int ii) 
{
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms} ii is 0,1,2...9
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec		}

	byte bb;
	int ww;
	if (ii > 9 ) ii = 9;
	bb = ii & 7;
	if (ii > 7) bb |= (1 << 5);
	bb |= (1 << WDCE);
	ww = bb;
	Serial.println(ww);

	MCUSR &= ~(1 << WDRF);
	// start timed sequence
	WDTCSR |= (1 << WDCE) | (1 << WDE);
	// set new watchdog timeout value
	WDTCSR = bb;
	WDTCSR |= _BV(WDIE);
}

// Watchdog Interrupt Service / is executed when  watchdog timed out
ISR(WDT_vect) 
{
	watchdog_expired = 1;  // set global flag
}

Your code seems avr code rather than Arduino. Some stuffs like cbi, sbi made by Arduino platform on background.
You should look deeply Arduino learning section.

IMHO it's unlikely the code is cracking your chips, I'd put hardware set-up as number one suspect, especially when you manipulating power line. Injection current in digital/analog input limited to 1-5 mA for Atmega chips. Check connection with external circuitry, or post schematic.

hardware setup doesn't appear to be a problem, i should have mentioned that the last time i "broke" the chip all i had was an arduino connected to absoultely nothing except for the PC via USB cable

I wouldn't do this in setup:

	attachInterrupt(0,sms_received,LOW); //the GSM will send a pin low for 120ms when a sms is received, it will b connected to interupt pin0 (Dpin2)

Put it into system_sleep just before you sleep. Otherwise the system will be dragged down to very poor performance as it gets a low signal on pin 2.

Also disable that interrupt immediately it occurs, like this:

void sms_received(void)
{
    detachInterrupt(0);   // don't want more interrupts on LOW state of pin 

  // blah blah    

}

A few comments wouldn't hurt here:

	byte bb;
	int ww;
	if (ii > 9 ) ii = 9;
	bb = ii & 7;
	if (ii > 7) bb |= (1 << 5);
	bb |= (1 << WDCE);
	ww = bb;
        attachInterrupt(0,sms_received,LOW); //the GSM will send a pin low for 120ms when a sms is received, it will b connected to interupt pin0 (Dpin2)
	
	pinMode(pin_wake,INPUT);

Those two statements are the wrong way round, although it shouldn't matter unless you have previously used the pin as an output. However, depending on the GSM device, you might need to enable the internal pullup on that pin, and if so, that should also be done before attaching the interrupt.

I doubt the chips are "bricked". I'm thinking the ATmega is either too busy or to sleepy? to respond to the upload request from the IDE. I have run into this situation before and the way I usually am able to get around it is to send the upload signal to the Arduino immediately following bootup. Try the following.

  1. Make sure your code is ready in the IDE and get ready to click the upload button.
  2. Plug the serial cable into the Ardunio
  • Assuming here there is no external power and the Arduino is off
  1. Watch the LED blink during bootup (takes roughly 4 seconds or so)
  2. When the LED stops blining hit the upload button ASAP!
  • More than 1 second can be too long...

It sounds like a pain to do each time, but it should help you get back to troubleshooting.

Hope it helps.

willnue

You are right willnue, they aren't quite bricked as i can reburn the bootloader using another arduino and the chips will work fine again.

I'll give all these suggestions a go and report back soon, thanks for all the help guys, this is so frustrating and tbh embarrassing! :stuck_out_tongue:

Are you fiddling with the fuses? It shouldn't normally be possible to alter the bootloader, and therefore you shouldn't need to reburn it.

LevPewPew:
I'll give all these suggestions a go and report back soon, thanks for all the help guys, this is so frustrating and tbh embarrassing! :stuck_out_tongue:

Don't worry. I'm sure we have all been there many times and if my solution works for you then we will both feel a little bit better.

willnue

PS. I can't tell you how many hours I have wasted troubleshooting only to find out I had the wrong board type selected in the IDE. Talk about frustration...

I fixed it by moving the attach interrupt and inserting the detach interrupt as Nick suggested, and everything seems to be working fine =) I also remove all connections to the Tx and Rx of my GSM module just to be safe though.

No am not fiddling with fuses but I was using the reburning of the bootloader as the uC equivalent of reformatting windows to fix my problem :stuck_out_tongue: