Hot answers tagged

18

According to C language specification any value whose size is less than the size of int (depends on the particular compiler; in your case int is 16-bits wide) involved in any operation (in your case >>) is upcast to an int before the operation. This behaviour of the compiler is called integer promotion. And that's exactly what the compiler did: r19=...


15

You can not compress the hex code, you can only try to reduce it. Try different? compiler settings (maximum optimization and optimize for size) Pick your way through the source code and see what can be optimized or omitted. See if any unnecessary library code is pulled in. (It should not be, but who knows) Good point from Jeroen3: Check if you need/have ...


13

You could try making the loop actually do something. As it stands the compiler is quite rightly saying "This loop is doing nothing - I'll get rid of it". So you could try a construct I use frequently: int i; for (i = 0; i < 10; i++) { asm volatile ("nop"); } Note: not all targets for the gcc compiler use the same inline assembly syntax - you may ...


11

The MCU cannot execute compressed code. However, there are some things you can do: Instead of using full fledged library functions, create some or all of the functions yourself; this way you can optimize library functions that mostly are (too) flexible for your specific need. Remove duplicated code in your own code. Use parameters for almost duplicated ...


9

Four problems You are using a resistor voltage divider to power your MCU. Bad. Bad bad. You need a proper regulator. Or a USB (IE 5v) power supply. Heck, use 3 AA batteries instead of a 9v if you don't have a regulator. The ATMega line can take what, 2.5 to 5v normal range? You have nothing that really depends on a full 5v, no clock sensitive/dependent code....


9

Since in one comment you state that "each CPU tick is worthy" I suggest using some inline assembly to make your delays loop just as you want. This solution is superior to the various volatile or -O0 because it makes clear what your intent is. unsigned char i = 10; __asm__ volatile ( "loop: subi %0, 0x01\n\t" " brne loop" ...


8

"text" is actually code flash size, not SRAM. There are several problems here: 1) The "print" function pulls in a large amount of code for formatting format strings. This is dumb. The '85 only has 8 kB of flash total, compared to the 32 kB of the Arduino Uno. 2) The String class uses both some amount of code space, AND a lot of SRAM. The '85 only has 512 ...


8

Wow, that's pretty crazy. Those programs are almost identical. Just for easier comparison, the first program, with the assignment in main, has the assembly (with comments): 0: 20 9a sbi 0x04, 0 ; Set Bit of IO for DDRB 2: 28 9a sbi 0x05, 0 ; Set Bit of IO for PORTB 4: 00 c0 rjmp .+0 ; Relative JuMP of 0 bytes ...


8

In addition to the excellent suggestions provided in the other answers here I want to comment that there can be a huge difference in how much compilers (and linkers) can optimize code. I worked at a company some years back where the product was using the ATMega8. When I arrived on the scene this product had three different source code builds to provide ...


8

The first step for any kind of optimisation is find out what's doing it. Your first move should be to get the linker to dump the address of every identifier in the build. That's all functions and all variables. Your linker should also be able to report the sizes of functions; it probably won't do variable sizes, but you can infer those from the address of ...


7

libc, included with gcc and avr-gcc, has a function that's used to count leading zeros when converting from an int or uint into a float or a double. This function uses a 256 byte table to speed up the zero counting operation, which is fine for computers with lots of memory, but not so great for microcontrollers where 256 bytes is 1/4 or 1/8 of the total ram ...


7

The first rule of using interrupts: Keep them very short. When an interrupt occurs, whether it is enabled or not, and whether it is currently servicing an interrupt or not, an Interrupt Fired flag gets set. Every interrupt has one of these flags associated with it (such as SPSR.SPIF). That always gets set as soon as the interrupt fires. The interrupt ...


7

Straight off I see two issues - one sneaky, and one which shows a bit of a lack of understanding. The sneaky one is this line: char REC; REC is used within your interrupt and also outside your interrupt. As such it has to be flagged as volatile or the compiler is at risk of optimizing it out as it doesn't know it's being changed by the ISR. volatile ...


7

You'll need to inspect the output of avr-objdump to see what exact instructions were generated for your code. Incidentally, it would be helpful to include your C code in the disassembly via avr-objdump -S main.elf > main.s. I doubt that the whole program becomes different when you replace the 0x1F constant by 0x3F, isolating differences in the listing and ...


6

