Forum: Mikrocontroller und Digitale Elektronik sercom i2c samd09


von Patrick S. (patricksch)


Lesenswert?

Hallo zusammen

Ich benutze einen SAMD09D14 und habe es geschafft das SERCOM USART 
Module ohne ASF zu benutzen. Beim I2C scheitert es allerdings, da ich 
auf den Pins überhaupt keine Signale bekomme.

Kann mir wer hier weiterhelfen?
Hier der i2C init:

/* port mux configuration*/
PORT->Group[0].PINCFG[PIN_PA22].reg = PORT_PINCFG_PMUXEN; /* SDA */
PORT->Group[0].PINCFG[PIN_PA23].reg = PORT_PINCFG_PMUXEN; /* SCL */

/*PMUX: even = n/2, odd: (n-1)/2 */
PORT->Group[0].PMUX[PIN_PA22/2].reg = 0x02;
PORT->Group[0].PMUX[PIN_PA23/2].reg = 0x20;

/* APBCMASK */
PM->APBCMASK.reg |= PM_APBCMASK_SERCOM1;

/*gclk configuration for sercom1 module*/
GCLK->CLKCTRL.reg =  GCLK_CLKCTRL_ID (SERCOM1_GCLK_ID_CORE) |
            GCLK_CLKCTRL_GEN(0) |
            GCLK_CLKCTRL_CLKEN;

/* set configuration for SERCOM1 I2C module */
SERCOM1->I2CM.CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN; /* smart mode enable 
*/
while (SERCOM1->I2CM.SYNCBUSY.reg);

/* Set baudrate */
uint32_t fgclk    = 8000000;  /* 8MHz */
uint32_t fscl    = 100000; /* 100kHz SCL */
uint32_t trise    = 215; /* 215 ns rising time */
int32_t numerator  = fgclk - fscl*(10 + fgclk*trise/1000000000);
int32_t denominator  = 2*fscl;
int32_t tmp_baud = (int32_t)(div_ceil(numerator, denominator));
SERCOM1->I2CM.BAUD.bit.BAUD = SERCOM_I2CM_BAUD_BAUD(tmp_baud);
while (SERCOM1->I2CM.SYNCBUSY.reg);

/* enable module */
SERCOM1->I2CM.CTRLA.reg =  SERCOM_I2CM_CTRLA_ENABLE | 
SERCOM_I2CM_CTRLA_MODE_I2C_MASTER |  /* i2c master mode */
SERCOM_I2CM_CTRLA_SDAHOLD(3);    /* SDA hold time to 600ns */
while (SERCOM1->I2CM.SYNCBUSY.reg);

SERCOM1->I2CM.STATUS.reg |= SERCOM_I2CM_STATUS_BUSSTATE(1); /* set to 
idle state */
while (SERCOM1->I2CM.SYNCBUSY.reg);

von Marco H. (damarco)


Lesenswert?

1
/*PMUX: even = n/2, odd: (n-1)/2 */
2
PORT->Group[0].PMUX[PIN_PA22/2].reg = 0x02;
3
PORT->Group[0].PMUX[PIN_PA23/2].reg = 0x20;

Da wird wohl das Pinmux falsch sein.  Auf Peripheral C ist korrekt.

von Patrick S. (patricksch)


Lesenswert?

A = 0x00
B = 0x01
C = 0x02
usw. der Pinmux sollte also stimmen

Habe aber mittlerweilen diese Zeilen umgeschrieben auf:
PORT->Group[0].PMUX[PIN_PA22/2].bit.PMUXO = 0x02;
PORT->Group[0].PMUX[PIN_PA23/2].bit.PMUXE = 0x02;

von chris_ (Gast)


Lesenswert?

1
PORT->Group[0].PMUX[PIN_PA22/2].reg = 0x02;
2
PORT->Group[0].PMUX[PIN_PA23/2].reg = 0x20;
22/2=11
23/2=11,5

Falls ich mich nicht täusche, setzt Du mit der zweiten Zeile den ersten 
Mux wieder auf 0.
Es sollte also nur eine Zeile sein:
1
PORT->Group[0].PMUX[PIN_PA22/2].reg = 0x22;

von Patrick S. (patricksch)


Lesenswert?

Hab ich in meinem zweiten Post dann schon ausgebessert, das ist aber 
hier leider nicht das Problem.

von chris_ (Gast)


Lesenswert?

Hast Du Pull-Up-Widerstände in den Leitungen?

Hier habe ich noch eine Application-Note mit Beispielen für den SAMD21 
gefunden:
https://www.google.de/url?sa=t&rct=j&q=&esrc=s&source=web&cd=4&cad=rja&http://www.atmel.com/Images/Atmel-42631-SAM-D21-SERCOM-I2C-Configuration_ApplicationNote_AT11628.pdf

von chris_ (Gast)


Lesenswert?


von Patrick S. (patricksch)


Lesenswert?

Vielen Dank für den Link.
Müsste ich eigentlich nicht schon was an den Pins sehen, nachdem ich

SERCOM1->I2CM.ADDR.reg = (0x29 << 1) | I2C_TRANSFER_WRITE;

schreibe?

von Patrick S. (patricksch)


Lesenswert?

Nicht, wenn man nicht genügend Pullup Widerstand hat:)

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.