Go Down

Topic: core13: An Arduino core for the Attiny13 *testers wanted* (Read 167614 times) previous topic - next topic

mcnobby

Thanks for that Hiduino, decided not to use progmem for the time being and have a work around for now

Smeeze, well I guess it is a noticable difference from the t85 I 'upgraded' from !! - if you know of any exact settings I should use for 9.6 jiggawatts then please share, for now I have this tiny micro searching for a 88us sync pulse in a 250kbps continuous data stream - I am synching beautifully and grabbing the data with ease on the t13 @ 9.6mhz

What seemed like an impossible task a few weeks back is now a success !! thanks for your help
http://www.youtube.com/user/Recovered
http://www.smartshow.lighting

mcnobby

I am trying to suss out a bug I have with t13.. I am using EEPROM.h and im just wondering if when I upload the program it wipes the eeprom, how can I stop this with t13 ? (I think I had a similar problem with t85 before but got over that after someone on here helped) - Thanks in advance
http://www.youtube.com/user/Recovered
http://www.smartshow.lighting

smeezekitty

#272
Sep 19, 2014, 07:48 pm Last Edit: Sep 19, 2014, 07:52 pm by smeezekitty Reason: 1

I am trying to suss out a bug I have with t13.. I am using EEPROM.h and im just wondering if when I upload the program it wipes the eeprom, how can I stop this with t13 ? (I think I had a similar problem with t85 before but got over that after someone on here helped) - Thanks in advance

Not a bug. Its because the Arduino IDE is passing the erase chip option to avrdude.

The way around it (AFAIK) is to upload manually with avrdude which is a pain
-edit-
oops coding badly has a better option. I forgot about the fuse
Avoid throwing electronics out as you or someone else might need them for parts or use.
Solid state rectifiers are the only REAL rectifiers.
Resistors for LEDS!

Coding Badly


Uh, actually, it is a fuse bit.  Ensure Preserve EEPROM memory through the Chip Erase cycle; [EESAVE=0] is "set".

mcnobby

Ah yes, thats it CodingBaldy, I had forgotten about that.. I shall check my fuse options - cheers
http://www.youtube.com/user/Recovered
http://www.smartshow.lighting

mcnobby

I was using 0x7a for low fuse, but should be 0x3a to preserve my eeprom during pogramming

found this, VERY useful

http://www.elektronik-kompendium.de/public/arnerossius/programme/web/avrfuse/tn13fuse.html

Cheers :)
http://www.youtube.com/user/Recovered
http://www.smartshow.lighting

hiduino

That's an interesting view of the fuse settings.  I like to use this fuse site, http://eleccelerator.com/fusecalc/fusecalc.php?chip=attiny13a.  It supports most of the Atmel AVR mcu.

mcnobby

I just committed to a PCB design for the ATTiny13, really pleased with my code and the minimal design in SMD

Big thanks to all who have helped me here :)

http://www.youtube.com/user/Recovered
http://www.smartshow.lighting

swe-dude

Hello!
Any one succeeded in getting this core to work on arduino 1.5.7 ?? i have been trying but no luck for me so far.

hiduino

#279
Sep 22, 2014, 12:36 pm Last Edit: Sep 22, 2014, 12:46 pm by hiduino Reason: 1
Yes, I've been using the core13 with IDE 1.5.x for a while now.  The main thing is to have a proper boards.txt and platform.txt files. Also you need to have the proper directory path structure.  For IDE 1.5.x the boards.txt file structure has some slight changes.

For IDE 1.0.6:
/sketches/hardware/tiny13/boards.txt
/sketches/hardware/tiny13/core/core13/

For IDE 1.5.7:
/sketches/hardware/tiny13/avr/boards.txt
/sketches/hardware/tiny13/avr/platform.txt
/sketches/hardware/tiny13/avr/core/core13/

I have combined both in the attached file.  It includes the core13_19 files.  I have included various CPU clock options for the tiny13.  Just keep in mind when you go below 1 MHz clock rates you need to make sure your ISP programmer supports a slow clock option.  Otherwise you may not be able to program it unless you have a different ISP programmer option.

