• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Нужна помощь Telink Single Wire

pvvx

Активный участник сообщества
1765396689151.png
Простой JTAG на FTDI чипе за 3 копейки....
 

RedOrm

New member
Там в RAM на исполнение через SWire загружается код загрузчика для процессора TC32 и архитектуры чипа TLSR825x. По старту этот код в чипе включает UART и программатор переходит на работу c UART чипа.
А возможно в принципе прошивка FLASH только через Swire? Без загрузки в RAM TLSR825x загрузчика, который настраивает UART, только передачей всей прошивки по Swire.
 

pvvx

Активный участник сообщества
А возможно в принципе прошивка FLASH только через Swire? Без загрузки в RAM TLSR825x загрузчика, который настраивает UART, только передачей всей прошивки по Swire.
Все остальные представленные программаторы, кроме оригинального EVT, так и делают - работают через Swire обращаясь к SPI контролеру в чипе и SPI уже работает с дополнительным SPI-Flash кристаллом...
Swire имеет доступ ко всем регистрам чипа, к CPU и к RAM. Т.е. ко всему, с чем работает CPU.
CPU для чтения Flash не нужен. На время работы с Flash CPU останавливают, чтобы он одновременно не полез в SPI и не сбил работу.
 

RedOrm

New member
Попробовал по Вашей схеме, эмулировать Swire на UART. Не выходит каменный цветок. Не поделитесь опытом?
В своём проекте делаю так: 1бит Swire = 1 байт UART. Выглядит это так:
photo_2025-12-23_09-41-19.jpg

Для примера подключил рабочий программатор Telink и смотрю осциллограмму как он работает. Расшифровал по осциллографу, что программатор, отправляет что читает. Пробую повторить тоже самое на плате-эмуляторе. Для программатора Telink настроил самую медленную скорость. Подогнал под неё частоту работы UART платы-эмулятора. Сформировал своей платой-эмулятором все импульсы как и программатор Telink. Пробую записать в регистр TLSR9218AER потом прочитать из него - TLSR9218AER не отвечает. Адреса взял актуальные. Единственное отличие - Swire формирует один байт как 5 равных интервалов: для лог. 1 это 4 интервала нуля и один - единица. Получается соотношение 1/4. Для UART такого соотношения не выходит, получается 1,5/4 (одна единичка в UARTе лишняя из-за особенностей реализации).

Как у Вас получилось работать с Swire по UART ?
 

pvvx

Активный участник сообщества
Дык примеры даны и там всё просто посмотреть...
Какие могут быть нюансы:
1. Битрейт приемника у чипа не может синхронизоваться на любую скорость. Там стандартная в мегабитах - около 1 мегабита для TLSR825x и максимум за 2 Мегабита. И опускаться до синхронизации десятикратного делениям baud-rate UART (115200/10 = 11 кбит) не может.
2. USB-UART имеет ограниченный внутренний буфер и USB работает блоками. При переходе на новый блок/буфер будет разрыв в битовом потоке.
3. Максимальный битрейт с неразрывным битовым потоком зависит от USB-UART чипа, ОС, скорости работы вашего компа и самой программы (как она устанавливает параметры для UART). Для большинства китайских чипов это baud-rate в 230400
4. FTDI чипы не применимы.
 

pvvx

Активный участник сообщества
Для программатора Telink настроил самую медленную скорость.
А чип будет отвечать на своей скорости, в зависимости от кварца, т.к. протокол самосинхронизирующийся.

> получается 1,5/4
Чипу пофигу - хоть 1/3
 

pvvx

Активный участник сообщества
Что тут сложного, в перекодировании блока в пакет swire?
Python:
def sws_code_blk(blk):
    pkt=[]
    d = bytearray([0xe8,0xef,0xef,0xef,0xef])
    for el in blk:
        if (el & 0x80) != 0:
            d[0] &= 0x0f
        if (el & 0x40) != 0:
            d[1] &= 0xe8
        if (el & 0x20) != 0:
            d[1] &= 0x0f
        if (el & 0x10) != 0:
            d[2] &= 0xe8
        if (el & 0x08) != 0:
            d[2] &= 0x0f
        if (el & 0x04) != 0:
            d[3] &= 0xe8
        if (el & 0x02) != 0:
            d[3] &= 0x0f
        if (el & 0x01) != 0:
            d[4] &= 0xe8
        pkt += d 
        d = bytearray([0xef,0xef,0xef,0xef,0xef])
    return pkt
