Can I connect directly ESP32 Modbus output from UART pins to TTL-USB converter? - c

I am creating a slave device for a Modbus network. This is my first encounter with this protocol, so I am not really sure about few things.
So, this a recommended schematic for a proper Modbus RTU connection using RS-485.
+---------+ +----x------+ +-----x-----+
| RX |<---------|RO | | RO|--> RXD
| ESP32 | | B|------|B |
| TX |--------->|DI MAX485 | \ / | MAX485 DI|<-- TXD
| | | |RS-485| | MODBUS MASTER
+---------+ RTS -+->|DE | / \ | DE|--+
| | A|------|A | |
+--|/RE | | /RE|--+- RTS
+----x------+ +-----x-----+
I currently don't have any RS-485 converters on my hand and I am trying to test my modbus implementation using setup like this:
+---------+ +---------+ +---------+
| RX |<------| TX | | |
| ESP32 | | TTL-USB |<=====>| PC |
| | | | USB | |
| TX |------>| RX | | |
+---------+ +---------+ +---------+
Does it have any right to work like this? Those 2 RS-485 converters should have no impact or am I missing something? How important is RTS in this type of serial transmission?
If that setup is ok, then I have no idea why I can't communicate with my ESP32 slave device. This is code that I am running currently (removed unnecessary parts for simplicity).
Defines:
#define MB_PORT_NUM UART_NUM_1
#define MB_SLAVE_ADDR (2)
#define MB_DEV_SPEED (9600)
#define UART_TXD_GPIO_NUM 19
#define UART_RXD_GPIO_NUM 18
Content of a task responsible for communicating with modbus master. Almost identical to: https://github.com/espressif/esp-idf/tree/release/v4.4/examples/protocols/modbus/serial/mb_slave
mb_param_info_t reg_info; // keeps the Modbus registers access information
void *mbc_slave_handler = NULL;
ESP_ERROR_CHECK(mbc_slave_init(MB_PORT_SERIAL_SLAVE, &mbc_slave_handler)); // Initialization of Modbus controller
mb_communication_info_t comm_info;
comm_info.mode = MB_MODE_RTU;
comm_info.slave_addr = MB_SLAVE_ADDR;
comm_info.port = MB_PORT_NUM;
comm_info.baudrate = MB_DEV_SPEED;
comm_info.parity = MB_PARITY_NONE;
ESP_ERROR_CHECK(mbc_slave_setup((void *)&comm_info));
mb_register_area_descriptor_t reg_area; // Modbus register area descriptor structure
reg_area.type = MB_PARAM_INPUT;
reg_area.start_offset = 0;
/* there is a struct defined somewhere else */
reg_area.address = (void *)&input_reg_params.temp_r1;
reg_area.size = sizeof(uint16_t);
ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
ESP_ERROR_CHECK(mbc_slave_start());
// RTC and CRC pins are unconnected
ESP_ERROR_CHECK(uart_set_pin(MB_PORT_NUM, UART_TXD_GPIO_NUM, UART_RXD_GPIO_NUM, -1, -1));
// Changed UART_MODE from RS485_DUPLEX, to UART_MODE_UART
ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_UART));
while (true) {
mb_event_group_t event = mbc_slave_check_event((mb_event_group_t)MB_READ_WRITE_MASK);
/* I never get past this point. Stuck at check_event*/
}
In order to test it I am using mbpoll program on Linux (https://github.com/epsilonrt/mbpoll).
Command (meaning of parameters: slave adress=2, read input, offset=0, baudrate=9600, no parity):
mbpoll -a 2 -t 3 -r 0 -0 -b 9600 -P none /dev/ttyUSB0
When I run it I get 'Connection timed out' error, but I don't see any debug info on my ESP32 about incoming transmission. /dev/ttyUSB0 is a correct device, when I 'cat' this file I see something happening on UART.

Related

SAMA5d31:The Uboot cannot be started

I currently use a custom board based on SAMa5D31:
Emmc is currently used for boot
The Uboot fails to be started
Stuck in SD/MMC: Done to load image without any reaction
Modify the following
diff --git a/board/sama5d3xek/sama5d3xek.c b/board/sama5d3xek/sama5d3xek.c
index 57093b58..153749ce 100644
--- a/board/sama5d3xek/sama5d3xek.c
+++ b/board/sama5d3xek/sama5d3xek.c
## -75,12 +75,12 ## static void ddramc_reg_config(struct ddramc_register *ddramc_config)
| AT91C_DDRC2_MD_DDR2_SDRAM);
ddramc_config->cr = (AT91C_DDRC2_NC_DDR10_SDR9
- | AT91C_DDRC2_NR_14
+ | AT91C_DDRC2_NR_13
| AT91C_DDRC2_CAS_3
| AT91C_DDRC2_DISABLE_RESET_DLL
| AT91C_DDRC2_ENABLE_DLL
| AT91C_DDRC2_ENRDM_ENABLE /* Phase error correction is enabled */
- | AT91C_DDRC2_NB_BANKS_8
+ | AT91C_DDRC2_NB_BANKS_4
| AT91C_DDRC2_NDQS_DISABLED /* NDQS disabled (check on schematics) */
| AT91C_DDRC2_DECOD_INTERLEAVED /* Interleaved decoding */
| AT91C_DDRC2_UNAL_SUPPORTED); /* Unaligned access is supported */

