ATtiny202 how to use variables properly ?

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

I am having problems with simple programm which should approximate reflow profile by 7th order polynomial approximation.

 

main.c

 

#define F_CPU 3333333

#include <stdint.h>
#include <xc.h>             // F_CPU
#include <avr/io.h>
#include <util/delay.h>
#include <math.h>
#include <avr/pgmspace.h>

const float koef[8] PROGMEM = {1.103965E-13, -1.218061E-10, 5.197188E-08, -1.109508E-05, 1.335485E-03, -1.060644E-01, 6.772042E+00, -1.131728E+02};

int main(void) {

    float y;
    uint8_t i;
    uint16_t x;

    while (1) {
        for (x = 25; x < 350; x++) {
            y = 0;
            asm("nop");
            for (i = 8; i > 0; i--) {
                y += koef[8 - i] * powf(x, i - 1);
            }
            asm("nop");
        }
        _delay_ms(500);
    }
}

The stdint.h includes only:

 

# include "stdint-gcc.h" and this includes:

 

#ifdef __INT8_TYPE__
typedef __INT8_TYPE__ int8_t;
#endif
#ifdef __INT16_TYPE__
typedef __INT16_TYPE__ int16_t;
#endif

 

What's the problem ?

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

The first problem is the compiler is optimizing away most of your code except for the nop's and delay (program used graphic says 102, which is a good clue you do not have much real code). Don't know what the ide has against the uint8_t/uint16_t, as we cannot  see what the light bulb says, buts it not complaining about the valid use of uint8_t/uint16_t.

 

Second, PROGMEM use means you have to use progmem_ functions to read them. Since it appears you want to use XC8-avr instead of gcc-avr, you are stuck having to use the old style PROGMEM for const flash data because they do not use a .rodata section like every one else. If using any normal avr-gcc (and xc8), for avr0/1 you simply use const, and everything is taken care of- the data resides in flash, and also needs no special way to read the const var data. In the case of XC8-avr, using only const will mean the data will get moved to ram. (only if volatile- same as gcc-avr).

 

Third, as soon as you get the compiler to not optimize your code away you will most likely end up using more flash than you have in a 202 if the float/powf has to be computed at runtime, which it most likely will.

Last Edited: Wed. Jan 27, 2021 - 12:50 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Fourth, using powf() this way is not efficient for integer exponents...

 

Edit: added:

 

The first problem is the compiler is optimizing away most of your code

Because currently, the results of the calculations are not being used...

 

The preferred replacement for powf() would be something like:

 

        float term = x;   // start with x**1
        for (i = 0; i < 8; i--) {
            y += koef[i] * term;
            term = term * x;  // next power of x
        }

 

 

Last Edited: Tue. Jan 26, 2021 - 04:12 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

7th order polynomial approximation.

Um...ok that already sounds quite a bit unsteady or rather unsavory...how  will you get measurements of all of these very precise coefficients to make a good 7th order fit (vs even a 3rd or maybe even 4th order)?  Don't fool yourself & find out it works no better than a quadratic  (Y= ax^2 +bX +c).  How much exacting-precision do you need-- Do you have  data to match up to?

 

5.197188E-08

How do you know you don't have 5.197263E-08 instead?  If you don't have it, you gain little, other than agony & wasted processing.   

 

Edit:

Now I see what your "curve" looks like--ok, that calls for a higher order, or a lookup table. You still need to watch coefficient sensitivity very carefully when you use things like 7th powers, those numbers swing around a LOT   (try plotting x^2 vs x^7)

 

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

Last Edited: Tue. Jan 26, 2021 - 06:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
            for (i = 8; i > 0; i--) {
                y += koef[8 - i] * powf(x, i - 1);
            }

Why run your loop backwards ?

There is nothing to be gained but only trouble & confusion when reading through. We have to double-check the array index and the argument to the pow function,. Several times

 

Reverse your koef array and stick to the regular for lopp pattern:

    for (i = 0; i < 8; i++) {
        y += koef[i] * powf(x, i);
    }

 

