MAX17205(fuel gauge) Issue with COPY NV BLOCK [E904h] - arduino

from last 2 weeks I am trying to integrate an IC MAX17205 (Fuel Gauge) on arduino mega 2560. In that I am able to read and write registers but whenever I try to copy the content of Shadow RAM to Non Volatile Memory The CommStat.NVError gets High and Without that I cant modify PackCfg reg & get the voltage for 3S cell Configuration. Please Help me in this. I have provided link to the datasheet and code below.
MAX17205 Datasheet
max17205.ino
/**
This is an example demonstrating the use of the max1720x library
Print out the information to serial monitor at 115200 baud
*/
#include <Wire.h>
#include <max1720x.h>
max1720x gauge;
void setup()
{
Serial.begin(9600); // Initializes serial port
// Waits for serial port to connect. Needed for Leonardo only
while ( !Serial ) ;
gauge.reset(); // Resets MAX1720x
delay(200); // Waits for the initial measurements to be made
}
void loop()
{
// gauge.reset();
if (gauge.getAvgCurrent() != 0) {
Serial.println(gauge.getAvgCurrent());
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(MAX1720X_COMMAND_ADDR);
Wire.write(0x04);
Wire.write(0xE9);
// delay(500);
Wire.endTransmission();
delay(400);
}
else{
Serial.print("Capacity: ");
Serial.print(gauge.getCapacity()); // Gets the battery's state of charge
Serial.print(" mAh, TTE: ");
Serial.print(gauge.getTTE()); // Gets the battery's state of charge
Serial.print(" s, TTF: ");
Serial.print(gauge.getTTF()); // Gets the battery's state of charge
Serial.print(" s, Current: ");
Serial.print(gauge.getCurrent()); // Gets the battery's state of charge
Serial.print(" mA, Temperature: ");
Serial.print(gauge.getAvgCurrent()); // Gets the battery's state of charge
Serial.print(" mA, Temperature: ");
Serial.print(gauge.getTemperature()); // Gets the battery's state of charge
Serial.print(" degC, SOC: ");
Serial.print(gauge.getSOC()); // Gets the battery's state of charge
Serial.print("%, VCELL: ");
Serial.print(gauge.getVoltage()); // Gets the battery voltage
Serial.println('mV');
delay(2000);
}
}
MAX17205.c
/**
* Name: max1720x
* Author: Luka Mustafa - Institute IRNAS Race { info#irnas.eu }
* Version: 1.0
* Description: A library for interfacing the MAXIM MAX17201/MAX17205
* Li+ fuel gauges.
* Source: https://github.com/pAIgn10/max1720x
* License: Copyright (c) 2017 Nick Lamprianidis
* This library is licensed under the GPL license
* http://www.opensource.org/licenses/mit-license.php
* Inspiration: The library is inspired by: https://github.com/pAIgn10/max1720x
* Filename: max1720x.cpp
* File description: Definitions and methods for the max1720x library
*/
#include "max1720x.h"
// Initializes variables and the Wire library
max1720x::max1720x() {
Wire.begin();
}
// Returns a measurement of the voltage of the connected LiIon Polymer battery
double max1720x::getVoltage()
{
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(MAX1720X_VBAT_ADDR);
Wire.endTransmission(false);
Wire.requestFrom(MAX1720X_ADDR, (int)2,HIGH); //send stop
uint16_t combined = Wire.read()|(Wire.read()<<8); // LSB or-ed with MSB
double voltage = combined; //combine registers
return voltage*0.078125; // //calculate actual value and return in mV
}
double max1720x::getCurrent()
{
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(MAX1720X_CURENT_ADDR);
Wire.endTransmission(false);
Wire.requestFrom(MAX1720X_ADDR, (int)2,HIGH); //send stop
int16_t combined = Wire.read()|(Wire.read()<<8); // LSB or-ed with MSB
double current = (double)combined*0.0015625/0.01;
return current;//calculate actual value as 0.0015625 mV/Ohm
}
double max1720x::getAvgCurrent()
{
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(0x61);
Wire.endTransmission(false);
Wire.requestFrom(MAX1720X_ADDR, (int)2,HIGH); //send stop
int16_t combined = Wire.read()|(Wire.read()<<8); // LSB or-ed with MSB
double current = (double)combined*0.0015625/0.01;
return combined;//calculate actual value as 0.0015625 mV/Ohm
}
double max1720x::getTemperature()
{
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(MAX1720X_TEMP_ADDR);
Wire.endTransmission(false);
Wire.requestFrom(MAX1720X_ADDR, (int)2,HIGH); //send stop
int16_t combined = Wire.read()|(Wire.read()<<8); // LSB or-ed with MSB
double temperature = (double)combined/256;
return temperature;
}
// Returns the relative state of charge of the connected LiIon Polymer battery
// as a percentage of the full capacity w/ resolution 1/256%
double max1720x::getSOC()
{
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(MAX1720X_REPSOC_ADDR);
Wire.endTransmission(false);
Wire.requestFrom(MAX1720X_ADDR, (int)2);
uint16_t combined = Wire.read()|(Wire.read()<<8); // LSB or-ed with MSB
double soc = combined; //combine registers
return soc/256; //calculate actual value and return in %
}
// RepCap or reported capacity is a filtered version of the AvCap register that prevents large jumps in the reported value caused by changes in the application such as abrupt changes in temperature or load current.
double max1720x::getCapacity()
{
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(MAX1720X_REPCAP_ADDR);
Wire.endTransmission(false);
Wire.requestFrom(MAX1720X_ADDR, (int)2);
uint16_t combined = Wire.read()|(Wire.read()<<8); // LSB or-ed with MSB
double capacity = (double)combined*0.005/0.01;
return capacity;//calculate actual value as 0.005 mVh/Ohm
}
// The TTE register holds the estimated time to empty for the application under present temperature and load conditions
double max1720x::getTTE()
{
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(MAX1720X_TTE_ADDR);
Wire.endTransmission(false);
Wire.requestFrom(MAX1720X_ADDR, (int)2);
uint16_t combined = Wire.read()|(Wire.read()<<8); // LSB or-ed with MSB
double capacity = (double)combined*5.625;
return capacity;//calculate actual value as value*5.625s
}
// The TTF register holds the estimated time to full for the application under present conditions.
double max1720x::getTTF()
{
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(MAX1720X_TTF_ADDR);
Wire.endTransmission(false);
Wire.requestFrom(MAX1720X_ADDR, (int)2);
uint16_t combined = Wire.read()|(Wire.read()<<8); // LSB or-ed with MSB
double capacity = (double)combined*5.625;
return capacity;//calculate actual value as value*5.625s
}
// Status Register (000h) The Status register maintains all flags related to alert thresholds and battery insertion or removal.
uint16_t max1720x::getStatus()
{
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(MAX1720X_STATUS_ADDR);
Wire.endTransmission(false);
Wire.requestFrom(MAX1720X_ADDR, (int)2);
uint16_t combined = Wire.read()|(Wire.read()<<8); // LSB or-ed with MSB
return combined;
}
// Reset procedure
uint8_t max1720x::reset()
{
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(MAX1720X_COMMAND_ADDR);
Wire.write(0x0f);
Wire.write(0x00);
Wire.endTransmission();
delay(50);
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(MAX1720X_CONFIG2_ADDR);
Wire.write(0x01);
Wire.write(0x00);
delay(50);
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(MAX1720X_nPackcfg);
Wire.write(0x03);
Wire.write(0x0A);
Wire.endTransmission();
delay(50);
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(0x61);
Wire.write(0x00);
Wire.write(0x00);
Wire.endTransmission();
delay(50);
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(MAX1720X_COMMAND_ADDR);
Wire.write(0xE0);
Wire.write(0x01);
Wire.endTransmission();
delay(400);
return;
}
MAX17205.h
/**
* Name: max1720x
* Author: Luka Mustafa - Institute IRNAS Race { info#irnas.eu }
* Version: 1.0
* Description: A library for interfacing the MAXIM MAX17201/MAX17205
* Li+ fuel gauges.
* Source: https://github.com/pAIgn10/LiFuelGauge
* License: Copyright (c) 2017 Nick Lamprianidis
* This library is licensed under the GPL license
* http://www.opensource.org/licenses/mit-license.php
* Inspiration: The library is inspired by: https://github.com/pAIgn10/LiFuelGauge
* Filename: max1720x.h
* File description: Definitions and methods for the max1720x library
*/
#ifndef max1720x
#define max1720x_h
#include <Arduino.h>
#include <Wire.h>
// MAX1720X register addresses
const int MAX1720X_ADDR = 0x36;
const int MAX1720X_STATUS_ADDR = 0x00; // Contains alert status and chip status
const int MAX1720X_VCELL_ADDR = 0x09; // Lowest cell voltage of a pack, or the cell voltage for a single cell
const int MAX1720X_REPSOC_ADDR = 0x06; // Reported state of charge
const int MAX1720X_REPCAP_ADDR = 0x05; // Reported remaining capacity
const int MAX1720X_TEMP_ADDR = 0x08; // Temperature
const int MAX1720X_CURENT_ADDR = 0x0A; // Battery current
const int MAX1720X_AVG_CURENT_ADDR = 0x29; // Battery current
const int MAX1720X_TTE_ADDR = 0x11; // Time to empty
const int MAX1720X_TTF_ADDR = 0x20; // Time to full
const int MAX1720X_CAPACITY_ADDR = 0x10; // Full capacity estimation
const int MAX1720X_VBAT_ADDR = 0xDA; // Battery pack voltage
const int MAX1720X_AVCELL_ADDR = 0x17; // Battery cycles
const int MAX1720X_COMMAND_ADDR = 0x60; // Command register
const int MAX1720X_CONFIG2_ADDR = 0xbb; // Command register
const int MAX1720X_nPackcfg = 0xBD;
const int MAX1720X_WriteSlave = 0x6C;
// Class for interfacing the MAX1720X Li+ fuel gauges
class max1720x
{
public:
max1720x();
double getVoltage();
double getSOC();
double getTemperature();
double getCurrent();
double getAvgCurrent();
double getCapacity();
double getTTE();
double getTTF();
uint8_t reset();
private:
uint16_t getStatus();
};
#endif // max1720x

