1
\$\begingroup\$

I have had lots of problems trying to get a piece of firmware to work which has worked fine earlier, and is working on a copy of the board I'm having problems with. I've narrowed in down to the following (at least to start with):

This piece of code works:

#define F_CPU 8000000

#include <avr/io.h>
#include <util/delay.h>

int main(void)
{   
   // LEDs - initial setting
   DDRC |= 0x03;                // LEDs on pins PC0 and PC1 
   PORTC &= ~(1<<0);             // LED0 OFF
   PORTC |= (1<<1);             // LED1 ON

   DDRD |= 0x30;    // PD4..5 OUT
   TCCR1A = 0xE2;   //0b11100010 (Set OC1A + Clear OC1B on compare match, )
   TCCR1B = 0x19;   //0b00011001 (WGM13:10 = 0b1110 => Fast PWM Mode, TOP = ICR1, CS12:0 = 001 => Use IO clock, no prescaling)
   OCR1A = 18;
   OCR1B = 18;      //  18 / 8000000 =  2.25 us (Output compare match value (OC1A->HIGH, OC1B->LOW)
   ICR1 = 757;      // 757 / 8000000 = 94.625us (TOP value for timer1)

   // Loop blinks LED0..1 alternately
   while(1)
   {
       PORTC = PORTC ^ 0x03;
       _delay_ms(250);
   }
}

It starts the timer and outputs the pulse with the specified timing, and enters the blinking LED loop.

However, this code fails:

#define F_CPU 8000000

#include <avr/io.h>
#include <util/delay.h>

void pulse_init(void)
{   
   DDRD |= 0x30;    // PD4..5 OUT
   TCCR1A = 0xE2;   //0b11100010 (Set OC1A + Clear OC1B on compare match, )
   TCCR1B = 0x19;   //0b00011001 (WGM13:10 = 0b1110 => Fast PWM Mode, TOP = ICR1, CS12:0 = 001 => Use IO clock, no prescaling)
   OCR1A = 18;
   OCR1B = 18;      //  18 / 8000000 =  2.25 us (Output compare match value (OC1A->HIGH, OC1B->LOW)
   ICR1 = 757;      // 757 / 8000000 = 94.625us (TOP value for timer1)
}


int main(void)
{   
   // LEDs - initial setting
   DDRC |= 0x03;                // LEDs on pins PC0 and PC1 
   PORTC &= ~(1<<0);            // LED0 OFF
   PORTC |= (1<<1);         // LED1 ON

   pulse_init();

   // Loop blinks LED0..1 alternately
   while(1)
   {
       PORTC = PORTC ^ 0x03;
       _delay_ms(250);
   }
}

...it's just the same statements as before, moved to the pulse_init() function. When I upload this code the timer is set up correctly and the output pulse is OK, but the program never starts blinking the LEDs on PC0..1.

Any ideas? It's not just this function, this is part of a bigger program with other initalization functions and it seems whenever the program enters a function separate from the main loop it fails to return to main. I am not so familiar with C and how it works on the function block level. I am using Atmel Studio 7 now with the following compiler options:

-x c -funsigned-char -funsigned-bitfields -DDEBUG  -I"C:\Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.1.130\include"  -O1 -ffunction-sections -fdata-sections -fpack-struct -fshort-enums -g2 -Wall -Wextra -pedantic -mmcu=atmega32 -B "C:\Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.1.130\gcc\dev\atmega32" -c -std=gnu99 -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)"

but I had the same problems with avrdude. I also tried reading the full binary from the working board and writing it to the board I'm working on. It should communicate with PC over a USB-to-serial but it doesn't work. When I power up the board it spews a few kilobytes on nonsense to the serial (the same nonsense every time, though) and then freezes, i.e. doesn't send the regular "Waiting for command" message or reply to any commands.

The chip is Atmega32L8AU, 8MHz external crystal, LFUSE=0xFF, HFUSE=0x99.

Any ideas?

Edit: SOLVED - The firmware works after changing the AVR chip. Turns out to be a faulty memory area in the SRAM or possibly something wrong with the SRAM/GPR bus. This was suggested by in comments to Maximus' answer below.

Thank you for all your help!

\$\endgroup\$
  • \$\begingroup\$ Codewise, there's nothing wrong with what you've done. I can't see any obvious problem, a single function called once shouldn't be a problem unless you have zero size for the stack. If I understood your question correctly and it works on one board but not on another, I would suspect hardware rather than software. \$\endgroup\$ – Roger Rowland Dec 28 '16 at 11:00
  • 2
    \$\begingroup\$ Might be incorrect stack setup. Triple-check that the correct part ist used when linking the project. \$\endgroup\$ – Turbo J Dec 28 '16 at 11:56
  • \$\begingroup\$ @RogerRowland I haven't actually tried compiling and programming the board that is already working with my updated code for fear of bricking it. What I have done is read the hex file off that board and program the board I'm working on with it, and it doesn't work. I suspect hardware problems as well, but I can't for the life of me find any... Maybe the chip is damaged. I just wanted to get a second opinion on the coding aspect. \$\endgroup\$ – Snorre O. Dec 28 '16 at 12:02
  • \$\begingroup\$ @TurboJ : The linker options: -Wl,-Map="$(OutputFileName).map" -Wl,--start-group -Wl,-lm -Wl,--end-group -Wl,--gc-sections -mmcu=atmega32 -B "C:\Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.1.130\gcc\dev\atmega32" It's the correct part number at least, but for the other parameters I'm not so familiar with them. \$\endgroup\$ – Snorre O. Dec 28 '16 at 12:03
  • 2
    \$\begingroup\$ @SnorreO. - the resolution of your question should not be edited into your question, as a question here is not "resolved" until an answer is accepted. If none of the existing answers contain your solution, you can post your own answer explaining it. Your theory, while not impossible does seem rather unlikely however. \$\endgroup\$ – Chris Stratton Jan 9 '17 at 7:25