As for testing, I would compile for the PC and test there. On the other hand you might like to print the calculation results through the UART and capture the output to a file which you could import into any spreadsheet program of your choice.

 

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

XC8 (v2.10) 32bit Compiler setting (64bit v2.31 didn't work, errors), Default Optimization level = 1.

 

 

I replaced powf(0 with pow(0) although I know in math.h is extern double pow(double __x, double __y) __ATTR_CONST__;

 

For x = 349^7 = 6.31E+17 i need 60 bit variable i.e. uint64_t. I can replace pow() by multiplication loop as suggested by @westfw

 

I calculated the polynomial coefficients in Excel with full Excel precision (can use up to 13 digits), see real data and reflow profile approximation:

 

 

Light bulb:

 

But BUILD SUCCESSFUL (total time: 155ms)

 

Variable values are the same as in the first IDE picture:

 

 

 

 

 

 

 

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


That display is still saying 8% of 2048 bytes used - that us 163 bytes. As the GCC floating point lib is about 700 bytes that program is clearly being optimised away (as you were told before).

 

The issue is that the "output" is the variable y but (a) it's just local and (b) once the result is assigned it is not "used" in anyway. The compiler can see this and will make the decision" why would I bother generating any code for line 30 (and the loops around it) when it's a line that has no effect later?"

 

Now when you make your great new project and it has this calculation within it the chances are the "output" is going to be passed on to some following stage (perhaps display by LCD or terminal or something or even just something like an EEPROM write?)

 

But for now, when you are trying tests like this you have to fool the compiler into thinking that the result is used somehow. A common technique is to write it to a volatile. A volatile is basically a variable for which the compiler is being told "OK, I give in, you and I both know this looks pointless but whatever we both may think you must write to this anyway".

 

It's probably just enough to make y itself volatile. Alternatively just pick a CPU register (like an IO direction/output register or a timer counter or something) and have the result written there.

 

Oh and forget about the red squiggles under the variable types. That stuff is just "eye candy" and it doesn't always work. What really matters is what the preprocessor, C compiler and linker think of the code. So to know if there's some kind of problem build it. There's probably a switch thing somewhere to turn off the red squiggle technology if its false negatives irritate you. (not sure if it is "Naggy" or Vassist" that will be doing it?).

 

BTW as I have AS7 easily available I put the same code into that instead and built it:

 

 

So it has it's own set of red squiggles that are equally nonsensical! (the red squiggler should be told, for example not to look inside "" !)

 

You will see that it has built the code to be 102 bytes. That is basically an "empty" program as it, too, has optimized everything from main(). In fact you can see that in the .lss:

00000046 <main>:
#include <math.h>
#include <avr/pgmspace.h>

const float koef[8] PROGMEM = {1.103965E-13, -1.218061E-10, 5.197188E-08, -1.109508E-05, 1.335485E-03, -1.060644E-01, 6.772042E+00, -1.131728E+02};

int main(void) {
  46:	85 e4       	ldi	r24, 0x45	; 69
  48:	91 e0       	ldi	r25, 0x01	; 1
    uint16_t x;

    while (1) {
        for (x = 25; x < 350; x++) {
            y = 0;
            asm("nop");
  4a:	00 00       	nop
            for (i = 8; i > 0; i--) {
                y += koef[8 - i] * powf(x, i - 1);
            }
            asm("nop");
  4c:	00 00       	nop
  4e:	01 97       	sbiw	r24, 0x01	; 1
    float y;
    uint8_t i;
    uint16_t x;

    while (1) {
        for (x = 25; x < 350; x++) {
  50:	e1 f7       	brne	.-8      	; 0x4a <main+0x4>
	#else
		//round up by default
		__ticks_dc = (uint32_t)(ceil(fabs(__tmp)));
	#endif

	__builtin_avr_delay_cycles(__ticks_dc);
  52:	25 e1       	ldi	r18, 0x15	; 21
  54:	86 e1       	ldi	r24, 0x16	; 22
  56:	95 e0       	ldi	r25, 0x05	; 5
  58:	21 50       	subi	r18, 0x01	; 1
  5a:	80 40       	sbci	r24, 0x00	; 0
  5c:	90 40       	sbci	r25, 0x00	; 0
  5e:	e1 f7       	brne	.-8      	; 0x58 <main+0x12>
  60:	f2 cf       	rjmp	.-28     	; 0x46 <main>

Basically the only things that made it through optimization are the two NOP and the _delay_ms(). Everything else is gone. 

 

But if I make y volatile:

 

The 102 bytes of virtually "empty" program has now basically filled the AVR with mainly float library (and of course I am wrong about the size of the FP lib - it may be 700 bytes on a Mega that has the MUL opcode but on a Tiny it takes a whole lot more code).

 

The LSS file this time confirms you are now getting what you want:

                y += koef[8 - i] * powf(x, i - 1);
 11a:	c6 01       	movw	r24, r12
 11c:	a0 e0       	ldi	r26, 0x00	; 0
 11e:	b0 e0       	ldi	r27, 0x00	; 0
 120:	8d 83       	std	Y+5, r24	; 0x05
 122:	9e 83       	std	Y+6, r25	; 0x06
 124:	af 83       	std	Y+7, r26	; 0x07
 126:	b8 87       	std	Y+8, r27	; 0x08
 128:	d7 01       	movw	r26, r14
 12a:	4d 90       	ld	r4, X+
 12c:	5d 90       	ld	r5, X+
 12e:	6d 90       	ld	r6, X+
 130:	7d 90       	ld	r7, X+
 132:	7d 01       	movw	r14, r26
 134:	b8 01       	movw	r22, r16
 136:	01 2e       	mov	r0, r17
 138:	00 0c       	add	r0, r0
 13a:	88 0b       	sbc	r24, r24
 13c:	99 0b       	sbc	r25, r25
 13e:	96 d0       	rcall	.+300    	; 0x26c <__floatsisf>
 140:	4b 01       	movw	r8, r22
 142:	5c 01       	movw	r10, r24
 144:	6d 81       	ldd	r22, Y+5	; 0x05
 146:	7e 81       	ldd	r23, Y+6	; 0x06
 148:	8f 81       	ldd	r24, Y+7	; 0x07
 14a:	98 85       	ldd	r25, Y+8	; 0x08
 14c:	8d d0       	rcall	.+282    	; 0x268 <__floatunsisf>
 14e:	a5 01       	movw	r20, r10
 150:	94 01       	movw	r18, r8
 152:	7b d1       	rcall	.+758    	; 0x44a <pow>
 154:	9b 01       	movw	r18, r22
 156:	ac 01       	movw	r20, r24
 158:	89 80       	ldd	r8, Y+1	; 0x01
 15a:	9a 80       	ldd	r9, Y+2	; 0x02
 15c:	ab 80       	ldd	r10, Y+3	; 0x03
 15e:	bc 80       	ldd	r11, Y+4	; 0x04
 160:	c3 01       	movw	r24, r6
 162:	b2 01       	movw	r22, r4
 164:	0f d1       	rcall	.+542    	; 0x384 <__mulsf3>
 166:	a5 01       	movw	r20, r10
 168:	94 01       	movw	r18, r8
 16a:	1a d0       	rcall	.+52     	; 0x1a0 <__addsf3>
 16c:	69 83       	std	Y+1, r22	; 0x01
 16e:	7a 83       	std	Y+2, r23	; 0x02
 170:	8b 83       	std	Y+3, r24	; 0x03
 172:	9c 83       	std	Y+4, r25	; 0x04
 174:	01 50       	subi	r16, 0x01	; 1
 176:	11 09       	sbc	r17, r1
 178:	b8 f6       	brcc	.-82     	; 0x128 <main+0x40>

You can see that now calling out to all kinds of functions in the FP lib.

 

Thinks: doing float experiments in a 2K micro if not going to work !! Get an Arduino or something. If you use a 32K micro like a 328P then the 700 or even 2K "cost" of adding the FP lib is a mere drop in the ocean (and of course you only pay the entry price once no matter how much more FP activity you may add later - however printf(%f) is an extra cost you may be wanting to add later.

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

Thank you for the detail explanation. It's funny as I like to program Intel i7 in x64 asm e.g. to process 4 GB text file (two reads) with 40 millions rows of GPS coordinates is no problem for me including merge sort, binary search and HD graphics to display routes on a World map smiley. The program runs about 3 seconds.

I have Arduino Pro Mini ATMega328P 3.3V or even Microchip ATSAMR34-XPro available but I am sure I will make the hot plate reflow with ATtiny202 (or ATtiny204, need one pin more). I have working Zero Detection Crossing circuit to feed ATtiny202 IRQ pin sensing (both edges) to start TCB 80µS pulses for triac control, RTC 1s clock for PID control, SPI to get hot plate temperature from the MAX6675 thermocouple (see the thread below) and USART to get actual temperature data out or display them on the Nextion HMI TFT 3.5" Display. I just need to finish with the polynomial approximation wink.

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

Kevil wrote:
but I am sure I will make the hot plate reflow with ATtiny202 (or ATtiny204, need one pin more).
If you intend to stick to 2K you will likely want to do any floating calculation on your PC then simply embed a look up table of results in the micro. As you've seen, trying to do floating point maths almost immediately fills a 2K micro even before you have added your own control code. At least consider the tiny404. In 4K you might have a chance.

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

Although the program itself is just 208 bytes but calling subroutines::

 

__floatundisf
__mulsf3
__addsf3

 

makes the total size 1 514 bytes and remaing 534 bytes only.  I can't accept it and will go another way. I will store temperature uint8_t values for each second of the reflow profile which takes up only 240 bytes of program memory without using any function wink.

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

Like I say there is a cost for the FP lib (that is all those routines like __mulsf3 etc) that is about 700 bytes for Mega chips and maybe 1500 bytes for Tiny chips. But you only pay that cost once. So once you use even a single +-*/ with float in a program it adds that but after that you can use a thousand of those and it won't increase (except that even every add, sub, mul, div has quite a few bytes of "setup" getting the float values into the right registers before making the call).

 

If you like the peripherals in a Tiny202 and the chip is the right package/form factor then as you say, for a few more pins move sideways from 202 to 204. But for increased flash then move up (402/404). For all the pins and enough room for some float maths consider the 404. Sure 1.5K of the 4K might be required for the FP lib but then you still have 2.5K for your own code.

 

As you say the alternative is to do everything in integer math and where you "need float" consider a lookup table. For example if you wanted a sine output you could use float maths and the sin() function but equally you could precalculate 90 degrees worth of sine values in Excel or somewhere then just hold those precalculated values in the CPU code. Say you had 90 values and each float is 4 bytes then the whole "cost" is just 360 bytes.

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


Kevil wrote:
I will store temperature uint8_t values for each second of the reflow profile which takes up only 240 bytes of program memory without using any function

So where will you store this 256 bytes of data, you choice of micro only has 128 bytes of ram, and the stack will use some of that!

We see these type of rookie mistakes all the time here, where the OP has chosen a micro before knowing what resources are needed to do the job!

Set your compiler to use the largest member of the family, write the program, and look to see what is needed to support it, then pick a micro that fits the job.

ex. atmega328, compile, find it uses less then 6k of flash and 128 bytes of ram, then choose an atmega88 for the project.

In an 8 pin package, the largest in your family is the attiny402, but going to a 14 pin package, you can get a attiny1604, which has 16k flash and 1024 bytes of ram.

Jim

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

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

I like the AVR 0-Series. It's a great product for small tasks. Maybe I will select ATtiny804 or ATtiny1604. I need to use pins:

 

1x sensing Zero Cross Detect

1x Triac control

4x SPI (MOSI, MISO, CLK, SS) for temperature reading from MAX6675 thermocouple

2x USART temperature output or Nextion HMI TFT 3.5" Display control

 

My first project, remote car battery voltage measurement (ATtiny202 + Wisol  SigFox modem BRKSWS01)

 

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

ki0bk wrote:
So where will you store this 256 bytes of data, you choice of micro only has 128 bytes of ram, and the stack will use some of that!

It's simple. I will store data in the 2KB program memory.

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

ki0bk wrote:
So where will you store this 256 bytes of data
I think he was talking about data in a "const" LUT. So prog flash is fine for that.

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

> that is about 700 bytes for Mega chips and maybe 1500 bytes for Tiny chips

 

mega0 = tiny0/1. They should have come up with a new name for this series that more easily distinguishes them. Reusing old names, and picking out numbers within the name is not a great thing. 

 

>It's simple. I will store data in the 2KB program memory.

 

As noted before, you have to use the progmem_ functions in progmem.h to read const PROGMEM. (not true for xc8 either, my bad) I would switch to gcc-avr (anyway) for that alone (so only need to use const, without having to use progmem functions).

Last Edited: Wed. Jan 27, 2021 - 12:48 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm wrote:
As noted before, you have to use the progmem_ functions in progmem.h to read const PROGMEM. I would switch to gcc-avr for that alone (so only need to use const, without having to use progmem functions).

 

I can select either XC8 or AVR (avr8-gnu) compiler. Please advice me if I can use AVR compiler without using PROGMEM, simple example and #include ... ? would be appreciated.

 

I started with this for AVR (avr8-gnu) compiler:

 

#include <avr/io.h>

volatile const uint8_t temp[235] = {20, 23, 26, 29, 32, 34, 37, 40, 42, 45, 47, 50, 52, 55, 57, 59, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 89, 91, 93, 94, 96, 98, 99, 101, 102, 104, 105, 107, 108, 110, 111, 112, 114, 115, 116, 117, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 135, 136, 137, 138, 138, 139, 140, 140, 141, 142, 142, 143, 143, 144, 144, 145, 145, 146, 146, 146, 147, 147, 148, 148, 148, 149, 149, 149, 149, 150, 150, 150, 150, 151, 151, 151, 151, 152, 152, 152, 152, 152, 152, 153, 153, 153, 153, 153, 153, 154, 154, 154, 154, 154, 154, 155, 155, 155, 155, 155, 155, 156, 156, 156, 156, 157, 157, 157, 157, 158, 158, 158, 159, 159, 159, 160, 160, 161, 161, 162, 162, 163, 163, 164, 164, 165, 165, 166, 166, 167, 168, 168, 169, 170, 171, 171, 172, 173, 174, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 196, 197, 198, 199, 200, 201, 203, 204, 205, 206, 207, 208, 210, 211, 212, 213, 214, 215, 216, 217, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 228, 229, 230, 231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 237, 237, 238};

volatile uint8_t temperature;

int main(void) {
    /* Replace with your application code */
    while (1) {
        for (volatile uint8_t i=0; i<235; i++){
            temperature = temp[i];
            asm ("nop");
        }
    }
}

But I am getting errors:

 

c:/program files (x86)/atmel/studio/7.0/toolchain/avr8/avr8-gnu-toolchain/bin/../lib/gcc/avr/5.4.0/../../../../avr/bin/ld.exe: address 0x80406c of dist/default/production/202_avr8-gnu.X.production.elf section `.data' is not within region `data'

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

I'm intrigued by the concept of a "volatile const" ?!? "volatile" basically means "this thing could change at any moment so you MUST always read/write it when told to do so" while "const" means "this is constant and will never change"

 

(True, I was the one who mentioned volatile, but the point about it is that you should use it sparingly on only those things that MUST be volatile. Otherwise you are going to switch a large part of the compiler's ability to optimize things!)

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

With XC8 it works well:

 

#include <avr/io.h>
#include <avr/pgmspace.h>

const uint8_t temp[235] PROGMEM = {20, 23, 26, 29, 32, 34, 37, 40, 42, 45, 47, 50, 52, 55, 57, 59, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 89, 91, 93, 94, 96, 98, 99, 101, 102, 104, 105, 107, 108, 110, 111, 112, 114, 115, 116, 117, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 135, 136, 137, 138, 138, 139, 140, 140, 141, 142, 142, 143, 143, 144, 144, 145, 145, 146, 146, 146, 147, 147, 148, 148, 148, 149, 149, 149, 149, 150, 150, 150, 150, 151, 151, 151, 151, 152, 152, 152, 152, 152, 152, 153, 153, 153, 153, 153, 153, 154, 154, 154, 154, 154, 154, 155, 155, 155, 155, 155, 155, 156, 156, 156, 156, 157, 157, 157, 157, 158, 158, 158, 159, 159, 159, 160, 160, 161, 161, 162, 162, 163, 163, 164, 164, 165, 165, 166, 166, 167, 168, 168, 169, 170, 171, 171, 172, 173, 174, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 196, 197, 198, 199, 200, 201, 203, 204, 205, 206, 207, 208, 210, 211, 212, 213, 214, 215, 216, 217, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 228, 229, 230, 231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 237, 237, 238};

volatile uint8_t temperature;

int main(void) {
    /* Replace with your application code */
    while (1) {
        for (volatile uint8_t i=0; i<235; i++){
            temperature = pgm_read_byte(&temp[i]);
            asm ("nop");
        }
    }
}

 

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

>section `.data' is not within region `data'

 

That most likely means your toolchain is using a 'bad' linker script. It look like you are using the 'old' avr toolchain provided by microchip. It probably means the linker script does not have the __DATA_REGION_ORIGIN__ used to specify the data region start address which means its using an incorrect address for the data region and the linker does not like that.

 

It can be fixed-

https://www.avrfreaks.net/commen...

 

But I would get a more up to date toolchain- 

Arduino has gcc-avr 7.3.0, buts its always seem hard to find the direct link to it, so download the Arduino ide zip file, extract the hardware/tools/avr folder (the toolchain) to somewhere. I don't use atmel stdudio, but there has to be somewhere in there where you can add a toolchain, pointing to the bin folder of the extracted files. You now have gcc-avr 7.3.0 (and it will have a 'good' linker script).

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

curtvm wrote:
Arduino has gcc-avr 7.3.0, buts its always seem hard to find the direct link to it

 

The download links for various OSes are somewhere inside this file:   https://github.com/arduino/Arduino/blob/master/hardware/package_index_bundled.json

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

What I do is put a PWM value in EEPROM (rather than a temperature value); the PWM will be in use for two seconds, then move to the next value. I measure the profile with a TC to make sure it is right from time to time, but I don't have to keep the TC in the oven all the time; I can use it for other things. In theory, I could do 100k changes to the profile since it is in EEPROM before needing to replace the chip. There is less that can fail since the TC is not in the control loop, so that might be more reliable.

 

The IR elements in the ovens I have looked at include plenty of thermal capacitance and take a long time to heat (>5sec at full power). That means the PWM period can also be a long time (1 or even 2 seconds). Anyway, this is a profile of what I have been using; an 8 bit PWM period (255 does a buzzer, not IR) in effect for two seconds and TC data.

 

 

It sort of looks like heating zones (with a transition rate). Guess how they got those "ideal" profiles? Yep, the big reflow ovens on production lines have zones that the boards move through.

Last Edited: Tue. Jan 26, 2021 - 06:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
while "const" means "this is constant and will never change"

Not in 'C'.

 

In 'C' it just means, "you are not allowed to write to this".

 

So it would be perfectly valid & reasonable to declare a memory-mapped read-only register as 'volatile const'

 

Or, perhaps, a variable which is updated by an ISR, but other code is only allowed to read it.

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

clawson wrote:

while "const" means "this is constant and will never change"

 

Not in 'C'.

 

In 'C' it just means, "you are not allowed to write to this".

 

Well this explains the volatile then. If you somehow write to the constant, since it is in flash, it wont have the value you wrote. So it's volatile.

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

 

You have to be real careful when playing around with things like 7th powers...unless you measure & control your coefficients very carefully you can get vastly different results---it is very sensitive

Here is the original plot with 1.103965E-13, changed by less then 1% to 1.113965E-13   ...the output changed from 100 to 800  , MUCH more than 1% 

a few other coefficients mis-measured or changed slightly and it will be even more of a scramble

 

 

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

Last Edited: Tue. Jan 26, 2021 - 07:10 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ron_sutherland wrote:
The IR elements in the ovens I have looked at include plenty of thermal capacitance and take a long time to heat (>5sec at full power). That means the PWM period can also be a long time (1 or even 2 seconds). Anyway, this is a profile of what I have been using; an 8 bit PWM period (255 does a buzzer, not IR) in effect for two seconds and TC data.

 

That looks nice. I have to measure the heating curve of the hot plate first when I get the TC. I suppose to use IR TC (MLX90614ESF-BAA-000-SP) for immediate temperature measurement later. To avoid any snubber I will use Zero Detect Crossing switching of the Triac in 2% steps. I.e. The power 16% will mean I will switch on the first 16 halfwaves from 100 in a 1 second period (220V/50Hz). To adjust PID control I am going to use autotune in MATLAB & Simulink.

Last Edited: Tue. Jan 26, 2021 - 07:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

while "const" means "this is constant and will never change"

Not in 'C'.

In 'C' it just means, "you are not allowed to write to this".

 

Nevertheless, on the "unified address space" tiny-0 chips, declaring a global data item as 'const' is sufficient to make the compiler put it in the flash memory, rather than RAM.  Even with "XC8."

(Whether the subsequent steps to create and program the actual flash work correctly is a different question.)

 

You do NOT want to use PROGMEM as well, as that redefines the symbol relative to the start of flash, which is a different address than if it is in the aliased unified address space.

 

Symbol dump, Compiled with XC8, and "const" only:

00000618 00000074 T exp
000008a6 00000010 T inverse
0080886a 00000020 R koef
00000684 00000074 T ldexp
000004fe 000000a0 T log
000002b4 000000ce T main
000006f0 00000068 T modf

 

with "const ... PROGMEM":

000005fc 00000074 T exp
0000086a 00000010 T inverse
000000ca 00000020 T koef
00000668 00000074 T ldexp
000004e2 000000a0 T log
00000298 000000ce T main
000006d4 00000068 T modf

 

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

standby

 

>Even with "XC8."

 

My bad. Here's what threw me for a loop (while testing the code in xc8)- if you make a const volatile (for testing, to make the compiler keep it), the data is moved to ram. That seems to be the case for xc8 and gcc-avr. Don't know why, as there are legitimate uses for volatile const although unusual (like writing to flash, and the compiler will not know about it, so you want to make the compiler always read a const instead of using a value it thinks it knows since it is const). I should have suspected something was wrong with my testing, as I thought is was odd, but went with it anyway.

 

Another difference found- xc8 linker script does not have a .rodata section, so it must be creating the vma address internally.

 

So, to correct my previous statement- just use const in xc8 or gcc-avr for the 0/1 series. If you want to make the compiler keep a const while testing, use some other method than volatile. It does get a little difficult sometimes to get the compiler to play dumb.

 

I tried to clean up my previous posts. Sorry for misinfo.

Last Edited: Wed. Jan 27, 2021 - 12:53 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Once upon a time, I tried to do something like this:

extern volatile int fred;  // from header

ISR(...)
{
    extern int fred;
    ...
}

Though perfectly meaningful, the compiler did not like it.

Not sure whether the compiler was correct.

I'd expect the same result from const.

 

On a platform that automatically puts constants in flash,

the only way to get an effective const volatile might be to locate it with the linker.

Moderation in all things. -- ancient proverb