[SOLVED][C]Bluetooth/USART interrupt interference

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hi,
I'm working on a ATmega168 project. the node has also a 3-axis accelerometer and a bluetooth transceiver (WT12).
the accelerometer is connected to the micro via SPI and the transceiver via USART.
the program does the following:

.inizialization
.read some paramenters from the internal eeprom, if precedently stored
.enter a loop
- read acc. data
- calculate some features
- send data (16 byte packet via usart/BT)
- wait the end of the cycle (10ms)

it can recieve some comands via BT in the form: 'i' '4' where 'i' selects the parameter (ex. variable id) and '4' is the new value for the variable. these commands are handled as interrupts on USART_rx.
here comes my troubles... I've noticed some arbitrary changes on some of these values, and the only vay to change them is reading from eeprom at the beginning or via USART commands from the pc.
here is an example:

in the file eeprom.h

void readEeprom(void)
{
	uint8_t eepromData;
        ...
        //read idCube
        eeprom_busy_wait();
        eepromData = eeprom_read_byte((uint8_t*)7);
        if (eepromData == 0xff)
	      idCube = IDCUBE_DEFAULT;
        else
	      idCube = eepromData;
        ...
//other parameters have the same form
}

in the file UART.h


void init_UART(void)
{
	//--------------------------------------
	//UART init
	// control reg.A: set only U2X for baudrate
	UCSR0A |= (U2XPARAMETER<<U2X0);
	// control reg.B: Enable Receiver and Transmitter. 
        //Enable RX interrupt. 8 data bit (UCSZ2=0)
	UCSR0B = (1<<RXCIE0)|(0<<TXCIE0)|(0<<UDRIE0)|(1<<RXEN0)|(1<<TXEN0)|(0<<UCSZ02);
	// control reg.C: asincronous uart, no parity, 1 stop bit, 8 data bit
	UCSR0C = (0<<UMSEL00)|(0<<UMSEL01)|(0<<UPM01)|(0<<UPM00)|(0<<USBS0)|(1<<UCSZ01)|(1<<UCSZ00);
	// baud rate
	UBRR0H = 0;
	UBRR0L = BAUDRATEPARAMETER;
	//--------------------------------------------------------
}

ISR(USART_RX_vect)
{
	uint8_t datoUART;
	datoUART = UDR0;
      ...
      if (datoUART == 'i')		//id
	{
		loop_until_bit_is_set(UCSR0A, RXC0);
		idCube = UDR0;
		eeprom_busy_wait();
		eeprom_write_byte((uint8_t*)7, idCube);
	}
}


void sendPacket(int16_axis sample, uint8_t confLedPrecedente, uint8_t stato)
{
	
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = 'i';
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = idCube;				
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = configurationH;
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = configurationL;
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = confLedPrecedente;		
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = sample.x;
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = (sample.x>>8);			
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = sample.y;
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = (sample.y>>8);	
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = sample.z;
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = (sample.z>>8);		
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = stato;  			// 10 
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = 0; //resByte   		
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = 0; //resByte			
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = 0; //resByte;
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = 'f'; 
	return;
}

idCube is global var. uint8_t
sometimes it sends me the correct idCube (default = 9), but after I try to change it (set it to 1) it sends me strange values ( ex. 82 or 101). this variable isn't usad in any other piece of code, and the rest of the program (read acc. data, features ecc) works well... I thought that, until the same char 'i' is sent as the first bit in every packet, it could interact with the interrupt, but I had same results changing the command to 'w'. I also checked the tranceiver config but it is ok.

any help/advice is appriciated...
thank you,
bo.

Last Edited: Sun. Mar 1, 2009 - 03:54 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

:shock: Eeew! You define functions in a header (.h) file? Not a good idea. For better programming practices, check out:

[TUT] [C] Modularizing C Code: Managing large projects

Not your problem, but I had to comment.

There are several things going on here that I would change. First off:

ISR(USART_RX_vect)
{
   uint8_t datoUART;
   datoUART = UDR0;
      ...
      if (datoUART == 'i')      //id
   {
      loop_until_bit_is_set(UCSR0A, RXC0);
      idCube = UDR0;
      eeprom_busy_wait();
      eeprom_write_byte((uint8_t*)7, idCube);
   }
}

Two things wrong here. First, you should never "delay" in an ISR. The loop_until_bit_is_set() is a delay. While you are in the ISR, no other interrupts can be handled. Delays in the ISR just "lock" the machine up.

