HTCC-AB01, ADS1115 and LORAWAN (Chirpstack)

Hi, i am trying to debug an issue i have with the HTCC-AB01 and the ADS1115 ADC - and sending the data via lorawan. The code works fine until it reaches a count of 169 then it stops working - i used both my own code and the standard wasn code with the same result. If i use the code with fixed data (no ADS) it works fine and if i used the code with ADS no lorawan it works fine as well. I tried to debug but it seems to hand after count of 169 at the ads.begin() command under static void prepareTxFrame( uint8_t port )

#include “LoRaWan_APP.h”
#include “Arduino.h”
#include “Wire.h”
#include “Adafruit_ADS1X15.h”


  • set LoraWan_RGB to Active,the RGB active in loraWan
  • RGB red means sending;
  • RGB purple means joined done;
  • RGB blue means RxWindow1;
  • RGB yellow means RxWindow2;
  • RGB green means received done;

/* OTAA para*/
uint8_t devEui[] = { 0x18, 0xd8, 0x24, 0x3c, 0x81, 0xac, 0xa8, 0xaf };
uint8_t appEui[] = { 0x70, 0xb3, 0xd5, 0x7e, 0xd0, 0x02, 0xa0, 0xe1 };
uint8_t appKey[] = { 0x69, 0x91, 0xdb, 0x20, 0x4d, 0x05, 0xff, 0xbc, 0xff, 0x7e, 0x6d, 0x19, 0x62, 0x3c, 0x14, 0x22 };

/* ABP para*/
uint8_t nwkSKey[] = { 0x15, 0xb1, 0xd0, 0xef, 0xa4, 0x63, 0xdf, 0xbe, 0x3d, 0x11, 0x18, 0x1e, 0x1e, 0xc7, 0xda,0x85 };
uint8_t appSKey[] = { 0xd7, 0x2c, 0x78, 0x75, 0x8c, 0xdc, 0xca, 0xbf, 0x55, 0xee, 0x4a, 0x77, 0x8d, 0x16, 0xef,0x67 };
uint32_t devAddr = ( uint32_t )0x007e6ae1;

/LoraWan channelsmask, default channels 8-15 + 65/
//uint16_t userChannelsMask[6]= { 0xFF00, 0x0000, 0x0000, 0x0000, 0x0002, 0x0000};
uint16_t userChannelsMask[6]={ 0xFF00,0x0000,0x0000,0x0000,0x0002,0x0000 };

/LoraWan region, select in arduino IDE tools/
LoRaMacRegion_t loraWanRegion = ACTIVE_REGION;

/LoraWan Class, Class A and Class C are supported/
DeviceClass_t loraWanClass = LORAWAN_CLASS;

/the application data transmission duty cycle. value in [ms]./
uint32_t appTxDutyCycle = 15000;

bool overTheAirActivation = LORAWAN_NETMODE;

/ADR enable/
bool loraWanAdr = LORAWAN_ADR;

/* set LORAWAN_Net_Reserve ON, the node could save the network info to flash, when node reset not need to join again */

/* Indicates if the node is sending confirmed or unconfirmed messages */
bool isTxConfirmed = LORAWAN_UPLINKMODE;

/* Application port /
uint8_t appPort = 2;

  • Number of trials to transmit the frame, if the LoRaMAC layer did not
  • receive an acknowledgment. The MAC performs a datarate adaptation,
  • according to the LoRaWAN Specification V1.0.2, chapter 18.4, according
  • to the following table:
  • Transmission nb | Data Rate
  • ----------------|-----------
  • 1 (first) | DR
  • 2 | DR
  • 3 | max(DR-1,0)
  • 4 | max(DR-1,0)
  • 5 | max(DR-2,0)
  • 6 | max(DR-2,0)
  • 7 | max(DR-3,0)
  • 8 | max(DR-3,0)
  • Note, that if NbTrials is set to 1 or 2, the MAC will not decrease
  • the datarate, in case the LoRaMAC layer did not receive an acknowledgment
    uint8_t confirmedNbTrials = 4;

uint16_t baseline;
int count = 0;
int maxtry = 50;

Adafruit_ADS1115 ads; /* Use this for the 16-bit version */

\brief Prepares the payload of the frame

static void prepareTxFrame( uint8_t port )
/*appData size is LORAWAN_APP_DATA_MAX_SIZE which is defined in “commissioning.h”.
*appDataSize max value is LORAWAN_APP_DATA_MAX_SIZE.
*if enabled AT, don’t modify LORAWAN_APP_DATA_MAX_SIZE, it may cause system hanging or failure.
*if disabled AT, LORAWAN_APP_DATA_MAX_SIZE can be modified, the max value is reference to lorawan region and SF.
*for example, if use REGION_CN470,
*the max value for different DR can be found in MaxPayloadOfDatarateCN470 refer to DataratesCN470 and BandwidthsCN470 in “RegionCN470.h”.
pinMode(Vext, OUTPUT);
digitalWrite(Vext, LOW);
Serial.println(“before ads.begin”);
Serial.println(“after ads.begin”);

/*appData size is LORAWAN_APP_DATA_MAX_SIZE which is defined in “commissioning.h”.
*appDataSize max value is LORAWAN_APP_DATA_MAX_SIZE.
*if disabled AT, LORAWAN_APP_DATA_MAX_SIZE can be modified, the max value is reference to lorawan region and SF.
*for example, if use REGION_CN470,
*the max value for different DR can be found in MaxPayloadOfDatarateCN470 refer to DataratesCN470 and BandwidthsCN470 in “RegionCN470.h”.
appDataSize = 0;

int16_t adc0, adc1, adc2, adc3;

/* Be sure to update this value based on the IC and the gain settings! /
//float multiplier = 3.0F; /
ADS1015 @ +/- 6.144V gain (12-bit results) /
float multiplier = 0.1875F; /
ADS1115 @ +/- 6.144V gain (16-bit results) */