memory map adress to function call

TLDR:
Is it possible to map an adresspace to a function call in a kernel module?
So similar to mmap. But mmap is for userspace and will only call the functions if you access the next page.
+---+---+---+---+--------------------+
| | | | | |
+-------+---+---+--------------------+
|
+-------------------------------------------------+
|
+---------------------v----------------+
| void my_driver_function(int offset); |
+--------------------------------------+
EDIT:
here the Long Story
Old world
In our old world we had N Devices that where controlled by N independent device drivers. Each registers of each device where memory mapped at a location. And every driver just ioremaped the registers and controlled the hardware directly.
+----------------+ +--------------+ +------------+ +--------------+
| Driver A | | Driver B | | Driver C | | Driver E |
+----------------+ +--------------+ +------------+ +--------------+
|ioremap |ioremap |ioremap |ioremap
| | | |
+----+-----------+ +--------------+ +------------+ +--------------+
| Device A | | Device B | | Device C | | Device E |
| | | | | | | |
+----------------+ +--------------+ +------------+ +--------------+
New World
In our new world we merged the device hardware. But the drivers are still separate. Due to hardware limitations, it is now necessary to mutex all access to the one new device. Also there are now some more constraints that where not there in the old world (alignment, byteorder, timing, ...). But because the drivers are independent they do not know about code or access happening in another driver. So it leads to violations of this constraints.
+----------------+ +--------------+ +------------+ +--------------+
| Driver A | | Driver B | | Driver C | | Driver E |
+----------------+ +--------------+ +------------+ +--------------+
|ioremap |ioremap |ioremap |ioremap
| | | |
+----+----------------------------------------+-----------------+---------+
| Device A/B/C/D/E |
| |
+-------------------------------------------------------------------------+
the idea
because we do not want to rework all the drivers. go through all the code and seek for every pointer that my be pointing to a hardware register to guard all this accesses by mutexes, my idea was to add a virtual device memory. This should be a memory area there each access will be routed to a function. This function will then perform locking and tracking and things and access to the hardware.
+----------------+ +--------------+ +------------+ +--------------+
| Driver A | | Driver B | | Driver C | | Driver E |
+----------------+ +--------------+ +------------+ +--------------+
|ioremap |ioremap |ioremap |ioremap
| | | |
+----+----------------------------------------+-----------------+---------+
| Virtual Device A/B/C/D/E |
| |
+----------------------+--------------------------------------------------+
|
|my_mapper_function(...)
| /* do (un)locking, check constraints, ... */
|
+----------------------+--------------------------------------------------+
| Device A/B/C/D/E |
| |
+-------------------------------------------------------------------------+
the question
is there a mechanism in the linux kernel, that allows to map every access to a specific memory region to be routed trough a function? Similar to what mmap does, but actually quite different because you cannot hook every arbitrary function to mmap. Also it will not route every request through this function but only if a request crosses a page border.
I am thinking of moving Driver A/B/C... to UserSpace using UIO, and all these driver using same kernel space code which used to control all related devices.
User Space | Driver A | Driver B | Driver C |
|================================|
Kernel Space | KObject ABC |
|================================|
Hardware | Device A|B|C |

Struggling to understand channel selection using the ADC on a PIC microcontroller?

