Forum: Compiler & IDEs MAX7221 mit ATMega32 über SPI


von Marius (Gast)


Lesenswert?

Guten Abend zusammen,

ich habe mir einen LED-Cube (4x4x4) zusammengelötet, der per MAX7221 
angesteuert wird. Als µC habe ich einen ATMega32 auf einem 
AVR-Evaluationsboard von Pollin. Programmiert wird über ein USB-AVR-Lab 
von Ullihome mit STK500 Firmware.

Ich hbe den Cube schon mittels Bascom angesteuert und es hat auch alles 
so funktioniert, wie es sollte, also ist die elektronische Schaltung 
richtig.

Nun möchte ich gerne auf C umsteigen, aber es klappt nicht. Manchmal 
leuten alle LEDs und manchmal keine. Ich hab "erweiterte 
Grundkenntnisse" in C, hab aber noch nie einen AVR-Programmiert. Bisher 
immer nur mit Bascom.

Der MAX7221 wartet auf insgesamt 16 bit. Das erste Bit ist das MSB. Nach 
der Initialisierung steht das erste Byte für das Digit und das zweite 
Byte für die 8 Segmente. Damit sollte mit diesem Code bei Digit 1 die 
erste LED leuchten (SPI_write(0x01,0x01)). Tut sie aber nicht.

Code:
1
#include <avr\io.h>
2
3
4
void SPI_write(unsigned char, unsigned char);
5
void max7221_init(void);
6
7
void main(){
8
    DDRB = (1<<PB4)|(1<<PB5)|(1<<PB6); // MOSI,SCK, SS als Output, Rest als Input
9
  SPCR = (1<<SPE)|(1<<MSTR);         // SPI enable, Master Mode
10
  PORTB |= (1<<PB4);
11
  max7221_init();
12
  SPI_write(0x01,0x01);
13
  while(1){                          //mainloop    
14
  }
15
}
16
17
18
void SPI_write(unsigned char addr,unsigned char data)
19
{
20
    PORTB &= ~(1<<PB4);           // Set CS pin to 0
21
  SPDR = addr;                  // Start Address transmission
22
  while(!(SPSR & (1<<SPIF)));   // Wait for transmission complete
23
  SPDR = data;                  // Start Data transmission 
24
  while(!(SPSR & (1<<SPIF)));   // Wait for transmission complete
25
  PORTB |= (1<<PB4);         // Set tze CS pin to 1
26
}
27
28
void max7221_init(){
29
  SPI_write(0x0C,0x01); //normal operation
30
  SPI_write(0x09,0x00); //no decode
31
  SPI_write(0x0A,0x02); //set intensity
32
  SPI_write(0x0B,0x07); //display all digits
33
  SPI_write(0x0C,0x01); //normal operation
34
  SPI_write(0x0F,0x00); //Displaytest aus
35
  SPI_write(0x01,0x00); //clear Digit 1
36
  SPI_write(0x02,0x00); //clear Digit 2
37
  SPI_write(0x03,0x00); //clear Digit 3
38
  SPI_write(0x04,0x00); //clear Digit 4
39
  SPI_write(0x05,0x00); //clear Digit 5
40
  SPI_write(0x06,0x00); //clear Digit 6
41
  SPI_write(0x07,0x00); //clear Digit 7
42
  SPI_write(0x08,0x00); //clear Digit 8
43
}

Noch ne kurze ergänzende Frage:
SPI nutzt ja die gleichen Pins wie die ISP. Macht es dann etwas aus, 
wenn der Programmer noch am Board hängt?

Ich hoffe ihr könnt mir Helfen!

Viele Grüße
Marius

von Marius F. (marius_f)


Lesenswert?

Ich bins nochmal:

