ATSAMD21G18A I2C slave - Page 1
Forum section: electronics / general

author: WILDERNESSBAGEL
author_rank: Contributor
timestamp: February 01, 2022, 01:49:25 pm
content: Ok so I have a I2C master another ATSAMD21G18A but it uses arduino bootloder / code to drive the master. To learn how I2C works I wanted to write the slave on my own without the arduino code, however I am not doing something correctly. I know this is vague but before I start posting a bunch of code and asking someone to find the problem I want to check if there is a working bare bones slave implementation available that I could use as a guide and check with the datasheet what has and has not been used. The only thing I found is thishttps://www.avrfreaks.net/sites/default/files/forum_attachments/Atmel-42631-SAM-D21-SERCOM-I2C-Configura.pdf, however if I use this slave and an I2C scanner codehttps://playground.arduino.cc/Main/I2cScanner/to see if any slaves exist I get nothing. Any advice is appreciated

author: ataradov
author_rank: Super Contributor
timestamp: February 01, 2022, 05:23:21 pm
content: Here is a simple implementation. This one answers to two different addresses. It was taken from a real project, you can remote parts that deal with 2 addresses.

author: ataradov
author_rank: Super Contributor
timestamp: February 01, 2022, 05:27:40 pm
content: Here a bare minimum example. It sends an incrementing counter and ignores any received bytes.

