DIY-Multiprotocol-TX-Module
DIY-Multiprotocol-TX-Module copied to clipboard
Support for HotRC / Rlaarlo receivers
Discussed in https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/discussions/1072
Originally posted by c0ldtech February 11, 2025 It would be nice to have support for the HotRC receivers (which are also being used by Rlaarlo it seems). I'd be more than willing to order a receiver and have it sent to someone if it helps.
@c0ldtech I'll update my findings here
I am willing to provide funds for the purchase of a test Tx-Rx. :) PayPal?
I am willing to provide funds for the purchase of a test Tx-Rx. :) PayPal? Hi Guys I have a selection of HoRc Tx and Rx, I'm happy to test, wreck etc. I have pulled apart a DS-4A and stared a bit of reverse engineering. (I might need some guidance capturing signals off air with my SDR or JTAG dump of the firmware.) Cheers Rod
Hi Pascal I just received this from AliExpress: ST-Link V2 https://a.aliexpress.com/_msNDlOB Is it going to work to capture the data you require.
Cheers Rod
No it's not the right device.... You need a cheap ($10) Saleae 8 channels compatible analyzer for that purpose.
Cool I'll get that sorted.
On Sat, 17 May 2025, 12:08 pm pascallanger, @.***> wrote:
pascallanger left a comment (pascallanger/DIY-Multiprotocol-TX-Module#1082) https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/issues/1082#issuecomment-2887964523
No it's not the right device.... You need a cheap ($10) Saleae 8 channels compatible analyzer for that purpose.
— Reply to this email directly, view it on GitHub https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/issues/1082#issuecomment-2887964523, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABXYD47VQMJS43NICHGDEUL262KZDAVCNFSM6AAAAABYI3H7OOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDQOBXHE3DINJSGM . You are receiving this because you commented.Message ID: @.*** com>
Is there any progress on this?
My first time in this forum. Any problems or help needed on this protocol?
Hi all!
I finally got some time to take apart my RC transmitter HotRC CT-8A.
I soldered wires on the RF module and after some try and error I found the correct pinout. For the sake of completeness, looking at the RF module with the antenna plug on the top, pinout is:
1: CSn [D4 in PulseView dump]
2: CLK [D0 in PulseView dump]
3: MOSI [D2 in PulseView dump]
4: MISO [D4 in PulseView dump]
5: don't know
6: 3v3
7: likely IRQ
8: likely CE
9: don't know
10: GND
https://github.com/motorello/hotrc_RF_SPI_dumps/blob/main/RF-SPI_pinout.png
The RF chip has no silkscreen on it, the PA/LNB frontend is a AT2401C.
My findings as of now are the following:
-
when switching on the transmitter, after all the RF initialiazion registers, the TX broacasts, using REG 0x07, on RF channel 0x21 the list of the RF channels that will be used for hopping:
MOSI 07 01 21MOSI 32 14 8A 74 A4 33 23 55 41 0F 73 19 2D 69 37 05 5F 4B 24 56 42 1023 55 41 0F 73 19 2D 69 37 05 5F 4B are the channels used for frequency hopping and the TX always begins with the second one (0x55) -
after the successful connection with the receiver:
MOSI 07 01 55MOSI 32 0C 80 4C 64 22 96 B0 84 25 2C 61 09 4BMOSI 07 01 41MOSI 32 0C 80 4C 64 22 96 B0 84 25 2C 61 09 4BMOSI 07 01 0FMOSI 32 0C 80 4C 64 22 96 B0 84 25 2C 61 09 4BMOSI 07 01 73MOSI 32 0C 80 4C 64 22 96 B0 84 25 2C 61 09 4BMOSI 07 01 19MOSI 32 0C 80 4C 64 22 96 B0 84 25 2C 61 09 4BMOSI 07 01 2DMOSI 32 0C 80 4C 64 22 96 B0 84 25 2C 61 09 4BMOSI 07 01 69MOSI 32 0C 80 4C 64 22 96 B0 84 25 2C 61 09 4BMOSI 07 01 05MOSI 32 0C 80 4C 64 22 96 B0 84 25 2C 61 09 4BMOSI 07 01 5FMOSI 32 0C 80 4C 64 22 96 B0 84 25 2C 61 09 4BMOSI 07 01 4BMOSI 32 0C 80 4C 64 22 96 B0 84 25 2C 61 09 4BMOSI 07 01 23MOSI 32 0C 80 4C 64 22 96 B0 84 25 2C 61 09 4B -
the packet containing RC channels information is written on register 0x32 and is 13 bytes long, no CRC I've found so far
-
the bytes are sent LSByte first
-
all the 8 channels have the same precision and are encoded on 11 bits (somehow similar to the SBUS protocol, as far as I know)
-
the first two bytes of the "RC channels packet" do not change over time and over receivers (I tested with two different, in my case the are always 0x0C 0x80): maybe they could carry information of RC channels 9 and 10 on 8 bit each...
-
starting from the third byte, the 8 RC channels are encoded (I've tried to represent the pattern, it is easier to swap the sequence to LSByte first, so that bits on every channel are contiguous): https://github.com/motorello/hotrc_RF_SPI_dumps/blob/main/RC-channels.png
-
trims are changing the middle values of the channels (they are not carried out on separate bytes)
-
in normal conditions (receiver connected), packets are transmitted every 5ms (200Hz)
-
the time spent to send 13 bytes seems to be around 1460us, which means 1460/13/8 = 14us/bit which means 1000000us/14us = around 71kbps (so likely the raw bitrate could be 250kbps)
-
all the SPI transactions are made with at least 3 bytes (likely one byte for register address and two for payload) -> I didn't manage to find RF chips that always use two bytes of payload, but my knowledge is very limited
-
it seems that the RF also uses some kind of strobes : A4, A5, A6, A7, B0, B2 are always used with two following FF FF
I didn't look at the binding workflow yet, but I've dumped it as well. I didn't analyze how the telemetry works yet.
I've created a temporary GitHub repo with some SPI dumps (https://github.com/motorello/hotrc_RF_SPI_dumps):
- 'dump-BINDING_RX-in-binding_TX-off-on_bind_automatically_RX-F04A' -> binding workflow: transmitter OFF, receiver in binding, transmitter ON
- 'dump-RX-off_TX-off-on_RX-on_RX-off_TX-on-off_RX-F04A' -> receiver OFF, transmitter OFF, transmitter ON, receiver ON, transmitter OFF
- 'dump-CH1-M-L-M-H-M_CH2-M-L-M-H-M_RX-F04A' -> RC channel 1: from mid to low, to mid, to high, to mid; then RC channel 2, same pattern
- 'dump-CH3-L-M-H-M-L_CH4-L-M-H-M-L_throw90' > RC channel 3: from mid to low, to mid, to high, to mid (100% throw); then RC channel 4, same pattern
- 'dump-CH5-L-M-H-M-L_CH6-L-M-H-M-L_CH7-L-M-H-M-L_CH8-L-M-H-M-L_throw90' -> same as before but for CH5, CH6, CH7, CH8 (90% throw)
- 'dump-CH5-L-M-H-M-L_CH6-L-M-H-M-L_CH7-L-M-H-M-L_CH8-L-M-H-M-L_throw100' -> same as before: CH5, CH6, CH7, CH8 (100% throw)
I have also wrote some one-liner to create csv files ready to be used in Excel/LibreCalc starting from the PulseView SPI decoder (right-click > export all annotations), maybe it can help someone:
spiDumpFile=MY_SPI_DECODED.txt
## packet as sent via SPI
sed -E '/ bits:/d; / data:/d; s/ SPI: (M[OI]+S[IO]+) transfers: /\t\1\t/g; s/-[0-9]+//g; s/ /\t/g' \
$spiDumpFile | sort -n -k1,1 -k2,2r \
> ${spiDumpFile/.txt/-ReadyForExcel.csv}
## MSB and LSB in one file
awk '{ printf "\nMSB\t%s", $0 }; { printf "\nLSB\t%s\t%s\t%s", $1, $2, $3 }; { for (i = NF; i > 3; i--) printf "\t%s", $i } ' \
${spiDumpFile/.txt/-ReadyForExcel.csv} \
| sed '/^$/d' \
> ${spiDumpFile/.txt/-ReadyForExcel-MSB+LSB.csv}
I'd love to write some code to support this new protocol (today I also bought a CT-10B transmitter as I'm curious to see where the channels 9 and 10 are encoded...), but I need some initial guidance or suggestions on which RF chip could be used for HotRC (A7105? CC2500?).
Feel free to ask for additional SPI dumps, the transmitter is here open and wires hooked up to Sigrok.
Cheers! Francesco
Ok, it turned out that the RF transceiver is a LT8910, which is why the data payload is always 2 bytes. I'm pasting below the full initialization sequence for completeness. The configuration per se is not that bad, no scramble, no whitening, no FEC, easy hopping sequence. BUT: the data rate is 125Kbps, which is not supported by NRF24L01. This is bad since we cannot use the wonderful emulation layer that Pascal already developed in 2016, if I recall correctly. I don't know, if someone managed to use some undocumented register in NRF24 to get 125Kbps data rate... Otherwise, I fear it is needed to write a similar emulation layer on top of CC2500. I will study the datasheet in spare time.
This is the full initialization SPI dump, together with some my notes:
| DELTA TIME us | SIGNAL | REG | R/W | MOSI REG | PKT-0 | PKT-1 | REG/REPL | BITS-P-0 | BITS-P-1 | NOTES |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | MOSI | 00 | W | 00 | 6F | E0 | 00h (0d) | 01101111 | 11100000 | Recommended on datasheet |
| 0 | MISO | 00 | 00 | 00 | 01 | 00000000 | 00000000 | 00000001 | ||
| 709,773 | MOSI | 02 | W | 02 | 66 | 17 | 02h (2d) | 01100110 | 00010111 | Recommended on datasheet |
| 709,773 | MISO | 01 | 02 | 01 | 01 | 00000001 | 00000001 | 00000001 | ||
| 108 | MOSI | 04 | W | 04 | 9C | C9 | 04h (4d) | 10011100 | 11001001 | Recommended on datasheet |
| 108 | MISO | 01 | 04 | 80 | 01 | 00000001 | 10000000 | 00000001 | ||
| 106 | MOSI | 05 | W | 05 | 66 | 37 | 05h (5d) | 01100110 | 00110111 | Recommended on datasheet |
| 106 | MISO | 01 | 05 | 01 | 81 | 00000001 | 00000001 | 10000001 | ||
| 105 | MOSI | 07 | W | 07 | 00 | 00 | 07h (7d) | 00000000 | 00000000 | TX_EN: 0 RX_EN: 0 RF_CH: 0d / 00h |
| 105 | MISO | 01 | 07 | 01 | 01 | 00000001 | 00000001 | 00000001 | ||
| 106 | MOSI | 08 | W | 08 | 6C | 90 | 08h (8d) | 01101100 | 10010000 | Recommended on datasheet |
| 106 | MISO | 01 | 08 | 01 | 01 | 00000001 | 00000001 | 00000001 | ||
| 107 | MOSI | 09 | W | 09 | 1F | C0 | 09h (9d) | 00011111 | 11000000 | PA_PWCTR: 0001 (1d); PA_GN: 1111 (15d) |
| 107 | MISO | 01 | 09 | 81 | 81 | 00000001 | 10000001 | 10000001 | ||
| 108 | MOSI | 0B | W | 0B | 00 | 08 | 0Bh (11d) | 00000000 | 00001000 | Recommended on datasheet |
| 108 | MISO | 01 | 0B | 01 | 01 | 00000001 | 00000001 | 00000001 | ||
| 107 | MOSI | 0D | W | 0D | 48 | BD | 0Dh (13d) | 01001000 | 10111101 | Recommended on datasheet |
| 107 | MISO | 81 | 0D | 01 | 01 | 10000001 | 00000001 | 00000001 | ||
| 113 | MOSI | 16 | W | 16 | 00 | FF | 16h (22d) | 00000000 | 11111111 | Recommended on datasheet |
| 113 | MISO | 01 | 16 | 01 | 01 | 00000001 | 00000001 | 00000001 | ||
| 107 | MOSI | 17 | W | 17 | 80 | 05 | 17h (23d) | 10000000 | 00000101 | TxRx_VCO_CAL_EN: 1 |
| 107 | MISO | 00 | 17 | 00 | 01 | 00000000 | 00000000 | 00000001 | ||
| 108 | MOSI | 18 | W | 18 | 00 | 67 | 18h (24d) | 00000000 | 01100111 | Recommended on datasheet |
| 108 | MISO | 01 | 18 | 81 | 01 | 00000001 | 10000001 | 00000001 | ||
| 107 | MOSI | 1A | W | 1A | 19 | E0 | 1Ah (26d) | 00011001 | 11100000 | Recommended on datasheet |
| 107 | MISO | 01 | 1A | 01 | 01 | 00000001 | 00000001 | 00000001 | ||
| 106 | MOSI | 1B | W | 1B | 13 | 00 | 1Bh (27d) | 00010011 | 00000000 | XI_trim: 00000 |
| 106 | MISO | 01 | 1B | 00 | 01 | 00000001 | 00000000 | 00000001 | ||
| 106 | MOSI | 20 | W | 20 | 48 | 00 | 20h (32d) | 01001000 | 00000000 | PREAMBLE_LEN: 010 (3 bytes); SYNCWORD_LEN: 01 (32 bits → {Reg39[15:0],Reg36[15:0]); TRAILER_LEN: 000 (4 bits); DATA_PACKET_TYPE: 00 (NRZ law data); FEC_TYPE: 00 (No FEC); BRCLK_SEL: 000 (keep low) |
| 106 | MISO | 01 | 20 | 01 | 80 | 00000001 | 00000001 | 10000000 | ||
| 105 | MOSI | 21 | W | 21 | 3F | C7 | 21h (33d) | 00111111 | 11000111 | VCO_ON_DELAY_CNT: 3Fh (63 us); TX_PA_OFF_DELAY: 11 (4us + 3us); TX_PA_ON_DELAY: 00111 (7 us) |
| 105 | MISO | 01 | 21 | 01 | 80 | 00000001 | 00000001 | 10000000 | ||
| 106 | MOSI | 22 | W | 22 | 20 | 00 | 22h (34d) | 00100000 | 00000000 | TX_CW_DLY: 20h (32 us); TX_SW_ON_DELAY: 000000 (0 us) |
| 106 | MISO | 01 | 22 | 01 | 01 | 00000001 | 00000001 | 00000001 | ||
| 106 | MOSI | 23 | W | 23 | 03 | 00 | 23h (35d) | 00000011 | 00000000 | RE-TRANSMIT_TIMES: 0011 (3 times); SCRAMBLE_DATA: 0000000 (no Scramble) |
| 106 | MISO | 80 | 23 | 80 | 01 | 10000000 | 10000000 | 00000001 | ||
| 108 | MOSI | 28 | W | 28 | 44 | 01 | 28h (40d) | 01000100 | 00000001 | FIFO_EMPTY_THRESHOLD: 01000 (8d); FIFO_FULL_THRESHOLD: 10000 (16d); SYNCWORD_THRESHOLD: 000001 (0 errors allowed) |
| 108 | MISO | 01 | 28 | 01 | 81 | 00000001 | 00000001 | 10000001 | ||
| 107 | MOSI | 29 | W | 29 | B4 | 00 | 29h (41d) | 10110100 | 00000000 | CRC_ON: 1; SCRAMBLE_ON: 0; PACK_LENGTH_EN: 1 (1st byte is payload length); FW_TERM_TX: 1; AUTO_ACK: 0 PKT_FIFO_POLARITY: 1 (FIFO flag Active low); CRC_INITIAL_DATA: 0 |
| 107 | MISO | 01 | 29 | 01 | 01 | 00000001 | 00000001 | 00000001 | ||
| 128 | MOSI | 2A | W | 2A | FD | B0 | 2Ah (42d) | 11111101 | 10110000 | SCAN_RSSI_CH_NO: 111111 (63d); Rx_ACK_TIME: B0h (176 us) |
| 128 | MISO | 01 | 2A | 00 | 00 | 00000001 | 00000000 | 00000000 | ||
| 117 | MOSI | 2C | W | 2C | 08 | 00 | 2Ch (44d) | 00001000 | 00000000 | DATARATE: 1000 (8d → 125 Kbps) |
| 117 | MISO | 01 | 2C | 01 | 01 | 00000001 | 00000001 | 00000001 | ||
| 107 | MOSI | AC | R | 2C | FF | FF | 2Ch (44d) | 11111111 | 11111111 | |
| 107 | MISO | 01 | 2C | 88 | 00 | 00000001 | 10001000 | 00000000 | ||
| 3,298 | MOSI | AC | R | 2C | FF | FF | 2Ch (44d) | 11111111 | 11111111 | |
| 3,298 | MISO | 80 | 2C | 00 | 01 | 10000000 | 00000000 | 00000001 | ||
| 3,438 | MOSI | 2D | W | 2D | 05 | 52 | 2Dh (45d) | 00000101 | 01010010 | Best value is 0552H when data rate is 125Kbps |
| 3,438 | MISO | 01 | 2D | 81 | 81 | 00000001 | 10000001 | 10000001 | ||
| 114 | MOSI | 34 | W | 34 | 80 | 80 | 34h (52d) | 10000000 | 10000000 | CLR_W_PTR: 1; CLR_R_PTR: 1 |
| 114 | MISO | 01 | 34 | 81 | 01 | 00000001 | 10000001 | 00000001 | ||
| 121 | MOSI | 27 | W | 27 | 12 | 34 | 27h (39d) | 00010010 | 00110100 | SYNC_WORD[1]: 1234h (MSWord) |
| 121 | MISO | 01 | 27 | 01 | 01 | 00000001 | 00000001 | 00000001 | ||
| 107 | MOSI | 24 | W | 24 | 56 | 78 | 24h (36d) | 01010110 | 01111000 | SYNC_WORD[0]: 5678h (LSWord) |
| 107 | MISO | 01 | 24 | 01 | 01 | 00000001 | 00000001 | 00000001 | ||
| 106 | MOSI | 09 | W | 09 | 48 | 00 | 09h (9d) | 01001000 | 00000000 | PA_PWCTR: 0001 (1d); PA_GN: 1111 (15d) |
| 106 | MISO | 80 | 09 | 01 | 01 | 10000000 | 00000001 | 00000001 | ||
| 119 | MOSI | 34 | W | 34 | 80 | 80 | 34h (52d) | 10000000 | 10000000 | CLR_W_PTR: 1; CLR_R_PTR: 1 |
| 119 | MISO | 00 | 34 | 01 | 01 | 00000000 | 00000001 | 00000001 | ||
| 109 | MOSI | 07 | W | 07 | 00 | A1 | 07h (7d) | 00000000 | 10100001 | TX_EN: 0; RX_EN: 1; RF_CH: 33d / 21h |
| 109 | MISO | 01 | 07 | 01 | 01 | 00000001 | 00000001 | 00000001 | ||
| 2,445 | MOSI | A4 | R | 24 | FF | FF | 24h (36d) | 11111111 | 11111111 | reads SYNC_WORD @ 36 (24h) |
| 2,445 | MISO | 32 | 24 | 53 | 7C | 00110010 | 01010011 | 01111100 | ||
| 1,237 | MOSI | A5 | R | 25 | FF | FF | 25h (37d) | 11111111 | 11111111 | reads SYNC_WORD @ 37 (25h) |
| 1,237 | MISO | 33 | 25 | 00 | 00 | 00110011 | 00000000 | 00000000 | ||
| 1,281 | MOSI | A6 | R | 26 | FF | FF | 26h (38d) | 11111111 | 11111111 | reads SYNC_WORD @ 38 (26h) |
| 1,281 | MISO | 13 | 26 | 00 | 00 | 00010011 | 00000000 | 00000000 | ||
| 1,314 | MOSI | A7 | R | 27 | FF | FF | 27h (39d) | 11111111 | 11111111 | reads SYNC_WORD @ 39 (27h) |
| 1,314 | MISO | 12 | 27 | 02 | 30 | 00010010 | 00000010 | 00110000 | ||
| 1,665,875 | MOSI | 27 | W | 27 | 12 | 34 | 27h (39d) | 00010010 | 00110100 | SYNC_WORD[1]: 1234h (MSWord) |
| 1,665,875 | MISO | 12 | 27 | 12 | 12 | 00010010 | 00010010 | 00010010 | ||
| 132 | MOSI | 24 | W | 24 | 56 | 78 | 24h (36d) | 01010110 | 01111000 | SYNC_WORD[0]: 5678h (LSWord) |
| 132 | MISO | 13 | 24 | 1A | 12 | 00010011 | 00011010 | 00010010 | ||
| 3,240 | MOSI | A4 | R | 24 | FF | FF | 24h (36d) | 11111111 | 11111111 | reads SYNC_WORD @ 36 (24h) |
| 3,240 | MISO | 1A | 24 | 56 | 78 | 00011010 | 01010110 | 01111000 | ||
| 1,227 | MOSI | A5 | R | 25 | FF | FF | 25h (37d) | 11111111 | 11111111 | reads SYNC_WORD @ 37 (25h) |
| 1,227 | MISO | 02 | 25 | 00 | 00 | 00000010 | 00000000 | 00000000 | ||
| 1,291 | MOSI | A6 | R | 26 | FF | FF | 26h (38d) | 11111111 | 11111111 | reads SYNC_WORD @ 38 (26h) |
| 1,291 | MISO | 12 | 26 | 00 | 00 | 00010010 | 00000000 | 00000000 | ||
| 1,201 | MOSI | A7 | R | 27 | FF | FF | 27h (39d) | 11111111 | 11111111 | reads SYNC_WORD @ 39 (27h) |
| 1,201 | MISO | 1A | 27 | 12 | 30 | 00011010 | 00010010 | 00110000 | ||
| 1,510 | MOSI | 87 | R | 07 | FF | FF | 07h (7d) | 11111111 | 11111111 | |
| 1,510 | MISO | 02 | 07 | 00 | 20 | 00000010 | 00000000 | 00100000 |
I will keep on investigating on this.
Ciao, Francesco