The story of the borrowing process in the development of electronics on a good example.
Logging the elevator work with homemade sniffer
Once I needed to copy a fairly simple device. The manufacturing company has ceased to exist, but throughout the country there was still a demand for the replacement of broken or exhausted devices.
The device itself is the elevator call button in the photo on the left. For the experiments I was given two copies, one of which could be completely disassembled.
The overall work plan looked like this:
With the failure of paragraph 4, the further plan would have been more difficult, but I was lucky.
Main microcontroller
A piece of elevator wiring diagram on which our boards are circled in red
The board is assembled on a microcontroller of 1997 release AT89C2051 , which is based on the architecture of Intel MCS-51 . In 2020, she celebrates her 40th anniversary in the embedded market.
A small explanation: the microcontroller is such a chip containing a computational core and a set of peripherals to control external devices. For example, in a modern washing machine, the microcontroller polls control buttons, sensors, displays information on the screen, and controls the pumps, heater, valves, and drum drive. For most of the listed functions, it does not require intermediate devices, only a set of passive electronic components.
We disassemble the board for drawing the electrical circuit
Drawing the original circuit board in the future will help you find out the pin assignment of the microcontroller, which is necessary to parse the firmware code.
The original device was developed by a Chinese company, and therefore its scheme is extremely complicated and with a lot of unnecessary components. For example, the relay was turned on through a triple cascade of a bipolar transistor, an optocoupler and a field device (in that order).
An acquaintance working with Chinese manufactures told me that the Chinese are engaged in a similar complication of schemes to increase the cost of development and production, if both are made by some people. After this, I tend to believe him:
The same place on the Chinese dual layer board on both sides. Three huge resistors are not connected to anything. I even shined the board with a powerful flashlight to be sure.
The scheme is copied, mysterious places are modeled in multisyme , we take up the firmware.
I was very lucky that the read protection was not enabled on both the controllers in the controllers, so I successfully merged two versions of the firmware with similar pornography:
Photo from the personal blog of the American enthusiast
In the next step, we need to convert this machine code to something more readable:
Take the well-known tool IDA Pro , which already has our controller with all the registers of the periphery, and open the HEX firmware file:
Processing accepted by the card data in assembly language
After that, there is a rather tedious process of studying the instruction set of our computational core, commenting and decoding assembly code.
At the addresses of the interrupt vector table, interrupt handlers themselves were found, writing to the peripheral registers gave information about the configuration of the communication interface. Step by step, the unnamed assembly code has become something that can be read.
Since I needed to develop a new device on a different element base, it was necessary to extract an algorithm from the code. Some time later, this pseudocode was born:
void UartISR (void) { counter500ms = 0; //ClearFlag(isrFlags, ISR_FLAG_3); ProcessUart(recievedByte); } void ProcessUart(uint8_t recievedData) { static uint8_t uartPacketsToRxLeft, uartRecievedCmd, uartCurrPacketCRC; static uint8_t i, carryFlag; static uint16_t uartIsrPointer; static uint8_t uartBuffer1[8], uartBuffer2[6]; static uint8_t uartBuffer1Pos, uartBuffer2Pos; // 0 - // 1 - // 2 - // 3 - led state, 0x0F // 4 - // 5 - // 6 - // 7 - // 8 - buttons time static uint8_t dataRegisters[9]; // RAM:0050 uint8_t tmpVal, i; uint8_t dataToSend; if (GetFlag(UartISRFlags, UART_RECIEVED_FLAG)) { ClearFlag(UartISRFlags, UART_RECIEVED_FLAG); if (recieved9thBit) { switch (recievedData) { case 0xC1: uartPacketsToRxLeft = 8; uartRecievedCmd = 1; uartBuffer1Pos = 0; uartBuffer1[uartBuffer1Pos] = recievedData; //uartIsrPointer = 0x0037; //tmpVal_0037 = recievedData; uartCurrPacketCRC = recievedData; UartRxOn(); return; break; case 0xC2: uartPacketsToRxLeft = 3; uartRecievedCmd = 2;
The same processing of received data in the C language
Who is interested in the transfer protocol:
The elevator control station communicated with the call button boards over a full-duplex 24-volt interface. In normal mode, the button boards listened to the line, waiting for a 9-bit data packet. If in this packet the address of our board arrived (set by a DIP switch on the board), the board switched to 8-bit receive mode, and all subsequent packets were hardware ignored by the other boards.
The first after the address was a packet with the control command code. Specifically, this board took only 3 teams:
- Write to data registers. For example, the frequency and duration of the flashing button when called;
- Turn on the button illumination;
- Request the status of the buttons (pressed or not).
The last byte was the checksum, which is a simple XOR of all bytes after the address.
After the checksum, the fee again went into standby for its address.
For the development phase of the new circuitry and the PCB, I have no pictures, but it was like this:
Wiring and wiring board made in Altium Designer . The manufacture of a printed circuit board was ordered in Zelenograd Rezonite .
While our new board is in production, we are going to the facility where these call buttons are installed, and check the correctness of the disassembled transmission protocol using the sniffer assembled on the arduin:
A piece of transmitter circuit that is electrically equivalent to the original. The receiver is just an optocoupler.
//UART1 initialize // desired baud rate:19200 // actual baud rate:19231 (0,2%) // char size: 9 bit // parity: Disabled void uart1_init(void) { UCSR1B = 0x00; //disable while setting baud rate UCSR1A = 0x00; UCSR1C = 0x06; UBRR1L = 0x33; //set baud rate lo UBRR1H = 0x00; //set baud rate hi UCSR1B = 0x94; } #pragma interrupt_handler uart1_rx_isr:iv_USART1_RXC void uart1_rx_isr(void) { unsigned char tmp; unsigned int rcv = 0; if (UCSR1B & 0x02) { rcv = 0x100; } rcv |= UDR1; tmp = (rcv >> 4) & 0x0F; if (rcv & 0x100) { tmp |= 0xC0; } else { tmp |= 0x80; } txBuf12 = (rcv & 0x0F); txBuf11 = tmp; txState1 = 0; TX_ON(); msCounter0 = 5000; }
Gosnokodim in ICC AVR our sniffer
Then it was necessary to act very carefully so as not to burn anything in the elevator and prevent it from stopping.
We climb into the call button. Thick yellow wires - board power and transmission interface. White on the 4-pin connector - connect the button and its backlight.
We check that everything works as it should, fix the jambs and write a new firmware for our device:
//ICC-AVR application builder : 11.02.2015 12:25:51 // Target : M328p // Crystal: 16.000Mhz #include <macros.h> #include <iccioavr.h> #include <avrdef.h> #include "types.h" #include "gpio.h" #define TX_OFF() UCSR0B &= 0b11011111; #define TX_ON() UCSR0B |= 0b00100000; #define TX_STATE() (UCSR0B & 0b00100000) #define MAX_TIMEOUT 3000 //#define SNIFFER_MODE 1 //#define MASTER_MODE 1 // #pragma avr_fuse (fuses0, fuses1, fuses2, fuses3, fuses4, fuses5) #pragma avr_fuse (0xFF, 0xD1, 0xFC) #pragma avr_lockbits (0xFC) // AVR signature is always three bytes. Signature0 is always the Atmel // manufacturer code of 0x1E. The other two bytes are device dependent. #pragma avr_signature (0x1E, 0x95, 0x0F) // atmega32 static GPIOx errorLed, rcvLed, butUp, butDn, ledUp, ledDn, butLedUp, butLedDn, ledButUp, ledButDn; static uint8_t msFlag = 0; static uint8_t ledState = 0, buttonsState = 0; static uint16_t rcvLedLitTime = 0, butMaskCalcTime = 0, timeoutTimer = 0; typedef struct { uint16_t buffer[10]; uint8_t dataLength; } UartPacket; static UartPacket txPacket, rxPacket; #ifdef SNIFFER_MODE static uint8_t txBuffer[64], txBufferLength = 0, bufferMutex = 0; #endif static uint8_t GetPacketCRC(UartPacket* packet); static void SendLedState(void); uint8_t GetAddress(void) { return (PINC & 0x3F); }
C code for the new board based on the AVR ATmega328P microcontroller
The simplicity of the device and firmware can be estimated by the amount of code, it contains only about 600 lines in the C language.
The build process looked like this:
The fee is different, but the principle is the same.
I can not attach the photo of the finished device, just believe that it is still being made and sold.
About the elevator buttons "up" and "down" on the floor. I noticed that many people completely misunderstand their purpose and press both at once.
The elevator has two sets of buttons: in the cab there is an order bar, and on the floor, a call bar. Already by name, you can guess that the orders panel has a higher management priority.
All elevators that have call panels with up and down buttons work with some of the variants of the travel optimization algorithm, the purpose of which is to transport the maximum number of passengers in minimum time and a separate condition for maximum waiting time on the floor (regulated by the state standard).
Such an algorithm usually involves the selection of passengers on the floors, if they are traveling in the same direction, which is indicated by pressing the call button "up" or "down."
Imagine a situation that an elevator with passengers goes down and on the way receives a call “down” from the floor below. The elevator will stop for the selection of a passenger (yes, there is still accounting for the loading of the cabin on the weighing sensor, but we will lower it).
The elevator goes further and receives a “upward” call from the floor below. It is logical that the elevator will not stop for the selection of a passenger, as it will not change the direction of travel (this is also regulated by the standard), and picking up a passenger to go down and then up is useless energy consumption and space in the elevator.
The elevator goes further and receives two calls up and down at once from the floor below, which were pressed by some impatient passenger who needs to go up. It is logical that the elevator will stop on this floor, but the passenger will not enter it, but will spend time in the cabin for people to slow down and stop the elevator, open the doors, wait, close the doors and accelerate to the rated speed.
If the elevator has only one button on the floor, then in 99% of cases it works according to the “collective down” algorithm, and if there are orders in the cabin it stops only when it moves down.
If you have programming skills in JS, you can try to implement a similar control algorithm in the online game Elevator Saga . It has all aspects of optimizing travel without deepening in hardcore like the work of elevator safety chains.
In my telegram channel, I post similar materials. Right now there you can follow the development of the next device.
Source: https://habr.com/ru/post/459492/
All Articles