Ich hab noch etwas rumgesucht und bin über Google auf folgende Seite 
gestoßen:
http://www.hackchina.com/en/r/19672/Max7221.h__html
Dabei wird nich das Hardware-SPI verwendet, sondern das ganze "per Hand" 
gemacht. Daraufhin hab ich den Code folgendermaßen umgestrickt, und nun 
Läuft es:
1
#include <avr\io.h>
2
3
#define _nop_() asm volatile("nop")
4
5
typedef unsigned char byte;
6
7
struct test {
8
  byte b0:1;
9
  byte b1:1;
10
  byte b2:1;
11
  byte b3:1;
12
  byte b4:1;
13
  byte b5:1;
14
  byte b6:1;
15
  byte b7:1;
16
} __attribute__((__packed__));
17
18
#define BIT(r,n) (((volatile struct test *)&r)->b##n)
19
20
#define Max7221DIN     BIT(PORTD,5)
21
22
23
void SPI_write(unsigned char, unsigned char);
24
void max7221_init(void);
25
26
void main(){
27
    //DDRB |= (1<<PB4)|(1<<PB5)|(1<<PB6); // MOSI,SCK, SS als Output, Rest als Input
28
  //SPCR |= (1<<SPE)|(1<<MSTR)|(1<<SPR1);         // SPI enable, Master Mode
29
  //SPSR |= (1<<SPI2X);
30
  //PORTB |= (1<<PB4);
31
  DDRD = (1<<PD4)|(1<<PD5)|(1<<PD6); //Als Ausgänge setzen
32
  PORTD |= (1<<PD4); //CS auf 1
33
  PORTD |= (1<<PD6); //Clock auf 1
34
35
  max7221_init();
36
  SPI_write(0x01,0x0F);
37
  //SPI_write(0x02,0x05);
38
  while(1){                          //mainloop    
39
  }
40
}
41
42
43
void SPI_write(unsigned char Address,unsigned char Data) 
44
{ 
45
  unsigned char i; 
46
  PORTD &= ~(1<<PD4); 
47
  for (i=0;i<8;i++) 
48
  { 
49
    PORTD &= ~(1<<PD6); //Clock auf 0
50
    Max7221DIN = (Address&(0x80>>i)) ? 1:0; 
51
    _nop_(); 
52
    _nop_(); 
53
    PORTD |= (1<<PD6);  //Clock auf 1
54
    _nop_(); 
55
    _nop_(); 
56
  } 
57
  for (i=0;i<8;i++) 
58
  { 
59
    PORTD &= ~(1<<PD6);  //Clock auf 0
60
    Max7221DIN = (Data&(0x80>>i)) ? 1:0; 
61
    _nop_(); 
62
    _nop_(); 
63
    PORTD |= (1<<PD6);  //Clock auf 1
64
    _nop_(); 
65
    _nop_(); 
66
  } 
67
  PORTD |= (1<<PD4);
68
} 
69
 
70
71
72
/*
73
void SPI_write(unsigned char addr,unsigned char data)
74
{
75
    PORTB &= ~(1<<PB4);           // Set CS pin to 0
76
  SPDR = addr;                  // Start Address transmission
77
  while(!(SPSR & (1<<SPIF)));   // Wait for transmission complete
78
  SPDR = data;                  // Start Data transmission 
79
  while(!(SPSR & (1<<SPIF)));   // Wait for transmission complete
80
  PORTB |= (1<<PB4);         // Set tze CS pin to 1
81
}
82
*/
83
84
void max7221_init(){
85
  SPI_write(0x0C,0x01); //normal operation
86
  SPI_write(0x09,0x00); //no decode
87
  SPI_write(0x0A,0x02); //set intensity
88
  SPI_write(0x0B,0x07); //display all digits
89
  SPI_write(0x0C,0x01); //normal operation
90
  SPI_write(0x0F,0x00); //Displaytest aus
91
  SPI_write(0x01,0x00); //clear Digit 1
92
  SPI_write(0x02,0x00); //clear Digit 2
93
  SPI_write(0x03,0x00); //clear Digit 3
94
  SPI_write(0x04,0x00); //clear Digit 4
95
  SPI_write(0x05,0x00); //clear Digit 5
96
  SPI_write(0x06,0x00); //clear Digit 6
97
  SPI_write(0x07,0x00); //clear Digit 7
98
  SPI_write(0x08,0x00); //clear Digit 8
99
}

Warum funktioniert das ganze dann nicht mit dem Hardware-SPI?
Ich hab nur Clock, MOSI und CS auf andere Pins gelegt, ansonsten ist die 
Hardware identisch.
Hat jemand ne Idee?

Viele Grüße
Marius

von Peter D. (peda)


Lesenswert?

Marius F. schrieb:
> Warum funktioniert das ganze dann nicht mit dem Hardware-SPI?

Ein möglicher Fehler:
Der /SS-Pin muß vor SPI-Init auf Ausgang gesetzt werden.


Peter

von Marius F. (marius_f)


Lesenswert?

Hallo Peter,

das hab ich doch getan.
Zuerst DDRB konfiguriert und dann SPI eingeschaltet
1
DDRB = (1<<PB4)|(1<<PB5)|(1<<PB6); // MOSI,SCK, SS als Output, Rest als Input
2
SPCR = (1<<SPE)|(1<<MSTR);         // SPI enable, Master Mode
3
PORTB |= (1<<PB4);

Oder meinst du was anderes?

Gruß
Marius

von Peter D. (peda)


Lesenswert?

Marius F. schrieb:
> das hab ich doch getan.

Dann wird wohl was anderes falsch sein.
Probier mal alle 4 Modies aus.

Ich benutze meistens auch nur das Bitschubser-SPI in SW.


Peter

von holger (Gast)


Lesenswert?

>Ich benutze meistens auch nur das Bitschubser-SPI in SW.

Mein Gott wie armselig. Kriegst du das SPI Modul nicht zum laufen?
Ich geb dir gerne Nachhilfestunden;)

von Peter D. (peda)


Lesenswert?

holger schrieb:
> Ich geb dir gerne Nachhilfestunden;)

Nicht nötig.
Ich hab an einem ATmega2560 am SPI ADCs und DACs am Laufen und an einer 
UART im SPI-Modus einige IO-Expander (74HC165/74HC595).

Welcher Modus für den MAX7219 paßt, müßte ich aber erst im Datenblatt 
nachsehen.

Ich benutze auch oft ATtinys und da bevorzuge ich SW-SPI.


Peter

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
Noch kein Account? Hier anmelden.