This may just be a typo in your post, but the line where you enable the Timer Compare interrupt says: TIMSK0 != (1 << OCIE0A); ... when it should say ... TIMSK0 |= (1 << OCIE0A); It's subtle, but if that's what your code actually was, then you were comparing TIMSK0 to a constant rather than assigning to it (and therefore never actually ...


6

Your moving average filter is rather inefficient; there's no need to shift the data, nor to calculate the total each time again. Instead of a FIFO implement it as a round robin: *i points to the oldest sample in the list* total -= samples[i] total += new_sample samples[i] = new_sample i = (i+1) mod 8 average = total >> 3 So you replace the ...


6

The expression like (1<<7) is actually constant, because its value is computed in compile time. It is equal to ldi R16, 128. As long this is the same instruction, the execution time will be the same.


6

Yes you could assume that. If you declare variable i as volatile you tell the compiler not to optimise on i.


6

With only 32 bytes of memory (as mentioned by MarkU in a comment), memory on the ATtiny10 is incredibly tight. The AVR-GCC compiler does not provide any tools for stack checking, and will happily generate code which will overrun the stack. For example, here's what it generated for the prologue to your ISR: 000000ba <__vector_4>: ba: 1f 93 ...


6

In an abstract manner the code does this: for each pin PA6 to PA4 (column) set pin as output, driving '0' for each pin PA3 to PA0 (row) if pin reads '0' then return key code calculated as row*3+column return 0xFF as key code, meaning "no key" KEYPAD_PORT|= 0X0F; should preset the output register of the port with '0's for PA6 to ...


6

There is no "practical" way to run compressed code on an AVR so your problem becomes "how do I optimize the size of my firmware". Toolchain tricks (ie. you don't have to modify your code): What is the compiler optimization level? In gcc the option to optimize for minimum size is called -Os There is a facility called link time optimization that can further ...


5

The AVR-Libc user manual has an entire chapter on how to build a library. I would suggest starting there. If you use an IDE like eclipse, there will be project settings that are applicable if you want to build as a library instead of an executable. Edit Here's what eclipse does when I set it up for your example: So that it couldn't be trivially compiled ...


5

Your problem: Your DDR setting is incorrect: You've written DDRC |= _BV(PC0) | _BV(PC1) | _BV(PC3) & _BV(PC2); but you want DDRC |= _BV(PC0) | _BV(PC1) | _BV(PC3) DDRC &= ~_BV(PC2); You say you want more detail because you just kinda emulated other DDRC assignments and don't really understand what you wrote? OK, here goes: How to set ...


5

You can declare an eeprom array and write individual positions. Note that unlike the ram array you can only read write to the eeprom array using the read/write eeprom macro. The code below is to read/write 16bit unsigned values #include <avr/io.h> #include <avr/eeprom.h> // macro for easier usage #define read_eeprom_word(address) ...


5

The conventional way to achieve what you want is to hand code the delay subroutine in the native assembly language. Almost all development tool sets that are C compilers will have the capability to include assembly language modules into the build. A common trick used by experienced programmers is to first build the delay routine in C code as you have done. ...


5

Don't declare your variable as volatile. That pretty much forces the compiler to use a memory location, and to access it on every loop iteration. Use register instead.


5

when i burn it on the kit it doesn't work . what is the wrong with this code ?? Who knows? Could be anything. You haven't told us how you know it doesn't work. But that is not relevant, I will tell you why. I will not address your particular code in my answer more than this: It is too big. It seems to me that this is your first project tested on ...


5

You need to be aware that as written your code will spin around the while loop dozens if not 100's of times seeing the one or the other of the switches pressed. Since your IF statement only checks for the '0' level of the switch input it will detect for as long as the input is active. So you will need to change your coding strategy some. Each time around ...


5

The DS18x20 series are digital thermometers using the One-Wire protocol on their data pin. Look up any of the Dallas/Maxim DS18b20 libraries to use this one. If, on the other had, you want an analog thermo-sensor, try the LM34/LM35 series of analog sensors (Fahrenheit/Celsius, respectively) which put voltage, proportional to temperature, on their data pin.


5

Here is your code with the comments that it should have had all along added in, plus tables showing exactly what the shift operations are doing (the latter shouldn't be necessary for any experienced C programmer): #define KEYPAD A #define KEYPAD_PORT PORT(KEYPAD) #define KEYPAD_DDR DDR(KEYPAD) #define KEYPAD_PIN PIN(KEYPAD) uint8_t GetKeyPressed() { ...


Only top voted, non community-wiki answers of a minimum length are eligible