Forum: Mikrocontroller und Digitale Elektronik SamC21 - Outputtoggle funktioniert nicht wie erwartet


von Ali K. (teddy50)


Lesenswert?

Hallo Zusammen,
Ich beschäftige mich zur Zeit mit dem AtsamC21J18A auf dem XPlained 
Board.
Die Registerzugriffe mache ich selbst zu Fuß mithilfe von CMSIS und 
Microchips DFP.

Beim Port ist mir aufgefallen, dass das Toggeln eines Pins nicht so 
funktioniert wie gewünscht. Scheinbar werden andere aktive PortPins 
gelöscht, wenn ein anderer getoggelt wird.
1
static void GetPortRegister(PortPin *me)
2
{
3
  if(me->port == PORT_A)
4
    port_register = (port_registers_t*)(0x41000000);
5
  else
6
    port_register = (port_registers_t*)((0x41000000)+0x80);
7
}
8
void HAL_Portpin_OutputToggle(PortPin *me)
9
{
10
  ASSERT(me == NULL)
11
12
  GetPortRegister(me);
13
14
  port_register->GROUP->PORT_OUTTGL |= (1UL << me->pin); // Hier werden andere aktive Pins gelöscht!
15
}

Als Alternative habe ich es jetzt so umgesetzt:
1
void HAL_Portpin_OutputToggle(PortPin *me)
2
{
3
  ASSERT(me == NULL)
4
5
  GetPortRegister(me);
6
7
  if(GetOutputLevel(me) == LEVEL_HIGH)
8
    HAL_Portpin_SetOutputLevel(me, LEVEL_LOW);
9
  else
10
    HAL_Portpin_SetOutputLevel(me, LEVEL_HIGH);
11
}
12
void HAL_Portpin_SetOutputLevel(PortPin *me, Level level)
13
{
14
  ASSERT(me == NULL || level > 1)
15
16
  GetPortRegister(me);
17
18
  if(level == LEVEL_HIGH)
19
    port_register->GROUP->PORT_OUT |= (1UL << me->pin);
20
  else
21
    port_register->GROUP->PORT_OUT &= ~(1UL << me->pin);
22
}

Die Frage ist, was mache ich falsch?
Wie kann ich verhindern, dass andere aktive Pins gelöscht werden, wenn 
ich OUTTGL nutze?

Viele Grüße

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ali K. schrieb:
> port_register->GROUP->PORT_OUTTGL |= (1UL << me->pin); // Hier werden
> andere aktive Pins gelöscht!

Klar. Du hast denn Sinn des Toggle-Controls falsch verstanden.

Du schreibst eine '1' in die Bits, die getoggelt werden sollen. Wenn du 
(was du machst) vorher erstmal alle Bits ausliest, danach ein Bit 
hinzufügst und neu schreibst – dann toggelst du alle Bits, die als '1' 
zurück gelesen worden waren (vermutlich alle die, die schon gesetzt 
waren).

Der Sinn des Toggle-Controls ist ja gerade, dass man kein 
read-modify-write erst machen muss.
1
port_register->GROUP->PORT_OUTTGL = (1UL << me->pin);

Die Adressen der Ports sollte man sich über die zuständigen device 
header files beschaffen.
1
#include "sam.h"
2
3
#define PORTA PORT->Group[0]
4
#define PORTB PORT->Group[1]
5
6
// ...
7
  PORTA.OUTTGL.bit.OUTTGL = (1 << 18);

: Bearbeitet durch Moderator
von Ali K. (teddy50)


Lesenswert?

Hey danke für die Antwort.
Das hatte ich befürchtet!
Dann bleibt mir wohl keine andere Möglichkeit über, als meine Lösung 
umzusetzen.

Die Adresse habe ich aus dem Datenblatt, weil im Header-File keine 
Adressen zu finden sind.

