mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik STM32 DMA Lookuptable etc.


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Reginald L. (Firma: HS Ulm) (reggie)


Bewertung
0 lesenswert
nicht 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:
    UART(uint8_t uart_id, uint32_t uart_baudrate, StopBitType stop_bits, ParityType parity,
      IO::PortType tx_port, uint8_t tx_pin, IO::PortType rx_port, uint8_t rx_pin);
    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)


Bewertung
0 lesenswert
nicht 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: HS Ulm) (reggie)


Bewertung
0 lesenswert
nicht 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: HS Ulm) (reggie)


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

von Thomas S. (doschi_)


Bewertung
0 lesenswert
nicht 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: HS Ulm) (reggie)


Bewertung
0 lesenswert
nicht 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 :>
// Übergabe einer Peripherie und der ID (z.B. UART1, UART3, SPI2, ...)
void UART::InitRx(uint8_t * rx_buffer, bool rx_dma_mode)
{
  if (rx_dma_mode)
  {
    DMA dma = DMA(DMA::UART_RX, ID, (uint32_t)&UART_PERI->DR, (uint32_t)&RxBuffer);
  }


}

// Konstrukt des Teufels
  class DMA
  {
  public:
    enum PeripheralID : uint8_t
    {
      UART_RX = 0,
      UART_TX = 1
    };
  private:
    class PeripheralItem
    {
    public:
      uint8_t DMANo;
      uint8_t StreamNo;
      uint8_t ChannelNo;
    };
    class Peripheral
    {
    public:
      uint8_t Amount;
      PeripheralItem Item;
      Peripheral* Next;
    };

    class PItemDef
    {
    public:
      Peripheral USART_RX_1_0 = Peripheral{ 2, 2, 2, 4, &USART_RX_1_1 };
      Peripheral USART_RX_1_1 = Peripheral{ 2, 2, 5, 4, &USART_RX_1_0 };
      Peripheral USART_RX_2 = Peripheral{ 1, 1, 5, 4 };
      Peripheral USART_RX_3 = Peripheral{ 1, 1, 1, 4 };
      Peripheral UART_RX_4 = Peripheral{ 1, 1, 2, 4 };
      Peripheral UART_RX_5 = Peripheral{ 1, 1, 0, 4 };
      Peripheral USART_RX_6_0 = Peripheral{ 2, 2, 1, 5, &USART_RX_6_1 };
      Peripheral USART_RX_6_1 = Peripheral{ 2, 2, 2, 5, &USART_RX_6_0 };
      Peripheral UART_RX_7 = Peripheral{ 1, 1, 3, 5 };
      Peripheral UART_RX_8 = Peripheral{ 1, 1, 6, 5 };

      Peripheral USART_TX_1 = Peripheral{ 1, 2, 7, 4 };
      Peripheral USART_TX_2 = Peripheral{ 1, 1, 6, 4 };
      Peripheral USART_TX_3_0 = Peripheral{ 2, 1, 3, 4, &USART_TX_3_1 };
      Peripheral USART_TX_3_1 = Peripheral{ 2, 1, 4, 7, &USART_TX_3_0 };
      Peripheral UART_TX_4 = Peripheral{ 1, 1, 4, 4 };
      Peripheral UART_TX_5 = Peripheral{ 1, 1, 7, 4 };
      Peripheral USART_TX_6_0 = Peripheral{ 2, 2, 6, 5, &USART_TX_6_1 };
      Peripheral USART_TX_6_1 = Peripheral{ 2, 2, 7, 5, &USART_TX_6_0 };
      Peripheral UART_TX_7 = Peripheral{ 1, 1, 1, 5 };
      Peripheral UART_TX_8 = Peripheral{ 1, 1, 0, 5 };
    };

    class PMatrixType
    {
    private:
      PItemDef pitem;
    public:
      Peripheral* Item[2][8] =
      {
        {
          &pitem.USART_RX_1_0,
          &pitem.USART_RX_2,
          &pitem.USART_RX_3,
          &pitem.UART_RX_4,
          &pitem.UART_RX_5,
          &pitem.USART_RX_6_0,
          &pitem.UART_RX_7,
          &pitem.UART_RX_8
        },{
          &pitem.USART_TX_1,
          &pitem.USART_TX_2,
          &pitem.USART_TX_3_0,
          &pitem.UART_TX_4,
          &pitem.UART_TX_5,
          &pitem.USART_TX_6_0,
          &pitem.UART_TX_7,
          &pitem.UART_TX_8
        }
      };
    };
};

// nun kann man schon was damit anfangen
DMA::DMA(PeripheralID id, uint8_t peripheral_no_id, uint32_t transfer_source_address, uint32_t transfer_destination_address)
{
  PID = id;
  PNID = peripheral_no_id;
  SourceAddress = transfer_source_address;
  DestinationAddress = transfer_destination_address;

  Peripheral* a = PMatrix.Item[id][peripheral_no_id];

  int x = 1;

}

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: HS Ulm) (reggie)


