I have modified the Adafruit Fona GPS example file to show the error between my location and GPS and GSM locations that it collects. The error part that I'm outputting is showing up correctly, but the AT codes are also displaying on the serial monitor and I can't figure out how to suppress them. Code is below and output is below that. I'm trying to get rid of everything that isn't the line starting with "GPS Error...".
/**
* ___ ___ _ _ _ ___ __ ___ ___ ___ ___
* | __/ _ \| \| | /_\ ( _ )/ \( _ ) / __| _ \/ __|
* | _| (_) | .` |/ _ \ / _ \ () / _ \ | (_ | _/\__ \
* |_| \___/|_|\_/_/ \_\ \___/\__/\___/ \___|_| |___/
*
* This example is meant to work with the Adafruit
* FONA 808 or 3G Shield or Breakout
*
* Copyright: 2015 Adafruit
* Author: Todd Treece
* Licence: MIT
*
*/
#include "Adafruit_FONA.h"
// standard pins for the shield, adjust as necessary
#define FONA_RX 2
#define FONA_TX 3
#define FONA_RST 4
const float CURR_LAT = 28.086084;
const float CURR_LON = -82.401916;
float GPS_LAT;
float GPS_LON;
float GSM_LAT;
float GSM_LON;
// We default to using software serial. If you want to use hardware serial
// (because softserial isnt supported) comment out the following three lines
// and uncomment the HardwareSerial line
#include <SoftwareSerial.h>
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;
// Hardware serial is also possible!
// HardwareSerial *fonaSerial = &Serial1;
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
// Have a FONA 3G? use this object type instead
//Adafruit_FONA_3G fona = Adafruit_FONA_3G(FONA_RST);
void setup() {
while (! Serial);
Serial.begin(115200);
// Serial.println(F("Adafruit FONA 808 & 3G GPS demo"));
// Serial.println(F("Initializing FONA... (May take a few seconds)"));
fonaSerial->begin(4800);
if (! fona.begin(*fonaSerial)) {
// Serial.println(F("Couldn't find FONA"));
while(1);
}
// Serial.println(F("FONA is OK"));
// Try to enable GPRS
// Serial.println(F("Enabling GPS..."));
fona.enableGPS(true);
}
void loop() {
delay(1000);
float latitude, longitude, speed_kph, heading, speed_mph, altitude;
// if you ask for an altitude reading, getGPS will return false if there isn't a 3D fix
boolean gps_success = fona.getGPS(&latitude, &longitude, &speed_kph, &heading, &altitude);
if (gps_success) {
// Serial.print("GPS lat:");
// Serial.println(latitude, 6);
// Serial.print("GPS long:");
// Serial.println(longitude, 6);
// Serial.print("GPS speed KPH:");
// Serial.println(speed_kph);
// Serial.print("GPS speed MPH:");
// speed_mph = speed_kph * 0.621371192;
// Serial.println(speed_mph);
// Serial.print("GPS heading:");
// Serial.println(heading);
// Serial.print("GPS altitude:");
// Serial.println(altitude);
GPS_LAT = latitude;
GPS_LON = longitude;
} else {
// Serial.println("Waiting for FONA GPS 3D fix...");
}
// Fona 3G doesnt have GPRSlocation :/
if ((fona.type() == FONA3G_A) || (fona.type() == FONA3G_E))
return;
// Check for network, then GPRS
// Serial.println(F("Checking for Cell network..."));
if (fona.getNetworkStatus() == 1) {
// network & GPRS? Great! Print out the GSM location to compare
boolean gsmloc_success = fona.getGSMLoc(&latitude, &longitude);
if (gsmloc_success) {
// Serial.print("GSMLoc lat:");
// Serial.println(latitude, 6);
// Serial.print("GSMLoc long:");
// Serial.println(longitude, 6);
GSM_LAT = latitude;
GSM_LON = longitude;
} else {
// Serial.println("GSM location failed...");
// Serial.println(F("Disabling GPRS"));
fona.enableGPRS(false);
// Serial.println(F("Enabling GPRS"));
if (!fona.enableGPRS(true)) {
// Serial.println(F("Failed to turn GPRS on"));
}
}
}
//const float CURR_LAT = 28.086084;
//const float CURR_LON = -82.401916;
//float GPS_LAT;
//float GPS_LON;
//float GSM_LAT;
//float GSM_LON;
float GPS_DIFF = sqrt((GPS_LAT - CURR_LAT)*(GPS_LAT - CURR_LAT) + (GPS_LON - CURR_LON)*(GPS_LON - CURR_LON));
float GSM_DIFF = sqrt((GSM_LAT - CURR_LAT)*(GSM_LAT - CURR_LAT) + (GSM_LON - CURR_LON)*(GSM_LON - CURR_LON));
Serial.print("GPS Error: ");
Serial.print(GPS_DIFF,6);
Serial.print(" GSM Error: ");
Serial.println(GSM_DIFF,6);
}
And the output is:
GPS Error: 87.056900 GSM Error: 87.056900
---> AT+CGNSINF
<--- +CGNSINF: 1,0,20170529194222.000,,,,0.20,78.0,0,,,,,,12,3,,,25,,
---> AT+CREG?
<--- +CREG: 0,1
---> AT+CIPGSMLOC=1,1
<--- +CIPGSMLOC: 601
---> AT+CIPSHUT
<--- SHUT OK
---> AT+SAPBR=0,1
<--- ERROR
---> AT+CIPSHUT
<--- SHUT OK
---> AT+CGATT=1
<--- OK
---> AT+SAPBR=3,1,"CONTYPE","GPRS"
<--- OK
---> AT+SAPBR=3,1,"APN","FONAnet"
<--- OK
---> AT+CSTT="FONAnet"
<--- OK
---> AT+SAPBR=1,1
<--- OK
---> AT+CIICR
<--- OK
GPS Error: 87.056900 GSM Error: 87.056900
You are using Adafruit's library/functions like fona.getGPS and is coded to return information.
It can be edited at the libraries "Adafruit_Fona" folder.
Related
Why code stucked in the ISR routine in msp430fg6626 microcontroller? here i performing the rs485 communiction with this uc and SN75176A max485 ic.during this i was set the buad rate at 9600 here data was successfully sent from uc and same received at the max485 ic but in receiving time data was not received at uc from max485 ic. why this occured i will share the code of same here please check and answer me.
i will share the samw code below
code was stuck in this line -> __bis_SR_register(LPM3_bits + GIE);
#include <msp430.h>
int ReceiveData;
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // Stop WDT
CTSD16CCTL0 |= CTSD16SC; // Workaround for CTSD16OFFG errata
do
{
CTSD16CTL &= ~CTSD16OFFG;
}
while (CTSD16CTL&CTSD16OFFG); // End of CTSD16OFFG workaround
while(BAKCTL & LOCKBAK) // Unlock XT1 pins for operation
BAKCTL &= ~(LOCKBAK);
UCSCTL6 &= ~(XT1OFF); // XT1 On
UCSCTL6 |= XCAP_3; // Internal load cap
// Loop until XT1 fault flag is cleared
do
{
UCSCTL7 &= ~(XT2OFFG | XT1LFOFFG | DCOFFG);
// Clear XT2,XT1,DCO fault flags
SFRIFG1 &= ~OFIFG; // Clear fault flags
}while (SFRIFG1&OFIFG); // Test oscillator fault flag
//------------ Configuring MAX485 Control Lines ---------------//
P8SEL |= BIT4; // Assign P8.4 to ~RE DE and...
P8DIR |= BIT4; // P8.4 -> DE,-> ~RE output
P8OUT &= ~(BIT4); // ~RE & DE SET TO ZERO IN RECEIVING MODE
P8SEL |= 0x0C; // Assign P8.2 to UCA0TXD and...
P8DIR |= 0x0C; // P8.3 to UCA0RXD
UCA1CTL1 |= UCSWRST; // **Put state machine in reset**
UCA1CTL1 |= UCSSEL_1; // CLK = ACLK
UCA1BR0 = 0x03; // 32kHz/9600=3.41 (see User's Guide)
UCA1BR1 = 0x00; //
UCA1MCTL = UCBRS_3|UCBRF_0; // Modulation UCBRSx=3, UCBRFx=0
UCA1CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
UCA1IE |= UCRXIE; // Enable USCI_A1 RX interrupt
__bis_SR_register(LPM3_bits + GIE); // Enter LPM3, interrupts enabled***
__no_operation(); // For debugger
while(1)
{
while (!(UCA1IFG&UCTXIFG)); // USCI_A1 TX buffer ready?
// UCA1TXBUF = 0x55; // TX -> RXed character
// __delay_cycles (160000);
}
}
// Echo back RXed character, confirm TX buffer is ready first
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A1_VECTOR
__interrupt void USCI_A1_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_A1_VECTOR))) USCI_A1_ISR (void)
#else
#error Compiler not supported!
#endif
{
switch(__even_in_range(UCA1IV,4))
{
case 0:break; // Vector 0 - no interrupt
case 2: // Vector 2 - RXIFG
while (!(UCA1IFG&UCTXIFG)); // USCI_A1 TX buffer ready?
ReceiveData=UCA1RXBUF;
P8OUT |= BIT4; // ~RE & DE SET TO HIGH FOR TRANSMITTING MODE
__delay_cycles (16000);
UCA1TXBUF = ReceiveData; // TX -> RXed character
__delay_cycles (16000);
P8OUT |= ~(BIT4); // ~RE & DE SET TO ZERO IN RECEIVING MODE
__delay_cycles (16000);
break;
case 4:break; // Vector 4 - TXIFG
default: break;
}
}
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;
}
}
I have a code that I downloaded from a webpage that is supposed to let me control a MAX7219 LED Matrix from a Web Interface using an ESP8266 (I'm using a NodeMcu v3.0 with an ESP8266-12E), but every time I try to compile the code, the following error comes out:
MAX7219_ESP8266:45: error: invalid conversion from 'uint8_t {aka unsigned char}' to 'MD_MAX72XX::moduleType_t' [-fpermissive]
MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES);
^
In file included from
E:\Searches\Desktop\MAX7219_ESP8266\MAX7219_ESP8266.ino:14:0:
E:\Documents\Arduino\libraries\MD_MAX72XX\src/MD_MAX72xx.h:362:3:
error: initializing argument 1 of
'MD_MAX72XX::MD_MAX72XX(MD_MAX72XX::moduleType_t, uint8_t, uint8_t)'
[-fpermissive]
MD_MAX72XX(moduleType_t mod, uint8_t csPin, uint8_t numDevices=1);
^
exit status 1 invalid conversion from 'uint8_t {aka unsigned char}' to
'MD_MAX72XX::moduleType_t' [-fpermissive]
What could I do in order to fix it? I tried using a different library and even modifying the library, but the same error came out.
The code is the following:
// IP address for the ESP8266 is displayed on the scrolling display
// after startup initialisation and connected to the WiFi network.
//
// Connections for ESP8266 hardware SPI are:
// Vcc 3v3 LED matrices seem to work at 3.3V
// GND GND GND
// DIN D7 HSPID or HMOSI
// CS or LD D8 HSPICS or HCS
// CLK D5 CLK or HCLK
//
#include <ESP8266WiFi.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#define PRINT_CALLBACK 0
#define DEBUG 0
#define LED_HEARTBEAT 0
#if DEBUG
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
#define PRINTS(s) { Serial.print(F(s)); }
#else
#define PRINT(s, v)
#define PRINTS(s)
#endif
#if LED_HEARTBEAT
#define HB_LED D2
#define HB_LED_TIME 500 // in milliseconds
#endif
// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define MAX_DEVICES 4
#define CLK_PIN D5 // or SCK
#define DATA_PIN D7 // or MOSI
#define CS_PIN D8 // or SS
// SPI hardware interface
MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES);
// Arbitrary pins
//MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
// WiFi login parameters - network name and password
const char* ssid = "your SSID"; // edit your wifi SSID here
const char* password = "your Password"; // edit your wifi password here
// WiFi Server object and parameters
WiFiServer server(80);
// Global message buffers shared by Wifi and Scrolling functions
const uint8_t MESG_SIZE = 255;
const uint8_t CHAR_SPACING = 1;
const uint8_t SCROLL_DELAY = 75;
char curMessage[MESG_SIZE];
char newMessage[MESG_SIZE];
bool newMessageAvailable = false;
char WebResponse[] = "HTTP/1.1 200 OK\nContent-Type: text/html\n\n";
char WebPage[] =
"<!DOCTYPE html>" \
"<html>" \
"<head>" \
"<title>eTechPath MAX7219 ESP8266</title>" \
"<style>" \
"html, body" \
"{" \
"width: 600px;" \
"height: 400px;" \
"margin: 0px;" \
"border: 0px;" \
"padding: 10px;" \
"background-color: white;" \
"}" \
"#container " \
"{" \
"width: 100%;" \
"height: 100%;" \
"margin-left: 200px;" \
"border: solid 2px;" \
"padding: 10px;" \
"background-color: #b3cbf2;" \
"}" \
"</style>"\
"<script>" \
"strLine = \"\";" \
"function SendText()" \
"{" \
" nocache = \"/&nocache=\" + Math.random() * 1000000;" \
" var request = new XMLHttpRequest();" \
" strLine = \"&MSG=\" + document.getElementById(\"txt_form\").Message.value;" \
" request.open(\"GET\", strLine + nocache, false);" \
" request.send(null);" \
"}" \
"</script>" \
"</head>" \
"<body>" \
"<div id=\"container\">"\
"<H1><b>WiFi MAX7219 LED Matrix Display</b></H1>" \
"<form id=\"txt_form\" name=\"frmText\">" \
"<label>Msg:<input type=\"text\" name=\"Message\" maxlength=\"255\"></label><br><br>" \
"</form>" \
"<br>" \
"<input type=\"submit\" value=\"Send Text\" onclick=\"SendText()\">" \
"<p><b>Visit Us at</b></p>" \
"www.eTechPath.com" \
"</div>" \
"</body>" \
"</html>";
char *err2Str(wl_status_t code)
{
switch (code)
{
case WL_IDLE_STATUS: return("IDLE"); break; // WiFi is in process of changing between statuses
case WL_NO_SSID_AVAIL: return("NO_SSID_AVAIL"); break; // case configured SSID cannot be reached
case WL_CONNECTED: return("CONNECTED"); break; // successful connection is established
case WL_CONNECT_FAILED: return("CONNECT_FAILED"); break; // password is incorrect
case WL_DISCONNECTED: return("CONNECT_FAILED"); break; // module is not configured in station mode
default: return("??");
}
}
uint8_t htoi(char c)
{
c = toupper(c);
if ((c >= '0') && (c <= '9')) return(c - '0');
if ((c >= 'A') && (c <= 'F')) return(c - 'A' + 0xa);
return(0);
}
boolean getText(char *szMesg, char *psz, uint8_t len)
{
boolean isValid = false; // text received flag
char *pStart, *pEnd; // pointer to start and end of text
// get pointer to the beginning of the text
pStart = strstr(szMesg, "/&MSG=");
if (pStart != NULL)
{
pStart += 6; // skip to start of data
pEnd = strstr(pStart, "/&");
if (pEnd != NULL)
{
while (pStart != pEnd)
{
if ((*pStart == '%') && isdigit(*(pStart+1)))
{
// replace %xx hex code with the ASCII character
char c = 0;
pStart++;
c += (htoi(*pStart++) << 4);
c += htoi(*pStart++);
*psz++ = c;
}
else
*psz++ = *pStart++;
}
*psz = '\0'; // terminate the string
isValid = true;
}
}
return(isValid);
}
void handleWiFi(void)
{
static enum { S_IDLE, S_WAIT_CONN, S_READ, S_EXTRACT, S_RESPONSE, S_DISCONN } state = S_IDLE;
static char szBuf[1024];
static uint16_t idxBuf = 0;
static WiFiClient client;
static uint32_t timeStart;
switch (state)
{
case S_IDLE: // initialise
PRINTS("\nS_IDLE");
idxBuf = 0;
state = S_WAIT_CONN;
break;
case S_WAIT_CONN: // waiting for connection
{
client = server.available();
if (!client) break;
if (!client.connected()) break;
#if DEBUG
char szTxt[20];
sprintf(szTxt, "%03d:%03d:%03d:%03d", client.remoteIP()[0], client.remoteIP()[1], client.remoteIP()[2], client.remoteIP()[3]);
PRINT("\nNew client # ", szTxt);
#endif
timeStart = millis();
state = S_READ;
}
break;
case S_READ: // get the first line of data
PRINTS("\nS_READ");
while (client.available())
{
char c = client.read();
if ((c == '\r') || (c == '\n'))
{
szBuf[idxBuf] = '\0';
client.flush();
PRINT("\nRecv: ", szBuf);
state = S_EXTRACT;
}
else
szBuf[idxBuf++] = (char)c;
}
if (millis() - timeStart > 1000)
{
PRINTS("\nWait timeout");
state = S_DISCONN;
}
break;
case S_EXTRACT: // extract data
PRINTS("\nS_EXTRACT");
// Extract the string from the message if there is one
newMessageAvailable = getText(szBuf, newMessage, MESG_SIZE);
PRINT("\nNew Msg: ", newMessage);
state = S_RESPONSE;
break;
case S_RESPONSE: // send the response to the client
PRINTS("\nS_RESPONSE");
// Return the response to the client (web page)
client.print(WebResponse);
client.print(WebPage);
state = S_DISCONN;
break;
case S_DISCONN: // disconnect client
PRINTS("\nS_DISCONN");
client.flush();
client.stop();
state = S_IDLE;
break;
default: state = S_IDLE;
}
}
void scrollDataSink(uint8_t dev, MD_MAX72XX::transformType_t t, uint8_t col)
// Callback function for data that is being scrolled off the display
{
#if PRINT_CALLBACK
Serial.print("\n cb ");
Serial.print(dev);
Serial.print(' ');
Serial.print(t);
Serial.print(' ');
Serial.println(col);
#endif
}
uint8_t scrollDataSource(uint8_t dev, MD_MAX72XX::transformType_t t)
// Callback function for data that is required for scrolling into the display
{
static enum { S_IDLE, S_NEXT_CHAR, S_SHOW_CHAR, S_SHOW_SPACE } state = S_IDLE;
static char *p;
static uint16_t curLen, showLen;
static uint8_t cBuf[8];
uint8_t colData = 0;
// finite state machine to control what we do on the callback
switch (state)
{
case S_IDLE: // reset the message pointer and check for new message to load
PRINTS("\nS_IDLE");
p = curMessage; // reset the pointer to start of message
if (newMessageAvailable) // there is a new message waiting
{
strcpy(curMessage, newMessage); // copy it in
newMessageAvailable = false;
}
state = S_NEXT_CHAR;
break;
case S_NEXT_CHAR: // Load the next character from the font table
PRINTS("\nS_NEXT_CHAR");
if (*p == '\0')
state = S_IDLE;
else
{
showLen = mx.getChar(*p++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf);
curLen = 0;
state = S_SHOW_CHAR;
}
break;
case S_SHOW_CHAR: // display the next part of the character
PRINTS("\nS_SHOW_CHAR");
colData = cBuf[curLen++];
if (curLen < showLen)
break;
// set up the inter character spacing
showLen = (*p != '\0' ? CHAR_SPACING : (MAX_DEVICES*COL_SIZE)/2);
curLen = 0;
state = S_SHOW_SPACE;
// fall through
case S_SHOW_SPACE: // display inter-character spacing (blank column)
PRINT("\nS_ICSPACE: ", curLen);
PRINT("/", showLen);
curLen++;
if (curLen == showLen)
state = S_NEXT_CHAR;
break;
default:
state = S_IDLE;
}
return(colData);
}
void scrollText(void)
{
static uint32_t prevTime = 0;
// Is it time to scroll the text?
if (millis() - prevTime >= SCROLL_DELAY)
{
mx.transform(MD_MAX72XX::TSL); // scroll along - the callback will load all the data
prevTime = millis(); // starting point for next time
}
}
void setup()
{
#if DEBUG
Serial.begin(115200);
PRINTS("\n[MD_MAX72XX WiFi Message Display]\nType a message for the scrolling display from your internet browser");
#endif
#if LED_HEARTBEAT
pinMode(HB_LED, OUTPUT);
digitalWrite(HB_LED, LOW);
#endif
// Display initialisation
mx.begin();
mx.setShiftDataInCallback(scrollDataSource);
mx.setShiftDataOutCallback(scrollDataSink);
curMessage[0] = newMessage[0] = '\0';
// Connect to and initialise WiFi network
PRINT("\nConnecting to ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
PRINT("\n", err2Str(WiFi.status()));
delay(500);
}
PRINTS("\nWiFi connected");
// Start the server
server.begin();
PRINTS("\nServer started");
// Set up first message as the IP address
sprintf(curMessage, "%03d:%03d:%03d:%03d", WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3]);
PRINT("\nAssigned IP ", curMessage);
}
void loop()
{
#if LED_HEARTBEAT
static uint32_t timeLast = 0;
if (millis() - timeLast >= HB_LED_TIME)
{
digitalWrite(HB_LED, digitalRead(HB_LED) == LOW ? HIGH : LOW);
timeLast = millis();
}
#endif
handleWiFi();
scrollText();
}
The error indicates that you're calling the MD_MAX72XX constructor with the wrong arguments.
This is your current call to it:
MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES);
The error indicates that the correct arguments are:
MD_MAX72XX(moduleType_t mod, uint8_t csPin, uint8_t numDevices=1);
The last argument has a default value. Looking at your call to the constructor, you're not passing it the moduleType_t mod argument. The compiler is taking CS_PIN to be that argument, using MAX_DEVICES for the csPin argument, and the default value of 1 for the numDevices argument. It throws the error you're seeing because CS_PIN is an integer and it's expecting a moduleType_t.
You can fix this by providing the correct first argument.
The header file for the library has a list of the possible values for the mod argument:
enum moduleType_t
{
PAROLA_HW, ///< Use the Parola style hardware modules.
GENERIC_HW, ///< Use 'generic' style hardware modules commonly available.
ICSTATION_HW, ///< Use ICStation style hardware module.
FC16_HW ///< Use FC-16 style hardware module.
};
Add the correct moduleType_t for your MAX7219 hardware as the first argument and you should see this error go away.
Believe this is because of the new updates in the library, Like #John Romkey suggested the function should be called with correct number of arguments, add this line of code in your Arduino Sketch and Select the correct hardware from the list PAROLA_H, GENERIC_HW, ICSTATION_HW, FC16_HW.
#######define HARDWARE_TYPE MD_MAX72XX::GENERIC_HW
MD_Parola P = MD_Parola(HARDWARE_TYPE,CS_PIN, MAX_DEVICES);
The library got a update and your code needs some changes to compile succesfully. Here are your options
Option-1. Modify your code to adopt updated library as suggested by John
Option-2. Use old library version. You can select library version in Arduino IDE (Sketch --> Include Library --> Manage Libraries)
I'm trying to write my own basic libraries to program the Arduino in pure C++. I've tried using a variadic function to implement something similar to Linux's ioctl() to control the SPI module but it just won't work and I have no idea why. I don't pin 13 (Arduino SCK) light up as expected during SPI transactions indicating that SPI is not operating. All the other functions in my library work properly.
The following is my SPI library:
/*
spi.h: SPI driver for Atmega328p
*/
#ifndef _SPI_H
#define _SPI_H
#include <avr/io.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdarg.h>
#include <inttypes.h>
// SPI bus pin mapping ///////////////////////////////////
#define PORT_SPI PORTB // Port register containing SPI pins
#define DDR_SPI DDRB // Data direction register containing SPI pins
#define DDR_SCK DDB5 // Data direction bit of SPI SCK pin
#define DDR_MISO DDB4 // Data direction bit of SPI MISO pin
#define DDR_MOSI DDB3 // Data direction bit of SPI MOSI pin
#define DDR_HWCS DDB2 // Data direction bit of SPI hardware chip select pin
#define PIN_SCK PB5 // Port register bit of SPI SCK pin
#define PIN_MISO PB4 // Port register bit of SPI MISO pin
#define PIN_MOSI PB3 // Port register bit of SPI MOSI pin
#define PIN_HWCS PB2 // Port register bit of SPI hardware chip select pin
// SPI ioctl commands ////////////////////////////////////
#define SPIIOCCONF 0 // Configure SPI command
#define SPIIOCDECONF 1 // Deconfigure SPI command
#define SPIIOCTRANSMIT 2 // SPI byte exchange command
// Clock frequency settings //////////////////////////////
#define SCK_DIV2 2 // Divide source pulse by 2
#define SCK_DIV4 4 // Divide source pulse by 4
#define SCK_DIV8 8 // Divide source pulse by 8
#define SCK_DIV16 16 // Divide source pulse by 16
#define SCK_DIV32 32 // Divide source pulse by 32
#define SCK_DIV64 64 // Divide source pulse by 64
#define SCK_DIV128 128 // Divide source pulse by 128
// SPI modes /////////////////////////////////////////////
#define SPI_MODE0 0
#define SPI_MODE1 1
#define SPI_MODE2 2
#define SPI_MODE3 3
// SPI transaction data orders ///////////////////////////
#define LSBFIRST 0
#define MSBFIRST 1
// The SPI module ////////////////////////////////////////
class spiModule {
private:
bool configured; // Indicates whether SPI is operating with a valid configuration
uint8_t ddrOld, portOld; // Value of DDR_SPI and PORT_SPI just before an SPI configuration was called for
// ( These variables are used to restore the state of the
// SPI pins when SPI is deconfigured )
/* ioctls used to operate the SPI module */
void spiiocconf(int, int, int); // Configure SPI with a valid clock frequency, data order and SPI mode
void spiiocdeconf(void); // Deconfigure SPI and restore SPI pins to their original states
void spiioctransmit(uint8_t, uint8_t *); // Exchange a byte of data over SPI
/* ioctl handlers */
/* These routines check the validity of the arguments and call the ioctls (above) only if all arguments make sense */
/* I've tested these functions by making them public and found that they work perfectly */
int conf(int, int, int); // call spiiocconf() if arguments are valid and SPI is configured
int deconf(void); // call spiiocdeconf() if all arguments are valid and SPI is configured
int transmit(uint8_t, uint8_t *); // call spiioctransmit() if all arguments are valid and SPI is configured
public:
spiModule(void); // Initialize this class
int ioctl(int action, ... ); // Core ioctl handler (supposed to work like the Linux ioctl() system call). But this one just won't work.
};
spiModule spi; // Object of class spiModule for using SPI
// Constructor ///////////////////////////////////////////
spiModule::spiModule(void) {
configured = false;
}
// Private routines //////////////////////////////////////
/* Ioctls */
void spiModule::spiiocconf(int clkDiv, int dataOrder, int mode) {
// Store the values of DDR_SPI and PORT_SPI so they may be recovered when SPI is deconfigured
ddrOld = DDR_SPI;
portOld = PORT_SPI;
// Configure SCK, MOSI and HWCS as output pins and MISO as an input pin
DDR_SPI |= (_BV(DDR_HWCS) | _BV(DDR_SCK) | _BV(DDR_MOSI));
DDR_SPI &= ~_BV(DDR_MISO);
// Power up the SPI module
PRR &= ~_BV(PRSPI);
// Enable SPI and configure it as master
SPCR = 0x00;
SPCR |= (_BV(SPE) | _BV(MSTR));
// Set data order
switch(dataOrder)
{
case LSBFIRST:
SPCR |= _BV(DORD);
break;
case MSBFIRST:
SPCR &= ~_BV(DORD);
break;
}
// Set SPI mode
switch(mode)
{
case SPI_MODE0:
SPCR &= ~(_BV(CPOL) | _BV(CPHA));
break;
case SPI_MODE1:
SPCR |= _BV(CPHA);
SPCR &= ~_BV(CPOL);
break;
case SPI_MODE2:
SPCR &= ~_BV(CPHA);
SPCR |= _BV(CPOL);
break;
case SPI_MODE3:
SPCR |= (_BV(CPOL) | _BV(CPHA));
break;
}
// Set SPI clock frequency
switch(clkDiv)
{
case SCK_DIV2:
SPCR &= ~(_BV(SPR0) | _BV(SPR1));
SPSR |= _BV(SPI2X);
break;
case SCK_DIV4:
SPCR &= ~(_BV(SPR0) | _BV(SPR1));
SPSR &= ~_BV(SPI2X);
break;
case SCK_DIV8:
SPCR |= _BV(SPR0);
SPCR &= ~_BV(SPR1);
SPSR |= _BV(SPI2X);
break;
case SCK_DIV16:
SPCR |= _BV(SPR0);
SPCR &= ~_BV(SPR1);
SPSR &= ~_BV(SPI2X);
break;
case SCK_DIV32:
SPCR &= ~_BV(SPR0);
SPCR |= _BV(SPR1);
SPSR |= _BV(SPI2X);
break;
case SCK_DIV64:
SPCR |= _BV(SPR0);
SPCR |= _BV(SPR1);
SPSR |= _BV(SPI2X);
break;
case SCK_DIV128:
SPCR |= _BV(SPR0);
SPCR |= _BV(SPR1);
SPSR &= ~_BV(SPI2X);
break;
}
// SPI is now configured
configured = true;
return;
}
void spiModule::spiiocdeconf(void) {
// Clear SPI configuration, power down the SPI module and restore the values of DDR_SPI and PORT_SPI
SPCR = 0x00;
PRR |= _BV(PRSPI);
DDR_SPI = ddrOld;
PORT_SPI = portOld;
// SPI is no longer configured
configured = false;
return;
}
void spiModule::spiioctransmit(uint8_t txbyte, uint8_t * rxbyte) {
// Write TX byte to data register
SPDR = txbyte;
while(!(SPSR & _BV(SPIF)))
{
/* wait for data transmission to complete */
}
SPSR &= ~_BV(SPIF);
// Return RX byte by storing it at the specified location
if(rxbyte != NULL)
{
*rxbyte = SPDR;
}
return;
}
/* Ioctl handlers (verify that all arguments are appropriate and only then proceed with the ioctl) */
int spiModule::conf(int clkDiv, int dataOrder, int mode) {
// Return with error of SPI is not configured
if(!configured)
{
return -1;
}
// Verify validity of clkDiv (clock pulse division factor)
switch(clkDiv)
{
case SCK_DIV2:
break;
case SCK_DIV4:
break;
case SCK_DIV8:
break;
case SCK_DIV16:
break;
case SCK_DIV32:
break;
case SCK_DIV64:
break;
case SCK_DIV128:
break;
default:
return -1;
}
// Verify validity of dataOrder (order of byte transfer)
switch(dataOrder)
{
case LSBFIRST:
break;
case MSBFIRST:
break;
default:
return -1;
}
// Check validity of mode (SPI mode)
switch(mode)
{
case SPI_MODE0:
break;
case SPI_MODE1:
break;
case SPI_MODE2:
break;
case SPI_MODE3:
break;
default:
return -1;
}
// If all goes well, execute the ioctl
spiiocconf(clkDiv, dataOrder, mode);
return 0;
}
int spiModule::deconf(void) {
// If SPI is configured, deconfigure it
if(!configured)
{
return -1;
}
spiiocdeconf();
return 0;
}
int spiModule::transmit(uint8_t tx, uint8_t * rx) {
// If SPI is configured, make a byte exchange
if(!configured)
{
return -1;
}
spiioctransmit(tx, rx);
return 0;
}
// Public routines ///////////////////////////////////////
int spiModule::ioctl(int action, ... ) {
// This routine checks the value of action and executes the respective ioctl
// It returns with error if the value of action is not valid
va_list ap;
int clkDiv, dataOrder, mode;
uint8_t txbyte;
uint8_t * rxbyte;
int retVal;
switch(action)
{
case SPIIOCCONF:
va_start(ap, action);
clkDiv = va_arg(ap, int);
dataOrder = va_arg(ap, int);
mode = va_arg(ap, int);
va_end(ap);
retVal = conf(clkDiv, dataOrder, mode);
return retVal;
case SPIIOCDECONF:
retVal = deconf();
return retVal;
case SPIIOCTRANSMIT:
va_start(ap, action);
txbyte = va_arg(ap, uint8_t);
rxbyte = va_arg(ap, uint8_t*);
va_end(ap);
retVal = transmit(txbyte, rxbyte);
return retVal;
default:
return -1;
}
}
#endif
I'm compiling and uploading my code to the Arduino using the following commands (spiTest.cpp is a code that I used to test this library)
COMPILER=~/Softwares/arduino-1.6.8/hardware/tools/avr/bin/avr-g++
HEXGENERATOR=~/Softwares/arduino-1.6.8/hardware/tools/avr/bin/avr-objcopy
UPLOADER=~/Softwares/arduino-1.6.8/hardware/tools/avr/bin/avrdude
AVRDUDE_CFG=~/Softwares/arduino-1.6.8/hardware/tools/avr/etc/avrdude.conf
$COMPILER -c -g -w -D F_CPU=16000000UL -mmcu=atmega328p -std=gnu++11 -o spiTest.o spiTest.cpp
$COMPILER -mmcu=atmega328p spiTest.o -o spiTest
$HEXGENERATOR -O ihex -R .eeprom spiTest spiTest.hex
$UPLOADER -C $AVRDUDE_CFG -v -p atmega328p -c arduino -P /dev/ttyACM0 -b 115200 -D -U flash:w:spiTest.hex:i
I've used variadic functions to implement ioctl() before and it worked when I used the Arduino IDE to compile and upload my program. I don't understand what's preventing variadic functions from working properly in this code.
You are in the C++, you can do it in better. For example something like:
class SPIIOCONF_t {} SPIIOCONF;
class SPIIOCDECONF_t {} SPIIOCDECONF;
class SPIIOCTRANSMIT_t {} SPIIOCTRANSMIT;
int ioctl(SPIIOCONF_t, int clkDiv, int dataOrder, int mode) {
return conf(clkDiv, dataOrder, mode);
}
int ioctl(SPIIOCDECONF_t) {
return deconf();
}
int ioctl(SPIIOCTRANSMIT_t, uint8_t txbyte, uint8_t rxbyte) {
return transmit(txbyte, rxbyte);
}
void setup() {
Serial.begin(115200);
Serial.println(ioctl(SPIIOCONF, 10, 1, 1));
Serial.println(ioctl(SPIIOCDECONF));
uint8_t rx;
Serial.println(ioctl(SPIIOCTRANSMIT, 0xFF, &rx));
}
or similarly without defining dummy class instance, but you have to create one in the call:
class SPIIOCONF {};
class SPIIOCDECONF {};
class SPIIOCTRANSMIT {};
int ioctl(SPIIOCONF, int clkDiv, int dataOrder, int mode) {
return conf(clkDiv, dataOrder, mode);
}
int ioctl(SPIIOCDECONF) {
return deconf();
}
int ioctl(SPIIOCTRANSMIT, uint8_t txbyte, uint8_t rxbyte) {
return transmit(txbyte, rxbyte);
}
void setup() {
ioctl(SPIIOCONF{}, 10, 1, 1);
uint8_t rx;
Serial.println(ioctl(SPIIOCTRANSMIT{}, 0xFF, &rx));
ioctl(SPIIOCDECONF{});
}
I read followed links and other sources, but didn't find answer for my question.
Binary data over serial terminal
Data gets corrupted during transmission over the serial port
I communicate with my embedded device through a serial port. By default, embedded Linux uses this port as a terminal. But I want to transfer also binary data (service packets) through the port. My /etc/inittab file has a "getty" call:
console::respawn:/sbin/getty 115200 ttyS0
I also have /etc/passwd file with string where "admin" user launch my "cli" application after log in:
admin:8Mt/Jtxcyg8AY:1000:0:admin:/tmp:/tmp/cli
My default ttyS0 settings before running the program is:
~ # stty -a
speed 115200 baud;stty: standard input
line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = ^J;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon ixoff
-iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon -iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
-echoctl echoke
~ #
So, in my cli program I do the following:
main ()
{
...
system("stty erase ^H);
system("stty -F /dev/ttyS0 -icrnl -ixon -ixoff -opost -isig -icanon -echo"); // enter in non-canonical (raw) mode
// What function do I need to use here to retrieve binary data (also symbols that > 0x7F) from /dev/ttyS0?
system("stty -F /dev/ttyS0 icrnl ixon ixoff opost isig icanon echo"); // go back to canonical mode
...
exit(0);
}
I have attempted read() function (with unsigned char buffer) to get binary data, but failed to receive correct data. I also preliminarily open /dev/ttyS0 again to get file_descriptor & use read() func.
My program sends 3 bytes: 0xAA, 0x02, 0xFE.
But in syslog I always see that device receives incorrect symbols: 0x98, 0xE6, 0x18.
What is the matter? How to get correct binary data?
A whole code that I am testing at the moment.
#include "cli.h"
#include "glb_vars.h"
/******************************************
*** Definitions
******************************************/
#define APPLICATION_NAME "cli"
#define SERIALPORT_IS_CONSOLE
/******************************************
*** Constants
******************************************/
const char dev_name[] = DEV_NAME;
const char lineminstr[] = "\t--------------------------------------------------------\n";
/******************************************
*** Internal Function Declarations
******************************************/
CLI_RETVAL cliInit(void);
CLI_RETVAL cliClose(void);
void cliWorkLoop(Term_callback_t **term);
/******************************************
*** External Function Declarations
******************************************/
extern void Vectors_init(Term_callback_t **vec);
extern char** Menu_completion(const char * text, int start, int end);
/****************************************************************************/
int file_descr, max_fd;
struct termios tty, orig_tty;
fd_set work_set;
/****************************************************************************/
/*!
* \brief Init cli
*
* \return success or failure
* \retval CLI_SUCCESS, CLI_FAILURE
*
* \ingroup CLI
*/
/****************************************************************************/
CLI_RETVAL cliInit(void)
{
long spd;
signal(SIGINT, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGTERM, SIG_IGN);
signal(SIGABRT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGILL, SIG_IGN);
// system("stty -F /dev/ttyS0 -icrnl -ixon -ixoff -opost -isig -icanon -echo"); // enter in non-canonical mode
// system("stty -a");
// sleep(1);
#ifdef SERIALPORT_IS_CONSOLE
file_descr = STDIN_FILENO;
SYS_LOG_DEBUG("SERIALPORT IS CONSOLE");
#else
SYS_LOG_DEBUG("SERIALPORT IS NOT CONSOLE");
file_descr = open("/dev/ttyS0", O_RDWR | O_ASYNC | O_NDELAY);
if (file_descr == -1) {
// Could not open the port
perror("unable to open /dev/ttyS0");
exit(1);
}
#endif
if(tcgetattr(file_descr, &tty) < 0)
{
perror("unable to get tty attributes");
exit(1);
}
// backup tty, make it raw and apply changes
orig_tty = tty;
spd = B115200;
cfsetospeed(&tty, (speed_t)spd);
cfsetispeed(&tty, (speed_t)spd);
cfmakeraw(&tty);
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 10;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS; /* no HW flow control? */
tty.c_cflag |= CLOCAL | CREAD;
tcsetattr(file_descr, TCSANOW, &tty);
// // update local mode flags
// tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
//// // renew control mode flags
//// tty.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | PARENB | PARODD);
//// tty.c_cflag |= (BAUD | DATABITS | STOPBITS | PARITYON | PARITY);
// // select 'raw' output mode
// tty.c_oflag &= ~OPOST;
// // disable mapping for input mode
// tty.c_iflag &= ~(INLCR | ICRNL);
//
//
// if(tcsetattr(file_descr, TCSAFLUSH, &tty) < 0)
// {
// perror("unable to set tty attributes");
// exit(1);
// }
//
// Setup fd_set
FD_ZERO(&work_set);
FD_SET(file_descr, &work_set);
max_fd = file_descr + 1;
/* Readline lib init */
// Define application name for readline library
rl_readline_name = APPLICATION_NAME;
// Update Pointer to alternative function to create matches.
rl_attempted_completion_function = Menu_completion;
// Start readline with reading /etc/inputrc file
using_history();
stifle_history(CLI_MAX_HISTORY_SIZE);
// Some other initialization code
// ...
// ...
return CLI_SUCCESS;
}
/****************************************************************************/
/*!
* \brief Close cli
*
* \return success or failure
* \retval CLI_SUCCESS, CLI_FAILURE
*
* \ingroup CLI
*/
/****************************************************************************/
CLI_RETVAL cliClose(void)
{
// system("stty -F /dev/ttyS0 icrnl ixon ixoff opost isig icanon echo"); // enter in canonical mode
tcsetattr(file_descr, TCSANOW, &orig_tty);
// if(tcsetattr(file_descr, TCSAFLUSH, &orig_tty) < 0)
// {
// perror("unable to set orig_tty attributes");
// exit(1);
// }
close(file_descr);
return CLI_SUCCESS;
}
/****************************************************************************/
/*!
* \brief Main cli processing loop
*
* \no return
*
* \ingroup CLI
*/
/****************************************************************************/
void cliWorkLoop(Term_callback_t **term)
{
Term_callback_t *cur_term;
int8 *commandString;
uint8 ret = CLI_REFRESH, no_prompt;
char prompt_str[20];
while (1) {
cur_term = *term;
global_cmd_compl_pointer = cur_term->cmd_list;
commandString = NULL;
sprintf(prompt_str, "%s:~> ", dev_name);
if(ret == CLI_REFRESH) {
CLEAR_SCR();
if(cur_term->out != NULL) {
cur_term->out(term, commandString, &ret);
no_prompt = ret;
}
CURSOR_DOWN();
}
int n;
struct timeval timeout;
uint8 tmpBuf[32];
while (1)
{
// Setup Timeout
timeout.tv_sec = 60;
timeout.tv_usec = 0;
// Wait for new connections
n = select(max_fd, &work_set, NULL, NULL, &timeout);
if (n < 0)
{
perror("select #2 failed");
break;
}
if (n > 0)
{
/* У нас есть ввод */
if (FD_ISSET(file_descr, &work_set))
{
if (read(file_descr, tmpBuf, 10) < 0) {
perror("cannot read");
exit(1);
}
else
{
SYS_LOG_DEBUG("READ first 4 chars: 0x%X,0x%X,0x%X,0x%X", tmpBuf[0], tmpBuf[1], tmpBuf[2], tmpBuf[3]);
}
}
break;
}
}
//
//
// n = read(file_descr, tmpBuf, 5);
// if (n > 0) {
// unsigned char *p = tmpBuf;
//
// while (n-- > 0)
// printf(" 0x%x", *p++);
// printf("\r\n");
// } else {
// printf("failed to read: %d\r\n", n);
// }
//
//
exit(0);
}
CLEAR_SCR();
return;
}
/****************************************************************************/
/*!
* \brief Main cli function
*
* \param[in] argc - argument number.
* \param[in,out] argv - argument values entered by user.
*
* \return success or failure
* \retval EXIT_SUCCESS, EXIT_FAILURE
*
*
* \ingroup CLI
*/
/****************************************************************************/
int main(int argc, char *argv[])
{
Term_callback_t *term;
char logname[16];
FILE *fp;
/* Set mask for file operation */
umask(0);
system("stty erase ^H");
openlog("cli", LOG_CONS, LOG_USER);
/* Write cli start log */
syslog(LOG_NOTICE, "Console startup. Software version: %s", VERSION);
/* Find login name */
strcpy(logname, "noname");
if ((fp = popen( "whoami", "r" )) == NULL)
{
SYS_LOG_ERR("Can't open process for \"whoami\" command.");
} else
{
fgets(logname, 16, fp);
pclose(fp);
}
SYS_LOG_INFO("Console is entered by \"%s\".", logname); //getenv("USER")
/* Console initialization */
if (cliInit() != CLI_SUCCESS) {
SYS_LOG_CRIT("CLI init failed");
return EXIT_FAILURE;
}
Vectors_init(&term);
/* Console work loop */
cliWorkLoop(&term);
cliClose();
/* Exiting from cli */
SYS_LOG_INFO("\"%s\" exited from console.", logname);
return EXIT_SUCCESS;
}
system("stty erase ^H);
system("stty -F /dev/ttyS0 -icrnl -ixon -ixoff -opost -isig -icanon -echo"); // enter into non-canonical (raw) mode
This would be insufficient code (and poor coding practice per POSIX conventions) to put the serial port into raw or non-canonical mode.
The easiest method in C and Linux is to use the function cfmakeraw() which is available in both the GNU libc and uClibc libraries. Use the man page to obtain the details on the termios structure members that are modified by cfmakeraw().
Beware that cfmakeraw() will setup the serial port in raw mode for a data length of 8 bits and no parity, for a total character frame of 10 bits (assuming one stop bit).
The preferred method is preserving a copy of the termios stucture (for restoration on program exit) and only modifying the required flag bits (rather than writing the complete structure members).
REVISION
Code that works on my ARM SoC is:
#include <stdio.h>
#include <stdlib.h>
#include <sys/un.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/syslog.h>
#include <termios.h>
#define SERIALPORT_IS_CONSOLE
main()
{
struct termios tty;
struct termios savetty;
speed_t spd;
unsigned int sfd;
unsigned char buf[80];
int reqlen = 79;
int rc;
int rdlen;
int pau = 0;
#ifdef SERIALPORT_IS_CONSOLE
sfd = STDIN_FILENO;
#else
sfd = open("/dev/ttyS1", O_RDWR | O_NOCTTY);
#endif
if (sfd < 0) {
syslog(LOG_DEBUG, "failed to open: %d, %s", sfd, strerror(errno));
exit (-1);
}
syslog(LOG_DEBUG, "opened sfd=%d for reading", sfd);
rc = tcgetattr(sfd, &tty);
if (rc < 0) {
syslog(LOG_DEBUG, "failed to get attr: %d, %s", rc, strerror(errno));
exit (-2);
}
savetty = tty; /* preserve original settings for restoration */
spd = B115200;
cfsetospeed(&tty, (speed_t)spd);
cfsetispeed(&tty, (speed_t)spd);
cfmakeraw(&tty);
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 10;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS; /* no HW flow control? */
tty.c_cflag |= CLOCAL | CREAD;
rc = tcsetattr(sfd, TCSANOW, &tty);
if (rc < 0) {
syslog(LOG_DEBUG, "failed to set attr: %d, %s", rc, strerror(errno));
exit (-3);
}
do {
unsigned char *p = buf;
rdlen = read(sfd, buf, reqlen);
if (rdlen > 0) {
if (*p == '\r')
pau = 1;
syslog(LOG_DEBUG, "read: %d, 0x%x 0x%x 0x%x", \
rdlen, *p, *(p + 1), *(p + 2));
} else {
syslog(LOG_DEBUG, "failed to read: %d, %s", rdlen, strerror(errno));
}
} while (!pau);
tcsetattr(sfd, TCSANOW, &savetty);
close(sfd);
exit (0);
}
The compiled program is loaded & executed on the target board.
From the host side of the serial comm link, the file seq.bin with the following contents is sent:
$ od -t x1 seq.bin
0000000 aa 02 fe
0000003
Then "ABC" is typed on the host (which is running the minicom terminal emulator program), followed by a carriage return.
The program terminates on the target, and the syslog is then examined:
# tail /var/log/messages
Sep xx xx:xx:42 atmel_soc user.info kernel: EXT3 FS on nvsram, internal journal
Sep xx xx:xx:42 atmel_soc user.info kernel: EXT3-fs: mounted filesystem with or.
Sep xx xx:xx:42 atmel_soc user.info kernel: kjournald starting. Commit intervas
Sep xx xx:xx:18 atmel_soc auth.info login[431]: root login on 'ttyS0'
Sep xx xx:xx:04 atmel_soc user.debug syslog: opened sfd=0 for reading
Sep xx xx:xx:14 atmel_soc user.debug syslog: read: 3, 0xaa 0x2 0xfe
Sep xx xx:xx:50 atmel_soc user.debug syslog: read: 1, 0x41 0x2 0xfe
Sep xx xx:xx:51 atmel_soc user.debug syslog: read: 1, 0x42 0x2 0xfe
Sep xx xx:xx:51 atmel_soc user.debug syslog: read: 1, 0x43 0x2 0xfe
Sep xx xx:xx:52 atmel_soc user.debug syslog: read: 1, 0xd 0x2 0xfe
#
The binary data has been received intact.
Note that since this is raw mode and the typed chars were entered relatively slowly, the read() returns "partial" data and the user program would be responsible for buffering/assembling the data into complete "messages". If the messages are of fixed length, then c_cc[VMIN]member could be set to the message length. But beware of message framing issues and complications when frame sync is lost!