author: WILDERNESSBAGEL
author_rank: Contributor
timestamp: February 02, 2022, 07:43:30 am
content: I tried this bare minimum example first but I still don't get anything when I run the scanner. I understand that it ignores any received bytes so maybe that's the reason. But I tried putting a print statement in the I2C_SERCOM_IRQ_HANDLER and it never gets printed. I used your samd21 starter to set up the UART, here is the code even tho it's basically your UART example with the copy pasted minimum example. But maybe I did something silly when putting them together.Code:/** Copyright (c) 2015, Alex Taradov <alex@taradov.com>* All rights reserved.** Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions are met:** 1. Redistributions of source code must retain the above copyright notice,* this list of conditions and the following disclaimer.* 2. Redistributions in binary form must reproduce the above copyright* notice, this list of conditions and the following disclaimer in the* documentation and/or other materials provided with the distribution.* 3. The name of the author may not be used to endorse or promote products* derived from this software without specific prior written permission.** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE* POSSIBILITY OF SUCH DAMAGE.*///-----------------------------------------------------------------------------#include <stdlib.h>#include <stdint.h>#include <stdbool.h>#include <string.h>#include "samd21.h"#include "hal_gpio.h"//-----------------------------------------------------------------------------#define PERIOD_FAST 100#define PERIOD_SLOW 500HAL_GPIO_PIN(UART_TX, B, 22)HAL_GPIO_PIN(UART_RX, B, 23)//-----------------------------------------------------------------------------HAL_GPIO_PIN(SDA, A, 8)HAL_GPIO_PIN(SCL, A, 9)#define I2C_BASE_ADDRESS 0x52// 8-bit address#define I2C_SERCOM SERCOM0#define I2C_SERCOM_PMUX HAL_GPIO_PMUX_C#define I2C_SERCOM_APBCMASK PM_APBCMASK_SERCOM0#define I2C_SERCOM_GCLK_ID SERCOM0_GCLK_ID_CORE#define I2C_SERCOM_IRQ_HANDLER irq_handler_sercom0#define I2C_SERCOM_IRQ SERCOM0_IRQn#define DelayTicks(ticks) {volatile uint32_t n=ticks; while(n--);}//takes 8 cycles#define DelayMs(ms) DelayTicks(MS_TO_DLYTICKS(ms))#define F_CPU 8000000#define CYCLES_IN_DLYTICKS_FUNC 8#define MS_TO_DLYTICKS(ms)(uint32_t)(F_CPU / 1000 * ms / CYCLES_IN_DLYTICKS_FUNC) // ((float)(F_CPU)) / 1000.0//-----------------------------------------------------------------------------static void timer_set_period(uint16_t i){TC3->COUNT16.CC.reg = (F_CPU / 1000ul / 256) * i;TC3->COUNT16.COUNT.reg = 0;}//-----------------------------------------------------------------------------void irq_handler_tc3(void){if (TC3->COUNT16.INTFLAG.reg & TC_INTFLAG_MC(1)){TC3->COUNT16.INTFLAG.reg = TC_INTFLAG_MC(1);}}//-----------------------------------------------------------------------------static void timer_init(void){PM->APBCMASK.reg |= PM_APBCMASK_TC3;GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(TC3_GCLK_ID) |GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);TC3->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_MFRQ |TC_CTRLA_PRESCALER_DIV256 | TC_CTRLA_PRESCSYNC_RESYNC;TC3->COUNT16.COUNT.reg = 0;timer_set_period(PERIOD_SLOW);TC3->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE;TC3->COUNT16.INTENSET.reg = TC_INTENSET_MC(1);NVIC_EnableIRQ(TC3_IRQn);}//-----------------------------------------------------------------------------static void uart_init(uint32_t baud){uint64_t br = (uint64_t)65536 * (F_CPU - 16 * baud) / F_CPU;HAL_GPIO_UART_TX_out();HAL_GPIO_UART_TX_pmuxen(PORT_PMUX_PMUXE_D_Val);HAL_GPIO_UART_RX_in();HAL_GPIO_UART_RX_pmuxen(PORT_PMUX_PMUXE_D_Val);PM->APBCMASK.reg |= PM_APBCMASK_SERCOM5;GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(SERCOM5_GCLK_ID_CORE) |GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);SERCOM5->USART.CTRLA.reg =SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_MODE_USART_INT_CLK |SERCOM_USART_CTRLA_RXPO(3/*PAD1*/) | SERCOM_USART_CTRLA_TXPO(1/*PAD0*/);SERCOM5->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN |SERCOM_USART_CTRLB_CHSIZE(0/*8 bits*/);SERCOM5->USART.BAUD.reg = (uint16_t)br;SERCOM5->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;}//-----------------------------------------------------------------------------static void uart_putc(char c){while (!(SERCOM5->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_DRE));SERCOM5->USART.DATA.reg = c;}//-----------------------------------------------------------------------------static void uart_puts(char *s){while (*s)uart_putc(*s++);}//-----------------------------------------------------------------------------static void sys_init(void){// Switch to 8MHz clock (disable prescaler)SYSCTRL->OSC8M.bit.PRESC = 0;}static void i2c_init(void){HAL_GPIO_SDA_pmuxen(I2C_SERCOM_PMUX);HAL_GPIO_SCL_pmuxen(I2C_SERCOM_PMUX);PM->APBCMASK.reg |= I2C_SERCOM_APBCMASK;GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(I2C_SERCOM_GCLK_ID) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);I2C_SERCOM->I2CS.ADDR.reg = I2C_BASE_ADDRESS;I2C_SERCOM->I2CS.CTRLB.reg = SERCOM_I2CS_CTRLB_SMEN;I2C_SERCOM->I2CS.CTRLA.reg = SERCOM_I2CS_CTRLA_ENABLE | SERCOM_I2CS_CTRLA_MODE_I2C_SLAVE;I2C_SERCOM->I2CS.INTENSET.reg = SERCOM_I2CS_INTENCLR_PREC | SERCOM_I2CS_INTENCLR_AMATCH |SERCOM_I2CS_INTENCLR_DRDY;NVIC_EnableIRQ(I2C_SERCOM_IRQ);}//-----------------------------------------------------------------------------void I2C_SERCOM_IRQ_HANDLER(void){uart_puts("\r\n Interrupt!\r\n");int flags;flags = I2C_SERCOM->I2CS.INTFLAG.reg;if (flags & SERCOM_I2CS_INTFLAG_AMATCH){I2C_SERCOM->I2CS.CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;I2C_SERCOM->I2CS.CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(3);}if (flags & SERCOM_I2CS_INTFLAG_PREC){I2C_SERCOM->I2CS.INTFLAG.reg = SERCOM_I2CS_INTFLAG_PREC;}if (flags & SERCOM_I2CS_INTFLAG_DRDY){if (I2C_SERCOM->I2CS.STATUS.reg & SERCOM_I2CS_STATUS_DIR){static int cnt = 0;I2C_SERCOM->I2CS.DATA.reg = cnt++;}else{I2C_SERCOM->I2CS.CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT;int data = I2C_SERCOM->I2CS.DATA.reg;(void)data;}I2C_SERCOM->I2CS.INTFLAG.reg = SERCOM_I2CS_INTFLAG_DRDY;}}//-----------------------------------------------------------------------------int main(void){uint32_t cnt = 0;bool fast = false;sys_init();timer_init();uart_init(115200);i2c_init();DelayMs(1000);uart_puts("\r\nHello, world!\r\n");DelayMs(1000);while (1){}return 0;}Could it be something on the arduino side of the exchange? I am reading the correct sensor addresses so I assumed everything is working properly.

author: ataradov
author_rank: Super Contributor
timestamp: February 02, 2022, 07:53:09 am
content: Do you have pull-ups on the bus? Why not capture the bus with a logic analyzer and see what is going on?

