Why UART module keeps on sending data?

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

Using ATtiny104 + GCC.

 

I have the following UART functions:

void UARTInit(void)
{
    power_usart_enable();

    UBRRH = (uint8_t)(BAUDRATE >> 8);
    UBRRL = (uint8_t)(BAUDRATE & 0x00FF);

    UCSRA |= _BV(U2X);                // Double speed
    UCSRB  = _BV(RXEN) | _BV(TXEN);   // Enable RX & TX
    UCSRC  = _BV(UCSZ1) | _BV(UCSZ0); // Character size 8-bit
}

void UARTSendByte(uint8_t byte)
{
    while (!(UCSRA & _BV(UDRE)));
    UDR = byte;
}

uint8_t UARTGetByte(void)
{
    while (!(UCSRA & _BV(RXC)));
    return UDR;
}

void UARTSendArray(uint8_t arr[], uint8_t size)
{
	for (uint8_t i = 0; i < size; i++)
		UARTSendByte(arr[i]);
}

 

I'm using them in the following function that communicates with a DFPlayer module (does not matter if you are not familiar with it):

 

int16_t DFPlayerSendCommand(uint8_t command, uint8_t parameter)
{
	int16_t returnVal = -1;
	uint8_t  tempCommand[10] = {0x7E ,0xFF ,0x06 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0xEF};
	int16_t  checksum;

	tempCommand[3] = command;

	if (parameter < 256)
		tempCommand[6] = parameter;
	else
	{
		tempCommand[5] = (uint8_t)(parameter >> 8);
		tempCommand[6] = (uint8_t)parameter;
	}

	checksum = _DFPlayerChecksum(tempCommand);

	tempCommand[7] = (uint8_t)(checksum >> 8);
	tempCommand[8] = (uint8_t)checksum;

	UARTSendArray(tempCommand, 10);

	// Wait for feedback
	if ((command == DFPLAYER_GET_VOLUME) || (command == DFPLAYER_GET_EQ ) || (command == DFPLAYER_GET_TF_FILES ))
	{
		uint8_t tempMessage[10];
		int16_t messageChecksum;

		for (uint8_t i = 0; i < 10; i++)
			tempMessage[i] = UARTGetByte;

		messageChecksum = (tempMessage[7] << 8) | (tempMessage[8]); // Glue --> int16_t

		// MSG OK?
		if ((tempMessage[0] == DFPLAYER_RX_START_BYTE) && (tempMessage[9] == DFPLAYER_RX_END_BYTE) && (messageChecksum == _DFPlayerChecksum(tempMessage)))
		{
			return tempMessage[6];
		}

	}

	return returnVal;
}

Here what happens here...

I'm inserting the command (parameter) into the command message, in the specific case I'm testing command = 3 & parameter = 1.

the parameter is inserted as well, followed by the checksum.

The array is sent out using one of the above functions.

 

If I comment out the rest of the function after 

UARTSendArray(tempCommand, 10);

the array is sent out as should (this was verified).

If I don't, then the array will not send correctly and instead the AVR will send an endless stream of the following values: 0xFE, 0xF9, 0x7E. Not in this particular order, and it seems like 0xF9 is the dominant value. By the way 0xF9 is not a part of the checksum values, 0xFE & 0x7E are. The strange thing is that the if condition that appears right after the sent array command should not evaluate as true because those macros all have different values:

#define DFPLAYER_PLAY_FILE     0x03
#define DFPLAYER_GET_VOLUME    0x43
#define DFPLAYER_VOLUME_UP     0x04
#define DFPLAYER_VOLUME_DOWN   0x05
#define DFPLAYER_GET_EQ        0x44
#define DFPLAYER_GET_TF_FILES  0x47

And I have checked this using the simulator and indeed the code is not executed.

Any suggestions for the cause of this strange behavior?

Last Edited: Sat. Dec 2, 2017 - 11:02 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have not shown the code of UARTSendArray()? Surely this could be the crux of the thing?

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

Sorry about it, I didn't mark all the code while copy & paste. Updated in the original post.

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

Presumably if you simply set a breakpoint after the call to uartSendArray() then equally it completes OK even with that following code present?

 

As it's a synchronous routine I cannot see any way in which the code that follows it could possibly affect its operation.

 

BTW I cannot help noticing that tiny104 is a 1K micro. This couldn't be that the code image has simply grown too big could it and that removing that following code brings it back into size range?

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

From the build report:

 

Program Memory Usage : 492 bytes   48.0 % Full

Data Memory Usage : 2 bytes   6.3 % Full

 

The code posted above really almost all the code in the application.

I will try using a breakpoint and report, until now I simply commented out the rest of the code. I am using the ATtiny104 xplain nano board which does not have a real debugger and I was naive enough to think I could avoid using a debugger.

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

