Forum: Mikrocontroller und Digitale Elektronik STM32 DMA Lookuptable etc.


von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Huhu!

C++:
Ich bin ja gerade dabei eine kleine Lib für meinen STM aufzubauen und 
bin beim DMA angelangt. Mein Ziel ist es immer, mit möglichst wenig 
Handgriffen, aber vielen nicht zwingenden Funktionsaufrufen, die 
Peripherie zum laufen zu bekommen. Auch die (globalen) #defines von ST 
haben mich gestört, weshalb sie in eine Klasse wanderten.
So kann ich beispielsweise das Ethernet über eine Handvoll Funktionen 
zum laufen bekommen oder die IOs mit einer Funktion im AF-Modus 
initialisieren. Wo immer es geht, arbeite ich mit Lookuptables, eine 
if-else Abfrage ist das höchste der Gefühle. 1MB ROM ist mehr als genug 
für meine Zwecke.

Allerdings hänge ich am DMA. So starte ich beispielsweise mit Uart:
1
    UART(uint8_t uart_id, uint32_t uart_baudrate, StopBitType stop_bits, ParityType parity,
2
      IO::PortType tx_port, uint8_t tx_pin, IO::PortType rx_port, uint8_t rx_pin);
3
    void InitRx(uint8_t* rx_buffer, bool rx_dma_mode);

Mein Problem bezieht sich auf die Auswahl des Streams und Channels für 
die jeweilige Peripherie. So kann ich beispielsweise die 
Register-Adresse des jeweiligen Uarts an die DMA-Klasse übergeben. Ich 
habe schon einiges probiert aber irgendwie läuft es immer auf 
irgendwelche Schleifen / switch-cases hinaus um den richtigen 
Stream/Channel zu bekommen.

Habt ihr einen Denkanstoß für mich?

Danke schonmal!

Grüße
Reggie

von aSma>> (Gast)


Lesenswert?

Servus,
guck dir mal an wie das Uwe Becker macht:
http://mikrocontroller.bplaced.net/wordpress/?page_id=744

Ich finde das ist genial gelöst.

> Ich
> habe schon einiges probiert aber irgendwie läuft es immer auf
> irgendwelche Schleifen / switch-cases hinaus um den richtigen
> Stream/Channel zu bekommen.

Eine Schleife ist mitunter das Beste, was man machen kann 
(Codeoptimierung). Ein switch case erhöht dafür die Übersichtlichkeit...

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

aSma>> schrieb:
> Ich finde das ist genial gelöst.
Welche Lib meinst du denn da konkret?

aSma>> schrieb:
> Eine Schleife ist mitunter das Beste, was man machen kann
> (Codeoptimierung). Ein switch case erhöht dafür die Übersichtlichkeit...
Was meinst du mit Codeoptimierung? Für den Speed eignet sich doch wohl 
ein Pointer auf die richtige Stelle allemal besser als ein 100er-Array 
durchzusuchen.

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Also die UART_DMA Lib bringt mich da nicht weiter, das ist ja über 
defines geregelt.

von Thomas S. (doschi_)


Lesenswert?

aSma>> schrieb:
> guck dir mal an wie das Uwe Becker macht:
> http://mikrocontroller.bplaced.net/wordpress/?page_id=744

Offtopic:
hat jemand Information bezügl. Uwe Becker?
Die Seite http://mikrocontroller.bplaced.net/wordpress/ ist seit April 
nicht mehr aktualisiert worden. Dort habe ich keine Informationen 
gefunden.

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Ich habe mir jetzt ein ziemlich unschönes Konstrukt gebaut, damit komme 
ich zwar weiter, aber vllt hat ja jemand noch ne Idee. Vllt wirds auch 
deutlicher was ich eigentlich bezwecken möchte :>
1
// Übergabe einer Peripherie und der ID (z.B. UART1, UART3, SPI2, ...)
2
void UART::InitRx(uint8_t * rx_buffer, bool rx_dma_mode)
3
{
4
  if (rx_dma_mode)
5
  {
6
    DMA dma = DMA(DMA::UART_RX, ID, (uint32_t)&UART_PERI->DR, (uint32_t)&RxBuffer);
7
  }
8
9
10
}
11
12
// Konstrukt des Teufels
13
  class DMA
