Forum: Mikrocontroller und Digitale Elektronik Atmel SAM TWI Peripherie auf JTAG Pin nutzen


von Michael (Gast)


Lesenswert?

Hallo, habe hier ein SAM4E-EK auf dem ich bereits den TWI0 ohne Probleme 
nutzen kann. Allerdings brauche ich für meine Hardware zwingend auch den 
zweiten I2C (TWI1) vom Controller. Dieser liegt wie der TWI0 auf 
Peripheral A.
PIN = Peripherie A = SYSIO
PB4 = TWD1 (TWI Daten) = TDI (JTAG) und
PB5 = TWCK1 (TWI CLK) = TDO/TRACESWO.

Da ich über den SAM ICE Debugge habe ich mich dann für Serial Debugwire 
entschieden, da hier die Pins TDI und TDO scheinbar unbenutzt sind. Um 
auf Nummer sicher zu gehen habe ich einen weiteren 20Pol 
Pfostenverbinder ohne Pin 5 und 13 (TDI und TDO) auf den SAM ICE 
gepresst, damich diese Leitungen wirklich getrennt sind zum Debugger.

Wenn ich die Portpins, wie auch schon bei TWI0, Peripheri A zuweise 
bleibt der PB5 Pin low. Beide Pins (PB5/PB4) haben einen Pullup nach 
VCC.

Einziges Problem in meinen Augen kann eigentlich nur noch der TRACESWO 
sein, der ja an der TPIU hängt. Da gucke ich aber nicht durch wie ich 
den konkret abschalten soll. Wenn ich einmal über den SAM ICE Debugge 
(20Pol verbindung gesteckt) ist der Pin low, dann zieh ich z.B. den 
Debugge, resette den MC und der Pin liegt hoch, aber der I2C macht 
nichts und Debuggen kann ich ja in dem Moment logischer Weise nicht.

Habt ihr noch irgendwelche Tips wie ich den TWI1 ebenfalls nutzen kann? 
Chip ist der SAM4E16E. Irgendwie sind die Pins nicht wirklich an 
Peripherie A.

von Thomas F. (tomasf)


Lesenswert?

Die entsprechenden Debugfunktionen müssen in der Applikation erst 
abgeschaltet werden.

Auf einem SAM4S sieht das so aus:
1
MATRIX->CCFG_SYSIO |= (1 << 4) | (1 << 5);

Auf dem SAM4E müsste das auch so gehen.

Debuggen geht dann noch über SWD (nur die beiden SWD-Leitungen).

von Michael (Gast)


Lesenswert?

Danke dir, das war zummindest ein Schritt in die richtige Richtung.
Habe auch den entsprechenden Absatz im Datenblatt gefunden.
1
26.9 System I/O Configuration
2
The System I/O Configuration register (CCFG_SYSIO) allows to configure some I/O lines in System I/O mode (such as
3
JTAG, ERASE, USB, etc...) or as general purpose I/O lines. Enabling or disabling the corresponding I/O lines in
4
peripheral mode or in PIO mode (PIO_PER or PIO_PDR registers) in the PIO controller as no effect. However, the
5
direction (input or output), pull-up, pull-down and other mode control is still managed by the PIO controller.

Trotzdem will der TWI1 immer noch nicht. Im Prinziep habe ich die 
gleiche Vorhergehensweise wie bei TWI0 durchlaufen (Ich nutze übrigens 
das ASF).

Pin Configuration ist
1
MATRIX->CCFG_SYSIO |= (1 << 4) | (1 << 5); //Disable SYSIO
2
ioport_set_pin_peripheral_mode(TWI1_DATA_GPIO, TWI1_DATA_FLAGS);
3
ioport_set_pin_peripheral_mode(TWI1_CLK_GPIO, TWI1_CLK_FLAGS);

TWI initialisiert
1
#define I2C_BUS1_ADDR_U5 0b0100000
2
3
twi_master_options_t opt_bus2 = {
4
    .speed = 300000,
5
    .chip  = I2C_BUS1_ADDR_U5
6
  };
7
8
  twi_master_setup(TWI1, &opt_bus2);

Datenpaket lesen
1
  uint8_t data_received[1];
2
  
3
    twi_package_t packet_read = {
4
      .addr         = {2},      // TWI Command
5
      .addr_length  = sizeof (uint8_t),    // TWI slave memory address data size
6
      .chip         = I2C_BUS1_ADDR_U5,      // TWI slave bus address
7
      .buffer       = data_received,        // transfer data destination buffer
8
      .length       = sizeof(data_received)                    // transfer data size (bytes)
9
    };
10
    
11
  while(twi_master_read(TWI1, &packet_read) != TWI_SUCCESS);

