¿Los punteros se tratan de manera diferente en AVR en comparación con, digamos, x86?

7

Microcontrolador: ATtiny13

IDE: Atmel Studio

Estoy intentando escribir una aplicación Hello World escribiendo alto al puerto PB4.

Esto funciona bien:

int main(void)
{
    DDRB = 0x10;
    PORTB = 0x10;

    while(1)
    {
    }
}

Mirando la definición de DDRB y PORTB, apuntan a 0x17 y 0x18, como se esperaba.

Esto, sin embargo, no funciona:

int main(void)
{
    char *dir = (void *)0x17;
    char *port = (void *)0x18;

    *dir = (unsigned int)0x10;
    *port = (unsigned int)0x10;

    while(1)
    {
    }
}

¿Mi código es incorrecto o debo hacer algo más para usar punteros?

    
pregunta tgun926

1 respuesta

23

Los punteros son punteros. Eso es lo que son. No se les trata de manera diferente (¿cómo podría tratarlos de manera diferente?)

Las principales diferencias entre X86 y AVR son:

  • AVR es de 8 bits, X86 es de 32 bits (o 64 bits para x86_64), por lo que los punteros tienen un tamaño diferente.
  • El AVR es la arquitectura de Harvard modificada, por lo que hay más de un espacio de direcciones, por lo que debe asegurarse de que está haciendo referencia al espacio de direcciones correcto.

Además, su código no tiene sentido:

char *dir = (void *)0x17;

¿Asignar un void * a un char *?

error: invalid conversion from ‘void*’ to ‘char*’

No estoy configurado para compilar ATTiny13 en este momento, por lo que estos números son todos para ATMega328p:

Al acceder a los resultados de DDRB y PORTB en este ensamblaje:

12c:    80 e1           ldi r24, 0x10   ; 16  
12e:    84 b9           out 0x04, r24   ; 4
130:    85 b9           out 0x05, r24   ; 5

El acceso de un puntero a una ubicación de memoria da como resultado este ensamblaje:

12c:    80 e1           ldi r24, 0x10   ; 16
12e:    80 93 17 00     sts 0x0017, r24
132:    80 93 18 00     sts 0x0018, r24

Como puede ver, DDRB y PORTB no son variables normales. DDRB se define como:

#define DDRB _SFR_IO8(0x04)

y PORTB como:

#define PORTB _SFR_IO8(0x05)

_SFR_IO8 () es una macro:

#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)

y _MMIO_BYTE es:

#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))

__SFR_OFFSET puede ser 0 o 0x20 dependiendo del chip (normalmente 0x20).

Entonces, eso debe significar que las direcciones de DDRB y PORTB deben ser más de 0x20.

Mirando el chip 328P, DDRB es 0x04 y PORTB es 0x05. Entonces, accediendo como 0x24 y 0x25, con los tipos de datos correctos por lo tanto:

volatile uint8_t *dir = (volatile uint8_t *)0x24;
volatile uint8_t *port = (volatile uint8_t *)0x25;

*dir = 0x10;
*port = 0x10;

da como resultado este ensamblaje:

12c:    80 e1           ldi r24, 0x10   ; 16
12e:    84 b9           out 0x04, r24   ; 4
130:    85 b9           out 0x05, r24   ; 5

¿Te resulta familiar? El compilador reconoció el desplazamiento 0x20, se dio cuenta de que eran SFR y compiló las instrucciones correctas out sin el desplazamiento 0x20.

Por lo tanto, el acceso a las direcciones de su puerto + 0x20 puede funcionar para el ATTiny13.

Solo mirando el ATTiny25, el DDRB = 0x10 resulta en:

out 0x17, r24

y acceder a un puntero en la dirección 0x37 da como resultado:

out 0x17, r24

Por lo que parece que probablemente sea así (agregue 0x20 a su dirección de puntero).

    
respondido por el Majenko

Lea otras preguntas en las etiquetas