I have been getting this error and I am not exactly sure what is going wrong. I am using an Adafruit Feather M0 with RFM95 LoRa Radio. Any help is much appreciated.
c:/users/evans/appdata/local/arduino15/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/bin/ld.exe: cannot find -larm_cortexM0l_math
collect2.exe: error: ld returned 1 exit status
exit status 1
Compilation error: exit status 1
Here is the code:
#include <arm_math.h>
#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <Adafruit_ADS1X15.h>
#include <DHT.h>
#define DHTTYPE DHT11 // Temp sensor type
#define topTemp 11 // Pin for top box temp sensor
#define bottomTemp 12 // Pin for bottom box temp sensor
#define outTemp 13 // Pin for outside temp sensor
int voltage = A0; // Pin for voltage reader
int fanControl = A1; // Pin for box fans
Adafruit_ADS1X15 ads; // ADC sensor initialization
Adafruit_ADS1X15 shunt; // Shunt sensor initialization
const float FACTOR = 30; //20A/1V from teh CT
const float multiplier = 0.0005; // Multiplier for ADC conversion
/*
##########################################
# #
# Temperature Sensors Definitions #
# #
##########################################
*/
DHT sensors_1(topTemp, DHTTYPE); // Used for defining top box temp sensor
DHT sensors_2(bottomTemp, DHTTYPE); // Used for defining bottom box temp sensor
OneWire oneWire(outTemp); // Used for defining outside temp
DallasTemperature sensors_3(&oneWire); // Used for defining outside temp
// This EUI must be in little-endian format, so least-significant-byte
// first. When copying an EUI from ttnctl output, this means to reverse
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3,
// 0x70.
static const u1_t PROGMEM APPEUI[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);}
// This should also be in little endian format, see above.
static const u1_t PROGMEM DEVEUI[8] = {0x5D, 0x63, 0x04, 0xD0, 0x7E, 0xD5, 0xB3, 0x70};
void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);}
// This key should be in big endian format (or, since it is not really a
// number but a block of memory, endianness does not really apply). In
// practice, a key taken from the TTN console can be copied as-is.
static const u1_t PROGMEM APPKEY[16] = {0xE2, 0xD1, 0xBA, 0xFC, 0x9B, 0x82, 0xA5, 0x00, 0x10, 0xA6, 0xE8, 0xD0, 0x50, 0x95, 0x94, 0x86};
void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16);}
// payload to send to TTN gateway
static uint8_t payload[13];
static osjob_t sendjob;
// Schedule TX every this many seconds (might become longer due to duty
// cycle limitations).
const unsigned TX_INTERVAL = 180;
// Pin mapping for Adafruit Feather M0 LoRa
const lmic_pinmap lmic_pins = {
.nss = 8,
.rxtx = LMIC_UNUSED_PIN,
.rst = 4,
.dio = {3, 6, LMIC_UNUSED_PIN},
.rxtx_rx_active = 0,
.rssi_cal = 8, // LBT cal for the Adafruit Feather M0 LoRa, in dB
.spi_freq = 8000000,
};
void printHex2(unsigned v) {
v &= 0xff;
if (v < 16)
Serial.print('0');
Serial.print(v, HEX);
}
void onEvent (ev_t ev) {
Serial.print(os_getTime());
Serial.print(": ");
switch(ev) {
case EV_SCAN_TIMEOUT:
Serial.println(F("EV_SCAN_TIMEOUT"));
break;
case EV_BEACON_FOUND:
Serial.println(F("EV_BEACON_FOUND"));
break;
case EV_BEACON_MISSED:
Serial.println(F("EV_BEACON_MISSED"));
break;
case EV_BEACON_TRACKED:
Serial.println(F("EV_BEACON_TRACKED"));
break;
case EV_JOINING:
Serial.println(F("EV_JOINING"));
break;
case EV_JOINED:
Serial.println(F("EV_JOINED"));
{
u4_t netid = 0;
devaddr_t devaddr = 0;
u1_t nwkKey[16];
u1_t artKey[16];
LMIC_getSessionKeys(&netid, &devaddr, nwkKey, artKey);
Serial.print("netid: ");
Serial.println(netid, DEC);
Serial.print("devaddr: ");
Serial.println(devaddr, HEX);
Serial.print("AppSKey: ");
for (size_t i=0; i<sizeof(artKey); ++i) {
if (i != 0)
Serial.print("-");
printHex2(artKey[i]);
}
Serial.println("");
Serial.print("NwkSKey: ");
for (size_t i=0; i<sizeof(nwkKey); ++i) {
if (i != 0)
Serial.print("-");
printHex2(nwkKey[i]);
}
Serial.println();
}
// Disable link check validation (automatically enabled
// during join, but because slow data rates change max TX
// size, we don't use it in this example.
LMIC_setLinkCheckMode(0);
break;
case EV_JOIN_FAILED:
Serial.println(F("EV_JOIN_FAILED"));
break;
case EV_REJOIN_FAILED:
Serial.println(F("EV_REJOIN_FAILED"));
break;
break;
case EV_TXCOMPLETE:
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
if( ( LMIC.txrxFlags & ( TXRX_DNW1 | TXRX_DNW2 ) ) != 0 )
{
Serial.print( "Received downlink\r\n");
}
if (LMIC.txrxFlags & TXRX_ACK)
Serial.println(F("Received ack"));
if (LMIC.dataLen) {
Serial.println(F("Received "));
Serial.println(LMIC.dataLen);
Serial.println(F(" bytes of payload"));
}
// Schedule next transmission
os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
break;
case EV_LOST_TSYNC:
Serial.println(F("EV_LOST_TSYNC"));
break;
case EV_RESET:
Serial.println(F("EV_RESET"));
break;
case EV_RXCOMPLETE:
// data received in ping slot
Serial.println(F("EV_RXCOMPLETE"));
break;
case EV_LINK_DEAD:
Serial.println(F("EV_LINK_DEAD"));
break;
case EV_LINK_ALIVE:
Serial.println(F("EV_LINK_ALIVE"));
break;
case EV_TXSTART:
Serial.println(F("EV_TXSTART"));
break;
case EV_TXCANCELED:
Serial.println(F("EV_TXCANCELED"));
break;
case EV_RXSTART:
/* do not print anything -- it wrecks timing */
break;
case EV_JOIN_TXCOMPLETE:
Serial.println(F("EV_JOIN_TXCOMPLETE: no JoinAccept"));
break;
default:
Serial.print(F("Unknown event: "));
Serial.println((unsigned) ev);
break;
}
}
void printMeasure(String prefix, float value, String postfix)
{
Serial.print(prefix);
Serial.print(value, 3);
Serial.println(postfix);
}
void do_send(osjob_t* j){
// Check if there is not a current TX/RX job running
if (LMIC.opmode & OP_TXRXPEND) {
Serial.println(F("OP_TXRXPEND, not sending"));
} else {
Serial.println("Do send else");
/*
################################
# #
# Reading Voltage Sensor #
# #
################################
*/
float voltagevalue = analogRead(voltage)/46.602;
/*
######################################
# #
# Reading Temperature Sensors #
# #
######################################
*/
sensors_3.requestTemperatures(); // Request temp for outside
float out = sensors_3.getTempFByIndex(0); // Temp for outside
float top = sensors_1.readTemperature(true); // Temp for top box
float bot = sensors_2.readTemperature(true); // Temp for bottom box
/*
#################################
# #
# Reading Output Current #
# #
#################################
*/
float currentRMS = getcurrent();
float maxCurrent;
int16_t results;
results = ads.readADC_SingleEnded(2);
// Getting maximum current value
for (int i=0;i<=5;i++){
currentRMS = getcurrent();
if (maxCurrent <= currentRMS){
maxCurrent = currentRMS;
}
}
/*
###################################
# #
# Reading Charging Current #
# #
###################################
*/
float amps = ((float)results * 256.0) / 32768.0; //100mv shunt
amps = amps * 0.53;
/*
####################################
# #
# Printing Sensors In Serial #
# #
####################################
*/
Serial.print("Top Temp: "); Serial.print(top); // Display temp for top box
Serial.print("\n");
Serial.print("Bot Temp: "); Serial.print(bot); // Display temp for bottom box
Serial.print("\n");
Serial.print("Out temp: "); Serial.print(out); // Display temp for outside
Serial.print("\n");
Serial.print("Voltage: "); Serial.print(voltagevalue); // Display voltage from battery
Serial.print("\n");
printMeasure("Ouput Current: ", maxCurrent, "A"); // Display adc current
Serial.print("Charing Current: "); // Display shunt current
Serial.println(amps);
/*
######################
# #
# Fan Control #
# #
######################
*/
if (top > 85 || bot > 85){
digitalWrite(fanControl, HIGH);
Serial.print("FAN ON");
}
else {
digitalWrite(fanControl, LOW);
}
/*
############################################
############################################
## ##
## TTN Settings For Sending Payload ##
## ##
############################################
############################################
#################################################
# #
# Adjust for the f2sflt16 range (-1 to 1) #
# #
#################################################
*/
top = top / 100;
bot = bot / 100;
out = out / 100;
maxCurrent = maxCurrent / 100;
amps = amps / 100;
voltagevalue = voltagevalue / 100;
/*
######################
# #
# float -> int #
# #
######################
*/
// note: this uses the sflt16 datum (https://github.com/mcci-catena/arduino-lmic#sflt16)
uint16_t payloadTempTop = LMIC_f2sflt16(top);
uint16_t payloadTempBot = LMIC_f2sflt16(bot);
uint16_t payloadTempOut = LMIC_f2sflt16(out);
uint16_t payloadCurrent = LMIC_f2sflt16(maxCurrent);
uint16_t payloadAmps = LMIC_f2sflt16(amps);
uint16_t payloadVoltage = LMIC_f2sflt16(voltagevalue);
/*
######################
# #
# int -> bytes #
# #
######################
*/
byte lowTopBox = lowByte(payloadTempTop);
byte highTopBox = highByte(payloadTempTop);
byte lowBotBox = lowByte(payloadTempBot);
byte highBotBox = highByte(payloadTempBot);
byte lowOut = lowByte(payloadTempOut);
byte highOut = highByte(payloadTempOut);
byte lowVoltage = lowByte(payloadVoltage);
byte highVoltage = highByte(payloadVoltage);
byte lowCurrent = lowByte(payloadCurrent);
byte highCurrent highByte(payloadCurrent);
byte lowAmps = lowByte(payloadAmps);
byte highAmps = highByte(payloadAmps);
/*
##########################################
# #
# Place the bytes into the payload #
# #
##########################################
*/
payload[0] = lowTopBox;
payload[1] = highTopBox;
payload[2] = lowBotBox;
payload[3] = highBotBox;
payload[4] = lowOut;
payload[5] = highOut;
payload[6] = lowVoltage;
payload[7] = highVoltage;
payload[8] = lowCurrent;
payload[9] = highCurrent;
payload[10] = lowAmps;
payload[11] = highAmps;
/*
#############################################################################################################
# #
# Prepare upstream data transmission at the next possible time. #
# transmit on port 1 (the first parameter); you can use any value from 1 to 223 (others are reserved). #
# don't request an ack (the last parameter, if not zero, requests an ack from the network). #
# Remember, acks consume a lot of network resources; don't ask for an ack unless you really need it. #
# #
#############################################################################################################
*/
LMIC_setTxData2(1, payload, sizeof(payload) - 1, 0);
}
// Next TX is scheduled after TX_COMPLETE event.
}
void setup() {
delay(5000);
Serial.begin(9600);
Serial.println(F("Starting"));
pinMode(fanControl, OUTPUT);
pinMode(voltage, INPUT);
sensors_1.begin(); // Initialize top temp sensor
sensors_2.begin(); // Initialize bottom temp sensor
sensors_3.begin(); // Initialize outside temp sensor
ads.setGain(GAIN_FOUR); // +/- 1.024V 1bit = 0.5mV
shunt.setGain(GAIN_FOUR);
ads.begin();
shunt.begin();
// LMIC init
os_init();
// Reset the MAC state. Session and pending data transfers will be discarded.
LMIC_reset();
// Disable link-check mode and ADR, because ADR tends to complicate testing.
LMIC_setLinkCheckMode(0);
// Set the data rate to Spreading Factor 7. This is the fastest supported rate for 125 kHz channels, and it
// minimizes air time and battery power. Set the transmission power to 14 dBi (25 mW).
LMIC_setDrTxpow(DR_SF7,14);
// in the US, with TTN, it saves join time if we start on subband 1 (channels 8-15). This will
// get overridden after the join by parameters from the network. If working with other
// networks or in other regions, this will need to be changed.
LMIC_selectSubBand(1);
// Start job (sending automatically starts OTAA too)
do_send(&sendjob);
}
void loop() {
os_runloop_once();
}
float getcurrent()
{
float voltage;
float current;
float sum = 0;
long time_check = millis();
int counter = 0;
while (millis() - time_check < 1000)
{
voltage = ads.readADC_Differential_0_1() * multiplier;
current = voltage * FACTOR;
//current /= 1000.0;
sum += sq(current);
counter = counter + 1;
}
current = sqrt(sum / counter);
return (current);
}