biemster / FindMy

Query Apple's Find My network
225 stars 39 forks source link

Lenze ST17H66 custom firmware #5

Closed biemster closed 1 year ago

biemster commented 1 year ago

Most budget friendly iTag bluetooth trackers nowadays have the Lenze st17h66 mcu (some old stock comes with the st17h26, which is an entirely different architecture, discussed in another issue #?) The SDK is available: ST17H66_SDK or BLE5_ST17H66 with a nice optimized example st17h66_fw_power_consumption. Also doc.lenze.club has a lot of material.

Flashing the chip proved difficult, according to the docs P09 and P10 should be the UART, but on the tags I have one of them is attached to the buzzer. Also the mcu should be reset just before the UXTDWU command is sent, but the chip does not have a reset pin. However, @vadimkozhin managed to successfully flash this chip with custom firmware as detailed here

biemster commented 1 year ago

@vadimkozhin let's get this compiling in GCC, you did great work flashing this chip. I was getting worried that Lenze built in some protection against reflashing, and was about to abandon this route. But since these tags are by far the cheapest and handiest (all other mcus come in bare module form) this is fantastic news.

Could you first explain how you flashed this chip, and in particular how you handled the reset step? (I'm aware of the LeKit software and everything available on docs.lenze.club, and spend countless hours getting it to recognize my board to no avail.)

At the same time let's look at converting the Keil project to GCC. Are you aware of ProjectConverter? After using that and a couple minor code changes the whole simpleBlePeripheral demo should compile in GCC (but not link).

vadimkozhin commented 1 year ago

P09 and P10 should be the UART, but on the tags I have one of them is attached to the buzzer

Yes, on my board one of UART pins also attached to the buzzer, and make buzz when something goes from UART.

Could you first explain how you flashed this chip, and in particular how you handled the reset step?

tx is P9 (GPIO 9) rx is P10 (GPIO 10)

1) Like the manual describes, you'll need to connect UART to LeKit software and switch it to UXTDWU state and click Connect button.

2) Then, PULL HIGH P15 (3v) when powering up the board. Тhis will enable reset mode. This pin in both datasheets (for different packages) named as _P15 / AIO4 (GPIO 15 / ADC input 4 / micbias output). The baudrate in the LeKit app automatically switches to 115200.

3) After that, like the manual describes: press Erase button to erase the chip.

4) Then in the Hex Merge tab need to double click the second text field (right from the APP dropdown) to choose path to *.hex firmware. This is not intuitive, but it here it is...

5) Press Write button to write to chip.

6) Then restart the board by disconnecting the power and connect 3v to it again.

Done. If everything is good, you'll need to see some data on UART.

On my board P15 connected to the tag button, so I just randomly figure it out, but when I started to looking how to RESET in the docs I could not find anything related. But honestly, I did not dig too deep, since I found the reset state by just pressing the button.

Are you aware of ProjectConverter? After using that and a couple minor code changes the whole simpleBlePeripheral demo should compile in GCC (but not link).

Thank you! I will try to take a look on ProjectConverter.

So far I manage to transfer a working project to uVision Community Edition. It comes with the v6.18 compiler, and important thing -- it is FREE for non-commercial projects (need to register and ARM gives you one year license).

Some minor code changes need to be done to transfer it for v6 compiler. I use this doc as a guide. I did not exactly sure that I've done this correctly: need to comment some piece of inline ASM and change some stuff that I'm not 100% sure what was that... but so far it works.

@biemster Plz let me know if you will successfully refresh the chip or at least put in on RESET.

I spent a couple of days actively working on this, and for now will take a little break. But please keep posting here if you'll have some progress. I will continue to working on this in a couple of days.

Happy hacking :)

biemster commented 1 year ago

Great info @vadimkozhin especially on the reset! On my board P15 is also connected to the button, it is very possible I never got the truly brilliant idea to press it to see if that has any effect.. I'll try this today and keep posting here on progress.

Further you mentioned that the tools are windows only, I'm running all this under wine which seems to do the trick just fine. (and a gray area Keil licence enables me to experiment with the full 5.31 version for personal use, I can detail how I did that if you are interested. no need to change any code then). I'm already working on a python version of the LeKit program, so I can flash them in linux natively.

Again, thanks a lot for your detailed info, let's get this chip programmable licence free and under linux! Can't beat that $1.5 pricetag which includes a case and sometimes even a battery!

vadimkozhin commented 1 year ago

I'm running all this under wine which seems to do the trick just fine.

At the moment I have dedicated windows minipc for the further experiments and improvements with this chip, but for the project will be better to port everything on GNU. I have m1 mac, and I've done all previous OHS experiments with ESP32 on m1. Can test GNU builds and flash on m1 in the future.

