cbalint13 / tinnymodbus

RS485 ModBus tiny multi-sensor module
Other
99 stars 31 forks source link

different Baudrate not working #8

Closed stif closed 7 months ago

stif commented 4 years ago

Hi Cristian,

Readings from a USB-RS485 Adapter to 4 daisy-chained RS485-Sensors are stable, but when i use a custom ESP32 Modul i sometimes have read errors. That is why i tried to lower the Baudrate..

I changed to 19200 Baud here https://github.com/cbalint13/tinnymodbus/blob/9338edd8b9495ad1da0f8c73a971d87fcf3038c3/libs/usiuartx.h#L73 and flashed it to the ATtiny85. But afterwards i could not connect to the Sensor anymore. Any Ideas why? Do i need to change the Baudrate on another place as well?

Thanks, Stefan

stif commented 4 years ago

i took a look at the AVR307 Document in this document they suggest (in Table1) to use #define TIMER_PRESCALER 8 instead of #define TIMER_PRESCALER 1 for 19200 Baud. But unfortunately it does not start to work after this change..

cbalint13 commented 3 years ago

@stif,

I did not covered these details in the documentation, spend lots of time making errorless communication so i had to choose fixed nut stable baud-rate.

i took a look at the AVR307 Document in this document they suggest (in Table1) to use #define TIMER_PRESCALER 8 instead of #define TIMER_PRESCALER 1 for 19200 Baud. But unfortunately it does not start to work after this change..

