Работа с GPIO Atmega128a в MicrochipStudio

Начинаю работать с микроконтроллерами Atmega, пробую просто зажечь светодиод и столкнулся со странным поведением. Вот код:

void GPIO_init(void)
{
    DDRE |= BIT7; // red LED
    DDRD |= BIT6; // yellow LED
    
    //PORTE |= BIT7;
}
int main(void)
{
    GPIO_init();
    PORTE |= BIT7;
    while (1);
}

Светодиод на пине 7 порта Е. Если PORTE |= BIT7 делать в main - светодиод не зажигается, а если в функции GPIO_init() - нормально светится, как и должен. В симуляторе одинаково работает в обоих случаях, а в железе нет. В чём может быть причина?

Вот ассемблерные листинги для случая когда код не работает в железе:

00000046  CLR R1            Clear Register 
00000047  OUT 0x3F,R1       Out to I/O location 
00000048  SER R28           Set Register 
00000049  LDI R29,0x10      Load immediate 
0000004A  OUT 0x3E,R29      Out to I/O location 
0000004B  OUT 0x3D,R28      Out to I/O location 
0000004C  RCALL PC+0x0014   Relative call subroutine 
0000004D  RJMP PC+0x0022    Relative jump 
0000004E  RJMP PC-0x004E    Relative jump 
0000004F  PUSH R28          Push register on stack 
00000050  PUSH R29          Push register on stack 
00000051  IN R28,0x3D       In from I/O location 
00000052  IN R29,0x3E       In from I/O location 
    DDRE |= 0x80; // red LED
00000053  LDI R24,0x22      Load immediate 
00000054  LDI R25,0x00      Load immediate 
00000055  LDI R18,0x22      Load immediate 
00000056  LDI R19,0x00      Load immediate 
00000057  MOVW R30,R18      Copy register pair 
00000058  LDD R18,Z+0       Load indirect with displacement 
00000059  ORI R18,0x80      Logical OR with immediate 
0000005A  MOVW R30,R24      Copy register pair 
0000005B  STD Z+0,R18       Store indirect with displacement 

0000005C  NOP           No operation 
0000005D  POP R29       Pop register from stack 
0000005E  POP R28       Pop register from stack 
0000005F  RET           Subroutine return 

00000060  PUSH R28      Push register on stack 
00000061  PUSH R29      Push register on stack 
00000062  IN R28,0x3D   In from I/O location 
00000063  IN R29,0x3E   In from I/O location 
    GPIO_init();
00000064  RCALL PC-0x0015       Relative call subroutine 
    PORTE |= 0x80;
00000065  LDI R24,0x23      Load immediate 
00000066  LDI R25,0x00      Load immediate 
00000067  LDI R18,0x23      Load immediate 
00000068  LDI R19,0x00      Load immediate 
00000069  MOVW R30,R18      Copy register pair 
0000006A  LDD R18,Z+0       Load indirect with displacement 
0000006B  ORI R18,0x80      Logical OR with immediate 
0000006C  MOVW R30,R24      Copy register pair 
0000006D  STD Z+0,R18       Store indirect with displacement 
    while (1);
0000006E  RJMP PC-0x0000        Relative jump 

А вот когда работает:

00000046  CLR R1        Clear Register 
00000047  OUT 0x3F,R1       Out to I/O location 
00000048  SER R28       Set Register 
00000049  LDI R29,0x10      Load immediate 
0000004A  OUT 0x3E,R29      Out to I/O location 
0000004B  OUT 0x3D,R28      Out to I/O location 
0000004C  RCALL PC+0x001D       Relative call subroutine 
0000004D  RJMP PC+0x0022        Relative jump 
0000004E  RJMP PC-0x004E        Relative jump 

0000004F  PUSH R28      Push register on stack 
00000050  PUSH R29      Push register on stack 
00000051  IN R28,0x3D       In from I/O location 
00000052  IN R29,0x3E       In from I/O location 
    DDRE |= 0x80; // red LED
00000053  LDI R24,0x22      Load immediate 
00000054  LDI R25,0x00      Load immediate 
00000055  LDI R18,0x22      Load immediate 
00000056  LDI R19,0x00      Load immediate 
00000057  MOVW R30,R18      Copy register pair 
00000058  LDD R18,Z+0       Load indirect with displacement 
00000059  ORI R18,0x80      Logical OR with immediate 
0000005A  MOVW R30,R24      Copy register pair 
0000005B  STD Z+0,R18       Store indirect with displacement 
    PORTE |= 0x80;
0000005C  LDI R24,0x23      Load immediate 
0000005D  LDI R25,0x00      Load immediate 
0000005E  LDI R18,0x23      Load immediate 
0000005F  LDI R19,0x00      Load immediate 
00000060  MOVW R30,R18      Copy register pair 
00000061  LDD R18,Z+0       Load indirect with displacement 
00000062  ORI R18,0x80      Logical OR with immediate 
00000063  MOVW R30,R24      Copy register pair 
00000064  STD Z+0,R18       Store indirect with displacement 

00000065  NOP       No operation 
00000066  POP R29       Pop register from stack 
00000067  POP R28       Pop register from stack 
00000068  RET       Subroutine return 

00000069  PUSH R28      Push register on stack 
0000006A  PUSH R29      Push register on stack 
0000006B  IN R28,0x3D       In from I/O location 
0000006C  IN R29,0x3E       In from I/O location 
    GPIO_init();
0000006D  RCALL PC-0x001E       Relative call subroutine 
    while (1);
0000006E  RJMP PC-0x0000        Relative jump 

Ответы (1 шт):

Автор решения: User_128

Проблема была аппаратная: перепаял микроконтроллер и всё заработало как надо

UPD: Замена чипа не помогла, просто забыл выключить оптимизацию, а с оптимизацией компилятор инлайнил функцию. А проблема возникала именно при возврате из функции. Так что новый чип вёл себя точно так же. В итоге я подпаялся JTAGом, посмотрел как меняются регистры. Оказалось, что по умолчанию указатель на стек указывает на пределы оперативной памяти, процессор не мог сохранить туда адрес возврата, а потому каждый раз из функции возвращался в участок памяти, где ничего нет. В настройках проекта есть пункт "начальный адрес стека". Я вписал туда адрес конца оперативной памяти (минус 2 байта), скомпилировал проект - и всё заработало

→ Ссылка