I'm already working on a python version of the LeKit program, so I can flash them in linux natively.

Thats great! I'm also thought about doing this. So far to speed up the tag cloning process I have a tiny python script that just replace base64 key in compiled .hex file, since the key is hardcoded in firmware... But it is temporary solution to speedup a workflow.

I assume porting the flashing process should not be that hard. At least a basic functions. Keep up!

Let's get this chip programmable licence free and under linux! Can't beat that $1.5 pricetag which includes a case and sometimes even a battery!

Exactly my thoughts :)

biemster commented 1 year ago

It looks like my old PL2303 trips over getting the chip in programming mode, so no game for me yet :( Luckily I have a new CP2102 coming in any day now, I hope that that one will be more resilient. Otherwise I'll have to try to get an ESP32 to talk to the uart, and program it like that but that sounds like a lot of work..

I'll keep trying coming days, at least I know now it should work. @vadimkozhin would you consider sharing your implementation for generating the FindMy advertisements on this chip?

vadimkozhin commented 1 year ago

@vadimkozhin would you consider sharing your implementation for generating the FindMy advertisements on this chip?

Here it is.

I took the example/ble_peripheral/simpleBlePeripheral as an example from the ST17H66_SDK_3.1.1.2.zip and add some stuff from the ESP32 example to the simpleBLEPeripheral.c.

You'll need to replace public_key uint8 (line 124) with your ADV KEY in simpleBLEPeripheral.c.

biemster commented 1 year ago

Nice, thanks! I'm still struggling with getting the chip in programming mode, even when using an ESP32 to talk to the uart. Did you already program multiple boards, and are they all the same as the photo you showed in the Openhaystack issue?

vadimkozhin commented 1 year ago

For now I have only one board (it is on photo). Other are still on the road from China.

Could you send me a closeup pic of your board and describe your setup? And plz draw over where you'll try to pin the UART connections, and what UART adapter you are trying to use?

You can send me your sketch for ESP32, I can try to reproduce your setup.

biemster commented 1 year ago

I have two different types of boards (actually three, I have two the same boards, some with st17h66 and some with st17h26, but the latter is completely different chip so that's for another discussion) The board with either 26 or 66 has a teardown here: https://simplysoldered.com/cheapest-bluetooth-low-energy-tag-teardown

The other board is very similar but has a couple extra test pads on the bottom and is basically mirrored from the one shown in the link. Actually I'm quite confident that my wiring is alright, I'm suspecting my procedure to putting the chip in programming mode is not correct.

On the ESP32 side, I'm using MicroPython where I just open the uart and start spamming UXTDWU at 9600 baud and listening for cmd>>:, just like LeKit seems to be doing. I feed the 17h66 via the d5 pin on the ESP32, that might be causing issues as well. (it can drive 40mA max, and the buzzer draws about 30 so that resets the chip :) )

from machine import Pin,UART

uart = UART(2)
uart.init(9600, timeout=50)

d5 = Pin(5, Pin.OUT, value=1)

resp = uart.any()
while not resp:
    uart.write('UXTDWU')
    resp = uart.read(6)

print(resp)
while True:
    resp = uart.read(32)
    if resp:
        print(resp)

At the moment I'm writing a little micropython script that acts like a 17h66, to see if this is indeed what LeKit is doing (I might be missing some newline or control character or whatever) (EDIT I just tested that, and it is indeed doing exactly that)

Also it might also be wine messing up something passing through the COM port while switching from 9600 to 115200, so plan B is setting up some windows box to do some tests there..

My setup is a bit of a mess at the moment, so difficult to reproduce, but thanks for the help!

vadimkozhin commented 1 year ago

Well... a bit of juggling with oscilloscope and logic analyser brought the results...

Here is the micropython code that work on my ESP32 setup:

from machine import UART
import time

#Initalize UART
uart = UART(2, tx=16, rx=17)
uart.init(9600, bits=8, parity=None, stop=1, timeout=1)

print('Sending the "UXTDWU" command...')

while True:
    uart.write('UXTDWU')
    time.sleep(0.0566)

    msg = uart.read(10)
    # This responce from the MCU should be b'\x00cmd>>:'
    if msg and msg.endswith(b'cmd>>:'):
        print('Response is:', msg)
        break

print('RESET MODE activated. Enter the command.')

time.sleep(1)

# Changing the baudrate
uart.init(115200, bits=8, parity=None, stop=1, timeout=1)

send = input()  # enter "er512" to erase the chip

uart.write(send)
time.sleep(1)

msg = uart.read(10)
print('Response is:', msg)

Pins 16 and 17 need to be changed to your setup.

This is the output from console:

Sending the "UXTDWU"...
Response is: b'\x00cmd>>:'
RESET MODE activated. Enter the command.

1) Turn off the power from MCU 2) Connect your ESP to rx and tx pins 3) Run the python script. Console should print Sending the "UXTDWU".... On my setup the buzzer on the st17h66 board should start 'ticking', indicating that python script sending the UXTDWU... 4) Enable the power on st17h66. Console should show the response and input() will wait for the command.