I'm trying to write a program that for a PIC18F252 microcontroller to use the ADC to convert 3 analogue signals (on 3 separate pins) into digital signals for use at the output of the program. The guide I've been using to help me understand the ADC has been helpful, but I'm struggling with the part where they put it all together. Here's the code:
unsigned int ADC_Read(unsigned char channel)
{
ADCON0 &= 0x11000101; //Clearing the Channel Selection Bits
ADCON0 |= channel<<3; //Setting the required Bits
__delay_ms(2); //Acquisition time to charge hold capacitor
GO_nDONE = 1; //Initializes A/D Conversion
while(GO_nDONE); //Wait for A/D Conversion to complete
return ((ADRESH<<8)+ADRESL); //Returns Result
}
Then you can call the function and assign it to a variable using this:
i = (ADC_Read(4)); //store the result of adc in ā€œiā€
My problem is that I'm struggling to understand the bitshifting part of the code. I get why and how it clears the channel selection bits, but my struggle is understanding how 'channel<<3', when channel=4 in this example, can create a binary value that can be OR'd with the ADCON0 value.
Is anyone able to explain what the value of channel is after the code has run, if it starts as 4, and also what the new configuration of ADCON0 would be after the OR line?
I understand each line individually I'm just struggling to get how they piece together because this has to be done 3 times, selecting a different channel each time, and at the moment I can't tell what channel this is setting.
The other answers provide the layout of the registers. This answer illustrates the process of changing the desired bits.
First, we clear the channel bits (and the unimplemented bit 1).
7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+
| a | b | c | d | e | f | g | h | Initial state
+---+---+---+---+---+---+---+---+
+---+---+---+---+---+---+---+---+ (The OP incorrectly
& | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | used 0x11000101
+---+---+---+---+---+---+---+---+ instead of 0b11000101.)
+---+---+---+---+---+---+---+---+
= | a | b | 0 | 0 | 0 | f | 0 | h |
+---+---+---+---+---+---+---+---+
Next, we need to slide the channel into bits 5-3.
+---+---+---+---+---+---+---+---+
|(0)|(0)|(0)|(0)|(0)| 1 | 0 | 0 | 4 (Channel in bits 2-0)
+---+---+---+---+---+---+---+---+
+---+---+---+---+---+---+---+---+
<< 3 |(0)|(0)| 1 | 0 | 0 |(0)|(0)|(0)| (Channel in bits 5-3)
+---+---+---+---+---+---+---+---+
Now, we can OR it in.
+---+---+---+---+---+---+---+---+
| a | b | 0 | 0 | 0 | f | 0 | h |
+---+---+---+---+---+---+---+---+
+---+---+---+---+---+---+---+---+
| |(0)|(0)| 1 | 0 | 0 |(0)|(0)|(0)|
+---+---+---+---+---+---+---+---+
+---+---+---+---+---+---+---+---+
= | a | b | 1 | 0 | 0 | f | 0 | h |
+---+---+---+---+---+---+---+---+
I used (0) to denote a zero bit that doesn't carry data.
If you refer to the DataSheet for PIC18F252 Section 17.0
The definition of the ADCON0 is given. Here bits 3,4,5 are the channel selection bits.
The code
ADCON0 &= 0x11000101; //Clearing the Channel Selection Bits
ADCON0 |= channel<<3; //Setting the required Bits
will set the channels from 0 to 7 as per the function parameter.
Refer image here
The ADCON0 register looks like this
bit 7-6 A/D Conversion Clock Select bits (ADCON0 bits in bold)
bit 5-3 Analog Channel Select bits
bit 2 GO/DONE
bit 1 Unimplemented
bit 0 ADON
So as you can see bit 5-3 serves as the channel select. bit 5-3 are treated as a 3-bit value, so if you wanna select channel 4 which is 100 in binary you would shift the number 4(100), 3 steps to left to place it in channel select bits.

Why 'Lost connection to MySQL server during query' errors occur time-to-time (timeouts raised, pinging before query)

I'm creating an experiment, in which the server side is a libuv based C/C++ application that runs queries on a mysql server (it's on localhost).
In most cases it just works, but sometimes I get 'Lost connection to MySQL server during query' in various places in the process.
I have tried raising all timeouts. But I think this is unrelated, if the server gets bombarded with requests (like every second) the same error gets thrown.
+-------------------------------------+----------+
| Variable_name | Value |
+-------------------------------------+----------+
| connect_timeout | 31536000 |
| deadlock_timeout_long | 50000000 |
| deadlock_timeout_short | 10000 |
| delayed_insert_timeout | 300 |
| innodb_flush_log_at_timeout | 1 |
| innodb_lock_wait_timeout | 50 |
| innodb_print_lock_wait_timeout_info | OFF |
| innodb_rollback_on_timeout | OFF |
| interactive_timeout | 31536000 |
| lock_wait_timeout | 31536000 |
| net_read_timeout | 31536000 |
| net_write_timeout | 31536000 |
| slave_net_timeout | 31536000 |
| thread_pool_idle_timeout | 60 |
| wait_timeout | 31536000 |
+-------------------------------------+----------+
I'm pinging the server before doing queries.
// this->con was set up somewhere before, just like down below in the retry section
char query[] = "SELECT * FROM data WHERE id = 12;";
mysql_ping(this->con);
if(!mysql_query(this->con, query)) {
// OK
return 0;
} else {
// reconnect usually helps
// here I get the error message
mysql_close(this->con);
this->con = mysql_init(NULL);
if(mysql_real_connect(this->con, this->host.c_str(), this->user.c_str(), this->password.c_str(), this->db.c_str(), 0, NULL, 0) == NULL) {
// no DB, goodbye
exit(6);
}
// retry
if(!mysql_query(this->con, query)) {
return 0;
} else {
// DB fail
return 1;
}
}
I have tried the reconnect option, the problem is the same.
In my understanding this flow should be possible with single-threaded libuv and mysql:
1. set up db connection
2. run event loop
-> make queries based on IO events, get results
3. event loop ends
4. db close
What do I miss?