14
  {
15
  public:
16
    enum PeripheralID : uint8_t
17
    {
18
      UART_RX = 0,
19
      UART_TX = 1
20
    };
21
  private:
22
    class PeripheralItem
23
    {
24
    public:
25
      uint8_t DMANo;
26
      uint8_t StreamNo;
27
      uint8_t ChannelNo;
28
    };
29
    class Peripheral
30
    {
31
    public:
32
      uint8_t Amount;
33
      PeripheralItem Item;
34
      Peripheral* Next;
35
    };
36
37
    class PItemDef
38
    {
39
    public:
40
      Peripheral USART_RX_1_0 = Peripheral{ 2, 2, 2, 4, &USART_RX_1_1 };
41
      Peripheral USART_RX_1_1 = Peripheral{ 2, 2, 5, 4, &USART_RX_1_0 };
42
      Peripheral USART_RX_2 = Peripheral{ 1, 1, 5, 4 };
43
      Peripheral USART_RX_3 = Peripheral{ 1, 1, 1, 4 };
44
      Peripheral UART_RX_4 = Peripheral{ 1, 1, 2, 4 };
45
      Peripheral UART_RX_5 = Peripheral{ 1, 1, 0, 4 };
46
      Peripheral USART_RX_6_0 = Peripheral{ 2, 2, 1, 5, &USART_RX_6_1 };
47
      Peripheral USART_RX_6_1 = Peripheral{ 2, 2, 2, 5, &USART_RX_6_0 };
48
      Peripheral UART_RX_7 = Peripheral{ 1, 1, 3, 5 };
49
      Peripheral UART_RX_8 = Peripheral{ 1, 1, 6, 5 };
50
51
      Peripheral USART_TX_1 = Peripheral{ 1, 2, 7, 4 };
52
      Peripheral USART_TX_2 = Peripheral{ 1, 1, 6, 4 };
53
      Peripheral USART_TX_3_0 = Peripheral{ 2, 1, 3, 4, &USART_TX_3_1 };
54
      Peripheral USART_TX_3_1 = Peripheral{ 2, 1, 4, 7, &USART_TX_3_0 };
55
      Peripheral UART_TX_4 = Peripheral{ 1, 1, 4, 4 };
56
      Peripheral UART_TX_5 = Peripheral{ 1, 1, 7, 4 };
57
      Peripheral USART_TX_6_0 = Peripheral{ 2, 2, 6, 5, &USART_TX_6_1 };
58
      Peripheral USART_TX_6_1 = Peripheral{ 2, 2, 7, 5, &USART_TX_6_0 };
59
      Peripheral UART_TX_7 = Peripheral{ 1, 1, 1, 5 };
60
      Peripheral UART_TX_8 = Peripheral{ 1, 1, 0, 5 };
61
    };
62
63
    class PMatrixType
64
    {
65
    private:
66
      PItemDef pitem;
67
    public:
68
      Peripheral* Item[2][8] =
69
      {
70
        {
71
          &pitem.USART_RX_1_0,
72
          &pitem.USART_RX_2,
73
          &pitem.USART_RX_3,
74
          &pitem.UART_RX_4,
75
          &pitem.UART_RX_5,
76
          &pitem.USART_RX_6_0,
77
          &pitem.UART_RX_7,
78
          &pitem.UART_RX_8
79
        },{
80
          &pitem.USART_TX_1,
81
          &pitem.USART_TX_2,
82
          &pitem.USART_TX_3_0,
83
          &pitem.UART_TX_4,
84
          &pitem.UART_TX_5,
85
          &pitem.USART_TX_6_0,
86
          &pitem.UART_TX_7,
87
          &pitem.UART_TX_8
88
        }
89
      };
90
    };
91
};
92
93
// nun kann man schon was damit anfangen
94
DMA::DMA(PeripheralID id, uint8_t peripheral_no_id, uint32_t transfer_source_address, uint32_t transfer_destination_address)
95
{
96
  PID = id;
97
  PNID = peripheral_no_id;
98
  SourceAddress = transfer_source_address;
99
  DestinationAddress = transfer_destination_address;
100
101
  Peripheral* a = PMatrix.Item[id][peripheral_no_id];
102
103
  int x = 1;
104
105
}

