Clocks, Baud Rate, _delay_ms (), F_CPU, etc...

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

Hello, colleagues!
I'm really new in AVR/ATMega, so sorry for my maybe dummy question. The questions are about clocks.
I have ATMega2560V-8AU with 7.3728MHz generator.
I want to use USART. There is a table "22.10 Examples of Baud Rate Setting" in datasheet. I want to setup 9600 8N1 UART. According to table my MCU should be initialized as 47 baud rate (9600/7.3728MHz) in UBBR.
1/9600 = 0.000104166666667Sec = 104msec per 1 bit.
Code written and compiled by AVR-GCC. :)
F_CPU defined as 7372800UL.
But Oscilloscope shows about ~800msec per bit.
Some experiments showed me that being initialized by 6 baud rate value one bit becomes about ~104ms. 6 baud rate value according to table is for 9600bps@1MHz.
I've checked _delay_ms(1000); (by LED) and LED worked about 8 secs. So I've divided time by 8 and tested again _delay_ms(1000/8);. And it was about one second. Then I've undefined F_CPU, got "warning F_CPU..." and _delay_ms(1000); gave me one second of blue LED light. But oscilloscope shows 800msec per one bit with 47 UBBR value.

How should I correctly setup USART and _delay_ms();?

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

A factor of 8? ;-)

Guess who forget to clear the CKDIV8 fuse when enabling the 7.3728 clock ;-)