How to set up stunserver and turnserver in icedemo?

I am using pjsip project 2.3.and I want to use ice to imp my p2p.
so i compiled icedemo.c.and the cmdline is "-s stunserver.org".
but when i run the demo,i found it can not work well.
the dump info like this:
11:46:45.343 os_core_win32. pjlib 1.4 for win32 initialized
11:46:45.359 pjlib select() I/O Queue created (00A338E4)
+----------------------------------------------------------------------+
| M E N U |
+---+------------------------------------------------------------------+
| c | create Create the instance |
| d | destroy Destroy the instance |
| i | init o|a Initialize ICE session as offerer or answerer |
| e | stop End/stop ICE session |
| s | show Display local ICE info |
| r | remote Input remote ICE info |
| b | start Begin ICE negotiation |
| x | send <compid> .. Send data to remote |
+---+------------------------------------------------------------------+
| h | help * Help! * |
| q | quit Quit |
+----------------------------------------------------------------------+
Input: c
11:46:49.703 icedemo Creating ICE stream transport with 1 component(s)
11:46:49.734 icedemo Comp 1: srflx candidate starts Binding discovery
11:46:50.000 stuntp00A34390 TX 36 bytes STUN message to 132.177.123.13:3478:
--- begin STUN message ---
STUN Binding request
Hdr: length=16, magic=2112a442, tsx_id=6784482372ae3d6c00015f90
Attributes:
SOFTWARE: length=10, value="pjnath-1.4"
--- end of STUN message ---
11:46:50.000 stuntsx00A3BCF STUN client transaction created
11:46:50.000 stuntsx00A3BCF STUN sending message (transmit count=1)
11:46:50.015 icedemo Comp 1: host candidate 192.168.2.146:7033 added
11:46:50.015 icedemo ICE stream transport created
11:46:50.015 icedemo.c ICE instance successfully created
+----------------------------------------------------------------------+
| M E N U |
+---+------------------------------------------------------------------+
| c | create Create the instance |
| d | destroy Destroy the instance |
| i | init o|a Initialize ICE session as offerer or answerer |
| e | stop End/stop ICE session |
| s | show Display local ICE info |
| r | remote Input remote ICE info |
| b | start Begin ICE negotiation |
| x | send <compid> .. Send data to remote |
+---+------------------------------------------------------------------+
| h | help * Help! * |
| q | quit Quit |
+----------------------------------------------------------------------+
Input: 11:46:50.359 stuntsx00A3BCF STUN sending message (transmit count=2)
11:46:50.562 stuntsx00A3BCF STUN sending message (transmit count=3)
11:46:50.968 stuntsx00A3BCF STUN sending message (transmit count=4)
11:46:51.781 stuntsx00A3BCF STUN sending message (transmit count=5)
11:46:53.390 stuntsx00A3BCF STUN sending message (transmit count=6)
11:46:56.593 stuntsx00A3BCF STUN sending message (transmit count=7)
11:46:58.203 stuntsx00A3BCF STUN timeout waiting for response
11:46:58.203 stuntp00A34390 Session failed because STUN Binding request failed
: STUN transaction has timed out (PJNATH_ESTUNTIMEDOUT)
11:46:58.203 icedemo STUN binding request failed: STUN transaction has
timed out (PJNATH_ESTUNTIMEDOUT)
11:46:58.203 icedemo.c ICE initialization failed: STUN transaction has ti
med out (PJNATH_ESTUNTIMEDOUT)
11:47:00.203 stuntsx00A3BCF STUN client transaction destroyed
I have been having similar issues with my PjSIP based application. Something seems to be wrong with the STUN server at stunserver.org. It keeps going down from time to time.
Try using one of the STUN servers provided by google. I found them to be pretty reliable.
stun.l.google.com:19302
stun1.l.google.com:19302
stun2.l.google.com:19302
stun3.l.google.com:19302
stun4.l.google.com:19302

Resources