1
\$\begingroup\$

Have you considered the warnings in your compiler (if any) ?

Your problem seems to me like there is an issue with function decleration, perhaps. Can you try to declare the function first on top of main and put function body at the bottom of main.c? Does the issue persists?

Also, have you tried debugger of atmel studio? If you haven't yet, please try and execute step by step. Observe the registers and see how they change.

One more question, can you do a simple error checking/tracking? For example,

#define F_CPU 8000000

#include <avr/io.h>
#include <util/delay.h>

uint8_t PROG_STATE = 0;
void Send_to_PC(uint8_t DATA);

void pulse_init(void)
{   
   PROG_STATE = 3;
   Send_to_PC(PROG_STATE);
   DDRD |= 0x30;    // PD4..5 OUT
   TCCR1A = 0xE2;   //0b11100010 (Set OC1A + Clear OC1B on compare match, )
   TCCR1B = 0x19;   //0b00011001 (WGM13:10 = 0b1110 => Fast PWM Mode, TOP = ICR1, CS12:0 = 001 => Use IO clock, no prescaling)
   OCR1A = 18;
   OCR1B = 18;      //  18 / 8000000 =  2.25 us (Output compare match value (OC1A->HIGH, OC1B->LOW)
   ICR1 = 757;      // 757 / 8000000 = 94.625us (TOP value for timer1)
}


int main(void)
{   
   PROG_STATE = 1;
   Send_to_PC(PROG_STATE);
   // LEDs - initial setting
   DDRC |= 0x03;                // LEDs on pins PC0 and PC1 
   PORTC &= ~(1<<0);            // LED0 OFF
   PORTC |= (1<<1);         // LED1 ON
   PROG_STATE = 2;
   Send_to_PC(PROG_STATE);
   pulse_init();
   PROG_STATE = 4;
   Send_to_PC(PROG_STATE);
   // Loop blinks LED0..1 alternately
   while(1)
   {
       PROG_STATE = 5;
       Send_to_PC(PROG_STATE);
       PORTC = PORTC ^ 0x03;
       _delay_ms(250);
       PROG_STATE = 6;
       Send_to_PC(PROG_STATE);
   }
}

void Send_to_PC(uint8 DATA){
//RS232 OR I2C etc
}

You get the idea. If you do something like this, then you can observe the state of your program live (apart from the debugger).

Edit:

Added Atmega32/32L internal block diagram

enter image description here

enter image description here

enter image description here

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ I think you mean declaration? The C language doesn't define any "function initialization", although an actual implementation may have steps needed before calling a function, such as copying the code segment from flash to RAM. \$\endgroup\$ – Ben Voigt Dec 28 '16 at 18:27
  • \$\begingroup\$ Yes, decleration. I'll edit my post. \$\endgroup\$ – user132236 Dec 28 '16 at 19:20
  • 1
    \$\begingroup\$ @BenVoigt, @ Maximus: I changed the chip, and it worked! Must have been a faulty SRAM area as you suggested. Thank you all for all your help :) PS I'm not sure about how to proceed in the stackexchange-correct way now, should I mark this one as the answer or make and accept a new answer referring Maximus' comment about memory fault? \$\endgroup\$ – Snorre O. Dec 29 '16 at 9:32
  • 1
    \$\begingroup\$ @SnorreO. Wow, man! Well, I suppose the SRAM could be faulty. If flash data was corrupt, wouldn't it become appearant when your IDE verifies the uploaded HEX? I think it could also be a fault on the program memory->SRAM/GPR line as well (data gets corrupt during transmission). But then it would be random so you wouldn't have done anything at all?I would suggest that you read the SRAM/GPR in debug mode, perhaps. I bet that there is a corrupt byte in there that tells the CPU to do an undefined operation so the CPU quits to the last verified stack in the program memory. (Just a guess) \$\endgroup\$ – user132236 Dec 29 '16 at 16:48
  • 1
    \$\begingroup\$ @SnorreO.: I've been working with AVR 8-bit controllers for 10+ years and never had a "faulty SRAM". I would classify this as highly unlikely. Are you able to change the controller back and verify that is does not work with the EXACT same code. Make also sure that the fuse bits are configured identically. \$\endgroup\$ – Rev1.0 Jan 9 '17 at 7:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.