In case it may help someone (i got here via google search):
I've been struggling with that procedure too, but got it working now.
This is my first I2C experience ever, so i think there's a lot of space for improving my code.
For me it's working like that:
const int MAX1720x_nV = 0x0b; // shifted 0x16
int a = 0; // to repeat NVCopy in case of failure
// Full Reset procedure
uint8_t max1720x::reset()
{
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(MAX1720X_COMMAND_ADDR); // Hardware reset
Wire.write(0x0f);
Wire.write(0x00);
Wire.endTransmission(true);
delay(50);
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(MAX1720X_CONFIG2_ADDR); // Fuel Gauge reset
Wire.write(0x01);
Wire.write(0x00);
return Wire.endTransmission(true); // delay(at least 10) after this function
}
// copy the shadow RAM to the nonvolatile Block
void max1720x::copyNV()
{
Wire.beginTransmission(MAX1720x_nV);
Wire.write(0x8e); // nODSCTh
Wire.write(0x00); // 16 bit Value to write there
Wire.write(0x00); // continued
Wire.endTransmission(false);
Wire.beginTransmission(MAX1720x_nV);
Wire.write(0x8f); // nODSCCfg
Wire.write(0x00); // 16 bit Value to write there
Wire.write(0x00); // continued
Wire.endTransmission(false);
.
. // add more configuarations as desired
.
// start NVCopy procedure
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(0x61); // clear commstat register
Wire.write(0x00);
Wire.write(0x00);
Wire.endTransmission(true);
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(0x60); // write E904h to 60h as described in datasheet
Wire.write(0x04);
Wire.write(0xe9);
Wire.endTransmission(true);
delay(1000); // can probably be shorter
Wire.beginTransmission(MAX1720X_ADDR); // read the CommStat.NVError
Wire.write(0x61);
Wire.endTransmission(false);
Wire.requestFrom(MAX1720x_nV, (int)2, true);
uint8_t combined = Wire.read()|(Wire.read()<<8);
Wire.endTransmission(true);
Serial.println(combined); // not neccessary, just for me
Serial.println(a);
if ((combined != 0) && (a == 1)) {
Serial.println(a);
Serial.println("failed more than once");
return;
}
if ((combined != 0) && (a == 0)) {
Serial.println("failed once");
a++;
max1720x::copyNV();
}
else if (combined == 0) { // if NVError is empty, finish the routine
Serial.println("CopyNV success!");
delay(500);
max1720x::reset(); // initiate a full reset
delay(150);
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(0xba); // probably not neccessary
Wire.write(0x00); // something with hibernate mode?
Wire.write(0x00);
Wire.endTransmission(true);
Wire.beginTransmission(MAX1720X_ADDR);
Wire.write(MAX1720X_COMMAND_ADDR);
Wire.write(0x80); // probably not neccessary
Wire.write(0x00); // something with hibernate mode?
Wire.endTransmission(true);
max1720x::reset(); // initiate a full reset, probably not neccessary
delay(500);
return;
}
}