adc0 = ads.readADC_SingleEnded(0);
adc1 = ads.readADC_SingleEnded(1);
adc2 = ads.readADC_SingleEnded(2);
adc3 = ads.readADC_SingleEnded(3);

int modnr = 0;
appData[appDataSize++] = modnr;
appData[appDataSize++] = 9;
appData[appDataSize++] = ((int)adc0) >> 8;
appData[appDataSize++] = (int)adc0;
appData[appDataSize++] = ((int)adc1) >> 8;
appData[appDataSize++] = (int)adc1;
appData[appDataSize++] = ((int)adc2) >> 8;
appData[appDataSize++] = (int)adc2;
appData[appDataSize++] = ((int)adc3) >> 8;
appData[appDataSize++] = (int)adc3;

Serial.print(" ADC0: “); Serial.print(adc0);
Serial.print(” ADC1: “); Serial.print(adc1);
Serial.print(” ADC3: “); Serial.print(adc2);
Serial.print(” ADC3: “); Serial.println(adc3);
Serial.print(” AIN0: “); Serial.print(adc0 * multiplier);
Serial.print(” AIN1: “); Serial.print(adc1 * multiplier);
Serial.print(” AIN2: “); Serial.print(adc2 * multiplier);
Serial.print(” AIN3: "); Serial.println(adc3 * multiplier);
Serial.print("Count: “); Serial.print(count);
Serial.println(” ");

Serial.println(“before wire.end”);
Serial.println(“after wire.end”);

//read battery voltage
uint16_t BatteryVoltage = getBatteryVoltage();
appData[appDataSize++] = (uint8_t)(BatteryVoltage >> 8);
appData[appDataSize++] = (uint8_t)BatteryVoltage;
Serial.print("BatteryVoltage: ");
Serial.println("Trigger: ");

//if(count > 169)
// {
// CySoftwareReset();
// ads1115.setup() };
// Serial.println(“ads reset”);
// else
// {
// Serial.println(“count less then 165”);

void setup() {

// The ADC input range (or gain) can be changed via the following
// functions, but be careful never to exceed VDD +0.3V max, or to
// exceed the upper and lower limits if you adjust the input range!
// Setting these values incorrectly may destroy your ADC!
// ADS1015 ADS1115
// ------- -------
// ads.setGain(GAIN_TWOTHIRDS); // 2/3x gain +/- 6.144V 1 bit = 3mV 0.1875mV (default)
ads.setGain(GAIN_ONE); // 1x gain +/- 4.096V 1 bit = 2mV 0.125mV
// ads.setGain(GAIN_TWO); // 2x gain +/- 2.048V 1 bit = 1mV 0.0625mV
// ads.setGain(GAIN_FOUR); // 4x gain +/- 1.024V 1 bit = 0.5mV 0.03125mV
// ads.setGain(GAIN_EIGHT); // 8x gain +/- 0.512V 1 bit = 0.25mV 0.015625mV
// ads.setGain(GAIN_SIXTEEN); // 16x gain +/- 0.256V 1 bit = 0.125mV 0.0078125mV

deviceState = DEVICE_STATE_INIT;

void loop()
switch( deviceState )
deviceState = DEVICE_STATE_JOIN;
prepareTxFrame( appPort );
// Schedule next packet transmission
txDutyCycleTime = appTxDutyCycle + randr( 0, APP_TX_DUTYCYCLE_RND );
deviceState = DEVICE_STATE_INIT;

Here’s a copy of the debug - i print before and after the ads.begin command and wire.end. As you can see it stops after the count of 169 (or at 170) under the command ads.begin(). Disregard the unconfirmed link as i get the message every other transmission - this is another issue i am trying to solve but the ADS issue is the priority

11:39:06.879 -> before ads.begin
11:39:06.879 -> after ads.begin
11:39:07.394 -> ADC0: 4512 ADC1: 4688 ADC3: 4752 ADC3: 4528
11:39:07.394 -> AIN0: 846.00 AIN1: 879.00 AIN2: 891.00 AIN3: 849.00
11:39:07.394 -> Count: 168
11:39:07.394 -> before wire.end
11:39:07.394 -> after wire.end
11:39:07.953 -> BatteryVoltage: 4162
11:39:07.953 -> Trigger:
11:39:08.422 -> Payload length(12) and fOptLen(2) exceed max size(11 for current datarate DR 0), set datarate to Dr 1
11:39:08.469 -> unconfirmed uplink sending …
11:39:08.469 -> TX on freq 903900000 Hz at DR 1 power 20 dBm
11:39:08.705 -> Event : Tx Done
11:39:09.693 -> RX on freq 923300000 Hz at DR 11
11:39:09.739 -> Event : Rx Timeout
11:39:10.724 -> RX on freq 923300000 Hz at DR 8
11:39:10.770 -> Event : Rx Timeout
11:39:24.218 -> before ads.begin
11:39:24.218 -> after ads.begin
11:39:24.732 -> ADC0: 4624 ADC1: 4656 ADC3: 4576 ADC3: 4480
11:39:24.732 -> AIN0: 867.00 AIN1: 873.00 AIN2: 858.00 AIN3: 840.00
11:39:24.732 -> Count: 169
11:39:24.732 -> before wire.end
11:39:24.732 -> after wire.end
11:39:25.249 -> BatteryVoltage: 4164
11:39:25.249 -> Trigger:
11:39:25.769 -> unconfirmed uplink sending …
11:39:25.769 -> TX on freq 905100000 Hz at DR 1 power 20 dBm
11:39:26.004 -> Event : Tx Done
11:39:26.990 -> RX on freq 926900000 Hz at DR 11
11:39:27.037 -> Event : Rx Done
11:39:27.271 -> received unconfirmed downlink: rssi = -107, snr = -2, datarate = 11
11:39:41.573 -> before ads.begin

You try to put “ads.begin()” in “setup()”.

I think you want to setup at the beginning and disable at the end of Tx.
At the beginning, you need to add ads.begin(); and ads.setGain(GAIN_ONE);
In the end, Wire.end(); should be ok.

Also, I only see digitalWrite(Vext, LOW); at the beginning, is it correct?
I think you should consider deactivate Vext using digitalWrite(Vext, HIGH);

1 Like

Thanks for the response. I am not sure what you mean at the beginning - are you talking at the beginning of the loop “static void prepare TxFrame”? or perhaps the “void loop”?

Regarding the digitalWrite(Vext, HIGH) - i did catch that issue and corrected it it.

for now i do have the workaround, when it reaches a count of 169 i reset the device but certainly is not the best way around that issue.

beginning of the prepareTxFrame

Thanks that’s what I thought you me and I did try it but gives me the same result. I do believe it has something to do with the ADS1115 register. I am looking for a way to reset the ADS instead of the HTCC- AB01. If you have any other ideas please let me know. The original WASN lora multi sensor sketch has the same issue. With the ADS1015 it stops at 165.

That’s really weird. There have been reports of something similar before, see here

I hate that turning ADR off helped in that case as that’s surely not a final answer, but if it changes the behaviours then at least we’ll learn something. Also you could implement the watchdog documented there too, again attacking the symptom rather than the cause though.

Thanks I do agree this is weird. I will also try turning ADR off to see if it helps. One good thing that it is consistent after frame 169 hence i can reset the board after it gets to that count - and it does work. Since it hangs while attempting to process ads.begin i will focus more on the wire.end and wire.begin and ads. Perhaps there is a way to reset either of them. I am not very familiar with watchdog - does stop the board from going to “sleep”?

Does it only say that right befor it stops working? That’d correlate to ADR possibly fixing it if it starts with a faster data rate and decays to one that can’t support sending 12 bytes (DR12, I imagine). There may be a latent bug with the DR change that log message says is trying to happen. Which region are you using?

And yes the watchdog is “unfriendly” to deep sleep, see what Aaron (Heltec) says back up that thread.

It does say that but it also adjust do DR1 prior to sending. I did put some print debug statement and it does hand on ads.begin() everytime - i printed before and after - the before print statement works then the after does not which makes be believe there is an issue between cubecell, lorawan and ads.
I am using the 915 US band (2nd band) and have an 8 channel gateway. By the way same happened with an ADS1015 and stopped at 164 consistently.
I have read there may be ways to reset the ads and will try this later in the week with a spare HTCC-AB01.
I did add this statement for now as a workaround:
if(count > 169)
{CySoftwareReset(); }

Fair enough.

This issue, and specifically this reset code, may be of interest.

Why the ads gets upset is another question. The board has pull-up resistors?

thanks, i will try over the next few days.
As far as i know pullups are not necessary for the ADS - given that it works 169 times supports that statement.

From what i have read lately it would seem to point out to the Wire library - given that it hangs at ads.begin leads me to believe it might be correct. The ads1x15 does call on the wire library as well. Here’s an excerpt from a forum with similar issues with an arduino:

" It’s hard to say anything for sure without seeing the code, but for a program that freezes using I2C communication, I would seriously suspect the Wire library. This library has a few loops here and there where it waits for a specific condition on the bus, with no timeout . See twi.c. "

I will also try a this modified library to see if it helps.

I tried the new wire library but same result. Tried with turning the led off - same result.