Instead, capture the character from the UART, throw it in a circular buffer, and have a higher level (non-ISR) routine check for changes and handle them.

For tutorials on using the UART and interrupt-driven UARTs, check out:

[TUT] [SOFT] Using the USART - Serial communications

[TUT] [SOFT] Using the USART - Interrupt driven serial comms

Next issue with that routine -- the EEPROM code will (potentially) wait on an interrupt. Thus, it's probably a bad idea to have that code in an ISR. Again, I recommend moving all code not directly associated with capturing the byte from the UART out of the ISR. In your upper-level (non-ISR) code, recognize the change to idCube and store the value in the EEPROM there.

Next issue: How is idCube defined? Whenever you have a value changed in an ISR that you expect to be seen in upper level code, you should declare that variable as volatile. For more information, check out FAQ #1 in:

AVR-libc Manual: Frequently Asked Questions

Also check out:

Introduction to the "Volatile" Keyword

Next: Why do you have all of your UART receive code in an ISR, but the transmit code in non-ISR code? It's not illegal, but it is weird. Again, set up a circular buffer for the output and have it run from another ISR. The above tutorials should clue you in.

That's the obvious stuff right off.

Stu

Edit 1: PS: I added Dave Hyland's circular buffer code as an attachment. Note that the header file contains code for both C and C++ and presents the appropriate form for each.

Attachment(s): 

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thanks a lot!
I'll definetly change that ISR! I was already thinking about using a circular buffer/ISR for the transmit code ;)
I haven't started this project so I'm organizing everythig right now from a messy similar C/ASM project. it's my first large project, so i'm still looking for the right way to handle everythig (headers, function defs, global vars, ...)
thanks again for the tips!
cheers,
bo.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There is an excellent tutorial in the Tutorials forum on how to organise "large" projects. It explains how to structure your .c and .h files. Go search it out. IIRC the terms "large" and "projects" was used in the title.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think it's the same tutorial that Stu already linked in his post and now I'm following it... ;)
thanks,
bo.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For uart w. interrupts , have a look here (code from danni)

https://www.avrfreaks.net/index.p...

/Bingo

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I think it's the same tutorial that Stu already linked

Ooops! Sorry for any confusion.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

... I tryed everything but it don't work properly!
now my situation is:

I initialize the UART0 without enabling the RX interrupt, which is enabled just before the infinite loop.
I've got a global volatile uint8_t command that is initialized to 9 just before the infinite loop.
then it loops on:
.read accelerometer
.compute some features
.send_packet()
. if (checkCommand == 1)
checkCommand = 0;
.wait for cycle time

now the uart routines are:

************************************************************
// routine interrupt intRx_uart
ISR(USART_RX_vect)
{
	uint8_t datoUART;
	datoUART = UDR0;

	if (checkCommand == 0)
	{
		command = datoUART;
		checkCommand = 1;
	}
}

void UART_send_packet()
{
	uint8_t dummy;

	UCSR0B |= (0<<RXCIE0);
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = 'i';
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = command; 
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = configurationH;
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = configurationL;
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = 'f';
	loop_until_bit_is_set(UCSR0A, UDRE0);
	while ( UCSR0A & (1<<RXC0) ) dummy = UDR0;
	UCSR0B |= (1<<RXCIE0);
	return;
}

when I start the program it sends me a command = 0x52 always. if i send a new value, it reads it properly and starts sending the new value. now command is changed in only 2 places: in the beginning when initialized to 9, and in the ISR, so I think that somehow the isr is executed at the beginning and catches this strange value. i tryed every combination of enabling/disabling the usart RX and the usart RX interrupt, and flushing the UDR0 when not needed...
I'm shure that everything else works fine, but here I'm losing days debugging this uart recieve...
thanks for every help...
bo.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I solved all the problems!
the problems were generated at the restart of the system, and lead to a first interrupt that wasn't supposed to come so it was mis-handled.
I found 2 possible solutions:
1. setting a timer for a 5 sec timeout, after the init of the system, but before enabling the uart_rx_int. in this way I discarded all the stuff recieved at the beginning.
2.(my actual implementation) I implemented a command start/stop: after initalization the program waits for a uart_rx with the char 's' and then starts normal program flow (sample-compute-send). in this way I also can use limited functions of the whole program, ex. sample-send raw data, or sample-compute but send only on request and a sleep mode.
thanks everyone for the support.
bye,
bo.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you have a working HCI stack or are you running in iWRAP mode?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sorry if I didn't answered you...
we are using the iWRAP stack from bluegiga, which is implemented on the wt12.