Related

TTGO ESP32 + GSM 800l AT Commands

Good day all
I'm working on a project that takes sensor data and sends it to an online database using HTTP requests.Im ussing the TTGO esp32 sim 800 board, Everything works fine and all the data is stored in my online database the problem is that I cant get the AT commands to work, I need the Signal strength, battery voltage, and amount of Data available on the sim card.
Can someone please assist with this matter?
kind regards Hansie
Code
#include <HCSR04.h>
#define SOUND_SPEED 0.034
#define CM_TO_INCH 0.393701
// Set serial for debug console (to Serial Monitor, default speed 115200)
#define SerialMon Serial
// Set serial for AT commands (to SIM800 module)
#define SerialAT Serial1
// Configure TinyGSM library
#define TINY_GSM_MODEM_SIM800 // Modem is SIM800
#define TINY_GSM_RX_BUFFER 1024 // Set RX buffer to 1Kb
// Define the serial console for debug prints, if needed
//#define DUMP_AT_COMMANDS
#include <Wire.h>
#include <TinyGsmClient.h>
#define uS_TO_S_FACTOR 1000000UL /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP 36 /* Time ESP32 will go to sleep (in seconds) 3600 seconds = 1 hour */
#define IP5306_ADDR 0x75
#define IP5306_REG_SYS_CTL0 0x00
// TTGO T-Call pins
#define MODEM_RST 5
#define MODEM_PWKEY 4
#define MODEM_POWER_ON 23
#define MODEM_TX 27
#define MODEM_RX 26
#define I2C_SDA 21
#define I2C_SCL 22
int deviceID=101;
const int trigPin = 5;
const int echoPin = 18;
//Calculation variable for depth
//define sound speed in cm/uS
long duration;
float distanceCm;
double damDepth =200;
// Your GPRS credentials
const char apn[] = "Vodacom APN"; // APN
const char gprsUser[] = ""; // GPRS User
const char gprsPass[] = ""; // GPRS Password
// SIM card PIN (leave empty, if not defined)
const char simPIN[] = "";
// Server details
const char server[] = "grow-with-pierre.com"; // domain name:
const char resource[] = "/post-data.php"; // resource path, for example: /post-data.php
const int port = 80; // server port number
// Keep this API Key value to be compatible with the PHP code
String apiKeyValue = "tPmAT5Ab3j7F9";
#ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm modem(debugger);
#else
TinyGsm modem(SerialAT);
#endif
// I2C for SIM800 (to keep it running when powered from battery)
TwoWire I2CPower = TwoWire(0);
// TinyGSM Client for Internet connection
TinyGsmClient client(modem);
bool setPowerBoostKeepOn(int en)
{
I2CPower.beginTransmission(IP5306_ADDR);
I2CPower.write(IP5306_REG_SYS_CTL0);
if (en)
{
I2CPower.write(0x37); // Set bit1: 1 enable 0 disable boost keep on
} else
{
I2CPower.write(0x35); // 0x37 is default reg value
}
return I2CPower.endTransmission() == 0;
}
void setup()
{
Serial.begin(115200); // Starts the serial communication
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
// Set serial monitor debugging window baud rate to 115200
SerialMon.begin(115200);
// Start I2C communication
I2CPower.begin(I2C_SDA, I2C_SCL, 400000);
// Keep power when running from battery
bool isOk = setPowerBoostKeepOn(1);
SerialMon.println(String("IP5306 KeepOn ") + (isOk ? "OK" : "FAIL"));
// Set modem reset, enable, power pins
pinMode(MODEM_PWKEY, OUTPUT);
pinMode(MODEM_RST, OUTPUT);
pinMode(MODEM_POWER_ON, OUTPUT);
digitalWrite(MODEM_PWKEY, LOW);
digitalWrite(MODEM_RST, HIGH);
digitalWrite(MODEM_POWER_ON, HIGH);
// Set GSM module baud rate and UART pins
SerialAT.begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX);
delay(3000);
// Restart SIM800 module, it takes quite some time
// To skip it, call init() instead of restart()
SerialMon.println("Initializing modem...");
modem.restart();
// use modem.init() if you don't need the complete restart
// Unlock your SIM card with a PIN if needed
if (strlen(simPIN) && modem.getSimStatus() != 3 )
{
modem.simUnlock(simPIN);
}
// Configure the wake up source as timer wake up
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
}
void loop()
{
postData();
Serial.print(String(" Percentage: ") + depth());
// Put ESP32 into deep sleep mode (with timer wake up)
esp_deep_sleep_start();
}
String postData()
{
SerialMon.print("Connecting to APN: ");
SerialMon.print(apn);
if (!modem.gprsConnect(apn, gprsUser, gprsPass))
{
SerialMon.println(" fail");
}
else
{
SerialMon.println(" OK");
SerialMon.print("Connecting to ");
SerialMon.print(server);
if (!client.connect(server, port))
{
SerialMon.println(" fail");
}
else
{
SerialMon.println(" OK");
// Making an HTTP POST request
SerialMon.println("Performing HTTP POST request...");
String httpRequestData = "api_key=" + apiKeyValue + "&value1=" + String(deviceID)
+ "&value2=" + String(distanceCm) + "&value3=" + String(80) + "&value4=" + String(40) + ""+ "&value5=" + String(50) + "";
// then, use the httpRequestData variable below (for testing purposes without the BME280 sensor)
// String httpRequestData = "api_key=tPmAT5Ab3j7F9&value1=24.75&value2=49.54&value3=1005.14";
client.print(String("POST ") + resource + " HTTP/1.1\r\n");
client.print(String("Host: ") + server + "\r\n");
client.println("Connection: close");
client.println("Content-Type: application/x-www-form-urlencoded");
client.print("Content-Length: ");
client.println(httpRequestData.length());
client.println();
client.println(httpRequestData);
unsigned long timeout = millis();
while (client.connected() && millis() - timeout < 10000L)
{
// Print available data (HTTP response from server)
while (client.available())
{
char c = client.read();
SerialMon.print(c);
timeout = millis();
}
}
SerialMon.println();
// Close client and disconnect
client.stop();
SerialMon.println(F("Server disconnected"));
modem.gprsDisconnect();
SerialMon.println(F("GPRS disconnected"));
}
}
}
float depth() //Find Depth in cm
{
double persentage;
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculate the distance
distanceCm = duration * SOUND_SPEED/2;
// Prints the distance in the Serial Monitor
Serial.print("Distance (cm): ");
Serial.println(distanceCm);
persentage = (distanceCm/damDepth)*100;
if(persentage>=100)
{
persentage=100;
}
else
{
persentage=100- persentage;
}
return persentage;
}
For at least some of the desired functions, it isn't necessary to push AT-commands.
Try signalStrength = modem.getSignalQuality(); instead. It works for me on the Lilygo T-Call SIM800L. You can check out TinyGSM's Github-page for additional commands or this handy class reference

