core13: An Arduino core for the Attiny13 *testers wanted*

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

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...)

  1. 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.)

  2. 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.)

  3. 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!


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);
  }
}

kosine:
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.

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:

B = A + (A / 5);

or faster but less accurate (using 25% scaling)

B = A + (A >> 2);

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

  1. 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.

  1. 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.

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.

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.

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
 );
}

Ok so for comparison do you think you can test a millis() loop for size and accuracy

This topic has been hashed many times for optimized math division. Check these out.

http://forum.arduino.cc/index.php?topic=185662.0

http://forum.arduino.cc/index.php?topic=164644.0

http://forum.arduino.cc/index.php?topic=167414.0

http://forum.arduino.cc/index.php?topic=172635.0

http://forum.arduino.cc/index.php?topic=165860.0

http://forum.arduino.cc//index.php?topic=192209.msg1448435#msg1448435

A quick comparison using millis() and micros() shows them to be pretty bad when using a simple while loop:

void loop() {
 PORTB=1;
 period=micros()+1000;
 while(micros()<period){
 }
 PORTB=0;
 period=micros()+1000;
 while(micros()<period){
 }
}

Using micros() the sketch compiles to 398 bytes and times at 1400-1800us (with very inconsistent timing)
Using millis() the sketch compiles to 414 bytes, and times at 1120ms consistently.

In constrast, the new delay() and delayMicroseconds routines give:

delayMicroseconds(1000) compiles to 266 bytes, times at 1064us
delay(1000) compiles to 252 bytes, times at 1070ms

An obvious problem with using millis() or micros() is that the timer overflow counter is only incremented every 256 clock cycles, ie. every 213us at 1.2MHz. With millis() this is then scaled by 5/19/37 for 1.2/4.8/9.6MHz. These don't quite give exact ms values. At 1.2MHz for example, 2565=1280 clock cycles and 12800.833=1066us.

micros() fares even worse, since the time has increased by 213us for each ovrf++ (at 1.2MHz). And because there's no way of controlling exactly when these functions are executed, ovrf may have increased beyond the required timing value, being some multiple of 213us larger than desired. (Unless 213 happens to be an aliquot part of your required duration.) This also means that micros() can't deal with periods less than 213us.

I think that with higher clock speeds and with longer delays millis() and micros() are probably adequate. But micros() is not too good for actually counting microseconds.

kosine:
A quick comparison using millis() and micros() shows them to be pretty bad when using a simple while loop:

void loop() {

PORTB=1;
period=micros()+1000;
while(micros()<period){
}
PORTB=0;
period=micros()+1000;
while(micros()<period){
}
}




Using micros() the sketch compiles to 398 bytes and times at 1400-1800us (with very inconsistent timing)
Using millis() the sketch compiles to 414 bytes, and times at 1120ms consistently.

This is quite expected from the current micros() routine at clock clock rates
I am very surprised they are so large though

In constrast, the new delay() and delayMicroseconds routines give:

delayMicroseconds(1000) compiles to 266 bytes, times at 1064us
delay(1000) compiles to 252 bytes, times at 1070ms

An obvious problem with using millis() or micros() is that the timer overflow counter is only incremented every 256 clock cycles, ie. every 213us at 1.2MHz. With millis() this is then scaled by 5/19/37 for 1.2/4.8/9.6MHz. These don't quite give exact ms values. At 1.2MHz for example, 2565=1280 clock cycles and 12800.833=1066us.

Well I am seriously thinking that I am going to increase the timer interrupt rate in a future version

I think that with higher clock speeds and with longer delays millis() and micros() are probably adequate. But micros() is not too good for actually counting microseconds.

I am fully aware of the limitations on the uS routines. However I will work on improvements.

The problem with your routines is they fail completely on clock speeds below 1 MHz. Not a huge deal with uS since "microsecond"
timing and overhead would be pretty awful at 128 or 600 khz. BUT working millisecond timing is important.

I may set it up so it switches routines based on clock speed

Yeah, I need to have a look at the slower clock speeds. 600kHz might not be too terrible, but I can see 128kHz being awkward. I'll give it some thought. (Perhaps 1MHz << 8 is close enough?)

A reasonable millis() can be done, but a robust micros() eludes me at present. With some modified functions I can get these results:

@ 9.6MHz (chip 1):
micros()+100 : 124 to 154us
micros()+500 : 520us

millis()+5 : 4.1 to 4.7ms
millis()+50 : 49.6ms
millis()+500 : 492ms
millis()+5000 : 4920ms

@ 1.2MHz (chip 2):
micros()+100 : 400 to 600us
micros()+500 : 640 to 860us

