Forum: Mikrocontroller und Digitale Elektronik SPI allgemein, MAX7221


von Tester (Gast)


Lesenswert?

Hallo,

Ich beschäftige mich gerade das erste mal mit SPI.
Ich benutze Codevision einen Mega8515 und einen MAX7221 7-Seg-Treiber.
(http://www.datasheetcatalog.com/datasheets_pdf/M/A/X/7/MAX7221.shtml)

Mein einziger Erfolg bisher war, alle Segmente zum Leuchten zu brigen.
Erstens bin ich mir nämlich nicht sicher was ich bei Clock Phase und 
Clock Polarity einstellen muss, also welchen SPI-Mode.
Des weiteren ist mir noch nicht ganz klar, wie ich die 2 x 8 Bit senden 
soll.
Einfach SPI(0xff) und in der nächsten Zeile die zweite 8 bit funkt 
nicht.
Hätte mich eh gewundert.
noch was: Aus dem Datenblatt: "LOAD/CS must go high concurrently with or 
after the
16th rising clock edge, but before the next rising clock
edge or data will be lost." Wie weiß ich wann die 16te Flanke kommt. Mit 
dem Interrupt?

Wäre für ein kurzes Beispiel mit der Codevision-Funktion sehr dankbar!

von Stephan H. (stephan-)


Lesenswert?

Hallo Tester,
der SPI wird ähnlich wie die UART beschreiben.
Byte in den Puffer und raus geht es. Wenn fertig dann Int und nächstes 
rein.
Kann ich leider nicht genau sagen. Ich habe das bei meinen MAX 7221
zu fuss gemacht, da sie an einem 2051 dran sind. Der hat kein HW SPI.
zu Fuß muß man drauf achten wann die Load/CS Leitung hoch geht.
Eben frühestens mit dem Letzten Bit. Spätestens danach.
Mit der Phase/Polarity hatte ich zu fuß auch nichts zu tun.
Mache ich ja alles selber.
CLR CS, Bit anlegen, Takt, alles 16 Mal oder 32 oder 64 und SETB CS.

ich hoffe das hilft dir.

Gruß

von Stefan (Gast)


Lesenswert?

Hier meine Routinen die für einen 7219 waren, müsste also auch auf den 
7221 übertragbar sein:
1
void segWrite (unsigned char data_out){
2
3
  unsigned char loop, mask;
4
5
  for (loop=0,mask=0x80;loop<8;loop++, mask=mask>>1)
6
7
  {
8
9
    PORT_SCK_7219 &= ~(1<<PIN_SCK_7219);
10
11
    if (data_out & mask)
12
13
      PORT_MOSI_7219 |= (1<<PIN_MOSI_7219);
14
15
    else
16
17
      PORT_MOSI_7219 &= ~(1<<PIN_MOSI_7219);
18
19
    PORT_SCK_7219 |= (1<<PIN_SCK_7219);
20
21
  }
22
23
  PORT_SCK_7219 &= ~(1<<PIN_SCK_7219);
24
25
}
26
27
28
29
void segAusgabe (unsigned char address, unsigned char data) {
30
31
  PORT_CS_7219 |= (1<<PIN_CS_7219);    // Chip Select
32
33
  segWrite(address);
34
35
  segWrite(data);
36
37
  PORT_CS_7219 &= ~(1<<PIN_CS_7219);   // Chip Unselect
38
39
}
40
41
42
43
void segInit (void) {
44
45
  unsigned char loop;
46
47
48
49
  DDR_SCK_7219 |= (1<<PIN_SCK_7219);
50
51
  DDR_MOSI_7219 |= (1<<PIN_MOSI_7219);
52
53
  DDR_CS_7219 |= (1<<PIN_CS_7219);
54
55
56
57
  for (loop = 0; loop < 4; loop++) {  // 4 mal um Fehler zu eliminieren
58
59
    segAusgabe(0x0c, 0x01);  // Shutdown aus
60
61
    segAusgabe(0x09, 0xff);  // Decode-Mode: alles auf Code B
62
63
    segAusgabe(0x0a, 0x08);  // Intensität
64
65
    segAusgabe(0x0b, 0x05);  // 6 digits
66
67
  }
68
69
70
71
  for (loop = 1; loop <= 6; loop++)
72
73
    segAusgabe(loop, 0x0A);   // "-" auf allen Anzeigen anzeigen
74
75
}

von Georg (Gast)


Lesenswert?

Viel spaß damit
1
/*****************
2
Konstante Register
3
******************/
4
//Hier werden KontrollRegister definiert
5
6
#define REG_DECODE 0x09
7
#define REG_INTENSITY 0x0a
8
#define REG_SCAN_LIMIT 0x0b
9
#define REG_SHUTDOWN 0x0c
10
#define REG_DISPLAY_TEST 0x0f
11
12
/*******************
13
Konstanten Allgemein
14
********************/
15
//6 Routinen, um die Ausgangspins high oder low zu setzen 
16
17
#define DIN_PORT P4
18
#define DIN_DDR P4
19
#define DIN_BIT 0x04   //liegt auf Pin10 der Pfosten-Stiftleiste
20
#define DIN_0()        (DIN_PORT &= ~DIN_BIT)   //Pin 4.2 auf low
21
#define DIN_1()        (DIN_PORT |= DIN_BIT)    //Pin 4.2 auf high                      
22
23
#define CLK_PORT P4
24
#define CLK_DDR P4
25
#define CLK_BIT 0x01   //liegt auf Pin4 der Pfosten-Stiftleiste 
26
#define CLK_0()        (CLK_PORT &= ~CLK_BIT)    //Pin 4.0 auf low
27
#define CLK_1()        (CLK_PORT |= CLK_BIT)     //Pin 4.0 auf high
28
29
#define LOAD_PORT P4
30
#define LOAD_DDR P4
31
#define LOAD_BIT 0x10  //liegt auf Pin7 der Pfosten-Stiftleiste
32
#define LOAD_0()        (LOAD_PORT &= ~LOAD_BIT) //Pin 4.4 auf low
33
#define LOAD_1()        (LOAD_PORT |= LOAD_BIT)  //Pin 4.4 auf high
34
35
#define INTENSITY_MAX 0x0f      //Konstante fuer maximale Leuchtstaerke 
36
37
38
/*************
39
Unterprogramme
40
**************/
41
42
void MAX7219_Init (void);
43
void MAX7219_ShutdownStart (void);
44
void MAX7219_ShutdownStop (void);
45
void MAX7219_DisplayTestStart (void);
46
void MAX7219_DisplayTestStop (void);
47
void MAX7219_SetBrightness (char brightness);
48
void MAX7219_Clear (void);
49
void ziffern (void);
50
51
void MAX7219_Write (unsigned char reg_number, unsigned char dataout);
52
53
unsigned char z; //wird fuer den NO-OP Befehl des MAX7219 benoetigt
54
55
56
57
58
59
60
void MAX7219_Init (void)
61
   {
62
   // DIN, CLK & LOAD als Ausgang definieren
63
   DIN_DDR |= DIN_BIT; 
64
   CLK_DDR |= CLK_BIT;
65
   LOAD_DDR |= LOAD_BIT;
66
67
   MAX7219_Write(REG_DECODE, 0xFF);        //Decode Mode B einschalten fr alle Digits
68
   MAX7219_SetBrightness(INTENSITY_MAX);   //Helligkeit der Segmente definieren
69
   MAX7219_Write(REG_SCAN_LIMIT, 0x04);    //5-Digits aktivieren
70
   MAX7219_ShutdownStop();                 //normaler Betrieb - kein Shutdown Mode
71
   MAX7219_DisplayTestStart();             //Test Betrieb - alle Digits leuchten!
72
   }
73
74
void MAX7219_ShutdownStart (void)
75
76
/* Schaltet das Display ab - Shutdown Mode */
77
   {
78
   MAX7219_Write (REG_SHUTDOWN, 0);
79
   }
80
81
void MAX7219_ShutdownStop (void)
82
83
/* Bringt das Display aus dem Shutdown Mode */
84
   {
85
   MAX7219_Write (REG_SHUTDOWN, 1);
86
   }
87
88
void MAX7219_DisplayTestStart (void)
89
90
/* Schaltet alle Segmente ein - Test Mode*/
91
   {
92
   MAX7219_Write (REG_DISPLAY_TEST, 1);
93
   }
94
95
void MAX7219_DisplayTestStop (void)
96
97
/* Bringt das Display aus dem Test Mode */
98
   {
99
   MAX7219_Write (REG_DISPLAY_TEST, 0);
100
   }
101
102
void MAX7219_SetBrightness (char brightness)
103
104
/* Setzt die Helligkeit des Displays*/
105
   {
106
   brightness &= 0x0f;
107
   MAX7219_Write (REG_INTENSITY, brightness);
108
   }
109
110
void MAX7219_Clear (void)
111
112
/* Loescht das Display*/
113
   {
114
   char k;
115
   for (k=1; k<=5; k++)
116
      {
117
      MAX7219_Write (k, 0x00);
118
      }
119
   }
120
121
void MAX7219_Write (unsigned char reg_number, unsigned char dataout)
122
123
/* Hier werden die Daten in die Register der Displays geschrieben - MSB (15) zuerst*/
124
   {
125
   char i,g;
126
   LOAD_0();
127
128
   // Datenbits D15-D12 werden beliebig (z.b.: '0') uebertragen:
129
   for (i=0;i<4;i++)
130
      {
131
      DIN_0();
132
      CLK_1();
133
      CLK_0();
134
      }
135
   // Datenbits D11-D8 (Registeradresse) werden uebertragen:
136
   for (i=4;i>0;i--)
137
      {
138
      unsigned char mask = 1 << (i-1);
139
      if (reg_number & mask)
140
         {
141
         DIN_1();
142
         }
143
      else
144
         {
145
         DIN_0();
146
         }
147
      CLK_1();
148
      CLK_0();
149
      }
150
   // Datenbits D7-D0 (Daten) werden uebertragen:
151
   for (i=8; i>0; i--)
152
      {
153
      unsigned char mask = 1 << (i-1);
154
      if (dataout & mask)
155
         {
156
         DIN_1();
157
         }
158
      else
159
         {
160
         DIN_0();
161
         }
162
      CLK_1();
163
      CLK_0();
164
      }
165
   // No-op Register beschreiben
166
   if (z>>0)
167
      {
168
      for (g=0;g<z;g++)
169
         {
170
         for (i=0;i<4;i++ //beliebig (z.b.: '0') uebertragen
171
             )
172
            {
173
            DIN_0();
174
            CLK_1();
175
            CLK_0();
176
            }
177
         for (i=4;i>0;i--  //In NO-OP Register 0x00 schreiben
178
             )
179
            {
180
            DIN_0();
181
182
            CLK_1();
183
            CLK_0();
184
            }
185
         for (i=8;i>0;i-- //beliebig (z.b.: '0') uebertragen
186
             )
187
            {
188
            DIN_0();
189
            CLK_1();
190
            CLK_0();
191
            }
192
         }
193
      }
194
   LOAD_1();
195
   }
196
197
void ziffern (void)
198
   {
199
   if (v==1)
200
      {
201
      /*Hier findet die Auswertung der Timerwerte die im Feld t1
202
        gespeichert wurden statt. Jede Ziffer muss aus der Zahl
203
        mithilfe von Rechenoperationen ermittelt werden*/
204
 
205
      unsigned int aa, xx, b1,d1,f1,g1; 
206
      unsigned long f,ziffer;
207
      unsigned char fehl;
208
      
209
      fehl = 0; //Fehler Zehlvariable 0 setzen
210
      for (aa=1;aa<=9;aa++)
211
         {
212
         if (t1[aa] == 0)
213
            {
214
            fehl++;
215
            }
216
         }
217
      if (fehl == 0 //es sind alle beschrieben
218
         )
219
         {
220
         for (aa=1;aa<10;aa++)
221
            {
222
            z=aa-1;              
223
            xx=5;
224
225
            f=t1[aa];
226
            ziffer= f/10000;     
227
            MAX7219_Write (xx,(unsigned char)ziffer);
228
229
            b1=f%10000;      
230
            ziffer = b1/1000;                  
231
            xx--;                    
232
            MAX7219_Write (xx,(unsigned char)ziffer);
233
234
            d1=b1%1000;      
235
            ziffer=d1/100;            
236
            xx--;                          
237
            MAX7219_Write (xx,(unsigned char)ziffer);
238
239
            f1=d1%100;                     
240
            ziffer=f1/10;                
241
            xx--;                          
242
            MAX7219_Write (xx,(unsigned char)ziffer);
243
244
            g1=f1%10;                    
245
            ziffer=g1;
246
            xx--;                           
247
            MAX7219_Write (xx,(unsigned char)ziffer);
248
            MAX7219_SetBrightness(INTENSITY_MAX);
249
            }

  

von Michael (Gast)


Lesenswert?

hallo.

zur SPI:
CPOL gibt an, ob die erste flanke ("leading edge") steigend oder fallend 
ist.
anders gesagt: CPOL legt den "ruhepegel" des CLK-signals fest. in deinem 
fall ist er LOW.

CPHA gibt an, mit welcher flanke die daten übernommen werden. in deinem 
fall mit der "leading edge", die hier die steigende ist (siehe "Figure 
1. Timing Diagram", seite 6 im datenblatt).

stelle also beide werde auf 0.

der rest läuft dann so:
- SPI konfigurieren (interrupt aktivieren nicht vergessen!)
- erstes datenbyte ins senderegister schreiben
- 1. SPI-Interrupt: evtl. empfangene daten ablegen, dann zweites 
datenbyte schreiben
- 2. SPI-Interrupt: evtl. empfangene daten ablegen, übertragung beendet 
-> chip select wegnehmen

der satz "LOAD/CS must go high concurrently with or after the 16th 
rising clock edge, but before the next rising clock edge or data will be 
lost."
heißt ganz einfach, daß in die LOW-phase des signals "LOAD/CS" maximal 
16 steigende flanken des clock-signals fallen dürfen, sonst werden die 
daten verworfen.

gruß

michael

von Tester (Gast)


Lesenswert?

Guten Morgen ihr Nachtschwärmer!

Danke erstmal. CPOL und CPHA auf 0. Auf das bin ich nach lagem Studium 
des Datenblatts auch gekommen. Aber danke für die Bestätigung.
Die Routinen werd heut Nachmittag probieren. Ich geb dann bescheid...

thks

von Tester (Gast)


Lesenswert?

Hallo,

Ich bringe dieses SCH**** Ding nicht zum laufen. Habe eure Routinen 
probiert.
Funktionieren ebenso wenig wie meine. Es leuchten immer alle Segmente. 
Jeman d einen Idee? Der µC steckt aufm STK500, MAX7221 auf einem 
Steckbrett. Leider bin ich kein Besitzer eines Oszis. Ich würd mir diese 
stinkenden Bits gern mal ansehen...

von Peter D. (peda)


Lesenswert?

Tester wrote:
> Ich bringe dieses SCH**** Ding nicht zum laufen. Habe eure Routinen
> probiert.


Ich hätte auch noch eine, läuft wie dumm:

Beitrag "DCF77 Uhr in C mit ATtiny26"

Ist sogar für Anzeigen mit gemeinsamer Anode.


Aber solange Du nichts von Dir zeigst, kann auch keiner Deinen Fehler 
sehen.


Peter

von Tester (Gast)


Angehängte Dateien:

Lesenswert?

OK, anhängender code müsste meiner Meinung nach einfach nur mal eine 
Zahl am 7-Seg ausgeben. Aber bei leuchten alle Segmente. auch mit 
Stefans code.
Also dachte ich an ein Hardware-Problem. Komm aber nicht drauf.

Danke für alle Denkanstöße... (oder Lösungen ;-)

von Tester (Gast)


Lesenswert?

Wahnsinn, das geht ja schnell hier!

könnte trotzdem bitte mal jemand einen Blick auf den Code werfen?
Oder ists wirklich ein Hardware-Problem?
Danke

von Peter D. (peda)


Lesenswert?

Wo ist die Funktion spi() definiert ?

Wo wird der Interrupt enabled und warum erst die Umstände mit dem 
Interrupt ?

Läuft das Programm überhaupt durch ?


Statt tonnenweise Copy&Paste, mach lieber ne Unterfunktion, dann muß man 
sich nicht den gleichen Schnulli wieder und wieder durchlesen.

D.h. der Code wird wesentlich übersichtlicher und fehlerfreier.


Peter


von Tester (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

Den Interrupt deswegen, damit er mit dem senden der zweiten 8bit wartet 
bis die ersten fertig sind. Oder ist das nicht notwendig. Ich habs halt 
so gemacht weil es anders nicht funktionierte. Das Programm läuft durch.
(PORTC=Leds vom STK500) aber am Digit steht immer nur "8." Was mache ich 
mit der nicht benutzen Dout-Leitung vom MAX7221?

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.