Let me know if it works for you.

vadimkozhin commented 1 year ago

I measure the intervals between "UXTDWU" messages from LeKit, and it was around 57ms. May be this was the case... I guess MCU need some time to get the message, but your script sending one msg after another without any interval.

image

But anyway, I suggest you to power the chip from outside of ESP, since in RESET mode in my case it consumes around 125mA. May be the power issues cause your troubles to enable RESET mode.

biemster commented 1 year ago

Wow great stuff! Nice to have a Rigol on the bench, that should take out a lot of guesswork :). I'll try the code you sent when I get back to my desk. On the send interval, I use the timeout on the uart.read() to pace it a bit, which I estimated from the clicking to be 50ms, good to know that LeKit is on 57ms. What is most likely my issue, is the power draw of 125mA, the ESP pin can't deliver that even close. I'll report back when I have some results.

biemster commented 1 year ago

This is more and more looking like a power issue. My ESP32 is definitely not capable of feeding the 17h66. When I connect my board to my PL2303 uart with power only, it runs fine. I can also add the rx line, still no problems. But when I connect tx, either directly to the pin or after the 500 Ohm resistor (so between resistor and buzzer), the 17h66 is not able to run anymore. Maybe I have to add a diode, or a resistor in the tx line? (I still did not finish my copy of The Art of Electronics, so I'm just guessing here). I'll try both, and other suggestions are also very welcome.

vadimkozhin commented 1 year ago

You can put something like 100ohm in series, or some diode... but this used for protection usually. I guess the trouble can be how you feed the board...

Make sure that your UART board outputs 3.3v logic. Check the specs, how power it can deliver thru the power pin.

What you can try, is power the st17 board with external battery or 3.3v power supply, and try to connect to UART with ESP32. Just put some switch in series which can disconnect the power from the board, and make sure the st17 and ESP32 share the GND.

biemster commented 1 year ago

This is getting frustrating. I tried with external power, the board stays operational with all wires attached now so it should get enough juice. I tried with different boards, both types (the one from the previous post and the mirrored version), but none of the chips I have I can get in RESET mode. Not with my own ESP code or the code posted 2 days ago here. I'm running out of ideas, besides the suspicion that the boards I have have a different bootloader.. @vadimkozhin what kind of tags did you order? The same you already had or different ones?

vadimkozhin commented 1 year ago

I'm running out of ideas, besides the suspicion that the boards I have have a different bootloader.

Actually, it is hard to guess what could be wrong. I personally faced with this SoC first time, and without the board itself it is hard to tell what's can be wrong. May be another chip revision, may be something else... If you have a link on exact item that you've bought, please share it, so I can order one and try to reflash it, or may be find what's the difference in flashing process.

Also, can you post a closeup of your board with all connections, and mark where you put Tx and Rx. May be we miss something obvious...

@vadimkozhin what kind of tags did you order? The same you already had or different ones?

I have created a document describing flash process on my board. Take another look on it, may be something is missing in your setup. Also, there is a link to exact seller where I bought mine. But keep in mind, it's Aliexpress... you cant' be 100% sure that you've got the same board.

I've ordered another pack from this seller, and also a couple from another seller with the same tag on pictures.

biemster commented 1 year ago

These are the ones I bought with st17h66: https://www.aliexpress.com/item/1005001516473637.html https://www.aliexpress.com/item/1005003409996515.html https://www.aliexpress.com/item/1005003911609836.html

and with st17h26: https://www.aliexpress.com/item/33035468217.html https://www.aliexpress.com/item/32920866060.html

I'll make a closeup of the board with the connections this weekend, but I need some time for that because I actually made a couple changes to it like disconnecting the LED, and cutting the trace from pin1 and pin2 to power, because I tried the SWS and SWD interfaces as well. But for my latest tests today I used a completely unmodified board.

Very nice write-up you did in your repo, I've forked it and will start working on the GCC port there. I'll get a couple of those tags you worked with as well, they are even a bit cheaper than mine (although a bit bulkier).

vadimkozhin commented 1 year ago

Thank you for the links. I've ordered one with st17h66 to try to find out what could be different in setup or tag schematics.

I've forked it and will start working on the GCC port there.

👍

I'll get a couple of those tags you worked with as well, they are even a bit cheaper than mine (although a bit bulkier).

Yes they look bulkier, but I hope more capable battery there could fit in their enclosure. I've order some cheap tablet like batteries (CR2450) to test. Specs says that they are 550 mAh (compared to 235 mAh in CR2032 which comes with the tag) and it should extend the working time of the tag.

biemster commented 1 year ago

SUCCESS! And I'm an idiot as well.. This is by far the most finicky mcu I have ever worked with. What went wrong:

  1. So first I indeed did not give the 17h66 enough power to even get into RESET mode, since it seems to be very hungry when it goes there for some reason. And my only usb uart at this moment is a PL2303 which is known to have issues with supplying 3v3 sometimes.
  2. I've added a 100 ohm resistor on the tx line, which caused the signal to be too weak due to the buzzer and 500 ohm resistor connected to that pin as well.
  3. I connected the tx of the ESP after the 500 ohm and before the transistor base to the buzzer, which deteriorated the signal that was left even further.
  4. The 17h66 is throwing a lot of \x00 back over the uart, which made my script miss the cmd>>: Your script @vadimkozhin actually caught it, I just managed to get one of my boards in RESET mode!
  5. After I finally managed to supply the chip with enough power yesterday, I wrongly connected the rx of the uart to P09 as well..

One thing to note @vadimkozhin , I did not need to press the button on P15 to get it into RESET mode..

So long story short, those (newer?) boards can be flashed just fine as well, no new schematics, serial numbers or bootloaders! Good start of the weekend! Now I'll compile a firmware, and get this thing on the road!

biemster commented 1 year ago

@vadimkozhin which responses are you getting when you use the CheckID button in LeKit, or use the following code on your ESP32 (which are the commands LeKit sends):

from machine import UART
import time

#Initalize UART
uart = UART(2, tx=16, rx=17)
uart.init(9600, bits=8, parity=None, stop=1, timeout=1)

print('Sending the "UXTDWU" command...')

while True:
    uart.write('UXTDWU')
    time.sleep(0.0566)

    msg = uart.read(10)
    # This responce from the MCU should be b'\x00cmd>>:'
    if msg and msg.endswith(b'cmd>>:'):
        print('Response is:', msg)
        break

print('RESET MODE activated. Changing baudrate to 115200')
time.sleep(1)
uart.init(115200, bits=8, parity=None, stop=1, timeout=1)

print('CheckID')
for cmd in [b'rdreg11000800', b'rdreg11000900']:
    print('sent', cmd)
    uart.write(cmd)
    time.sleep(1)
    msg = uart.read()
    print('Response is:', msg)

My response is this:

MPY: soft reboot
MicroPython v1.19.1 on 2022-06-18; ESP32 module with ESP32
Type "help()" for more information.
>>> import getid
Sending the "UXTDWU" command...
Response is: b'cmd>>:'
RESET MODE activated. Changing baudrate to 115200
CheckID
sent b'rdreg11000800'
Response is: b'=0xffffffff#OK>>:'
sent b'rdreg11000900'
Response is: b'=0xffffffff#OK>>:'
>>>
vadimkozhin commented 1 year ago

SUCCESS!

Congrats! :)

