timing problem ATtiny13a 128kHz

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

I tried to set my fuses such that the chip runs at 128kHz. The objective is literally to get it to run at 128kHz.

 

The bigger goal is a battery powered device, but I read that it's probably more power efficient to run at a high clock freq. and get back to sleep faster, so I'm aware that it probably doesn't make sense to run at 128kHz, but I just want to understand what's going on. It will simply flash a LED for halve a sec, then sleep for three sec. That's it for now.

The problem is that a _delay_ms(5000); is in reality much shorter than five seconds, more like halve a second. In fact I have to #define F_CPU to about 1MHz to make it approx. five seconds: an order of magnitude bigger than expected. It looks like my chip is not actually running at 128kHz, even though I think I configured the fuses to do so.

 

My fuses: -U lfuse:w:0x7b:m -U hfuse:w:0xff:m (used engbedded fuse calc. with CKDIV8 unchecked).

any thoughts? PS: makefile and main.c attached.

Attachment(s): 

This topic has a solution.
Last Edited: Tue. Jun 11, 2019 - 05:55 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I fear you are asking too much of _delay_ms(). Your best bet is to use it more like:

void delay_seconds(uint8_t n) {
    while (n--) {
        _delay_ms(1000);
    }
}

...

  delay_seconds(5);

Or you may even need to split that up even more like:

void _delay_tenth(uint8_t n) {
    while (n--) {
        _delay_ms(100);
    }
}
void delay_seconds(uint8_t n) {
    while (n--) {
        delay_tenth(10);
    }
}

...

  delay_seconds(5);

I'm guessing _delay_ms() should easily be able to reach 100ms even at 128000UL

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


I may be having a mental aberration. Surely it is at very HIGH speed that it may overflow cycle counters, not at LOW speed? Off for quick experiment..



EDIT: OK so I did this:

 

I reset the cycle counter/stopwatch when it stopped on PORTB ^= the first time. Then I just ran it to the breakpoint again. As you can see it has taken almost exactly 5 million microseconds (the extra is the bit looping back) and it has executed almost exactly 64,000 cycles which is the right number to delay for 5s at 128kHz.

 

Ergo if you observe something different in the hardware then it is NOT running at 128kHz. The code itself builds correctly.

Last Edited: Fri. Jun 7, 2019 - 12:14 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh and just for completeness this is the code generated for _delay_ms(5000) with F_CPU = 128000UL:

	__builtin_avr_delay_cycles(__ticks_dc);
  2c:	2f ef       	ldi	r18, 0xFF	; 255
  2e:	83 ef       	ldi	r24, 0xF3	; 243
  30:	91 e0       	ldi	r25, 0x01	; 1
  32:	21 50       	subi	r18, 0x01	; 1
  34:	80 40       	sbci	r24, 0x00	; 0
  36:	90 40       	sbci	r25, 0x00	; 0
  38:	e1 f7       	brne	.-8      	; 0x32 <main+0x10>
  3a:	00 c0       	rjmp	.+0      	; 0x3c <main+0x1a>
  3c:	00 00       	nop

So it loads a 24 bit counter with 0x01F3FF then each decrement takes an SUBI and two SBCIs. It starts with 3 1 cycle LDIs, then the subtractions - those are all 1 cycle opcodes so it takes 3 cycles to subtract 1 from 1F3FF. The BRNE will branch every time except the last iteration - it is 2 cycles when it branches - 1 when it falls through at the end. The RJMP is 2 cycles and the NOP is 1 cycle.

 

So the delay here will be:

 

1 + 1 + 1

(1F3FE * (1 + 1 + 1 + 2)) +

1 + 1 + 1 + 1 +2 + 1

 

I make that 3 + 639,990 + 7 = 640,000. So _delay_ms(5000) executes 640,000 cycles at 128kHz. At that speed 1 cycle is 7.8125us so this is 640000 * 7.8125 = 5,000,000us = 5s.

 

There's no question this really is a 5 second delay IF the CPU is running at 128kHz.

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

kevink27 wrote:
My fuses: -U lfuse:w:0x7b:m -U hfuse:w:0xff:m (used engbedded fuse calc. with CKDIV8 unchecked).

I keep this site on my bookmarks right below AVRFreaks so I can check fuse settings when I need them:  http://www.engbedded.com/fusecalc/

And it shows you have set your fuses correctly for 128kHz clock rate.

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
stack gold/silver https://www.onegold.com/join/713...

 

 

 

 

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

Oh and I took your own main.c and Makefile and just stopping to add -g so I could get source I did an objdump -S on the ELF file to generate this:

00000022 <main>:
#define LED_PIN PB0

