Tardy bus responses causing problems, odd behavior observed

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

I am using one of the UART interfaces on my ATMEGA128RFA1 to talk to an external device. The external device responds to all commands sent to it, but the response time varies (can be ms or multiple seconds). All messages from the device end with a .

I have the following code to check for responses:

uint8_t devCheckRxData(void) {
	uint8_t nextByte = 0;
	uint8_t prevByte = 0;
	uint8_t devMsgStat = DEV_NO_MSG;
	uint16_t rxByteCount, i;
	static uint16_t index = 0;
		

	if(!devRxFlag) {		//Only check for new data if the last message was processed
		
		if(index == 0) {
			devBufCnt = 0;
		}

		rxByteCount = ringBufferGetCount(&rxBufferDev);
	
		if(rxByteCount > (DEV_BUF_SIZE - index)) {
			fprintf_P(&comExt_str, PSTR("Warning - checkDevRxData(): devBuffer overflow condition, discarding latest [unread] data.\n"));
			for(i = 0; i < rxByteCount; i++) {
				ringBufferRemove(&rxBufferDev);
			}
		}
		else if(rxByteCount > 0) {
			for(i = index; i < (index + rxByteCount); i++) {
				prevByte = nextByte;
				nextByte = ringBufferRemove(&rxBufferDev);
				devBuffer[i] = nextByte;		//ringBufferRemove(&rxBufferDev);
				devBufCnt++;
			}

			if((prevByte == 13) && (nextByte == 10) && (devBufCnt > 0)) {		//All messages from modem end with 
				devMsgStat = DEV_COMPLETE_MSG;
				devRxFlag = 1;
				index = 0;
			}
			else {
				devMsgStat = DEV_PARTIAL_MSG;
				index = devBufCnt - 1;
			fprintf(&comExt_str, "devBufCnt (inside): %d\n", devBufCnt);  //DEBUG HERE
			}
			
		}
	}

	return(devMsgStat);
}

devRxFlag, devBuffer, and devBufCnt are all global variables. Ring buffer functions are Dean's.

I call the above function like this:

	if(ringBufferGetCount(&rxBufferDev)) {
			devCheckForResponse();
		}

void devCheckForResponse(void) {
	uint8_t rxResult = 0;

	DEV_KICK = 0;
	while((rxResult != DEV_COMPLETE_MSG) && (!DEV_KICK)) {
		rxResult = devCheckRxData();
	}
	//Feed the watchdog
	wdt_reset();

	DEV_KICK = 0;
}

Where DEV_KICK is a global variable set to one by a WDT interrupt. It is the only variable modified by the ISR, and is declared as volatile.

