/* P9_4.c - Test I2C burst read with DS1337 * * This program initializes the SERCOM1 as I2C and continuously * reads all the time registers of the DS1337 using burst reads. * Register 0 contains the second count. The clock is powered-up * enabled and the second count is incrementing. The bit 0 is * used to turn on and off the LED0 of the SAMD21 Xplained Pro * board. The LED0 should blink every second. * PA16 = SDA, PA17 = SCL * No errors or acknowledgement are checked. * * Tested with Atmel Studio 7 v7.0.1006 and Keil MDK-ARM v5.21a. */ #include "samd21.h" unsigned char* ARRAY_PORT_PINCFG0 = (unsigned char*)®_PORT_PINCFG0; unsigned char* ARRAY_PORT_PMUX0 = (unsigned char*)®_PORT_PMUX0; #define SLAVE_ADDR 0x68 /* 1101 000. DS1337 */ void I2C2_init(void) ; int I2C2_burstRead(char saddr, char maddr, int byteCount, char* data); void delayMs(int n); int main (void) { char timeDateReadback[7]; I2C2_init(); REG_PORT_DIRSET1 = 0x40000000; /* make PB30 output */ while (1) { I2C2_burstRead(SLAVE_ADDR, 0, 7, timeDateReadback); if (timeDateReadback[0] & 1) REG_PORT_OUTCLR1 = 0x40000000; else REG_PORT_OUTSET1 = 0x40000000; delayMs(10); } } void I2C2_init(void) { REG_PM_APBCMASK |= 0x00000008; /* SERCOM1 bus clock */ GCLK->CLKCTRL.reg = 0x4015; /* SERCOM1 core clock */ ARRAY_PORT_PINCFG0[16] |= 1; /* allow pmux to set PA16 pin configuration */ ARRAY_PORT_PINCFG0[17] |= 1; /* allow pmux to set PA17 pin configuration */ ARRAY_PORT_PMUX0[8] = 0x22; /* PA16 = SDA, PA17 = SCL */ REG_SERCOM1_I2CM_CTRLA = 1; /* reset SERCOM1 */ while (REG_SERCOM1_I2CM_CTRLA & 1) {} /* wait for reset to complete */ REG_SERCOM1_I2CM_CTRLA = 0x14; /* master mode */ REG_SERCOM1_I2CM_BAUD = 0; /* 1MHz main clock -> ~100KHz I2C clock */ REG_SERCOM1_I2CM_CTRLA |= 2; /* enable SERCOM1 */ REG_SERCOM1_I2CM_STATUS = 0x10; /* force idle */ } /* Read memory * read: S-(saddr+w)-ACK-maddr-ACK-R-(saddr+r)-ACK-data-ACK-data-ACK-...-data-NACK-P */ int I2C2_burstRead(char saddr, char maddr, int byteCount, char* data) { while((REG_SERCOM1_I2CM_STATUS & 0x30) != 0x10) ; /* wait until idle */ REG_SERCOM1_I2CM_ADDR = saddr << 1; /* send address */ while((REG_SERCOM1_I2CM_INTFLAG & 1) == 0); /* wait until saddr sent */ REG_SERCOM1_I2CM_DATA = maddr; /* send memory address */ while((REG_SERCOM1_I2CM_INTFLAG & 1) == 0); /* wait until maddr sent */ REG_SERCOM1_I2CM_ADDR = (saddr << 1) | 1; /* send restart with address */ for (; byteCount > 0; byteCount--) { while((REG_SERCOM1_I2CM_INTFLAG & 2) == 0); /* wait until data received */ *data++ = REG_SERCOM1_I2CM_DATA; /* read data */ if (byteCount > 1) REG_SERCOM1_I2CM_CTRLB = 0x20000; /* generate ack */ else { REG_SERCOM1_I2CM_CTRLB |= 0x40000; /* generate nack */ REG_SERCOM1_I2CM_CTRLB |= 0x30000; /* issue a stop */ } } return 0; } // delay n milliseconds (1MHz CPU clock) void delayMs(int n) { int i; for (; n > 0; n--) for (i = 0; i < 199; i++) __asm("nop"); }