Hallo, hat jemand schonmal im EFB-Block das I2C-Interface mit Wishbone Bus erfolgreich zum Laufen gebracht? Ich habe mir einen I2C-IP Core mit IPexpress erzeugt (Eckdaten fwb = 50 MHz und fi2c = 100kHz). Diesen wollte ich mittels des Reference Designs von Lattice (rd1047) in Betrieb nehmen. Hierbei habe ich meinen erzeugten I2C IP-Core an die Stelle des im Reference Design eingebundenen Cores gesetzt und einige Parameter angepasst (Slave Adresse). Ich wollte das Design mit dem Aldec simulieren jedoch bekomme ich keine I2C Daten (sda)und keinen Takt (scl). Ggf. kann mir jemand weiterhelfen bzw. sieht meinen Fehler. Danke für die Hilfe.
Da ist mehr als nur ein paar Parameter anzupassen, Der Hard I2C Block im MachXO2 ist ganz sicher nicht registerkompatibel zu dem Soft I2C Block aus dem RD1046 Referenzdesign.
Hallo, ich habe versucht die Register unter Anleitung des Lattice Reference_Guide (TN1246) zu setzen, jedoch mach ich noch einen Fehler. Dem User Guide ist zu entnehmen das jeder Wishbone Zyklus drei Takte benötigt um das jeweilige Register zu setzen. Somit warte ich immer auf ein ACK vom Wishbone Controller bevor ich das nächste Register setze. Also ACK da, neues Register wird gesetzt. Der folgende Ausschnitt der State Machine zeigt wie ich die Register setzte. -- i2c core enable when START => WB_WRITE_EN <= '1'; WB_CYCLE <= '1'; WB_STROBE <= '1; -- CR WB_ADRESS <= x"4A"; --CORE ENABLE WB_DATA_IN <= x"8C"; if WB_ACK = '1' then WB_WRITE_EN <= '0'; WB_CYCLE <= '0'; WB_STROBE <= '0'; STATE <= I_TXDR; end if; --initialize write cycle when I_TXDR => WB_WRITE_EN <= '1'; WB_CYCLE <= '1'; WB_STROBE <= '1'; -- write to TXDR the slave address followed by Write bit ('0') WB_ADRESS <= x"4E"; WB_DATA_IN <= SLAVE_ADRESS & '0'; if WB_ACK = '1' then WB_WRITE_EN <= '0'; WB_CYCLE <= '0'; WB_STROBE <= '0'; STATE <= I_CMDR; end if; Alle weiteren Register setze ich nach diesem Schema. Dabei habe ich mich an das State-Diagramm auf Seite 17-13 im UG gehalten. Nach Beenden des Write Prozesses, bekomme ich 0x20 vom WB-Controller ausgegeben, das laut UG bedeutet im Staus Register SR ist RARC = 1. SCL und SCA sind immer hochohmig 'Z'. Ggf. hat jemand das Ding schon verwendet und kann mir weiterhelfen. Vielen Dank.
In diesem Codeschnipsel ist nicht zu erkennen ob du den WB Cycle richtig aufgesetzt hast. Wie sieht die Simulation des WB aus? PS: Verwende VHDL Tags für den geposteten Code. Wie die aussehen steht in der Eingabe massen direkt über den Namen!
Danke für die Antwort. Anbei der komplette Code zur Initialsierung der Register für den write Mode sowie ein Auschnitt aus der Simulation.
1 | WB_to_I2C_FSM : process(CLK, RESET, STATE, WB_DATA_OUT, WB_ACK) |
2 | begin
|
3 | if rising_edge(CLK) then |
4 | if RESET = '1' then |
5 | -- reset core
|
6 | WB_ADRESS <= x"4F"; |
7 | WB_DATA_IN <= (others => '0'); |
8 | WB_WRITE_EN <= '0'; |
9 | WB_CYCLE <= '0'; |
10 | WB_STROBE <= '0'; |
11 | STATE <= START; |
12 | else
|
13 | case STATE is |
14 | when POR => |
15 | WB_WRITE_EN <= '1'; |
16 | WB_CYCLE <= '1'; |
17 | WB_STROBE <= '1'; |
18 | WB_ADRESS <= x"4A"; |
19 | -- core enable
|
20 | WB_DATA_IN <= x"8C"; |
21 | |
22 | if WB_ACK = '1' then |
23 | WB_WRITE_EN <= '0'; |
24 | WB_CYCLE <= '0'; |
25 | WB_STROBE <= '0'; |
26 | STATE <= I_TXDR; |
27 | end if; |
28 | |
29 | when I_TXDR => |
30 | WB_WRITE_EN <= '1'; |
31 | WB_CYCLE <= '1'; |
32 | WB_STROBE <= '1'; |
33 | -- write to TXDR
|
34 | WB_ADRESS <= x"4E"; |
35 | -- set write mode
|
36 | WB_DATA_IN <= SLAVE_ADRESS & '0'; |
37 | if WB_ACK = '1' then |
38 | WB_WRITE_EN <= '0'; |
39 | WB_CYCLE <= '0'; |
40 | WB_STROBE <= '0'; |
41 | STATE <= I_CMDR; |
42 | end if; |
43 | |
44 | when I_CMDR => |
45 | WB_WRITE_EN <= '1'; |
46 | WB_CYCLE <= '1'; |
47 | WB_STROBE <= '1'; |
48 | --write STA and WR bits to CMDR
|
49 | WB_ADRESS <= x"4B"; |
50 | WB_DATA_IN <= x"94"; |
51 | if WB_ACK = '1' then |
52 | WB_WRITE_EN <= '0'; |
53 | WB_CYCLE <= '0'; |
54 | WB_STROBE <= '0'; |
55 | STATE <= WAIT_TRRDY; |
56 | end if; |
57 | |
58 | when WAIT_TRRDY => |
59 | --wait for SR to negate TIP and RxACK
|
60 | WB_WRITE_EN <= '0'; |
61 | WB_CYCLE <= '1'; |
62 | WB_STROBE <= '1'; |
63 | WB_ADRESS <= x"4F"; |
64 | WB_DATA_IN <= "XXXXXXXX"; |
65 | |
66 | if WB_ACK = '1' then |
67 | if WB_DATA_OUT(2)= '1' then |
68 | WB_WRITE_EN <= '0'; |
69 | WB_CYCLE <= '0'; |
70 | WB_STROBE <= '0'; |
71 | STATE <= W_TXDR; |
72 | end if; |
73 | end if; |
74 | |
75 | when W_TXDR => |
76 | -- write data
|
77 | WB_WRITE_EN <= '1'; |
78 | WB_CYCLE <= '1'; |
79 | WB_STROBE <= '1'; |
80 | WB_ADRESS <= x"4E"; |
81 | --write test data
|
82 | WB_DATA_IN <= x"1A"; |
83 | |
84 | if WB_ACK = '1' then |
85 | WB_WRITE_EN <= '0'; |
86 | WB_CYCLE <= '0'; |
87 | WB_STROBE <= '0'; |
88 | STATE <= W_CMDR; |
89 | end if; |
90 | |
91 | when W_CMDR => |
92 | WB_WRITE_EN <= '1'; |
93 | WB_CYCLE <= '1'; |
94 | WB_STROBE <= '1'; |
95 | WB_ADRESS <= x"4B"; |
96 | WB_DATA_IN <= x"14"; -- (WR) |
97 | |
98 | if WB_ACK = '1' then |
99 | WB_WRITE_EN <= '0'; |
100 | WB_CYCLE <= '0'; |
101 | WB_STROBE <= '0'; |
102 | STATE <= STOP; |
103 | end if; |
104 | |
105 | when STOP => |
106 | WB_WRITE_EN <= '1'; |
107 | WB_CYCLE <= '1'; |
108 | WB_STROBE <= '1'; |
109 | WB_ADRESS <= x"4B"; |
110 | WB_DATA_IN <= x"44"; --(STOP) |
111 | if WB_ACK = '1' then |
112 | WB_WRITE_EN <= '0'; |
113 | WB_CYCLE <= '0'; |
114 | WB_STROBE <= '0'; |
115 | end if; |
116 | |
117 | when others => |
118 | STATE <= STOP; |
119 | end case; |
120 | end if; |
121 | end if; |
122 | end process WB_to_I2C_FSM; |
Dieser wird direkt auf den I2C-Core geführt. Das Signal S_WB_CLK verwende ich in diesem Fall nicht. Ich dachte eher ich habe bei der Initialisierung was falsch, denn der O_WB_DATA liefert mir 0x20?
Wo setzt du denn die Startcondition? Was mich auch stört, ist dass die toplevel I2C als 'z' angezeigt werden. Ich weiss allerdings nicht wie man in einer VHDL Testbench einen Pullup modelliert.
Ich habe gerade bemerkt, das ich im Resetfall in den State Start springe den es nicht gibt. Also State START = POR. Die Startcondition ist somit POR. Ich setze das CR (x"4A") mit I2CEN=1 (Bit 7),SDA_DEL_SEL =11 (Bit 3 + 2).
Lattice User schrieb: > Ich weiss allerdings nicht wie man in einer VHDL Testbench einen Pullup > modelliert. Ich verwende 'H'. Duke
Die Startcondition setze ich im State I_CMDR, dort schreibe ich auf das Commando Register und setze Registerbit 7 (START) und 4 (Write) = x"94".
Hat noch keiner diesen Core verwendet und initialisiert?
lattice_user schrieb: > Die Startcondition setze ich im State I_CMDR, dort schreibe ich auf das > Commando Register und setze Registerbit 7 (START) und 4 (Write) = x"94". Ok, habe ich übersehen. Ich muss also nochmal darauf zurückkommen: Lattice User schrieb: > Was mich auch stört, ist dass die toplevel I2C als 'z' angezeigt werden. > Ich weiss allerdings nicht wie man in einer VHDL Testbench einen Pullup > modelliert. Der I2CHardcore ist Multimasterfähig, d.h. es wird kein I2C Telegramm gestartet wenn der I2C Bus nicht frei ist, und 'Z' auf SCL und SDA erfüllt diese Bedingung nicht. Siehe das Posting von Duke: Beitrag "Re: Probleme bei Lattice I2C EFB mit Wishbone Interface" wie man einen Pullup modelliert.
Also SCL und SDA im default Zustand auf 'H' setzen? Ok, probiere ich gleich mal aus. Danke für den Hinweis.
Ich habe in meiner Testbench die SCL und SDA mit high 'H' beschaltet. Tut sich jedoch garnichts. Der Core liefert trotzdem immer 'Z'...für SCL und SDA.
Hallo lattice_user ! Ich poste noch den Reg-Satz von dem Hardened Port I2C-Port #1 $40..$49, bzw. $4A .. $53 I2C Secondary Port.(#2). Address Mapping. Das ist aus meinem WBone I2C-Bus #1 als "Master"-Config, auf ein I2C-BUS Temp-Sensor von TI Typ: TMP101. Damit ist das MachXo2 Pico Board ein Ref-Design. Mit dem Mico8 kann man die Register von dem TempSensor via WBone-Bus lesen bzw. schreiben. Was hast du für ein Ref-Board ?.
1 | read_temp: |
2 | |
3 | movi r15, EFB |
4 | |
5 | movi r0, ADR_I2C_WR |
6 | movi r1, REG_I2C_1_TXDR |
7 | exporti r0, r1 ; r0 -> (r1) |
8 | movi r0, I2C_STRT_WR |
9 | movi r1, REG_I2C_1_CMDR ; Drive Slave Address - Write |
10 | exporti r0, r1 ; r0 -> (r1) |
11 | call wait_for_i2c_trrdy |
12 | |
13 | movi r0, ADR_I2C_TEMP |
14 | movi r1, REG_I2C_1_TXDR |
15 | exporti r0, r1 ; r0 -> (r1) |
16 | movi r0, I2C_WR |
17 | movi r1, REG_I2C_1_CMDR ; Send Register Address |
18 | exporti r0, r1 ; r0 -> (r1) |
19 | call wait_for_i2c_trrdy |
20 | |
21 | movi r0, ADR_I2C_RD |
22 | movi r1, REG_I2C_1_TXDR |
23 | exporti r0, r1 ; r0 -> (r1) |
24 | movi r0, I2C_STRT_WR |
25 | movi r1, REG_I2C_1_CMDR ; Drive Slave Address - Read |
26 | exporti r0, r1 ; r0 -> (r1) |
27 | call wait_for_i2c_srw |
28 | |
29 | movi r0, I2C_RD |
30 | movi r1, REG_I2C_1_CMDR ; request data from slave |
31 | exporti r0, r1 ; r0 -> (r1) |
32 | |
33 | call wait_for_i2c_trrdy |
34 | movi r1, REG_I2C_1_RXDR ; Get Read Data 1 |
35 | importi r24, r1 ; r24 <- (r1) |
36 | |
37 | movi r0, I2C_RD_NACK_STP ; --- REAL-TIME REQUIREMENT --- |
38 | movi r1, REG_I2C_1_CMDR ; request last data byte from slave |
39 | exporti r0, r1 ; r0 -> (r1) |
40 | |
41 | call wait_for_i2c_trrdy |
42 | movi r1, REG_I2C_1_RXDR ; Get Read Data 2 |
43 | importi r25, r1 ; r25 <- (r1) |
44 | |
45 | mov r2, r24 ; move to r2, r3 for return values |
46 | mov r3, r25 |
47 | |
48 | setz |
49 | |
50 | ret |
Holger schrieb: > Ich poste noch den Reg-Satz von dem Hardened Port I2C-Port #1 $40..$49, > bzw. $4A .. $53 I2C Secondary Port.(#2). > Address Mapping. Tipp: Mach das mal als aktiv "Master am "primary I2C-Bus Port. Deine Source ist für das secondary I2C-Bus Port, und Slave mode. ------------------------------------------------------------------------ -- ------------------------------------------------------------------------ -- Der 6-Pinnige TMP101NA/250 von TI Burr-Brown Temperatur Sensor hat Addr: 1001010, wenn Pin-5 an 'HIGH liegt. Fazit: Also somit der I2C-Bus-Addresss-Trigger bei ($4A). ist somit binär 100_1010 Das Datenblatt von TI ist mit dem Sromlaufplan von dem Machxo2 Pico Board via I2C-Addr schon mal konform. ------------------------------------------------------------------------ - Das mit dem internen Oscillator via I2C-Bus is tricky gemacht. Damit wird die Stromaufnahme von dem PICO Board als Standallone Coin Cell Bat.App erst möglich. ------------------------------------------------------------------------ - Trap: Mit den I2C-Bus-Addresss-Trigger via Machxo2 im "Slave "mode, geht nur ein feste Adresse z.B $09 an primary Port, bzw. $0A an secondary Port. Die Machxo2-Pinne im primary I2C-Port sind fest, via Hardened Core vorgegeben, auch mit ext. Pull-Up ect. Der dedizierte I2C-Port-Pin() ist somit tristate,bidir,Open-Drain.... ------------------------------------------------------------------------ - Viel Erfolg bei den MachXo2 Pico Project. Gruss Holger.
Hallo, vielen Dank für eure Antworten. Ich werde versuchen deine Lösung nachzuprogrammieren. Ich verwende das Lattice Breakout Board. Super Support.
lattice_user schrieb: > Ich verwende das Lattice Breakout Board. Damit sollte das gehen, wenn du einen aktiven Master via EFB damit machst. Die Simulation ist damit auch möglich. Duch den aktiven Master wird das Modell einfacher zu duchschauen. Gruss Holger. Die Bilder im Anhang: Register und Wish-Bone Bus. Asm Befehle. Export ist schreiben auf den Wish-Bone Bus via Mico8 Code. Import ist lesen auf den Wish-Bone Bus via Mico8 Code. Obigen Anhang: http://www.mikrocontroller.net/attachment/222781/Environment_Scanning.asm.bak
1 | ; Ich habe dem Code aus dem Obigen Anhang rausgeholt, |
2 | ; der Code ist also fuer Master-Mode. |
3 | ; Auf dem Lattice Pico Board befindet sich ein I2C-Bus Sensor. |
4 | ; |
5 | ; Achtung: |
6 | ; 6 PIN-iger TMP101NA/250 von TI oder Burr Brown IC |
7 | ; TEMPERATUR-SENSOR. |
8 | ; Achtung: PIN 5 des Sensors ist an HIGH zu legen, somit ist die |
9 | ; 7Bit Slave-Trigger-Arddess: 100_10_10 binary aktiv festgelegt. |
10 | ; Der Sensor hat daraufhin die 7Bit-Adresse 100_10_10, ist also (0x4A) |
11 | ; bingo>. |
12 | ; Dieses Bit-Muster wird also im Master-Mode, in das |
13 | ; sogenannte REG_I2C_1_TXDR = Transmit-(Data-Reg) “uebertragen“. |
14 | |
15 | ; Achtung: Im I2C-Master-Mode-“Write-Mode“ |
16 | ; Dazu muss man das obige 7Bit-Muster 1 mal nach links schieben, und eine Null “ankleben“. |
17 | ; Fazit: Die Null am Ende ist der I2C-Bus-Write-Mode. |
18 | |
19 | Fazit: |
20 | ;; Symbol-Address-Tabelle für den Temperatur-Sensor : |
21 | ;; Fazit: .equ ADR_I2C_WR, 0x94 ; $4A => 100_10_10 + Write_0 |
22 | ;; Fazit .equ ADR_I2C_RD, 0x95 ; 100_10_10_(1), ist Read-Mode. |
23 | ; I2C-Bus-Write-Mode-prepare: REG_I2C_1_TXDR also Transmit-(Data-Reg) |
24 | ; Dann steht im 8 Bit Transmit-(Data-Register) das Bitmuster 100_10_10_0 also 10010100b . |
25 | ; Fazit: Damit steht der Inhalt von [0x94] im 8 Bit Transmit-(Data-Register), |
26 | ; und wird nun mit dem |
27 | ; Befehl: I2C_STRT_WR, also (0x90) via REG_I2C_1_CMDR (Command-Register) ab-gesendet. |
28 | ; Der Befehl I2C_STRT_WR ist ein Bitkombination von START + WR, also 0x80 und 0x10 => (0x90) |
29 | ; Siehe Tabelle: 17.5. |
30 | ; Danach wird der call-Aufruf: call wait_for_i2c_rdy aktiv, der pollt das I2C-Status-Reg, |
31 | ; und zwar das Bit 4 also TRRDY. |
32 | ; Siehe Tabelle 17.9 |
33 | ; |
34 | ; |
Hier die i2c_101_config_device codes für den TMP101NA/250 Sensor, im I2C_Master Mode. via i2c_101_config_device:
1 | ; init i2c 101_temperatur_device_1 im I2C-Master Mode |
2 | i2c_101_config_device: |
3 | movi r0, ADR_I2C_WR ; .equ ADR_I2C_WR, 0x94 ; $4A => 100_10_10 + Write_0 --> 0x94 |
4 | movi r1, REG_I2C_1_TXDR ; load Tx register with I2C address - Write [0x94] |
5 | exporti r0, r1 ; r0 -> (r1) |
6 | movi r0, I2C_STRT_WR ; .equ I2C_STRT_WR, 0x90 |
7 | movi r1, REG_I2C_1_CMDR ; Command i2c master to transmit data in Tx register |
8 | exporti r0, r1 ; r0 -> (r1) |
9 | call wait_for_i2c_rdy ; @Status mask: 0X04 REG_I2C_1_SR ; read Status Register |
10 | |
11 | movi r0, ADR_I2C_CFG ;.equ ADR_I2C_CFG, 0x01 ; TI-Sensor Data_1 |
12 | movi r1, REG_I2C_1_TXDR ; (0000_0001) 0x01 |
13 | exporti r0, r1 ; r0 -> (r1) |
14 | movi r0, I2C_WR ; solo write + Ack |
15 | movi r1, REG_I2C_1_CMDR ; Send Register Address 0x01 |
16 | exporti r0, r1 ; r0 -> (r1) |
17 | call wait_for_i2c_rdy ; @Status mask: 0X04 REG_I2C_1_SR ; read Status Register |
18 | |
19 | movi r0, 0x20 ; # Set config for 1/4ths resolution |
20 | movi r1, REG_I2C_1_TXDR ; (0010_0000) 0x20 |
21 | exporti r0, r1 ; r0 -> (r1) |
22 | movi r0, I2C_WR ; solo write + Ack |
23 | movi r1, REG_I2C_1_CMDR ; Send Register Data |
24 | exporti r0, r1 ; r0 -> (r1) |
25 | call wait_for_i2c_rdy ; @Status mask: 0X04 REG_I2C_1_SR ; read Status Register |
26 | |
27 | |
28 | movi r0, I2C_WR_STP ;.equ I2C_"WR"_(STP), 0x40 -<0100_0000, no_wrbit set, but 0 Ack_bit set |
29 | movi r1, REG_I2C_1_CMDR ; Command i2c master to STOP |
30 | exporti r0, r1 ; r0 -> (r1) |
31 | call wait_for_i2c_rdy ; @Status mask: 0X04 REG_I2C_1_SR ; read Status Register |
32 | ret |
Im I2C-Master-Mode´call wait_for_i2c_rdy
1 | wait_for_i2c_trrdy: ; use for 01A silicon |
2 | ;---------------------- |
3 | ; passed in: |
4 | ; none |
5 | ; passed out; |
6 | ; R20 : WD error if non-zero |
7 | ; other registers used: |
8 | ; R0, R1, R15 |
9 | ; (R21, R22 : WD routine) |
10 | ;---------------------- |
11 | movi r15, EFB |
12 | movi r20, 0x00 ; clear error flag |
13 | i2c_trrdy_loop: |
14 | movi r1, REG_I2C_1_SR ; read Status Register |
15 | importi r0, r1 ; r0 <- (r1) |
16 | andi r0, 0x04 ; Mask out all but TRRDY bit |
17 | cmpi r0, 0x04 |
18 | bz i2c_trrdy_no_error ; TRRDY true, exit loop |
19 | call WD_delay |
20 | addi r20, 0x01 |
21 | cmpi r20, 0xFF |
22 | bnz i2c_trrdy_loop ; loop until timeout |
23 | b i2c_trrdy_exit |
24 | i2c_trrdy_no_error: |
25 | movi r20, 0x00 ; clear error flag |
26 | i2c_trrdy_exit: |
27 | ret |
Holger schrieb: > Damit sollte das gehen, wenn du einen aktiven Master via EFB damit > machst. Obigen Anhang: Env_I2C_Scanning.asm Reduziert auf nur das I2C-Bus interface am primaray Port. Mit externen Pull-Ups an deinem Break-Out Port, sollte der Mastermode die Pinne I2C-CLK u. I2C-DATA aktiv machen. Also via Scope messen. Gruss Holger. Hier noch das sniplet für Enable Routine via 0x80 in Controll-Register. Sonst ist der I2C-Core nicht aktiv via I/O Pinning.
init_i2c: ; init EFB i2c module ; EFB address space exceeds 32 locations, so must use indirect addressing (importi/exporti) movi r15, EFB movi r0, VAL_I2C_CLKDIV ; movi r1, REG_I2C_1_BR0 ; Set clock divider LSB exporti r0, r1 ; r0 -> (r1) movi r0, 0x00 ; movi r1, REG_I2C_1_BR1 ; Set clock divider MSB exporti r0, r1 ; r0 -> (r1) ;enable the i2c_primary core movi r0, 0x80 ; 1000_0000 movi r1, REG_I2C_1_CR ; Enable I2C primary in (Controll_(Reg exporti r0, r1 ; r0 -> (r1) ; to do: send STOP+NACK in command REG_I2C_1_CMDR set_Command 0100_10xx ; movi r0, 0x00 ; movi r1, REG_I2C_1_IRQEN ; Disable I2C interrupts exporti r0, r1 ; r0 -> (r1) movi r0, 0x00 ; 0000_0001xx movi r1, REG_I2C_1_CMDR ; Disable clock stretching, enable ACK exporti r0, r1 ; r0 -> (r1) ;START routine ; call wait_for_i2c_not_busy
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.