An meinem STM32F417IG Mikrocontroller habe ich einen externen 16bit-DAC (TI DAC81404) angeschlossen, der mit einer Rate von 32kHz ein Signal generieren soll. Die Kommunikation soll über SPI und unabhängig von der CPU erfolgen. Daher möchte ich DMA verwenden, welches über einen Timer getriggert werden soll und die Daten mit der Rate von 32kHz ins SPI Data Register schreibt, sodass die Daten zum DAC gesendet werden. Infos zum DAC Der DAC aktualisiert seine Ausgangsspannung immer wenn ein neuer Wert über SPI empfangen wurde. Das wird erreicht, indem: 1. der CS/NSS/SYNC – Pin auf low gezogen wird 2. eine 24bit/3 byte große Nachricht gesendet wird und 3. CS anschließend wieder auf high gezogen wird. In den ersten 8bit (von 24bit) befindet sich u.a. die Information an welchem Channel die Ausgangsspannung anliegen soll. Die restlichen 16bit enthalten den digitalen Wert der Ausgangsspannung. Infos zum STM32 Leider haben die Mikrocontroller von ST ein Hardwareproblem mit dem NSS. Der Pin wird richtigerweise zu Beginn einer SPI-Kommunikation auf low gezogen. Anschließend bleibt er jedoch low bis SPI letztendlich komplett deaktiviert wird. (Reference Manual Seite 877). Das ist aber nicht Sinn der Sache. Der Pin soll nach jeder Nachricht wieder auf high gezogen werden. Eine „Lösung“ wäre die Verwendung eines GPIOs als Output für den NSS, der manuell geschaltet wird. Das steht auch genauso im Datenblatt: When a master is communicating with SPI slaves which need to be de-selected between transmissions, the NSS pin must be configured as GPIO or another GPIO must be used and toggled by software. Problem Das hat zur Folge, dass ich den Prozess nicht einfach zu Beginn starten kann und anschließend keine CPU-Ressourcen mehr benötigt werden. Stattdessen muss ich eine Lösung finden, DMA über einen Timer getriggert zu nutzen und zwischendurch Interrupts zu verwenden, um den NSS zu schalten. Meine Frage ist nun, ob ich eine Möglichkeit übersehen habe, um doch irgendwie mit DMA ohne zyklischen Aufruf einer CPU-lastigen Funktion auszukommen oder ob es eine andere Methode gibt, den NSS-Pin ressourcenarm zu steuern. Bei letzterem habe ich auch Schwierigkeiten bei der Umsetzung, da die BUSY Flag natürlich erst am Ende der SPI-Übertragung, also am Ende des ganzen Datenblock auf low gesetzt wird und nicht nach jeder 24bit Nachricht.
Ist ja toll, was alles nicht möglich ist :( Ist denn schon klar, welche Pins benutzt werden? Und wie die 32kHz Abtastfrequenz erzeugt wird? Irgendwie muss es eigentlich machbar sein, mal sehen. Ein Timer könnte per Output Compare den CS erzeugen. Das ist ein 32kHz-Rechteck, das Tastverhältnis ergibt sich ungefähr aus dem Verhältnis Timer-Takt zu SPI-Takt. Der gleiche Timer triggert mit drei anderen Output Compare nacheinander drei DMA-Kanäle. Jeder Kanal ist für eins der 3 Byte zuständig. Formal arbeitet ein DMA-Kanal im memory to memory mode, obwohl das Ziel das SPIDR ist. Das SPI-Modul wird so konfiguriert, als ob man alles per Software machen wollte. NSS wird nicht benutzt, dafür haben wir ja einen Compare-Ausgang. Wenn das PINCOS-Bit im DMA_SxCR eine echte Addition bewirken würde, könnte jeder DMA-Kanal 1 Byte lesen und schreiben, aber die RAM-Adresse um 4 hochzählen. Dann würden die 24 DAC-Bits in ein Wort passen. Wenn das nicht funktioniert, müssen die Daten im RAM Byteweise abgelegt werden. Im ersten Block für den ersten DMA-Kanal alle Adress/Control-Bytes, im zweiten alle ersten Daten-Bytes... Kein Nachteil ohne Vorteil: so braucht man nur 3/4 so viel RAM.
Ich hab das mit einem DMA Interrupt gelöst. Wenn alles gesendet ist, tritt der DMA interrupt auf und setzt dann das CS wieder high. Kostet seeehr wenig.
Der DMA Interrupt (z.B. TCIF- Transfer Complete) löst leider erst aus, wenn alle Daten aus dem Datenbuffer gesendet wurden. Ich brauche einen Interrupt sobald 24bit gesendet wurden. Ich werde mal diesen Ansatz verfolgen: https://community.st.com/s/question/0D53W00001NVgChSAL/interface-with-external-adc-via-spi-at-1mss
@Bauform B. Ich habe schon einige Pins belegt, aber bin noch flexibel. Die 32kHz würde ich mit einem Timer erzeugen. Deine Idee mit der Aufteilung der 3 Bytes auf verschiedene Channels klingt gut. Das CS könnte ich mit einem weiteren Channel oder einen verknüpften Timer PWM togglen. Mal sehen :) Vielen Dank für eure Antworten!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.