Go Down

Topic: ATTiny85 port (work in progress) (Read 46037 times) previous topic - next topic

ChineseJacklee

how can I check and define speed for ATTiny85 ?

I went through bill2009's code on page 3 [glow]http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1274820597/30[/glow] many times, and can't find anywhere defines CPU speed to 8Mhz.

Anyone can help please !


graynomad

#76
Sep 23, 2010, 03:37 pm Last Edit: Sep 23, 2010, 03:48 pm by graynomad Reason: 1
Quote
ok, as of this morning I have my 8mhz attiny85 running with software serial at 4800 baud

post #44

I haven't been following this much but I do know that the 85 can run at 1 or 8MHz and I'm fairly sure it will default to 1 unless you program the fuse differently.

As for finding this in the code I don't think you will, the fuse is set by the programmer.
Rob Gray aka the GRAYnomad www.robgray.com

foxbat

Quote

how can I check and define speed for ATTiny85 ?

I went through bill2009's code on page 3 http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1274820597/30 many times, and can't find anywhere defines CPU speed to 8Mhz.

Anyone can help please !


The default speed from the factory is 1Mhz. You have to set a fuse bit to change to 8Mhz. Be super careful setting fuse bits on the ATtiny. If you change the one that selects whether the RESET pin is for reset or data then you'll lock yourself out and only a high voltage programmer can get you back.

That said, this the avrdude configuration you need to increase the clock to 8Mhz:



The 'E2' fuse value was calculated by this excellent web page:

http://www.engbedded.com/fusecalc

bill2009

Thanks, I had assumed the question was about boards.txt and answwered by pm.  nice calculator link.

foxbat

There are two more problems I've found that may or may not be an issue for others.

Firstly, the default port of the core code continues to use timer 0 for millis() and micros() timing. The ATtiny has only two timers and they are not equally capable. Timer 0 can do full PWM in the same way as we're used to with the ATmega series. Timer 1 cannot and is the less useful of the two. Therefore it makes more sense to me to move the millis() and micros() timer to timer 1 so that the app can play with timer 0 without messing up the 'clock'.

Secondly, the core code cannot do microsecond delays unless the clock speed is 16 or 8Mhz so the default 1Mhz clock is immediately a problem.

Both of those problems are in wiring.c. I modified my own copy to fix both issues. The timer0 to timer1 move definitely works but I know I'll be off slightly on my fix to delayMicroseconds() due to my lack of knowledge about how many instructions each line of C++ compiles down to. Feedback on that would be appreciated.

Here's the code:

Code: [Select]

/*
 wiring.c - Partial implementation of the Wiring API for the ATmega8.
 Part of Arduino - http://www.arduino.cc/

 Copyright (c) 2005-2006 David A. Mellis

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General
 Public License along with this library; if not, write to the
 Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 Boston, MA  02111-1307  USA

 $Id: wiring.c 585 2009-05-12 10:55:26Z dmellis $

 Modified 28-08-2009 for attiny84 R.Wiersma
 Modified 14-108-2009 for attiny45 Saposoft
*/

#include "wiring_private.h"

// the prescaler is set so that timer0 ticks every 64 clock cycles, and the
// the overflow handler is called every 256 ticks.
#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))

// the whole number of milliseconds per timer0 overflow
#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)

// the fractional number of milliseconds per timer0 overflow. we shift right
// by three to fit these numbers into a byte. (for the clock speeds we care
// about - 8 and 16 MHz - this doesn't lose precision.)
#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
#define FRACT_MAX (1000 >> 3)

volatile unsigned long timer0_overflow_count = 0;
volatile unsigned long timer0_millis = 0;
static unsigned char timer0_fract = 0;

//different name, TIMER0_OVF_vect to this
ISR(TIMER1_OVF_vect)
{
     // copy these to local variables so they can be stored in registers
     // (volatile variables must be read from memory on every access)
     unsigned long m = timer0_millis;
     unsigned char f = timer0_fract;

     m += MILLIS_INC;
     f += FRACT_INC;
     if (f >= FRACT_MAX) {
           f -= FRACT_MAX;
           m += 1;
     }

     timer0_fract = f;
     timer0_millis = m;
     timer0_overflow_count++;
}

