Hallo zusammen,
ich baue gerade an einer SPI-Kommunikation zwischen einem Atmega162
(master) und einem PIC18F46 (slave)
Die Verleiterbahnung erlaubt keine SS-Synchronisation. Stattdessen
werden vom Slave die empfangenen Bits gezählt und immer 8 Bits zu einem
Byte zusammengesetzt.
Da es sich um eine Daisy chain handeln kann, wird ein Latch-Clock-Signal
(RCK, StorageClock) an INT0 verwendet, um im Slave
Schieberegisterverhalten zu erzeugen.
Mein Testszenario sieht vor, dass der Master einen uint8_t von 0...255
inkrementiert und die Werte über die Leitung schickt.
Allerdings empfängt der Slave die Bytes um ein Bit verschoben: das LSB
wird MSB des nächsten/vorigen Bytes. Möglicherweise so:
MASTER
00000000,00000001,00000010,00000011,00000100,00000101...
SLAVE
?0000000,00000000,10000001,00000001,10000010,00000010,1...
Höchstwarscheinlich sieht es so aus. Ansehen kann ich die Bytes nur
ungefähr (Bargraph). Aber ich weiß, dass das MSB im Slave schnell
flippt. Alle anderen Bits zählen normal, aber etwas langsam. Daher meine
Interpretation.
SCK-Frequenz sind 4MHz, Leitungslänge ca. 15cm (ungeschirmt, in der Luft
hängend). Das Verhalten ist deterministisch (=immer so!).
Hier mal der Code. Die Idee: Der Reset des Slaves hängt zur
Synchronisation einem out-pin des Masters. Durch Resetten des Slaves
kann der Master anzeigen, wo die Übertragung beginnt.
Master:
1 | void StorageClkOut()
|
2 | {
|
3 | loop_until_bit_is_set(SPSR, SPIF);
|
4 | SPIPORT |= (1<<RCK);
|
5 | SPIPORT &= ~(1<<RCK);
|
6 | }
|
7 | void SlaveResetEdge()
|
8 | {
|
9 | SPIPORT &= ~(1<<SLAVE_RESET); // 0
|
10 | wait10msec(50); // 500msec
|
11 | SPIPORT |= (1<<SLAVE_RESET); // 1
|
12 | wait10msec(50); // 500msec
|
13 | }
|
14 | void static inline init_timing()
|
15 | {
|
16 | // ClockPrescaler auf 1 schalten --> ca. 8 MHz (interner Takt)
|
17 | CLKPR = (1<<CLKPCE); // PreScaler vorwarnen, dass er gleich benutzt wird
|
18 | CLKPR = (0<<CLKPS3)|(0<<CLKPS2)|(0<<CLKPS1)|(0<<CLKPS0); // PreScaler auf 1x schalten und CLKPCE auf 0 setzen
|
19 | wait10msec(1);
|
20 | }
|
21 | void static inline init_SPI()
|
22 | {
|
23 | // DDRB - die SPI Pins als Ausgänge konfigurieren (auch das unbenutzte SS)
|
24 | SPIDDR |= (1 << OUT) | (1 << SCK) | (1 << RCK) | (1 << PL);
|
25 | // SPI-Modul konfigurieren (Master & Enable & positive idle & sample@positive edge)
|
26 | SPCR |= (1 << MSTR)| (1 << SPE) | (1 << CPOL) | (1 << CPHA);
|
27 | // Double Speed aktivieren, maximale Geschwindigkeit, Datenblatt S. 163 unten
|
28 | SPSR |= (1<<SPI2X);
|
29 | // Dummy Daten
|
30 | SPDR = 0;
|
31 | loop_until_bit_is_set(SPSR, SPIF); // Auf Übertragung warten
|
32 | }
|
33 | void static inline initAll()
|
34 | {
|
35 | init_timing();
|
36 | init_SPI();
|
37 |
|
38 | DDRB |= 1<<SLAVE_RESET;
|
39 | }
|
40 | int main()
|
41 | {
|
42 | // Initialisierung
|
43 | initAll();
|
44 | SlaveResetEdge();
|
45 |
|
46 |
|
47 | uint8_t counter=0;
|
48 | while(1)
|
49 | {
|
50 | SPDR = counter++; // rechtes Digit auf den Bus legen, dazu DP
|
51 | StorageClkOut();
|
52 |
|
53 | wait10msec(1);
|
54 |
|
55 | }
|
56 | }
|
Slave:
1 | volatile u8 inputBuffer;
|
2 |
|
3 | void interrupt high_priority ISR_highPriority()
|
4 | {
|
5 |
|
6 | // external interrupt (i.e. Latch Clock)
|
7 | if(INTCONbits.INT0F == 1)
|
8 | {
|
9 | INTCONbits.INT0F = 0;
|
10 | // copy current Data
|
11 | inputBuffer = SSP1BUF;
|
12 | }
|
13 | }
|
14 |
|
15 | inline void MainInit(void) {
|
16 | // 16MHz
|
17 | OSCCONbits.IRCF2 = 1;
|
18 | OSCCONbits.IRCF1 = 1;
|
19 | OSCCONbits.IRCF0 = 1;
|
20 | // PLL x4 = 64 MHz
|
21 | OSCTUNEbits.PLLEN = 1;
|
22 |
|
23 |
|
24 | // global interrupts
|
25 | INTCONbits.PEIE = 1;
|
26 | INTCONbits.GIE = 1;
|
27 | }
|
28 | inline void InitMSSP1(void)
|
29 | {
|
30 | // MSSP1 configured as SPI Slave
|
31 | SSP1STATbits.SMP1 = 0; // clear bit for slave operation
|
32 | SSP1STATbits.CKE1 = 1; // set output before positive edge (idle->active)
|
33 | SSP1CON1bits.CKP1 = 0; // transmission on positive edge (active=positive)
|
34 | SSP1CON1bits.SSPM = 0b0101; // SPI Slave Mode, SS1 disabled (software input)
|
35 | SSP1CON1bits.WCOL1 = 0; // clear indicator bit
|
36 | SSP1CON1bits.SSPOV1 = 0; // clear indicator bit
|
37 |
|
38 | SSP1CON3bits.BOEN = 0; // disable buffer overflow
|
39 | // since some data may just be running through the daisy chain
|
40 |
|
41 | // MSSP1 data directions
|
42 | TRISCbits.RC3 = 1; // CLK
|
43 | ANSELCbits.ANSC3 = 0; // digital
|
44 | TRISCbits.RC4 = 1; // DATA IN
|
45 | ANSELCbits.ANSC4 = 0; // digital
|
46 | TRISCbits.RC5 = 0; // DATA OUT
|
47 | ANSELCbits.ANSC5 = 0; // digital
|
48 |
|
49 | // wait for clock line to be idle
|
50 | while(PORTCbits.RC3==0)
|
51 | ;
|
52 | SSP1CON1bits.SSPEN1 = 1; // enable serial port
|
53 | }
|
54 | int main(void/*int argc, char** argv*/)
|
55 | {
|
56 | // init timing
|
57 | MainInit();
|
58 |
|
59 | // start MSSP1 in SPI slave mode
|
60 | InitMSSP1();
|
61 |
|
62 | // activate INT0 (positive edge triggered)
|
63 | TRISBbits.RB0 = 1; // INT0 input
|
64 | ANSELBbits.ANSB0 = 0; // digital
|
65 | INTCON2bits.INTEDG0 = 1; // edge
|
66 | INTCONbits.INT0E = 1; // enable
|
67 |
|
68 | // continuous operation: gather new data while mux and sensing continues to run
|
69 | while(1)
|
70 | Bargraph(inputBuffer);
|
71 | }
|
seht ihr irgendwas? Habe ich die Konfiguration der SPI-Peripherie
verbockt?
also: init_SPI(void) vs. InitMSSP1(void)