(BTW you can over-ride the CKDIV8 fuse in your software by setting CLKPR to 0 (two writes does it) - it's well worth putting that at the top of programs for all AVRs that have CLKPR so it doesn't matter whether you've switched the irritating fuse or not).

in fact all AVR programs could use:

__attribute__((OS_main)) int main(void) {
#ifdef CLKPR
   CLKPR = (1<<CLKPCE);
   CLKPR = 0; // this must be within 4 cycles - sets /1
#endif
etc.

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

Great thanks, clawson!
That worked.
Can you tell me - is there any way to set initial value of some port? I need to set the port E (UART port on ATMega2560) to FF.
So I could turn power on and see that port E is at FF.

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

Nope the AVR powers on with the default values given in the datasheet for all registers which includes all PORT and all DDR register = 0x00 which means all I/O are high-Z inputs without pull-up.

Even in C the chances are your C compiler has SOME mechanism by which you can get some code executed very early in the startup process. For example:

__attribute__((naked,section(".init3"))) void early(void) {
  DDRB = 0xF0;
  PORTB = 0xAA;
}

This would run just a few cycles after power on (but note there are restrictions on what you can do in a routine such as this - don't rely on RAM contents being set up yet).

The other alternative is to wire external pull-up (or perhaps pull-down) resistors in your design so that the moment power is applied the resistors drive the pin in a certain direction until the code in the AVR can get things under control itself.

Cliff

EDIT: as a full example:

#include 
#include 

char buff[5];
char test[] = "hello";

__attribute__((naked,section(".init3"))) void early(void) {
  DDRB = 0xF0;
  PORTB = 0xAA;
} 

int main (void)
{
    while (1)
    { 
                       
    }
}

leads to:

00000054 <__ctors_end>:
  54:	11 24       	eor	r1, r1
  56:	1f be       	out	0x3f, r1	; 63
  58:	cf e5       	ldi	r28, 0x5F	; 95
  5a:	d4 e0       	ldi	r29, 0x04	; 4
  5c:	de bf       	out	0x3e, r29	; 62
  5e:	cd bf       	out	0x3d, r28	; 61

00000060 :
#include 

char buff[5];
char test[] = "hello";

__attribute__((naked,section(".init3"))) void early(void) {
  60:	80 ef       	ldi	r24, 0xF0	; 240
  62:	87 bb       	out	0x17, r24	; 23
  DDRB = 0xF0;
  PORTB = 0xAA;
  64:	8a ea       	ldi	r24, 0xAA	; 170
  66:	88 bb       	out	0x18, r24	; 24

00000068 <__do_copy_data>:
  68:	10 e0       	ldi	r17, 0x00	; 0
  6a:	a0 e6       	ldi	r26, 0x60	; 96
  6c:	b0 e0       	ldi	r27, 0x00	; 0
  6e:	e0 ea       	ldi	r30, 0xA0	; 160
  70:	f0 e0       	ldi	r31, 0x00	; 0
  72:	02 c0       	rjmp	.+4      	; 0x78 <.do_copy_data_start>

00000074 <.do_copy_data_loop>:
  74:	05 90       	lpm	r0, Z+
  76:	0d 92       	st	X+, r0

00000078 <.do_copy_data_start>:
  78:	a6 36       	cpi	r26, 0x66	; 102
  7a:	b1 07       	cpc	r27, r17
  7c:	d9 f7       	brne	.-10     	; 0x74 <.do_copy_data_loop>

0000007e <__do_clear_bss>:
  7e:	10 e0       	ldi	r17, 0x00	; 0
  80:	a6 e6       	ldi	r26, 0x66	; 102
  82:	b0 e0       	ldi	r27, 0x00	; 0
  84:	01 c0       	rjmp	.+2      	; 0x88 <.do_clear_bss_start>

00000086 <.do_clear_bss_loop>:
  86:	1d 92       	st	X+, r1

00000088 <.do_clear_bss_start>:
  88:	ab 36       	cpi	r26, 0x6B	; 107
  8a:	b1 07       	cpc	r27, r17
  8c:	e1 f7       	brne	.-8      	; 0x86 <.do_clear_bss_loop>
  8e:	0e 94 4d 00 	call	0x9a	; 0x9a 
92: 0c 94 4e 00 jmp 0x9c ; 0x9c <_exit>

while .init1 gets it even earlier:

__attribute__((naked,section(".init1"))) void early(void) {
  DDRB = 0xF0;
  PORTB = 0xAA;
} 

int main (void)
{
    while (1)
    { 
                       
    }
}

leading to:

Disassembly of section .text:

00000000 <__vectors>:
   0:	0c 94 2a 00 	jmp	0x54	; 0x54 
   4:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
   8:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
   c:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
  10:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
  14:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
  18:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
  1c:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
  20:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
  24:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
  28:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
  2c:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
  30:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
  34:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
  38:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
  3c:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
  40:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
  44:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
  48:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
  4c:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>
  50:	0c 94 4b 00 	jmp	0x96	; 0x96 <__bad_interrupt>

00000054 :
#include 

char buff[5];
char test[] = "hello";

__attribute__((naked,section(".init1"))) void early(void) {
  54:	80 ef       	ldi	r24, 0xF0	; 240
  56:	87 bb       	out	0x17, r24	; 23
  DDRB = 0xF0;
  PORTB = 0xAA;
  58:	8a ea       	ldi	r24, 0xAA	; 170
  5a:	88 bb       	out	0x18, r24	; 24
  5c:	11 24       	eor	r1, r1
  5e:	1f be       	out	0x3f, r1	; 63
  60:	cf e5       	ldi	r28, 0x5F	; 95
  62:	d4 e0       	ldi	r29, 0x04	; 4
  64:	de bf       	out	0x3e, r29	; 62
  66:	cd bf       	out	0x3d, r28	; 61
etc.

Note this is only for GCC - for other compilers the technique will be different.

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

Thank you, Cliff. I've made some experiments with early initialization but lets start with the main question.
On the oscilloscope I see that my ATMega program correctly sends byte to the UART. I see it right after MCU and after MAX.
But when I send 0x55 I get 0xB5 or 0xF5 on PC-side. And when I hold reset button I get part of zeros, but some times don't get zeros.
Can you suggest what should I fix to get data on PC side?

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

Quote:

Can you suggest what should I fix to get data on PC side?

PCs UARTs always work at the right speed so if you are getting framing errors it is your AVR that is at fault. Somewhere round here it tells you that 99.9% of UART errors are timing problems - so your AVR is probably not being clocked right.

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

clawson wrote:
Somewhere round here it tells you that 99.9% of UART errors are timing problems

Now where was it that I saw that before? It's like I can see it right in front of me...

Science is not consensus. Science is numbers.

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

Quote:

On the oscilloscope I see that my ATMega program correctly sends byte to the UART. I see it right after MCU

Does "correctly" include "at correct speed"?

Quote:
That worked.

Are you sure? Are you sure you're actually running at 7.3... MHz? That is quite close to 8 MHz, which is the frequency of the default internal RC oscillator. That one is generally not good enough for UART work, and it is definitively too far away from 7.3... MHz for the UBBR values to produce a correct baud rate.

Read out the fuse bits from your AVR and report them here.

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

Quote:
It's like I can see it right in front of me...
Or right above me, as the case may be ;)

Regards,
Steve A.

The Board helps those that help themselves.

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

Quote:
Does "correctly" include "at correct speed"?

Now I'm really not sure.

Quote:
Read out the fuse bits from your AVR and report them here.

# avrdude -c jtagmkII -P usb -p m2560 -v

avrdude: Version 5.10, compiled on Jul 29 2011 at 18:20:55
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2009 Joerg Wunsch

         System wide configuration file is "/usr/local/etc/avrdude.conf"
         User configuration file is "/root/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : usb
         Using Programmer              : jtagmkII
avrdude: usbdev_open(): Found JTAGICE mkII, serno: 070000003C7B
JTAG ICE mkII sign-on message:
Communications protocol version: 1
M_MCU:
  boot-loader FW version:        255
  firmware version:              6.06
  hardware version:              0
S_MCU:
  boot-loader FW version:        255
  firmware version:              6.06
  hardware version:              1
Serial number:                   07:00:00:00:3c:7b
Device ID:                       JTAGICEmkII
         AVR Part                      : ATMEGA2560
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PA0
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    10     8    0 no       4096    8      0  9000  9000 0x00 0x00
           flash         65    10   256    0 yes    262144  256   1024  4500  4500 0x00 0x00
           lfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           lock           0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : JTAGMKII
         Description     : Atmel JTAG ICE mkII
         M_MCU hardware version: 0
         M_MCU firmware version: 6.06
         S_MCU hardware version: 1
         S_MCU firmware version: 6.06
         Serial number:          07:00:00:00:3c:7b
         Vtarget         : 3.4 V
         JTAG clock      : 891.7 kHz (1.1 us)

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e9801
avrdude: safemode: lfuse reads as 62
avrdude: safemode: hfuse reads as 19
avrdude: safemode: efuse reads as FF

avrdude: safemode: lfuse reads as 62
avrdude: safemode: hfuse reads as 19
avrdude: safemode: efuse reads as FF
avrdude: safemode: Fuses OK

avrdude done.  Thank you.
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Program built with UBBR value 47 (9600/7.3MHz) with F_CPU = 7372800.
Time measured on oscilloscope. 1 bit = 96 microsecond.

Program built with UBBR value 51 (9600/8MHz) with F_CPU = 8000000.
Time measured on oscilloscope. 1 bit = 104 microsecond.

The last is correct timing for 9600 baud. But still many garbage on PC-side. Sending 1 byte results in 74 bytes of predominantly zeros with few values.

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

0x62 in the low fuse byte suggests CKDIV8 is active - did you intend this? In fact 0x62 is the datasheet default so the chip is running at roughly 1MHz from its internal oscillator. I thought the intention here was to run it from a 7.3MHz crystal?

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

At the previous week I've measured (by LED + _delay_ms () and by 1 bit + oscilloscope) that default clock of my ATMega is 1MHz. And added

__attribute__((OS_main)) int main(void) { 
 #ifdef CLKPR 
    CLKPR = (1<<CLKPCE); 
    CLKPR = 0; // this must be within 4 cycles - sets /1 
 #endif

as you suggested.

But now I have another result.
I'm working now as on 8MHz (I don't understand why 8 - it should be 7.3 because there is external clock generator).
I use 51 UBBR and F_CPU 8MHz. And I get data on PC-side!

I think a lots of garbage is produced at the startup moment when UART is being initialized and PC receives noise on it's UART RX.
I've added 10 seconds delay after UART initialization and _before_ sending something. Before I turn MCU on, I kill the cat process (which directs data from ttyS1 to local file) then power on MCU and while it waits after UART initialization I start cat. Then I get string without noise.

Is there any way to do this automatically?

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

Quote:

(I don't understand why 8 - it should be 7.3 because there is external clock generator).

But that was my point above - you have not changed the CKSEL fuse bits - the low byte is still at the 0x62 default. If you over-ride CLKPR then you clear the effect of CKDIV8 but you are still running at 8MHz from the internal oscillator and it's pretty inaccurate so may not be exactly 8MHz so your baud rate may be borderline.