(msp430)gcc Preprocessor Macro Frage

OP #7358664
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

#7358906
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
}
Persönliche Seite #7359012
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.

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