unsigned long millis()
{
     unsigned long m;
     uint8_t oldSREG = SREG;

     // disable interrupts while we read timer0_millis or we might get an
     // inconsistent value (e.g. in the middle of a write to timer0_millis)
     cli();
     m = timer0_millis;
     SREG = oldSREG;

     return m;
}

unsigned long micros() {
     unsigned long m, t;
     uint8_t oldSREG = SREG;
     
     cli();      
     t = TCNT1;
 
#ifdef TIFR0
     if ((TIFR0 & _BV(TOV0)) && (t == 0))
           t = 256;
#else
     if ((TIFR & _BV(TOV1)) && (t == 0))
           t = 256;
#endif

     m = timer0_overflow_count;
     SREG = oldSREG;
     
     return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}

void delay(unsigned long ms)
{
     unsigned long start = millis();
     
     while (millis() - start <= ms)
           ;
}

/* Delay for the given number of microseconds.  Assumes a 8 or 16 MHz clock.
* Disables interrupts, which will disrupt the millis() function if used
* too frequently. */
void delayMicroseconds(unsigned int us)
{
     uint8_t oldSREG;

     // calling avrlib's delay_us() function with low values (e.g. 1 or
     // 2 microseconds) gives delays longer than desired.
     //delay_us(us);

#if F_CPU >= 16000000L
     // for the 16 MHz clock on most Arduino boards

     // for a one-microsecond delay, simply return.  the overhead
     // of the function call yields a delay of approximately 1 1/8 us.
     if (--us == 0)
           return;

     // the following loop takes a quarter of a microsecond (4 cycles)
     // per iteration, so execute it four times for each microsecond of
     // delay requested.
     us <<= 2;

     // account for the time taken in the preceeding commands.
     us -= 2;
#elif F_CPU == 8000000L
     // for the 8 MHz internal clock on the ATmega168

     // for a one- or two-microsecond delay, simply return.  the overhead of
     // the function calls takes more than two microseconds.  can't just
     // subtract two, since us is unsigned; we'd overflow.
     if (--us == 0)
           return;
     if (--us == 0)
           return;

     // the following loop takes half of a microsecond (4 cycles)
     // per iteration, so execute it twice for each microsecond of
     // delay requested.
     us <<= 1;
   
     // partially compensate for the time taken by the preceeding commands.
     // we can't subtract any more than this or we'd overflow w/ small delays.
     us--;
#elif F_CPU == 1000000L
     // for the 1 MHz internal clock on the ATtiny85

     // for a <16 microsecond delay, simply return.  the overhead of
     // the function calls takes more than 16 microseconds.

     if(us<16)
           return;

     us-=16;

     // the following loop takes 4 microseconds (4 cycles)
     // per iteration, so execute it for a quarter of the delay
     us >>= 2;

     // partially compensate for the time taken by the preceeding commands.
     // we can't subtract any more than this or we'd overflow w/ small delays.
     us--;
#else
#warning MCU speed not supported by delayMicroSeconds()!
#endif

     // disable interrupts, otherwise the timer 0 overflow interrupt that
     // tracks milliseconds will make us delay longer than we want.
     oldSREG = SREG;
     cli();

     // busy wait
     __asm__ __volatile__ (
           "1: sbiw %0,1" "\n\t" // 2 cycles
           "brne 1b" : "=w" (us) : "0" (us) // 2 cycles
     );

     // reenable interrupts.
     SREG = oldSREG;
}

