LowPower + Softwareserial = data cut off

Ive got a thermometer with optional RS232. When RS232 is turned on i want the data to be logged on a SD-card. Since the Arduino would be running continuously and wasting a lot of energy i want to use LowPower.h with a trigger set to the data, which is either never or only once per second if RS232 is on.
However… the logged Data is not correct anymore. Its incomplete, cut of.
I can see a difference in the intensity of the LED during the reading, without any powersaving its on for maybe 100ms and brightly lit, with powersaving its only shortly lit up a tiny bit.
So i figure the interrupt must be working but the device it not on long enough to send everything to the SD-card. I tryed to add a 100ms delay after the reading but that didnt change anything.
The code works fine without the energy/interrupt parts. How can i change things to get the data out correctly?

#include <SoftwareSerial.h>
#include <SD.h>
#include <SPI.h>
#include <LowPower.h>
const int chipSelect = 10;


#define rxPin 8
#define txPin 9

const int wakeUpPin = 8;      // Use pin 8 as wake up pin
int led = 13;
volatile int state = LOW;


// set up a new serial port
SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin, true);

void setup()  {

  pinMode(wakeUpPin, INPUT);    // Configure wake up pin as input.
  pinMode(led, OUTPUT);         //digitalWrite(2, HIGH);


  Serial.begin(9600);                                   // open serial port, set the baud rate as 9600 bps
  delay(1000);                                           // while (!Serial) {
  Serial.print("Initializing SD card...");              // wait for serial port to connect. Needed for native USB port only


  if (!SD.begin(chipSelect)) {                            // see if the card is present and can be initialized:
    Serial.println("Card failed or not present");

    return;                                               // don't do anything more:
  }
  Serial.println("card initialized.");


  // define pin modes for tx, rx:
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  // set the data rate for the SoftwareSerial port
  mySerial.begin(9600);
  Serial.begin(9600);
}

void loop() {

  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);

  // Allow wake up pin to trigger interrupt on high.
  attachInterrupt(0, toggle, HIGH); //note the High on my design
  // Enter power down state with ADC and BOD module disabled.
  // Wake up when wake up pin is high.


  if (mySerial.available() > 0) {
    char data = mySerial.read();
    File dataFile = SD.open("log.txt", FILE_WRITE);
    dataFile.print(data);
    dataFile.close();
    Serial.print(data);
  }
  delay (100);

}
void toggle() {
  if (state == LOW)
  {
    state = HIGH;
  }
  else
  {
    state = LOW;
  }
  digitalWrite(led, state);

}

with a trigger set to the data

What does that mean? Be as explicit as possible.

const int wakeUpPin = 8;      // Use pin 8 as wake up pin

Just defining a pin number as a wake up pin does not mean anything.

  // Allow wake up pin to trigger interrupt on high.
  attachInterrupt(0, toggle, HIGH); //note the High on my design

That means that pin 2 is the wake up pin, NOT pin 8.

  if (mySerial.available() > 0) {
    char data = mySerial.read();
    File dataFile = SD.open("log.txt", FILE_WRITE);
    dataFile.print(data);
    dataFile.close();
    Serial.print(data);
  }

Writing one character at a time to the file is incredibly wasteful.

You are aware, I hope, that the arrival of data on the software serial pins will NOT wake your device up. That data will, in fact, be lost while the Arduino is sleeping.

The data comes as a high signal. As soon as there is a high it has to wake up.

It just means that i can use “wakeUpPin” instead of the number. But it has to be waking up… how would there be any data at all otherwise?

That means that pin 2 is the wake up pin, NOT pin 8.

Oh there are specific interrupt pins at 2 and 3 that get labled 0 and 1…
But why did it work at all? I dont see how it gives me even one reading like that…

Writing one character at a time to the file is incredibly wasteful.

It would be my pleasure to get any better code to do the job. But as its there the code does work and the output it not a single char at a time but the whole temperatur like “C,20.13”. As fas as i understand it the if (mySerial-abailable()) looks for any mySerial data in the Buffer and .read returns it. So if there is >1 char of data it will also read more than this one char.