SPI Problem Arduino Mega with pressure sensor MS5803-05BA

I need your help for a project.
I have actually 2 parallel sensors of the type: MS5803-05BA, which supports I2C and SPI connection. One sensor is on I2C bus and one sensor is on SPI. They are both sending to my Arduino Mega. The I2C works perfect with short cables.
Here the datasheet of the sensor:
https://www.amsys.de/downloads/data/MS5803-05BA-AMSYS-datasheet.pdf
For some informations who wants to do the same with I2C. Here you can find a good code. (You can find the other MS580X typs there too). For the communication between the sensor and the Arduino Mega you need an logic converter like this txs0108e, which can be bought with a break out board (you need pull up resistors on the sensor side!):
https://github.com/millerlp/MS5803_05
But to my problem: I have an sensor distance for about 3-5 meters and the I2C connections doesnt work. Yes I can try to fix the pullup resistors but it doesnt worked for me (I have tried some different lower resistors between 3-10kOhm). Therefore I want to switch to the SPI bus.
I have edit the code from https://github.com/millerlp/MS5803_05, https://github.com/vic320/Arduino-MS5803-14BA and https://arduino.stackexchange.com/questions/13720/teensy-spi-and-pressure-sensor.
The File is added. (You have to put the .h and .cpp files in the folder of the arduino code (.spi).
I have problems with the code from the SPI (ccp and header). There is no right communication. I have checked my cables twice. I couldnt find a problem and the connection with the txs0108e works for parallel I2C sensor. Both sensors are working on I2C.
Here is the main code (arduino .spi) for SPI and I2C parallel:
/_____ I N C L U D E S
#include <stdio.h>
#include <math.h>
#include <SPI.h>
#include <Wire.h>
#include "MS5803_05.h"
#include "MS5803_05_SPI.h"
const int miso_port = 50; //SDI
const int mosi_port = 51; //SDO
const int sck_port = 52; //SLCK
const int slaveSelectPin = 53; // CSB
MS_5803 sensor = MS_5803(512);
MS_5803_SPI sensor_spi = MS_5803_SPI(4096, slaveSelectPin);
void setup()
{
pinMode(miso_port, INPUT);
pinMode(mosi_port, OUTPUT);
pinMode(slaveSelectPin, OUTPUT);
pinMode(sck_port, OUTPUT);
Serial.begin(9600);
//SPI BUS
if (sensor_spi.initializeMS_5803_SPI()) {
Serial.println( "MS5803 SPI CRC check OK." );
}
else {
Serial.println( "MS5803 SPI CRC check FAILED!" );
}
//I2C BUS
delay(1000);
if (sensor.initializeMS_5803()) {
Serial.println( "MS5803 I2C CRC check OK." );
}
else {
Serial.println( "MS5803 I2C CRC check FAILED!" );
}
}
void loop()
{
Serial.println("SPI Sensor first pressure [mbar], than temperature[°C]:");
sensor_spi.readSensor();
// Show pressure
Serial.print("Pressure = ");
Serial.print(sensor_spi.pressure());
Serial.println(" mbar");
// Show temperature
Serial.print("Temperature = ");
Serial.print(sensor_spi.temperature());
Serial.println("C");
////********************************************************
Serial.println("");
Serial.println("I2C Sensor first pressure [mbar], than temperature[°C]:");
sensor.readSensor();
// Show pressure
Serial.print("Pressure = ");
Serial.print(sensor.pressure());
Serial.println(" mbar");
// Show temperature
Serial.print("Temperature = ");
Serial.print(sensor.temperature());
Serial.println("C");
delay(2000);
}
}
The first connection with SPI is here (.cpp):
#include "MS5803_05_SPI.h"
#include <SPI.h>
#define CMD_RESET 0x1E // ADC reset command
#define CMD_ADC_READ 0x00 // ADC read command
#define CMD_ADC_CONV 0x40 // ADC conversion command
#define CMD_ADC_D1 0x00 // ADC D1 conversion
#define CMD_ADC_D2 0x10 // ADC D2 conversion
#define CMD_ADC_256 0x00 // ADC resolution=256
#define CMD_ADC_512 0x02 // ADC resolution=512
#define CMD_ADC_1024 0x04 // ADC resolution=1024
#define CMD_ADC_2048 0x06 // ADC resolution=2048
#define CMD_ADC_4096 0x08 // ADC resolution=4096
#define CMD_PROM_RD 0xA0 // Prom read command
#define spi_write SPI_MODE3
#define spi_write2 SPI_MODE1
// Create array to hold the 8 sensor calibration coefficients
static unsigned int sensorCoeffs[8]; // unsigned 16-bit integer (0-65535)
// D1 and D2 need to be unsigned 32-bit integers (long 0-4294967295)
static uint32_t D1 = 0; // Store uncompensated pressure value
static uint32_t D2 = 0; // Store uncompensated temperature value
// These three variables are used for the conversion steps
// They should be signed 32-bit integer initially
// i.e. signed long from -2147483648 to 2147483647
static int32_t dT = 0;
static int32_t TEMP = 0;
// These values need to be signed 64 bit integers
// (long long = int64_t)
static int64_t Offset = 0;
static int64_t Sensitivity = 0;
static int64_t T2 = 0;
static int64_t OFF2 = 0;
static int64_t Sens2 = 0;
// Some constants used in calculations below
const uint64_t POW_2_33 = 8589934592ULL; // 2^33 = 8589934592
SPISettings settings_write(500000, MSBFIRST, spi_write);
SPISettings settings_write2(500000, MSBFIRST, spi_write2);
//-------------------------------------------------
// Constructor
MS_5803_SPI::MS_5803_SPI( uint16_t Resolution, uint16_t cs) {
// The argument is the oversampling resolution, which may have values
// of 256, 512, 1024, 2048, or 4096.
_Resolution = Resolution;
//Chip Select
_cs=cs;
}
boolean MS_5803_SPI::initializeMS_5803_SPI(boolean Verbose) {
digitalWrite( _cs, HIGH );
SPI.begin();
// Reset the sensor during startup
resetSensor();
if (Verbose)
{
// Display the oversampling resolution or an error message
if (_Resolution == 256 | _Resolution == 512 | _Resolution == 1024 | _Resolution == 2048 | _Resolution == 4096){
Serial.print("Oversampling setting: ");
Serial.println(_Resolution);
} else {
Serial.println("*******************************************");
Serial.println("Error: specify a valid oversampling value");
Serial.println("Choices are 256, 512, 1024, 2048, or 4096");
Serial.println("*******************************************");
}
}
// Read sensor coefficients
for (int i = 0; i < 8; i++ )
{
SPI.beginTransaction(settings_write2);
digitalWrite(_cs, LOW); //csb_lo(); // pull CSB low
unsigned int ret;
unsigned int rC = 0;
SPI.transfer(CMD_PROM_RD + i * 2); // send PROM READ command
/*
ret = SPI.transfer(0x00); // send 0 to read the MSB
rC = 256 * ret;
ret = SPI.transfer(0x00); // send 0 to read the LSB
rC = rC + ret;
*/
// send a value of 0 to read the first byte returned:
rC = SPI.transfer( 0x00 );
rC = rC << 8;
rC |= SPI.transfer( 0x00 ); // and the second byte
sensorCoeffs[i] = (rC);
digitalWrite( _cs, HIGH );
delay(3);
}
//SPI.endTransaction(); // interrupt can now be accepted
// The last 4 bits of the 7th coefficient form a CRC error checking code.
unsigned char p_crc = sensorCoeffs[7];
// Use a function to calculate the CRC value
unsigned char n_crc = MS_5803_CRC(sensorCoeffs);
if (Verbose) {
for (int i = 0; i < 8; i++ )
{
// Print out coefficients
Serial.print("C");
Serial.print(i);
Serial.print(" = ");
Serial.println(sensorCoeffs[i]);
delay(10);
}
Serial.print("p_crc: ");
Serial.println(p_crc);
Serial.print("n_crc: ");
Serial.println(n_crc);
}
// If the CRC value doesn't match the sensor's CRC value, then the
// connection can't be trusted. Check your wiring.
if (p_crc != n_crc) {
return false;
}
// Otherwise, return true when everything checks out OK.
return true;
}
// Sends a power on reset command to the sensor.
void MS_5803_SPI::resetSensor() {
SPI.beginTransaction(settings_write);
digitalWrite(_cs, LOW); //csb_lo(); // pull CSB low to start the command
SPI.transfer(CMD_RESET); // send reset sequence
delay(3); // wait for the reset sequence timing delay(3)
digitalWrite(_cs, HIGH); //csb_hi(); // pull CSB high to finish the command
SPI.endTransaction(); // interrupt can now be accepted
}
The Code can be downloaded at: https://forum.arduino.cc/index.php?topic=670661.0
There you can find the schematic and output picture too.
Thanks a lot :).

