Why does the SD card stop logging without error? - arduino
The following sketch is for an Arduino Nano clone. It waits for a START command then collects data from an I2C slave, assembles it for logging on an SD card, writes it to the card, prints it to the serial monitor and repeats. I've tested and retested. The SD card logfile ALWAYS stops after logging the header and 3 out of 30 lines of data, but the serial monitor shows all the expected data. Never in any of my tests was an SD write error generated.
I'd appreciate any ideas as to why the SD stops logging and how to fix it.
Arduino Sketch
#include <Wire.h>
#include <Servo.h>
#include <SD.h>
#include <SPI.h>
// Uncomment the #define below to enable internal polling of data.
#define POLLING_ENABLED
//define slave i2c address
#define I2C_SLAVE_ADDRESS 9
/* ===================================
Arduino Nano Connections
ESC (PWM) Signal - Pin 9 (1000ms min, 2000ms max)
S.Port Signal - Pin 10
SPI Connections
MOSI = Pin 11
MISO = Pin 12
SCLK = PIN 13
I2C Connections
SDA = Pin A4
SCL = Pin A5
Start/Stop Switches
Start = Pin 2 => INT0
Stop = Pin 3 => INT1
===================================*/
Servo esc; // Servo object for the ESC - PIN 9
const unsigned long pause = 800; // Number of ms between readings
const unsigned long testDelay = 30000; // Number of ms between tests
const int CS_pin = 10; // Pin to use for CS (SS) on your board
const int Startpin = 2;
const int Stoppin = 3;
const int readings = 3; // Number of readings to take at every step
const int steps = 5; // Number of steps to stop the ESC and take readings
const byte HALT = 0;
int ESC = 0;
int throttle = 0;
int increment;
volatile bool STOP = 0;
volatile bool START = 0;
const String header = "% Thr,Thrust,Curr,Volts,RPM,Cell1,Cell2,Cell3,Cell4,Cell5,Cell6";
char buffer0[33]; // Buffer for I2C received data
char buffer1[33]; // Buffer for I2C received data
String logEntry = " GOT NO DATA "; //52 bytes
void setup() {
Wire.begin();
Serial.begin(115200);
pinMode(Startpin, INPUT_PULLUP);
pinMode(Stoppin, INPUT_PULLUP);
// Attach an interrupt to the ISR vector
attachInterrupt(digitalPinToInterrupt(Startpin), start_ISR, LOW);
attachInterrupt(digitalPinToInterrupt(Stoppin), stop_ISR, LOW);
esc.attach(9, 1000, 2000);
// attaches the ESC on pin 9 to the servo object and sets min and max pulse width
esc.write(HALT); // Shut down Motor NOW!
increment = 180 / (steps - 1);
// Number of degrees to move servo (ESC) per step (servo travel is 0-180 degrees so 180 = 100% throttle)
delay(500);
Serial.println(" Thrust Meter I2C Master");
//Print program name
//Initialize SD Card
if (!SD.begin(CS_pin)) {
Serial.println("Card Failure");
}
Serial.println("Card Ready");
//Write Log File Header to SD Card
writeSD(header);
Serial.println(header);
}
void loop() {
if (START) {
Serial.println("Start Pressed");
while (!STOP) {
for (throttle = 0; throttle <= 180; throttle += increment) {
for (int x = 0; x < readings; x++) {
if (STOP) {
esc.write(HALT); // Shut down Motor NOW!
Serial.println("Halting Motor");
} else {
wait (pause);
esc.write(throttle); // increment the ESC
wait (200);
ESC = throttle * 100 / 180;
getData(buffer0);
wait (100);
getData(buffer1);
String logEntry = String(ESC) + "," + String(buffer1) + "," + String(buffer0);
writeSD(logEntry);
Serial.println(logEntry);
}
}
}
for (throttle = 180; throttle >= 0; throttle -= increment) {
for (int x = 0; x < readings; x++) {
if (STOP) {
esc.write(HALT); // Shut down Motor NOW!
Serial.println("Halting Motor");
} else {
wait (pause);
esc.write(throttle); // increment the ESC
wait (200);
ESC = throttle * 100 / 180;
getData(buffer0);
wait (100);
getData(buffer1);
String logEntry = String(ESC) + "," + String(buffer1) + "," + String(buffer0);
writeSD(logEntry);
Serial.println(logEntry);
}
}
}
Serial.println("End of Test Pass");
wait (testDelay);
}
esc.write(HALT); // Shut down Motor NOW!
}
}
void writeSD(String logdata) {
File logFile = SD.open("NANO_LOG.csv", FILE_WRITE);
if (logFile) {
logFile.println(logdata);
logFile.close();
} else {
Serial.println("Error writing log data");
}
}
void wait(unsigned long i) {
unsigned long time = millis() + i;
while(millis()<time) { }
}
void start_ISR() {
START = 1;
STOP = 0;
}
void stop_ISR() {
STOP = 1;
START = 0;
}
void getData(char* buff) {
Wire.requestFrom(9, 32);
for (byte i = 0; i < 32 && Wire.available(); ++i) {
buff[i] = Wire.read();
if (buff[i] == '#') {
buff[i] = '\0';
break;
}
}
}
This is the SD card contents:
% Thr,Thrust,Curr,Volts,RPM,Cell1,Cell2,Cell3,Cell4,Cell5,Cell6
0,-12,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
0,-12,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
0,128,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
This is the output from the serial monitor:
Thrust Meter I2C Master
Card Ready
% Thr,Thrust,Curr,Volts,RPM,Cell1,Cell2,Cell3,Cell4,Cell5,Cell6
Start Pressed
0,-12,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
0,-12,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
0,128,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
25,2062,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
25,2520,0.00,15.75,0,3.10,4.20,3.96,3.96,0.00,0.00
25,2710,0.00,15.75,0,3.10,4.20,3.96,3.96,0.00,0.00
50,519,0.00,15.75,0,3.10,4.20,3.96,3.96,0.00,0.00
50,216,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
50,2288,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
75,890,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
75,891,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
75,1386,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
100,2621,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
100,2424,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
100,692,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
100,3409,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
100,227,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
100,3349,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
75,2220,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
75,2249,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
75,509,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
50,1977,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
50,2986,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
50,546,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
25,3746,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
25,3337,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
25,3015,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
0,96,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
0,-12,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
0,-14,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
End of Test Pass
The solution to the problem was to replace the SD card with a faster one. Once I did that the data logged as it should. Thanks Patrick for the suggestion.
Related
How to control multiple SPI's
I am having a weeny trouble with my SAMD21 board. I have got this starter kit (schematics) and I want to add some more sensors. They use SPI, so I programmed them. Since SAMD21 got the code it lag's everytime, when code reache's the sensor begin function. Please give me some advice, how to control both SPI's correctly and avoid lags. *lags are total lags - SAMD21 do nothing after reaching the begin function. *schematics: http://kit.sciencein.cz/wiki/images/b/be/MainBoard_v2.0_RevB_SCH.png *sorry for mistakes in the code (it is long code cut to short) *my code: #include <Adafruit_BME280.h> // include Adafruit BME280 library #include <Adafruit_INA219.h> // include INA219 #include <SD.h> // include Arduino SD library #include "Open_Cansat_GPS.h" //include our new sensors #include "MQ131.h" #include <Wire.h> #include <SPI.h> #include "RFM69.h" // include RFM69 library // Local #define PC_BAUDRATE 115200 #define MS_DELAY 0 // Number of milliseconds between data sending and LED signalization #define LED_DELAY 100 #define Serial SerialUSB RTCZero rtc; // RFM69 #define NETWORKID 0 // Must be the same for all nodes (0 to 255) #define MYNODEID 1 // My node ID (0 to 255) #define TONODEID 2 // Destination node ID (0 to 254, 255 = broadcast) #define FREQUENCY RF69_433MHZ // Frequency set up #define FREQUENCYSPECIFIC 433000000 // Should be value in Hz, now 433 Mhz will be set #define CHIP_SELECT_PIN 43 //radio chip select #define INTERUP_PIN 9 //radio interrupt // BME280 SETTING #define BME280_ADDRESS_OPEN_CANSAT 0x77 #define SEALEVELPRESSURE_HPA 1013.25 //OZONE2CLICK const byte pinSS = 2; //cs pin const byte pinRDY = 12; const byte pinSCK = 13; const byte O2Pin = 10; #define DcPin 8 // SD card #define sd_cs_pin 35 // set SD's chip select pin (according to the circuit) // create object 'rf69' from the library, which will // be used to access the library methods by a dot notation RFM69 radio(CHIP_SELECT_PIN, INTERUP_PIN, true); // define our own struct data type with variables; used to send data typedef struct { int16_t messageId; uint16_t year; uint8_t month; uint8_t day; uint8_t hour; uint8_t minute; uint8_t sec; float longitude; float latitude; uint8_t num_of_satelites; float temperature; float pressure; float altitude; float humidity_bme280; float voltage_shunt; float voltage_bus; float current_mA; float voltage_load; int16_t rssi; } messageOut; messageOut cansatdata; //create the struct variable // create object 'bme' from the library, which will // be used to access the library methods by a dot notation Adafruit_BME280 bme; // create object 'ina219' from the library with address 0x40 // (according to the circuit, which will be used to access the // library methods by a dot notation Adafruit_INA219 ina219(0x40); // create object 'gps' from the library OpenCansatGPS gps; // SD card File file; // SD library variable // LEDS #define D13_led_pin 42 // D13 LED #define M_led_pin 36 // MLED // Local variables int idCounter = 1; bool isBmeOk = true; bool isSdOk = true; bool isRadioOk = true; bool isGpsConnected = true; // My variables float NH3Data; float COData; float NO2Data; float PPMO2; float PPBO2; float MGM3O2; float UGM3O2; float SSmoke1; float SSmoke2; float SSmoke3; float ESmoke1; float ESmoke2; float ESmoke3; int DataCounter = 0; void OZONE2CLICKCalibrate () { Serial.println("2"); //MQ131.begin(pinSS, pinRDY, O2Pin, LOW_CONCENTRATION, 10000); //(int _pinCS, int _pinRDY, int _pinPower, MQ131Model _model, int _RL) Serial.println("99"); Serial.println("Calibration in progress..."); MQ131.calibrate(); Serial.println("Calibration done!"); Serial.print("R0 = "); Serial.print(MQ131.getR0()); Serial.println(" Ohms"); Serial.print("Time to heat = "); Serial.print(MQ131.getTimeToRead()); Serial.println(" s"); } void OZONE2CLICKMeasure () { Serial.println("Sampling..."); MQ131.sample(); Serial.print("Concentration O3 : "); PPMO2 = MQ131.getO3(PPM); Serial.print(PPMO2); Serial.println(" ppm"); Serial.print("Concentration O3 : "); PPBO2 = MQ131.getO3(PPB); Serial.print(PPBO2); Serial.println(" ppb"); Serial.print("Concentration O3 : "); MGM3O2 = MQ131.getO3(MG_M3); Serial.print(MGM3O2); Serial.println(" mg/m3"); Serial.print("Concentration O3 : "); UGM3O2 = MQ131.getO3(UG_M3); Serial.print(UGM3O2); Serial.println(" ug/m3"); } void setup() { pinMode(pinSS, OUTPUT); digitalWrite(pinSS, HIGH); delay(10000); Serial.begin(PC_BAUDRATE); // wait for the Arduino serial (on your PC) to connect // please, open the Arduino serial console (right top corner) // note that the port may change after uploading the sketch // COMMENT OUT FOR USAGE WITHOUT A PC! // while(!Serial); Serial.println("openCanSat PRO"); Serial.print("Node "); Serial.print(MYNODEID,DEC); Serial.println(" ready"); // begin communication with the BME280 on the previously specified address // print an error to the serial in case the sensor is not found if (!bme.begin(BME280_ADDRESS_OPEN_CANSAT)) { isBmeOk = false; Serial.println("Could not find a valid BME280 sensor, check wiring!"); return; } // begin communication with the INA219 ina219.begin(); // check of Gps is connected Wire.beginTransmission(0x42); // 42 is addres of GPS int error = Wire.endTransmission(); if (error != 0) { isGpsConnected = false; } // begin communication with gps gps.begin(); // Uncomment when you want to see debug prints from GPS library // gps.debugPrintOn(57600); if(!radio.initialize(FREQUENCY, MYNODEID, NETWORKID)) { isRadioOk = false; Serial.println("RFM69HW initialization failed!"); } else { radio.setFrequency(FREQUENCYSPECIFIC); radio.setHighPower(true); // Always use this for RFM69HW } pinMode(D13_led_pin, OUTPUT); pinMode(DcPin, OUTPUT); pinMode(MICS6814Pin, OUTPUT); pinMode(MICSVZ89TEPin, OUTPUT); pinMode(O2Pin, OUTPUT); GyroscopeTurnOn(); } void loop() { cansatdata.messageId = idCounter; GyroscopeMeasure(); LandingChecker(); Serial.println("MessageId = " + static_cast<String>(cansatdata.messageId)); cansatdata.temperature = 0; cansatdata.pressure = 0; cansatdata.altitude = 0; if(isBmeOk) { cansatdata.temperature += bme.readTemperature(); cansatdata.pressure += bme.readPressure() / 100.0F; cansatdata.altitude += bme.readAltitude(SEALEVELPRESSURE_HPA); cansatdata.humidity_bme280 = bme.readHumidity(); } Serial.println("Temperature = " + static_cast<String>(cansatdata.temperature) + " *C"); Serial.println("Pressure = " + static_cast<String>(cansatdata.pressure) + " Pa"); Serial.println("Approx altitude = " + static_cast<String>(cansatdata.altitude) + " m"); Serial.println("Humidity = " + static_cast<String>(cansatdata.humidity_bme280) + " %"); // read values from INA219 into structure cansatdata.voltage_shunt = ina219.getShuntVoltage_mV(); cansatdata.voltage_bus = ina219.getBusVoltage_V(); cansatdata.current_mA = ina219.getCurrent_mA(); cansatdata.voltage_load = cansatdata.voltage_bus + (cansatdata.voltage_shunt / 1000); Serial.println("Shunt Voltage: " + static_cast<String>(cansatdata.voltage_shunt) + " mV"); Serial.println("Bus Voltage: " + static_cast<String>(cansatdata.voltage_bus) + " V"); Serial.println("Current: " + static_cast<String>(cansatdata.current_mA) + " mA"); Serial.println("Load Voltage: " + static_cast<String>(cansatdata.voltage_load) + " V"); // Initialize GPS cansatdata.year = 0; cansatdata.month = 0 ; cansatdata.day = 0; cansatdata.hour = 0; cansatdata.minute = 0; cansatdata.sec = 0; cansatdata.latitude = 0; cansatdata.longitude = 0; cansatdata.num_of_satelites = 0; // save start time in millisec uint32_t start = millis(); // END LED BLINK digitalWrite(D13_led_pin, LOW); pinMode(M_led_pin, INPUT); // END LED BLINK if(isGpsConnected) { if (gps.scan(250)) { cansatdata.year = gps.getYear(); cansatdata.month = gps.getMonth(); cansatdata.day = gps.getDay(); cansatdata.hour = gps.getHour(); cansatdata.minute = gps.getMinute(); cansatdata.sec = gps.getSecond(); cansatdata.latitude = gps.getLat(); cansatdata.longitude = gps.getLon(); cansatdata.num_of_satelites = gps.getNumberOfSatellites(); Serial.println(String("Time to find fix: ") + (millis() - start) + String("ms")); Serial.println(String("Datetime: ") + String(cansatdata.year) + "/"+ String(cansatdata.month) + "/"+ String(cansatdata.day) + " " + String(cansatdata.hour) + ":"+ String(cansatdata.minute) + ":"+ String(cansatdata.sec)); Serial.println(String("Lat: ") + String(cansatdata.latitude, 7)); Serial.println(String("Lon: ") + String(cansatdata.longitude, 7)); Serial.println(String("Num of sats: ") + String(cansatdata.num_of_satelites)); Serial.println(); } else { Serial.println("Gps have no satelit to fix."); } } // RFM69HW cansatdata.rssi = 0; if(isRadioOk) { cansatdata.rssi = radio.RSSI; Serial.println("Signal = " + static_cast<String>(radio.RSSI)); radio.send(TONODEID, (const void*)&cansatdata, sizeof(cansatdata)); } Serial.println(); // START LED hart beat pinMode(M_led_pin, OUTPUT); digitalWrite(D13_led_pin, HIGH); digitalWrite(M_led_pin, HIGH); // START LED hart beat if(!isGpsConnected) { delay(200); } idCounter ++; }
How to make Built in LED blink systematically?
I am trying to make my built in LED on my arduino blink every 1 second while recording my data and putting it in the EEPROM, but I am not sure how to do that. I am supposed to print data to the EEPROM every minute, until the EEPROM is full and while that is going on my built in LED should blink for approx 1 second. My problem seems to be that I am setting a delay to delay how long the data is stored on the EEPROM, but it is also affecting the time it takes for my LED to blink as it is waiting to blink as the data is stored. Any help would be appreciated, the code is below: #include<EEPROM.h> const int SWITCH = 4; void setup() { // put your setup code here, to run once: Serial.begin(115200); pinMode(LED_BUILTIN, OUTPUT); pinMode(SWITCH, INPUT_PULLUP); } void loop() { // put your main code here, to run repeatedly: int addr = 0; float v; float c; int t = 0; int r = analogRead(0); if (digitalRead(SWITCH) == LOW) { Serial.println("----Recording----"); while (addr <= 1024) { Serial.println(r); EEPROM.put(addr, r); addr = addr + 2; delay(600); } while (true); } else { Serial.println("----Replaying----"); Serial.println("Time(s), Temp(C)"); while (addr <= 1024) { t = t + 1; EEPROM.get(addr, r); addr = addr + 2; v = r * 5.0 / 1024.0; c = 100 * (v - 0.5); Serial.print(t * 60); Serial.print("\t"); Serial.println(c); delay(1000); } while (true); } }
Can I temporarily disable Arduino Serial data receive?
I am working on a project and I encountered some problems. I am using a DHT11 temperature sensor, an Arduino Uno and a TFT LCD display 2.2-inch model ITDB02-2.2. What I want my project to do is to use 2 functioning modes for the sensor that I can select from the keyboard at the beginning of the program(one which is normal and one which will be used on special occasions)(so I need serial communication). I noticed that the screen does not function if I start a serial communication at any rate so I used Arduino Serial.begin(9600) and Serial.end() for the mode selecting part of the program. THE PROBLEM: My Arduino is still sending data through serial port even if I ended the serial communication and is looking like this: I found out that Serial.end() function does not shut off serial communication but just the rate of communication. I am curious if you have any idea that I can use in order to get rid of the extra data, to neglect it before the computer receives it. I`m stuck. I thought that interruptions would be a solution but they are not as far as I researched on the internet. My ARDUINO CODE: #include <SimpleDHT.h> #include <UTFT.h> UTFT myGLCD(ITDB22,A5,A4,A3,A2); SimpleDHT11 dht11; // Declare which fonts we will be using extern uint8_t BigFont[]; //dht sensor data pin int dataPinSensor1 = 12; char mode; int del; void setup() { Serial.begin(9600); Serial.print("Select functioning mode"); mode=SensorModeSelect(mode); Serial.end(); pinMode(12, INPUT); } void loop() { if(mode=='1') { FirstFuncMode(dataPinSensor1); } if(mode=='2') { SecondFuncMode(dataPinSensor1,del); } delay(10); } char SensorModeSelect(char in) { char mode='0'; while(mode=='0') { if(Serial.available() > 0) { mode=Serial.read(); } } if (mode == '1') { Serial.print("\nMOD1 SELECTED: press t key to aquire data \n"); } if (mode == '2') { Serial.print("\nMOD2 SELECTED: press q if you want to quit auto mode \n"); Serial.print("Select the data aquisition period(not smaller than 1 second) \n"); } return mode; } int DataAqPeriod() { int del=0; while(del==0) { while(Serial.available() > 0) { //Get char and convert to int char a = Serial.read(); int c = a-48; del *= 10; del += c; delay(10); } } del*=1000; return del; } void FirstFuncMode(int dataPinSensor1) { byte temperature = 0; byte humidity = 0; int err = SimpleDHTErrSuccess; bool DispCond=false; Serial.begin(9600); delay(1500); if (Serial.read() == 't' ) { DispCond=true; //read temperature and compare it with an error value if((err = dht11.read(dataPinSensor1, &temperature, &humidity, NULL)) != SimpleDHTErrSuccess) { Serial.print("unreliable measurement or unselected functioning mode"); } byte f = temperature * 1.8 + 32; Serial.print((int)temperature); Serial.print(" *C, "); Serial.print((int)f); Serial.print(" *F, "); Serial.print((int)humidity); Serial.println(" H humidity"); delay(1500); } Serial.end(); if(DispCond==true) { //Setup the LCD myGLCD.InitLCD(); myGLCD.setFont(BigFont); //print value on LCD displayNoInit((int)temperature,(int)humidity); } } void SecondFuncMode(int dataPinSensor1,int del) { bool q=false; byte temperature = 0; byte humidity = 0; int err = SimpleDHTErrSuccess; Serial.begin(9600); del=DataAqPeriod(); Serial.end(); //Setup the LCD myGLCD.InitLCD(); myGLCD.setFont(BigFont); while(q==false) { Serial.begin(9600); //read temperature and compare it with an error value if((err = dht11.read(dataPinSensor1, &temperature, &humidity, NULL)) != SimpleDHTErrSuccess) { Serial.print("unreliable measurement or unselected functioning mode \n"); } float f = temperature * 1.8 + 32; Serial.print((int)temperature); Serial.print(" *C, "); Serial.print((int)f); Serial.print(" *F, "); Serial.print((int)humidity); Serial.println(" H humidity"); delay(del); if(Serial.read() == 'q') q=true; Serial.end(); displayNoInit((int)temperature,(int)humidity); delay(10); } } void displayNoInit(int temperature,int humidity) { //effective data display myGLCD.clrScr(); myGLCD.setColor(255, 255, 0); myGLCD.setBackColor(10,10,10); myGLCD.print(" Temperature ", CENTER, 10); myGLCD.setColor(254, 254, 254); myGLCD.printNumI(temperature, CENTER, 45); myGLCD.setColor(255, 255, 0); myGLCD.print("C ", RIGHT, 45); myGLCD.print("Relative Hum.", CENTER, 90); myGLCD.setColor(204, 245, 250); myGLCD.printNumI(humidity, CENTER, 120); myGLCD.print("%", RIGHT, 120); }
You are correct in the definition that Serial.end() does not disable the serial monitor, only the interrupts. After calling Serial.end() you can disable the serial monitor like so. #include <avr/io.h> // Save status register, disable interrupts uint8_t oldSREG = SREG; cli(); // Disable TX and RX cbi(UCSRB, RXEN); cbi(UCSRB, TXEN); // Disable RX ISR cbi(UCSRB, RXCIE); // Flush the internal buffer Serial.flush(); // Restore status register SREG = oldSREG;
Reading and transferring encoder data from slave Arduino to master Arduino over SPI
My goal is to transfer a speed value from an encoder from a slave Arduino to a master Arduino via SPI. I am currently getting zeros on the master side serial print and I'm not sure what I am doing wrong. I have increased the amount of time to wait several times to see if it was a processing time issue but I had it waiting for 100mS with still no change. I know an unsigned int is 4 bytes and I am unsure if a union is the best option in this case seeing I might be overwriting my data due to the separate interrupts but I am unsure. I thought to use a struct since I'll have to move to transferring an array of floats and ints over SPI from various sensors including this encoder later. Below is my code and thank you for any help received: Slave #include "math.h" #define M_PI byte command = 0; const int encoder_a = 2; // Green - pin 2 - Digital const int encoder_b = 3; // White - pin 3 - Digital long encoder = 0; int Diameter = 6; // inches float previous_distance = 0; unsigned long previous_time = 0; void setup (void) { Serial.begin(115200); pinMode(MOSI, INPUT); pinMode(SCK, INPUT); pinMode(SS, INPUT); pinMode(MISO, OUTPUT); // turn on SPI in slave mode SPCR |= _BV(SPE); // turn on interrupts SPCR |= _BV(SPIE); pinMode(encoder_a, INPUT_PULLUP); pinMode(encoder_b, INPUT_PULLUP); attachInterrupt(0, encoderPinChangeA, CHANGE); attachInterrupt(1, encoderPinChangeB, CHANGE); } // SPI interrupt routine ISR (SPI_STC_vect) { union Data{ float f; byte buff[4];} data; byte c = SPDR; data.f = assembly_speed(); command = c; switch (command) { // no command? then this is the command case 0: SPDR = 0; break; // incoming byte, return byte result case 'a': SPDR = data.buff[0]; break; // incoming byte, return byte result case 'b': SPDR = data.buff[1]; break; // incoming byte, return byte result case 'c': SPDR = data.buff[2]; break; // incoming byte, return byte result case 'd': SPDR = data.buff[3]; break; } } void loop (void) { // if SPI not active, clear current command if (digitalRead (SS) == HIGH) command = 0; } void encoderPinChangeA() { encoder += digitalRead(encoder_a) == digitalRead(encoder_b) ? -1 : 1; } void encoderPinChangeB() { encoder += digitalRead(encoder_a) != digitalRead(encoder_b) ? -1 : 1; } float distance_rolled() { float distance_traveled = (float (rotation()) / 8) * PI * Diameter; return distance_traveled; } int rotation() { float eigth_rotation = encoder / 300; return eigth_rotation; } float assembly_speed() { float current_distance = (float (rotation()) / 8) * PI * Diameter; unsigned long current_time = millis(); unsigned long assemblySpeed = (((current_distance - previous_distance) / 12) * 1000) / (current_time - previous_time); // gives ft/s previous_distance = current_distance; previous_time = current_time; return assemblySpeed; } Master #include <SPI.h> void setup (void) { pinMode(MOSI, OUTPUT); pinMode(MISO, INPUT); pinMode(SCK, OUTPUT); pinMode(SS, OUTPUT); Serial.begin (115200); Serial.println (); digitalWrite(SS, HIGH); SPI.begin (); SPI.setClockDivider(SPI_CLOCK_DIV8); } byte transferAndWait (const byte what) { byte a = SPI.transfer (what); delayMicroseconds(10000); return a; } union Data { float f; byte buff[4]; } data; void loop (void) { digitalWrite(SS, LOW); transferAndWait ('a'); data.buff[0] = transferAndWait ('b'); data.buff[1] = transferAndWait ('c'); data.buff[2] = transferAndWait ('d'); data.buff[3] = transferAndWait (0); digitalWrite(SS, HIGH); Serial.print("data.f = ");Serial.print(data.f);Serial.println(" Ft/s"); delay(200); }
microphone sph0645 with I2S less sensitive after watchdog sleep with Adafruit Feather M0
I am using the Adafruit Feather M0 RFM69 with the Adafruit I2S MEMS Microphone Breakout SPH0645. Every second I take a reading (sampleRate = 16000, bits per sample = 32) using the I2S library and send it over the radio. This all works fine. My problem is that, when I want to save power, I am getting weird readings after I wake the board from sleep (using Adafruit_SleepyDog library). The microphone somewhat still works, although it is much less sensitive, only picks up loud sounds and also returns 60dB in a quiet room. When I don't put it to sleep, in the same sound setting, I get 40dB. However, if I put a delay of 250ms after waking up, the microphone works fine again, like before, but this is obviously not saving energy then. I wonder why this is happening. Is there something I can do to get the microphone to work quicker? I checked the datasheet, but it only says: "When Vdd is applied the microphone senses the CLOCK line, if the frequency is greater than 900KHz, the microphone enters the normal mode of operation." This should not even take a few ms though? Thanks in advance #include <I2S.h> #include <Adafruit_SleepyDog.h> #include <SPI.h> #include <RH_RF69.h> /************ Radio Setup ***************/ #define RF69_FREQ 433.0 #define SLEEP //#if defined(ARDUINO_SAMD_FEATHER_M0) // Feather M0 w/Radio #define RFM69_CS 8 #define RFM69_INT 3 #define RFM69_RST 4 #define LED 13 //#endif // radio // Singleton instance of the radio driver RH_RF69 rf69(RFM69_CS, RFM69_INT); int transmit_interval = 1000; int time_counter = 0; int packetnum = 0; // MIC #define SAMPLES 1024//2048 // make it a power of two for best DMA performance int samples[SAMPLES]; int measurementsdB = 0; int current_measure; #define ADC_SOUND_REF 65 #define DB_SOUND_REF 41 int sampleRate1 = 16000; int bitsPerSample1 = 32; typedef struct { uint8_t measurementdB = 123; uint8_t battery = 111; uint8_t test = 222; } RadioMessage; RadioMessage struct_message; void setup() { delay(2000); // Wait so its easier to program Serial.begin(115200); //while (!Serial) { delay(1); } // wait until serial console is open, remove if not tethered to computer // Init Mic if (!I2S.begin(I2S_PHILIPS_MODE, sampleRate1, bitsPerSample1)) { while (1); // do nothing } pinMode(LED, OUTPUT); digitalWrite(LED, LOW); pinMode(RFM69_RST, OUTPUT); digitalWrite(RFM69_RST, LOW); Serial.println("Feather RFM69 TX Test!"); Serial.println(); // manual reset digitalWrite(RFM69_RST, HIGH); delay(10); digitalWrite(RFM69_RST, LOW); delay(10); if (!rf69.init()) { Serial.println("RFM69 radio init failed"); while (1); } Serial.println("RFM69 radio init OK!"); // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM (for low power module) // No encryption if (!rf69.setFrequency(RF69_FREQ)) { Serial.println("setFrequency failed"); } // If you are using a high power RF69 eg RFM69HW, you *must* set a Tx power with the // ishighpowermodule flag set like this: rf69.setTxPower(20, true); // range from 14-20 for power, 2nd arg must be true for 69HCW // The encryption key has to be the same as the one in the server uint8_t key[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; rf69.setEncryptionKey(key); Serial.print("RFM69 radio #"); Serial.print((int)RF69_FREQ); Serial.println(" MHz"); //GCLK->GENCTRL.bit.RUNSTDBY=1; // !! can go } void loop() { Serial.println("START"); ///// MIC //PM->APBCMASK.reg |= PM_APBCMASK_I2S; int a = 0; while (a == 0) a = I2S.available(); uint8_t current_measure = sample_audio_signal(samples); ///// RADIO if (true)//((time_counter + transmit_interval) < millis()) { struct_message.measurementdB = current_measure; //struct_message.battery = measuredvbat; // Send a message! /* Serial.print("Array content: "); uint8_t* bla = (uint8_t*) &struct_message; for (int i = 0; i < 3; i++) { Serial.println(bla[i]); }*/ rf69.send((const uint8_t*) &struct_message, sizeof(struct_message)); rf69.waitPacketSent(); Serial.print("Wait for reply"); // Now wait for a reply uint8_t buf[RH_RF69_MAX_MESSAGE_LEN]; uint8_t len = sizeof(buf); if (rf69.waitAvailableTimeout(100)) { // Should be a reply message for us now if (rf69.recv(buf, &len)) { Serial.print("Got a reply: "); Serial.println((char*)buf); } else { Serial.println("Receive failed"); } } else { Serial.println("No reply, is another RFM69 listening?"); } Serial.println("Radio sleeping"); rf69.sleep(); time_counter = millis(); } // sleep time #ifdef SLEEP int sleepMS = Watchdog.sleep(10); delay(250); #else delay(1000); #endif Serial.println("loop ended"); } void Blink(byte PIN, byte DELAY_MS, byte loops) { for (byte i=0; i<loops; i++) { digitalWrite(PIN,HIGH); delay(DELAY_MS); digitalWrite(PIN,LOW); delay(DELAY_MS); } } float sample_audio_signal(int samples[]) { for (int i=0; i<SAMPLES; i++) { int sample = 0; while ((sample == 0) || (sample == -1) ) { sample = I2S.read(); } // convert to 18 bit signed sample >>= 14; samples[i] = sample; } // ok we have the samples, get the mean (avg) float meanval = 0; for (int i=0; i<SAMPLES; i++) { meanval += samples[i]; } meanval /= SAMPLES; // subtract it from all samples to get a 'normalized' output for (int i=0; i<SAMPLES; i++) { samples[i] -= meanval; } // find the 'peak to peak' max float maxsample, minsample; minsample = 100000; maxsample = -100000; for (int i=0; i<SAMPLES; i++) { minsample = min(minsample, samples[i]); maxsample = max(maxsample, samples[i]); } int newdB = 20 * log10((float)maxsample / (float)ADC_SOUND_REF) + DB_SOUND_REF; return newdB;
Ok, the best I got it down to is 3.8mA. I only got so far by leaving the voltage regulator and the internal oscillator (DFLL) on during sleeping. After adding the following code to my setup routine, when board goes to sleep, the microphone still works after waking up: SYSCTRL->DFLLCTRL.bit.RUNSTDBY=1; SYSCTRL->VREG.bit.RUNSTDBY=1; However, ideally I would like to get much less than that, but then the mic doesn't work...