millis()+5 : 4.84 to 5.20ms
millis()+50 : 50.8ms
millis()+500 : 508ms
millis()+5000 : 5040ms

The figures are slightly different between chips, so this is probably as good as I can get.

unsigned long micros(){
//	asm("CLI\n");
	unsigned long us_actual = ovrf << 9;		// Put number of overflows into higher bits (equivalent to total clocks*2)
	us_actual = us_actual + TCNT0;			// Put current timer-counter into lower 8 bits


	#if F_CPU == 1000000				// 1.0us per clock = 1 clock per us
	us_actual = us_actual >> 1;			// Equivalent to clocks

	#elif F_CPU == 2000000 				// 0.5us per clock = 2 clocks per us
	us_actual = us_actual >> 2;			// Equivalent to clocks/2

	#elif F_CPU == 4000000 				// 0.25us per clock = 4 clocks per us
	us_actual = us_actual >> 3;			// Equivalent to clocks/4

	#elif F_CPU == 8000000 				// 0.125us per clock = 8 clocks per us
	us_actual = us_actual >> 4;			// Equivalent to clocks/8

	#elif F_CPU == 16000000 			// 0.0625us per clock = 16 clocks per us
	us_actual = us_actual >> 5;			// Equivalent to clocks/16


	#elif F_CPU == 600000				// 1.66us per clock = 0.833 clock per us
	us_actual = (us_actual >> 1) + (us_actual >> 2) + (us_actual >> 3) + (us_actual >> 6);	// Equivalent to clocks*0.8906

	#elif F_CPU == 1200000 				// 0.83333us per clock = 1.2 clocks per us
	us_actual = (us_actual >> 2) + (us_actual >> 3) + (us_actual >> 4) + (us_actual >> 7);	// Equivalent to clocks*0.4453

	#elif F_CPU == 4800000 				// 0.20833us per clock = 4.8 clocks per us
	us_actual = (us_actual >> 4) + (us_actual >> 5) + (us_actual >> 6) + (us_actual >> 9);	// Equivalent to clocks*0.1113

	#elif F_CPU == 9600000 				// 0.10416us per clock = 9.6 clocks per us
	us_actual = (us_actual >> 5) + (us_actual >> 6) + (us_actual >> 7) + (us_actual >> 10);	// Equivalent to clocks*0.0557

	#else
	#error This CPU frequency is not defined
	#endif
//	asm("SEI\n");

	return us_actual;
}


unsigned long millis(){
	return (micros() >> 10); 			// This is 2.4% too low is but compensated for above at 0.6/1.2/4.8/9.6MHz
}

Been a bit busy last few weeks, but tried a couple of alternative ways to improve the timing functions. None were much better sadly.

Did discover a couple of other things while playing about:

  1. Removing the init() function from wiring.c and pasting the code into main() (main.cpp) seems to save 92 bytes if you don't need the timing functions. A "bare minimum" sketch normally compiles to about 194 bytes, but moving the init() code reduces it to 102 bytes. The overhead comes back if you call any timing function, but it doesn't if you're not using those.

  2. The following code appears in analogWrite:

		if(pin == 1){
			TCCR0A |= (1 << COM0B1);
			OCR0B = (val / 4) * 4;
		}
		if(pin == 0){
			TCCR0A |= (1 << COM0A1);
			OCR0A = val;
		}

Is there a reason for "(val / 4) * 4"? Replacing it with "OCR0B = val" should work and avoids the overheads

On the subject of analogWrite, I needed full control over the PWM output so wrote this:

void configPWM(uint8_t pwmmode, uint16_t prescaler)	// set PWM mode and prescaler frequency
{	
	if (pwmmode){
	TCCR0A = _BV(WGM00);}				// set to phase correct PWM mode.

	if (!pwmmode){
	TCCR0A = _BV(WGM00)|_BV(WGM01);}		// set to fast PWM 



	if (prescaler == 8){
	TCCR0B = _BV(CS01);}				// clk/8 prescaler

	else if (prescaler == 64){
	TCCR0B = _BV(CS01) | _BV(CS00);}		// clk/64 prescaler

	else if (prescaler == 256){
	TCCR0B = _BV(CS02);}				// clk/256 prescaler

	else if (prescaler == 1024){
	TCCR0B = _BV(CS02) | _BV(CS00);}		// clk/1024 prescaler

	else{
	TCCR0B = _BV(CS00);}				// no prescaler (Default setting.)
}

I've tested it at 1.2MHz and the measured outputs are pretty close to the theoretical - slightly lower, but possibly just due to chip tolerances. The nominal FAST output (pwmmode=1) with prescaler=1 should be 4687Hz, I measure it at about 4460Hz. The nominal PHASE CORRECT output (pwmmode=0) with prescaler=1024 should be 2.3Hz, I measure it at about 2.1Hz.

