Atmega Dynamische Portzuweisung in Schleife

#5657036
Lesenswert?

Hi!

ich bastle gerade etwas mit einem Atmega2560 in c++ herum. Ich möchte 
gern in einer for-Schleife die Ports beschreiben.
Also mit
1
i=0    PORTA |= (....);
2
i=1    PORTC |= (....);
3
i=2    PORTD |= (....);
4
...

Der Übersichtlichkeit halber habe ich die entsprechenden Ports definiert 
als
1
#define CC0  PORTA
2
#define CC1  PORTC
3
#define CC2  PORTD
4
...
und hatte auf eine Möglichkeit gehofft, in der Schleife jetzt dynamisch 
a la CCi zuzugreifen. Aber die Möglichkeit gibt es ja in c++ nicht. Bin 
aber überfordert ob man einen Pointer auf PORTA setzen kann? Was sagt 
die Schwarmintelligenz?
#5657049
Lesenswert?

Ja, man kann. Schließlich verbirgt sich hinter den PORTn-Defines nichts 
anderes als ein Pointer. Schau dir die Definition im Header an. Das 
nutzt dir aber letztendlich nicht viel, weil die Port-Register nicht 
direkt hintereinander im Adressraum angeordnet sind.

Am saubersten ist da ein switch oder ein if/else if, oder aber ein Array 
mit den Port-Pointern mit Zugriff über den Index.

Oliver
#5657055
Lesenswert?

Hmm, ich hatte das _SFR_IO8(0X02) schon gesehen aber kann damit nicht 
viel anfangen. Eine switch-Anweisung wird da halt übel ausladend bei 7 
Ports. Hätte das echt gern als Schleife gemacht.

Edit: Ah also das _SFR_IO8(0X02) in ein Array legen und dann auf die 
Adresse zugreifen geht? Dann werd ich damit mal rumprobieren.
Moderator (Firma: Titel) Persönliche Seite #5657064
Lesenswert?

Hannes J. schrieb:
> ich hatte das _SFR_IO8(0X02) schon gesehen aber kann damit nicht viel
> anfangen.
Das ist auch nur ein Makro. Und das Drama löst sich in der sfr_defs.h 
(ein Stück weit) auf:
1
    #define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)
Jetzt musst du nur noch das Makro _MMIO_BYTE() auflösen und den 
__SFR_OFFSET suchen, und du kannst dann daraus die Adresse berechnen.

Oder im Netz nach diesen Makros suchen. Diese Frage hatten schon einige 
vor dir:
https://www.avrfreaks.net/forum/how-does-macro-mmioword-actually-work
Und zum Schluss findest du heraus, dass das "nur" eine RAM-Adresse ist, 
die du sogar im Datenblatt wiederfindest...  ;-)

Stefanus F. schrieb:
> Ja, aber alle anderen Methoden sind unterm Strich auch nicht eleganter.
Man könnte mit dem Index über eine Pointertabelle fahren...
#5657475
Lesenswert?

Lothar M. schrieb:
> Das ist auch nur ein Makro. Und das Drama löst sich in der sfr_defs.h
> (ein Stück weit) auf:
>
1
>     #define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)
2
>
> Jetzt musst du nur noch das Makro _MMIO_BYTE() auflösen und den
> __SFR_OFFSET suchen, und du kannst dann daraus die Adresse berechnen.
>
> Oder im Netz nach diesen Makros suchen. Diese Frage hatten schon einige
> vor dir:
> https://www.avrfreaks.net/forum/how-does-macro-mmioword-actually-work
> Und zum Schluss findest du heraus, dass das "nur" eine RAM-Adresse ist,
> die du sogar im Datenblatt wiederfindest...  ;-)
> [...]
> Man könnte mit dem Index über eine Pointertabelle fahren...


Ah danke für die erhellende Antwort! Damit kann ich mich doch mal 
außeinandersetzen. :)
#5657693
Lesenswert?

Hannes J. schrieb:
> Eine switch-Anweisung wird da halt übel ausladend bei 7
> Ports. Hätte das echt gern als Schleife gemacht.

