Same code Complies Differently on ArduinoIDE and VS - NativeEthernet/ModbusTCP Issues

mfrac

Member
Came across an odd error lately. If I use the exact same code in Visual Studio and Arduino IDE and upload to my Teensy 4.1 I get some changes in performance. Specifically I think it's affecting the EthernetClient aspect of NativeEthernet has trouble with connecting clients. VS code seems to have no issues managing the clients whereas the Arduino IDE will hang and disconnect the socket sometimes. I've attached screenshots of the errors. There is a time based algorithm that I am using so hangs aren't any good. I've copied the ArduinoModbus and ArduinoRS485 libraries from VS to the Arduino IDE and they both pull the same NativeEthernet library so I am not sure what's going on here. I've made sure Arduino IDE was latest version as well as all the libraries. This code also needs to go onto some lockable teensy 4.1s that I have so I am unaware of anyway to upload code to those unless it's through the Arduino IDE. Otherwise I'd just go along using VS.

The code as a whole sends out a UDP message with the Teensy IP every 10th loop cycle, that I have another device use to connect to it initially. The Teensy then does some work, posts it to some registers and repeats the cycle.

I'm sure the issue is in the dowork function. This function runs 1000 times and iterates through some data so I embedded the modbuspoll into it as I'll potentially have a few clients trying to get data every couple of seconds and I feel like this is the best place to poll. I used to poll outside this function (so once every ten seconds) for when I had just one client and it worked very well. With more clients I figured I had to poll/establish clients quicker and this does work very well with the VS uploaded code, but hangs and pauses a lot in Arduino IDE.

Code:
Code:
#include <Arduino.h>
#include <NativeEthernet.h>
#include <ArduinoRS485.h>
#include <ArduinoModbus.h>

//Udp stuff
EthernetUDP Udp;

uint16_t destPort = 52362;      // port to send Teensy UDP heartbeat to
const char all_ip[] = "255.255.255.255";
char udp_message[] = "Teensy";
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];

//Modbus Registers
int variable1_reg = 46000;
int variable2_reg = 46002;
int variable3_reg = 46004;
int variable4_reg = 46006;
int variable5_reg = 46080;
int register_range = 65500; 

float variable1 = 1.0;
float variable2 = 2.0;
float variable3 = 3.0;
float variable4 = 4.0;

int variable5 = 5;

int modport = 50000;

uint8_t LED = 13;
uint8_t mac[6];

EthernetServer ethServer(modport);
ModbusTCPServer modbusTCPServer;


void teensyMAC(uint8_t *mac) {
// Obbtaining native hardware mac address
  for (uint8_t by = 0; by < 2; by++) mac[by] = (HW_OCOTP_MAC1 >> ((1 - by) * 8)) & 0xFF;
  for (uint8_t by = 0; by < 4; by++) mac[by + 2] = (HW_OCOTP_MAC0 >> ((3 - by) * 8)) & 0xFF;
  Serial.printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

void blink(uint8_t repititions, uint16_t time) {
  //Blinks a defined number of times with a declared delay
  for (int i=0; i<repititions; i++){
    digitalWrite(LED, HIGH);
    delay(time);
    digitalWrite(LED, LOW);
    delay(time);
  }
}

void udp_heartbeat() {
//Send out UDP message with Teensy IP every 10th call

  static int i = 0;
  int call_freq = 10;
  int packet_size = Udp.parsePacket();

  if (i==0) {
    Udp.beginPacket(all_ip, destPort);
    Udp.write(udp_message);
    Udp.endPacket();
    i++;
  }

  else if (i == call_freq){
    i = 0;
  }

  else {
    i++;
  }
}


void modbus_init() {

  if (!modbusTCPServer.begin()) {
    Serial.println("Failed to start Modbus TCP Server!");
    blink(6, 500);
    delay(2000);
  }
  
  else {
    Serial.println("Modbus TCP Server Active");
    modbusTCPServer.configureHoldingRegisters(1, register_range);
    delay(10);
  }
}

void Ethernet_init() {
  String IP;

  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    blink(3, 500);
    delay(2000);

    // Check for Ethernet hardware present
    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      Serial.println("No Ethernet hardware found");
      blink(4, 500);
      delay(2000);
    }
    // Check if a link is present
    if (Ethernet.linkStatus() == LinkOFF) {
      Serial.println("Ethernet cable is not connected");
      blink(5, 500);
      delay(2000);
    }
  } 
  
  // Good Ethernet connection established, getting assigned IP of Teensy
  else {
    Serial.print("DHCP assigned IP: ");
    Serial.println(Ethernet.localIP());
    blink(1, 1000);
     
  }
}