The function compiles to 68 bytes, with an additional 8 bytes for every reuse.

I just like this tiny13 MCU , even more than ATtiny85, some litle effort and you can do great things with little resource.
Many thanks to smeezekitty - you did great job with this core.
I find some fine two channel volt meter here - MrПоделкинЦ Blog: Двух канальный вольтметр на Attiny13 и 74CH595

and with this small serial library - Nerd Ralph: AVR half-duplex software UART supporting single pin operation
( only 64 bytes more on flash work also great with ATtiny85) i manage to do some modifications and to create this small ATtiny13 two chanel Console terminal volt meter.
I use LP2950ACZ-5.0 (5V - 0.5%) LDO for power supply and for reference also ( 100mA max. current), 10KOhm input resistors , and result is pretty accurate ( 4.096 V , 0.728 V with my cheap volt meter ). And a little unnecessary graphics purely to try to see what can do with so little memory.

#include <BasicSerial.h> // Samo TX ( SALJE Serial)
//#include <BasicSerial3.h> // TX i RX( SALJE I PRIMA Serial)
#include <util/delay.h>

//////////////////////////////////////////////////////////////////////////////////////////////////////
// #define UART_Tx 3 - U BasicSerial.S tj. Po defaultu Pin 3 ( PB3 ) - 115.2kbps ako je 9.6 MHz-a
void serOut(const char* str){
while (*str) TxByte (*str++);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////

#include <avr/pgmspace.h>
// Ispis na istoj poziciji u externoj konzoli - pre svake komande mora Escape - \033 ( Umesto \033 moze \x1B ):
// \033 - Escape
// [2J - Clear screen
// [H - Go to home position (0,0)
// [0;36m - color tirkiz
// [0;34m - plava , [1;34m - svetlo plava
// [?25l - hide_cursor
// [4m - underscore
// [0;m - Normal color za sve
// [0;5m"; - blink
// [1;5m"; - blink bold
// \033[m - stop za blink
prog_char Message0[] PROGMEM = {
"\033[H\n\033[1;34m#\033[0;31m-------- \033[0;36mQ"};
prog_char Message1[] PROGMEM = {
"\033[H\n\n\033[1;34m#\033[0;31m-------- \033[0;32mQ"};
prog_char Message2[] PROGMEM = {
"\033[1;34m### \033[0;m\033[1;5mATTINY13 VOLT METER\033[m \033[1;34m###\033[?25lQ"};
prog_char Message3[] PROGMEM = {
" \033[0;31m--------\033[1;34m#Q"};
prog_char Message4[] PROGMEM = {
"\033[1;34m###########################Q"};

#define ADC_Pin_1 A1 // PB2
#define ADC_Pin_2 A2 // PB4

/////////////////////////////////////////////////////////////////////////////
int main() {
#if defined (AVR_ATtiny13)
char buf[2];
byte b = 0;
while(1){
buf[0] = pgm_read_byte_near(&(Message2**));**
** buf[1] = '\0';**
** if(buf[0] == 'Q')break;**
** serOut(buf);**
** b++;**
** }**
** b = 0;**
** serOut("\n\n\n");**
** while(1){**
buf[0] = pgm_read_byte_near(&(Message4**));
__
buf[1] = '\0';__
__
if(buf[0] == 'Q')break;__
__
serOut(buf);__
__
b++;__
__
}__
#elif defined(AVR_ATtiny85)
__
serOut("\x1B[0;31mATtiny85\033[?25l");__
__
#else**__
** serOut("");**
#endif
** DDRB &= ~(1 << ADC_Pin_1); // pinMode(ADC_Pin, INPUT);
DDRB &= ~(1 << ADC_Pin_2); // pinMode(ADC_Pin, INPUT);
#if defined (AVR_ATtiny13)
turn_on_adc(); // Samo ako odaberemo drugu verziju**

#endif
** while(1) {**
** unsigned int adc_read_1,adc_read_2;
#if defined (AVR_ATtiny13)
adc_read_1 = (/analogRead/readADC(ADC_Pin_1));
adc_read_2 = (/analogRead/readADC(ADC_Pin_2));
#elif defined(AVR_ATtiny85)
adc_read_1 = (((unsigned int)analogRead(ADC_Pin_1)*49/10));
adc_read_2 = (((unsigned int)analogRead(ADC_Pin_2)*49/10));
__
#endif**__
** print_tree_UINT_dec( adc_read_1, 1 );
print_tree_UINT_dec( adc_read_2, 2 );
delay_ms(500);
__
}**_
** return 0;**
}
/////////////////////////////////////////////////////////////////////////////////////////
void turn_on_adc(){ADCSRA |= (1 << ADEN) |(1 << ADPS2)|(1 << ADPS1);
** ACSR |= (1 << ACD);**
** DIDR0 |= (1 << ADC3D)|(1 << ADC2D);**
}
unsigned int readADC(unsigned char ch) {
** ADMUX = ch;**
** ADCSRA |= (1 << ADSC);**
** while((ADCSRA & (1 << ADSC)));**
** // return(ADC); // 0-1023**
////// LP2950ACZ-5.0 ~~ 5V , 0.5% ///////////////
__ return(ADC*49/10); // 1023 * 49 / 10 = (int)5012.4 = 5012( 49/10 kada je 5.0 V = Vcc = refV)
** // Posto koriscenje float prom. trosi mem. mora se koristiti racional aprox. kao ovde a za ref. voltazu birati Vcc sa sto tacnijom regulacijom.**
}
////////////////////////////////////////////////////////////////////////////////////////////////
// unsigned int max do 65 536
void print_tree_UINT_dec( unsigned int aprox_a , int voltCh ){
** unsigned int decimals = 1000; // 3 decimale**
** unsigned int b = aprox_a / decimals; // ceo broj 3**
** unsigned int c = (aprox_a % decimals) / (decimals/10); // 1. decimala - ostatak 1**
** unsigned int d = (aprox_a % (decimals/10) ) / (decimals/100); // 2. decimala - ostatak 4**
** unsigned int e = aprox_a % (decimals/100); // 3. decimala - ostatak 4**
** char buf[2];**
** byte bb = 0;**
** if(voltCh == 1){**
** while(1){**
** buf[0] = pgm_read_byte_near(&(Message0[bb]));
__
buf[1] = '\0';**

** if(buf[0] == 'Q')break;**
** serOut(buf);**
** bb++;**
** }**
** }**
** if(voltCh == 2){**
** bb = 0;**
** while(1){**
** buf[0] = pgm_read_byte_near(&(Message1[bb]));
__
buf[1] = '\0';__
__
if(buf[0] == 'Q')break;__
__
serOut(buf);__
__
bb++;__
__
}__
__
}__
__
char buffer [2];__
__
itoa (b,buffer,10);__
__
serOut( buffer );__
__
serOut( "." );__
__
itoa (c,buffer,10);__
__
serOut( buffer );__
__
itoa (d,buffer,10);__
__
serOut( buffer );__
__
itoa (e,buffer,10);__
__
serOut( buffer );__
__
serOut( " V" );__
__
// Crvene crtice desno __
__
bb = 0;__
__
while(1){__
buf[0] = pgm_read_byte_near(&(Message3[bb]));
__
buf[1] = '\0';__
__
if(buf[0] == 'Q')break;__
__
serOut(buf);__
__
bb++;__
__
}__
__
}__
__
[/quote]__
ATtiny13_Terminal_VoltMeter.zip (1.76 KB)**

Thanks for sharing. Although it begs the question on why you are overriding the ADC functions.

To kosine:
I have noticed your feedback but I haven't had time to implement anything.
That /4 line was for testing and somehow it slipped through. It will be fixed in the next release

smeezekitty:
Thanks for sharing. Although it begs the question on why you are overriding the ADC functions.

No reason at all, build in analogRead work fine in 0.19 core , i just trying something and forget to roll back before post.

Hi there all,

Ive been out of the t13 for a few weeks now, but thought I would get round to publishing a working project on here

ATTiny13 - DMX512 to WS2812 RGB LED interface

Thanks to all that have helped and contributed

Bob

Thanks for sharing.
I am long overdue for an update

Core13 0.20 released!

Features improved PWM output and rewritten delayMicroseconds() code
which should be more accurate at all clock speeds and delay length.

(first release of 2015!)

smeezekitty:
Core13 0.20 released!

Features improved PWM output and rewritten delayMicroseconds() code
which should be more accurate at all clock speeds and delay length.

(first release of 2015!)

Great, will give it a go to make sure my arduino-based 13a stuff still works. Any impact of these changes on generated code size?

evildave_666:
Great, will give it a go to make sure my arduino-based 13a stuff still works. Any impact of these changes on generated code size?

Certain functions may be a little larger. Sorry about that :frowning:

I have been playing with ATTINY13A again

This time I got to drive a projector in 8 colours DIRECTLY from the ATTINY13 !!

http://forum.arduino.cc/index.php?topic=288766.0

hi all.

I just unzip core13_20.zip on ...\Arduino\hardware\tiny\cores\core13

Where is the attiny def for boards.txt?

Am i in the right way?

It works with Attiny13A?

thanks.