Hallo liebe Forengemeinde, ich möchte serielle asynchrone Daten mit 4MBit/s senden (Daten+CRC). Diese müssten Manchester codiert werden und mit 8MBit/s den µC verlassen. Desweiteren soll das ganze auch rückwärts geschehen (simplex). Asynchonen Manchestercode empfangen, decodieren, CRC check durchführen und Daten verwenden. Passt das ganze Vorhaben einigermaßen adäquat in einen STM32F407? (Nebenbei soll noch eine Ethernetschnittstelle betrieben werden) Ansonsten könnte ich mir auch vorstellen einen Zync zu verwenden, wenn es mit dem µC zu eng wird. Habt ihr diesbezüglich Erfahrungen/Ratschläge? Beste Grüße Hans
Wie oft willst Du die Daten senden? Bei durchgehend 8mbit/s ist der STM32F4 wohl etwas überfordert, falls nicht andauernd Daten gesendet/empfangen werden, sollte das so gehen: Senden bekommst Du über DMA hin: * DMA über Timer mit 16Mhz triggern * und für jede Flanke (high->low und low->high) einen vorberechneten Bitwert aus einer Tabelle per DMA auf das GPIOx_BSRR ausgeben Nachteil: Du brauchst für jedes Bit 2 * 32Bit als AusgabePuffer für das GPIOx_BSRR. Aber der STM32F4 hat ja etwas RAM. Empfangen sollte über 2 Input-Capture Register, die per DMA eingelesen werden, realsisierbar sein. Gruß, Stefan
bdw: Die Manchster-Ausgabe kannst Du auch mit einer SPI und einem externen XOR-Gatter erreichen. Gruß, Stefan
@ Stefan (Gast) >Senden bekommst Du über DMA hin: >* DMA über Timer mit 16Mhz triggern >* und für jede Flanke (high->low und low->high) einen vorberechneten >Bitwert > aus einer Tabelle per DMA auf das GPIOx_BSRR ausgeben Geht einfacher, mit SPI. DMA ist natürlich zusätzlich nett. >Empfangen sollte über 2 Input-Capture Register, die per DMA eingelesen >werden, realsisierbar sein. Ich würde lieber per Timer und DMA den Datenstrom einfach abtasten und dann per CPU dekodieren. Wenn man es clever macht, könnte man sogar einen dauerhaften Datenstrom empfangen und nebenbei noch andere Dinge erledigen. Die DMA arbeitet dabei auf einen FIFO.
@ Stefan (Gast) >Die Manchster-Ausgabe kannst Du auch mit einer SPI und einem externen >XOR-Gatter erreichen. Wozu das Gatter? Das kann die CPU locker vorher berechnen, im einfachsten und schnellsten Fall über eine Tabelle mit 256 16 Bit Einträgen.
Ok, Du willst nur den SPI-Datenpin benutzen und zwar mit der doppelten Bitrate. Geht auch, clever. Die eigendliche Herausforderung dürfte das Empfangen sein. Und da kommt es etwas darauf an, wieviel Daten der TS empfangen will. Gruß, Stefan
Vielen Dank für die zahlreichen Antworten. Das Senden über SPI finde ich eine sehr gute Idee, so werde ich das denke ich auch machen. Das Empfangen wird da sicherlich nicht ganz so einfach. Die zu empfangenen Pakete sind 36Bit lang. Die Häufigkeit der Pakete werde ich in Erfahrung bringen. Das Abtasten des Datenstreams ist halt nicht so einfach. Der Takt ist bekannt, jedoch ist die Phasenlage unbekannt. Könnte ich nicht im einfachsten Fall mit der ersten steigenden oder fallenden Flanke einen Timer starten und dann den Datenstream auslesen? Anschließend dekodieren und CRC-Checken. Ist die interne CRC-Check Routine des STM 32F4 brauchbar? Besten Dank...
PS: Die Datenlänge die ich per SPI senden kann ist frei definierbar? Zu senden sind ebenfalls 36Bit Pakete.
@Hans (Gast) >Das Empfangen wird da sicherlich nicht ganz so einfach. Fast! Das machst du acuh mit SPI, nur halt mit höherer Datenrate. 8Mbit/s sollte man mindestens mit 32 MHz abtasten, besser 64 MHz. Schau mal ob deine SPI so schnell arbeiten kann. Die DMA schafelt dazu die Daten in den RAM. > Die zu >empfangenen Pakete sind 36Bit lang. Also praktisch nix. > Die Häufigkeit der Pakete werde ich >in Erfahrung bringen. 36 Bit @ 8MHz = 4,5us. Selbst wenn die alle 100us kommen, schafft das deine CPU locker. SOOO lange dauert die Dekodierung nicht. > Das Abtasten des Datenstreams ist halt nicht so >einfach. Doch, siehe oben. Wenn es deine SPI nicht schnell genug abtasten kann, kann man auch einen Timer + DMA versuchen, der einfach einen Eingangsport in den Speicher schreibt. > Der Takt ist bekannt, jedoch ist die Phasenlage unbekannt. >Könnte ich nicht im einfachsten Fall mit der ersten steigenden oder >fallenden Flanke einen Timer starten und dann den Datenstream auslesen? Vergiss es, nicht bei 8 Mbit/s. Abtasten heißt das Zauberwort. So machen es alle. RS232, CAN, USB etc. Clock & Data Recovery. >Anschließend dekodieren und CRC-Checken. Ist die interne CRC-Check >Routine des STM 32F4 brauchbar? Kann sein, bei 36 Bit lohnt das aber kaum.
@ Hans (Gast) >PS: Die Datenlänge die ich per SPI senden kann ist frei definierbar? Zu >senden sind ebenfalls 36Bit Pakete. Niemand hindert dich, 36 Bit als 5x8 Bit zu senden. Die letzten 4 Bit hängt man Dummydaten an. Beim Empfang ebenso.
Eine Sache hab ich bezüglich dem Einlesen über SPI noch nicht ganz nachvollzogen. Ich habe nur eine Leitung an der ich die Manchestercodierten Daten empfange. Es ist keine SCLK oder SS Leitung vorhanden. Der Dateneingang wird auf MISO gelegt und dann abgetastet. Wann weiß der SPI Controller ab wann er abtasten soll. Erfolgt die Abtastung automatisch mit der ersten Flanke mit dem eingestellten Takt und für die Dauer der gewählten Datengröße? Besten Dank...
@ Hans (Gast) >Ich habe nur eine Leitung an der ich die Manchestercodierten Daten >empfange. Reicht doch. > Es ist keine SCLK oder SS Leitung vorhanden. Brauchst du auch nicht. > Der Dateneingang >wird auf MISO gelegt und dann abgetastet. Wann weiß der SPI Controller >ab wann er abtasten soll. Er macht es einfach dauerhaft mit der eingestellten Bitrate. Dass dabei weder SCK noch CS eine Rolle spielt, ist dem SPI-Modul egal. Es tastet die Daten ab, schreibt sie ins Eingangsschieberegister und von dort landen sie per DMA im RAM. Einkanal Logicanalyzer für Arme ;-)
Wenn die Daten mit 8Mbit/s empfangen werden und ich mit 32MHz Abtaste erhalte ich vier Abtastwerte je Bit. Wenn die Nachrichtenbreite von 36Bit vierfach abgetastet wird, so erhalte ich 144Bit je SPI-Frame. Aber wie stelle ich sicher, dass sich genau dort dann auch eine Nachricht von Anfang bis Ende befindet, wenn ich dauerhaft einlese? Ist es dann nicht einfacher ein 16Bit Schieberegister mit (SPI1) zu füllen und auf 0x000F abzufragen (Siehe Anhang), das würde den Beginn einer Nachricht kennzeichnen? Dann ein (SPI2) mit dem (SPI1) triggern um den Payload auszulesen. Hat das Aussicht auf Erfolg oder übersehe ich etwas? SPI3 würde ich dann zum senden benutzen.
@Hans (Gast) >wie stelle ich sicher, dass sich genau dort dann auch eine Nachricht von >Anfang bis Ende befindet, wenn ich dauerhaft einlese? Gar nicht. Du musst mehr Daten lesen und dann intelligent den Anfang erkennen. >Ist es dann nicht einfacher ein 16Bit Schieberegister mit (SPI1) zu >füllen und auf 0x000F abzufragen (Siehe Anhang), Nein, das geht nicht. Denn dein SPI läuft nicht synchron zu deiner Datenquelle. > das würde den Beginn >einer Nachricht kennzeichnen? Dann ein (SPI2) mit dem (SPI1) triggern um >den Payload auszulesen. Hat das Aussicht auf Erfolg oder übersehe ich >etwas? SPI3 würde ich dann zum senden benutzen. Ohjemine. Jetzt ist mir klar, wozu man 4 SPI Module in einem ARM braucht 8-0 SO NICHT! Es reicht EIN SPI-Modul. Woran kannst du erkennen, ob ein Datenpaket geschickt wird? Passiert das "zufällig" oder weiß man ungefähr, wann es gesendet wird? Denn in den Pausen musst du auch Daten abtasdten und erkennen, ob nichts ankommt oder eine echte Nachricht. Wenn auf dem Kanal zwischen den Nachrichten dauerhaft LOW oder HIGH gesendet wird, kann man das in den abgetasteten Daten als 0x00 oder 0xFF erkennen. Da es aber Manchesterkodiert ist, könnte es auch sein, dass dauerhaft 0x55 oder 0xAA empfangen wird. Aber auch das ist leicht erkennbar.
>>Ist es dann nicht einfacher ein 16Bit Schieberegister mit (SPI1) zu >>füllen und auf 0x000F abzufragen (Siehe Anhang), >Nein, das geht nicht. Denn dein SPI läuft nicht synchron zu deiner >Datenquelle. >>das würde den Beginn >>einer Nachricht kennzeichnen? Dann ein (SPI2) mit dem (SPI1) triggern um >>den Payload auszulesen. Hat das Aussicht auf Erfolg oder übersehe ich >>etwas? SPI3 würde ich dann zum senden benutzen. >Ohjemine. Jetzt ist mir klar, wozu man 4 SPI Module in einem ARM braucht >8-0 >SO NICHT! Es reicht EIN SPI-Modul. Ich habe deinen Ansatz verstanden dauerhaft abzutasten und dann den Anfang einer Nachricht zu suchen und diese zu extrahieren. Nochmal kurz zu meiner Idee: Was spricht denn dagegen ein zweites SPI Modul zu verwenden? Das wäre doch eher zum Vorteil, da ich die CPU weniger belasten würde. Mir ist schon klar, dass die Daten asynchron sind, aber das macht doch keinen Unterschied. In dem Anhang: Frame.png ist der Beginn einer Nachricht mit einer einzigartigen Folge gekennzeichnet "0001". Diese Folge erfasse ich doch in jedem Fall, da vier Abtastpunkte je Bit vorhanden sind um "000F" zu erhalten. Auf diese Weise habe ich doch elegant den Beginn meiner Nutzlast gefunden, ohne die CPU zu beanspruchen. Beste Grüße
@ Hans (Gast) >Was spricht denn dagegen ein zweites SPI Modul zu verwenden? Es bringt keinerlei Vorteil. > Das wäre >doch eher zum Vorteil, da ich die CPU weniger belasten würde. Nein. >Mir ist >schon klar, dass die Daten asynchron sind, Wirklich? >aber das macht doch keinen >Unterschied. In dem Anhang: Frame.png ist der Beginn einer Nachricht mit >einer einzigartigen Folge gekennzeichnet "0001". Diese Folge erfasse ich >doch in jedem Fall, da vier Abtastpunkte je Bit vorhanden sind um "000F" >zu erhalten. Aber die Grenzen des 1. Bytes sind NICHT synchron zu deiner Abtastung. Du kannst als erstes 16 Bit Wort genausogut 0x00FA empfangen, weil das erste Nibble durch die beliebige Phasenlage ins vorherige 16 Bit Wort gerutscht ist. Genauso wie 0x003C Hier ist es eine Verschiebung um 2 Bit. > Auf diese Weise habe ich doch elegant den Beginn meiner >Nutzlast gefunden, ohne die CPU zu beanspruchen. Nö. Dazu musste eine Hardwarelogik exisiteren, welche immer nach 0x000F sucht und dann "Hallo" ruft. Die gibt es aber in den SPI-Modulen nicht.
Falk Brunner schrieb: >>aber das macht doch keinen >>Unterschied. In dem Anhang: Frame.png ist der Beginn einer Nachricht mit >>einer einzigartigen Folge gekennzeichnet "0001". Diese Folge erfasse ich >>doch in jedem Fall, da vier Abtastpunkte je Bit vorhanden sind um "000F" >>zu erhalten. > > Aber die Grenzen des 1. Bytes sind NICHT synchron zu deiner Abtastung. > Du kannst als erstes 16 Bit Wort genausogut > > 0x00FA empfangen, weil das erste Nibble durch die beliebige Phasenlage > ins vorherige 16 Bit Wort gerutscht ist. Genauso wie > > 0x003C > > Hier ist es eine Verschiebung um 2 Bit. Die Idee ist nicht immer ein Byte einzulesen, sondern jedes Bit einzeln und dann das Schieberegister zu beurteilen, oder funktioniert das bei SPI nur Byteweise? Dann wäre mein Ansatz natürlich nicht sinnvoll.
Dann vielleicht über ein normales Schieberegister/Timer die Startsequenz abtasten, dann SPI triggern für die Nutzdaten und anschließend nach der Verarbeitung das Schieberegister/Timer wieder starten.
@ Hans (Gast) >Die Idee ist nicht immer ein Byte einzulesen, sondern jedes Bit einzeln >und dann das Schieberegister zu beurteilen, Bei 8 Mbit/s? Jaja ;-) >oder funktioniert das bei >SPI nur Byteweise? Das auch. >Dann wäre mein Ansatz natürlich nicht sinnvoll. Eben!
Wie wäre es den mit einem "CMOS 4094" den Start einer Nachricht abzutasten? Beste Grüße
Ich greife mal deinen Vorschlag auf: 36Bit mit 4 Abtastwerten ergeben sich 144Bit je Nachricht. Die 144Bit, die dann im Speicher stehen müssen nach dem Startmuster untersucht werden. Diese 144Bit müssen aus dem Speicher in einen weiteren Speicher umkopiert werden, bevor die neuen 144Bit da sind. Mit den vorhandenen 288Bit ließe sich dann eine Nachricht extrahieren.
@Hans (Gast) >Wie wäre es den mit einem "CMOS 4094" den Start einer Nachricht >abzutasten? Unsinn, ausserdem ist der viel zu langsam. >36Bit mit 4 Abtastwerten ergeben sich 144Bit je Nachricht. >Die 144Bit, die dann im Speicher stehen müssen nach dem Startmuster >untersucht werden. Ja. >Diese 144Bit müssen aus dem Speicher in einen >weiteren Speicher umkopiert werden, bevor die neuen 144Bit da sind. Ja. > Mit >den vorhandenen 288Bit ließe sich dann eine Nachricht extrahieren. ??? Den Speicher macht man sinnvollerweise um einiges größer, wir reden hier nur übe ein paar Dutzend Bytes. Dabei nutztem man 2 DMA Kanäle abwechselnd, welche zyklisch ZWEI Speicher immer wieder voll schreiben. Während der eine Speicher geschrieben wird, kann man den anderen durchsuchen und ggf. dekodieren.
8 Mbit/s mit 4 Bit/Bit gesampelt gibt 4 MByte/s. Ich bezweifle, dass Du es schaffst, Dich mit einem F4 kontinuierlich durch den Datenwust zu wuehlen....
@ Uwe Bonnes (Gast) >8 Mbit/s mit 4 Bit/Bit gesampelt gibt 4 MByte/s. Ich bezweifle, dass Du >es schaffst, Dich mit einem F4 kontinuierlich durch den Datenwust zu >wuehlen.... Der Mensch wächst an seinen Aufgaben. Immerhin ist es ein 32 Bit Prozessor mit 168 MHz. Da geht schon was. Klar, ein kleiner CPLD, der als Dekoder + UART läuft macht das locker, da reichen 32 MHz. Ist aber zu einfach ;-)
Ich versuche grade per SPI zu senden, jedoch läuft da was nicht ganz richtig. Irgendwie sehe ich nicht was falsch ist, siehe (Anhang). An PE7 ist das CS korrekt zu sehen und an PA5 ein merkwürdiges SCK. PA7 zeigt jedoch keine Nachricht.
1 | void init_SPI1(void){ |
2 | |
3 | GPIO_InitTypeDef GPIO_InitStruct; |
4 | SPI_InitTypeDef SPI_InitStruct; |
5 | |
6 | // enable clock for used IO pins
|
7 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); |
8 | |
9 | /* configure pins used by SPI1
|
10 | * PA5 = SCK
|
11 | * PA6 = MISO
|
12 | * PA7 = MOSI
|
13 | */
|
14 | GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5; |
15 | GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; |
16 | GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; |
17 | GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; |
18 | GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; |
19 | GPIO_Init(GPIOA, &GPIO_InitStruct); |
20 | |
21 | // connect SPI1 pins to SPI alternate function
|
22 | GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1); |
23 | GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1); |
24 | GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1); |
25 | |
26 | // enable clock for used IO pins
|
27 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); |
28 | |
29 | /* Configure the chip select pin
|
30 | in this case we will use PE7 */
|
31 | GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7; |
32 | GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; |
33 | GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; |
34 | GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; |
35 | GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; |
36 | GPIO_Init(GPIOE, &GPIO_InitStruct); |
37 | |
38 | GPIOE->BSRRL |= GPIO_Pin_7; // set PE7 high |
39 | |
40 | // enable peripheral clock
|
41 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); |
42 | |
43 | /* configure SPI1 in Mode 0
|
44 | * CPOL = 0 --> clock is low when idle
|
45 | * CPHA = 0 --> data is sampled at the first edge
|
46 | */
|
47 | SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines |
48 | SPI_InitStruct.SPI_Mode = SPI_Mode_Master; // transmit in master mode, NSS pin has to be always high |
49 | SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide |
50 | SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; // clock is low when idle |
51 | SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // data sampled at first edge |
52 | SPI_InitStruct.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set; // set the NSS management to internal and pull internal NSS high |
53 | SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; // SPI frequency is APB2 frequency / 4 |
54 | SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first |
55 | SPI_Init(SPI1, &SPI_InitStruct); |
56 | |
57 | SPI_Cmd(SPI1, ENABLE); // enable SPI1 |
58 | }
|
59 | |
60 | /* This funtion is used to transmit and receive data
|
61 | * with SPI1
|
62 | * data --> data to be transmitted
|
63 | * returns received value
|
64 | */
|
65 | uint8_t SPI1_send(uint8_t data){ |
66 | |
67 | SPI1->DR = data; // write data to be transmitted to the SPI data register |
68 | while( !(SPI1->SR & SPI_I2S_FLAG_TXE) ); // wait until transmit complete |
69 | while( !(SPI1->SR & SPI_I2S_FLAG_RXNE) ); // wait until receive complete |
70 | while( SPI1->SR & SPI_I2S_FLAG_BSY ); // wait until SPI is not busy anymore |
71 | return SPI1->DR; // return received data from SPI data register |
72 | }
|
73 | |
74 | int main(void){ |
75 | |
76 | uint8_t received_val = 0; |
77 | |
78 | init_SPI1(); |
79 | |
80 | while(1){ |
81 | |
82 | GPIOE->BSRRH |= GPIO_Pin_7; // set PE7 (CS) low |
83 | SPI1_send(0xAA); // transmit data |
84 | received_val = SPI1_send(0x00); // transmit dummy byte and receive data |
85 | GPIOE->BSRRL |= GPIO_Pin_7; // set PE7 (CS) high |
86 | }
|
87 | }
|
@ Hans (Gast) >richtig. Irgendwie sehe ich nicht was falsch ist, siehe (Anhang). An PE7 >ist das CS korrekt zu sehen und an PA5 ein merkwürdiges SCK. PA7 zeigt >jedoch keine Nachricht. Deine Signale sehr ziemlich schlecht aus. Das kriegt man deutlich besser hin. Dazu muss man u.a. einen 10:1 Taskopf benutzen und die Masse kurz halten. Auf deinem CS SIgnal gibt es ziemlich viel Übersprechen vom SCK, auch ein Indiz für eine schlechte Masseanbindung.
Ein remap der SCK MOSI UND MISO funktioniert irgendwie nicht. Woran kann das liegen? Ich messe den SLK trotz remap immer noch an PA5... Das darf doch nicht sein, oder?
1 | void init_SPI1(void){ |
2 | |
3 | GPIO_InitTypeDef GPIO_InitStruct; |
4 | SPI_InitTypeDef SPI_InitStruct; |
5 | |
6 | // enable peripheral clock
|
7 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); |
8 | |
9 | // enable clock for used IO pins
|
10 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); |
11 | |
12 | /* GPIO Deinitialisation */
|
13 | GPIO_DeInit(GPIOA); |
14 | GPIO_DeInit(GPIOA); |
15 | GPIO_DeInit(GPIOA); |
16 | |
17 | /* configure pins used by SPI1
|
18 | * PA4 = SCK
|
19 | * PA5 = MISO
|
20 | * PA6 = MOSI
|
21 | */
|
22 | |
23 | // connect SPI1 pins to SPI alternate function
|
24 | GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI1); |
25 | GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1); |
26 | GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1); |
27 | |
28 | GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; |
29 | GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; |
30 | GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; |
31 | GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; |
32 | |
33 | GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4; |
34 | GPIO_Init(GPIOA, &GPIO_InitStruct); |
35 | |
36 | GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5; |
37 | GPIO_Init(GPIOA, &GPIO_InitStruct); |
38 | |
39 | GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; |
40 | GPIO_Init(GPIOA, &GPIO_InitStruct); |
41 | |
42 | // enable clock for used IO pins
|
43 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); |
44 | |
45 | /* Configure the chip select pin
|
46 | in this case we will use PE7 */
|
47 | GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7; |
48 | GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; |
49 | GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; |
50 | GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; |
51 | GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; |
52 | GPIO_Init(GPIOE, &GPIO_InitStruct); |
53 | |
54 | GPIOE->BSRRL |= GPIO_Pin_7; // set PE7 high |
55 | |
56 | /* configure SPI1 in Mode 0
|
57 | * CPOL = 0 --> clock is low when idle
|
58 | * CPHA = 0 --> data is sampled at the first edge
|
59 | */
|
60 | |
61 | SPI_I2S_DeInit(SPI1); |
62 | SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines |
63 | SPI_InitStruct.SPI_Mode = SPI_Mode_Master; // transmit in master mode, NSS pin has to be always high |
64 | SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide |
65 | SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; // clock is low when idle |
66 | SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // data sampled at first edge |
67 | SPI_InitStruct.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set; // set the NSS management to internal and pull internal NSS high |
68 | SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; // SPI frequency is APB2 frequency / 4 |
69 | SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first |
70 | SPI_Init(SPI1, &SPI_InitStruct); |
71 | |
72 | SPI_Cmd(SPI1, ENABLE); // enable SPI1 |
73 | }
|
74 | |
75 | /* This funtion is used to transmit and receive data
|
76 | * with SPI1
|
77 | * data --> data to be transmitted
|
78 | * returns received value
|
79 | */
|
80 | uint8_t SPI1_send(uint8_t data){ |
81 | |
82 | SPI1->DR = data; // write data to be transmitted to the SPI data register |
83 | while( !(SPI1->SR & SPI_I2S_FLAG_TXE) ); // wait until transmit complete |
84 | while( !(SPI1->SR & SPI_I2S_FLAG_RXNE) ); // wait until receive complete |
85 | while( SPI1->SR & SPI_I2S_FLAG_BSY ); // wait until SPI is not busy anymore |
86 | return SPI1->DR; // return received data from SPI data register |
87 | }
|
88 | |
89 | int main(void){ |
90 | |
91 | uint8_t received_val = 0; |
92 | |
93 | init_SPI1(); |
94 | int i =0; |
95 | |
96 | while(1){ |
97 | |
98 | GPIOE->BSRRH |= GPIO_Pin_7; // set PE7 (CS) low |
99 | SPI1_send(0xFA); // transmit data |
100 | received_val = SPI1_send(0x00); // transmit dummy byte and receive data |
101 | GPIOE->BSRRL |= GPIO_Pin_7; // set PE7 (CS) high |
102 | }
|
103 | }
|
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.