int main(void) {

  // Configure LED_PIN (PB4) as output
  DDRB |= (1 << LED_PIN);
  22:   b8 9a           sbi     0x17, 0 ; 23

  while (1) {
    PORTB |= (1 << LED_PIN);
  24:   c0 9a           sbi     0x18, 0 ; 24
        #else
                //round up by default
                __ticks_dc = (uint32_t)(ceil(fabs(__tmp)));
        #endif

        __builtin_avr_delay_cycles(__ticks_dc);
  26:   2f ef           ldi     r18, 0xFF       ; 255
  28:   83 ef           ldi     r24, 0xF3       ; 243
  2a:   91 e0           ldi     r25, 0x01       ; 1
  2c:   21 50           subi    r18, 0x01       ; 1
  2e:   80 40           sbci    r24, 0x00       ; 0
  30:   90 40           sbci    r25, 0x00       ; 0
  32:   e1 f7           brne    .-8             ; 0x2c <main+0xa>
  34:   00 c0           rjmp    .+0             ; 0x36 <main+0x14>
  36:   00 00           nop
    _delay_ms(5000);
    PORTB &= ~(1 << LED_PIN);
  38:   c0 98           cbi     0x18, 0 ; 24
  3a:   2f ef           ldi     r18, 0xFF       ; 255
  3c:   83 ef           ldi     r24, 0xF3       ; 243
  3e:   91 e0           ldi     r25, 0x01       ; 1
  40:   21 50           subi    r18, 0x01       ; 1
  42:   80 40           sbci    r24, 0x00       ; 0
  44:   90 40           sbci    r25, 0x00       ; 0
  46:   e1 f7           brne    .-8             ; 0x40 <__SREG__+0x1>
  48:   00 c0           rjmp    .+0             ; 0x4a <__SREG__+0xb>
  4a:   00 00           nop
  4c:   eb cf           rjmp    .-42            ; 0x24 <main+0x2>

There is some very familiar code in that! So those delays really are 5 seconds accurate to the exact machine cycle.

 

I suspect you have failed to set the fuses and it is at 1MHz where 5s takes 0.625s which is probably the "half second" you observed.

 

PS after you think you have set the fuses what do you get if you actually try to read them back?

 

PPS oh and this is one of these weird chips were the clock is 9.6MHz not 8MHz. So at default CKDIV8 that makes it 1.2MHz in fact so a 640,000 cycle delay would take 0.533s which is even closer to what you observed. Presumably if you set F_CPU to 1200000UL you would see the exact 5s ?

 

PPPS why -DF_CPU then #define it again? -D is preferable so remove the #define from the code file.

Last Edited: Fri. Jun 7, 2019 - 12:45 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You might already know this, but...

 

Depending upon the programming software you are using you have to specifically hit the WRITE FUSE button for the write to take place.

 

Just selecting tic boxes and pull-down's doesn't always do it.

 

JC

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

If it save power to run fast and then sleep depends a lot of your HW, and especially which voltage you want/need to run at.

In many situations AVR's (systems) use less total power by running slow at low voltage (if it can get the job done, and on a small chip like a tiny13 it is way better to use ASM).

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

Okay thanks for the effort! I'm glad the code and fuses are ok, so it must be the way I'm trying to set the fuses. I wasn't aware that reading fuses was possible, but

avrdude -c arduino -P /dev/cu.usbmodem14201 -b 19200 -p t13 -U lfuse:r:-:i -v

gives me:
 

avrdude: Version 6.0.1, compiled on Dec 16 2013 at 17:26:24
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2009 Joerg Wunsch

         System wide configuration file is "/usr/local/CrossPack-AVR-20131216/etc/avrdude.conf"
         User configuration file is "/Users/kevin/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : /dev/cu.usbmodem14201
         Using Programmer              : arduino
         Overriding Baud Rate          : 19200
         AVR Part                      : ATtiny13
         Chip Erase delay              : 4000 us
         PAGEL                         : P00
         BS2                           : P00
         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     5     4    0 no         64    4      0  4000  4000 0xff 0xff
           flash         65     6    32    0 yes      1024   32     32  4500  4500 0xff 0xff
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00
           lock           0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           calibration    0     0     0    0 no          2    0      0     0     0 0x00 0x00
           lfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00

         Programmer Type : Arduino
         Description     : Arduino
         Hardware Version: 2
         Firmware Version: 1.18
         Topcard         : Unknown
         Vtarget         : 0.0 V
         Varef           : 0.0 V
         Oscillator      : Off
         SCK period      : 0.1 us

avrdude: AVR device initialized and ready to accept instructions

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

avrdude: Device signature = 0x1e9007
avrdude: safemode: lfuse reads as 6A
avrdude: safemode: hfuse reads as FF
avrdude: reading lfuse memory:

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

avrdude: writing output file "<stdout>"
:010000006A95
:00000001FF

avrdude: safemode: lfuse reads as 6A
avrdude: safemode: hfuse reads as FF
avrdude: safemode: Fuses OK (H:FF, E:FF, L:6A)

avrdude done.  Thank you.

I'm wonder what the 95 means in "010000006A95". Anyways: lfuse is 6A and hfuse is FF, which is indeed the default 9.6 MHz devided by 8 (CKDIV8=0).

I don't use AVR studio or something where I have a "WRITE FUSE" button, but I'll try to figure out what is wrong with my makefile.

Thanks for the suggestion about assembly language. I'll stick to C / C++ for now, but will keep it in mind for when I'm getting more advanced!
 

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

Note that it does not need to run for 500ms, it just needs to wake up for a few microseconds to turn the led back on, or back off.

Within a few microseconds of running, it will always be back to sleep.  It will be running so little (program is only maybe 10-20 instructions), the power consumed will be very minimal

 

wakeup---turn led on, set timer for 500ms, sleep

wakeup---turn led off, set timer for 3000ms, sleep

repeat

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

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

Thanks @avrcandies, I'll look into how to make the chip sleep and try to do what you suggested :)

I found my main problem as well. Like @DocJC pointed out, I needed to actually write the fuses. I assumed that "make flash" did that. I did not understand makefiles - just used one that I found in a avr blink tutorial. After watching this video about Makefiles: https://www.youtube.com/watch?v=_r7i5X0rXJk, I understood that I had to do a "make fuse", which then invokes 

avrdude -c arduino -P /dev/cu.usbmodem14201 -b 19200 -p t13 -U lfuse:w:0x7b:m -U hfuse:w:0xff:m

to set the fuses. I think that worked:
 


avrdude: AVR device initialized and ready to accept instructions

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

avrdude: Device signature = 0x1e9007
avrdude: reading input file "0x7b"
avrdude: writing lfuse (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of lfuse written
avrdude: verifying lfuse memory against 0x7b:
avrdude: load data lfuse data from input file 0x7b:
avrdude: input file 0x7b contains 1 bytes
avrdude: reading on-chip lfuse data:

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

avrdude: verifying ...
avrdude: 1 bytes of lfuse verified
avrdude: reading input file "0xff"
avrdude: writing hfuse (1 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 1 bytes of hfuse written
avrdude: verifying hfuse memory against 0xff:
avrdude: load data hfuse data from input file 0xff:
avrdude: input file 0xff contains 1 bytes
avrdude: reading on-chip hfuse data:

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

avrdude: verifying ...
avrdude: 1 bytes of hfuse verified

avrdude: safemode: Fuses OK (H:FF, E:FF, L:7B)

avrdude done.  Thank you.

However, when I try to read them again, using
 

avrdude -c arduino -P /dev/cu.usbmodem14201 -b 19200 -p t13 -U lfuse:r:-:i -v

I get:
 

avrdude: Version 6.0.1, compiled on Dec 16 2013 at 17:26:24
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2009 Joerg Wunsch

         System wide configuration file is "/usr/local/CrossPack-AVR-20131216/etc/avrdude.conf"
         User configuration file is "/Users/kevin/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : /dev/cu.usbmodem14201
         Using Programmer              : arduino
         Overriding Baud Rate          : 19200
         AVR Part                      : ATtiny13
         Chip Erase delay              : 4000 us
         PAGEL                         : P00
         BS2                           : P00
         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     5     4    0 no         64    4      0  4000  4000 0xff 0xff
           flash         65     6    32    0 yes      1024   32     32  4500  4500 0xff 0xff
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00
           lock           0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           calibration    0     0     0    0 no          2    0      0     0     0 0x00 0x00
           lfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00

         Programmer Type : Arduino
         Description     : Arduino
         Hardware Version: 2
         Firmware Version: 1.18
         Topcard         : Unknown
         Vtarget         : 0.0 V
         Varef           : 0.0 V
         Oscillator      : Off
         SCK period      : 0.1 us

avrdude: AVR device initialized and ready to accept instructions

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

avrdude: Device signature = 0x000000 (retrying)

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

avrdude: Device signature = 0xffffff (retrying)

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

avrdude: Device signature = 0xffffff
avrdude: Yikes!  Invalid device signature.
         Double check connections and try again, or use -F to override
         this check.

avrdude done.  Thank you.

So I my Arduino (leonardo pro micro) as ISP is talking too fast to the slow 128kHz ATtiny. I read something about Arduino as ISP for slow clock speeds, which I'm now going to try.

Last Edited: Mon. Jun 10, 2019 - 07:47 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ISP has to be 1/4 or less of CPU speed so if you set a very low clock you have to run ISP at an astronomically low rate.

 

If you are lucky -B will slow your programmer down (not all programmers respond to -B)

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

I read that -B doesn't work for Arduino as ISP (didn't test). In the Arduino as ISP sketch from the Arduino IDE you can specify the clock speed.

I specified:

#define SPI_CLOCK     (128000/6)

And am now able to set the fuses and flash the code (also at 128kHz). Thanks for the help - everything working properly now!