Nach der Initialisierung sind die Register gleich wie in TWI0.  Wenn ich 
die Datenleitungen PB4 und PB5 als output initialisieren und nicht dem 
TWI1 zuordne lassen diese sich auch High und Low schalten. Nur wenn der 
TWI1 den Pinnen zugeordnet ist, sind diese immer High. twi_master_read() 
hängt er sich in der Funktion auf und bekommt scheinbar kein 
TWI_SR_RXRDY.

Hier auch einmal die FUnktion (unverändert aus dem ASF):
1
uint32_t twi_master_read(Twi *p_twi, twi_packet_t *p_packet)
2
{
3
  uint32_t status, cnt = p_packet->length;
4
  uint8_t *buffer = p_packet->buffer;
5
  
6
  /* Check argument */
7
  if (cnt == 0) {
8
    return TWI_INVALID_ARGUMENT;
9
  }
10
11
  /* Set read mode, slave address and 3 internal address byte lengths */
12
  p_twi->TWI_MMR = 0;
13
  p_twi->TWI_MMR = TWI_MMR_MREAD | TWI_MMR_DADR(p_packet->chip) |
14
      ((p_packet->addr_length << TWI_MMR_IADRSZ_Pos) &
15
      TWI_MMR_IADRSZ_Msk);
16
17
  /* Set internal address for remote chip */
18
  p_twi->TWI_IADR = 0;
19
  p_twi->TWI_IADR = twi_mk_addr(p_packet->addr, p_packet->addr_length);
20
21
  /* Send a START Condition */
22
  p_twi->TWI_CR = TWI_CR_START;
23
24
  while (cnt > 0) {
25
    status = p_twi->TWI_SR;
26
    if (status & TWI_SR_NACK) {
27
      return TWI_RECEIVE_NACK;
28
    }
29
30
    /* Last byte ? */
31
    if (cnt == 1) {
32
      p_twi->TWI_CR = TWI_CR_STOP;
33
    }
34
35
    if (!(status & TWI_SR_RXRDY)) {
36
      continue;
37
    }
38
    *buffer++ = p_twi->TWI_RHR;
39
40
    cnt--;
41
  }
42
43
  while (!(p_twi->TWI_SR & TWI_SR_TXCOMP)) {
44
  }
45
46
  p_twi->TWI_SR;
47
48
  return TWI_SUCCESS;
49
}

Da das Ganze beim TWI0 super funktioniert schließe ich hier eigentlich 
den Fehler aus. Irgendwas muss noch mit meiner Peripheriezuweisung 
falsch sein. In der Funktion wird auch das TWI-MMR richtig beschrieben. 
Danach passiert nichts mehr in den Registern / in der Funktion.

Die PIO Statusregister PIO_PSR P4 und P5 sind auch auf 0 sodass sie der 
PIO_ABCDSR0 und 1 Peripherie zugeordnet werden. Hier sind alle Bits 0, 
also Peripherie A für den TWI.

von Thomas F. (tomasf)


Lesenswert?

Schwer zu sagen, wo der Fehler ist, wenn du den Code nur in Ausschnitten 
postest.

Schaltest du die Clock des TWI1 irgendwo ein?

in der Art:
1
pmc_enable_periph_clk(ID_TWI1);

von Michael (Gast)


Angehängte Dateien:

Lesenswert?

Danke für deine Hilfe Thomas, die Clock sollte aktiviert sein, habe sie 
auch nochmal expliziert über den PMC eingeschaltet -> keine Veränderung.

Ich habe auch für meine Übersicht nochmal ein neues Projekt (mit Vorlage 
für das SAM4E-EK Board) angelegt, den TWI Service über den ASF 
hinzugefügt und in der init.c den TWI1 definiert:
1
#ifdef CONF_BOARD_TWI1
2
MATRIX->CCFG_SYSIO |= (1 << 4) | (1 << 5);
3
ioport_set_pin_peripheral_mode(TWI1_DATA_GPIO, TWI1_DATA_FLAGS);
4
ioport_set_pin_peripheral_mode(TWI1_CLK_GPIO, TWI1_CLK_FLAGS);
5
#endif

