Hier eine Library um die SPI-Schnittstelle im Master-Mode und per DMA-Betrieb nutzen zu könnnen.
ich habe wieder 3 identische Libs für SPI1, SPI2, SPI3 erstellt.
die SPI-Pins die benutzt werden sollen, müssen im C-File eingetragen werden
(im H-File kann der Clock-Vorteiler gewählt werden)
Das setzen der ChipSelect-Leitung muss von der Übergeordneten Funktion gemacht werden (event. muss das disable Signal in die ISR gepackt werden)
Beim initialisieren kann der Mode (Mode-0 bis Mode-3) und LSB oder MSB gewählt werden. Die Schnittstelle darf nur einmal initialisiert werden.
Zum senden und empfangen gibt es je ein Byte-Array dessen max. Größe im H-File eingestellt werden kann.
Vor dem senden müssen die Daten in das TX-Array kopiert werden. Beim senden muss die Anzahl der Daten zum senden mit übergeben werden. (1 bis Arraysize)
Das eigentliche senden/empfangen passiert dann per DMA und über eine Funktion kann geprüft werden ob das senden/empfangen fertig ist. Falls es fertig ist, wird die Anzahl der empfangenen Bytes zurückgegeben und die eigentlichen Daten stehen dann im RX-Array.
Falls die Senderoutine aufgerufen wird, aber das letzte senden noch gar nicht fertig ist, wird solange gewartet und erst im Anschluss daran gesendet.
im Beispiel wurde SPI2 benutzt mit dieser Pinbelegung :
1 2 3 | SCK an PB13 MOSI an PB15 MISO an PB14 |
Voraussetzungen :
1 2 | Benutzte Module der CooCox-IDE : GPIO, SPI, DMA, MISC Benutzte Librarys : keine |
Enumerationen (für SPI1) :
1 2 3 4 5 6 7 8 9 10 | typedef enum { SPI_MODE_0_MSB = 0, // CPOL=0, CPHA=0 (MSB-First) SPI_MODE_1_MSB, // CPOL=0, CPHA=1 (MSB-First) SPI_MODE_2_MSB, // CPOL=1, CPHA=0 (MSB-First) SPI_MODE_3_MSB, // CPOL=1, CPHA=1 (MSB-First) SPI_MODE_0_LSB, // CPOL=0, CPHA=0 (LSB-First) SPI_MODE_1_LSB, // CPOL=0, CPHA=1 (LSB-First) SPI_MODE_2_LSB, // CPOL=1, CPHA=0 (LSB-First) SPI_MODE_3_LSB // CPOL=1, CPHA=1 (LSB-First) }SPI1_Mode_t; |
Funktionen (für SPI1) :
1 2 3 | ErrorStatus UB_SPI1_DMA_Init(SPI1_Mode_t mode); ErrorStatus UB_SPI1_DMA_SendBuffer(uint32_t cnt); uint32_t UB_SPI1_DMA_GetReceivedBytes(void); |
Beispiel :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | //-------------------------------------------------------------- // File : main.c // Datum : 30.12.2014 // Version : 1.0 // Autor : UB // EMail : mc-4u(@)t-online.de // Web : www.mikrocontroller-4u.de // CPU : STM32F4 // IDE : CooCox CoIDE 1.7.4 // GCC : 4.7 2012q4 // Module : CMSIS_BOOT, M4_CMSIS_CORE // Funktion : Demo der SPI_DMA Library // Hinweis : Diese zwei Files muessen auf 8MHz stehen // "cmsis_boot/stm32f4xx.h" // "cmsis_boot/system_stm32f4xx.c" //-------------------------------------------------------------- #include "main.h" #include "stm32_ub_spi2_dma.h" int main(void) { SystemInit(); // Quarz Einstellungen aktivieren // SPI2 im Mode0 initialisieren UB_SPI2_DMA_Init(SPI_MODE_0_MSB); // TX-Puffer mit 3 Bytes Daten fuellen SPI2_DMA.tx_buffer[0]=0x55; SPI2_DMA.tx_buffer[1]=0xAA; SPI2_DMA.tx_buffer[2]=0x01; // 3Bytes per DMA senden UB_SPI2_DMA_SendBuffer(3); while(1) { if(UB_SPI2_DMA_GetReceivedBytes()>0) { // wenn senden fertig // hier die 3 Bytes vom RX-Buffer auswerten } } } |
Hier die Library zum Download :
Hier der komplette CooCox-Projektordner zum Download :
Hey Uwe!
Wollte gerade mein EADOG-Display 1701 auf SPI-DMA umstellen, da ich für ein Programm eine Refreshzeit von 500ms des kompletten Displays brauche!
Leider bin ich auf das Problem gestossen, dass die Funktion in der EADOG-Lib -> P_EADOG_SetCursor(…) den COMMAND/DATA-Pin umschaltet.
Meine einziger “Lösungsansatz” ist, der aber nicht viel bringen wird, jeweils commands und data getrennt an den DMA zu übergeben….
Hast du eine Idee, ob man das noch irgendwie anders machen kann. Eventuell hat der Display einen internen “Burst-mode” bei dem man keine Koordinaten angeben muss, sondern intern einfach pro empfangenen Byte automatisch die nächste Koordinate angesprungen wird? Oder kann man mit dem DMA vielleicht sogar einen normalen GPIOPin mit dem RICHTIGEN Timing zum SPI Transfer schalten(-> glaub ich nicht)?
Würde mich freuen wenn du da helfen könntest!
Im Datenblatt vom Controller
http://www.lcd-module.de/deu/pdf/grafik/dogs102-6.pdf
hab ich gerade etwas gefunden, was sich sehr nach den vom mir betitelten “Burst-Mode” anhört.
Seite 5:
(25) Set Adv. Program Control 0
Jetzt muss ich nur mal rausfinden wie ich die Lib dementsprechend umschreibe… Sollte aber nocht so heftig sein…
ich hab für den ATMega eine Library für das EA-Dog Display geschrieben. Ein Byte setzt ja 8 Pixel vom LCD gleichzeitig
(und das Display incrementiert die Adresse selbst)
also kannst du nach jeder “Zeile” von 102 Pixel den Cursor
um eine Page weiterschalten (das sind dann 8Pixel)
somit brauchst du zum löschen vom kompletten LCD nur 8mal
die Adresse neu setzen