ATSAMD10D13AS - How to set up sleep with I2C address match as a wake up source

1 post / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First of all shout out to Ataradov and his mcu-starter-projects page since most (99%) of the code if from there. The attached I2C example works good if there is no sleep. And the received numbers are correct and there is no problems.

This is the master code, basically it only sends numbers from 0-9 to address 0x29.

#include<Wire.h>
int x = 5;
void setup() {
  // Start the I2C Bus as Master
  Wire.begin();
  Wire.setClock(100 * 1000);
  Serial1.begin(115200);
  delay(10000);

}
void loop() {

  Wire.beginTransmission(0x29); // transmit to device #9
  Wire.write(x);              // sends x
  Wire.endTransmission();    // stop transmitting
  x++; // Increment x
  if (x > 9) x = 0; // `reset x once it gets 6
  Serial1.println("Write");
  delay(15000);
}

Slave main code (I2C code for the slave is attached didn't want to make this super long, I added | SERCOM_I2CS_CTRLA_RUNSTDBY to the CTRLA register): 

 

#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "I2C.h"
#include "UART.h"

static void sysInit(void)
{
  // Switch to 8MHz clock (disable prescaler)
  SYSCTRL->OSC8M.bit.PRESC = 0;
}

int main(void)
{
  sysInit();
  uart_init(115200);
  uart_puts("\r\nHello, world!\r\n");
  i2cInit();
  int a = 0;
  while (1)
  {
    /*
	SYSCTRL->XOSC32K.bit.RUNSTDBY = 1;
	SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
	__DSB();
	__WFI();
*/
  }
  return 0;
}

 

The received numbers are correct, example of print to COM using a UART to USB:

...

20:27:16.264 -> data received 8
20:27:31.283 -> data received 9
20:27:46.269 -> data received 0
20:28:01.284 -> data received 1
20:28:16.250 -> data received 2
20:28:31.275 -> data received 3

...

However if I uncomment the lines above:
 

SYSCTRL->XOSC32K.bit.RUNSTDBY = 1;
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
__DSB();
__WFI();

The output in the console gets a bit odd. It looks like this: 
20:51:22.216 -> data received 5⸮data received 6⸮data received 7⸮data received 8⸮data received 9⸮

 

I tried to reinitialize uart and the prescaler in case they get turned off when going to sleep (in I2C.h). So I added that to the beginning of the interrupt:

 

void I2C_SERCOM_IRQ_HANDLER(void) {
	SYSCTRL->OSC8M.bit.PRESC = 0;
	uart_init(115200);
....rest of the I2C code...

And if I put something in the main loop the code never comes back from sleep: 

int main(void)
{
  sysInit();
  uart_init(115200);
  uart_puts("\r\nHello, world!\r\n");
  i2cInit();

  while (1)
  {
	int a = 0;
	for(uint8_t i = 0; i < 100; ++i){
		a += 1;
	}

	SYSCTRL->XOSC32K.bit.RUNSTDBY = 1;
	SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
	__DSB();
	__WFI();
  }

  return 0;
}

This only outputs:


21:02:52.045 -> Hello, world! ⸮

and is stuck until I reset the MCU.

 

 

And finally if I add displaying the number before going to sleep (the DisplayData.h is also attached):

 

int main(void)
{
  sysInit();
  uart_init(115200);
  uart_puts("\r\nHello, world!\r\n");
  i2cInit();
  displaysettings.mode = IDLE;

  REG_PORT_DIR0 = 0;
  REG_PORT_OUT0 = 0;
  PWMclockInit();
  PWMbegin();
  while (1)
  {	

	displayToggleNumber(received);

	SYSCTRL->XOSC32K.bit.RUNSTDBY = 1;
	SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
	__DSB();
	__WFI();

  }

  return 0;
}

I get even weirder results and the MCU resets in between receiving data:

...

21:07:51.840 -> Hello, world!
21:08:02.781 -> data received 5⸮data received 6⸮data received 7⸮⸮
21:08:47.789 -> Hello, world!
21:09:02.819 -> data received 9⸮⸮
21:09:17.792 -> Hello, world!
21:09:32.780 -> data received 1⸮⸮
21:09:47.809 -> Hello, world!
21:10:02.771 -> data received 3⸮⸮
21:10:17.781 -> Hello, world!
...

 

I know this is a lot of stuff so even if only the first problem is solved, where I receive weird data when going to sleep it will be really helpful. Also if there is any comprehensive tutorial regarding I2C and waking up the device please point me to it. Just a few general questions, when the MCU comes back from sleep and enters the I2C interrupt, where does the code return to (I assumed it is to the point where the WFI() is)? Furthermore should I turn all the clocks off before going to sleep? Is there any example of using ADDRESS match to wake up the device from sleep?

 

If someone got this far, I really appreciate it and thanks in advance.

 

Attachment(s):