I did not need to press the button on P15 to get it into RESET mode

Sometimes my board is also goes into the RESET mode without me pressing a button. I didn't investigate it, but seems like if firmware actively transfer something by UART, and UART packet injects between two UXTDWU packets, it is triggers RESET mode. But may be not :)

which responses are you getting when you use the CheckID button in LeKit

At the moment I don't have a setup with ESP32. But I have logic analyser and I have done some captures... RESET, GetInfo, whole flashing process and ERASE. So I hope it will help you.

Here they are.

You can download Logic2 software for free and explore whole communication. To make things easier, I'll attach the firmware .hex file, which was user during flashing process. Also, in .txt files are LeKit console outputs.

Spoiler -- seems like SoC do not output GetInfo in clear text, and whole interaction based on commands and registers... Need to take a closer looks at all documentation, may the commands and registers are there.

biemster commented 1 year ago

Those captures are great, they help a lot. At the moment I'm stuck at the flashing process, I managed to do an erase using commands sent over the ESP32 UART, plus quite a few more commands return #OK>>:. However, my boards don't want to send the checksum after they receive the data following the cpbin command, while in your captures it looks like the 17h66 should answer with the checksum after about half a second. I noticed that your version of Lekit is 2.5.1a, while I am using 2.5.2 (no clue where I found that though), and there are a couple more commands in your trace than I got from LeKit. Maybe those are necessary for the flashing process, I'll investigate more when I get some time.

biemster commented 1 year ago