I used `#define TIMER_PRESCALER 1 but also tweak the clock speed in accord, different from AVR307 example.

no-ahnu commented 7 months ago

Hello, can the baud rate of the main.c be changed to 9600? Unfortunately my electricity meter cannot support a higher baud rate.

I have it with: tinnymodbus/libs/usiuartx.h

/*
  * USI UART Defines
  */
//#define SYSTEM_CLOCK 14745600
//#define SYSTEM_CLOCK 11059200
//#define SYSTEM_CLOCK 8000000
//#define SYSTEM_CLOCK 7372800
//#define SYSTEM_CLOCK 3686400
//#define SYSTEM_CLOCK 2000000
//#define SYSTEM_CLOCK 1843200
#define SYSTEM_CLOCK 1000000

//#define BAUD RATE 115200
////#define BAUD RATE 57600
//#define BAUD RATE 38400
//#define BAUD RATE 28800
//#define BAUD RATE 19200
//#define BAUD RATE 14400
#define BAUD RATE 9600

#define TIMER_PRESCALER 1
//#define TIMER_PRESCALER 8

tried. Unfortunately I no longer get an answer: user@rtu:~/tinnymodbus-BME-1w-9600/tools$ sudo python3 examples/pymodbus3.x/sensors-read.py 0x03 0x0000

Traceback (most recent call last): File "/home/user/tinnymodbus-BME-1w-9600/tools/examples/pymodbus3.x/sensors-read.py", line 40, in decoder = BinaryPayloadDecoder.fromRegisters(result.registers, byteorder=Endian.Big, wordorder=Endian.Big) ^^^^^^^^^^^^^^^^ AttributeError: 'ModbusIOException' object has no attribute 'registers'

Thanks for your help

cbalint13 commented 7 months ago

@no-ahnu

9600 is very low for USI hw at 8MHz main clock with prescaler = 1, you also need to lower the SYSTEM_CLOCK to a lower internal oscilator frequency (via burn.sh appropriate fuse bits) or even better just simply adjust TIMER_PRESCALER to 8 (1, 8,16 are legit values).

Perhaps is not documented, 9600 is possible but need careful adjusment of this clocks and prescaler. If it works and need super fine tunning (with a precise scope and clock rference) there is also the TIMER0_SEED_COMPENSATION fine offset adjusment to compensate small drifts.

Rmember that attiny85 is a very low cost and scarce resource, it does not affort crystal oscillator and does not own a real UART, so the challenge is here to make it work. But this is the real fun part of this project :)

BTW, if your tinny is 57600 on the same wire with a 9600 device you still can communicate with booth at different speeds.

no-ahnu commented 7 months ago

Hello cbalint13 That sounds complicated... I just "broken" my working board, I probably set the wrong clock frequency. In any case, it can no longer be flashed with my programmer. And unfortunately my new board doesn't respond via Modbus. Flashing works, but there is no response via the boot mode info.

So I'm starting the days all over again. THANK YOU for the help so far.

cbalint13 commented 7 months ago

Hello cbalint13 That sounds complicated... I just "broken" my working board, I probably set the wrong clock frequency.

The good part is that attiny85 cannot be broke by setting frequency, original 8Mhz was already the highest. Fuses in burn process cannot harm, but to avoid them it is enough to set the prescaler and baud_rate in source code.

In any case, it can no longer be flashed with my programmer. And unfortunately my new board doesn't respond via Modbus. Flashing works, but there is no response via the boot mode info.

I am sorry to hear this, but there is always a way to bring back things, that is for sure, no matter what.

So I'm starting the days all over again. THANK YOU for the help so far.

You are welcome !

cbalint13 commented 7 months ago

@no-ahnu ,

I revised the very math of the issue:

The formula is: TIMER0_SEED = (256 - ( (SYSTEM_CLOCK / BAUDRATE) / TIMER_PRESCALER )) + TIMER0_SEED_COMPENSATION

With fixed 8MHz, any BAUDRATE can be achieved:

  1. With 38400 at 8Mhz and scaler=1: TIMER0_SEED = 256 - (8000000/38400/1) = 48
  2. With 9600 at 8Mhz and scaler=1: TIMER0_SEED = 256 - (8000000/9600/1) = -577 (!!)
  3. With 9600 at 8Mhz and scaler=8: TIMER0_SEED = 256 - (8000000/9600/8) = 151

The (2) is negative is not legit at all, but (3) with using a TIMER_PRESCALER=8 it becomes a legit timer value.

Commited now a compile time error message for non-legit cases to warn users: https://github.com/cbalint13/tinnymodbus/blob/master/libs/usiuartx.h#L105-L107

no-ahnu commented 7 months ago

Sometimes it helps to take a break, which is what I did now. my new board now responds to the bootmode-info.py with running mode 1 and software 0.02. But the remote flash stops at the first line.

I don't really understand the error now.

EDIT: I've currently only flashed the bootloader. If I now change the running mode to 0, it will “confirm” me. However, with a new query it is 1 again. Is that correct?

no-ahnu commented 7 months ago

I revised the very math of the issue:

The formula is: TIMER0_SEED = (256 - ( (SYSTEM_CLOCK / BAUDRATE) / TIMER_PRESCALER )) + TIMER0_SEED_COMPENSATION

With fixed 8MHz, any BAUDRATE can be achieved:

1. With 38400 at 8Mhz and scaler=1: TIMER0_SEED = 256 - (8000000/38400/1) = 48

2. With 9600 at 8Mhz and scaler=1: TIMER0_SEED = 256 - (8000000/9600/1) = -577 (!!)

3. With 9600 at 8Mhz and scaler=8: TIMER0_SEED = 256 - (8000000/9600/8) = 151

The (2) is negative is not legit at all, but (3) with using a TIMER_PRESCALER=8 it becomes a legit timer value.

Commited now a compile time error message for non-legit cases to warn users:

I almost overlooked this great post

If I understood correctly, for the baud rate of 9600 I need the TIMER_PRESCALER here change to 8 and the baud rate here to 9600 the system_clock always stays at 8mhz?

I'll try that out

cbalint13 commented 7 months ago

If I understood correctly, for the baud rate of 9600 I need the TIMER_PRESCALER here change to 8 and the baud rate here to 9600 the system_clock always stays at 8mhz?

Yes exactly.

I'll try that out

no-ahnu commented 7 months ago

Hello Cristian, I'm despairing again. If I have flashed the boot.hex and then run the remote-flash.sh, the transfer always stops at this point:

TX: 01 10 12 00 00 10 69 e0 70 e0 a6 d1 41 e0 50 e0 4c 0f 5d 1f 84 0f 95 1f dc 01 8c 91 80 31 09 f0 ab c0 ce 5b de 4f CRC [0x0f28] RX: 01 10 12 00 00 10 CRC [0xc4bd]

TX: 01 10 12 20 00 10 18 82 19 82 1a 82 1b 82 c2 54 d1 40 f8 94 c9 01 69 e0 70 e0 8e d1 01 96 aa 24 a3 94 b1 2c ac 0e CRC [0x70c5] RX: 01 10 12 20 00 10 CRC [0xc577]

TX: 01 10 12 40 00 10 bd 1e a8 0e b9 1e c3 d7 88 23 09 f4 62 c0 c5 01 06 d8 84 e4 f5 d7 99 d7 88 23 e9 f3 b8 d7 88 23 CRC [0xf7d9] ^C user@rtu:~/tinnymodbus/tools$

In make.sh I activated these DEVS_ENABLE="-DDS18B20 -DBME280" drivers, and I ran make.sh in Docker.

If I limit the drivers to DDS18B20, everything is transferred but the program cannot be switched to mainmode. The main mode switches report boot mode 0, but the boot mode info still reports boot mode 1

Do you have a tip for me here? I already suspected my Modbus <-> USB converter, but the new one doesn't work either.

cbalint13 commented 7 months ago

Hi @no-ahnu ,

TX: 01 10 12 40 00 10 bd 1e a8 0e b9 1e c3 d7 88 23 09 f4 62 c0 c5 01 06 d8 84 e4 f5 d7 99 d7 88 23 e9 f3 b8 d7 88 23 CRC [0xf7d9] ^C user@rtu:~/tinnymodbus/tools$

In make.sh I activated these DEVS_ENABLE="-DDS18B20 -DBME280" drivers, and I ran make.sh in Docker.

If I limit the drivers to DDS18B20, everything is transferred but the program cannot be switched to mainmode. The main mode switches report boot mode 0, but the boot mode info still reports boot mode 1

Do you have a tip for me here? I already suspected my Modbus <-> USB converter, but the new one doesn't work either.

Some facts about boot mode, and the attiny85 constraints:

Now,

Considering that the attiny85 have a internal RC that may drift (unless you calibrate using OSCCAL) on long trailing sequences (like firmware datagrams) there might be errors, thus it will hang on any/first error. Of course if you reduce the code size there are more chances to pass.

An attempt to add handshake to firmware transfer. e.g. respond back with a simple NAK (when CRC fail) and force host to resend that particular page/datagram may increase the bootloader codesize that is already at a limit of very few bytes left.

However it is not impossible to add a NAK back-response but care is needed on the code budget, for example a simple exception response like: https://github.com/cbalint13/tinnymodbus/blob/master/boot.c#L316 might be enough to signal host to retransmit the whole datagram with the payload.

In my experience a calibrated OSCCAL attiny85 expose no problems at 9600 firmware upgrade.

no-ahnu commented 7 months ago

Good morning cbalint13,

thank you for the detailed answer. I'm not the best programmer, but there is one in my family. I'll try to program a NAK back-response.

The explanation at least explains why I have different behavior with different boards (ATTiny85). This will definitely help others who have a similar problem.

I solved it quickly by reading the memory from the ATtinny85 that I was able to program. I then transferred this memory content to my “problem” µC.

EDIT: I have boot.c from line 368 (here) extended with the following code.

           else
           {
               send_modbus_exception( &modbus[32+0], 0x03 );
               break;
           }// end with valid crc

Good news, the program is still running. I can't yet judge whether this fixes my "error". So far he hasn't appeared again.

EDIT2: Unfortunately the change didn't work and it got stuck again. But I'm surprised that it gets stuck in the middle of the code: TX: 01 10 10 20 00 10 c6 5b de 4f 88 83 ca 54 d1 40 af d8 c6 5b de 4f 48 81 ca 54 d1 40 44 23 39 f0 81 11 3c c0 f4 01 CRC [0x1053] RX: 01 10 10 20 00 10 CRC [0xc4cf]

TX: 01 10 10 40 00 10 80 81 87 29 80 83 1f c0 d4 01 9c 91 88 23 31 f0 87 2d 80 95 98 23 d4 01 9c 93 15 c0 64 10 04 c0 CRC [0xf486] ^C

modbus-flash.cpp line 344

     printf(' CRC [0x');
     for ( int i = 38; i < 40; i++ )
     {
       printf( '%02x', msg[i] );
     }
     printf(']');
     // small buffer
     unsigned char buf[40];
     // read header
     printf("\nRX:");
     for ( int i = 0; i < 6; i++ )
     {
       read( fd, &buf[i], 0x1 );
       printf( " %02x", buf[i] );
     }

The 'CRC[..]' is still output with print, the RX is no longer output. Therefore it should be "unsigned char buf[40];" hang right? I would have expected an RX 0x1 0x3 0x....

EDIT END

Now I can start my experiments with the 9600 baud rate.

Thank you for your help!

For others with the problem, attached the memory. Enabled drivers: DEVS_ENABLE="-DDS18B20 -DBME280" ATtinny85-Memory.zip

no-ahnu commented 7 months ago

Hello, I have the usiuart.h

adjusted like this:

/*
  * USI UART Defines
  */
//#define SYSTEM_CLOCK 14745600
//#define SYSTEM_CLOCK 11059200
#define SYSTEM_CLOCK 8000000
//#define SYSTEM_CLOCK 7372800
//#define SYSTEM_CLOCK 3686400
//#define SYSTEM_CLOCK 2000000
//#define SYSTEM_CLOCK 1843200
//#define SYSTEM_CLOCK 1000000

//#define BAUD RATE 115200
////#define BAUD RATE 57600
//#define BAUD RATE 38400
//#define BAUD RATE 28800
//#define BAUD RATE 19200
//#define BAUD RATE 14400
#define BAUD RATE 9600

//#define TIMER_PRESCALER 1
#define TIMER_PRESCALER 8

and re-flashed the main.hex. Unfortunately, retrieval is still only possible over 38400 baud. :'(

no-ahnu commented 7 months ago

Good morning, can the ATtiny85 be replaced with an ATtiny84A without any problems? This has more inputs, so you could equip the µC with a crystal oscillator. If I understood OSCCAL correctly, such a calibration would no longer be necessary. Since I want to use the BME280 as a weather station, I have to make do with a large temperature difference between summer and winter. That would make the internal RC even less accurate.

Thanks in advance for the feedback.

cbalint13 commented 7 months ago

Good morning, can the ATtiny85 be replaced with an ATtiny84A without any problems? This has more inputs, so you could equip the µC with a crystal oscillator.

Should work, personally I have never tried it.

If I understood OSCCAL correctly, such a calibration would no longer be necessary.

Calibrated OSCAL or XTAL may make sense if you do transfers with large trailing data payload like the firmware. This project as its very name says (apparently misspelled but it's not) is about doing telemetry in/with scarce resources.

Since I want to use the BME280 as a weather station, I have to make do with a large temperature difference between summer and winter. That would make the internal RC even less accurate.

Using this project's promoted PCB layout (voltage regulator, noise filter caps on power rails) and it's wiring sockets:

These days there are cheaper mcu options like the 0.10$ USD: https://www.wch-ic.com/products/CH32V003.html , but that would require porting the project to it.

cbalint13 commented 7 months ago

@no-ahnu ,

One more note I would drop here:

If you use your custom modules (mixture of boards), you also keep considering to add filter caps, ideally two on same place: 100nF and 1uF (for the low and high freq noise components) on power rails. On the Vss input of attiny, on the Vss input of your rs485 transceiver and on the very output Vss that goes to sensors or right where the sensors are.

This is very important for noise and stability, it make huge difference. This project here deploys two a 0.47uF one at input, and one placed at very output power rail (the most important), and the PCB size holds quite small wires with very low chance of interference.

no-ahnu commented 7 months ago

Thanks for the further insightful explanations!

I'm still undecided what to do, calibrate or replace the µC. Two more questions:

If I carry out an OSCAL calibration, I have to write it into the OSCCAL memory every time I start. I haven't figured out how yet.

And when I switched to the 84A, I couldn't find where the pins were defined in the code. If I researched correctly, the external clock must be on pin "XTAL1", which is already assigned to "PB3" on the ATtiny85. I think the code needs to be adjusted here.

Another question about my "main problem", communication in main mode and the baud rate 9600. Unfortunately, the µC does not respond to a request with 9600 baud. This also depends on the internal RC. Osc. together?

cbalint13 commented 7 months ago

Thanks for the further insightful explanations!

I'm still undecided what to do, calibrate or replace the µC. Two more questions:

If I carry out an OSCAL calibration, I have to write it into the OSCCAL memory every time I start. I haven't figured out how yet.

You can simply add a line in C to write the value to the register, in main(). Something like OSCCAL = 0xYY; would work as very first line of main(), in booth boot.c and main.c

And when I switched to the 84A, I couldn't find where the pins were defined in the code. If I researched correctly, the external clock must be on pin "XTAL1", which is already assigned to "PB3" on the ATtiny85. I think the code needs to be adjusted here.

You have to reassign that pin, yes. This means to replace all PB3 occurences with another PBX which is free on 84A.

Another question about my "main problem", communication in main mode and the baud rate 9600. Unfortunately, the µC does not respond to a request with 9600 baud. This also depends on the internal RC. Osc. together?

It is weird it should respond, worst case with errors in communication, the RC drift should be not as much to disable the communication. The drift would affect error rate rather than the whole comm.

Other speeds like 19200 works ? I always use that 38400 default, even if on the same wire there are other devices with other speed. There is also the COMPENSATION (already tuned to a sweet point) to fine tune the length of serial comm clock pulse: https://github.com/cbalint13/tinnymodbus/blob/345a1c6cbfe78ed804feca9e3dadedc4f9c794ff/libs/usiuartx.h#L102

To find out the 9600 issue the best is to look at it with a digital scope (these days are very affordable ones for few dollars of budget, you can use them with the opensource pulseview/sigrok, and of course in other projects or issues as well), then you can even fine tune (without the tedious osccal) only that COMPENSATION parameter. Unfortunatley given this RC scenario and the fact USI is not a full real UART this is the price of switching baud rates on this very tiny device.

In this document page 5, there is a table with possible speeds and what it imolies on this USI module: http://www.professordan.com/avr/techlib/techlib8/appnotes/pdf_avr/AVR307.pdf

9600 is present, either at 1mhz clock or easyer with 8mhz but prescaler=8. If I remember something like 2400 was not possible in any ways, 9600 was lowest in my tests, and I remained settle to the 38400 (a value not even in the atmel pdf).

no-ahnu commented 7 months ago

Good morning cbalint13, First of all, THANK YOU for your patience with me. You take me, as an absolute beginner when it comes to microcontrollers, to answer my many questions. Thanks for that!

I googled OSCCAL again and found this project https://github.com/pepaslabs/CalibrateATtiny85OSCCAL. I ordered the USB <-> TTL adapters and a cheap digital scope today.

When the parts arrive, I'll try to calibrate my ATtiny85.

I don't think I need to start trying for baud 9600 beforehand.

no-ahnu commented 7 months ago

Hello, I finally got the parts and found the time to continue working with OSCCAL.

I “calibrated” my OSCCAL as described in “CalibrateATtiny85OSCCAL”, the TX and RX signals are now both the same length.

So in the boot.c on line 99 and in the main.c line 142 I added this "OSCCAL = 0x9C; " Unfortunately the remode-flash.sh still breaks after a while, I'm at a loss.

RX TX

no-ahnu commented 7 months ago

Hello, I googled the topic of OSCCAL again and came across the FUSE bit6 "CKOUT". This makes checking the OSCCAL even easier :). So I quickly soldered together a new board... and tried it out.

OSCCAL140

Unfortunately I still have crashes when transferring the main.hex. I guess I can't get around it by adapting the "modbus-flash.cpp".

EDIT: here i programm for OSCCAL with FUSE bit 6

#include <avr/io.h>

int main(void)
{
    /* Replace with your application code */
    while (1) 
    {
        OSCCAL = 140;
    }
}

This is my question again that I asked here. https://github.com/cbalint13/tinnymodbus/issues/8#issuecomment-1897922196

no-ahnu commented 7 months ago

Hello, I got the baud rate 9600 to work. It doesn't matter which baud rate I set with "TIMER_PRESCALER 8", after that the communication no longer works. So I left the "TIMER_PRESCALER" at 1 and activated the FUSE bit "LOX.CKDIV8". After that the baud rate 9600 works. I also changed the "SYSTEM_CLOCK" to 1000000 in the "usiuartx.h".

Thanks for the help!