Hallo,
ich bin gerade dabei spi funktionen für einen ATxmega128 zu schreiben,
um ein display anzusteuern. Dabei orientiere ich mich an dem Code von
Atmel: http://www.atmel.com/dyn/resources/prod_documents/AVR1309.zip
Da ich nur Daten versenden will, habe ich entsprechend den Code
verkürzt. Im Anhang sieht man eine Aufzeichnung vom Logic Analyzer, wie
es aussehen sollte. Es sollten also die vier folgenden Schritte
stattfinden:
1. SS auf low
2. versende erstes byte
3. versende zweites byte
4. SS auf high
Ich bin quasi durch Zufall auf den "richtigen" Code gekommen. Der
folgende Code macht nur Schritt 1 und 2, ein Interrupt wird nicht
ausgelöst (die Initialisierung habe ich weggelassen):
1 | void transmit_data( volatile struct spi_handle *sh )
|
2 | {
|
3 | uint8_t data;
|
4 |
|
5 | // If more data
|
6 | if (sh->spi_stat.data_index < sh->spi_stat.data_size) {
|
7 | data = sh->spi_stat.data_pointer[sh->spi_stat.data_index];
|
8 | sh->spi_stat.data_index++; // Next byte
|
9 | sh->spi_reg->DATA = data;
|
10 | }
|
11 |
|
12 | // Transmission complete
|
13 | else {
|
14 | sh->spi_port->OUT |= SPI_SS_bm;
|
15 | sh->spi_stat.complete = 1;
|
16 | }
|
17 |
|
18 | }
|
19 |
|
20 | ISR(SPID_INT_vect)
|
21 | {
|
22 | transmit_data( spi_handle_portd );
|
23 | }
|
24 |
|
25 | void spi_send( volatile struct spi_handle *sh, uint8_t *data, uint8_t size )
|
26 | {
|
27 | while (sh->spi_stat.complete == 0); // wait until previous transmission finishes
|
28 |
|
29 | sh->spi_stat.data_pointer = data;
|
30 | sh->spi_stat.data_index = 0;
|
31 | sh->spi_stat.data_size = size;
|
32 |
|
33 | sh->spi_port->OUT &= ~SPI_SS_bm;
|
34 | transmit_data( sh );
|
35 | }
|
36 |
|
37 |
|
38 | int main( void )
|
39 | {
|
40 | uint8_t data[2] = {0xaa, 0xf1};
|
41 | spi_send( sh, data, 2 );
|
42 |
|
43 | return 0;
|
44 | }
|
Die nächste Version von transmit_data() war eigentlich die
ursprüngliche. Hier wird Schritt 1, 2 und 3 durchgeführt, allerdings
stimmen die Daten bei 3 nicht. Es wird einmal der Interrupt ausgelöst.
1 | void transmit_data( volatile struct spi_handle *sh )
|
2 | {
|
3 | // If more data
|
4 | if (sh->spi_stat.data_index < sh->spi_stat.data_size) {
|
5 | sh->spi_reg->DATA = sh->spi_stat.data_pointer[sh->spi_stat.data_index];
|
6 | sh->spi_stat.data_index++; // Next byte
|
7 | }
|
8 |
|
9 | // Transmission complete
|
10 | else {
|
11 | sh->spi_port->OUT |= SPI_SS_bm;
|
12 | sh->spi_stat.complete = 1;
|
13 | }
|
14 |
|
15 | }
|
Da ich bereits ein funktionierendes hd44780 display habe, wollte ich mal
den index ausgeben. Ich habe dann erstmal einen sprintf() Aufruf
gebraucht, um den entsprechenden String zu bekommen, doch da
funktionierte es auch schon. Die folgende Version macht alle 4 Schritte
korrekt und die ISR wird auch zweimal aufgerufen:
1 | void transmit_data( volatile struct spi_handle *sh )
|
2 | {
|
3 | char buffer[16];
|
4 | sprintf( buffer, "index: %d", sh->spi_stat.data_index );
|
5 |
|
6 | // If more data
|
7 | if (sh->spi_stat.data_index < sh->spi_stat.data_size) {
|
8 | sh->spi_reg->DATA = sh->spi_stat.data_pointer[sh->spi_stat.data_index];
|
9 | sh->spi_stat.data_index++; // Next byte
|
10 | }
|
11 |
|
12 | // Transmission complete
|
13 | else {
|
14 | sh->spi_port->OUT |= SPI_SS_bm;
|
15 | sh->spi_stat.complete = 1;
|
16 | }
|
17 |
|
18 | }
|
Ich glaube, dass ich irgendetwas noch nicht beachte. So will ich die
Daten nicht übertragen, wer weiß was sonst noch passiert. Ich verwende
avr-gcc. Kann mir bitte jemand sagen, warum hier so ein Chaos
stattfindet?