It seems version 2.5.2 of LeKit is not able to flash the 17h66, but version 2.5.1a can.. I seem to have bad luck with this chip, first an usb uart that is not supplying enough power, then a LeKit version that is sending the wrong commands, @vadimkozhin I'm very luckily you got it right, where did you even find this v2.5.1a? doc.lenze.club has 2.5.2

So 2.5.2 sends the rdrev+ command prepended with a couple wrreg commands, and then the chip responds with just #OK>>:. But 2.5.1a just sends a plain rdrev+, and the 17h66 responds with 0x00124085 6222M005 #OK>>:, telling the LeKit software to write to a completely different location, and set up some SPI stuff as well!

from machine import UART
import time

#Initalize UART
uart = UART(2, tx=16, rx=17)
uart.init(9600, bits=8, parity=None, stop=1, timeout=1)

print('Sending the "UXTDWU" command...')

while True:
    uart.write('UXTDWU')
    time.sleep(0.0566)

    msg = uart.read(10)
    # This responce from the MCU should be b'\x00cmd>>:'
    if msg and msg.endswith(b'cmd>>:'):
        print('Response is:', msg)
        break

print('RESET MODE activated. Changing baudrate to 115200')
time.sleep(1)
uart.init(115200, bits=8, parity=None, stop=1, timeout=1)

print('Read rev+')
cmd_251a = b'rdrev+ '
cmd_252 = b'wrreg4000c890 6000001 wrreg4000c8a8 0 wrreg4000c890 1008001 rdrev+ '
cmd = cmd_251a
uart.write(cmd)
print('sent', cmd)
time.sleep(1)
msg = uart.read()
print('Response is:', msg)
biemster commented 1 year ago

Alright so I managed to flash my first 17h66 today! Because I only have a bad PL2303 usb uart I had to first have the LeKit v2.5.1a transfer the firmware to an ESP32 that was pretending to be a 17h66 in programming mode, and then replay it over the ESP32 UART to a 17h66. So for people following along this thread:

  1. Check if you provide enough power to the 17h66 if the instructions by @vadimkozhin are not working for you.
  2. Make sure you are using LeKit v2.5.1a (also found together with the flashing instructions in point 1.) and not v2.5.2 as available on doc.lenze.club

The following micropython snippet shows the proper flow that should be sent to the 17h66 (you need a c0.bin, c1.bin and c2.bin in your internal flash of your ESP32, as sent by the LeKit software):

from machine import UART
import time
import os

#Initalize UART
uart = UART(2, tx=16, rx=17)
uart.init(9600, bits=8, parity=None, stop=1, timeout=1)

print('Sending the "UXTDWU" command...')

while True:
    uart.write('UXTDWU')
    time.sleep(0.0566)

    msg = uart.read(10)
    # This responce from the MCU should be b'\x00cmd>>:'
    if msg and msg.endswith(b'cmd>>:'):
        print('Response is:', msg)
        break

print('RESET MODE activated. Changing baudrate to 115200')
time.sleep(1)
uart.init(115200, bits=8, parity=None, stop=1, timeout=1)

print('Erase + Write')
cmds = []
cmds.append(b'er512') # erase
cmds.append(b'rdrev+ ')
cmds.append(b'wrreg4000c890 ab000001 ')
cmds.append(b'wrreg4000c838 ff010005 ')
cmds.append(b'spifs 0 1 3 0 ')
cmds.append(b'sfmod 2 2 ')
cmds.append(b'cpnum ffffffff ')
cmds.append(b'cpbin c0 002000 ' + b'%x' % os.stat('c0.bin')[6] + b' 11002000')
cmds.append(b'cpbin c1 005000 ' + b'%x' % os.stat('c1.bin')[6] + b' 11005000')
cmds.append(b'cpbin c2 020000 ' + b'%x' % os.stat('c2.bin')[6] + b' 11020000')

for cmd in cmds:
    uart.write(cmd)
    print('sent', cmd)
    time.sleep(0.5)
    msg = uart.read()
    print('Response is:', msg)

    if cmd[5:9] in [b' c0 ', b' c1 ', b' c2 ']:
        cfile = cmd[7] -48
        f = open('c%d.bin' % cfile, 'rb')
        data = f.read(32000)
        uart.write(data)
        print('sent c%d' % cfile)
        time.sleep(1)
        msg = uart.read()
        print('Response is:', msg)

        uart.write(b'%08x' % sum(data))
        print('sent checksum')
        time.sleep(1)
        msg = uart.read()
        print('Response is:', msg)
vadimkozhin commented 1 year ago

Wow @biemster! Seems like your board force you going the hard way :) Great job that you've managed to flash it! Congrats! Did the tablet shows on the map?

where did you even find this v2.5.1a?