Switch kann man auch in einer Schleife aufrufen.
Du kannst Ports über deren Adresse ansprechen, nur wird das viel 
aufwändiger als ein Switch, da die Adressen 16bittig sind.
Auch sind die Ports nicht hintereinander angeordnet, d.h. Du must Dir 
die Adresse erst aus einem Array der Portadressen holen.
Bei nur 7 Case ist ein Switch daher schneller und weniger Code.
#5657897
Lesenswert?

Peter D. schrieb:
>
> Switch kann man auch in einer Schleife aufrufen.

Schon klar, mit Schleife brauche ich aber keine switch mehr und mit 
switch keine Schleife.

> Du kannst Ports über deren Adresse ansprechen, nur wird das viel
> aufwändiger als ein Switch, da die Adressen 16bittig sind.
> Auch sind die Ports nicht hintereinander angeordnet, d.h. Du must Dir
> die Adresse erst aus einem Array der Portadressen holen.
> Bei nur 7 Case ist ein Switch daher schneller und weniger Code.

Dazu ein paar Fragen..
Genau das ist was ich machen will, warum meinst du sollte das mit 
Schleife aufwändiger werden als switch? Wenn ich die Adressen in ein 
Array packe kann ich das doch in der Schleife durchgehen, 
dereferenzieren und ich hab was ich will? Ob 8 oder 16 Bit macht doch 
keinen Unterschied, außer dass ich uint16_t* schreibe anstatt uint8_t*? 
Eine switch kommt mir hier fehl am Platze vor, weil im Prinzip in jedem 
Port die gleiche Operation erfolgt, nur mit unterschiedlichen Daten. Ich 
hätte also 14x den gleichen Befehl anstatt 2x.

Was mich jetzt noch verwirrt: Die Adressen der meisten Ports haben 8 
Bit. Erst ab Port H sind es mehr. Port H hat bspw. die Adresse 0x102. Am 
Ende der Macro-Kette werden die aber alle gecasted auf (*(volatile 
uint8_t *)(mem_addr)). Da wird doch die führende 1 abgeschnitten? Warum 
dann überhaupt 0x102?
#5657924
Lesenswert?

Ja ist mir auch gerade aufgefallen. Vor 12 klappt das mit dem denken 
noch nicht so ;-)

Sollte doch dann so funktionieren?:
1
volatile uint8_t * _ptrList[7];
2
// Fill pointer list
3
_ptrList[0] = &PORTA;
4
_ptrList[1] = &PORTB;
5
_ptrList[2] = &PORTD;
6
_ptrList[3] = &PORTE;
7
_ptrList[4] = &PORTF;
8
_ptrList[5] = &PORTH;
9
_ptrList[6] = &PORTJ;
10

11
// Assign row
12
for(uint8_t i=0; i<7; i++)
13
{
14
  *_ptrList[i] = prop.getRow(i);
15
  [...]
16
}
#5657970
Lesenswert?

Hannes J. schrieb:
> Wenn ich die Adressen in ein
> Array packe kann ich das doch in der Schleife durchgehen

Genauso würde ich das machen.
1
volatile uint8_t* ports[] =
2
{
3
  &PORTA,
4
  &PORTC,
5
  &PORTD,
6
  &PORTE,
7
  /* ... */
8
}
9

10
for (uint8_t i=0; i<(sizeof(ports)/sizeof(ports[0]); i++)
11
{
12
  *(ports[i]) |= /* ... */;
13
}

Wie man drauf kommt? Man liest die Dokumentation:

https://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_port_pass
#5657977
Lesenswert?

Oliver S. schrieb:
> Du hast Dir die Makros immer noch nicht angesehen.
>
> Oliver

Um ehrlich zu sein, doch..

Axel S. schrieb:
> Genauso würde ich das machen.
>
>
1
> volatile uint8_t* ports[] =
2
> {
3
>   &PORTA,
4
>   &PORTC,
5
>   &PORTD,
6
>   &PORTE,
7
>   /* ... */
8
> }
9
> 
10
> for (uint8_t i=0; i<(sizeof(ports)/sizeof(ports[0]); i++)
11
> {
12
>   *(ports[i]) |= /* ... */;
13
> }
14
>
>
> Wie man drauf kommt? Man liest die Dokumentation:
>
> https://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_port_pass

Thx!

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren