Hallo zusammen, ich möchte mich jetzt schon entschuldigen, dass der Code nicht richtig formatiert ist, ich weiss nicht mit welchem TAG ich hier das machen kann. Hab gesucht aber nichts gefunden. Ich bin neu hier und habe ein Problem mit meinem SPI. Ich habe zwei uC (2xLPC1754) die miteinander kommunizieren sollen. Wahrscheinlich reicht mir sogar wenn der Master dem Slave Daten schicken kann und dieser die Daten lesen kann. Der Slave muss also nicht unbedingt was zurück schicken können. Ich habe zuerst mal im User Manual (http://www.nxp.com/documents/user_manual/UM10360.pdf) nachgelesen, da ich wenig Erfahrung damit habe. Jedoch ist es dort sehr oberflächlich erklärt oder so, dass ich es nicht verstehe. Ich habe dann mit einem Beispiel, dass ich gefunden habe probiert es zum Laufen zu bringen. Nur läuft es nicht gerade so wie es soll. Ich habe den Code leider nicht zu Hause und bin nicht mehr im Geschäft, kann den noch nachreichen aber ist in etwa das Folgende zur Initialisierung PINSEL_CFG_Type PinCfg; SPI_DATA_SETUP_Type xferConfig; uint32_t tmp; /* * Initialize SPI pin connect * P0.15 - SCK; * P0.16 - SSEL - used as GPIO * P0.17 - MISO * P0.18 - MOSI */ PinCfg.Funcnum = 3; PinCfg.OpenDrain = 0; PinCfg.Pinmode = 0; PinCfg.Portnum = 0; PinCfg.Pinnum = 15; PINSEL_ConfigPin(&PinCfg); PinCfg.Pinnum = 17; PINSEL_ConfigPin(&PinCfg); PinCfg.Pinnum = 18; PINSEL_ConfigPin(&PinCfg); PinCfg.Pinnum = 16; PinCfg.Funcnum = 0; PINSEL_ConfigPin(&PinCfg); SPI_ConfigStruct.CPHA = SPI_CPHA_SECOND; SPI_ConfigStruct.CPOL = SPI_CPOL_LO; SPI_ConfigStruct.ClockRate = 2000000; SPI_ConfigStruct.DataOrder = SPI_DATA_MSB_FIRST; SPI_ConfigStruct.Databit = SPI_DATABIT_SIZE; SPI_ConfigStruct.Mode = SPI_MASTER_MODE; SPI_Init(LPC_SPI, &SPI_ConfigStruct); Damit sollte ich das SPI initialisiert haben (Clock, Power und sonstige Einstellungen). Ich habe nun eine Quadrature Signal, also zwei Signale die 90° verschoben sind. Die Idee ist nun, dass ich jedes mal, wenn eines der Signale ändert die Interruptroutine aufgerufen wird und der Zählerwert per SPI an den Slave geschickt wird. Die Interruptroutine hab ich schon und das Auslesen des Zählers und der Interrupt selber funktioniert ohne Probleme. Das Problem ist, dass ich den Wert des Counters nun schicken will. Dazu schreibe ich ins LPC_SPI->SPDR, wenn ich mich richtig erinnere und laut User Manual und anderen Kommentaren im Internet, sollte durch das beschreiben die Datenübertragung starten, dies passiert aber nicht, es passiert gar nichts. nach dem beschreiben will ich eigentlich auf das SPIF warten und dann SPDR auslesen also wie folgt while(!LPC_SPI->SPIF); tmp = LPC_SPI->SPDR; jedoch startet das SPI gar nicht mit dem senden. Woran könnte es liegen? Vergesse ich da was Wichtiges? Ich habe das SPI auch schon zum laufen gebracht aber glaube nicht so wie es eigentlich soll ^^ Ich habe dazu einfach jedes mal das LPC_SPI->SPDR beschrieben und danach CS_Force(0); for (tmp = 10000; tmp; tmp--); xferConfig.tx_data = Tx_Buf; xferConfig.rx_data = Rx_Buf; xferConfig.length = BUFFER_SIZE; SPI_ReadWrite(LPC_SPI, &xferConfig, SPI_TRANSFER_POLLING); for (tmp = 10000; tmp; tmp--); CS_Force(1); gemacht. Irgendwie konnte ich dann senden und mit dem Slave empfangen aber habe was geändert und jetzt läuft gar nichts mehr und ich weiss nicht was ich geändert habe. Ist es nicht so, dass ich das SPI_ReadWrite() gar nicht benötige sondern die Daten selber geschickt werden sollten wenn ich was ins SPDR lege? Auf der Slave Seite habe ich einen Interrupt für das CS Signal und wenn dieses auf HIGH geht warte ich auf das SPIF und lese dann das LPC_SPI->SPDR aus, dies hat auch funktioniert. Gibt wahrscheinlich auch dafür ne einfachere Methode aber hab halt selber was versucht um bisschen Erfahrung zu sammeln und hat ja gut funktioniert :-) Ich hoffe es kann mir wer helfen, hab da schon mehrere Tage dran probiert aber irgendwie komme ich nicht wirklich vorwärts. Gruss Cance
Igor cancarevic schrieb: > auf das SPIF warten und dann SPDR auslesen also wie folgt > > while(!LPC_SPI->SPIF); > tmp = LPC_SPI->SPDR; > > jedoch startet das SPI gar nicht mit dem senden. Im Codeschnipsel wird SPDR nur gelesen.. Bei SPI wird immer gleichzeitig gelesen und geschrieben. Um eine Datenübertragung auf dem Master zu starten, muss also SPDR geschrieben werden, eventuell mit einem Dummy Wert. Übrigens empfehle ich auf einem LPC17xx lieber die SSP Einheiten zu benutzen. Die können auch SPI, haben aber FIFOs und DMA Support zusätzlich und bis zu 16 Bit breite Datenwörter.
Danke erstmal für die schnelle Antwort. Den Teil wo ich ins SPDR schreibe habe ich weggelassen. Dabei lese ich einen Wert aus dem Counter aus und berechne daraus die Differenz zum letzten Wert und übergebe die Differenz dann an SPDR LPC_SPI->SPDR = counter_delta; danach warte ich auf SPIF und lese SPDR aus while(!LPC_SPI->SPIF); tmp = LPC_SPI->SPDR; Damit startet bei mir aber keine Übertragung. Sollte dies nicht automatisch die Übertragung starten? Oder fehlt bei mir was in der Initialisierung? Im Beispiel ist auch der Polling mode gewählt nicht der Interrupt mode. Ich weiss nicht genau worauf sich das bezieht, ist das vielleicht der Grund, dass es nicht automatisch startet, falls ja was muss ich da alles einstellen damit es mit Interrupt funktioniert? Ich habe wahrscheinlich die SSP Einheit in Gebrauch, da ich bei der Grösse der Datenwörter zwischen 8-16bit wählen kann. Da ich aber nur die Differenz zwischen dem letzten Wert und dem neuen Wert übergebe reichen mit 8bit locker, da die Differenz in meinem Fall nur Plus oder Minus 1 ist :-) Vielleicht wird später auch mal mehr übertragen oder auch was vom Slave gesendet aber für den Moment brauch ich das nicht. Im Moment sendet es nur etwas, wenn ich SPI_ReadWrite() verwende, was anscheinend nicht nötig sein sollte und wenn ich es verwende ist das Timing auch nicht immer super, hatte mal eine Version wo es funktioniert hat, dafür hat er aber immer weiter Chip Select gemacht in unregelmässigen Abständen :-( Ich hoffe mein Problem ist deutlich geworden.
p0.15-Funcnum 3 ist laut Handbuch spi und nicht ssp. p0.16 - cs - sollte normaler gpio - also Funcnum 0 - sein. Bei mir hat es geholfen, zunächst einen software-spi zu programmieren. man kann beim software-spi leicht jeden einzelnen Takt überprüfen. wenn das geht, kann man auf spi oder ssp umstellen.
funktionierender spi-code: //init hw spi PINSEL0|=(3<<30);//0.15-4:ck PINSEL1|=(3<<2);//0.17-4:miso PINSEL1|=(3<<4);//0.18-4:mosi PINSEL1 = 0b111100; // P0.18 = MOSI, P0.17 = MISO, P0.16 = GPIO PINMODE0 = 2<<30; // P0.15 has neither pull-up nor pull-down PINMODE1 = 0b101010; // P0.18..16 have neither pull-up nor pull-down #define BitEnablehwspi 0 #define MSTRhwspi 5 #define CPOLhwspi 4 #define CPHAhwspi 3 #define SPIFhwspi 7 LPC_SPI->SPCR=(1<<MSTRhwspi); LPC_SPI->SPCR&=~(1<<BitEnablehwspi);// LPC_SPI->SPCR|=(1<<CPOLhwspi);// S0SPCR|=(1<<CPOL);// LPC_SPI->SPCR|=(1<<CPHAhwspi);// //LPC_SPI->SPCR&=~(1<<LSBF);//????msbf LPC_SPI->SPCCR=8; //send/receive hwspi LPC_SPI->SPDR=byte_s; while(!(LPC_SPI->SPSR & (1<<SPIFhwspi))); return(LPC_SPI->SPDR);
Danke für den Code, ich musste für PINSEL noch LPC_SPI-> vorne hin setzen aber das war ja nicht ein grosses Ding ^^ Mit deinem Code reagiert das SPI auf das beschreiben des SPDR, jedoch sehe ich auf dem Oszilloskop, dass nur der MOSI und der Clock kommen, diese passen aber zueinander. Jedoch kommt kein CS Signal, bzw. CS, bleibt auf HIGH, dadurch passiert beim Slave natürlich nichts. Ist ja als GPIO definiert, sollte ja eigentlich passen. Muss ich das CS einfach vor dem "LPC_SPI->SPDR=byte_s;" LOW ziehen und nach dem abwarten des SPIF wieder HIGH ziehen? oder sollte das von alleine funktionieren? Was wird eigentlich gestartet beim beschreiben des SPDR? ist der Code irgendwo ersichtlich? Gruss Cance
leluno schrieb: > p0.15-Funcnum 3 ist laut Handbuch spi und nicht ssp. p0.16 - cs - sollte > normaler gpio - also Funcnum 0 - sein. Bei mir hat es geholfen, zunächst > einen software-spi zu programmieren. man kann beim software-spi leicht > jeden einzelnen Takt überprüfen. wenn das geht, kann man auf spi oder > ssp umstellen. OK, dann ist es wohl doch SPI ^^ Jedoch kann ich die Wortbreite von 8-16bit wählen mit dem Beispiel das ich gefunden habe, hat eigentlich auch einigermassen funktioniert aber nicht perfekt. CS ist als GPIO definiert PinCfg.Pinnum = 16; PinCfg.Funcnum = 0; PINSEL_ConfigPin(&PinCfg); Mit Hilfe von karl k.'s beispiel funktioniert es jetzt soweit ziemlich gut. Wenn man den CS selber machen muss vor und nach dem senden, dann passt das soweit. habs jetzt so gemacht. GPIO_ClearValue(CS_PORT_NUM, (1<<CS_PIN_NUM)); for (tmp = 10; tmp; tmp--); LPC_SPI->SPDR=send_delta; while(!(LPC_SPI->SPSR & (1<<SPIFhwspi))); GPIO_SetValue(CS_PORT_NUM, (1<<CS_PIN_NUM)); status = LPC_SPI->SPDR; und sieht schon mal gut aus auf dem Oszilloskop. Danke euch für die schnellen Antworten. Gruss Cance
im Abstand von einem halben Jahr tut der oben vorgestellte code richtig
weh
>> //init hw spi
PINSEL0|=(3<<30);//0.15-4:ck
PINSEL1|=(3<<2);//0.17-4:miso
PINSEL1|=(3<<4);//0.18-4:mosi
PINSEL1 = 0b111100; // P0.18 = MOSI, P0.17 = MISO, P0.16 = GPIO
PINMODE0 = 2<<30; // P0.15 has neither pull-up nor pull-down
PINMODE1 = 0b101010; // P0.18..16 have neither pull-up nor pull-down
man sollte auf die nicht aus sich selbst heraus verständlichen
Unter-Register ganz verzichten und Macros über Portnum und Pinnum
definieren.
#define pinSEL(p,b,v) PINSEL[(p) * 2 + (b) / 16] = (PINSEL[(p) * 2 +
(b) / 16] & ~(3 << ((b) * 2 % 32))) | (v << ((b) * 2 % 32))
#define non_pullup 2
pinSEL(0,18,3)
pinMODE(0,18,non_pullup)
Man weiß dann sofort, um welchen pin es geht und was mit ihm geschehen
soll.
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.