Forum: Compiler & IDEs (msp430)gcc Preprocessor Macro Frage


von Eduard I. (eiten)


Lesenswert?

Hallo zusammen,

ich bin gerade dabei, mich in den msp430 einzuarbeiten. Da habe ich nun 
folgendes Problem: von verschiedener Peripherie, zum Beispiel den eUSCIs 
(Enhanced Universal Serial Communication Interface) gibt's mehrere. 
Damit ich die Funktionen nicht mehrfach schreiben muss, wie zum Beispiel
1
void eUSCI_A0_softreset(void) {
2
  UCA0CTLW0 |= UCSWRST; 
3
}
4
void eUSCI_A1_softreset(void) {
5
  UCA1CTLW0 |= UCSWRST; 
6
}

habe ich mir vorgestellt, dass man vielleicht ein Makro schreiben kann, 
dass einen Parameter annimmt, so das folgendes möglich wird:
1
void eUSCI_Ax_softreset(uint8_t eusci_nr) {
2
  UCAxCTLW0(eusci_nr) |= UCSWRST;
3
}

Ich habe aber nicht rausgefunden, ob und wie das möglich ist. Folgendes 
funktioniert leider nicht:
1
#define UCAxCTLW0(x) UCA#xCTLW0

Irgendwelche Tips?

Danke und Gruss, Edi

von Clemens L. (c_l)


Lesenswert?

1
#define UCAxCTLW0(x) UCA##x##CTLW0
Und das funktioniert nur mit einer Konstanten; ein Symbol 
UCAeusci_nrCTLW0 gibt es nicht.

Aber die Register jedes Modules liegen am gleichen Offset zur 
Basisadresse.
Im Header findest du folgende Definitionen:
1
#define __MSP430_BASEADDRESS_USCI_A0__ 0x05C0
2
...
3
#define UCA0CTLW0_            0x05C0    /* USCI A0 Control Word Register 0 */
4
...
5
#define __MSP430_BASEADDRESS_USCI_A1__ 0x0600
6
...
7
#define UCA1CTLW0_            0x0600    /* USCI A1 Control Word Register 0 */

Also prober folgendes:
1
#define UCAxCTLW0_OFFSET (UCA0CTLW0_ - __MSP430_BASEADDRESS_USCI_A0__)
2
3
static const uint16_t eusci_baseaddr[2] = {
4
  __MSP430_BASEADDRESS_USCI_A0__,
5
  __MSP430_BASEADDRESS_USCI_A1__,
6
};
7
8
static inline uint16_t readw(uint16_t addr) {
9
  return *(volatile uint16_t *)addr;
10
}
11
static inline void writew(uint16_t addr, uint16_t value) {
12
  *(volatile uint16_t *)addr = value;
13
}
14
15
void eUSCI_Ax_softreset(uint8_t eusci_nr) {
16
  uint16_t addr = eusci_baseaddr[eusci_nr] + UCAxCTLW0_OFFSET;
17
  writew(addr, readw(addr) | UCSWRST);
18
}

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Falls beide Communication Interfaces gleiches Layout im Speicher haben, 
ist ein Ansatz sich eine Struct zu definieren, und über diese 
zuzugreifen:
1
#include <stdint.h>
2
3
typedef struct
4
{
5
    uint16_t foo1;
6
    uint16_t bar2;
7
    uint16_t ctlw0;
8
    uint16_t ctlw1;
9
    // ...
10
} usci_t;
11
12
#define eUSCI_A0_addr 0xbeef
13
#define eUSCI_A1_addr 0xbabe
14
15
#define USCI_A0 ((volatile usci_t*) eUSCI_A0_addr)
16
#define USCI_A1 ((volatile usci_t*) eUSCI_A1_addr)
17
18
#define UCSWRST 0x0001
19
20
void eUSCI_A_softreset (volatile usci_t* usci)
21
{
22
    usci->ctlw0 |= UCSWRST;
23
}
24
25
int main (void)
26
{
27
    eUSCI_A_softreset (USCI_A0);
28
    eUSCI_A_softreset (USCI_A1);
29
}

Bei dieser Lösung muss man überall volatile mit angeben.  Alternativ 
kann man das volatile ins typedef mit aufnehmen, was aber lästig sein 
kann wenn man eine non-volatile Version von ucsi_t braucht.

Und je nach Anwendung kann es besser sein, die Funktionen "static 
inline" zu machen.

von Max G. (l0wside) Benutzerseite


Lesenswert?

Ausschnitt aus meiner tools.h:
1
/* Set/clear a bit on a port */
2
#define POUT_SET_(PORT,BIT,VAL) { if (VAL == 0) { P ## PORT ## OUT &= (~(1 << BIT)); } else { P ## PORT ## OUT |= (1 << BIT); } }
3
#define POUT_SET(PORT,BIT,VAL) POUT_SET_(PORT,BIT,VAL)

Funktioniert hervorragend und sollte auch (nach Anpassung) dein Problem 
lösen.

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.