Closed zekageri closed 2 years ago
@zekageri
I see you are using PlatformIO. Is your build based on Arduino Core 1.0.6? Latest PIO Arduino Core is still 1.0.6.
Would you mind testing it using Arduino IDE with latest Arduino Core (2.0.3-RC1)?
Thanks.
This is my pio ini file
[env:arduino-esp32]
platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream
board = esp32dev
framework = arduino
platform_packages =
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32#master
board_build.f_cpu = 240000000L
upload_port = COM8
upload_speed = 921600
monitor_speed = 115200
monitor_filters = esp32_exception_decoder
board_build.flash_size = 16MB
board_build.flash_mode = dio
board_build.partitions = ./hsh_Partition.csv
board_build.f_flash = 80000000L
build_flags = -DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
-DCORE_DEBUG_LEVEL=0
;-D CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
;-D CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
extra_scripts = mklittlefs/replace_fs.py
I downloaded the new Arduino IDE 2.0.0 and i can only download the 1.0.6 espressif framework.
Please check this guide: https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html
For using v2.0.3-rc1, you need to change your link in Preferences to Development release link.
I know that but with PIO i'm already using the latest with this ini file:
platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream
board = esp32dev
framework = arduino
platform_packages =
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32#master
@zekageri - please check these links regarding PIO setup: https://github.com/espressif/arduino-esp32/issues/6647#issuecomment-1111792625 https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html#installing-using-platformio
Thank you, i will try this!
Wow @SuGlider i got a bunch of warning messages ( like really much ) and then a linker fail
c:/users/pc/.platformio/packages/toolchain-xtensa-esp32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: final link failed: No such file or directory
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\arduino-esp32\firmware.elf] Error 1
I will try to delete platform and packages folder from .platformio and recompile
Okay, deleted cache, packages and platform folder from .platformio inside users. The sketch compiled, i did upload it to my esp32 but the problem presist. Serial.flush() does not wait for all bytes
I'm pretty sure that Serial.flush()
only returns when all bytes are sent.
https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-uart.c#L319-L332
There was an issue related to MODBUS and it was fixed there. Fixed by #6133
Are you sure you are building with the latest Arduino Core version?
Yeah, its 4.1.0
This is really interesting. Is there something wrong with my code? I configured Serial2 now instead of the Serial1 and commented out the microsec delay and i rarely got frame timeout now.
If there is file system access or other mid heavy process on other tasks, i got one or two frame timeouts.
void mBusSetup(){
pinSetup();
Serial2.begin(MBUS_BAUD,SERIAL_8N1,MBUS_RX,MBUS_TX);
}
void mSystem::pinSetup(){
pinMode(MBUS_TX_EN, OUTPUT);
digitalWrite(MBUS_TX_EN, LOW);
}
void mSystem::startWrite(){
digitalWrite(MBUS_TX_EN, HIGH);
}
void mSystem::endWrite(){
Serial2.flush();
//delayMicroseconds(400);
digitalWrite(MBUS_TX_EN, LOW);
}
void mSystem::rawWrite(uint8_t * data, int length){
int crc16 = getCRC_16(data, length);
startWrite();
Serial2.write( data, length );
Serial2.write( lowByte(crc16) );
Serial2.write( highByte(crc16) );
endWrite();
}
#define MBUS_LISTEN_TIMEOUT 150 // Modules will respond back in maximum of 15ms.
void writeReadDevice(int index){
// This function handles which device address to write and assmebles the writable data and calls
// rawWrite. If rawWrite returns, this function waits for the response data.
uint8_t exampleData[] = {0xFF, 0x03, 0x00, 0x06, 0x00, 0x03};
uint8_t responseData[20]; // Maximum response data is 10-13.
rawWrite(exampleData, sizeof(exampleData));
// wait for the response data.
// The modules will respond back if the data is understandable.
long startMs = millis();
while( !Serial1.available() ){
vTaskDelay(1);
if( millis() - startMs >= MBUS_LISTEN_TIMEOUT ){
Serial.println("FRAME TIMEOUT!");
return;
}
}
int respDataCount = 0;
while( Serial1.available() > 0 ){
responseData[respDataCount] = Serial1.read();
respDataCount++;
}
}
Are you absolutely sure that the output data is broken?
I currently have issues reading the data with v2.0.0+, including v2.0.3-rc1.
My issue is that incoming data up to 120 bytes (UART_FIFO_LEN
- margin?) gets buffered (Serial1.available()
returns 0), but then everything arrives in a burst.
There is a new API for UART called onReceive(callbackFunc)
It works as a sort of ISR... When data arrives and there is short interval of time (as long as about 11 symbols in the current baudrate), it will call right away the callback function.
It may help...
@SuGlider thank you. onReceive
works for the default Serial
, but doesn't work on the Serial1, which is initialized this way:
//Serial1.setRxBufferSize(512); // tried this, doesn't affect anything. data is always read in chunks of 120 bytes
Serial1.begin(9600, SERIAL_8N1, 2, 15);
On 1.0.6 i don't see such issues. Could it be an ESP-IDF issue?
UPD: ok, what I experience is similar to this: https://github.com/espressif/esp-idf/issues/8369 But in my case RS485 is not involved. Ok, will get to this with the logic analyzer.
Actually it works for all Serial, Serial1 and Serial2.
Just use Serial1.onReceive()
Sure. But it looks like i have problems on the signal lavel. Sorry, it is probably unrelated to this issue.
void mBusSetup(){ pinSetup(); Serial2.begin(MBUS_BAUD,SERIAL_8N1,MBUS_RX,MBUS_TX); } void mSystem::pinSetup(){ pinMode(MBUS_TX_EN, OUTPUT); digitalWrite(MBUS_TX_EN, LOW); } void mSystem::startWrite(){ digitalWrite(MBUS_TX_EN, HIGH); } void mSystem::endWrite(){ Serial2.flush(); //delayMicroseconds(400); digitalWrite(MBUS_TX_EN, LOW); } void mSystem::rawWrite(uint8_t * data, int length){ int crc16 = getCRC_16(data, length); startWrite(); Serial2.write( data, length ); Serial2.write( lowByte(crc16) ); Serial2.write( highByte(crc16) ); endWrite(); } #define MBUS_LISTEN_TIMEOUT 150 // Modules will respond back in maximum of 15ms. void writeReadDevice(int index){ // This function handles which device address to write and assmebles the writable data and calls // rawWrite. If rawWrite returns, this function waits for the response data. uint8_t exampleData[] = {0xFF, 0x03, 0x00, 0x06, 0x00, 0x03}; uint8_t responseData[20]; // Maximum response data is 10-13. rawWrite(exampleData, sizeof(exampleData)); // wait for the response data. // The modules will respond back if the data is understandable. long startMs = millis(); while( !Serial1.available() ){ vTaskDelay(1); if( millis() - startMs >= MBUS_LISTEN_TIMEOUT ){ Serial.println("FRAME TIMEOUT!"); return; } } int respDataCount = 0; while( Serial1.available() > 0 ){ responseData[respDataCount] = Serial1.read(); respDataCount++; } }
It seems OK, if you are sending data through Serial2 and receiving through Serial1.
Okay, deleted cache, packages and platform folder from .platformio inside users. The sketch compiled, i did upload it to my esp32 but the problem presist. Serial.flush() does not wait for all bytes
I just tested Serial.flush()
. It only returns when FIFO is empty and all data has been sent out.
It is very easy to see it when baudrate is 300bps and we send a string with about 200 characters, associating turning on/off builtin LED before/after Serial.print()
.
Can it be high baud rate problem? ( 115200 ) Or can it be that other tasks interfere, and the pin is not going to low in time?
void mSystem::startWrite(){
digitalWrite(MBUS_TX_EN, HIGH);
}
void mSystem::endWrite(){
Serial1.flush();
digitalWrite(MBUS_TX_EN, LOW);
}
void mSystem::rawWrite(uint8_t * data, int length){
int crc16 = getCRC_16(data, length);
startWrite();
Serial1.write( data, length );
Serial1.write( lowByte(crc16) );
// Other tasks interrupts this task in here maybe??
Serial1.write( highByte(crc16) );
// OR here?
endWrite();
}
@zekageri - Just to make sure it is not bad configuration of the development environment, could you please update your PlatformIO version to the latest as described in https://piolabs.com/blog/news/platformio-oss-april-2022-updates.html
Thanks!
Thank you for your response. I did update my environmnet. Currently using espressif 4.2.0 and PlatformIO 5.2.5.
This results in a strange boot loop when using default_16MB.csv with esp-wrover-kit
board.
The wrover kit's external ram and it's 16mb flash is absolutly necessary for me.
I can't go forward if this isnt solved.
I opened a new issue for this : Boot loop issue with 16mb csv
Boot loop problem solved. Upgraded to latest framework, issue still presist.
Frame timeouts are inconsistent. Can not lower the baudrate because the modules that i communicate with are tied to 115200.
void mSystem::startWrite(){
//mBusLock();
//Serial2.flush();
digitalWrite(MBUS_TX_EN, HIGH);
}
void mSystem::endWrite(){
Serial2.flush();
//delayMicroseconds(200);
digitalWrite(MBUS_TX_EN, LOW);
//mBusUnLock();
}
void mSystem::rawWrite(uint8_t * data, int length){
int crc16 = getCRC_16(data, length);
startWrite();
Serial2.write( data, length );
Serial2.write( lowByte(crc16) );
Serial2.write( highByte(crc16) );
endWrite();
}
rawWrite(writeBuffer,writeBufferSize);
long startMS = millis();
while ( !Serial2.available() ){
vTaskDelay(1);
if( millis() - startMS > READ_WRITE_TIMEOUT ){
Serial.printf("FRAME TIMEOUT at millis: %d\n",millis());
return false;
}
}
Serial:
FRAME TIMEOUT at millis: 71669
FRAME TIMEOUT at millis: 127851
It is rarely happening with the new espressif 4.2.0. But it is there.
( mostly on page refresh, or long file operations with LittleFs )
Sometimes i get a bunch of timeouts on page close or refresh like this:
FRAME TIMEOUT at millis: 39941
FRAME TIMEOUT at millis: 40124
FRAME TIMEOUT at millis: 40304
FRAME TIMEOUT at millis: 57933
FRAME TIMEOUT at millis: 58296
FRAME TIMEOUT at millis: 58484
FRAME TIMEOUT at millis: 58675
FRAME TIMEOUT at millis: 77164
FRAME TIMEOUT at millis: 85935
FRAME TIMEOUT at millis: 86111
FRAME TIMEOUT at millis: 86289
FRAME TIMEOUT at millis: 86468
FRAME TIMEOUT at millis: 86642
FRAME TIMEOUT at millis: 89668
FRAME TIMEOUT at millis: 89844
FRAME TIMEOUT at millis: 90020
FRAME TIMEOUT at millis: 90196
FRAME TIMEOUT at millis: 90459
Questions:
How much is READ_WRITE_TIMEOUT
? 150ms?
Why using vTaskDelay(1);
? It will delay for a whole RTOS Tick... I'm not sure but I think that it is about 100ms...
How to make sure that this timeout is not due to other devices or the bus itself?
@vshymanskyy
My issue is that incoming data up to 120 bytes (
UART_FIFO_LEN
- margin?) gets buffered (Serial1.available()
returns 0), but then everything arrives in a burst.
It seems that IDF has actually a special behavior when RX FIFO reaches 120 bytes (full threshold). I'm investigating it and there is a setup for "timeout always on even on FIFO Full" that is disabled by default in IDF driver. Further information in https://github.com/espressif/arduino-esp32/issues/6689#issuecomment-1146626896
READ_WRITE_TIMEOUT is 150ms. ( it should be max 20-30 ms since a device takes about 10-15 ms to respond )
vTaskDelay(1) is used to allow other tasks to run while that task waits for incoming bytes. ( it does not change anything if i comment it out )
We measured it with Oscilloscope. The devices on the bus never missed a single packet in extensive texting. They are not doing any other tasks just sending back their registers if the esp asks them to.
Possible relationship with https://github.com/espressif/arduino-esp32/issues/6689#issuecomment-1146626896
Meanwhile i throttled my communication task and i found out that if i write on serial every 4.7ms the esp sends out all the packets and the modules on the bus are happily answer every time. This delay is fluid because i did not used timers, just the good old millis(). But it definitely helped. Ofc it is a workaround. I want my communication task to be as fast as possible since there can be dozens of modules on the bus and it can take a while to write all of them ( and wait for every response )
The processors inside the modules are PICKs, they are not the fastest, so if the esp wants like 20 continous register values, that can delay the whole communication. And there are GPIO-s on some of the modules too. So it would be really good to not include this 4700 micro delay.
@zekageri
Regarding the time it take to return from Serial2.available()
, please try with this code (change it to Serial2 if necessary):
void mBusSetup(){
pinSetup();
Serial1.begin(MBUS_BAUD,SERIAL_8N1,MBUS_RX,MBUS_TX);
Serial1.setRxTimeout(1);
// Not sure if the code lline below improves response time for Serial1.available()
// please make a test with it and another without it
uart_set_always_rx_timeout(1, true); // 1 is for Serial1, in this case
}
Thank you for the suggesrion. i will try this now.
identifier "uart_set_always_rx_timeout" is undefined
Do i have to include something for this to work?
error: 'uart_set_always_rx_timeout' was not declared in this scope
uart_set_always_rx_timeout(2, true);
With this in setup:
Serial2.begin(MBUS_BAUD,SERIAL_8N1,MBUS_RX,MBUS_TX);
Serial2.setRxTimeout(1);
//uart_set_always_rx_timeout(1, true);
and commented out delay in loop
//if( micros() - lastWriteMicros >= MODBUS_MIN_WRITE_TIME_MICRO ){
//lastWriteMicros = micros();
writeReadDevice(deviceIndex);
deviceIndex++;
if( deviceIndex > deviceCounter ){ deviceIndex = 0; vTaskDelay(1); }
//}
it is much worse.
Sample from my debug output:
FRAME TIMEOUT at millis: 144274 module id: 20
FRAME TIMEOUT at millis: 144334 module id: 179
FRAME TIMEOUT at millis: 144430 module id: 20
FRAME TIMEOUT at millis: 144490 module id: 179
FRAME TIMEOUT at millis: 144559 module id: 177
FRAME TIMEOUT at millis: 144637 module id: 20
FRAME TIMEOUT at millis: 144697 module id: 179
FRAME TIMEOUT at millis: 144766 module id: 177
FRAME TIMEOUT at millis: 144846 module id: 20
FRAME TIMEOUT at millis: 144906 module id: 179
FRAME TIMEOUT at millis: 144975 module id: 177
FRAME TIMEOUT at millis: 145053 module id: 20
FRAME TIMEOUT at millis: 145119 module id: 177
FRAME TIMEOUT at millis: 145183 module id: 177
FRAME TIMEOUT at millis: 145262 module id: 20
FRAME TIMEOUT at millis: 145328 module id: 177
FRAME TIMEOUT at millis: 145392 module id: 177
FRAME TIMEOUT at millis: 145499 module id: 177
FRAME TIMEOUT at millis: 145590 module id: 179
FRAME TIMEOUT at millis: 145687 module id: 20
FRAME TIMEOUT at millis: 145747 module id: 179
FRAME TIMEOUT at millis: 145816 module id: 177
FRAME TIMEOUT at millis: 145895 module id: 20
FRAME TIMEOUT at millis: 145966 module id: 179
In every 200 ms or so, there is still a timeout on a random module.
If i use Serial2.setRxTimeout(1);
i got frame timeouts even with the 4700 microsec delay.
So my task looks like this:
void mBusLoopTask(void* parameter){
hsh_modbus.setup();
hsh_modbus.ready = true;
for(;;){
hsh_modbus.loop();
}
}
Loop looks like this:
void mSystem::loop(){
scanBus(); // <-- waits for a flag
reinitSavedDevices(); // <-- waits for a flag
if( !shouldScanBus && !reinitingSavedDevices && !hsh_Server.firmwareUpdating && !hsh_Performance.isHwResetRunning() ){
// MODBUS_MIN_WRITE_TIME_MICRO -> 4700
if( micros() - lastWriteMicros >= MODBUS_MIN_WRITE_TIME_MICRO ){
lastWriteMicros = micros();
writeReadDevice(deviceIndex); // <-- actual write function you see above. Assemble, write and wait for the packet back.
deviceIndex++;
if( deviceIndex > deviceCounter ){ deviceIndex = 0; vTaskDelay(1); }
}
hsh_modules.sendPeriodicModuleInfo(); // <-- every couple secs with millis() ( non blocking )
faultReset(); // <-- waits for a queue
consumeMaxAmper(); // <-- waits for a queue
consumeThermCalibration(); // <-- waits for a queue
}else{
vTaskDelay(100);
}
}
Write function important part:
rawWrite(writeBuffer,writeBufferSize);
long startMS = millis();
while ( !Serial2.available() ){
//vTaskDelay(1); // Not used. Changes nothing.
// READ_WRITE_TIMEOUT -> 55ms ( for now )
if( millis() - startMS > READ_WRITE_TIMEOUT ){
Serial.printf("FRAME TIMEOUT at millis: %d module id: %d\n",millis(),modules[index]->id);
return false;
}
}
while ( Serial2.available() ){
respBuffer[respDataCount] = Serial2.read();
respDataCount++;
}
Serial1
or Serial2
does not change anything.
@zekageri - I found out that some power meters send BREAK (holds the line Low for more than 11 bits in the current baudrate) to UART at the end of a data frame.
It seems to cause this delay that you are reporting. Do you think that this is your case?
identifier "uart_set_always_rx_timeout" is undefined
Do i have to include something for this to work?
error: 'uart_set_always_rx_timeout' was not declared in this scope uart_set_always_rx_timeout(2, true);
it is necessary to include "driver/uart.h"
#include "driver/uart.h"
I think that both (setRxTimeout(1)
and uart_set_always_rx_timeout(2, true)
) may improve the timing.
The idea is to force available()
to always have data in the timeout of 1 symbol at the current UART baudrate.
So for 9600 bauds, 1 symbol with 11 bits (parity, stop bits etc), the timeout to get data available would be about 1ms.
Thank you for the tremendous help. The modules does not send BREAK, i'm sure of it. They are configured for 8 bit and a stop bit. I can monitor their response with multiway v10 which is a software to test modbus communcation for PC. If the esp is out of the bus and i send commands to the modules manually with multiway, i can see that they answering correctly every time. The Multiway software is configured for the same settings which is 115200 baud, no parity, 8 data bit and 1 stop bit.
I included "driver/uart.h", commented out the delay again and on setup i set both
Serial2.setRxTimeout(1);
uart_set_always_rx_timeout(2, true);
The frame timeout is here again.
But i noticed something. Regardless of these two lines, my task loop looks like this:
void mBusLoopTask(void* parameter){
hsh_modbus.setup();
hsh_modbus.ready = true;
for(;;){
//if( micros() - lastWriteMicros >= MODBUS_MIN_WRITE_TIME_MICRO ){
//lastWriteMicros = micros();
writeReadDevice(deviceIndex); // <-- actual write function you see above. Assemble, write and wait for the packet back.
deviceIndex++;
if( deviceIndex > deviceCounter ){ deviceIndex = 0; vTaskDelay(1); }
// }
}
}
Notice the vTaskDelay(1)
; for task switching happens if it writed every module. So i wanted the task switch to happen only if the esp writed every module. This results in a lot of FRAME_TIMEOUT ( usually in every 100ms or so ).
If i modify my task loop to this:
void mBusLoopTask(void* parameter){
hsh_modbus.setup();
hsh_modbus.ready = true;
for(;;){
//if( micros() - lastWriteMicros >= MODBUS_MIN_WRITE_TIME_MICRO ){
//lastWriteMicros = micros();
vTaskDelay(1);
writeReadDevice(deviceIndex); // <-- actual write function you see above. Assemble, write and wait for the packet back.
deviceIndex++;
if( deviceIndex > deviceCounter ){ deviceIndex = 0; }
// }
}
}
The FRAME_TIMEOUTS happens only a couple of seconds on a random module, but now i have CRC Mismatch too.
Sample from the debug output:
FRAME TIMEOUT at millis: 3431308 module id: 20
new write CRC Mismatch. Got: FC00 Calculated: E140
new write CRC Mismatch. Got: FC00 Calculated: 21B1
new write CRC Mismatch. Got: FC00 Calculated: E140
IO - Disconnected!
new write CRC Mismatch. Got: FC00 Calculated: 21B1
new write CRC Mismatch. Got: FC00 Calculated: 21B1
IO - Disconnected!
FRAME TIMEOUT at millis: 3435624 module id: 20
IO - Disconnected!
new write CRC Mismatch. Got: FD00 Calculated: ED80
FRAME TIMEOUT at millis: 3438019 module id: 30
new write CRC Mismatch. Got: FD00 Calculated: ED80
new write CRC Mismatch. Got: FC00 Calculated: E140
IO - Disconnected!
IO - Disconnected!
new write CRC Mismatch. Got: FC00 Calculated: E140
new write CRC Mismatch. Got: FC00 Calculated: 21B1
So if i let the task switch frequently ( after every write ) the response data is broken a lot of the times, and sometimes it is even timeouts.
If i let TickType_t 2
delay for the task between every write, no CRC mismatch and no frame timeout. ( only if i load a heavy webpage )
Like this:
void mBusLoopTask(void* parameter){
hsh_modbus.setup();
hsh_modbus.ready = true;
for(;;){
vTaskDelay(2);
writeReadDevice(deviceIndex); // <-- actual write function you see above. Assemble, write and wait for the packet back.
deviceIndex++;
if( deviceIndex > deviceCounter ){ deviceIndex = 0; }
}
}
But ofc this results in a somewhat slow communication, since i'm monitoring push buttons and their times too which are wired to the modules. I can live with that, there are ways to eliminate these times with software adjustment but for perfect timing, i would prefer faster writes. :/
There are 8 modules on the bus right now. This results in a 8x2 tick delay for a module. This vTaskDelay()
can be any number, since i don't know how much time it takes to return to this task. It could be 15 or 20 or more ms in my understanding. So if i count with 15ms between writes the last module response would be 8x15ms after the communication starts. So it is 120ms between two write for a module. If the user increases the number of modules ( there can be any number of modules on the bus since the ID's are hand out automatically and stored in the fs ) let's say the user has 20 modules on the bus, it can take 300ms for one module between writes.
But this is an ideal time since i don't know how much the RTOS works with other tasks. But this 300ms delay can affect a lot of things.
Just to get us in the same page:
FreeRTOS runs the tasks at 1000Hz by default in Arduino.
https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/esp32/sdkconfig#L943
vTaskDelay(1)
means delaying at least 1ms, depending on how the processing goes.
But, this time depends on the other Tasks that are running in the ESP32. I think that your project has ETH as well... The ISRs and other routines with higher priority may interfere with this timing. It is hard to make Arduino work in a very deterministic way with several peripherals, tasks and so on.
How exactly is this wired?
Are you using a RS-485 module? Which one?
Does it use ESP32 RTS pin in order to control DE/RE pin of the RS485 module?
Or DE/RE (if any) are in shortcut and controlled by MBUS_TX_EN
pin?
Yes, i aggree it can be hard to tell with so many peripherials. Yes, i use ETH and a lot of other things, and i have a lot of other tasks.
Modbus is using an RS-485 converter. I can not tell now which one it is because it itn't a complett module but an SMD IC. ( i will look it up )
The converter uses the esp MBUS_TX_EN
pin to determine if it has to switch to rx or tx mode, which will be pulled low by my software when it sent out all the packets and high when it starts sending. I don't use any built in pin for this. Should i?
And again, i can not use the built in modbus library because the protocoll slighly modified in my environment and some things can not work. It isn't a standard modbus protocoll. But the timing and the packets are the same.
As you can see in my examples before, i have these functions to write to the serial:
// Pull the converter pin to HIGH to indicate the start of the packets.
void mSystem::startWrite(){
digitalWrite(MBUS_TX_EN, HIGH);
}
// Pull the converter pin to LOW to indicate the end of the packets and flush Serial to send all the data that is left in the buffer.
void mSystem::endWrite(){
Serial1.flush();
digitalWrite(MBUS_TX_EN, LOW);
}
void mSystem::rawWrite(uint8_t * data, int length){
// Compute the crc for the data.
int crc16 = getCRC_16(data, length);
startWrite();
// Add the whole data to Serial buffer.
Serial1.write( data, length );
// Add CRC low and high byte to the Serial buffer.
Serial1.write( lowByte(crc16) );
Serial1.write( highByte(crc16) );
endWrite();
}
I did not specify any pin in Serial1.begin()
These fucntions should work fine... What exactly is the issue you are seeing with it?
I tested it here for about 12 horus sending data, using ESP32 with DIO (QIO doesn't work with default pins 9 and 10 for Serial1 beacuse these pins are used for accessing the flash). It works fine and fast, no delay, no data loss.
Sorry i meant i did not specify any data controll pin which would internally go high on write and low on flush. I do it myself. My pins are the following for serial
#define MBUS_RX 34 // 6. PIN #define MBUS_TX 15 // 23. PIN #define MBUS_TX_EN 5 #define MODBUS_MIN_WRITE_TIM.E_MICRO 5000
The issue iam seeing is byte loss when writing with 115200 baudrate continously
@zekageri
I would like to propose a fix for Serial2.read()
and Serial2.available()
that I think would improve UART response time:
// Necessary include for testing the fix
#include "driver/uart.h"
void setup() {
// for example, start Serial2 - UART2
Serial2.begin(115200);
// right after starting UART2, add this code:
uart_intr_config_t uart_intr = {
.intr_enable_mask = (0x1<<0) | (0x8<<0), // UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT,
.rx_timeout_thresh = 1,
.txfifo_empty_intr_thresh = 10,
.rxfifo_full_thresh = 112,
};
uart_intr_config((uart_port_t) 2, &uart_intr); // Two is the UART number for Arduino Serial
}
Could you please test it and let me know. Thanks.
Thank you i will try it now.
I have got some compile errors with this:
src/utilities/modBus.cpp: In member function 'void mSystem::testSerialSetup()':
src/utilities/modBus.cpp:1506:27: error: 'UART_INTR_RXFIFO_FULL' was not declared in this scope
.intr_enable_mask = UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT,
^~~~~~~~~~~~~~~~~~~~~
src/utilities/modBus.cpp:1506:27: note: suggested alternative: 'UART_BUFFER_FULL'
.intr_enable_mask = UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT,
^~~~~~~~~~~~~~~~~~~~~
UART_BUFFER_FULL
src/utilities/modBus.cpp:1506:51: error: 'UART_INTR_RXFIFO_TOUT' was not declared in this scope
.intr_enable_mask = UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT,
^~~~~~~~~~~~~~~~~~~~~
src/utilities/modBus.cpp:1506:51: note: suggested alternative: 'UART_FIFO_OVF'
.intr_enable_mask = UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT,
^~~~~~~~~~~~~~~~~~~~~
UART_FIFO_OVF*** [.pio\build\esp-wrover-kit\src\utilities\modBus.cpp.o] Error 1
#include "driver/uart.h"
void mSystem::testSerialSetup(){
uart_intr_config_t uart_intr = {
.intr_enable_mask = UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT,
.rxfifo_full_thresh = 112,
.rx_timeout_thresh = 1,
.txfifo_empty_intr_thresh = 10,
};
uart_intr_config((uart_port_t) 1, &uart_intr);
}
void mSystem::setup(){
Serial1.begin(MBUS_BAUD,SERIAL_8N1,MBUS_RX,MBUS_TX);
testSerialSetup();
}
By the way here is all my task initialization. I try to isolate the modbus task from the rest.
void initTasks(){
fileSys.init(1,2,FILE_SYS_STACK_SIZE);
hsh_modbus.init(-1,4,MODBUS_SYS_STACK_SIZE);
networkSys.init(1,2,NETWORK_SYS_STACK_SIZE);
hshDisplay.init(1,2,DISPLAY_SYS_STACK_SIZE);
hsh_Server.init(1,2,SERVER_SYS_STACK_SIZE);
hsh_Performance.init(1,2,PERFORMANCE_SYS_STACK_SIZE);
hsh_GeoSystem.init(1,2,GEO_SYS_STACK_SIZE);
hsh_timeSystem.init(1,2,TIME_SYS_STACK_SIZE);
zones.init(1,3,ZONES_SYS_STACK_SIZE);
}
Board
esp32-wrover-e
Device Description
Custom board, using ESP32-Wrover-E ( 16mb flash 8mb external ram )
Hardware Configuration
Ethernet -> ETH_LAN_8720 chip
RTC Module -> DS3231 chip ( i2c )
Transistor for restarting the device -> 2n2222 or similar. ( GPIO 12 )
Two hardware serial UART:
Version
latest master (checkout manually)
IDE Name
Platform IO
Operating System
Windows 10
Flash frequency
80Mhz
PSRAM enabled
yes
Upload speed
115200
Description
Serial1 sometimes does not send out all the bytes and i got a frame timeout in my communication because the modules that my esp communicates doesnt understand the broken message. Happens mostly on web page load or file upload via HTTP.
Communication runs on an available core in a separate task with 115200 baud rate, tries to write as soon as possible.
Sketch
Debug Message
Other Steps to Reproduce
Try to write frequently on serial1.
I have checked existing issues, online documentation and the Troubleshooting Guide