author: WILDERNESSBAGEL
author_rank: Contributor
timestamp: February 02, 2022, 08:36:52 am
content: I don't have a logic analyzer, I only have a scope. I changed the arduino code to make it easier to capture it now looks like this:Code:#include<Wire.h>int x = 0;void setup() {// Start the I2C Bus as MasterWire.begin();Serial1.begin(115200);}void loop() {Wire.beginTransmission(0x52); // transmit to device #9Wire.write(x); // sends xWire.endTransmission(); // stop transmittingx++; // Increment xif (x > 5) x = 0; // `reset x once it gets 6Serial1.println("Write");delay(500);}The slave code stayed the same.Here is an image of clock and data. As far as I can tell the address part is good. Aren't there supposed to be some stop and start bits between the address part and the slave part.https://imgur.com/a/xdIustA

author: ataradov
author_rank: Super Contributor
timestamp: February 02, 2022, 08:42:08 am
content: Wire.beginTransmission(); takes 7-bit address, so you need to provide 0x29 as an address.Also, at least capture clock and data on two different traces at the same time. It is hard to interpret the results.And get a logic analyzer. $15 will save you a ton of time.

author: WILDERNESSBAGEL
author_rank: Contributor
timestamp: February 02, 2022, 09:02:27 am
content: I changed the address in the arduino code to 0x29 but no dice there is still no print on the slave. I'm not really sure if I understand the addressing part I see your comment that 0x52 is an 8 bit address (in the code) and if I understand 0x29 is just 0x52 shifted once. I see that the SAMD21 has 7 bit and 10 bit addressing so I thought the code uses 10 bit version but I don't see ADDR.TENBITEN=1 being set anywhere? Or is it ok because 0x52 == 0b1010010 (only 7 bits needed to represent the number) but why do I need to shift the address in wire begin then? I'm a bit confused. Here is a picture of clock and data when the address is 0x29.https://imgur.com/a/sXz2bvq. And thank you for the quick responses and patience with this. Do i need to change the slave address to 0x29 aswell (I tried but it didn't help)?

author: ataradov
author_rank: Super Contributor
timestamp: February 02, 2022, 09:13:38 am
content: It has 7 bit address, but the register that holds is shifted by 1. So, you either need to shift 7-bit value before writing to the register, or specify 8-bit value. I always use 8-bit addresses.According to this, scanner actually uses 8-bit addresses too. I'm not sure if there is a difference between different Arduino implementations or their documentation is wrong. But you can return the address back to 0x52 on Ardiuno side.And just to double check, you use my startup code as well? So your interrupt handler in the vector table is also called irq_handler_sercom0?And double check that you have connected SCL/SDA correctly on the D21 side.