clawson wrote:
BTW I cannot help noticing that tiny104 is a 1K micro.
And with only 32 bytes of RAM. The complete function has 26 bytes of local data, the version with the commented part has 14 bytes. So ...

Stefan Ernst

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

slow_rider wrote:
Data Memory Usage : 2 bytes 6.3 % Full
What Stefan just said highlights the futility of this figure for "Data Memory Usage". It's really "Data memory usage allocated at link time" and does not take into account dynamic/stack frame allocation.

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

The HEX file is over 2k in size... so that might be a problem. Is that being copied 1:1 to flash?

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

No, hex files are a bit more than twice the FLASH image size.

 

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

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

slow_rider wrote:
The HEX file is over 2k in size... so that might be a problem.

As Jim says, the flash "consumption" is not equal to the size of the hex file. Hex files are encoded, are record-oriented with record type tags, record lengths, destination addresses and checksums taking up space in the file that will never actually end up in the flash memory. The actual flash contents are binhex-encoded so that one byte of actual flash memory contents takes up two bytes in the hex file. So hex file is more than double the size of the actual flash consumption. How much more depends largely on how "fragmented" the hex file is - i.e. how small the records are. The extreme degeneration (never seen this in real life) would be one hex record for each byte of flash. This case would have 12 bytes in the hex file for each byte of actual flash contents, i.e. 12 times the size. For more on the hex file format, look no further than to the Wikipedia article on the subject.

 

All that aside, for the flash consumption the memory report at the end of the build is the final word - and you have:

Program Memory Usage : 492 bytes   48.0 % Full

No problems there.

 

As has been noted above, you are not so good when it comes to RAM consumption. I have not checked the details here (not on Windows with Studio available for a simulation) but your peak RAM consumption could well be more than 32 bytes. You have not shown a complete program, so we do not know the details of how DFPlayerSendCommand() is called but lets assume it is called directly from main.
Sketchy, guesstimative, breakdown:

Statically allocated:                       2 bytes (From the build memory report)

Startup code calls main():                  2 bytes (return address pushed on stack)

main() calls FPlayerSendCommand()
  i)  Used registers must be saved by
      pushing them onto the stack           ? bytes
  ii) Call                                  2 bytes (return address pushed onto the stack)
  
Local array in FPlayerSendCommand()        10 bytes (uint8_t tempCommand[10])

Local array in FPlayerSendCommand()        10 bytes (uint8_t tempMessage[10])

FPlayerSendCommand() calls UARTSendArray()
  i)  Used registers must be saved by
      pushing them onto the stack           ? bytes
  ii) Call                                  2 bytes (return address pushed onto the stack)

UARTSendArray() calls UARTSendByte()
  i)  Used registers must be saved by
      pushing them onto the stack           ?
  ii) Call                                  2 bytes (return address pushed onto the stack)

  GUESSTIMATE TOTAL                        30 bytes plus the '?' unknowns for register preservation

 

I might very well have missed out on something so it might be worse than the above sketch.

 

You are overflowing your RAM.

 

With 32 bytes of RAM, at least the below techniques must be considered:

 

  • You must be as absolutely conservative with RAM usage (i.e. variables) as at all possible.
  • In general consider using global variable rather than passing parameters to functions. This will reduce RAM footprint in many situations, but not in all.
  • Re-use/re-purpose global variables. (Example: You are allocating two arrays of 10 uint8_t's. Since they are not used at the same time, replace them with one such array, used for both things. Whether to allocate it as a local variable or as a global "depends on things".)

 

You have chosen a microcontroller that is extremely challenged with respect to available RAM. These things are normally intended for very simple applications, e.g. basic regulator stuff trying to keep a parameter (think temperature) within bounds of an upper and a lower limit. Or a simple parameter reader-and-sender (reads temperature, sends on UART). That kind of stuff..

 

Doing a game control with string handling and messaging and checksumming using a tiny104 could well be a case of "wrong AVR model chosen". It at least requires very good knowledge of what the compiler does: how it generates code, how it allocates space for variables etc. Very good knowledge. This is what will help you with decisions like "allocate this thing as a local or a global?".

 

There are AVRs that have e.g. 256 bytes of RAM. Consider moving to such a model.

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]

Last Edited: Sat. Dec 2, 2017 - 06:30 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm also starting to think that the MCU is too "small" and perhaps I should move up to something like the ATtiny441 which has 4k flash + 256 bytes of RAM. In order to reduce RAM usage, the commands could be stored in code space using PROGMEM attribute. This could work for all the commands that do not require a parameter, because the checksum can be calculated ahead. The problem is that even if this works I still need to add more stuff to the code and at the end space will run out on the flash as well. I'll order some ATtiny441s...

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

slow_rider wrote:
 256 bytes of RAM. 

That is still a very, very small amount of RAM!!

 

Why are you deliberately making things difficult for yourself.

 