Bewertung
0 lesenswert
nicht lesenswert
Ich habs jetzt noch etwas angepasst, Funktion ist gegeben, aber gefallen 
tuts mir nicht:

  class DMA
  {
  public:
    enum PeripheralType : uint8_t
    {
      UART_RX = 0,
      UART_TX = 1
    };
  private:
    enum ChannelType : uint8_t
    {
      Channel0 = 0x00,
      Channel1 = 0x01,
      Channel2 = 0x02,
      Channel3 = 0x03,
      Channel4 = 0x04,
      Channel5 = 0x05,
      Channel6 = 0x06,
      Channel7 = 0x07
    };
    class Peripheral
    {
      class PeripheralInfo
      {
      public:
        uint8_t DMANo;
        RegisterTypeDef::DMA* DMA_REG;
        ChannelType Channel;
      };
    public:
      PeripheralInfo Item;
      Peripheral* Next;
    };
    class StreamChannelType
    {
    private:
      class PeripheralDef
      {
      public:
        Peripheral USART_RX_1_0 = Peripheral{ 2, Register::DMA2[2], Channel4, &USART_RX_1_1 };
        Peripheral USART_RX_1_1 = Peripheral{ 2, Register::DMA2[5], Channel4, &USART_RX_1_0 };
        Peripheral USART_RX_2 = Peripheral{ 1, Register::DMA1[5], Channel4, nullptr };
        Peripheral USART_RX_3 = Peripheral{ 1, Register::DMA1[1], Channel4, nullptr };
        Peripheral UART_RX_4 = Peripheral{ 1, Register::DMA1[2], Channel4, nullptr };
        Peripheral UART_RX_5 = Peripheral{ 1, Register::DMA1[0], Channel4, nullptr };
        Peripheral USART_RX_6_0 = Peripheral{ 2, Register::DMA2[1], Channel5, &USART_RX_6_1 };
        Peripheral USART_RX_6_1 = Peripheral{ 2, Register::DMA2[2], Channel5, &USART_RX_6_0 };
        Peripheral UART_RX_7 = Peripheral{ 1, Register::DMA1[3], Channel5, nullptr };
        Peripheral UART_RX_8 = Peripheral{ 1, Register::DMA1[6], Channel5, nullptr };

        Peripheral USART_TX_1 = Peripheral{ 2, Register::DMA1[7], Channel4, nullptr };
        Peripheral USART_TX_2 = Peripheral{ 1, Register::DMA1[6], Channel4, nullptr };
        Peripheral USART_TX_3_0 = Peripheral{ 1, Register::DMA2[3], Channel4, &USART_TX_3_1 };
        Peripheral USART_TX_3_1 = Peripheral{ 1, Register::DMA2[4], Channel7, &USART_TX_3_0 };
        Peripheral UART_TX_4 = Peripheral{ 1, Register::DMA1[4], Channel4, nullptr };
        Peripheral UART_TX_5 = Peripheral{ 1, Register::DMA1[7], Channel4, nullptr };
        Peripheral USART_TX_6_0 = Peripheral{ 2, Register::DMA2[6], Channel5, &USART_TX_6_1 };
        Peripheral USART_TX_6_1 = Peripheral{ 2, Register::DMA2[7], Channel5, &USART_TX_6_0 };
        Peripheral UART_TX_7 = Peripheral{ 1, Register::DMA1[1], Channel5, nullptr };
        Peripheral UART_TX_8 = Peripheral{ 1, Register::DMA2[0], Channel5, nullptr };
      };
      PeripheralDef def;
    public:
      Peripheral* Item[2][8] =
      {
        {
          &def.USART_RX_1_0,
          &def.USART_RX_2,
          &def.USART_RX_3,
          &def.UART_RX_4,
          &def.UART_RX_5,
          &def.USART_RX_6_0,
          &def.UART_RX_7,
          &def.UART_RX_8
        },{
          &def.USART_TX_1,
          &def.USART_TX_2,
          &def.USART_TX_3_0,
          &def.UART_TX_4,
          &def.UART_TX_5,
          &def.USART_TX_6_0,
          &def.UART_TX_7,
          &def.UART_TX_8
        }
      };
    };

  public:
    DMA(PeripheralType id, uint8_t peripheral_no_id, uint32_t transfer_source_address, uint32_t transfer_destination_address);
  private:
    PeripheralType PID;
    uint8_t PNID;
    RegisterTypeDef::DMA* DMA_REG;
    Peripheral* Periph;
    uint32_t SourceAddress;
    uint32_t DestinationAddress;
  private:
    static const StreamChannelType StreamChannel;
    static bool isAssignedDMA1[8][8];
    static bool isAssignedDMA2[8][8];
  };

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

von Torsten C. (torsten_c) Benutzerseite


Bewertung
0 lesenswert
nicht 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: HS Ulm) (reggie)


Bewertung
0 lesenswert
nicht 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: HS Ulm) (reggie)


Bewertung
0 lesenswert
nicht 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


Bewertung
0 lesenswert
nicht 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: HS Ulm) (reggie)


Bewertung
0 lesenswert
nicht 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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.