author: WILDERNESSBAGEL
author_rank: Contributor
timestamp: February 02, 2022, 09:24:14 am
content: I see the addresses are starting to make more sense. Yeah the arduino is wonky to to say the least, if there is a master slave example for samd I could try that just to make sure it's not some random arduino problem.If this is the vector table then I guess it's correct. I checked the wiring it seems ok.Code:void (* const vectors[])(void) ={&_stack_top, // 0 - Initial Stack Pointer Value// Cortex-M0+ handlersirq_handler_reset, // 1 - Resetirq_handler_nmi, // 2 - NMIirq_handler_hard_fault, // 3 - Hard Fault0, // 4 - Reserved0, // 5 - Reserved0, // 6 - Reserved0, // 7 - Reserved0, // 8 - Reserved0, // 9 - Reserved0, // 10 - Reservedirq_handler_sv_call, // 11 - SVCall0, // 12 - Reserved0, // 13 - Reservedirq_handler_pend_sv, // 14 - PendSVirq_handler_sys_tick, // 15 - SysTick// Peripheral handlersirq_handler_pm, // 0 - Power Managerirq_handler_sysctrl, // 1 - System Controllerirq_handler_wdt, // 2 - Watchdog Timerirq_handler_rtc, // 3 - Real Time Counterirq_handler_eic, // 4 - External Interrupt Controllerirq_handler_nvmctrl, // 5 - Non-Volatile Memory Controllerirq_handler_dmac, // 6 - Direct Memory Access Controllerirq_handler_usb, // 7 - Universal Serial Bus Controllerirq_handler_evsys, // 8 - Event Systemirq_handler_sercom0, // 9 - Serial Communication Interface 0irq_handler_sercom1, // 10 - Serial Communication Interface 1irq_handler_sercom2, // 11 - Serial Communication Interface 2irq_handler_sercom3, // 12 - Serial Communication Interface 3irq_handler_sercom4, // 13 - Serial Communication Interface 4irq_handler_sercom5, // 14 - Serial Communication Interface 5irq_handler_tcc0, // 15 - Timer/Counter for Control 0irq_handler_tcc1, // 16 - Timer/Counter for Control 1irq_handler_tcc2, // 17 - Timer/Counter for Control 2irq_handler_tc3, // 18 - Timer/Counter 3irq_handler_tc4, // 19 - Timer/Counter 4irq_handler_tc5, // 20 - Timer/Counter 5irq_handler_tc6, // 21 - Timer/Counter 6irq_handler_tc7, // 22 - Timer/Counter 7irq_handler_adc, // 23 - Analog-to-Digital Converterirq_handler_ac, // 24 - Analog Comparatorirq_handler_dac, // 25 - Digital-to-Analog Converterirq_handler_ptc, // 26 - Peripheral Touch Controllerirq_handler_i2s, // 27 - Inter-IC Sound Interface};

author: ataradov
author_rank: Super Contributor
timestamp: February 02, 2022, 09:37:26 am
content: Here is I2C master examplehttps://github.com/ataradov/dgw/blob/master/embedded/i2c_master.cI see no other obvious reasons for it not to work.

author: WILDERNESSBAGEL
author_rank: Contributor
timestamp: February 02, 2022, 02:17:40 pm
content: Sorry for the late response, I tried to use the master code and the slave code. The i2c_start(0x52) function returns 0 if I understand correctly this means that there is no slave detected. Here are both complete codes just in case I messed something up.MASTER:Code:/** Copyright (c) 2016, Alex Taradov <alex@taradov.com>* All rights reserved.** Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions are met:** 1. Redistributions of source code must retain the above copyright notice,* this list of conditions and the following disclaimer.* 2. Redistributions in binary form must reproduce the above copyright* notice, this list of conditions and the following disclaimer in the* documentation and/or other materials provided with the distribution.* 3. The name of the author may not be used to endorse or promote products* derived from this software without specific prior written permission.** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE* POSSIBILITY OF SUCH DAMAGE.*//*MASTER*//*- Includes ----------------------------------------------------------------*/#include <stdlib.h>#include <stdint.h>#include <stdbool.h>#include "samd21.h"#include "hal_gpio.h"/*- Prototypes --------------------------------------------------------------*/int i2c_init(int freq);bool i2c_start(int addr);bool i2c_stop(void);bool i2c_read_byte(uint8_t *byte, bool last);bool i2c_write_byte(uint8_t byte);bool i2c_busy(int addr);void i2c_pins(int mask, int value);HAL_GPIO_PIN(UART_TX, B, 22)HAL_GPIO_PIN(UART_RX, B, 23)/*- Definitions -------------------------------------------------------------*/HAL_GPIO_PIN(SDA, A, 8);HAL_GPIO_PIN(SCL, A, 9);#define I2C_SERCOM SERCOM2#define I2C_SERCOM_PMUX PORT_PMUX_PMUXE_D_Val#define I2C_SERCOM_GCLK_ID SERCOM2_GCLK_ID_CORE#define I2C_SERCOM_CLK_GEN 0#define I2C_SERCOM_APBCMASK PM_APBCMASK_SERCOM2#define T_RISE 215e-9 // Depends on the board, actually#define DelayTicks(ticks) {volatile uint32_t n=ticks; while(n--);}//takes 8 cycles#define DelayMs(ms) DelayTicks(MS_TO_DLYTICKS(ms))#define CYCLES_IN_DLYTICKS_FUNC 8#define MS_TO_DLYTICKS(ms)(uint32_t)(F_CPU / 1000 * ms / CYCLES_IN_DLYTICKS_FUNC) // ((float)(F_CPU)) / 1000.0enum{I2C_TRANSFER_WRITE = 0,I2C_TRANSFER_READ = 1,};enum{I2C_PINS_SDA = (1 << 0),I2C_PINS_SCL = (1 << 1),};/*-----------------------------------UART------------------------------------*/#define PERIOD_SLOW 500//-----------------------------------------------------------------------------static void timer_set_period(uint16_t i){TC3->COUNT16.CC.reg = (F_CPU / 1000ul / 256) * i;TC3->COUNT16.COUNT.reg = 0;}//-----------------------------------------------------------------------------void irq_handler_tc3(void){if (TC3->COUNT16.INTFLAG.reg & TC_INTFLAG_MC(1)){TC3->COUNT16.INTFLAG.reg = TC_INTFLAG_MC(1);}}//-----------------------------------------------------------------------------static void timer_init(void){PM->APBCMASK.reg |= PM_APBCMASK_TC3;GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(TC3_GCLK_ID) |GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);TC3->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_MFRQ |TC_CTRLA_PRESCALER_DIV256 | TC_CTRLA_PRESCSYNC_RESYNC;TC3->COUNT16.COUNT.reg = 0;timer_set_period(PERIOD_SLOW);TC3->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE;TC3->COUNT16.INTENSET.reg = TC_INTENSET_MC(1);NVIC_EnableIRQ(TC3_IRQn);}//-----------------------------------------------------------------------------static void uart_init(uint32_t baud){uint64_t br = (uint64_t)65536 * (F_CPU - 16 * baud) / F_CPU;HAL_GPIO_UART_TX_out();HAL_GPIO_UART_TX_pmuxen(PORT_PMUX_PMUXE_D_Val);HAL_GPIO_UART_RX_in();HAL_GPIO_UART_RX_pmuxen(PORT_PMUX_PMUXE_D_Val);PM->APBCMASK.reg |= PM_APBCMASK_SERCOM5;GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(SERCOM5_GCLK_ID_CORE) |GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);SERCOM5->USART.CTRLA.reg =SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_MODE_USART_INT_CLK |SERCOM_USART_CTRLA_RXPO(3/*PAD1*/) | SERCOM_USART_CTRLA_TXPO(1/*PAD0*/);SERCOM5->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN |SERCOM_USART_CTRLB_CHSIZE(0/*8 bits*/);SERCOM5->USART.BAUD.reg = (uint16_t)br;SERCOM5->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;}//-----------------------------------------------------------------------------static void uart_putc(char c){while (!(SERCOM5->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_DRE));SERCOM5->USART.DATA.reg = c;}//-----------------------------------------------------------------------------static void uart_puts(char *s){while (*s)uart_putc(*s++);}//-----------------------------------------------------------------------------static void sys_init(void){// Switch to 8MHz clock (disable prescaler)SYSCTRL->OSC8M.bit.PRESC = 0;}/*----------------------------------I2C--------------------------------------*//*- Implementations ---------------------------------------------------------*///-----------------------------------------------------------------------------int i2c_init(int freq){int baud = ((float)F_CPU / freq - (float)F_CPU * T_RISE - 10.0) / 2.0;if (baud < 0)baud = 0;else if (baud > 255)baud = 255;freq = (float)F_CPU / (2.0 * (5.0 + baud) + (float)F_CPU * T_RISE);PM->APBCMASK.reg |= I2C_SERCOM_APBCMASK;GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(I2C_SERCOM_GCLK_ID) |GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(I2C_SERCOM_CLK_GEN);I2C_SERCOM->I2CM.CTRLA.reg = SERCOM_I2CM_CTRLA_SWRST;while (I2C_SERCOM->I2CM.CTRLA.reg & SERCOM_I2CM_CTRLA_SWRST);I2C_SERCOM->I2CM.CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN;while (I2C_SERCOM->I2CM.SYNCBUSY.reg);I2C_SERCOM->I2CM.BAUD.reg = SERCOM_I2CM_BAUD_BAUD(baud);while (I2C_SERCOM->I2CM.SYNCBUSY.reg);I2C_SERCOM->I2CM.CTRLA.reg = SERCOM_I2CM_CTRLA_ENABLE |SERCOM_I2CM_CTRLA_MODE_I2C_MASTER |SERCOM_I2CM_CTRLA_SDAHOLD(3);while (I2C_SERCOM->I2CM.SYNCBUSY.reg);I2C_SERCOM->I2CM.STATUS.reg |= SERCOM_I2CM_STATUS_BUSSTATE(1);HAL_GPIO_SDA_in();HAL_GPIO_SDA_clr();HAL_GPIO_SDA_pmuxen(I2C_SERCOM_PMUX);HAL_GPIO_SCL_in();HAL_GPIO_SCL_clr();HAL_GPIO_SCL_pmuxen(I2C_SERCOM_PMUX);return freq;}//-----------------------------------------------------------------------------bool i2c_start(int addr){I2C_SERCOM->I2CM.INTFLAG.reg = SERCOM_I2CM_INTFLAG_ERROR;I2C_SERCOM->I2CM.ADDR.reg = addr;while (0 == (I2C_SERCOM->I2CM.INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB) &&0 == (I2C_SERCOM->I2CM.INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB));if (I2C_SERCOM->I2CM.STATUS.reg & SERCOM_I2CM_STATUS_RXNACK ||I2C_SERCOM->I2CM.INTFLAG.reg & SERCOM_I2CM_INTFLAG_ERROR){I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);return false;}return true;}//-----------------------------------------------------------------------------bool i2c_stop(void){if ((I2C_SERCOM->I2CM.INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB) ||(I2C_SERCOM->I2CM.INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB)){I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);}return true;}//-----------------------------------------------------------------------------bool i2c_read_byte(uint8_t *byte, bool last){while (1){int flags = I2C_SERCOM->I2CM.INTFLAG.reg;if (flags & SERCOM_I2CM_INTFLAG_SB)break;if (flags & (SERCOM_I2CM_INTFLAG_MB | SERCOM_I2CM_INTFLAG_ERROR))return false;}if (last)I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT | SERCOM_I2CM_CTRLB_CMD(3);elseI2C_SERCOM->I2CM.CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;*byte = I2C_SERCOM->I2CM.DATA.reg;return true;}//-----------------------------------------------------------------------------bool i2c_write_byte(uint8_t byte){I2C_SERCOM->I2CM.DATA.reg = byte;uart_puts("\r\n Written in data reg \r\n");while (1){int flags = I2C_SERCOM->I2CM.INTFLAG.reg;if (flags & SERCOM_I2CM_INTFLAG_MB)break;if (flags & (SERCOM_I2CM_INTFLAG_SB | SERCOM_I2CM_INTFLAG_ERROR))return false;// uart_puts("\r\n Stuck in while \r\n");}if (I2C_SERCOM->I2CM.STATUS.reg & SERCOM_I2CM_STATUS_RXNACK){I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);return false;}return true;}//-----------------------------------------------------------------------------bool i2c_busy(int addr){bool busy;I2C_SERCOM->I2CM.ADDR.reg = addr | I2C_TRANSFER_WRITE;while (0 == (I2C_SERCOM->I2CM.INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB));busy = (0 != (I2C_SERCOM->I2CM.STATUS.reg & SERCOM_I2CM_STATUS_RXNACK));I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);return busy;}//-----------------------------------------------------------------------------void i2c_pins(int mask, int value){if (mask & I2C_PINS_SDA){HAL_GPIO_SDA_out();HAL_GPIO_SDA_write(value & I2C_PINS_SDA);}else{HAL_GPIO_SDA_in();HAL_GPIO_SDA_clr();}if (mask & I2C_PINS_SCL){HAL_GPIO_SCL_out();HAL_GPIO_SCL_write(value & I2C_PINS_SCL);}else{HAL_GPIO_SCL_in();HAL_GPIO_SCL_clr();}HAL_GPIO_SDA_pmuxdis();HAL_GPIO_SCL_pmuxdis();}int main(){sys_init();timer_init();uart_init(115200);DelayMs(3000);i2c_init(100000);uart_puts("\r\n uart done \r\n");uart_puts("\r\n i2c init done \r\n");uart_putc(i2c_start(0x52) + 48);while(1){uart_puts("\r\n before write \r\n");i2c_write_byte(2);uart_puts("\r\n data written\r\n");DelayMs(200);}return 0;}SLAVE:Code:/** Copyright (c) 2015, Alex Taradov <alex@taradov.com>* All rights reserved.** Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions are met:** 1. Redistributions of source code must retain the above copyright notice,* this list of conditions and the following disclaimer.* 2. Redistributions in binary form must reproduce the above copyright* notice, this list of conditions and the following disclaimer in the* documentation and/or other materials provided with the distribution.* 3. The name of the author may not be used to endorse or promote products* derived from this software without specific prior written permission.** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE* POSSIBILITY OF SUCH DAMAGE.*///-----------------------------------------------------------------------------#include <stdlib.h>#include <stdint.h>#include <stdbool.h>#include <string.h>#include "samd21.h"#include "hal_gpio.h"//-----------------------------------------------------------------------------#define PERIOD_FAST 100#define PERIOD_SLOW 500HAL_GPIO_PIN(UART_TX, B, 22)HAL_GPIO_PIN(UART_RX, B, 23)//-----------------------------------------------------------------------------HAL_GPIO_PIN(SDA, A, 8)HAL_GPIO_PIN(SCL, A, 9)#define I2C_BASE_ADDRESS 0x52// 8-bit address#define I2C_SERCOM SERCOM0#define I2C_SERCOM_PMUX HAL_GPIO_PMUX_C#define I2C_SERCOM_APBCMASK PM_APBCMASK_SERCOM0#define I2C_SERCOM_GCLK_ID SERCOM0_GCLK_ID_CORE#define I2C_SERCOM_IRQ_HANDLER irq_handler_sercom0#define I2C_SERCOM_IRQ SERCOM0_IRQn#define DelayTicks(ticks) {volatile uint32_t n=ticks; while(n--);}//takes 8 cycles#define DelayMs(ms) DelayTicks(MS_TO_DLYTICKS(ms))#define FCPU 8000000#define CYCLES_IN_DLYTICKS_FUNC 8#define MS_TO_DLYTICKS(ms)(uint32_t)(FCPU / 1000 * ms / CYCLES_IN_DLYTICKS_FUNC) // ((float)(F_CPU)) / 1000.0//-----------------------------------------------------------------------------static void timer_set_period(uint16_t i){TC3->COUNT16.CC.reg = (F_CPU / 1000ul / 256) * i;TC3->COUNT16.COUNT.reg = 0;}//-----------------------------------------------------------------------------void irq_handler_tc3(void){if (TC3->COUNT16.INTFLAG.reg & TC_INTFLAG_MC(1)){TC3->COUNT16.INTFLAG.reg = TC_INTFLAG_MC(1);}}//-----------------------------------------------------------------------------static void timer_init(void){PM->APBCMASK.reg |= PM_APBCMASK_TC3;GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(TC3_GCLK_ID) |GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);TC3->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_MFRQ |TC_CTRLA_PRESCALER_DIV256 | TC_CTRLA_PRESCSYNC_RESYNC;TC3->COUNT16.COUNT.reg = 0;timer_set_period(PERIOD_SLOW);TC3->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE;TC3->COUNT16.INTENSET.reg = TC_INTENSET_MC(1);NVIC_EnableIRQ(TC3_IRQn);}//-----------------------------------------------------------------------------static void uart_init(uint32_t baud){uint64_t br = (uint64_t)65536 * (F_CPU - 16 * baud) / F_CPU;HAL_GPIO_UART_TX_out();HAL_GPIO_UART_TX_pmuxen(PORT_PMUX_PMUXE_D_Val);HAL_GPIO_UART_RX_in();HAL_GPIO_UART_RX_pmuxen(PORT_PMUX_PMUXE_D_Val);PM->APBCMASK.reg |= PM_APBCMASK_SERCOM5;GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(SERCOM5_GCLK_ID_CORE) |GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);SERCOM5->USART.CTRLA.reg =SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_MODE_USART_INT_CLK |SERCOM_USART_CTRLA_RXPO(3/*PAD1*/) | SERCOM_USART_CTRLA_TXPO(1/*PAD0*/);SERCOM5->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN |SERCOM_USART_CTRLB_CHSIZE(0/*8 bits*/);SERCOM5->USART.BAUD.reg = (uint16_t)br;SERCOM5->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;}//-----------------------------------------------------------------------------static void uart_putc(char c){while (!(SERCOM5->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_DRE));SERCOM5->USART.DATA.reg = c;}//-----------------------------------------------------------------------------static void uart_puts(char *s){while (*s)uart_putc(*s++);}//-----------------------------------------------------------------------------static void sys_init(void){// Switch to 8MHz clock (disable prescaler)SYSCTRL->OSC8M.bit.PRESC = 0;}static void i2c_init(void){HAL_GPIO_SDA_pmuxen(I2C_SERCOM_PMUX);HAL_GPIO_SCL_pmuxen(I2C_SERCOM_PMUX);PM->APBCMASK.reg |= I2C_SERCOM_APBCMASK;GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(I2C_SERCOM_GCLK_ID) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);I2C_SERCOM->I2CS.ADDR.reg = I2C_BASE_ADDRESS;I2C_SERCOM->I2CS.CTRLB.reg = SERCOM_I2CS_CTRLB_SMEN;I2C_SERCOM->I2CS.CTRLA.reg = SERCOM_I2CS_CTRLA_ENABLE | SERCOM_I2CS_CTRLA_MODE_I2C_SLAVE;I2C_SERCOM->I2CS.INTENSET.reg = SERCOM_I2CS_INTENCLR_PREC | SERCOM_I2CS_INTENCLR_AMATCH |SERCOM_I2CS_INTENCLR_DRDY;NVIC_EnableIRQ(I2C_SERCOM_IRQ);}//-----------------------------------------------------------------------------void I2C_SERCOM_IRQ_HANDLER(void){uart_puts("\r\n Interrupt!\r\n");int flags;flags = I2C_SERCOM->I2CS.INTFLAG.reg;if (flags & SERCOM_I2CS_INTFLAG_AMATCH){I2C_SERCOM->I2CS.CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;I2C_SERCOM->I2CS.CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(3);}if (flags & SERCOM_I2CS_INTFLAG_PREC){I2C_SERCOM->I2CS.INTFLAG.reg = SERCOM_I2CS_INTFLAG_PREC;}if (flags & SERCOM_I2CS_INTFLAG_DRDY){if (I2C_SERCOM->I2CS.STATUS.reg & SERCOM_I2CS_STATUS_DIR){static int cnt = 0;I2C_SERCOM->I2CS.DATA.reg = cnt++;}else{I2C_SERCOM->I2CS.CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT;int data = I2C_SERCOM->I2CS.DATA.reg;(void)data;}I2C_SERCOM->I2CS.INTFLAG.reg = SERCOM_I2CS_INTFLAG_DRDY;}}//-----------------------------------------------------------------------------int main(void){uint32_t cnt = 0;bool fast = false;sys_init();timer_init();uart_init(115200);i2c_init();DelayMs(1000);uart_puts("\r\nHello, world!\r\n");DelayMs(1000);while (1){}return 0;}How important are resistor values for I2C? I used 10k to pullup both lines can this maybe be the reason, I see a lot of different values on the internet so not sure if this is good. I'll try to connect the master to a random sensor and see if it responds.UPDATE:It doesn't recognize the sensor either the sensor I used was tcn75https://ww1.microchip.com/downloads/en/DeviceDoc/21490D.pdfaddress should be 0x48.

author: ataradov
author_rank: Super Contributor
timestamp: February 02, 2022, 04:48:55 pm
content: 0x48 is the 7-bit address. 8-bit address would be 0x90.

author: WILDERNESSBAGEL
author_rank: Contributor
timestamp: February 03, 2022, 08:35:55 am
content: Ok so I guess it's something with the MCU. The one I used as a master works and returns true when testing with the sensor, the other one gets false with the same code. Any ideas what could be the problem could it be the crystal or something along those lines? In your opinion how hard would it be to figure it out? Also thanks for all the help, best help I had on any of the forums.

author: ataradov
author_rank: Super Contributor
timestamp: February 03, 2022, 08:40:56 am
content: You have the scope, you can check is the crystal is running. But you can also disable all clock initialization just to be sure.And also, put some pin toggling in he main loop. If the loop runs, then the clock is fine. Plus you have debug prints, check them and if they show up, then the clock must be good.The pins may be damaged too, which is also easy enough to test.

author: WILDERNESSBAGEL
author_rank: Contributor
timestamp: February 03, 2022, 01:30:49 pm
content: Thanks for the suggestions, I tried everything and everything worked as expected, I even tried generating PWM on random pins and it's fine. I'm out of ideas. It looks like everything besides I2C is okUPDATE:I continued to mess around doing simple things to see if anything brakes and now it randomly can't find the device signature. When I try to read it it reads it every 5th time and the same is for uploading the code. I tried to erase the chip (found this as a solution on another form post) but it didn't help.

author: ataradov
author_rank: Super Contributor
timestamp: February 03, 2022, 05:08:15 pm
content: Can you show your schematics and board layout?

author: WILDERNESSBAGEL
author_rank: Contributor
timestamp: February 07, 2022, 12:27:21 pm
content: Once again sorry for the late response, a friend of mine designed the board so I had to wait for him to send me the schematics. This is the schematic of the one that doesn't respond.. Board layout is in the attachment.P.S. I found another MKRGSM and the communication between two MKRs works as expected so the code is for sure good.

author: ataradov
author_rank: Super Contributor
timestamp: February 07, 2022, 05:00:53 pm
content: There is no schematic attached.

author: WILDERNESSBAGEL
author_rank: Contributor
timestamp: February 07, 2022, 08:10:31 pm
content: Whoops my bad I accidentally removed it when I edited the message. I will post it now.

author: ataradov
author_rank: Super Contributor
timestamp: February 07, 2022, 09:29:06 pm
content: Why is VDDCORE connected to 3.3 V? You are not supposed to connect anything to it, except for decoupling capacitors. This pin is an output of the internal voltage regulator, and it is 1.2 V.

author: WILDERNESSBAGEL
author_rank: Contributor
timestamp: February 08, 2022, 12:03:56 pm
content: Yep it's just a mistake, I'll give it back to get it fixed, is there anything else that should be changed? And could this have caused any damage to the MCU is there a way to check?I tested various things and now it seems like everything works fine. Thanks once again for all the help.

author: ataradov
author_rank: Super Contributor
timestamp: February 08, 2022, 04:39:24 pm
content: It could have damaged the device, so if possible I would replace it. There is no simple way to check it. If you leave it and something else does not work, then you will always have to doubt that it is because of the previous damage.The values for R9 and R10 are strange. They should be 5.1K.

author: WILDERNESSBAGEL
author_rank: Contributor
timestamp: February 11, 2022, 08:10:10 am
content: Thank you I'll have those changed as well for the next design.