swe-dude

#280
Sep 22, 2014, 05:49 pm Last Edit: Sep 22, 2014, 06:16 pm by swe-dude Reason: 1
Thanks a lot it works like a dream,
i saw in your boards file that you are not using reset as IO, a tip try ScratchMonkey hsvp programmer it works really well for attiny13 too. cheapest way to get a hsvp programmer i have seen so far.

http://microtherion.github.io/ScratchMonkey/GettingStarted.html

Thanks again for the Help

kosine

Hi all, I've been doing some work on that recurring delay/timing issue many have been experiencing. (Including myself!)

Long story short - I've written a new delay function that seems to be very close to spot on. I think it'll need a bit of explaining, but the base code is below. In a nutshell, millisecond delays are fine, but microsecond delays may need increasing by 20% depending on your clock speed.

There are two new functions, "delay_us" and "delay_ms", and both take an unsigned integer for the time period. You can put the functions in your sketch file, or add them to "wiring.c" in the core13 directory.

A few issues to consider:
1. "ms_delay" just reuses "us_delay", but note that the "ms_loops" variable can be 1200 rather than 1000. This is due to the ATTiny internal base frequency being at 1.2/4.8/9.6MHz. It's only 1000 if using 2/4/8/16MHz. This is done automatically for millisecond delays, so nothing to worry about.

However, such an adjustment is NOT done inside "us_delay". It would require a *1.2 multiplier, and maths functions eat up memory. As a result, if you're running at 1.2/4.8/9.6MHz then the value passed to "us_delay" MUST be increased by 20% to get the correct delay period. So if you want a 50us delay, you actually need to call "us_delay(60);" (This is a minor annoyance, but I'm working on it...)

2. The F_CPU parameters in "boards.txt" need to be the actual CPU frequency. The stock file has both 4.8MHz and 9.6MHz set to 1200000L, and this won't work. They need to be changed to 4800000L and 9600000L for these functions to work correctly. (Changing them may mess up the existing delay functions if you use those as well - but I haven't yet checked.)

3. There are some slight overheads which make the delays very slightly longer than expected. This is just a few microseconds, so isn't a problem for long delays, but it starts creeping in below 100us. (Actually called as "120us" - see point 1.)

4. The maximum delay in microseconds is 16383, the minimum is 4. Due to point 1, in practice this translates as 13650us if you're running at the awkward 1.2/4.8/9.6 clock speeds.


I've done a reasonable amount of testing with some ATTiny13As at 1.2MHz and 9.6MHz, and also with a standard Arduino (ATMega328) at 16MHz. At the higher clock speeds the timing is pretty accurate, but not quite so good at 1.2MHz. I think this is due to the overheads being longer in real-time at the slower clock speed.

I'll try and fix the annoying +20% issue when I get some free time, I suspect it may require changing the number of clock cycles used by the loop.

Comments and feedback appreciated. Someone may also wish to check the code as it's my first attempt at assembly!

________________