void init()
{
     // this needs to be called before setup() or some functions won't
     // work there
     sei();

// default values for timer 0 (fast pwm)
     
     sbi(TCCR0A, WGM01);
     sbi(TCCR0A, WGM00);

// set timer 0 prescale factor to 64

     sbi(TCCR0B, CS01);
     sbi(TCCR0B, CS00);

// setup timer 1 for the millis() and micros() interrupt because it's
// less likely to be wanted by the application

     sbi(TCCR1, CS12);                        // clk/64
     sbi(TCCR1, CS11);                        // clk/64
     sbi(TCCR1, CS10);                        // clk/64
     sbi(TIMSK, TOIE1);                  // overflow interrupt enable (see handler above)

     // set a2d prescale factor to 128
     // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
     // XXX: this will not work properly for other clock speeds, and
     // this code should use F_CPU to determine the prescale factor.
/* added F_CPU prescaler */
#if F_CPU >= 16000000L //128
     sbi(ADCSRA, ADPS2);
     sbi(ADCSRA, ADPS1);
     sbi(ADCSRA, ADPS0);
#elif F_CPU >= 8000000L //64
     sbi(ADCSRA, ADPS2);
     sbi(ADCSRA, ADPS1);
#else                        //8
     sbi(ADCSRA, ADPS1);
     sbi(ADCSRA, ADPS0);
#endif
     // enable a2d conversions
     sbi(ADCSRA, ADEN);
}


ChineseJacklee

Thank you all very much, I think the checking speed of Attiny CPU problem I was asking is defined in the boards.txt.

ChineseJacklee

Actually, I just found out when I use one Arduino with RF(434mhz,http://www.sparkfun.com/commerce/product_info.php?products_id=8946 from sparkfun) together, the softserial does NOT work.

How I connect them is:

1. Arduino pin 2 (Pin 2 is set as Tx in the softserial) to Transmitter model "data in" pin,and
2. Receiver model "data out" pin to the Arduino (the same Arduino as above) pin 3 (Pin 3 is set as Rx in the softserial)

the problems disappear if I user either of following solutions:
1. Removing RF models, so the Pin2 is directly connect with Pin3
2. use standard hardware serial Pins (Pin 0 and Pin 1)

Can anyone help me out please, I spent days on it and still can't work it out !

moustic

I read in another thread that RF modules should not shere the same ground.

ChineseJacklee

The transmitter's ground is connected with Arduino's ground, but the receiver is powered by a separate battery (the receiver's ground is connected with battery's ground). So they are NOT sharing the same ground.

Also, remember if I change to hardware serial Pins, everything works well (the grounds connections is the same with softserial).

bill2009

per my PM, check that the software serial is working at the right baud rate by connecting it to your PC.  I assume this is a tiny 85 - right?  Mine will not work at 9600 which could easily be the default for the rf module.


also, the 85 doesn't have hardware serial so you must be switching chips when you try that.

foxbat

Quote

Actually, I just found out when I use one Arduino with RF(434mhz,http://www.sparkfun.com/commerce/product_info.php?products_id=8946 from sparkfun) together, the softserial does NOT work.

If you have taken a factory fresh ATtiny85 and changed boards.txt to say it runs at 8Mhz without explicitly flashing the corresponding fuse byte then software serial will not work and neither will anything else that relies on timing because your MCU is still running at the factory default of 1MHz.

foxbat

...and I just checked the source code for SoftwareSerial and it uses delayMicroseconds() which is only implemented for 16Mhz and 8Mhz MCU's as I documented in my previous posts in this thread. So you're going to have to flash your fuses up to 8Mhz (or 16Mhz if you want to use the internal PLL) or help with extending the capability of the library code.

ChineseJacklee

Thank you very much guys! So can I confirm three things please:

1. The softserial will NOT work on 1 mhz unless the delayMiscroseconds() fixed as Andy said in pervious thread.
2. By default, the attiny 85 will run as 1mhz.
3. Changing the speed setting in the boards.txt will NOT automatically change the speed of the CPU, it needs to be set by flashing the corresponding fuse too.

Can someone confirm these please :)

graynomad

Rob Gray aka the GRAYnomad www.robgray.com

Osgeld

3 true, the boards.txt fuses only get set when you "burn a bootloader"
http://arduino.cc/forum/index.php?action=unread;boards=2,3,4,5,67,6,7,8,9,10,11,66,12,13,15,14,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,86,87,89,1;ALL

Go Up