Ansonsten ist die Source unangetastet. Alles Andere ist in der Main 
passiert:
1
#include <asf.h>
2
3
#define I2C_BUS1_ADDR_U5 0b0100000
4
5
int main (void)
6
{
7
  board_init();
8
  
9
  sysclk_init();
10
  
11
  pmc_enable_periph_clk(ID_TWI1);
12
  
13
   twi_master_options_t opt = {
14
     .speed = 50000,
15
     .chip  = I2C_BUS1_ADDR_U5
16
   };
17
18
   twi_master_setup(TWI1, &opt);
19
20
   uint8_t data_received[1];
21
22
   twi_package_t packet_read = {
23
     .addr         = {2},      // TWI slave memory address data
24
     .addr_length  = sizeof (uint8_t),    // TWI slave memory address data size
25
     .chip         = I2C_BUS1_ADDR_U5,      // TWI slave bus address
26
     .buffer       = data_received,        // transfer data destination buffer
27
     .length       = sizeof(data_received)                    // transfer data size (bytes)
28
   };
29
   // Perform a multi-byte read access then check the result.
30
   while(twi_master_read(TWI1, &packet_read) != TWI_SUCCESS);
31
   
32
   while(1);
33
34
  // Insert application code here, after the board has been initialized.
35
}

Das ganze Projekt ist auch als .zip angehängt.

Auch hier sind beide TWI Leitungen permanent high und er hängt in der 
twi_master_read().

von Thomas F. (tomasf)


Lesenswert?

>
1
> 
2
>    twi_master_options_t opt = {
3
>      .speed = 50000,
4
>      .chip  = I2C_BUS1_ADDR_U5
5
>    };
6
>

Das ist auf jeden Fall problematisch. twi_master_options_t liegt bei dir 
auf dem Stack und du initialisierst nicht alle Felder. Da steht dann 
also Müll drin. Da fehlt so was in der Art:
1
.smbus = 0;
2
.master_clk = sysclk_get_peripheral_bus_hz(TWI1);

von Michael (Gast)


Lesenswert?

Nein, ich fasse es nicht. Es passiert etwas an den Pinnen was im ersten 
Augenblick nach I2C ausschaut. Super.. Den Rest kann ich leider erst 
morgen genauer betrachten. Der Wahnsinn. Es scheint wirklich an 
irgendeinem Müll im Speicher gelegen zu haben.

Wirklich super vielen lieben Dank Thomas. Ich hab mir wirklich schon 
einen Wolf gesucht. War kurz davor einen Multiplexer zu integrieren um 
nur den TWI0 zu nutzen.

von Thomas F. (tomasf)


Lesenswert?

Das ist eine Stolperstelle, die sich durch die ganze ASF-Doku zieht. Zum 
Konfigurieren eines Moduls werden immer Strukturen genommen und diese 
sind in den Beispielen immer global definiert und oft eben nur teilweise 
initialisiert. Dann denkt man sich, dass sieht in einer Funktion viel 
schöner aus und schon sucht man 2 Tage den Fehler.

> War kurz davor einen Multiplexer zu integrieren um
> nur den TWI0 zu nutzen.

TWI ist ist ja aber eigentlich schon ein Bus, an dem mehrere devices 
hängen können oder hast du zwei devices mit den gleichen, nicht 
änderbaren, Adressen?

von Michael (Gast)


Lesenswert?

Genau das habe ich mir auch gedacht bei dem ASF. Es ist auch tatsächlich 
das erste Mal für mich wo ich mit dem ASF arbeite. Habe lange überlegt 
ob ich den Weg nach wie vor zu fuß gehe oder nicht. Letztendlich 
versuche ich mich nun mit dem ASF, da ich später noch SD + FAT + evtl. 
Ethernet benötige und ich mir hierdurch etwas weniger Aufwand und 
Fehlerquellen erhoffe.
Wieder was gelernt, sich die Strukturen genauer anzuschauen und sich 
nicht auf die Beispiel Doku zu verlassen.

Zum I2C. Habe ziemlich viele Ein- und Ausgabe-Bausteine (PCA9555PW) auf 
der Hardware. Zum einen reichen hier die 3 Adressbits nicht aus und zum 
Anderen habe ich einen Bus gedacht für Eingabelemente, der relativ 
zeitnah übertragen soll und an dem Anderen Bus sind die etwas 
zeitunkretischen Dinge, wie Anzeigeelemente angeschlossen.

von Thomas F. (tomasf)


Lesenswert?

Die ASF ist wohl besser als ihr Ruf und bei den ARMs kommt man wohl auch 
nicht mehr drum herum. Jedenfalls solange sie gewünschte 
Funktionalitäten abdeckt. Gerade das TWI-Modul ist da etwas rudimentär, 
es unterstützt keine interrupt-basierten Abläufe.
Für einfache Sachen, zB. Konfiguration eines PWMs, hat die ASF genau die 
Funktionen, die man sich ansonsten selber schreiben würde.

von Helmut W. (upm)


Angehängte Dateien:

Lesenswert?

Hallo liebe Gemeinde,


ich habe versucht das Beispiel von Michael auf TWI0 anzupassen ohne 
Erfolg.
Ich habe es als .zip in den Anhang gepackt vielleicht kann mir jemand 
helfen. Ich nutze einen ATSAM4E8C. Vielen Dank

VG

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.