Code: [Select]
void delay_us(uint16_t us_delay) // Works OK between 10us and 16382us. NOTE: Send x1.2 for ATTiny @ 1.2/4.8/9.6MHz
{
  us_delay = us_delay >> 2;
  uint8_t us_low = us_delay & 255;
  uint8_t us_high = us_delay >> 8;

  uint8_t us_loops;  // define the number of outer loops based on CPU speed (defined in boards.txt)

  #if (F_CPU == 16000000L)
    us_loops=16;
  #elif (F_CPU == 8000000L || F_CPU == 9600000L)
    us_loops=8;
  #elif (F_CPU == 4000000L || F_CPU == 4800000L)
    us_loops=4;
  #elif (F_CPU == 2000000L)
    us_loops=2;
  #elif (F_CPU == 1000000L || F_CPU == 1200000L)
    us_loops=1;
  #else
  #error This CPU frequency is not defined   
  #endif

   
  // loop is (4) + (4x us) + (4x us_loops) clock cycles in total - this is where the overheads occur
  // each clock cycle is 62.5ns @ 16MHz
  // each clock cycle is 833.3ns @ 1.2MHz
  asm volatile(
   "CLI\n" // turn off interrupts : 1 clock
   "MOV r28,%0\n" // Store low byte into register Y : 1 clock
   "MOV r29,%1\n" // Store high byte into register Y : 1 clock
   "MOV r30,%2\n" // Set number of loops into register Z : 1 clock
 
     // note branch labels MUST be numerical (ie. local) with BRNE 1b (ie. backwards)
     "1:\n" // = 4 clock cycles for each outer loop
     "MOV r26,r28\n" // Copy low byte into register X : 1 clock
     "MOV r27,r29\n" // Copy high byte into register X : 1 clock
   
       "2:\n" // = 4 clock cycles for each inner loop
       "SBIW r26,1\n" // subtract one from word : 2 clocks
       "BRNE 2b\n" // Branch back unless zero flag was set : 1 clock to test or 2 clocks when branching
       "NOP\n" // add an extra cycle if not branching
     
     "SUBI r30,1\n" // subtract one from loop counter : 1 clocks
     "BRNE 1b\n" // Branch back unless zero flag was set : 1 clock to test or 2 clocks when branching

   "SEI\n" // turn on interrupts :  1 clock (adds extra clock cycle when not branching)
   :: "r" (us_low), "r" (us_high), "r" (us_loops) // tidy up registers
);
}


void delay_ms(uint16_t ms_delay) // reuse delay_us routine
{
  uint16_t ms_loops=1000;  // define number for us cycles
  #if (F_CPU == 1200000L || F_CPU == 4800000L || F_CPU == 9600000L)
    ms_loops=1200;  // Need to compensate for 1.2/4.8/9.6MHz
  #endif

  for (int ms_loop=0; ms_loop < ms_delay; ms_loop++) {
    delay_us(ms_loops);
  }
}



smeezekitty




A few issues to consider:
1. "ms_delay" just reuses "us_delay", but note that the "ms_loops" variable can be 1200 rather than 1000. This is due to the ATTiny internal base frequency being at 1.2/4.8/9.6MHz. It's only 1000 if using 2/4/8/16MHz. This is done automatically for millisecond delays, so nothing to worry about.

I will try it out when I get a chance. But I am very concerned with flash usage.
Quote


However, such an adjustment is NOT done inside "us_delay". It would require a *1.2 multiplier, and maths functions eat up memory. As a result, if you're running at 1.2/4.8/9.6MHz then the value passed to "us_delay" MUST be increased by 20% to get the correct delay period. So if you want a 50us delay, you actually need to call "us_delay(60);" (This is a minor annoyance, but I'm working on it...)

To avoid floating point math, you might be able to do something like this:
Code: [Select]

B = A + (A / 5);

or faster but less accurate (using 25% scaling)
Code: [Select]

B = A + (A >> 2);

Those wouldn't have the (flash) overhead of *1.2 but still might still be slow.
Quote

2. The F_CPU parameters in "boards.txt" need to be the actual CPU frequency. The stock file has both 4.8MHz and 9.6MHz set to 1200000L, and this won't work. They need to be changed to 4800000L and 9600000L for these functions to work correctly. (Changing them may mess up the existing delay functions if you use those as well - but I haven't yet checked.)

The boards.txt that are set up like that are wrong plain and simple. They keep kicking around for some reason.
F_CPU should always be set to the actual core speed. This includes accounting for whether /8 fuse is set or not.
Quote

3. There are some slight overheads which make the delays very slightly longer than expected. This is just a few microseconds, so isn't a problem for long delays, but it starts creeping in below 100us. (Actually called as "120us" - see point 1.)

This is always the case especially at low clock speeds. Not much can be done.


Quote

Comments and feedback appreciated. Someone may also wish to check the code as it's my first attempt at assembly!

It looks fairly okay. It does have more overhead though.
I will see if it is worth integrating later.
Avoid throwing electronics out as you or someone else might need them for parts or use.
Solid state rectifiers are the only REAL rectifiers.
Resistors for LEDS!

