von
M430 (Gast)
17.08.2015 15:52
Hallo zusammen,
ich bin neu in MSP430 Programmierung und tue mich grade mit SPI
Kommunkation etwas schwer. Ich habe zwei Boards und möchte einfach mit
char Zeichen Leds steuern. Ich habe einen MSP430 als Master und einen
als Slave. Derzeit schaut der Code so aus:
Master:
1 #include <msp430.h>
2
3 unsigned char MST_Data , SLV_Data ;
4
5 int main ( void ) {
6 volatile unsigned int i ;
7
8 WDTCTL = WDTPW + WDTHOLD ; // Stop watchdog timer
9 FLL_CTL0 |= XCAP14PF ; // Configure load caps
10 P2DIR = 0xFF ;
11
12 // Wait for xtal to stabilize
13 do {
14 IFG1 &= ~ OFIFG ; // Clear OSCFault flag
15 for ( i = 0x47FF ; i > 0 ; i -- )
16 ; // Time for flag to set
17 } while (( IFG1 & OFIFG )); // OSCFault flag still set?
18
19 for ( i = 2100 ; i > 0 ; i -- )
20 ; // Now with stable ACLK, wait for
21 // DCO to stabilize.
22 P5OUT = 0x04 ; // P5 setup for LED and slave reset
23 P5DIR |= 0x06 ; //
24 P7SEL |= 0x0E ; // P7.3,2,1 option select
25 UCA0CTL0 |= UCMST + UCSYNC + UCCKPL + UCMSB ; //3-pin, 8-bit SPI master
26 UCA0CTL1 |= UCSSEL_2 ; // SMCLK
27 UCA0BR0 = 0x02 ; // /2
28 UCA0BR1 = 0 ; //
29 UCA0MCTL = 0 ; // No modulation
30 UCA0CTL1 &= ~ UCSWRST ; // **Initialize USCI state machine**
31 IE2 |= UCA0RXIE ; // Enable USCI_A0 RX interrupt
32
33 P5OUT &= ~ 0x04 ; // Now with SPI signals initialized,
34 P5OUT |= 0x04 ; // reset slave
35 P5OUT &= ~ 0x02 ;
36 P2OUT = 0x00 ;
37
38 while ( 1 )
39 {
40 while ( ! ( IFG2 & UCA0TXIFG ))
41 ; // USART1 TX buffer ready?
42 UCA0TXBUF = 'a' ; // Transmit character
43 P5OUT ^= 0x02 ;
44 // P2OUT ^= 0x02; // Toggle P2.0 using exclusive-OR
45 //
46 // i = 10000; // SW Delay
47 // do
48 // i--;
49 // while (i != 0);
50 __delay_cycles ( 1000000 );
51 }
52
53 // __bis_SR_register(LPM0_bits + GIE);
54 __bis_SR_register ( GIE );
55 // CPU off, enable interrupts
56 }
57
58 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
59 #pragma vector=USCIAB0RX_VECTOR
60 __interrupt void USCIA0RX_ISR ( void )
61 #elif defined(__GNUC__)
62 void __attribute__ (( interrupt ( USCIAB0RX_VECTOR ))) USCIA0RX_ISR ( void )
63 #else
64 #error Compiler not supported!
65 #endif
66 {
67 volatile unsigned int i ;
68 while ( ! ( IFG2 & UCA0RXIFG )); // USART1 RX buffer ready?
69 if ( UCA0RXBUF == 'A' ) // Test for correct character RX'd
70 {
71 P2OUT |= 0x02 ; // If correct, light LED
72 }
73
74 // MST_Data++; // Increment data
75 // SLV_Data++;
76 // UCA0TXBUF = MST_Data; // Send next value
77
78 for ( i = 100 ; i > 0 ; i -- )
79 ; // Add time between transmissions to
80 } // make sure slave can keep up
Slave:
1 #include <msp430.h>
2
3 typedef enum {
4 NO_LED , LED1 , LED2 , LED3 , LED4 , LED5 , LED6 , LED7 , LED8
5 } ledEnum ;
6
7 void turnLedOn ( char ledNum );
8 void turnLedOff ( char ledNum );
9
10 volatile int flag = 0 ;
11
12 int main ( void )
13 {
14 WDTCTL = WDTPW + WDTHOLD ; // Stop watchdog timer
15 P3DIR = 0xFF ;
16 // Configure XT1
17 PJSEL0 |= BIT4 + BIT5 ;
18
19 CSCTL0_H = 0xA5 ;
20 CSCTL1 |= DCOFSEL0 + DCOFSEL1 ; // Set max. DCO setting
21 CSCTL2 = SELA_0 + SELS_3 + SELM_3 ; // set ACLK = XT1; MCLK = DCO
22 CSCTL3 = DIVA_0 + DIVS_3 + DIVM_3 ; // set all dividers
23 CSCTL4 |= XT1DRIVE_0 ;
24 CSCTL4 &= ~ XT1OFF ;
25 do
26 {
27 CSCTL5 &= ~ XT1OFFG ;
28 // Clear XT1 fault flag
29 SFRIFG1 &= ~ OFIFG ;
30 } while ( SFRIFG1 & OFIFG ); // Test oscillator fault flag
31 // Configure SPI pins
32 P1SEL1 |= BIT5 ;
33 P2SEL1 |= BIT0 + BIT1 ;
34
35 UCA0CTLW0 |= UCSWRST ; // **Put state machine in reset**
36 UCA0CTLW0 |= UCSYNC + UCCKPL + UCMSB ; // 3-pin, 8-bit SPI slave
37 // Clock polarity high, MSB
38 UCA0CTLW0 |= UCSSEL_2 ; // ACLK
39 UCA0BR0 = 0x02 ; // /2
40 UCA0BR1 = 0 ; //
41 UCA0MCTLW = 0 ; // No modulation
42 UCA0CTLW0 &= ~ UCSWRST ; // **Initialize USCI state machine**
43 UCA0IE |= UCRXIE ; // Enable USCI_A0 RX interrupt
44
45 turnLedOff ( 6 );
46 turnLedOff ( 7 );
47 turnLedOff ( 8 );
48
49 // __bis_SR_register(LPM0_bits + GIE);
50 __bis_SR_register ( GIE );
51 while ( 1 )
52 {
53 turnLedOn ( 5 );
54 __delay_cycles ( 1000000 );
55 turnLedOff ( 5 );
56 __delay_cycles ( 1000000 );
57 if ( flag == 1 )
58 {
59 while ( ! ( UCA0IFG & UCTXIFG )); // USCI_A0 TX buffer ready?
60 UCA0TXBUF = 'A' ; // Echo received data
61 P3OUT ^= ( BIT7 );
62 }
63 }
64 // Enter LPM0, enable interrupts
65 }
66
67 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
68 #pragma vector=USCI_A0_VECTOR
69 __interrupt void USCI_A0_ISR ( void )
70 #elif defined(__GNUC__)
71 void __attribute__ (( interrupt ( USCI_A0_VECTOR ))) USCI_A0_ISR ( void )
72 #else
73 #error Compiler not supported!
74 #endif
75 {
76 if ( UCA0RXBUF == 'a' )
77 {
78 P3OUT ^= ( BIT6 );
79 flag = 1 ;
80 }
81 }
Ich kann Daten vom Masteraus senden. Der Slave reagiert wie programmiert
darauf und die LED s toggelen auch. Der Master empfängt jedoch nichts.
Die Abfrage in der main Funktion auf 'A' wird nie erfüllt. Im Debugger
erscheint der Receive Buffer des Masters mit einem Konstanten Wert von
0x66...
Kann mir jemand vielleicht einen kleinen Tipp geben?
lg M430
von
M430 (Gast)
17.08.2015 15:53
Der Master ist ein MSP430FG4618, der Slave ist ein MSP430FR5739
Hast Du bedacht, daß bei SPI das Senden und Empfangen starr gekoppelt
sind?
Der Master empfängt genau dann, wenn er auch sendet.
von
Nikolai.H. (Gast)
17.08.2015 16:15
Beim Master hast du das Interface nicht resettet, beim Slave aber schon:
UCA0CTLW0 |= UCSWRST; // **Put state machine in
reset**
Sollte beim Master in der Initialisierung auch rein.
von
16Bit (Gast)
17.08.2015 22:30
Schau dir das einmal an:
http://mykyta.info/msp430/group___m_o_d___s_p_i.html
Und wie Rufus schon schrieb:
Rufus Τ. F. schrieb:
> bei SPI das Senden und Empfangen
genau gleichzeitig statt finden, vollduplex.
von
M430 (Gast)
18.08.2015 10:09
Vielen Dank an alle, die sich die Zeit genommen haben. Leider gehts bei
mir immer noch nicht...
Ich habe was ihr geschrieben habt eingefügt. Sofort gesendet und mich
nach der Funktion uint8_t spi_transfer_byte(uint8_t data) gerichtet.
Ich bekomme leider noch immer nichts zurück. Manchmal klappt das Senden
auch nicht mehr. Man muss oft komplett alles resetten bis vlt was mal
funktioniert.
Ich habe den Code nochmal raufgeladen. Was mache ich noch immer falsch?
Master 1 #include <msp430.h>
2
3 unsigned char MST_Data , SLV_Data ;
4
5 char spi_transmit ( volatile char data );
6
7 int main ( void ) {
8 volatile unsigned int i ;
9
10 WDTCTL = WDTPW + WDTHOLD ; // Stop watchdog timer
11 FLL_CTL0 |= XCAP14PF ; // Configure load caps
12 P2DIR = 0xFF ;
13
14 // Wait for xtal to stabilize
15 do {
16 IFG1 &= ~ OFIFG ; // Clear OSCFault flag
17 for ( i = 0x47FF ; i > 0 ; i -- )
18 ; // Time for flag to set
19 } while (( IFG1 & OFIFG )); // OSCFault flag still set?
20
21 for ( i = 2100 ; i > 0 ; i -- )
22 ; // Now with stable ACLK, wait for
23 // DCO to stabilize.
24 P5OUT = 0x04 ; // P5 setup for LED and slave reset
25 P5DIR |= 0x06 ; //
26 P7SEL |= 0x0E ; // P7.3,2,1 option select
27 UCA0CTL0 |= UCMST + UCSYNC + UCCKPL + UCMSB ; //3-pin, 8-bit SPI master
28 UCA0CTL1 |= UCSWRST ; // **Put state machine in reset**
29 UCA0CTL1 |= UCSSEL_2 ; // SMCLK
30 UCA0BR0 = 0x02 ; // /2
31 UCA0BR1 = 0 ; //
32 UCA0MCTL = 0 ; // No modulation
33 UCA0CTL1 &= ~ UCSWRST ; // **Initialize USCI state machine**
34 IE2 |= UCA0RXIE ; // Enable USCI_A0 RX interrupt
35
36 P5OUT &= ~ 0x04 ; // Now with SPI signals initialized,
37 P5OUT |= 0x04 ; // reset slave
38 P5OUT &= ~ 0x02 ;
39 P2OUT = 0x00 ;
40
41 // __bis_SR_register(LPM0_bits + GIE);
42 // __bis_SR_register(GIE);
43 // CPU off, enable interrupts
44
45 while ( 1 )
46 {
47 if ( spi_transmit ( 'a' ) == 'b' )
48 {
49 P2OUT |= 0x02 ; // If correct, light LED
50 }
51 __delay_cycles ( 1000000 );
52 if ( spi_transmit ( 'c' ) == 'd' )
53 {
54 P2OUT &= ~ 0x02 ; // If correct, light LED
55 }
56 __delay_cycles ( 1000000 );
57 if ( spi_transmit ( 'e' ) == 'f' )
58 {
59 P2OUT |= 0x02 ; // If correct, light LED
60 }
61 P5OUT ^= 0x02 ;
62 __delay_cycles ( 1000000 );
63 }
64 }
65 char spi_transmit ( volatile char data )
66 {
67 UCA0TXBUF = data ;
68 while ( ! ( IFG2 & UCA0RXIFG ))
69 // wait for transfer to complete
70 ;
71 IFG2 &= ~ UCA0RXIFG ; // clear the rx flag
72 return ( UCA0RXBUF );
73 }
Slave 1 #include <msp430.h>
2
3 typedef enum {
4 NO_LED , LED1 , LED2 , LED3 , LED4 , LED5 , LED6 , LED7 , LED8
5 } ledEnum ;
6
7 void turnLedOn ( char ledNum );
8 void turnLedOff ( char ledNum );
9
10 volatile int flag = 0 ;
11 volatile char wert , test ;
12
13 int main ( void ) {
14 WDTCTL = WDTPW + WDTHOLD ; // Stop watchdog timer
15 P3DIR = 0xFF ;
16 // Configure XT1
17 PJSEL0 |= BIT4 + BIT5 ;
18
19 CSCTL0_H = 0xA5 ;
20 CSCTL1 |= DCOFSEL0 + DCOFSEL1 ; // Set max. DCO setting
21 CSCTL2 = SELA_0 + SELS_3 + SELM_3 ; // set ACLK = XT1; MCLK = DCO
22 CSCTL3 = DIVA_0 + DIVS_3 + DIVM_3 ; // set all dividers
23 CSCTL4 |= XT1DRIVE_0 ;
24 CSCTL4 &= ~ XT1OFF ;
25 do {
26 CSCTL5 &= ~ XT1OFFG ;
27 // Clear XT1 fault flag
28 SFRIFG1 &= ~ OFIFG ;
29 } while ( SFRIFG1 & OFIFG ); // Test oscillator fault flag
30 // Configure SPI pins
31 P1SEL1 |= BIT5 ;
32 P2SEL1 |= BIT0 + BIT1 ;
33
34 UCA0CTLW0 |= UCSWRST ; // **Put state machine in reset**
35 UCA0CTLW0 |= UCSYNC + UCCKPL + UCMSB ; // 3-pin, 8-bit SPI slave
36 // Clock polarity high, MSB
37 UCA0CTLW0 |= UCSSEL_2 ; // ACLK
38 UCA0BR0 = 0x02 ; // /2
39 UCA0BR1 = 0 ; //
40 UCA0MCTLW = 0 ; // No modulation
41 UCA0CTLW0 &= ~ UCSWRST ; // **Initialize USCI state machine**
42 UCA0IE |= UCRXIE ; // Enable USCI_A0 RX interrupt
43
44 turnLedOff ( 6 );
45 turnLedOff ( 7 );
46 turnLedOff ( 8 );
47
48 // __bis_SR_register(LPM0_bits + GIE);
49 __bis_SR_register ( GIE );
50 while ( 1 )
51 {
52 wert = test ;
53 turnLedOn ( 5 );
54 __delay_cycles ( 1000000 );
55 turnLedOff ( 5 );
56 __delay_cycles ( 1000000 );
57 if ( flag == 1 )
58 {
59 turnLedOn ( 6 );
60 while ( ! ( UCA0IFG & UCTXIFG )); // USCI_A0 TX buffer ready?
61 UCA0TXBUF = 'b' ;
62 }
63 else if ( flag == 2 )
64 {
65 turnLedOn ( 7 );
66 while ( ! ( UCA0IFG & UCTXIFG )); // USCI_A0 TX buffer ready?
67 UCA0TXBUF = 'd' ;
68 }
69 else if ( flag == 3 )
70 {
71 turnLedOn ( 8 );
72 while ( ! ( UCA0IFG & UCTXIFG )); // USCI_A0 TX buffer ready?
73 UCA0TXBUF = 'f' ;
74 }
75 }
76 }
77
78 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
79 #pragma vector=USCI_A0_VECTOR
80 __interrupt void USCI_A0_ISR ( void )
81 #elif defined(__GNUC__)
82 void __attribute__ (( interrupt ( USCI_A0_VECTOR ))) USCI_A0_ISR ( void )
83 #else
84 #error Compiler not supported!
85 #endif
86 {
87 if ( UCA0RXBUF == 'a' )
88 {
89 flag = 1 ;
90 }
91 else if ( UCA0RXBUF == 'c' )
92 {
93 flag = 2 ;
94 }
95 else if ( UCA0RXBUF == 'e' )
96 {
97 flag = 3 ;
98 }
99 }
M430 schrieb:
> Ich bekomme leider noch immer nichts zurück.
Du bekommst was zurück, nur nicht das, was Du erwartest.
Das, was Dein Master zurückbekommt, kann nicht das Resultat dessen sein,
was der Slave aufgrund der empfangenen Daten zurücksendet, denn der
Slave sendet --wie auch der Master-- genau dann, wenn er auch empfängt.
Das bedeutet, daß er das Empfangene erst dann auswerten kann, wenn der
Sendevorgang bereits abgeschlossen ist.
Obendrein darf Deine Interruptroutine das Empfangsregister nur genau
einmal auslesen, Du aber liest es bis zu dreimal aus.
Ändere das von1 if ( UCA0RXBUF == 'a' )
2 {
3 flag = 1 ;
4 }
5 else if ( UCA0RXBUF == 'c' )
6 {
7 flag = 2 ;
8 }
9 else if ( UCA0RXBUF == 'e' )
10 {
11 flag = 3 ;
12 }
zu
1 char c ;
2
3 c = UCA0RXBUF ;
4
5 if ( c == 'a' )
6 {
7 flag = 1 ;
8 }
9 else if ( c == 'c' )
10 {
11 flag = 2 ;
12 }
13 else if ( c == 'e' )
14 {
15 flag = 3 ;
16 }
oder
1 char c ;
2
3 c = UCA0RXBUF ;
4
5 switch ( c )
6 {
7 case 'a' :
8 flag = 1 ;
9 break ;
10
11 case 'c' :
12 flag = 2 ;
13 break ;
14
15 case 'e' :
16 flag = 3 ;
17 break ;
18 }
(Und was geschieht, wenn was anderes als a, c oder e empfangen wird?)
Aber das ist nicht das ganze Problem, nehmen wir für die folgende
Betrachtung mal an, Deine Interruptroutine würde das tun, was Du
beabsichtigst.
Was passiert?
1. Master sendet 'a' und empfängt X
2. Slave empfängt 'a' und setzt danach "flag" auf 1.
Da das Senderegister des Slaves zum Zeitpunkt des Empfangens nicht
initialisiert war, hat der Slave also irgendwas gesendet, und dieses
irgendwas ist X.
Der Master empfängt also ziemlich sicher kein 'b', und schaltet
deswegen seine LED nicht ein.
In der Hauptschleife des Slaves wird, weil "flag" auf 1 gesetzt wurde,
'b' in das Senderegister geschrieben.
3. Master sendet 'b' ... und empfängt 'b'
4. Der Slave empfängt 'b' und hat derweil 'b' gesendet, "flag" verändert
er nicht.
Also wird in der Hauptschleife des Slaves wieder ein 'b' in das
Senderegister geschrieben.
5. Master sendet 'c' ... und empfängt 'b'
6. Der Slave empfängt 'c' und hat derweil (wieder) 'b' gesendet; danach
setzt er "flag" auf 2.
In der Hauptschleife des Slaves wird daraufhin 'd' in das Senderegister
geschrieben.
7. Master sendet 'd' ... und empfängt 'd'
Der Slave empfängt 'd' und hat 'd' gesendet, "flag" ändert er nicht.
Wird's allählich klar?
SPI ist eine synchrone Kommunikation, jeder Sendevorgang liefert
zwangsweise auch empfangene Daten, die aber den Zustand vor dem Senden
wiedergeben.
von
M430 (Gast)
18.08.2015 11:38
Hallo rufus,
danke für Deinen ausführlichen Beitrag! :) ich habe dasselbe nochmal
hier beschrieben gefunden:
https://books.google.at/books?id=sVmQQsImi7AC&pg=PA150&lpg=PA150&dq=spi+schickt+was+zuerst+im+sendepuffer&source=bl&ots=hxRVL9t59i&sig=gwWtUxwTLOY9pSM9gl6FtkPe9Xw&hl=de&sa=X&ved=0CCMQ6AEwAGoVChMIoI2V-aiyxwIVyFwUCh36zQUS#v=onepage&q=spi%20schickt%20was%20zuerst%20im%20sendepuffer&f=false
Er erklärt das auch so, dass das was gesendet wird im Sendepuffer des
Slaves verbleibt bis es beim nächsten Byte vom Master auch tatsächlich
geschickt wird.
Jedoch verstehe ich noch immer etwas nicht. Ich habe meinen Code in der
ISR umgeschrieben und habe nun vom Master aus in der Endlosschleife nur
'a' schicken lassen, Mir ist jetzt klar, dass das erste Byte was ich
empfange irgendwas ist. Aber da ich es ja immer wieder aufrufe, müsste
es doch spätestens im zweiten Zyklus empfangen werden, oder?
Master (Veränderung):
1 while ( 1 )
2 {
3 if ( spi_transmit ( 'a' ) == 'b' )
4 {
5 P2OUT |= 0x02 ; // If correct, light LED
6 }
7
8 P5OUT ^= 0x02 ;
9 __delay_cycles ( 1000000 );
10 }
Slave (Veränderung):
1 while ( 1 )
2 {
3 wert = test ;
4 turnLedOn ( 5 );
5 __delay_cycles ( 1000000 );
6 turnLedOff ( 5 );
7 __delay_cycles ( 1000000 );
8 if ( flag == 1 )
9 {
10 // turnLedOn(6);
11 P3OUT ^= ( BIT5 );
12 // while (!(UCA0IFG & UCTXIFG)); // USCI_A0 TX buffer ready?
13 UCA0TXBUF = 'b' ;
14 }
15 else if ( flag == 2 )
16 {
17 turnLedOn ( 7 );
18 while ( ! ( UCA0IFG & UCTXIFG )); // USCI_A0 TX buffer ready?
19 UCA0TXBUF = 'd' ;
20 }
21 else if ( flag == 3 )
22 {
23 turnLedOn ( 8 );
24 while ( ! ( UCA0IFG & UCTXIFG )); // USCI_A0 TX buffer ready?
25 UCA0TXBUF = 'f' ;
26 }
27 }
28 }
29
30 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
31 #pragma vector=USCI_A0_VECTOR
32 __interrupt void USCI_A0_ISR ( void )
33 #elif defined(__GNUC__)
34 void __attribute__ (( interrupt ( USCI_A0_VECTOR ))) USCI_A0_ISR ( void )
35 #else
36 #error Compiler not supported!
37 #endif
38 {
39 receive = UCA0RXBUF ;
40 if ( receive == 'a' )
41 {
42 flag = 1 ;
43 }
44 if ( receive == 'c' )
45 {
46 flag = 2 ;
47 }
48 if ( receive == 'e' )
49 {
50 flag = 3 ;
51 }
52 }
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.