Trying to send a float value over SPI between 2 Arduinos

I am currently trying to send a float value across two Arduinos via SPI. Currently I am working to send a static value of 2.25 across and then read it via the Serial.println() command. I would then want to pass a float value from a linear displacement sensor. My end goal is to be able to have the master ask for information, the slave gathers the appropriate data and packages it and then master receives said data and does what it needs with it.
Currently I am getting an error "call of overloaded 'println(byte [7])' is ambiguous" and I am not to sure why I am getting this error. I am currently a mechanical engineering student and I am crash-coursing myself through C/C++. I am not entirely positive about what I am doing. I know that a float is 4 bytes and I am attempting to create a buffer of 7 bytes to store the float and the '\n' char with room to spare. My current code is below.
Master:
#include <SPI.h>
void setup() {
pinMode(SS,OUTPUT);
digitalWrite(SS,HIGH);
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV4);
}
void loop() {
digitalWrite(SS,LOW);
float a = 2.25;
SPI.transfer(a);
SPI.transfer('\n');
digitalWrite(SS,HIGH);
}
My slave code is as follows:
#include <SPI.h>
byte buf[7];
volatile byte pos = 0;
volatile boolean process_it = false;
void setup() {
Serial.begin(9600);
pinMode(MISO,OUTPUT);
digitalWrite(MISO,LOW);
SPCR |= _BV(SPE); // SPI Enable, sets this Arduino to Slave
SPCR |= _BV(SPIE); // SPI interrupt enabled
}
ISR(SPI_STC_vect) {
// Interrupt Service Routine(SPI_(SPI Transfer Complete)_vector)
byte c = SPDR;
// SPDR = SPI Data Register, so you are saving the byte of information in that register to byte c
if (pos < sizeof buf) {
buf[pos++] = c;
if (c == '\n') {
process_it = true;
}
}
}
void loop() {
if (process_it = true) {
Serial.println(buf);
pos = 0;
process_it = false;
}
}
I figured out what I needed to do and I wanted to post my finished code. I also added an ability to transfer more than one float value.
Master:
#include <SPI.h>
float a = 3.14;
float b = 2.25;
uint8_t storage [12];
float buff[2] = {a, b};
void setup()
{
digitalWrite(SS, HIGH);
SPI.begin();
Serial.begin(9600);
SPI.setClockDivider(SPI_CLOCK_DIV8);
}
void loop()
{
digitalWrite(SS, LOW);
memcpy(storage, &buff, 8);
Serial.print("storage[0] = "); Serial.println(storage[0]); // the
following serial prints were to check i was getting the right decimal
numbers for the floats.
Serial.print("storage[1] = "); Serial.println(storage[1]);
Serial.print("storage[2] = "); Serial.println(storage[2]);
Serial.print("storage[3] = "); Serial.println(storage[3]);
Serial.print("storage[4] = "); Serial.println(storage[4]);
Serial.print("storage[5] = "); Serial.println(storage[5]);
Serial.print("storage[6] = "); Serial.println(storage[6]);
Serial.print("storage[7] = "); Serial.println(storage[7]);
SPI.transfer(storage, sizeof storage ); //SPI library allows a user to
transfer a whole array of bytes and you need to include the size of the
array.
digitalWrite(SS, HIGH);
delay(1000);
}
For my Slave code:
#include <SPI.h>
byte storage [8];
volatile byte pos;
volatile boolean process;
float buff[2];
void setup()
{
pinMode(MISO,OUTPUT);
SPCR |= _BV(SPE);
SPCR |= _BV(SPIE);
pos = 0;
process = false;
Serial.begin(9600);
}
ISR(SPI_STC_vect)
{
byte gathered = SPDR;
if( pos < sizeof storage)
{
storage[pos++] = gathered;
}
else
process = true;
}
void loop()
{
if( process )
{
Serial.print("storage[0] = "); Serial.println(storage[0]);
Serial.print("storage[1] = "); Serial.println(storage[1]);
Serial.print("storage[2] = "); Serial.println(storage[2]);
Serial.print("storage[3] = "); Serial.println(storage[3]);
Serial.print("storage[4] = "); Serial.println(storage[4]);
Serial.print("storage[5] = "); Serial.println(storage[5]);
Serial.print("storage[6] = "); Serial.println(storage[6]);
Serial.print("storage[7] = "); Serial.println(storage[7]);
memcpy(buff,&storage,8);
Serial.print("This is buff[0]");Serial.println(buff[0]);
Serial.print("This is buff[1]");Serial.println(buff[1]);
storage[pos] = 0;
pos = 0;
process = false;
}
}
The immediate problem is that Serial.print doesn't know what to do with a byte array. Either declare it as a char array or cast it in the print statement:
char buf[7];
OR
Serial.print((char*) buf);
Either way, though, it's not going to show up as a float like you want.
An easier way to do all this is to use memcpy or a union to go back and forth between float and bytes. On the master end:
uint8_t buf[4];
memcpy(buf, &a, 4);
Then use SPI to send 4 bytes. Reverse it on the peripheral end.
Note that sending '\n' as the termination byte is a bad idea because it can lead to weird behavior, since one of the bytes in the float could easily be 0x0a, the hexadecimal equivalent of '\n'.