А для меньшей скорости, для приема на низкой скорости, уже требуется управление регистром делителя тактовой swire в чипе.
Python:
# encode data (blk) into 10-bit swire words
def sws_encode_blk(blk):
    pkt=[]
    d = bytearray(10) # word swire 10 bits
    d[0] = 0x80 # start bit byte cmd swire = 1
    for el in blk:
        m = 0x80 # mask bit
        idx = 1
        while m != 0:
            if (el & m) != 0:
                d[idx] = 0x80
            else:
                d[idx] = 0xfe
            idx += 1
            m >>= 1
        d[9] = 0xfe # stop bit swire = 0
        pkt += d
        d[0] = 0xfe # start bit next byte swire = 0
    return pkt
# decode 9 bit swire response to byte (blk)
def sws_decode_blk(blk):
    if (len(blk) == 9) and ((blk[8] & 0xfe) == 0xfe):
        bitmask = bit8mask
        data = 0;
        for el in range(8):
            data <<= 1
            if (blk[el] & bitmask) == 0:
                data |= 1
            bitmask = 0x10
        #print('0x%02x' % data)
        return data
    #print('Error blk:', blk)
    return None
По этому всё это глупости и нестабильности. Правильных варианта только два - реализация на ПЛМ с тактовой не менее десяток МГц или встроенный в чип аппаратный драйвер Telink SWire.
 

RedOrm

New member
1. Битрейт приемника у чипа не может синхронизоваться на любую скорость.
Вот в даташите пишут такое:
Скриншот (24.12.2025 13-28-56).jpg

А вот значение swire_clk_div = 0x05 в программе от Telink:
Скриншот (24.12.2025 13-30-10).jpg

Значит ли это, что после reset-а Telink-а нужно выбирать частоту Swire с учётом этого значения (swire_clk_div = 0x05) ? и если решил изменить частоту работы, то сначала при значении swire_clk_div = 0x05, изменить значение swire_clk_div на новое, и только потом менять частоту с учётом нового значения swire_clk_div ?
 

pvvx

Активный участник сообщества
Протокол Telink SWire имеет авто-синхронизацию приемника.

А передатчик работает на фиксированной частоте заданной в данном делите.

По этому прием чипом автоматически синхронизируется, а отвечает он на своей частоте и приемник адаптера синхронизируется под это. В итоге им пофигу на кокой частоте идет запрос и ответ.

Но границы синхронизации приемника распространяются только в область уменьшения частоты и в диапазоне около 10 раз.

Если частота выше – к примеру 2 мегабита, вместо 0.9 с делителем “5”, то надо корректировать данный регистр.

UART работает по другим принципам и не может 100% осуществлять связь по Telink SWire.
 

pvvx

Активный участник сообщества
BDT это не панацея. Это тупенький программатор со своими накопившимися глупостями за время его существования.

И кто вам сказал, или где указано, что это меню сделано для вашего типа чипа?

Там адрес регистра 0x00b0 от серии TLSR82xx.
 

RedOrm

New member
Там адрес регистра 0x00b0 от серии TLSR82xx.
Сам удивляюсь но с 0x00b0 в BDT работает. Хотя по осциллограмме этого числа нет, и программа указывает верный адрес 0x80100C02.
Мой проект на STM заработал. Telink наконец-то стал отвечать и при swire_clk_div = 0x05 и при swire_clk_div = 0x7F . Это был долгий путь.
Сейчас формирую посылки в Telink счётчиком, попробую вернуться к UARTу.
 

RedOrm

New member
Пользуясь случаем. BDT перед отправкой данных на запись, формирует на Swire вот такие импульсы (11 штук):
photo_2025-12-24_14-51-18.jpg

Частота/длительность их не зависит от swire_clk_div и всегда постоянна. Зачем они нужны?
 

pvvx

Активный участник сообщества
Это надо спрашивать у вас.
Не указано какой выбран тип чипа и не видно сколько грамм на клетку :)
У чипов есть и второй вход SWS совмещенный с USB...
 

RedOrm

New member
Берете EVK и программу BDT, соединяете с чипом и осциллографом считываете диаграмму.
Так это было сделано для прошлых серий.
А в своём реверс-инженеринге Вы использовали какой-нибудь декодер пакетов Swire ? или только осциллограф и терпение? Посмотрел сколько пакетов формирует BDT чтобы сделать Unlock FLASH и ужаснулся.
 

pvvx

Активный участник сообщества
А в своём реверс-инженеринге Вы использовали какой-нибудь декодер пакетов Swire ?
Зачем?
Большинство адресов регистров чипа описано в документации.
Swire адресуется аналогично - как и CPU - как если писать в программе.
Посмотрел сколько пакетов формирует BDT чтобы сделать Unlock FLASH и ужаснулся.
При обращении к Flash через SPI процессор делает аналогичные действия.
 

pvvx

