Hallo ihr Byteschubser!
Per (BASCOM) I2C sollen Farbwerte an einen angebundenen Slave gesendet
werden, an dem eine RGB LED mit Chip hängt.
Folgende -funktionierende- Lib läuft auf dem Slave:
https://github.com/usedbytes/neopixel_i2c
INFO: 1 | 'The slave address is currently hardcoded to 0x40 in the firmware
| 2 | '
| 3 | 'Writes look like this:
| 4 | 'Start Slave Address Register Address Data Stop
| 5 | 'The register address will auto-increment after every byte, so you can write data in bursts.
| 6 | 'The LED values are only updated after a STOP is received.
| 7 | '
| 8 | '*** Register Map:
| 9 | 'The register map consists of a number of global control registers - address 0x00-0x03 - followed by an array of registers which hold the individual value for each LED in normal mode.
| 10 | '
| 11 | 'Address Name Description Access Reset
| 12 | '0x00 CTRL Control Register R/W 0
| 13 | '0x01 GLB_G Global Green Value R/W 0
| 14 | '0x02 GLB_R Global Red Value R/W 0
| 15 | '0x03 GLB_B Global Blue Value R/W 0
| 16 | '*** Register Descriptions:
| 17 | 'CTRL
| 18 | 'The control register sets the operating mode.
| 19 | 'Name: RSVD RSVD RSVD RSVD RSVD RSVD GLB RST
| 20 | 'Bit: 7 6 5 4 3 2 1 0
| 21 | 'Access: r r r r r r rw rw
| 22 | '
| 23 | 'RST
| 24 | 'Writing a 1 to this bit will reset the LED controler, setting all LEDs to OFF. This bit will be automatically cleared once the reset has completed.
| 25 | '
| 26 | 'GLB
| 27 | 'Writing a one to this bit causes the global color value to be displayed on all LEDs at the end of the transaction.
| 28 | 'Normally you would set the GLB_R, GLB_G, and GLB_B values in the same transaction as setting the GLB bit, so that the new colour is immediately applied.
| 29 | 'Writing a zero to this bit will disable the global colour override and return to normal operation.
| 30 | '
| 31 | '*** GLB_R, GLB_G, GLB_B:
| 32 | 'These registers hold the global colour value. When the GLB bit in the CTRL register is set, all LEDs will display this colour.
| 33 | '
| 34 | '*** LED Value Array:
| 35 | 'Everything after the global registers is an array of data for each LED. When the GLB bit is not set, each LED will display whatever value is programmed in its corresponding register set.
| 36 |
| 37 |
| 38 | 'Info aus der I2C Lib des Slaves:
| 39 | 'Here's an example of I2C Communication to start a SRF08 ranging in cm:
| 40 | 'i2c_start(); // send start sequence
| 41 | 'i2c_tx(0xE0); // SRF08 I2C address with R/W bit clear
| 42 | 'i2c_tx(0x00); // SRF08 command register address
| 43 | 'i2c_tx(0x51); // command to start ranging in cm
| 44 | 'i2c_stop(); // send stop sequence
|
##############################################
BASCOM:
Die Prints kommen in der finales Version natürlich weg! 1 | $regfile "m328pdef.dat"
| 2 | $crystal = 8000000
| 3 |
| 4 | $framesize = 32
| 5 | $swstack = 32
| 6 | $hwstack = 64
| 7 |
| 8 | $baud = 4800
| 9 | $lib "i2c_twi.lbx"
| 10 | Config Twi = 100000 ' Init TWBR und TWSR - wanted clock frequency - 100kHz Standard , 400kHz Fast , 3.4MHz High speed
| 11 |
| 12 | ' TWI gleich einschalten, das macht Bascom ansonsten erst beim I2CStart:
| 13 | Twcr = &B00000100 ' nur TWEN setzen
| 14 |
| 15 | Const I2c_slave_adress_write = &H40 ' Slave Address WRITE
| 16 | Const I2c_slave_adress_read = &H41 ' Slave Address + 1 READ
| 17 | Const I2c_slave_ctrl_reg = &H00 ' Control Register CTRL = 0x00
| 18 |
| 19 | '******** hier bin ich nicht sicher, was besser wäre:
| 20 | 'Dim Colors_byte_array(3) As Byte
| 21 | 'Greenvalue Alias Colors_byte_array(_base) : Redvalue Alias Colors_byte_array(_base + 1) : Bluevalue Alias Colors_byte_array(_base + 2)
| 22 | Dim Greenvalue As Byte , Redvalue As Byte , Bluevalue As Byte
| 23 | '********
| 24 |
| 25 | Config Sda = Portc.4
| 26 | Config Scl = Portc.5
| 27 |
| 28 |
| 29 | Do
| 30 |
| 31 | Greenvalue = 0 : Redvalue = 255 : Bluevalue = 255 ' define a color
| 32 |
| 33 | 'Farbwerte besser in einer Tabelle bereitstellen? Performance?
| 34 | 'Colors_byte_array = Lookup (4, Farbbytetabelle) ' hol den Wert aus der 4. Zeile in der Tabelle namens "Farbbytetabelle"
| 35 |
| 36 | Print Greenvalue ; " " ; Redvalue ; " " ; Bluevalue
| 37 | I2cstart
| 38 | If Err = 0 Then Print "i2c start ok" ' In der Systemvariablen err wird das Ack-Bit hinterlegt
| 39 |
| 40 | I2csend I2c_slave_adress_write ' Slave ansprechen 'I2CSEND combines the i2cstart,i2cwbyte and i2cstop statements.
| 41 | If Err = 0 Then Print "i2c slave adresse ok"
| 42 |
| 43 | I2cwbyte I2c_slave_ctrl_reg ' Slave Control Register auswählen
| 44 | If Err = 0 Then Print "i2c CTRL register ok"
| 45 |
| 46 | I2cwbyte &H01 ' GLB_G Register auswählen
| 47 | I2cwbyte Greenvalue ' Farbwerte ins Register schreiben
| 48 | If Err = 0 Then Print "i2c farbbyte uebertragen"
| 49 |
| 50 | I2cwbyte &H02 ' GLB_R Register auswählen
| 51 | I2cwbyte Redvalue ' Farbwerte ins Register schreiben
| 52 | If Err = 0 Then Print "i2c farbbyte uebertragen"
| 53 |
| 54 | I2cwbyte &H03 ' GLB_B Register auswählen
| 55 | I2cwbyte Bluevalue ' Farbwerte ins Register schreiben
| 56 | If Err = 0 Then Print "i2c farbbyte uebertragen"
| 57 |
| 58 | I2cstop ' The LED values are only updated after a STOP is received
| 59 | If Err = 0 Then Print "i2c stop - LED values updated"
| 60 |
| 61 |
| 62 |
| 63 | Print Err ' Err = 0 -> kein Fehler ! Mit ERR kann nach jedem gesendeten Byte abgefragt werden, ob es mit ACK quittiert wurde (=0), oder nicht (=1).
| 64 | Print
| 65 |
| 66 | Wait 5
| 67 |
| 68 | ' NÄCHSTE FARBE
| 69 |
| 70 | Loop
| 71 |
| 72 | End
|
Ich schaffe es einfach nicht das RGB Bytearray bzw. die Einzelwerte
korrekt an den Slave zu schicken.
Muss ich nach dem Control-Register-Aufruf die 3 GLB_ Register einzeln
aufrufen, gefolgt von Farbbytes oder schicke ich sofort 3 Farbbytes nach
dem Aufruf des Control Registers?
Muss ich in das Control Register vor den Farbbytes irgendwas bestimmtes
reinschreiben?
Wie könnte ich die 3 RGB Bytes "eleganter" übergeben, als alles einzelne
Programmzeilen zu erstellen?
Interessant zu wissen ist folgendes:
"I2CSEND combines the i2cstart,i2cwbyte and i2cstop statements."
Wenn ich "I2c_slave_adress_write" mit I2c*wbyte* aufrufe, erhalte ich
kein ACK und die restlichen I2C Kommandos werden übersprungen. Wenn ich
es mit dem Kombinationsbefehl I2c*send* mache, dann bekomme ich das ACK
und alle weiteren Prints werden ausgegeben. Vom Prinzip her müsste es
aber mit I2c*wbyte* funktioneren.
Hat jemand eine Ahnung warum das nicht mit I2c*wbyte* funktioniert?
Hallo Alfred,
wenn Du die aktuelle Bascom Version (ab 2.0.7.9) verwendest, dann musst
Du eigentlich nur die so genannte Rainbow Library verwenden - und
fertig. Die Hilfe (F1) hält dazu auch ganz ordentliche Beispiele parat.
Du sparst Zeit und hast schneller Erfolg...
monkye
Danke für den Hinweis Uwe. Ich möchte aber lieber flexibel bleiben und
das Prozedere auch für andere Projekte einsetzen. Die Rainbow-lib kommt
nicht in Frage ;)
Hello? Nur C und Assembler Fans hier? =)
Hi
Fortran wird hier nicht helfen ;)
Wenn Du schon kein ACK bekommst - stimmt die Adresse des I2C-Slave?
MfG
Alfred S. schrieb:
> Hello? Nur C und Assembler Fans hier? =)
Hat nichts mit der Sprache zu tun. Du must erst mal verstehen wie
das Ganze funktioniert (auch I2C).
Also, so wie ich das oben rausgelesen habe, funktioniert es
folgendermassen:
a) Alle LEDs selbe Farbe z.B. RED 1 | i2cstart
| 2 | i2cwbyte (SlaveAdress*2) /* Weiss allerdings nicht, wie die Adressierung beim Bascom ist... */
| 3 | i2cwbyte 1 /* Wenn es stimmt was du oben geschrieben hast, gehen alle LEDs aus */
| 4 | i2cstop /* Ende, alle LEDs sollten jetzt Aus sein */
| 5 | waitms 50 /* Bisschen warten... */
| 6 | i2cstart
| 7 | i2cwbyte (SlaveAdress*2) /* Weiss allerdings nicht, wie die Adressierung beim Bascom ist... */
| 8 | i2cwbyte 2 /* Global Value (in deinem Fall RED) wird angezeigt */
| 9 | i2cwbyte 0 /* GLB_G (GREEN) ist OFF */
| 10 | i2cwbyte 255 /* GLB_R (RED) ist ON */
| 11 | i2cwbyte 0 /* GLB_B (BLUE) ist OFF */
| 12 | i2cstop /* Ende, alle LEDs sollten jetzt Rot leuchten */
|
b) Die ersten 5 LEDs leuchten in verschiedenen Farben: 1 | Dim NrOfLeds, lWert As Byte
| 2 |
| 3 | i2cstart
| 4 | i2cwbyte (SlaveAdress*2)
| 5 | For NrOfLeds=1 To 4
| 6 | i2cwbyte 0 /* CTRL + GLB_X sind OFF */
| 7 | Next
| 8 | Restore ledRGB
| 9 | For NrOfLeds=1 To 15
| 10 | Read lWert
| 11 | i2cwbyte lWert
| 12 | Next
| 13 | i2cstop /* Ende, alle LEDs sollten jetzt in verschiedenen Farben leuchten */
| 14 | End
| 15 |
| 16 | ledRGB:
| 17 | Data 255,0,0, 0,255,0, 0,0,255, 150,150,0, 0,150,150
|
Sollte funktionieren - ausprobieren, Resultat posten...
Also: 1 | i2cstart
| 2 | i2cwbyte (Slaveadresse)
| 3 | i2cwbyte 1
| 4 | i2cstop
|
Das geht einfach nicht mit "wbyte" an der Slaveadresse. Musste es durch
"send" ersetzen. Ich musste den Slave insgesamt nur 1x an seiner
Slaveadresse ansprechen. Habe es hinbekommen! Allerdings besteht noch
Klärungbedarf:
1 | Const I2c_slave_hello = &H40 ' Slave Address WRITE
| 2 | Const I2c_slave_read = &H41 ' Slave Address + 1 READ
| 3 | Const I2c_slave_ctrl_reg = &H00 ' Control Register CTRL = 0x00
| 4 |
| 5 |
| 6 | I2csend I2c_slave_hello ' Slave ansprechen 'I2CSEND combines the i2cstart,i2cwbyte and i2cstop statements.
| 7 |
| 8 | Do
| 9 |
| 10 |
| 11 | Print "es geht los:"
| 12 |
| 13 | Greenvalue = 0 : Redvalue = 255 : Bluevalue = 0 ' define a color - ROT
| 14 | Print Greenvalue ; " " ; Redvalue ; " " ; Bluevalue
| 15 |
| 16 | I2cstart
| 17 | 'If Err = 0 Then Print "i2c start ok"
| 18 |
| 19 | I2cwbyte I2c_slave_ctrl_reg ' Slave Control Register auswählen
| 20 | 'If Err = 0 Then Print "i2c CTRL register ok"
| 21 |
| 22 | 'I2cwbyte &B00000000 ' GLB auf 0 und RST auf 0 = LEDs aus = 00000000 -> Dezimal "0"
| 23 | 'I2cwbyte &B00000001 ' GLB auf 0 und RST auf 1 = LEDs ein (FALSCHE FARBEN) = 00000001 -> Dezimal "1"
| 24 | 'I2cwbyte &B00000010 ' GLB auf 1 und RST auf 0 = LEDs ein (FALSCHE FARBEN) = 00000010 -> Dezimal "2"
| 25 | I2cwbyte &B00000011 ' GLB auf 1 und RST auf 1 = LEDs ein (RICHTIGE FARBEN) = 00000011 -> Dezimal "3"
| 26 | 'If Err = 0 Then Print "CTRLbyte uebertragen"
| 27 | '*******
| 28 | I2cwbyte &H01
| 29 | If Err = 0 Then Print "was soll das hier - ohne gehts nicht"
| 30 | '*******
| 31 | I2cwbyte Greenvalue ' GLB_G Register: Farbwert ins Register schreiben
| 32 | 'If Err = 0 Then Print "i2c farbbyte uebertragen"
| 33 |
| 34 | I2cwbyte Redvalue ' GLB_R Register: Farbwert ins Register schreiben
| 35 | 'If Err = 0 Then Print "i2c farbbyte uebertragen"
| 36 |
| 37 | I2cwbyte Bluevalue ' GLB_B Register: Farbwert ins Register schreiben
| 38 | 'If Err = 0 Then Print "i2c farbbyte uebertragen"
| 39 |
| 40 | I2cstop ' The LED values are only updated after a STOP is received
| 41 | 'If Err = 0 Then Print "i2c stop - LED values updated"
| 42 |
| 43 | Print Err ' Err = 0 -> kein Fehler ! Mit ERR kann nach jedem gesendeten Byte abgefragt werden, ob es mit ACK quittiert wurde (=0), oder nicht (=1).
| 44 | Print
| 45 |
| 46 | Wait 2
| 47 |
| 48 | Greenvalue = 255 : Redvalue = 255 : Bluevalue = 0 ' define a color - GELB
| 49 | Print Greenvalue ; " " ; Redvalue ; " " ; Bluevalue
| 50 |
| 51 | I2cstart
| 52 | I2cwbyte I2c_slave_ctrl_reg
| 53 | I2cwbyte &B00000011
| 54 | '*******
| 55 | I2cwbyte &H01
| 56 | If Err = 0 Then Print "was soll das hier - ohne gehts nicht"
| 57 | '*******
| 58 | I2cwbyte Greenvalue
| 59 | I2cwbyte Redvalue
| 60 | I2cwbyte Bluevalue
| 61 | I2cstop
| 62 | Print Err
| 63 |
| 64 | Wait 2
| 65 |
| 66 | 'weitere Farben
| 67 |
| 68 | Loop
|
Bei "was soll das hier - ohne gehts nicht" musste ich ein Byte
übertragen, sonst wären die Farbwerte nicht übertragen worden. Es war
dabei quasi egal welchen Wert es enthielt. Hätte auch &HFF / 255 sein
können.
Läuft so seit Stunden mit 10 verschiedenen Farben durch und funktioniert
wohl einwandfrei.
Frage: Warum musste ich ein Byte rüberschicken, wo der Wert quasi egal
ist? Das CTRL Register hatte ich doch bereits ausgerufen und einen Wert
reingeschrieben...
Auch komisch: bei der Übertragung von &B00000001 ins CTRL Register wurde
das RESET Bit auf 1 gesetzt... und die LEDs blieben an (allerdings mit
falscher Farbdarstellung). Gibt es dazu eine Erklärung? Habe
verschiedene CTRL Registerwerte ausprobiert und die nicht
funktionierenden auskommentiert.
Alfred S. schrieb:
> Auch komisch: bei der Übertragung von &B00000001 ins CTRL Register wurde
> das RESET Bit auf 1 gesetzt... und die LEDs blieben an (allerdings mit
> falscher Farbdarstellung). Gibt es dazu eine Erklärung? Habe
Ja.
Das ist alles so falsch, dass du diesen armen LED-Treiber (was ist das
überhaupt für ein Ding ?) wahrscheinlich total durcheinandergebracht
hast.
Also, ohne durch deinen (Horror) Program ganz durchzugehen: 1 | I2csend I2c_slave_hello 'I2CSEND combines the i2cstart,i2cwbyte and i2cstop statements.
|
Wenn es stimmt, dann ist es damit auch schon zu Ende - Device muss
erst wieder neu adressiert werden, damit es weitergeht...
1 | I2cstart
| 2 | 'If Err = 0 Then Print "i2c start ok"
| 3 | I2cwbyte I2c_slave_ctrl_reg ' Slave Control Register auswählen
|
Nein, nicht Control Register auswählen.
Das, was du oben (zufällig) gemacht hast, nennt sich General Call,
und nur deswegen geht es überhaupt weiter...
Und von da an hatte ich keine Lust mehr.
Entweder hörst du auf rumzuspielen, machst ganz einfach ein copy &
paste mit von mir gepostetem Program und sagst ob es geht/nicht geht
oder es wird nie etwas.
Wenn es mit von dir oben gepostetem Program geht (wenn auch falsch),
dann muss es mit meinem Program erst recht gehen .
Das einzige, was bei mir ev. geändert werden müsste, ist die Adresse
für Slave, also einfach 0x40 als Adresse reinschreiben, mit dem Rest
nicht rumspielen, nicht ändern.
So:
Ich habe dein Programm getestet. Es lief nicht durch. Von daher habe ich
die Änderungen eingebaut.
Hier der Test mit deinem Programm: 1 | Do
| 2 |
| 3 | Print "es geht los:"
| 4 |
| 5 | i2cstart
| 6 | If Err = 0 Then Print "i2c start ok"
| 7 | I2cwbyte &H40 'Slaveadressierung
| 8 | If Err = 0 Then Print "i2c slave ok"
| 9 | I2cwbyte 1 '/* Wenn es stimmt was du oben geschrieben hast, gehen alle LEDs aus */
| 10 | If Err = 0 Then Print "i2c byte ok"
| 11 | I2cstop '/* Ende, alle LEDs sollten jetzt Aus sein */
| 12 | If Err = 0 Then Print "i2c stop ok"
| 13 | Waitms 50 '/* Bisschen warten... */
| 14 | I2cstart
| 15 | If Err = 0 Then Print "i2c start ok"
| 16 | I2cwbyte &H40 'Slaveadressierung
| 17 | If Err = 0 Then Print "i2c slave ok"
| 18 | I2cwbyte 2 '/* Global Value (in deinem Fall RED) wird angezeigt */
| 19 | If Err = 0 Then Print "i2c global value ok"
| 20 | I2cwbyte 0 '/* GLB_G (GREEN) ist OFF */
| 21 | If Err = 0 Then Print "i2c GLB_G ok"
| 22 | I2cwbyte 255 '/* GLB_R (RED) ist ON */
| 23 | If Err = 0 Then Print "i2c GLB_R ok"
| 24 | I2cwbyte 0 '/* GLB_B (BLUE) ist OFF */
| 25 | If Err = 0 Then Print "i2c GLB_B ok"
| 26 | I2cstop '/* Ende, alle LEDs sollten jetzt Rot leuchten */
| 27 | If Err = 0 Then Print "i2c stop ok"
| 28 |
| 29 | Print Err
| 30 |
| 31 | Wait 2
| 32 |
| 33 | 'nächste Farbe
| 34 | Loop
|
Ausgabe im Terminal: 1 | es geht los:
| 2 | i2c start ok
| 3 | i2c start ok
| 4 | 1
|
Gemäß der Anleitung und gemäß deines Codes müsste es funktionieren wie
von dir beschrieben. Tut es leider nicht.
Der Slave wird korrekt adressiert und da geht es nicht weiter. Hast du
einen Verdacht was es sein könnte? Adresse ist korrekt!
Habe das hier mal Testweise probiert: 1 | Scanbus: 'Scan bus for valid I2C addresses on bus
| 2 | ' ( test for ACK to come back from Busaddress )
| 3 | Print
| 4 | Print "Scan start"
| 5 | For Busaddress = 0 To 254 Step 2 'for all even addresses
| 6 | I2cstart 'send start
| 7 | I2cwbyte Busaddress 'send Busaddress
| 8 | If Err = 0 Then 'we got an ack
| 9 | Print "Slave at : " ; Busaddress ; "d, = " ; Hex(busaddress) ; "hex"
| 10 | Chipaddress = Busaddress \ 2
| 11 | Print " with chip address " ; Hex(chipaddress) ; "h"
| 12 | Print
| 13 | End If
| 14 | I2cstop 'free bus
| 15 | Next
| 16 | Print "End Scan"
| 17 | Return
|
Ausgabe im Terminal: 1 | Scan start
| 2 | Slave at : 0d, = 00hex
| 3 | with chip address 00h
| 4 |
| 5 | Slave at : 128d, = 80hex
| 6 | with chip address 40h
| 7 |
| 8 | End Scan
|
Es gibt nur 1 Slave.
Hilft das weiter?
Alfred S. schrieb:
> Der Slave wird korrekt adressiert und da geht es nicht weiter. Hast du
> einen Verdacht was es sein könnte? Adresse ist korrekt!
Nein.
Aber da du 2 Mal hintereinander "i2c start ok" kriegst und danach
eine 1 (wahrscheinlich für Err), nehme ich an, dass dieses Ding
die Adresse nicht bestätigt, also die Adresse falsch ist.
Probiere es mal mit General Call Adresse 0x00, so: 1 | I2cwbyte &H0 'Slaveadressierung
|
Wenn es durchgeht, dann ist das Ding in Ordnung, nur die Adresse
stimmt eben nicht - danach kannst du die Adresse 0x80 probieren, wenn
das aber nicht klappt, musst du die Adressen eine nach der anderen
abklappern...
Und zum zweiten Mal: Was ist das überhaupt für ein Ding ?
Mit der geänderten Adresse auf &H80 funktioniert dein Programm (es
musste nur noch das CTRL Register eingefügt werden.)
Mit Dezimal 1 gehen die LEDs aus und mit 2 gehen die an.
Ich muss das CTRL Register und das CTRL Byte aber bei JEDEM Farbwechsel
mitschicken, sonst ändert sich nichts.
Const I2c_slave_hello = &H80
Const I2c_slave_ctrl_reg = &H00
I2cstart
I2cwbyte I2c_slave_hello
I2cwbyte I2c_slave_ctrl_reg
I2cwbyte &B00000010 'Dezimal 2
I2cwbyte Greenvalue
I2cwbyte Redvalue
I2cwbyte Bluevalue
I2cstop
Was ist das überhaupt für ein Ding ? Siehe 1. Post:
https://github.com/usedbytes/neopixel_i2c
Das mit dem General Call funktioniert übrigens auch. Danke für den
Hinweis, dass es sowas gibt!
Insgesamt mal wieder was dazu gelernt.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|