The odd behavior is that the code seems to work as expected when I have the fprintf towards the end of the first function above (noted by //DEBUG HERE). When I remove that fprintf call, the function does not work (usually times out, due to watch dog). I realize fprintf calls add delays, etc., to a program, so this seems indicative of another problem lurking in the code that gets masked by the fprintf call.

I am using avr-gcc.

Does anything stand out in the functions above that should be altered by the addition of a simple fprintf statement?

Edit: the idea here is to "synchronize" the MCU and the device. I.e., it may take seconds for the device to respond, but once it starts to respond, it transmits the data continuously. Hence, I look in my ring buffer for data. If there is any, I enter a blocking routine to read until I get a complete message (or time out due to the WDT). If no data is available in the buffer, I continue on through the main loop. I implemented this because my code was receiving unpredictable msg fragments from the device, because it would read the buffer as the device was transmitting to it.

Science is not consensus. Science is numbers.

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

Follow up:

I tried making the variable devBufCnt volatile (though I don't think it should need to be, as it is not used in any ISRs) and removing the fprintf statement (in the last "else" in the post above, marked be "//DEBUG HERE") -- and the function did not work. I.e., it did not receive the message from the device. If I put the fprintf statement back in (and remove the volatile flag), the messages get received.

I don't currently have access to a scope, so I can not guarantee that the bits are actually being transmitted from the device, but as an fprintf to the other com port should have precisely zero impact on the device, I have a relatively high degree of confidence that the message is, in fact, being transmitted to the micro-controller.

Science is not consensus. Science is numbers.

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

I have tried everything I can think of, and the facts are unchanged. When the [debug] fprintf statement is included, the function works. When the fprintf statement is removed, the function only works if the entire message is waiting in the buffer the first time (i.e., it doesn't handle the "partial" message case).

Any suggestions would be most welcome.

If my code formatting is preventing you from reading the code, let me know, and I can change the format....

Science is not consensus. Science is numbers.

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

Perhaps some information on the message structure and transmission protocol would help.

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

The transmission protocol is [LVTTL] RS-232. The message structure varies (which is the annoying part). There are no defined headers, checksums, etc. In fact, the documentation for the device is very poor. I have had to test each message individually with a sniffer on the line to see the response formats. One constant is that every message ends with a

Science is not consensus. Science is numbers.

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

Well, that's a start, but you really have provided little additional information, beyond that a message ends with cr/lf.

If an entire message will fit in your buffer, perhaps you should just check
for this sequence before attempting to parse the message.

What is the device? Perhaps someone here has already tackled this problem.

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

Thanks for showing interest.

Unfortunately, I cannot divulge the device. It is not a particularly common device (but not that rare either). I doubt many people try to talk to it with a 8 bit microcontroller. The haphazard way the responses are structured implies to me that they expect something with a lot of processing time/memory to be parsing the incoming messages.

There really is not a whole lot of other information to provide with regards to the message structure -- because there isn't any. I know that I am not experiencing overflow. My uart rx buffer is a ring buffer, and my local rx buffer is 300 bytes. The max expected message is on the order of 50 bytes.

Could you expand on your suggestion to check for that sequence before attempting to parse the message? I think that is what I'm trying to do in the function that extracts data from the ring buffer. What I really don't understand is how a simple fprintf statement changes function behavior. In the past this was due to an oversight (on my part) w /regards to a volatile variable that was not declared volatile...

Science is not consensus. Science is numbers.

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

Declare 'prevByte' static.

Without the debug statement, you are processing 0 or 1 new byte on each call to devCheckRxData(), and 'prevByte' has forgotten what the previous byte really was.

The debug statement provides enough delay, so that on the next call to devCheckRxData() the entire message is waiting.

I don't know how committed you are to this code, but it might simplify things if you moved the cr/lf detection into the uart rx routine. Set a flag there, and in main() only check for messages when that flag is set.

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

Originally, I didn't think it had to be static, but that was based on the assumption that there would always be at least two bytes in the ring buffer. In the scenario where the entire message except for the final terminating is received the first time through and the the is received alone the second time through, this assumption would be false, and the code would break. I am not so sure about the delay -- I can't be sure (because I have tried so many different things), but I believe one of the things I tried was putting a small delay in the function in place of the fprintf. In any case, I will try the static and see what happens.

Science is not consensus. Science is numbers.

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

Quote:

Tardy bus responses causing problems, odd behavior observed

Yes, I've seen odd behaviour from the restless queue at the stop when the bus is late.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

I used to live next to a bus stop. You can see ALL kinds of odd behavior observing the people waiting...

Science is not consensus. Science is numbers.

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

Dodgy public transit patrons aside, I think that Mike identified the problem. I made the variable nextByte static, and the function now works w/o the fprintf. I believe the problem was caused by the scenario I mentioned above (i.e., the entire message except for the arrives the first time around, and only the the 2nd time around).

That said, I really like the idea of checking for the end bytes in the UART rx routine -- I think it would be cleaner and more elegant. When I have some time, I'll go back and rewrite this...

Thanks for your help Mike.

Science is not consensus. Science is numbers.