Surely, it would be far easier to start with a chip with plenty of RAM to get your system working in the first place, and then think about optimising it once it is actually working.

 

Concentrate first on getting your system working - not on fancy tricks to minimise RAM usage!

 

As the old saying goes, "premature optimisation is a root of all kinds of evils!"

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For all but the smallest applications, and with a sound design, the fraction of code that is written for a specific hardware will be relatively small.

 

Do the sane thing: Get an Arduino board. Use it as the prototyping, design and test platform. Once the application is relatively complete you will have a good picture of how much RAM and flash you need. This will then be the base for the final selection of AVR model.

 

Yes, you will need to keep in mind that a smaller AVR might have peripherals with less functionality. Use just the functionality you expect from your final selection. No magic solution, but better than starting out in the dark with what you hope will be the final device selection and fail. Perhaps several times.

 

A chinese Arduino board will cost you just a few $, so get a spare or two when you're at it.

 

If you want to stay in the tiny range then get the largest one you can find - for development.

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

To be honest you shouldn't be hitting this RAM limit now. If you follow a sensible design strategy then during the specification stage you will have done peripheral/pin, time and memory budgets and during the latter you will have a pretty strong idea of both total flash and RAM usage. Then you make the final chip choice. Then you write the detailed specification. Finally you start to design prototype electronics and start code implementation. This way you shouldn't get any nasty surprises at the point of implementation. 

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

I've ported the code to an ATmega128 and now the send function works as intended. How can I check how much RAM is being used at any given moment and is there any kind of checker that makes sure I won't overflow at runtime?

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

is there any kind of checker that makes sure I won't overflow at runtime?

Yes:

https://github.com/ezharkov/ezstack

... although it has limitations.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

joeymorin wrote:
has limitations.

like having no documentation - and not even any comments in the source code ?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

like having no documentation - and not even any comments in the source code ?

Among others.  It was written from our very own @ezharkov, who has made it available without much support.  Bummer, but it has been a useful to me and others.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

If I may, I would like to get back to the original post wink

I did some minor improvement to the function:

int16_t DFPlayerSendCommand(uint8_t command, uint8_t parameter)
{
	uint8_t tempCommand[10] = {0x7E ,0xFF ,0x06 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0xEF};
	int16_t checksum;
	
	tempCommand[3] = command;
	
	if (parameter < 256)
		tempCommand[6] = parameter;
	else
	{
		tempCommand[5] = (uint8_t)(parameter >> 8);
		tempCommand[6] = (uint8_t)parameter;
	}
	
	checksum = _DFPlayerChecksum(tempCommand);
	
	tempCommand[7] = (uint8_t)(checksum >> 8);
	tempCommand[8] = (uint8_t)checksum;
	
	UARTSendArray(tempCommand, 10);
	
	// Wait for feedback
	if ((command == DFPLAYER_GET_VOLUME) || (command == DFPLAYER_GET_EQ ) || (command == DFPLAYER_GET_TF_FILES ))
	{
		for (uint8_t i = 0; i < 10; i++)
			tempCommand[i] = UARTGetByte;
			
		checksum = (tempCommand[7] << 8) | (tempCommand[8]); // Glue --> int16_t
			
		// MSG OK?
		if ((tempCommand[0] == DFPLAYER_RX_START_BYTE) && (tempCommand[9] == DFPLAYER_RX_END_BYTE) && (checksum == _DFPlayerChecksum(tempCommand)))
			return tempCommand[6];
	}
	
	return -1; // Nothing to return
}

Both tempCommand & checksum are being re-used in the second part of the code (poll for UART RX) in order to save on RAM.

I've confirmed UARTSendArray(tempCommand, 10); send the correct arrays and could see the correct response from the external module on a terminal program.

 

On the next part of the function I poll the UART for 10 incoming bytes. I do get 10, however they are all the same (0xED) from some reason. It also important to note that 0xED is no part of the expect response from the external module, which should be 7E FF 06 43 00 00 1E FE 9A EF.

Last Edited: Mon. Dec 4, 2017 - 01:11 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

slow_rider wrote:
I do get 10, however they are all the same (0xED) from some reason.
0xED is the lower byte of the address of the function UARTGetByte. There is a pair of parentheses missing.

Stefan Ernst

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

How embarrassing blush

You are absolutely correct!

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

If I may, I would like to get back to the original post wink

Hey, whatever, man.  You asked the question.

and is there any kind of checker that makes sure I won't overflow at runtime?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

joeymorin Don't get offended. This was not a direct response to your last comment.

 

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

slow_rider wrote:
If I may, I would like to get back to the original post 

Well, the original question was, 

you wrote:
Any suggestions for the cause of this strange behavior?

 

That question has been answered some time ago - we are now well into follow-on questions!

 

cheeky

 

Maybe time for a new thread ... ?

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Don't get offended

It'll take a lot more than that ;-)

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]