Surprisingly, it is in the zip on doc.lenze.club. Why I choose this instead of 2.5.2 in the separate folder? I don't know. May be I just start to explore zips in the first place, and find out the 2.5.1a that I've previously seen on the screenshots in the docs and just copied it to use later. Do not remember exactly...

Bu funny thing is -- today I've tried to flash with 2.5.2 and it did go without any error. RESET mode triggered from the first attempt, flashing is went fine, and no difference between those versions for me. But I did not sniffed the actual communications and did not compare actual packets. I guess you should try whole process with another UART adapter...

I had to first have the LeKit v2.5.1a transfer the firmware to an ESP32 that was pretending to be a 17h66 in programming mode, and then replay it over the ESP32 UART to a 17h66.

What a trick! Glad that you've find the way! I am waiting for my tag that I've ordered with the link you provided, to confirm the unusual packets and stuff. Otherwise, it is something not exactly correct or wrong with your setup.

biemster commented 1 year ago

Did the tablet shows on the map?

Not yet, my neck of the woods don't have many iDevices around. But I expect it to show up soon, fingers crossed!

today I've tried to flash with 2.5.2 and it did go without any error.

That is very surprising. Did you notice in the LeKit log window any mentions of Spif or sfmod? Nevermind, I have a working setup now as well. Good thing is as well that with this working micropython script it is trivial to make a linux flasher as well. One thing left is to figure out how the firmware files are converted to the three binary files, and we are good to go!

vadimkozhin commented 1 year ago

This is the comparison of the Log output after the flashing the same firmware. Left is 2.5.2, right is 2.5.1a:

image

Good thing is as well that with this working micropython script it is trivial to make a linux flasher as well.

Oh yeah! Sounds promising!

One thing left is to figure out how the firmware files are converted to the three binary files, and we are good to go!

Did you notice, before the flashing LeKit creates .hexf file right next to compiled .hex, and if you take a look to the Log window of LeKit, you've notice, that the .hexf file is actually the firmware, and this is three intel hex parts in it.

It is corresponds with the Log output: image

... And the HEX tab: image

So, inside the .hexf file is the (remaped?) content of .hex, but other two are BOOT, which I guess the bootloader, and XIP#0, which is I have no idea at the moment what.

Need to investigate it further...

upd: I was a bit wrong about content of *.hex... it has different addresses. So LeKit remap .hex data... And the .hexf structure seen in console:

>>    BOOT========0x11002000------0x11002130========
>>     APP========0x11005000------0x11009c1c========
>>   XIP#0========0x11020000------0x110285ec========

And apparently XIP is Execute in place.

biemster commented 1 year ago

Very odd that your 2.5.2 is recognizing the chip correctly, while my chip gives a wrong answer on the rdrev+ command..

The compiler can generate binary files following these instructions: https://developer.arm.com/documentation/ka003023/latest The result is three binary files: JUMP_TABLE, ER_IROM1 and ER_ROM_XIP with sizes very similar to what LeKit is sending over uart. But the content seems still different, so I need to investigate more.

biemster commented 1 year ago

My tag was found by the FindMy network! Awesome stuff. And thanks @vadimkozhin , I probably would have abandoned the 17h66 if you did not mentioned you succeeded and were so helpful!

vadimkozhin commented 1 year ago

My tag was found by the FindMy network! Awesome stuff. And thanks @vadimkozhin , I probably would have abandoned the 17h66 if you did not mentioned you succeeded and were so helpful!

That's great! You did it! :)) Congratulations!

Very odd that your 2.5.2 is recognizing the chip correctly

Now that you've succeeded in flashing, I can wait till 'your' tag model arrived, and confirm or deny LeKit 2.5.2 fail to reflash it. So that's potentially can give us an answer where is the difference -- chip/board or the setup. So as you -- when 'my' model arrives to you.

Anyway, good to have a progress!

The result is three binary files: JUMP_TABLE, ER_IROM1 and ER_ROM_XIP with sizes very similar to what LeKit is sending over uart.

Oh, got it. Thank you! Will take a look on it also in a couple of days.

biemster commented 1 year ago

So this was actually a lot easier than I expected, the difference between the .hex and .hexf is the order of the three ihex files. The hex is XIP - JUMP_TABLE - IROM1, and the hexf is HEXF_HEADER - JUMP_TABLE + IROM1 - XIP. So the only thing left to be investigated is this new HEXF_HEADER as I called it. Hopefully it is the same for all firmwares, and just some standard startup code for the 17h66.