Den Ausschnitt habe ich aus port.h.
Ich nutze die DFP Version 3.8.119 (2022-03-17)
https://packs.download.microchip.com/
1
typedef struct
2
{
3
  __IO  uint32_t                       PORT_DIR;           /**< Offset: 0x00 (R/W  32) Data Direction */
4
  __IO  uint32_t                       PORT_DIRCLR;        /**< Offset: 0x04 (R/W  32) Data Direction Clear */
5
  __IO  uint32_t                       PORT_DIRSET;        /**< Offset: 0x08 (R/W  32) Data Direction Set */
6
  __IO  uint32_t                       PORT_DIRTGL;        /**< Offset: 0x0C (R/W  32) Data Direction Toggle */
7
  __IO  uint32_t                       PORT_OUT;           /**< Offset: 0x10 (R/W  32) Data Output Value */
8
  __IO  uint32_t                       PORT_OUTCLR;        /**< Offset: 0x14 (R/W  32) Data Output Value Clear */
9
  __IO  uint32_t                       PORT_OUTSET;        /**< Offset: 0x18 (R/W  32) Data Output Value Set */
10
  __IO  uint32_t                       PORT_OUTTGL;        /**< Offset: 0x1C (R/W  32) Data Output Value Toggle */
11
  __I   uint32_t                       PORT_IN;            /**< Offset: 0x20 (R/   32) Data Input Value */
12
  __IO  uint32_t                       PORT_CTRL;          /**< Offset: 0x24 (R/W  32) Control */
13
  __O   uint32_t                       PORT_WRCONFIG;      /**< Offset: 0x28 ( /W  32) Write Configuration */
14
  __IO  uint32_t                       PORT_EVCTRL;        /**< Offset: 0x2C (R/W  32) Event Input Control */
15
  __IO  uint8_t                        PORT_PMUX[16];      /**< Offset: 0x30 (R/W  8) Peripheral Multiplexing n */
16
  __IO  uint8_t                        PORT_PINCFG[32];    /**< Offset: 0x40 (R/W  8) Pin Configuration n */
17
  __I   uint8_t                        Reserved1[0x20];
18
} port_group_registers_t;
19
20
#define PORT_GROUP_NUMBER 2
21
22
/** \brief PORT register API structure */
23
typedef struct
24
{  /* Port Module */
25
        port_group_registers_t         GROUP[PORT_GROUP_NUMBER]; /**< Offset: 0x00  */
26
} port_registers_t;

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ali K. schrieb:
> Dann bleibt mir wohl keine andere Möglichkeit über, als meine Lösung
> umzusetzen.

Was gefällt dir denn nicht daran, einfach das Bit zu setzen, wie ich es 
dir gezeigt habe? Genau das toggelt den Ausgang, das ist der Sinn des 
Toggle-Registers. Nicht irgendwelcher read-modify-write-Kram (wie dein 
"|=" es erzeugt).

> Die Adresse habe ich aus dem Datenblatt, weil im Header-File keine
> Adressen zu finden sind.

Das obige Schnipsel war ein Stück aus realem Code, welches PA18 toggelt. 
Entscheidend ist das erste #include, zusammen mit den passenden 
Definitionen auf der Compiler-Kommandozeile zieht sich das die 
entsprechenden Definitionen für deine MCU rein.

Bei mir steht dafür im Makefile:
1
CDEFS += -D__SAMD20J18__

Wie dieses #define in deiner Entwicklungsumgebung generiert wird, 
müsstest du selbst sehen.

von Ali K. (teddy50)


Lesenswert?

Jörg W. schrieb:
> Ali K. schrieb:
>> Dann bleibt mir wohl keine andere Möglichkeit über, als meine Lösung
>> umzusetzen.
>
> Was gefällt dir denn nicht daran, einfach das Bit zu setzen, wie ich es
> dir gezeigt habe? Genau das toggelt den Ausgang, das ist der Sinn des
> Toggle-Registers. Nicht irgendwelcher read-modify-write-Kram (wie dein
> "|=" es erzeugt).
>

Ich kann nicht bitweise zugreifen, siehe Ausschnitt oben

>> Die Adresse habe ich aus dem Datenblatt, weil im Header-File keine
>> Adressen zu finden sind.
>
> Das obige Schnipsel war ein Stück aus realem Code, welches PA18 toggelt.
> Entscheidend ist das erste #include, zusammen mit den passenden
> Definitionen auf der Compiler-Kommandozeile zieht sich das die
> entsprechenden Definitionen für deine MCU rein.
>
> Bei mir steht dafür im Makefile:
>
>
1
> CDEFS += -D__SAMD20J18__
2
>
>
> Wie dieses #define in deiner Entwicklungsumgebung generiert wird,
> müsstest du selbst sehen.

Muss ich prüfen, danke.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ali K. schrieb:
> Ich kann nicht bitweise zugreifen, siehe Ausschnitt oben

Glaub ich dir nicht. Dein Ausschnitt oben zeigt ein komplett vergurktes 
Beispiel. Ich habe versucht, dir zu erklären, warum es vergurkt ist, 
aber ich bin mir nicht sicher, ob du das verstanden hast.

Nochmal so kurz wie möglich gefasst: der ODER-Operator ("|") hat bei 
Toggle-Register einfach nichts zu suchen, der muss weg.

von Ali K. (teddy50)


Lesenswert?

Vielen Dank, Du hast mir sehr geholfen.
ich hatte einen Brett vorm Kopf.


viele grüße

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Schön, wenn du es jetzt abnehmen konntest, freut mich. :-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.