Im trying to write a library but coming up to a strange error with the webIDE. its probably something I’m doing wrong but its causing a very strange bug
The code fails with the error below, which i cant work out… there is the normal IPAddress warnings, but the strange ones are the previous declaration of void setup() and void loop().
If i add a comment at the top it goes away… or if i delete the first line (blank line) it goes away. only seems to happen when the include application bit is on line 2 or lower, but if there is a comment in the first line its ok. I’ve tried other apps and they dont have the same thing with what line the include is on.
In file included from ../inc/spark_wiring.h:30:0,
from ../inc/application.h:29,
from SPI_Motor.h:35,
from SPI_Motor.cpp:35:
../../core-common-lib/SPARK_Firmware_Driver/inc/config.h:12:2: warning: #warning "Defaulting to Release Build" [-Wcpp]
#warning "Defaulting to Release Build"
^
In file included from ../inc/spark_wiring.h:37:0,
from ../inc/application.h:29,
from SPI_Motor.h:35,
from SPI_Motor.cpp:35:
../inc/spark_wiring_ipaddress.h: In member function 'IPAddress::operator uint32_t()':
../inc/spark_wiring_ipaddress.h:53:52: warning: dereferencing
type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
operator uint32_t() { return *((uint32_t*)_address); };
^
../inc/spark_wiring_ipaddress.h: In member function 'bool IPAddress::operator==(const IPAddress&)':
../inc/spark_wiring_ipaddress.h:54:72: warning: dereferencing
type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); };
^
../inc/spark_wiring_ipaddress.h:54:105: warning: dereferencing
type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); };
^
In file included from ../inc/spark_wiring.h:30:0,
from ../inc/application.h:29,
from dualdcmotor.cpp:2:
../../core-common-lib/SPARK_Firmware_Driver/inc/config.h:12:2: warning: #warning "Defaulting to Release Build" [-Wcpp]
#warning "Defaulting to Release Build"
^
dualdcmotor.cpp:4:6: error: previous declaration of 'void setup()' with 'C++' linkage
void setup();
^
In file included from ../inc/spark_wiring.h:34:0,
from ../inc/application.h:29,
from dualdcmotor.cpp:2:
../inc/spark_utilities.h:141:35: error: conflicts with new declaration with 'C' linkage
void setup() __attribute__ ((weak));
^
dualdcmotor.cpp:5:6: error: previous declaration of 'void loop()' with 'C++' linkage
void loop();
^
In file included from ../inc/spark_wiring.h:34:0,
from ../inc/application.h:29,
from dualdcmotor.cpp:2:
../inc/spark_utilities.h:142:34: error: conflicts with new declaration with 'C' linkage
void loop() __attribute__ ((weak));
^
In file included from ../inc/spark_wiring.h:37:0,
from ../inc/application.h:29,
from dualdcmotor.cpp:2:
../inc/spark_wiring_ipaddress.h: In member function 'IPAddress::operator uint32_t()':
../inc/spark_wiring_ipaddress.h:53:52: warning: dereferencing
type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
operator uint32_t() { return *((uint32_t*)_address); };
^
../inc/spark_wiring_ipaddress.h: In member function 'bool IPAddress::operator==(const IPAddress&)':
../inc/spark_wiring_ipaddress.h:54:72: warning: dereferencing
type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); };
^
../inc/spark_wiring_ipaddress.h:54:105: warning: dereferencing
type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); };
^
make: *** [dualdcmotor.o] Error 1
Error: Could not compile. Please review your code.
Here are the files
dualDCmotor.ino
#include "application.h"
#include "SPI_Motor.h"
SPI_Motor pumpCard(D7, 1, 2);
SPI_Motor stirCard(D7, 2, 2);
void setup() {
Serial.begin(115200);
while (!Serial.available()) SPARK_WLAN_Loop();
if (pumpCard.begin()){
Serial.println("Pump card Initialised!");
}
if (stirCard.begin()){
Serial.println("Stir card Initialised!");
}
pumpCard.resume();
pumpCard.A(STOP, 0);
pumpCard.B(STOP, 0);
stirCard.A(STOP, 0);
stirCard.B(STOP, 0);
}
void loop() {
Serial.println("Starting Motors in 5sec");
delay(5000);
Serial.println("Starting Motors now 80% power");
pumpCard.A(CW,200);
pumpCard.B(CCW,200);
stirCard.A(CW,200);
stirCard.B(CCW,200);
delay(10000);
Serial.println("Motor A Brake, Motor B Freewheel");
pumpCard.A(BRAKE);
pumpCard.B(STOP);
stirCard.A(BRAKE,200); //doesn't matter if we send PWM too, makes no difference
stirCard.B(STOP,200); //doesn't matter if we send PWM too, makes no difference
delay(10000);
Serial.println("Reversing Motor directions now");
pumpCard.A(CCW,200);
pumpCard.B(CW,200);
stirCard.A(CCW,200);
stirCard.B(CW,200);
delay(10000);
Serial.println("Stopping all motors");
pumpCard.A(STOP, 0); //sets pwm to minimum ready for next operation
pumpCard.B(STOP, 0);
stirCard.A(STOP, 0);
stirCard.B(STOP, 0);
delay(1000);
Serial.println("Ramping up all motors now");
pumpCard.A(CW); //setting just the direction, PWM will be same last time it was set
pumpCard.B(CW);
stirCard.A(CW);
stirCard.B(CW);
int i;
for(i=0; i<255; i++){
pumpCard.A(i);
pumpCard.B(i);
stirCard.A(i);
stirCard.B(i);
delay(115); //ramp from 0 to 255 should take about 30sec (maybe as a guess!!)
}
Serial.println("Ramping Down all motors now");
for(i=255; i>0; i--){
pumpCard.A(i);
pumpCard.B(i);
stirCard.A(i);
stirCard.B(i);
delay(115); //ramp from 0 to 255 should take about 30sec (maybe as a guess!!)
}
Serial.println("Putting both cards to low power mode now");
pumpCard.standby();
stirCard.standby();
Serial.println("Check power consumption now.. quick you have 10seconds!");
delay(10000);
Serial.println("Putting both cards to Normal/Run mode now");
pumpCard.resume();
stirCard.resume();
}
SPI_Motor.cpp
/******************************************************************************
This is a library for Hootie81's Dual DC Motor Shield for Spark Core
The Dual DC Motor Shield uses a Maxim MAX6966 SPI PWM I/O expander
to drive a Toshiba TB6612FNG Dual DC motor Driver. The MAX6966 has a SPI
Interface and allows shields to be stacked in a daisy chain configuration
minimizing the required I/O. The MAX6966 also has a built in 32kHz PWM
controller saving the Spark more precious I/O.
The TB6612FNG is a dual H-Bridge motor controller allowing forward and reverse
directions and PWM speed control. There is short circuit brake function and
free wheel functions also. The TB6612FNG will drive 2 DC motors at
up to 1.2A continuous and 3.2A peak.
The Card can be configured with solder jumpers, there are 4 options for CS on
the underside of the card - A0, A1, D0, D1
on the top side you can choose if the card it the first card and or the last
card. This sets up the MISO And MOSI lines to pass from card to card.
For single card choose Y for both First and Last.
For multiple cards,
on the bottom most card - choose Y for First, and N for Last
middle cards will be N for both First and Last
on the top most card choose N for First and Y for last.
Card Number will be 1 for the bottom most card, the upper limit it yet to
be determined, but will probably be limited by RAM on the core or Lag in motor
control from the need to clock data through multiple cards.
Written by Chris Huitema. 30/7/14
*****************************************************************************/
#include "SPI_Motor.h"
SPI_Motor::SPI_Motor(uint8_t pinCS) {
_CS = pinCS;
_card = 1;
_total = 1;
};
SPI_Motor::SPI_Motor(uint8_t pinCS, uint8_t cardNumber, uint8_t cardTotal) {
_CS = pinCS;
_card = cardNumber;
_total = cardTotal;
}
boolean SPI_Motor::begin(void) {
pinMode(_CS, OUTPUT);
digitalWrite(_CS, HIGH);
SPI.setBitOrder(MSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV4);
SPI.setDataMode(SPI_MODE1);
SPI.begin();
if (checkTotalCards(_total))return true;
return false;
}
// remember STOP, CW, CCW, BRAKE are the options for direction_t Type
boolean SPI_Motor::A(direction_t Direction, uint8_t PWM) {
if (A(Direction) && A(PWM)) return true;
return false;
}
boolean SPI_Motor::A(direction_t Direction) { //control option, assumes previous PWM
uint8_t _AIN1, _AIN2;
if (Direction == STOP) {
//set AIN1 low, AIN2
_AIN1 = 0x00;
_AIN2 = 0x00;
} else if (Direction == BRAKE) {
//set AIN1 High, AIN2
_AIN1 = 0x01;
_AIN2 = 0x01;
} else if (Direction == CW) {
//set AIN1 High, AIN2 Low
_AIN1 = 0x01;
_AIN2 = 0x00;
} else if (Direction == CCW) {
//set AIN1 Low, AIN2 High
_AIN1 = 0x00;
_AIN2 = 0x01;
}
if ((sendToCard(_CMD_AIN1, _AIN1)) && (sendToCard(_CMD_AIN2, _AIN2))) return true;
return false;
};
boolean SPI_Motor::A(uint8_t PWM) {
uint8_t _PWMA = map(PWM, 0, 255, 3, 254); //map it so its actually PWM output (MAX6966 needs 3-254 to output PWM)
if (sendToCard(_CMD_PWMA, _PWMA)) return true;
return false;
};
boolean SPI_Motor::B(direction_t Direction, uint8_t PWM) {
if (B(Direction) && B(PWM)) return true;
return false;
}
boolean SPI_Motor::B(direction_t Direction) { //control option, assumes previous PWM
uint8_t _BIN1, _BIN2;
if (Direction == STOP) {
//set BIN1 low, BIN2
_BIN1 = 0x00;
_BIN2 = 0x00;
} else if (Direction == BRAKE) {
//set BIN1 High, BIN2
_BIN1 = 0x01;
_BIN2 = 0x01;
} else if (Direction == CW) {
//set BIN1 High, BIN2 Low
_BIN1 = 0x01;
_BIN2 = 0x00;
} else if (Direction == CCW) {
//set BIN1 Low, BIN2 High
_BIN1 = 0x00;
_BIN2 = 0x01;
}
if ((sendToCard(_CMD_BIN1, _BIN1)) && (sendToCard(_CMD_BIN2, _BIN2))) return true;
return false;
};
boolean SPI_Motor::B(uint8_t PWM) {
uint8_t _PWMB = map(PWM, 0, 255, 3, 254); //map it so its actually PWM output (MAX6966 needs 3-254 to output PWM)
if (sendToCard(_CMD_PWMB, _PWMB)) return true;
return false;
};
boolean SPI_Motor::standby(void) {// puts both back to low power operation.
uint8_t _STBY = 0x00;
if ((sendToCard(_CMD_STBY, _STBY)) && (sendToCard(_CMD_CONFIG, _STBY))) return true;
return false;
};
boolean SPI_Motor::resume(void) {// puts both back to normal operation.
uint8_t _STBY = 0x01;
if ((sendToCard(_CMD_STBY, _STBY)) && (sendToCard(_CMD_CONFIG, _STBY))) return true;
return false;
};
boolean SPI_Motor::checkTotalCards(uint8_t total) {
// If we don't take CS high during this, the data will be pumped all the way back to us and wont effect the motors at all
int j;
uint8_t CMD = 0x55; // unique dummy number
uint8_t DATA = 0xF0; // unique dummy number
uint8_t _NOOP = 0x00;
PIN_MAP[_CS].gpio_peripheral->BRR = PIN_MAP[_CS].gpio_pin; //set CS low
Serial.println("CS set Low");
SPI.transfer(CMD); //send control byte
Serial.print(" CMD: ");
Serial.print(CMD);
SPI.transfer(DATA); //send data byte
Serial.print(" DATA: ");
Serial.print(DATA);
for (j = 1; j < 10; j++) { //send no-op + blank data to clear data past last card (not required for single card)
_checkCMD = SPI.transfer(_CMD_NOOP);
Serial.print(" CMD: ");
Serial.print(_CMD_NOOP);
_checkDATA = SPI.transfer(_NOOP);
Serial.print(" DATA: ");
Serial.print(_NOOP);
Serial.print(" CheckCMD: "); //check the return CMD is correct last one should be the CMD sent
Serial.print(_checkCMD);
Serial.print(" CheckDATA: "); //check the return Data is correct last one should be the Data sent
Serial.print(_checkDATA);
if ((_checkCMD == CMD) && (_checkDATA == DATA)){
Serial.println(" return match found ");
PIN_MAP[_CS].gpio_peripheral->BSRR = PIN_MAP[_CS].gpio_pin; //set CS high
Serial.println("CS set High");
Serial.print("Expecting: ");
Serial.print(total);
Serial.print(" Counted: ");
Serial.print(j);
if (total == j) {
Serial.println("Count matched expected... sweet!!");
return true;
}
else return false;
}
}
PIN_MAP[_CS].gpio_peripheral->BSRR = PIN_MAP[_CS].gpio_pin; //set CS high
Serial.println("CS set High");
Serial.println("Could not calculate total number of cards.. bummer!!");
return false;
}
boolean SPI_Motor::sendToCard(uint8_t CMD, uint8_t DATA) {
int j;
uint8_t _NOOP = 0x00;
PIN_MAP[_CS].gpio_peripheral->BRR = PIN_MAP[_CS].gpio_pin; //set CS low
Serial.println("CS set Low");
SPI.transfer(CMD); //send control byte
Serial.print(" CMD: ");
Serial.print(CMD);
SPI.transfer(DATA); //send data byte
Serial.print(" DATA: ");
Serial.print(DATA);
for (j = 1; j < _card; j++) { //send no-op + blank data to put in correct card (not required for single card)
SPI.transfer(_CMD_NOOP);
Serial.print(" CMD: ");
Serial.print(_CMD_NOOP);
SPI.transfer(_NOOP);
Serial.print(" DATA: ");
Serial.print(_NOOP);
}
PIN_MAP[_CS].gpio_peripheral->BSRR = PIN_MAP[_CS].gpio_pin; //set CS High so the data gets latched in the card
Serial.println();
Serial.println("CS set high");
PIN_MAP[_CS].gpio_peripheral->BRR = PIN_MAP[_CS].gpio_pin; //set CS low, now we clear out the data so it doesn't
// effect other cards.
Serial.println("CS set Low");
for (j = _card; j < _total; j++) { //send no-op + blank data to clear data past last card (not required for single card)
_checkCMD = SPI.transfer(_CMD_NOOP);
Serial.print(" CMD: ");
Serial.print(_CMD_NOOP);
_checkDATA = SPI.transfer(_NOOP);
Serial.print(" DATA: ");
Serial.print(_NOOP);
Serial.print(" CheckCMD: "); //check the return CMD is correct last one should be the CMD sent
Serial.print(_checkCMD);
Serial.print(" CheckDATA: "); //check the return Data is correct last one should be the Data sent
Serial.print(_checkDATA);
}
PIN_MAP[_CS].gpio_peripheral->BSRR = PIN_MAP[_CS].gpio_pin; //set CS high
Serial.println("CS set High");
return true;
}
SPI_Motor.h
/*******************************************************************************
This is a library for Hootie81's Dual DC Motor Shield for Spark Core
The Dual DC Motor Shield uses a Maxim MAX6966 SPI PWM I/O expander
to drive a Toshiba TB6612FNG Dual DC motor Driver. The MAX6966 has a SPI
Interface and allows shields to be stacked in a daisy chain configuration
minimizing the required I/O. The MAX6966 also has a built in 32kHz PWM
controller saving the Spark more precious I/O.
The TB6612FNG is a dual H-Bridge motor controller allowing forward and reverse
directions and PWM speed control. There is short circuit brake function and
free wheel functions also. The TB6612FNG will drive 2 DC motors at
up to 1.2A continuous and 3.2A peak.
The Card can be configured with solder jumpers, there are 4 options for CS on
the underside of the card - A0, A1, D0, D1
on the top side you can choose if the card it the first card and or the last
card. This sets up the MISO And MOSI lines to pass from card to card.
For single card choose Y for both First and Last.
For multiple cards,
on the bottom most card - choose Y for First, and N for Last
middle cards will be N for both First and Last
on the top most card choose N for First and Y for last.
Card Number will be 1 for the bottom most card, the upper limit it yet to
be determined, but will probably be limited by RAM on the core or Lag in motor
control from the need to clock data through multiple cards.
Written by Chris Huitema. 30/7/14
******************************************************************************/
#include "application.h"
enum direction_t {
STOP, CW, CCW, BRAKE
}; //these are the control options
class SPI_Motor {
public:
/***************************************************************************
Constructors:
Takes CS line for the card
Sets the card number and total cards if more than one card
used in daisy-chain mode.
**************************************************************************/
SPI_Motor(uint8_t); // sets CS and assumes single card
SPI_Motor(uint8_t, uint8_t, uint8_t); // CS, Card number, total cards
/***************************************************************************
Begin:
Sets up the CS Port as output and sets high
Sets up the SPI
Checks the total number of cards is correct, returns false if not
**************************************************************************/
boolean begin(void);
/***************************************************************************
Motor functions:
3 different options
Control word and PWM
Control word only
PWM only (faster speed changes as only PWM register changed)
Control words are:
STOP this sets the motor in free wheel mode
BRAKE this short circuits the motor pins causing a braking effect
CW makes the motor turn in a CW direction
CCW makes the motor turn in a CCW direction
All functions will return true is SPI return data looks correct
**************************************************************************/
boolean A(direction_t, uint8_t);
boolean A(direction_t);
boolean A(uint8_t);
boolean B(direction_t, uint8_t);
boolean B(direction_t);
boolean B(uint8_t);
/***************************************************************************
Power save options:
standby() sets the motor controller to low power mode.
resume() puts back to normal operation.
All functions will return true is SPI return data looks correct
**************************************************************************/
boolean standby(void); // puts the motor controller and IO chip to low power
boolean resume(void); // puts both back to normal operation.
private:
enum CMD {
//These are the control registers for the ports on the Max6966
_CMD_AIN1 = 0x01, //p1
_CMD_AIN2 = 0x00, //p0
_CMD_PWMA = 0x09, //p9
_CMD_BIN1 = 0x03, //p3
_CMD_BIN2 = 0x04, //p4
_CMD_PWMB = 0x05, //p5
_CMD_STBY = 0x02, //p2 low puts TB6612FNG in Standby
_CMD_CONFIG = 0x10, // control register for MAX6966 config
_CMD_NOOP = 0x20 //no-op control register used to pump the Data thru
};
// setup variables
uint8_t _CS; //chip select
uint8_t _card; //this instances card number
uint8_t _total; //total cards
uint8_t _checkCMD; //used for return data checks
uint8_t _checkDATA; //used for return data checks
//function to send the SPI data and check return from card
boolean sendToCard(uint8_t, uint8_t);
//function to test how many cards there are.
boolean checkTotalCards(uint8_t);
};