UPD: so I looked at a couple other hexf files, and there are slight differences here and there, in the last 2 or 3 lines of the header. The first byte in the header is also the amount of populated lines at the end of the header (2 or 3 in the examples I have), so there is definitely some firmware dependent initialization going on here. UPD2: Only 2 bytes in the middle of these last lines are different, so that must be some checksum, address or length or something. I'll investigate that further somewhere next days, when my new usb uart arrives. If I can first figure out why there are sometimes 2 and sometimes 3 such lines at the bottom, I'm probably on the horse. UPD3: So the first byte (and the number of populated lines at the bottom of the header) is the number of ihex sections in the file. I should stop updating this comment like this. UPD4: One last update, It's the size in bytes. Now I have everything to make a linux flasher in python! woohoo!

biemster commented 1 year ago

The following code should generate a proper c0, c1 and c2 from a hex file produced by Keil. With a small rewrite of the micropython flasher above to normal linux python3, we have a linux flasher for the st17h66. I'm going to wait for my new usb uart now.

#!/usr/bin/env python3
import sys
if len(sys.argv) != 2:
    print(f'Usage: {sys.argv[0]} <hex firmware file>')
    exit(-1)

xip = bytearray()
jump_table = bytearray()
irom1 = bytearray()

with open(sys.argv[1]) as f:
    # hex file order is assumed to be ER_ROM_XIP - JUMP_TABLE - ER_IROM1
    sections = ['ER_ROM_XIP','JUMP_TABLE','ER_IROM1']
    infiles = [xip,jump_table,irom1]
    infile_current = -1
    inbuf = None
    for line in f:
        if line[7:9] == '04':
            infile_current += 1
            print(f'Start of new ihex section found, assuming {sections[infile_current]}')
            inbuf = infiles[infile_current]
        elif line[7:9] == '00':
            inbuf.extend(bytearray.fromhex(line[9:-3]))

c0 = bytearray() # hexf header

c0.extend(bytearray.fromhex('03000000FFFFFFFF3818FF1FFFFFFFFF')) # initial support only for files with 3 ihex sections
c0.extend(bytearray.fromhex('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'))
c0.extend(bytearray.fromhex('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'))
c0.extend(bytearray.fromhex('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'))
c0.extend(bytearray.fromhex('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'))
c0.extend(bytearray.fromhex('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'))
c0.extend(bytearray.fromhex('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'))
c0.extend(bytearray.fromhex('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'))
c0.extend(bytearray.fromhex('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'))
c0.extend(bytearray.fromhex('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'))
c0.extend(bytearray.fromhex('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'))
c0.extend(bytearray.fromhex('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'))
c0.extend(bytearray.fromhex('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'))
c0.extend(bytearray.fromhex('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'))
c0.extend(bytearray.fromhex('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'))
c0.extend(bytearray.fromhex('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'))
c0.extend(bytearray.fromhex('00000200FFFF000000000211FFFFFFFF'))
c0.extend(bytearray.fromhex('00500000FFFF00000000FF1FFFFFFFFF'))
c0.extend(bytearray.fromhex('14540000FFFF00003818FF1FFFFFFFFF'))

c0[-44:-42] = int.to_bytes(len(xip), 2, 'little') # length ER_ROM_XIP
c0[-28:-26] = int.to_bytes(len(jump_table), 2, 'little') # length JUMP_TABLE
c0[-12:-10] = int.to_bytes(len(irom1), 2, 'little') # length ER_IROM1

c1 = bytearray() # JUMP_TABLE + ER_IROM1
c1.extend(jump_table)
c1.extend(bytearray.fromhex('0' *16))
c1.extend(irom1)

c2 = bytearray() # ER_ROM_XIP
c2.extend(xip)
biemster commented 1 year ago

I've started work to compile the firmware with arm-none-eabi-gcc, in this repo: https://github.com/biemster/st17h66_FindMy (i did not use my fork of your work @vadimkozhin because the code was still zipped there, and contained a lot of unnecessary code) It's based on the SDK v3.1.1.2 low power beacon example, and for now it compiles, but does not link properly yet. Also it is still just the beacon code, and not the FindMy code.

vadimkozhin commented 1 year ago

@biemster That's great news! I will watch the repo.

biemster commented 1 year ago

Getting this to compile in GCC is going to be quite an undertaking: https://github.com/biemster/st17h66_FindMy/issues/1

biemster commented 1 year ago

So I received my CP2102 usb uart, but LeKit still doesn't want to flash this chip! I tried my workaround with the ESP32, now while powering the 17h66 with this new usb uart, and that works. So it is providing enough power for sure, it just does not want to flash. I also received my drop shaped tags, like you have @vadimkozhin , and they are also flashing fine using the ESP32 method. Did you receive some more tags? I now saw 3 different rdrev+ versions of this chip, 0x00124085 6222M005, 0x0012600b 6222M005 and 0x001260eb 6222M005. They all seem to be writable alright.

vadimkozhin commented 1 year ago

Did you receive some more tags?