EDIT:
Was natürlich noch phänomenaler wäre, wenn ich anstatt der "UART_RX" bzw 
"UART_TX" einfach die Peripherie-Registeradresse mitgeben könnte.

: Bearbeitet durch User
von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Ich habs jetzt noch etwas angepasst, Funktion ist gegeben, aber gefallen 
tuts mir nicht:
1
  class DMA
2
  {
3
  public:
4
    enum PeripheralType : uint8_t
5
    {
6
      UART_RX = 0,
7
      UART_TX = 1
8
    };
9
  private:
10
    enum ChannelType : uint8_t
11
    {
12
      Channel0 = 0x00,
13
      Channel1 = 0x01,
14
      Channel2 = 0x02,
15
      Channel3 = 0x03,
16
      Channel4 = 0x04,
17
      Channel5 = 0x05,
18
      Channel6 = 0x06,
19
      Channel7 = 0x07
20
    };
21
    class Peripheral
22
    {
23
      class PeripheralInfo
24
      {
25
      public:
26
        uint8_t DMANo;
27
        RegisterTypeDef::DMA* DMA_REG;
28
        ChannelType Channel;
29
      };
30
    public:
31
      PeripheralInfo Item;
32
      Peripheral* Next;
33
    };
34
    class StreamChannelType
35
    {
36
    private:
37
      class PeripheralDef
38
      {
39
      public:
40
        Peripheral USART_RX_1_0 = Peripheral{ 2, Register::DMA2[2], Channel4, &USART_RX_1_1 };
41
        Peripheral USART_RX_1_1 = Peripheral{ 2, Register::DMA2[5], Channel4, &USART_RX_1_0 };
42
        Peripheral USART_RX_2 = Peripheral{ 1, Register::DMA1[5], Channel4, nullptr };
43
        Peripheral USART_RX_3 = Peripheral{ 1, Register::DMA1[1], Channel4, nullptr };
44
        Peripheral UART_RX_4 = Peripheral{ 1, Register::DMA1[2], Channel4, nullptr };
45
        Peripheral UART_RX_5 = Peripheral{ 1, Register::DMA1[0], Channel4, nullptr };
46
        Peripheral USART_RX_6_0 = Peripheral{ 2, Register::DMA2[1], Channel5, &USART_RX_6_1 };
47
        Peripheral USART_RX_6_1 = Peripheral{ 2, Register::DMA2[2], Channel5, &USART_RX_6_0 };
48
        Peripheral UART_RX_7 = Peripheral{ 1, Register::DMA1[3], Channel5, nullptr };
49
        Peripheral UART_RX_8 = Peripheral{ 1, Register::DMA1[6], Channel5, nullptr };
50
51
        Peripheral USART_TX_1 = Peripheral{ 2, Register::DMA1[7], Channel4, nullptr };
52
        Peripheral USART_TX_2 = Peripheral{ 1, Register::DMA1[6], Channel4, nullptr };
53
        Peripheral USART_TX_3_0 = Peripheral{ 1, Register::DMA2[3], Channel4, &USART_TX_3_1 };
54
        Peripheral USART_TX_3_1 = Peripheral{ 1, Register::DMA2[4], Channel7, &USART_TX_3_0 };
55
        Peripheral UART_TX_4 = Peripheral{ 1, Register::DMA1[4], Channel4, nullptr };
56
        Peripheral UART_TX_5 = Peripheral{ 1, Register::DMA1[7], Channel4, nullptr };
57
        Peripheral USART_TX_6_0 = Peripheral{ 2, Register::DMA2[6], Channel5, &USART_TX_6_1 };
58
        Peripheral USART_TX_6_1 = Peripheral{ 2, Register::DMA2[7], Channel5, &USART_TX_6_0 };
59
        Peripheral UART_TX_7 = Peripheral{ 1, Register::DMA1[1], Channel5, nullptr };
60
        Peripheral UART_TX_8 = Peripheral{ 1, Register::DMA2[0], Channel5, nullptr };
61
      };
62
      PeripheralDef def;
63
    public:
64
      Peripheral* Item[2][8] =
65
      {
66
        {
67
          &def.USART_RX_1_0,
68
          &def.USART_RX_2,
69
          &def.USART_RX_3,
70
          &def.UART_RX_4,
71
          &def.UART_RX_5,
72
          &def.USART_RX_6_0,
73
          &def.UART_RX_7,
74
          &def.UART_RX_8
75
        },{
76
          &def.USART_TX_1,
77
          &def.USART_TX_2,
78
          &def.USART_TX_3_0,
79
          &def.UART_TX_4,
80
          &def.UART_TX_5,
81
          &def.USART_TX_6_0,
82
          &def.UART_TX_7,
83
          &def.UART_TX_8
84
        }
85
      };
86
    };
87
88
  public:
89
    DMA(PeripheralType id, uint8_t peripheral_no_id, uint32_t transfer_source_address, uint32_t transfer_destination_address);
90
  private:
91
    PeripheralType PID;
92
    uint8_t PNID;
93
    RegisterTypeDef::DMA* DMA_REG;
94
    Peripheral* Periph;
95
    uint32_t SourceAddress;
96
    uint32_t DestinationAddress;
97
  private:
98
    static const StreamChannelType StreamChannel;
99
    static bool isAssignedDMA1[8][8];
100
    static bool isAssignedDMA2[8][8];
101
  };

