Hi all,
I'm trying to connect to the UBLOX M8Q MAX using the I2C on my SAMD21.
The address of this module is 0x42 and there are only a minimum needed. 0xFD, 0xFE and 0xFF from what i got out of the U-blox datasheet.
Currently I'm unable to setup the proper I2C master connecting.
After the setup of the master I have tried several write or read functions.
There are 3 of them included in the code
< #include "sam.h" #include "tmr.h" #include <stdlib.h> #include <stdint.h> #include <stdbool.h> #define I2C_SERCOM_PORT_PMUX PORT_PMUX_PMUXE_C_Val #define I2C_SERCOM_PINS_PORT_GROUP 0 #define I2C_SERCOM_SDA_PIN PORT_PA16 #define I2C_SERCOM_SCL_PIN PORT_PA17 #define I2C_SERCOM SERCOM1 #define I2C_SERCOM_APBxMASK PM_APBCMASK_SERCOM1 #define I2C_SERCOM_GCLK_ID_CORE SERCOM1_GCLK_ID_CORE #define I2C_SERCOM_CLK_GEN 0 #define I2C_SERCOM_IRQ_HANDLER SERCOM1_Handler #define I2C_SERCOM_IRQn SERCOM1_IRQn #define Baudrate 57600 #define Clockfreq 8000000 #define FAST_MODE 0x0 #define GPS_ADR 0x42 #define BUF_SIZE 3 uint8_t gpsreg = 0xFD; uint8_t tx_buf[BUF_SIZE] = {1, 2, 3}; uint8_t rx_buf[BUF_SIZE]; uint8_t i; volatile bool tx_done = false, rx_done = false; enum { I2C_TRANSFER_WRITE = 0, I2C_TRANSFER_READ = 1, }; void SERCOM1_Handler(void) { if(I2C_SERCOM->I2CM.INTFLAG.bit.MB) { if(i == BUF_SIZE) { I2C_SERCOM->I2CM.CTRLB.bit.CMD = 0x3; while(I2C_SERCOM->I2CM.SYNCBUSY.bit.SYSOP); tx_done = true; i=0; } else { I2C_SERCOM->I2CM.DATA.reg = tx_buf[i++]; while(I2C_SERCOM->I2CM.SYNCBUSY.bit.SYSOP); } } if(I2C_SERCOM->I2CM.INTFLAG.bit.SB) { if(i == (BUF_SIZE - 1)) { I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT; while(I2C_SERCOM->I2CM.SYNCBUSY.bit.SYSOP); I2C_SERCOM->I2CM.CTRLB.bit.CMD = 0x3; while(I2C_SERCOM->I2CM.SYNCBUSY.bit.SYSOP); rx_buf[i++] = I2C_SERCOM->I2CM.DATA.reg; while(I2C_SERCOM->I2CM.SYNCBUSY.bit.SYSOP); rx_done = true; } else { I2C_SERCOM->I2CM.CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; while(I2C_SERCOM->I2CM.SYNCBUSY.bit.SYSOP); rx_buf[i++] = I2C_SERCOM->I2CM.DATA.reg; while(I2C_SERCOM->I2CM.SYNCBUSY.bit.SYSOP); I2C_SERCOM->I2CM.CTRLB.bit.CMD = 0x2; while(I2C_SERCOM->I2CM.SYNCBUSY.bit.SYSOP); } } } void I2C_Init(void) { while(I2C_SERCOM->I2CM.SYNCBUSY.bit.ENABLE); I2C_SERCOM->I2CM.CTRLA.bit.ENABLE = 0; while(I2C_SERCOM->I2CM.SYNCBUSY.bit.SWRST); /* Perform a software reset */ I2C_SERCOM->I2CM.CTRLA.bit.SWRST = 1; /* Wait for synchronization */ while(I2C_SERCOM->I2CM.CTRLA.bit.SWRST); /* Wait for synchronization */ while(I2C_SERCOM->I2CM.SYNCBUSY.bit.SWRST || I2C_SERCOM->I2CM.SYNCBUSY.bit.ENABLE); //Using the WRCONFIG register to bulk configure both for being configured the SERCOM2 SDA and SCL pins PORT->Group[I2C_SERCOM_PINS_PORT_GROUP].WRCONFIG.reg = PORT_WRCONFIG_WRPINCFG| //Enables the configuration of PINCFG PORT_WRCONFIG_WRPMUX | //Enables the configuration of the PMUX for the selected pins PORT_WRCONFIG_PMUXEN | //Enables the PMUX for the pins PORT_WRCONFIG_PMUX(I2C_SERCOM_PORT_PMUX) | //Bulk configuration for PMUX PORT_WRCONFIG_PINMASK( I2C_SERCOM_SDA_PIN | I2C_SERCOM_SCL_PIN); //Selecting which pins are getting bulk configured PM->APBCMASK.reg |= I2C_SERCOM_APBxMASK; //Enable the SERCOM under the PM GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(I2C_SERCOM_GCLK_ID_CORE) | //Provide necessary clocks to the peripheral GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(I2C_SERCOM_CLK_GEN); I2C_SERCOM->I2CM.CTRLA.reg = SERCOM_I2CM_CTRLA_MODE_I2C_MASTER; // I2C_SERCOM->I2CM.CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN; //Configure I2C in SMART mode (will automatically ACK after reading buffer) I2C_SERCOM->I2CM.CTRLA.bit.INACTOUT = SERCOM_I2CM_CTRLA_INACTOUT(0); uint16_t BAUD_REG = ((float)Clockfreq / (float)(2 * Baudrate)) - 1; I2C_SERCOM->I2CM.BAUD.bit.BAUD = BAUD_REG; while (I2C_SERCOM->I2CM.SYNCBUSY.bit.ENABLE); //Wait for SYNCBUSY bit before enabling peripheral I2C_SERCOM->I2CM.CTRLA.reg |= SERCOM_I2CS_CTRLA_ENABLE; //Enable the peripheral } bool i2c_write(uint8_t *data, int size) { I2C_SERCOM->I2CM.ADDR.reg = SERCOM_I2CM_ADDR_ADDR(GPS_ADR); // while (0 == (I2C_SERCOM->I2CM.INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB)); if (I2C_SERCOM->I2CM.STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) { I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); return false; } for (int i = 0; i < size; i++) { I2C_SERCOM->I2CM.DATA.reg = data[i]; while (0 == (I2C_SERCOM->I2CM.INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB)); if (I2C_SERCOM->I2CM.STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) { I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); return false; } } I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); return true; } bool i2c_read(uint8_t *data, int size) { I2C_SERCOM->I2CM.ADDR.reg = GPS_ADR | I2C_TRANSFER_READ; while (0 == (I2C_SERCOM->I2CM.INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB)); if (I2C_SERCOM->I2CM.STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) { I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); //dbg_log("I2C: RXNACK during read (address)\r\n"); return false; } I2C_SERCOM->I2CM.CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; for (int i = 0; i < size-1; i++) { data[i] = I2C_SERCOM->I2CM.DATA.reg; while (0 == (I2C_SERCOM->I2CM.INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB)); } if (size) { I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT; I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); data[size-1] = I2C_SERCOM->I2CM.DATA.reg; } return true; } void i2c_master_transaction(void) { i = 0; I2C_SERCOM->I2CM.CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; while(I2C_SERCOM->I2CM.SYNCBUSY.bit.SYSOP); I2C_SERCOM->I2CM.ADDR.reg = (GPS_ADR << 1) | I2C_TRANSFER_WRITE; while(!tx_done); i = 0; I2C_SERCOM->I2CM.CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; while(I2C_SERCOM->I2CM.SYNCBUSY.bit.SYSOP); I2C_SERCOM->I2CM.CTRLB.reg = (GPS_ADR << 1) | I2C_TRANSFER_READ; while(!rx_done); I2C_SERCOM->I2CM.INTENCLR.reg = SERCOM_I2CM_INTENCLR_MB | SERCOM_I2CM_INTENCLR_SB; } int main(void) { /* Initialize the SAM system */ SystemInit(); TMR_Init(); I2C_Init(); i2c_master_transaction(); //uint8_t buffer[256]; //uint8_t gpsreg = 0xFD; /* Replace with your application code */ while (1) { i2c_write(gpsreg, 1); i2c_read(gpsreg, 1); } } >