kosine

Hi smeezekitty, thanks for the quick feedback!

I've done a bit of tweaking and oscilloscope testing - here's the results:

// Original routines
delayMicroseconds(1000) : +34 bytes, actual delay 1140us (+14%)
delay(1000) : +26 bytes, actual delay 1380ms (+38%)

// New routines
delayMicroseconds(1000) : +58 bytes, actual delay 1060us (+6%)
delay(1000) : +44 bytes, actual delay 1040ms (+4%)


With a bit of pruning I might be able to reduce the size a little, but for an extra 20 bytes or so the accuracy is much improved, especially with longer delays. (My current project can live with that.)

Turns out the new routines have to replace the old ones in wiring.c. If they're left as separate functions they seem to get embedded every time they're called. Replacing the originals in wiring.c then results in the usual overhead of just 6 bytes for every additional use.

I also fixed the annoying *1.2 issue by using 9/8 instead, which is easy to bitshift. (Thanks for the suggestion!) That also helps compensate for the clock cycle overheads in the loop. As a result, the maximum delayMicrosecond() is reduced to 58250, but you can now just pass the raw us value as normal.


Code: [Select]

void delay(unsigned ms)
{
  while(ms--){
    delayMicroseconds(1000);
  }
}



void delayMicroseconds(unsigned us)
{
  uint8_t us_loops;  // define the number of outer loops based on CPU speed (defined in boards.txt)
  #if (F_CPU == 16000000L)
    us_loops=16;
  #elif (F_CPU == 9600000L)
    us=us + (us >> 3); // this should be *1.2 but *1.125 adjusts for overheads
    us_loops=8;
  #elif (F_CPU == 8000000L)
    us_loops=8;
  #elif (F_CPU == 4800000L)
    us = us + (us >> 3);
    us_loops=4;
  #elif (F_CPU == 4000000L)
     us_loops=4;
  #elif (F_CPU == 2000000L)
    us_loops=2;
  #elif (F_CPU == 1200000L)
    us = us + (us >> 3);
    us_loops=1;
  #elif (F_CPU == 1000000L)
    us_loops=1;
  #else
  #error This CPU frequency is not defined   
  #endif

  us = us >> 2;
  uint8_t us_low = us & 255;
  uint8_t us_high = us >> 8;
   
  // loop is (4 clock cycles) + (4x us) + (4x us_loops)
  // each clock cycle is 62.5ns @ 16MHz
  // each clock cycle is 833.3ns @ 1.2MHz
  asm volatile(
   "CLI\n" // turn off interrupts : 1 clock
   "MOV r28,%0\n" // Store low byte into register Y : 1 clock
   "MOV r29,%1\n" // Store high byte into register Y : 1 clock
   "MOV r30,%2\n" // Set number of loops into register Z : 1 clock
 
     // note branch labels MUST be numerical (ie. local) with BRNE 1b (ie. backwards)
     "1:\n" // : 4 clock cycles for each outer loop
     "MOV r26,r28\n" // Copy low byte into register X : 1 clock
     "MOV r27,r29\n" // Copy high byte into register X : 1 clock
   
       "2:\n" // : 4 clock cycles for each inner loop
       "SBIW r26,1\n" // subtract one from word : 2 clocks
       "BRNE 2b\n" // Branch back unless zero flag was set : 1 clock to test or 2 clocks when branching
       "NOP\n" // add an extra clock cycle if not branching
     
     "SUBI r30,1\n" // subtract one from loop counter : 1 clocks
     "BRNE 1b\n" // Branch back unless zero flag was set : 1 clock to test or 2 clocks when branching

   "SEI\n" // turn on interrupts : 1 clock (adds extra clock cycle when not branching)
   :: "r" (us_low), "r" (us_high), "r" (us_loops) // tidy up registers
);
}



smeezekitty

Ok so for comparison do you think you can test a millis() loop for size and accuracy
Avoid throwing electronics out as you or someone else might need them for parts or use.
Solid state rectifiers are the only REAL rectifiers.
Resistors for LEDS!

Go Up