void dowork() {
//Slimmed down of real version, but analyses data in the for loop from various sensors that then get put into the modbus registers

  EthernetClient modclient;

  for(int i = 0; i<1000; i++) {

    modclient = ethServer.available();

    if (modclient) {
      modbusTCPServer.accept(modclient);
    }

    //Get some sensor data here

    delay(10);

    if (modclient.connected()) {
        modbusTCPServer.poll();
        Serial.println("Modbus Polled");
    }
  }

  Serial.println("Work Completed");
  
}



union {
  float asFloat;
  u_int16_t asInt[2];
}
variable1_modbus;

union {
  float asFloat;
  u_int16_t asInt[2];
}
variable2_modbus;

union {
  float asFloat;
  u_int16_t asInt[2];
}
variable3_modbus;

union {
  long asLong;
  u_int16_t asInt[2];
}
variable4_modbus;


void modbus_write_values() {

  //Splitting Floats into two u_int_16 variables
  variable1_modbus.asFloat=variable1;
  variable2_modbus.asFloat=variable2;
  variable3_modbus.asFloat=variable3;
  variable4_modbus.asLong=variable4;

  modbusTCPServer.holdingRegisterWrite(variable1_reg, variable1_modbus.asInt[0]);
  modbusTCPServer.holdingRegisterWrite(variable1_reg + 1, variable1_modbus.asInt[1]);

  modbusTCPServer.holdingRegisterWrite(variable2_reg, variable2_modbus.asInt[0]);
  modbusTCPServer.holdingRegisterWrite(variable2_reg + 1, variable2_modbus.asInt[1]);

  modbusTCPServer.holdingRegisterWrite(variable3_reg, variable3_modbus.asInt[0]);
  modbusTCPServer.holdingRegisterWrite(variable3_reg + 1, variable3_modbus.asInt[1]);
  
  modbusTCPServer.holdingRegisterWrite(variable4_reg, variable4_modbus.asInt[0]);
  modbusTCPServer.holdingRegisterWrite(variable4_reg + 1, variable4_modbus.asInt[1]);

  modbusTCPServer.holdingRegisterWrite(variable5_reg, variable5);

  blink(1, 50);
}

void setup() {
  delay(100);
  Serial.begin(9600);
  teensyMAC(mac);
  Ethernet_init();
  modbus_init();
  Udp.begin(destPort);
  ethServer.begin();
  
}


void loop() {

    udp_heartbeat();
    dowork();
    modbus_write_values();
  
}





ArduinoIDEissues.JPGVSNoIssue.JPG
 
Are you using VisualMicro with Visual Studio?
If not, this is the way to go with VS. It mimics the Arduino IDE and has all the bits n pieces to handle Encryption upload.
 
I'm using Visual Studio Code with Platformio. I just tried VisualMicro and it's acting like the Arduino IDE upload, as in it's having socket issues. Somehow VScode and Platformio isn't acting like this and it's bizarre to me, since again, I'm literally copy/pasting code from one IDE to the other.

I may very well just be structuring this code horribly when trying to deal with multiple clients, but it's just weird to me that two different IDEs with the same code and libraries are acting differently.
 
Same Compiler?
Same Compiler options?

Using same libraries and cores?

Earlier I found with VisualMicro they did not follow the Arduino search order processing for which copy it uses.

If I remember correctly with:

Arduino IDE if same library is in: teensy install, and a version is in your <sketches> library folder - it will use sketches folder version
visual micro used the teeny installed version. Not sure if still same
 
Libraries are the same. I copied the ones in VS Code/Platformio over to Arduino IDE just to be sure (and verified they're both the same version), then the NativeEthernet pulls from the same place I believe. I also copied the teensy and teensy4 cores over from platformio to Arduino, but I get some compilation error that way. I think it's on account of this message: "Error: CSF not within firmware image, found 6004D800" but I'm not too sure.

I'm not too sure how to change/match the options from VS Code/Platformio over to the Arduino IDE unfortunately, I haven't gone that deep yet.
 
I think it's actually working now... I copied the boards.txt, keywords.txt, platform.txt, cores folder and libraries folder over to the Arduino/hardware/teensy/avr folder and everything seems to be ok. Also copied the .piopm and package.json files over as well but I'm not sure if they do anything outside of platformio.
 
Had to back track, doing the above compiled/uploaded to an unlocked teensy, but wouldn't work on a locked. Had problems making the .ehex or something. Dug further and copied the NativeEthernet and FNET library from the platformio folder over to the Arduino/hardware/teensy/avr/libraries folder (after reverting this folder to its original files to undo what I did earlier) and it uploaded no problem.

I appreciate the help from everyone, I've been hung up on this problem longer that I like to admit.
 
Back
Top