Why Arduino int can't count over 14464?

I got some problem about reading from MPU6050 and then write to SD card.
Actually I could successfully do the read-and-write, but I found Arduino UNO can't count over 14464!?
I set every line of my data that is:
count, time(millis()), ax, ay, az, gx, gy, gz
It could record the data right till count to 14464 (I) and it will end the loop automated.
It really bothers me... and it seems no one face this problem before.
Here is my code:
#include "I2Cdev.h"
#include "MPU6050.h"
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
MPU6050 accelgyro;
//SD card here
#include <SPI.h>
#include <SD.h>
File myFile;
//////////Global Variable Here//////////
int16_t ax, ay, az;
int16_t gx, gy, gz;
int count = 1;
//set sec & count_limit
int set_time = 1000 * 60;
int count_limit = 80000;
int BTN = 7;
// uncomment "OUTPUT_READABLE_ACCELGYRO" if you want to see a tab-separated
// list of the accel X/Y/Z and then gyro X/Y/Z values in decimal. Easy to read,
// not so easy to parse, and slow(er) over UART.
#define OUTPUT_READABLE_ACCELGYRO
//Set LED
#define R_PIN 8
#define G_PIN 9
bool blinkState_R = false;
bool blinkState_G = false;
void setup() {
// configure Arduino LED for
pinMode(R_PIN, OUTPUT);
pinMode(G_PIN, OUTPUT);
pinMode(BTN, INPUT);
digitalWrite(G_PIN, HIGH);
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
// initialize serial communication
// (38400 chosen because it works as well at 8MHz as it does at 16MHz, but
// it's really up to you depending on your project)
Serial.begin(38400);
// initialize device
Serial.println("Initializing I2C devices...");
accelgyro.initialize();
accelgyro.setFullScaleAccelRange(MPU6050_ACCEL_FS_2);
// verify connection
Serial.println("Testing device connections...");
Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
// use the code below to change accel/gyro offset values
accelgyro.setXGyroOffset(59);
accelgyro.setYGyroOffset(42);
accelgyro.setZGyroOffset(-8);
accelgyro.setXAccelOffset(1359);
accelgyro.setYAccelOffset(-1620);
accelgyro.setZAccelOffset(1917);
/////////////////////////////////////////////////////////////////////
//SD card Initailize
/////////////////////////////////////////////////////////////////////
Serial.print("Initializing SD card...");
if (!SD.begin(4)) {
Serial.println("initialization failed!");
digitalWrite(R_PIN, HIGH);
return;
}
Serial.println("initialization done.");
digitalWrite(R_PIN, LOW);
if (SD.exists("example.txt")) {
Serial.println("example.txt exists.");
}
else {
Serial.println("example.txt doesn't exist.");
}
// open a new file and immediately close it:
Serial.println("Creating example.txt...");
myFile = SD.open("example.txt", FILE_WRITE);
myFile.close();
// Check to see if the file exists:
if (SD.exists("example.txt")) {
Serial.println("example.txt exists.");
}
else {
Serial.println("example.txt doesn't exist.");
}
// delete the file:
Serial.println("Removing example.txt...");
SD.remove("example.txt");
if (SD.exists("example.txt")) {
Serial.println("example.txt exists.");
}
else {
Serial.println("example.txt doesn't exist.");
}
delay(3000);
////////////////////////////////////////////////////////////////////////////////
//SD END
////////////////////////////////////////////////////////////////////////////////
digitalWrite(G_PIN, LOW);
}
void loop() {
// read raw accel/gyro measurements from device
accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
blinkState_R = !blinkState_R;
digitalWrite(R_PIN, blinkState_R);
// these methods (and a few others) are also available
//accelgyro.getAcceleration(&ax, &ay, &az);
//accelgyro.getRotation(&gx, &gy, &gz);
////////////////////////////////////////////
// Write to SD Card
///////////////////////////////////////////
// write data to file
if(count <= count_limit ){
myFile = SD.open("IMU_LOG.txt", FILE_WRITE);
Serial.print(count);Serial.print("\t"); myFile.print(count); myFile.print("\t");
Serial.print(millis()); Serial.print("\t"); myFile.print(millis()); myFile.print("\t");
Serial.print(ax); Serial.print("\t"); myFile.print(ax); myFile.print("\t");
Serial.print(ay); Serial.print("\t"); myFile.print(ay); myFile.print("\t");
Serial.print(az); Serial.print("\t"); myFile.print(az); myFile.print("\t");
Serial.print(gx); Serial.print("\t"); myFile.print(gx); myFile.print("\t");
Serial.print(gy); Serial.print("\t"); myFile.print(gy); myFile.print("\t");
Serial.print(gz); Serial.print("\n"); myFile.print(gz); myFile.print("\n");
myFile.close();
delay(5);
blinkState_G = !blinkState_G;
digitalWrite(G_PIN, blinkState_G);
}else{
while(1){
Serial.print("Process done.\n");
digitalWrite(G_PIN, OUTPUT);
delay(2000);
}
count= count + 1 ;
}
You should be getting a compiler warning here.
int count_limit = 80000;
The maximum value of int on your platform is 32,767. When you set an int to something larger, the behavior is undefined, which is bad news because it means that your program is incorrect.
In this particular case, you might notice that 80000 = 14464 + 216, which explains why it stopped at 14464, if int is 16 bits long.
You will need to use long if you want to count higher than 65,535.
long count_limit = 80000L;
long count = 1;

Arduino SNES wireless receiver code questions

I am building a transmitter and receiver pair for two SNES controllers, as I don't like using long extension cords to get the controllers to reach the couch. I'm using ATmega328Ps for the AVRs, with RF24l01 wireless transceivers (using ManiacBugs RF24 library). I am using a modified snesPad library on the transmitter to poll the button states of two controllers and return them as a 32-bit unsigned long, then transmitting that to the receiver. All standard libraries, no issues there (so far).
However, on the receiver side, I have to properly respond to the latch and clock signals from the SNES, and I haven't found any stock libraries for that. For those not familiar with the SNES controllers, they are basically two 8-bit parallel to serial shift registers in series. They latch all of the button states on the rising edge of the latch signal (12 µs pulse high, normally low), drive the first bit on the falling edge of latch, and then drive each successive bit on the rising edge of clock (6 µs delay from fall of latch, normally high, 6 µs low - 6 µs high cycle).
I've decided to use an external interrupt to trigger the proper behavior for the latch pulse and each clock pulse. I'm new to programming Arduinos though, and new to C/C++ as well. Although my code will compile, I'm not certain if it will actually function as intended. If someone who has some experience with AVR's could take a look at my code and let me know if it will work, and if not, where and why, I would be very grateful!
Arduino sketch follows:
/*
Copyright (C) 2012 John Byers <jbyers2#wgu.edu>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 3 as published by the Free Software Foundation
*/
/**
* Dual Wireless Retro Controller Adapter Transmitter
*
* This is the reciever side code for the adapter set.
*/
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
//
// Hardware Configuration
//
RF24 radio(9,10);
//
// Variable Inits
//
volatile unsigned long state2 = 0xFFFFFFFF;
volatile byte i = 0;
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
int strobe = 2;
int clock = 3;
volatile int data1 = 5;
volatile int data2 = 6;
bool firstLoop = true;
volatile int status2 = 1;
void setup()
{
radio.begin();
radio.setRetries(0,15);
radio.enableDynamicPayloads();
Serial.begin(57600);
pinMode(strobe, INPUT);
pinMode(clock, INPUT);
pinMode(data1, OUTPUT); digitalWrite(data1, LOW);
pinMode(data2, OUTPUT); digitalWrite(data2, LOW);
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
//
//Dump the configuration of the RF unit for debugging
//
radio.printDetails();
//
//Setup Interupts
//
attachInterrupt(strobe,latch,RISING);
attachInterrupt(clock,data,RISING);
}
void loop()
{
if (firstLoop) {
int status1 = 1;
bool ok = radio.write( &status1, sizeof(int));
firstLoop = false;
radio.startListening();
if (!ok) {
Serial.println("sync packet transmission failed");
}
else {
Serial.println("sync packet transmission successful");
}
}
if ( radio.available() )
{
unsigned long state = 0;
radio.read( &state, sizeof(unsigned long) );
Serial.println(state, BIN);
state2 = state;
}
else
{
Serial.println("No data recieved yet");
}
}
//Latch interrupt routine
void latch()
{
i = 0;
digitalWrite(data1,HIGH);
digitalWrite(data2,HIGH);
digitalWrite(data1,bitRead(state2,i));
digitalWrite(data2,bitRead(state2,(i+16)));
Serial.println("Bit0 out");
}
//Data interrupt routine
void data()
{
i++;
digitalWrite(data1,bitRead(state2,i));
digitalWrite(data2,bitRead(state2,(i+16)));
Serial.print("Bit");
Serial.print(i);
Serial.println(" out");
if(i=15)
{
digitalWrite(data1,LOW);
digitalWrite(data2,LOW);
radio.stopListening();
int status1 = status2;
bool ok = radio.write( &status1, sizeof(int));
if (!ok) {
Serial.println("sync packet transmission failed");
}
else {
Serial.println("sync packet transmission successful");
}
radio.startListening();
}
}

Resources