Hallo miteinander, Ich komme irgendiwie an meine Grenzen mit dem Verständlichen eines Datenblattes. Auch wen ich es noch so ganz genau anschaue sehe ich da nicht wirklich durch. Vieleicht hat auch schon jemand mit diesem Baustein (I/O Expander) MCP23S18 erfahrungen gemacht. Alles was ich möchtes ist lediglich An PORTA etwas ausgeben also z.B. 0x04. Schon alleine die Register Adressen sind nirgends erklärt da bin ich aber soweit das ich das Register OLATA benötige um ein Ausgangssignal zu generieren. Aber schon das zweite mit der BANK 1/0 ist nicht wirklich erleutert wie ich das setze. Würde ich dies mit I2C programmieren wäre es ev. einfacher da gibt es ein wunderbares Flussdiagramm aber bei SPI nicht. Sie sagen man sollte auch das definieren ob es jezt ein Eingang oder ein Ausgang (DDR) ist, aber das kann ich auch nicht mehr entnehmen von dem Ablauf her was zuerst kommt. Was mir auch klar ist das ich mit 0x40 schreiben und mit 0x41 lesen kann. Und wen ich jetzt das so anschaue müsste ich für meinen Zweck 0x40(Schreiben), 0x14 Regeister Adresse PortA, 0x04 (Pin 3 output 3,3V) senden. Ev. könnte mir jemand auf die Sprünge helfen oder sieht gleich wiso ich so nicht durchblicke. Leider habe ich auch noch keine Legende entdeckt über all diese Abkürzungen der Register. Danke.
Nico F. schrieb: > alleine die Register Adressen sind nirgends erklärt Doch im Datenblatt das Du angehängt hast, mußt Du nur genau lesen. Du entscheidest Dich zuerst, ob Du zwei 8Bit Ports oder einen 16Bit-Port haben willst. Dementsprechend setzt Du Bit 7 (Bank) in IOCON (0x05/0x15). Dadurch hast Du die Adressen der anderen Register festgelegt. Dann legst Du in IODIRA oder IODIRB (je nach Port) fest welcher Pin Ein- oder Ausgang sein soll. Danach kannst Du GPIOA oder GPIOB schreiben oder lesen. Wenn Du es liest bekommst Du den aktuellen Zustand, wenn Du schreibst wird OLATA/B entsprechend gesetzt. Du kannst auch OLATA/B direkt beschreiben. Der Rest kommt später ;-)
ach ja: Nico F. schrieb: > Leider habe ich auch noch keine Legende entdeckt > über all diese Abkürzungen der Register. ab 1.6.1, Seite 18 im Datenblatt. Nur die erste Seite lesen reicht nicht.
Hi, also ich nutze den 23S17, der ist ganz ähnlich. Die Register sind doch ab Seite 18 im Datenblatt sehr genau beschrieben. Du musst doch bloß im IODIR das entsprechende Muster reinschreiben, damit die Pins Ausgang werden (Standard ist Input) und dann in GPIO das, was du ausgeben willst. Da das BANK-Bit beim Starten 0 ist, sind die Register abwechselnd gemappt, wie du in Tabelle 1-1 sehen kannst. Also IODIR A/B auf 0x00 und 0x01 und GPIO auf 0x12 und 0x13. So sehen meine Routinen zum Beschreiben und Auslesen aus:
1 | void Write23s17(uint8_t reg, uint8_t data) { |
2 | SPITXbuffer[0] = 0x40; // 4 is fix, 0 is SPI address #0 with R/W=0 |
3 | SPITXbuffer[1] = reg; // register address follows |
4 | SPITXbuffer[2] = data; // data byte follows |
5 | |
6 | // Select MCP23S17 |
7 | CS_IO_EXPANDEROff(); |
8 | |
9 | Write_Buffer_Handle4 = DRV_SPI_BufferAddWriteRead(SPIHandle4, |
10 | (SPI_DATA_TYPE *) &SPITXbuffer[0], 3, |
11 | (SPI_DATA_TYPE *) &SPIRXbuffer[0], 3, |
12 | NULL,NULL |
13 | ); |
14 | // Wait for transmission done |
15 | while (0 == (DRV_SPI_BufferStatus(Write_Buffer_Handle4) & DRV_SPI_BUFFER_EVENT_COMPLETE)); |
16 | |
17 | CS_IO_EXPANDEROn(); |
18 | } |
19 | |
20 | uint8_t Read23s17(uint8_t reg) { |
21 | SPITXbuffer[0] = 0x41; // 4 is fix, 1 is SPI address #0 with R/W=1 |
22 | SPITXbuffer[1] = reg; |
23 | |
24 | // Select MCP23S17 |
25 | CS_IO_EXPANDEROff(); |
26 | |
27 | Write_Buffer_Handle4 = DRV_SPI_BufferAddWriteRead(SPIHandle4, |
28 | (SPI_DATA_TYPE *) &SPITXbuffer[0], 2, |
29 | (SPI_DATA_TYPE *) &SPIRXbuffer[0], 3, |
30 | NULL,NULL |
31 | ); |
32 | // Wait for transmission done |
33 | while (0 == (DRV_SPI_BufferStatus(Write_Buffer_Handle4) & DRV_SPI_BUFFER_EVENT_COMPLETE)); |
34 | |
35 | CS_IO_EXPANDEROn(); |
36 | |
37 | return SPIRXbuffer[2]; |
38 | } |
Viele Grüße Jochen
:
Bearbeitet durch User
Hallo, hmmm, die Register sind eigentlich alle im Datenblatt auf den letzten Seiten erklärt. Klar, da muss man sich durchbeißen. Die Register sind ebenfalls gleich zu meinem MCP23017 (I2C). So sieht der Auszug meiner Klasse für Ausgänge aus. Die Methoden readOneRegister und writeOneRegister sind nur die I2C Transfer Funktionen. Musste nur durch SPI Transfer Funktionen ersetzen. i2cAdr wäre dann bei dir der SPI /CS Pin. Die Pinnummern des MCP habe ich für mich einfach durchnummeriert und übergebe diesen Wert bei der Objektinitialisierung.
1 | #pragma once
|
2 | |
3 | // Register Table 3.1 mit IOCON.BANK = 0
|
4 | constexpr uint8_t IODIRA = 0x00; |
5 | constexpr uint8_t IODIRB = 0x01; |
6 | constexpr uint8_t OLATA = 0x14; |
7 | constexpr uint8_t OLATB = 0x15; |
8 | |
9 | |
10 | // GPA.0 ... GPA.7 => Pinnummer 0-7
|
11 | // GPB.0 ... GPB.7 => Pinnummer 8-15
|
12 | |
13 | // *** interne Hilfsfunktionen *** //
|
14 | constexpr uint8_t getBitMaske(const uint8_t pin) { |
15 | return (pin<8) ? (1<<pin) : (1<<(pin-8)); |
16 | }
|
17 | |
18 | constexpr uint8_t get_DIR_Port(const uint8_t pin) { |
19 | return (pin<8) ? IODIRA : IODIRB; |
20 | }
|
21 | |
22 | constexpr uint8_t get_OUT_Port(const uint8_t pin) { |
23 | return (pin<8) ? OLATA : OLATB; |
24 | }
|
25 | |
26 | |
27 | // >>> Output <<< ------------------------------------------------------------------
|
28 | template <uint8_t i2cAdr, uint8_t pin> |
29 | class Output |
30 | {
|
31 | public:
|
32 | // Konstruktor
|
33 | Output () |
34 | { } |
35 | |
36 | void init() |
37 | {
|
38 | setLow(); // verhindert Einschaltzucken |
39 | uint8_t is = 0; |
40 | readOneRegister (i2cAdr, get_DIR_Port(pin), is); // IODIR Port lesen |
41 | is &= ~(getBitMaske(pin)); // Bit löschen |
42 | writeOneRegister (i2cAdr, get_DIR_Port(pin), is); // modifizierte Maske zurückschreiben |
43 | }
|
44 | |
45 | void setHigh() |
46 | {
|
47 | uint8_t is = 0; |
48 | readOneRegister (i2cAdr, get_OUT_Port(pin), is); // OLAT Port lesen |
49 | is |= (getBitMaske(pin)); // Bit setzen |
50 | writeOneRegister (i2cAdr, get_OUT_Port(pin), is); // modifizierte Maske zurückschreiben |
51 | }
|
52 | |
53 | void setLow() |
54 | {
|
55 | uint8_t is = 0; |
56 | readOneRegister (i2cAdr, get_OUT_Port(pin), is); // OLAT Port lesen |
57 | is &= ~(getBitMaske(pin)); // Bit löschen |
58 | writeOneRegister (i2cAdr, get_OUT_Port(pin), is); // modifizierte Maske zurückschreiben |
59 | }
|
60 | |
61 | void set(const bool state) // für Zustandsentscheidung während der Laufzeit |
62 | {
|
63 | if (state) setHigh(); |
64 | else setLow(); |
65 | }
|
66 | };
|
Ist kostenlos, ich hoffe das es nicht umsonst ist. :-)
Das hilft mir schon einwenig aber sehe ich das demfalle Richtig das ich für jeden einzelenes commando einen Restart machen muss und neu beginnen. also CS /Write,0x40,0x14 CS/restart CS /write,0x40,0x00,0x04 somit müsste Pin3 PORTA = 3,3V sein
Du kannst auch im continuous Mode Daten schieben, steht auch im Datenblatt..
Hallo, was meinst du mit "Restart"? Du musst doch nur einmalig die Richtung festlegen in IODIRA. <== Ausgang Danach schaltest du nur noch in OLATA ein oder aus mit dem jeweiligen Bit.
Ja ich meine eher du must die Richtung im Register festlegen. Also musst du sicher mal zu dem Register navigieren. und mit restart meine ich CS High und dan erneut Low und neu beginnen. Oder verstehe ich das falsch.
Mein Jetziger code ist bis jetzt so CSlow; SPIT(0x40);//Schreiben SPIT(0x14);//IODIRA SPIT(0x00);//Richtung Ausgang CShigh; CSlow; SPIT(0x40);//Schreiben SPIT(0x14);//OLATA SPIT(0x04);//Output CShigh;
Ich hatte bei 23S17 noch das Problem, dass die drei Adressleitungen - auch im SPI-Modus - auf 0 gesetzt werden mussten, sonst war der nicht ansprechbar. Die Adresse wird beim 23S18 ja analog über Widerstandsteiler eingestellt. Wenn es nicht geht, vielleicht mal hier den Pin so beschalten, dass Adresse 0 eingestellt ist. Hab ich zwar beim Überfliegen des Datenblatts nicht gesehen, dass das erforderlich ist, aber der Teufel steckt ja manchmal im Detail. Viele Grüße Jochen
Muss korrigieren Aber leider klappt es so nicht ev können noch SPI Einstellungen wie CPOL oder CPHA falsch sein sind jetzt CPOL 1 und CPHA 1 CSlow; SPIT(0x40);//Schreiben SPIT(0x00);//IODIRA SPIT(0x00);//Richtung Ausgang CShigh; CSlow; SPIT(0x40);//Schreiben SPIT(0x14);//OLATA SPIT(0x04);//Output CShigh;
Ne, ich sehe gerade, du schreibst zweimal in die 0x14 (OLATA). Du musst einmal in 0x00 schreiben (IODIRA), am besten 0x00, dann sind alle Pins Ausgänge. Und dann in 0x12 (GPIOA), was ausgegeben werden soll. 0x14 (OLATA) sollte auch klappen - Schreibzugriffe in die 0x12 werden an 0x14 durchgereicht. Viele Grüße Jochen
Wenn du kein Oszi zur Hand hast, musst du die vier Modi, die möglich sind, ausprobieren. Sonst einfach mal schauen, ob die Signalform so ist, wie sie laut Datenblatt sein muss. Viele Grüße Jochen
Jochen S. schrieb: > Wenn du kein Oszi zur Hand hast, musst du die vier Modi, die > möglich > sind, ausprobieren. Sonst einfach mal schauen, ob die Signalform so ist, > wie sie laut Datenblatt sein muss. > > Viele Grüße > > Jochen Ja die Signalform stimmt bei steigender Flanke wird eingelesen von dem Clock und die Zeitabstände stimmen auch wie sie sollten.
Kannst ja auch das Lesen mal probieren. Zwei Register sind beim Anschalten mit 0xFF, alle anderen mit 0x00 initialisiert. Wenn du die ganze Register-Map ab Adresse 0x00 ausliest, siehst du ja, ob diese Antworten dabei sind oder alles 0xFF ist, was darauf deuten lässt, dass sich der Chip nicht angesprochen fühlt. Dann wie gesagt mal den ADDR-Pin so beschalten, dass Adresse 0 eingestellt ist. Viele Grüße Jochen
Beitrag #6135314 wurde vom Autor gelöscht.
Jochen S. schrieb im Beitrag #6135314: > Dumme Zusatzfrage: Quarz mit zwei Kondensatoren hast du auch dran? > > Viele Grüße > > Jochen Ehm am Controller ja an dem MCP23S18 wäre mir neu ;)
Wie ist dein /RESET-Pin beschaltet? Der muss "externally biased" sein, also Pull-Up mit anderen Worten. Viele Grüße Jochen
Ja, hab mich im Datenblatt vertan. Habe beim MCP2518 geschaut, den ich auch noch auf dem Bildschirm hatte. Das ist ein CAN-Controller und der braucht Oszi. Hab meinen Kommentar aber gelöscht. Viele Grüße Jochen
Jochen S. schrieb: > Wie ist dein /RESET-Pin beschaltet? Der muss "externally biased" > sein, > also Pull-Up mit anderen Worten. > > Viele Grüße > > Jochen Ja, der ist auf 3,3V der Reset
Seltsam, wenn da gar nix geht. Hab gerade auch gesehen, dass nur der 23018 den ADDR-Pin hat. Wenn der beim 23S18 fehlt, kann es damit auch nicht zusammenhängen ... Viele Grüße Jochen
Mit einem 23S17 bin ich auf die Nase gefallen wegen Spannungen. µC BluePill mit 3V3 23S17 an 5V und an den GPIOs ein 5V LCD128x64 uralt. Ging ein paar Stunden/Tage und dann war Schluß, LCD reagierte nicht mehr. Ursache ist der geringe High-Level an SPI wenn der 23S13 an 5V hängt. Der mag da Vcc*0.8 mindestens als high sehen Simple Diode reduziert die ChipSpannung und schon paßt es. Läuft alles an gleicher Spannung sollte das keine Thema sein.
> Ging ein paar Stunden/Tage und dann war Schluß, LCD reagierte nicht > mehr. > > Ursache ist der geringe High-Level an SPI wenn der 23S13 an 5V hängt. > Der mag da Vcc*0.8 mindestens als high sehen Also das hab ich jetz auch noch überprüft. Die Spannung geht wirklich auf 0.0-0.1V runter also kaum das dies noch als high gesehen werden könnte.
Andersrum: Der Highpegel vom BluePill langt dem MCP nicht als Eins wenn er an fetten 5V hängt.
NichtWichtig schrieb: > Andersrum: > Der Highpegel vom BluePill langt dem MCP nicht als Eins wenn er an > fetten 5V hängt. der high pegel liegt bei 3,2V dies sollte wohl reichen hängt ja nur an 3,3V
Hallo Horst, ich habe eine Frage zum IOCON-Register. Alle anderen Register gibt es einmal für A und B. Daher dachte ich, dass es das IOCON Register nur einmal gibt. Auf der Register-Karte taucht IOCON aber einmal bei A und einmal bei B auf. Allerdings werden da ja auch Parameter eingetragen, die beide Register betreffen? Ich sag' im Voraus schonmal besten Danke! MfG Manuel
Das ist dasselbe Register, was in beiden Bänken auftaucht, also gespiegelt. Viele Grüße Jochen
Also wer sich das ausgedacht hat, das Register zur Bankumschaltung auf unterschiedliche Adressen je Bank zu setzen, der hat nicht alle Tassen im Schrank. Um aus einem unbekannten BANK-Bit heraus zu kommen, muß man auf Verdacht 2 Zugriffe machen, auf 05 und auf 0B. Steht das Bit falschrum, schreibt man entweder auf ein nicht vorhandenes Register oder auf GPINTENB, was zumindest keinen Portpin falsch setzt.
Ja, das ist nicht durchdacht, da gebe ich dir recht. Aber im Normalfall entscheidet man sich ja beim Initialisieren für das eine oder das andere Modell und setzt das Bit entsprechend. Ein Problem ist es nur, wenn der Chip einmal initialisiert wurde und dann der Mikrocontroller z. B. durch Watchdog Reset neu startet. Dann weiß er halt nicht, dass der 23S18 noch im anderen Bankmodell ist und macht Blödsinn. Als Workaround kann man beim Initialisieren natürlich alle in Frage kommenden Register auf 0 zurücksetzen, was dem Zustand nach Reset entspricht, und dann die eigentliche Initialisierung zu machen. Umständlich, aber kein unlösbares Problem. Viele Grüße Jochen
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.