Активный участник сообщества
Посмотрел сколько пакетов формирует BDT чтобы сделать Unlock FLASH и ужаснулся.
Python:
    # Flash Write Enable
    rd_sws_wr_addr_usbcom(serialPort, 0x0d, bytearray([0x00]))  # cs low
    rd_sws_wr_addr_usbcom(serialPort, 0x0c, bytearray([0x06]))  # Flash cmd write enable
    rd_sws_wr_addr_usbcom(serialPort, 0x0d, bytearray([0x01]))  # cs high
    # Flash Write reg status
    rd_sws_wr_addr_usbcom(serialPort, 0x0d, bytearray([0x00]))  # cs low
    rd_sws_wr_addr_usbcom(serialPort, 0x0c, bytearray([0x01]))  # Flash cmd wr status
    rd_sws_wr_addr_usbcom(serialPort, 0x0c, bytearray([0x00]))  # data: 0
    rd_sws_wr_addr_usbcom(serialPort, 0x0d, bytearray([0x01]))  # cs high
 

RedOrm

New member
В BDT есть такая штука: "Unlock" (Flash). Как я понял, после прошивки Flash можно заблокировать. Это в проекте настраивается. Соответственно если потребуется прошить Telink с заблокированной Flash, сначала ей нужно будет сделать Unlock. Что BDT и делает при прошивке. Я решил, что штука не будет лишней в моём проекте. Запустил BDT, нажал Unlock, и посмотрел осциллографом, что BDT шлёт по Swire в Telink. А шлёт он очень много. Вот начало:
Address | Data
0x801401E2 | 0xE7
0x80140142 | 0x00
0xC0000000 | 0x0D
inc | 0xA0
inc | 0x07
inc | 0x00 - 19 штук
inc | 0x40
и так далее.
Посмотрел адрес 0xC0000000 - это оперативка. Данных много, и теперь думаю как их декодировать, чтобы повторить в своём проекте этот же функционал.
Или это всё лишнее и для прошивки достаточно сразу писать прошивку со стартового адреса?

В вашем проекте этого было достаточно для Unlock Flash ? :
Python:
# Flash Write Enable
rd_sws_wr_addr_usbcom(serialPort, 0x0d, bytearray([0x00])) # cs low
rd_sws_wr_addr_usbcom(serialPort, 0x0c, bytearray([0x06])) # Flash cmd write enable
rd_sws_wr_addr_usbcom(serialPort, 0x0d, bytearray([0x01])) # cs high
# Flash Write reg status
rd_sws_wr_addr_usbcom(serialPort, 0x0d, bytearray([0x00])) # cs low
rd_sws_wr_addr_usbcom(serialPort, 0x0c, bytearray([0x01])) # Flash cmd wr status
rd_sws_wr_addr_usbcom(serialPort, 0x0c, bytearray([0x00])) # data: 0
rd_sws_wr_addr_usbcom(serialPort, 0x0d, bytearray([0x01])) # cs high
B как понимать строчку: rd_sws_wr_addr_usbcom(serialPort, 0x0d, bytearray([0x00])) # cs low
0x0d - это адрес в памяти Telink?
bytearray([0x00] -это один байт данных 0x00,который будет записан по адресу 0x0d?
 

pvvx

Активный участник сообщества
В BDT есть такая штука: "Unlock" (Flash). Как я понял, после прошивки Flash можно заблокировать. Это в проекте настраивается. Соответственно если потребуется прошить Telink с заблокированной Flash, сначала ей нужно будет сделать Unlock. Что BDT и делает при прошивке. Я решил, что штука не будет лишней в моём проекте. Запустил BDT, нажал Unlock, и посмотрел осциллографом, что BDT шлёт по Swire в Telink. А шлёт он очень много.
Он может слать код для исполнения CPU.
Это BDT и там всё очень медленно... А оптимизацию по скорости там решили сделать путем загрузки исполняемого кода и передачи ему команд через RAM.
В вашем проекте этого было достаточно для Unlock Flash ?
Это прямая работа с SPI, подключенного к Flash в TLSR825x.

B как понимать строчку: rd_sws_wr_addr_usbcom(serialPort, 0x0d, bytearray([0x00])) # cs low
0x0d - это адрес в памяти Telink?
bytearray([0x00] -это один байт данных 0x00,который будет записан по адресу 0x0d?
Да. Это запись в регистр контроллера SPI для Flash.
По адресу 0x000d пишется значение 0x00.

SDK\components\drivers\8258\spi_i.h
C:
/**
 * @brief     This function servers to set the spi low level.
 * @param[in] none
 * @return    none
 */
_attribute_ram_code_ static inline void mspi_low(void){
    reg_mspi_ctrl = 0;
}
 
Сверху Снизу