You are aware, I hope, that the arrival of data on the software serial pins will NOT wake your device up. That data will, in fact, be lost while the Arduino is sleeping.

How is that possible when i get incomplete data instead of just nothing?
So these are 2 functions on one pin:
A) Wake up when there is any high (coming from the beginning of the data)
B) Buffer that data and write it to the SD (and go back to sleep)

Since the data comes at fixed intervals i for now ditched all the interrupt parts and went with 970ms of fixed sleeping. This does, however, lead to sync problems… but at least i could verify the powersaving and found out that my µSD draws about 15mA, at least 3x more then everything else put together.
So how to set up a correct interrupt?
This is my code at the moment with softwareserial going to the same pin 2:

#include <SoftwareSerial.h>
#include <SD.h>
#include <SPI.h>
#include <LowPower.h>
const int chipSelect = 10;



#define rxPin 2
#define txPin 3

SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin, true);    // set up a new serial port





void setup()  {

  Serial.begin(9600);                                     // open serial port, set the baud rate as 9600 bps
  delay(500);                                             // while (!Serial) {
  Serial.print("Initializing SD card...");                // wait for serial port to connect. Needed for native USB port only


  if (!SD.begin(chipSelect)) {                            // see if the card is present and can be initialized:
    Serial.println("Card failed or not present");

    return;                                               // don't do anything more:
  }
  Serial.println("card initialized.");


  pinMode(rxPin, INPUT);                                  // define pin modes for tx, rx:
  pinMode(txPin, OUTPUT);
  mySerial.begin(9600);                                   // set the data rate for the SoftwareSerial port
  delay(250);

}

void loop() {

  if (mySerial.available() > 0) {
    char data = mySerial.read();
    File dataFile = SD.open("log.txt", FILE_WRITE);
    dataFile.print(data);
    dataFile.close();
    Serial.print(data);
    Serial.println("");
  }
  Serial.println("sleep");
  LowPower.powerDown(SLEEP_500MS, ADC_OFF, BOD_OFF);

  LowPower.powerDown(SLEEP_250MS, ADC_OFF, BOD_OFF);

  LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_OFF);

  LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_OFF);
  Serial.println("wake");
}

PaulS: You are aware, I hope, that the arrival of data on the software serial pins will NOT wake your device up. That data will, in fact, be lost while the Arduino is sleeping.

Software Serial uses pin change interrupts, which are capable of waking the processor up from POWER_DOWN mode. So yes, it does work.

Software Serial uses pin change interrupts itself? No need to make other interrupts?

Since i found my own thread while searching for solutions…
Here is the working code. Note how pretty much everything is now different. Took way too much time and different approaches to get it going. The powerconsumption is now 20mA average while logging and 7mA when idle (RS232 off). Still not really good but i can live with it like that.

#include <SdFat.h>
#include <SPI.h>
#include <LowPower.h>
const int chipSelect = 10;
SdFat SD;


String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete

void setup()  {
  pinMode(5, OUTPUT);
  Serial.begin(9600);                                   // open serial port, set the baud rate as 9600 bps

  inputString.reserve(200);         // reserve 200 bytes for the inputString:
  delay(250);

}

void loop() {

  if (stringComplete) {               // print the string when a newline arrives:
    digitalWrite(5, HIGH);
    delay(10);
    if (!SD.begin(chipSelect)) {                            // see if the card is present and can be initialized:
      Serial.println("Card failed or not present");
      delay(50);
      return;
    }
    File dataFile = SD.open("log.txt", FILE_WRITE);
    dataFile.print(inputString);
    dataFile.close();
    Serial.print(inputString);
    Serial.flush();
    inputString = "";                  // clear the string:
    stringComplete = false;
  }

  else {
    digitalWrite(5, LOW);
    LowPower.idle(SLEEP_FOREVER, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF,
                  SPI_OFF, USART0_ON, TWI_OFF);
  }

}
void serialEvent() {
  while (Serial.available()) {

    char inChar = (char)Serial.read();       // get the new byte:
    inputString += inChar;                   // add it to the inputString:


    if (inChar == '\n') {                    // if the incoming character is a newline, set a flag
      stringComplete = true;                 // so the main loop can do something about it:
    }
  }
}