Wie gesagt, wenn jmd noch n Tipp hat, immer her damit :>

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Zumindest ich habe Dein Problem noch nicht verstanden.
Was genau stört Dich?

Etwas 'knackiger' wird es vielleicht mit Templates, aber das ist eher 
eine Geschmacksfrage.

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Ob man das nicht geschickter lösen könnte. Am besten wäre die Übergabe 
der Peripherie-Adresse (zb. UART1, UART3, SPI2). Ich komme aber nicht 
drauf, wie ich ohne Schleife den korrekten Offset aus der Lookuptable 
bekommen könnte.

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Torsten C. schrieb:
> Etwas 'knackiger' wird es vielleicht mit Templates, aber das ist eher
> eine Geschmacksfrage.
Damit habe ich noch nie geschafft. Aber ich denke, mein Problem bleibt 
trotzdem das Abarbeiten einer Loop, wenn ich die Peripherie-Adresse 
mitgeben möchte.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Zumindest ich habe Dein Problem noch immer nicht verstanden.
Ich sehe in diesem Thread weder eine Loop noch ein switch-case.

Falls nur ich dieses Problem habe, bitte ich um Entschuldigung.
Dann hatte ich wohl Tomaten auf den Augen.

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Torsten C. schrieb:
> Falls nur ich dieses Problem habe, bitte ich um Entschuldigung.
> Dann hatte ich wohl Tomaten auf den Augen.
Hehe, macht ja nix.

Reginald L. schrieb:
> Am besten wäre die Übergabe
> der Peripherie-Adresse (zb. UART1, UART3, SPI2).
Bisher übergebe ich ja eine Konstante aus dem Enumerator. Das Loopen 
entsteht, falls ich die Peripherie-Adresse übergeben werde. Und Loops 
mag meine Rolex nicht :>

Und hübsch finde ich meine Lösung auch nicht. Hätte ja sein können, dass 
man mir auch hier, wie bei meinen anderen Problemchen auch, andere, 
schönere Möglichkeiten aufzeigt. Falls nicht, dann halt nicht :)

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.