STM32 DMA Lookuptable etc.

OP (Firma: HEGRO GmbH) #4712344
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
Gast #4712367
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...
OP (Firma: HEGRO GmbH) #4712375
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.
OP (Firma: HEGRO GmbH) #4712484
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.
OP (Firma: HEGRO GmbH) #4712544
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 :>
OP (Firma: HEGRO GmbH) #4713760
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 :)

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