Yes, I received one batch with the same model that I have previously, and they are flashed just fine. Now I am trying to figure out with one tag from the the second batch how long batt will last. So far almost 3 weeks.

I am still waiting «your version» of а tag to try to flash... I am curious what's the difference in your setup, that you can't flash them directly.

olivluca commented 1 year ago

@vadimkozhin I ordered some tags using your link, in the product photos I can see some test pads in the battery compartment. Are they not usable? (since you had to solder wires on the other side). imatge

vadimkozhin commented 1 year ago

@olivluca Well... I don't have such pads on my tags. Mine (from two batches) looks like this: image

In the flashing instruction tx and rx pins are P9(TX) and P10(RX). You can disassemble the tablet and check, if some of those pads are connected to the TX RX pins. If yes, this will be much easier to flash them in batch.

biemster commented 1 year ago

yeah mine look like the ones @vadimkozhin has as well, no test pads in the battery compartment.

olivluca commented 1 year ago

Since I ordered from the same supplier I guess there will be no pads, At leasy I hope they'll have the ST17H66 :rofl: Aliexpress.... :roll_eyes:

biemster commented 1 year ago

On the linux flasher side, this seems familiar: https://github.com/diskman88/PHY6212/blob/master/applications/seneasy/SRC-PHY6212-EVB/tools/phytool.py

vadimkozhin commented 1 year ago

@biemster Yes, yes... And those chips datasheets are like copy-pasted. There is a memory differences, but pages and illustrations are very similar. Check it out: image

http://wiki.phyplusinc.com/doc/DataSheet/PHY6252_BLE_SoC_Datasheet_v1.2_20210428.pdf https://hoperf.cn/data/upload/portal/20220525/CMT4522_BLE_SoC_Datasheet_v1.31.pdf

May be those SDK's and samples will help you to figure out linker / build problems?

biemster commented 1 year ago

Nice! I didn't know about the hoperf yet. This PHY6212 I mentioned above is actually called 6212 and 6121 in about equal amounts in the documentation :). That SDK is GCC based, and the flashing instructions are mentioning the same LeKit / PhyPlusKit software we use for the 17h66, so as soon as I get that working I'm going to try flashing one of those.

biemster commented 1 year ago

I am curious what's the difference in your setup, that you can't flash them directly.

That's because I'm an idiot.. Somehow in my ESP32 flasher I got the rx and tx pins mixed up (uart = UART(2, tx=16, rx=17)), and then for an even more inexplicable reason I mixed them up again when connecting to the 17h66 so that worked :) But then again I mixed them up when I connected my PC with LeKit to the ESP32 to get the c{0,1,2} bin files in memory, so that worked too! So now when I connect my usb uart directly to the 17h66 I wired it like the ESP setup, and then it did not work. Long story short, this works now and I will push a flasher + firmware to his repo soon.

vadimkozhin commented 1 year ago

Congrats @biemster! The great mystery is solved! :)

biemster commented 1 year ago

Closing this as the firmware + flasher is pushed.

olivluca commented 1 year ago

Sorry to piggy back on this issue, but I cannot find another way to contact both of you: I have a bluetooth remote that doesn't do what I want (it emulates a mouse and I need keyboard emulation), the bt chip (sot16) is filed down, so I cannot see make and model. The seller says it's a Yizhao and, apart from a news item saying that xiaomi has invested in it, I cannot find anything. Per chance you or @vadimkozhin have some information (or pointers on how to find it)?

biemster commented 1 year ago

I found a link where someone traced and drew the circuit of these st17h66 tags by googling the markings on the pcb silkscreen, so that is something you could try. Also when there are testpads just connect an uart, there might be debug messages on it. And without testpads, there are techniques to find pins likely to be uart, although I cannot find a good link for that atm. Also, to reach github only accounts, just make a repo with all the info you have so far, pictures of the board and such, and open an issue there and tag the people that might be willing to help. Most people interested in this stuff enjoy hunting down obscure datasheets and welcome the challenge :).

vadimkozhin commented 1 year ago

Hey @olivluca. It is very hard to guess not seeing anything at all. As @biemster suggested, better to create some repo and put some details there: detailed photos, what you find already etc.

If you asking for some approaches to find a model of the chip, I'll start from Mouser, digikey, LCSC etc. and try to find chips with this exact package, read the datasheets on them for a typical applications, trace the nearest components and may be something pops up. Also, when reading datasheets probing VCC and GND pins, to sort out «wrong» model'. Then, if you have some suspects, probing UART, i2c and everything you can probe.

Hope it helps you a bit :) But it will be not that easy... Also a good start is to look at the oscillator, if there is any. The value of it sometime helps to sort out wrong suspects.