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

CH582M (СH581, CH582, СH583)

il-2

New member
Появилось немного свободного времени, решил написать про встроенную в библиотеку термокомпенсацию LSI. Которая была задумана, но... не работает.
Инициализация библиотеки BLE и TMOS выполняется функцией BLE_LibInit().
При вызове BLE_LibInit() заполняется и передается структура с параметрами инициализации ble_config_t. В этой структуре есть поле - tsCB, в которую следует поместить указатель на функцию измерения температуры. Все, что должна делать эта функция - вернуть 2-байтовое значение кода АЦП канала измерения температуры.
По задумке, эта функция должна вызываться с определенным интервалом (1 секунда - об этом позже...), а дальше сама библиотека отслеживает изменение температуры относительно последнего вызова калибровки LSI (функция калибровки указывается в поле rcCB при инициализации). Если температура изменилась на >7 градусов относительно предыдущей калибровки, то будет вызвана повторная калибровка, и т.д.
Данный алгоритм описан в комментариях исходников, он работает, но... он не запускается.
При вызове BLE_LibInit() в ходе инициализации выполняется вызов tsCB, а потом - тишина.
Я провел титаническую работу :) дизассемблирования и отладки процесса инициализации, и выяснил причину.
Библиотека BLE/TMOS имеет глобальную переменную gTmosPara, в которой хранятся различные данные. В ходе инициализации все поля этой переменной обнуляются, но - это обнуление выполняется в самом конце функции BLE_LibInit()
Однако в ходе инициализации одно из полей gTmosPara заполняется ненулевым значением - кодом АЦП температуры (для этого вызывается tsCB)
В дальнейшем ненулевое значение этого поля проверяется и используется для вызова алгоритма термокомпенсации.
То, что это поле сперва заполняется, а потом обнуляется говорит само за себя о качестве и проработанности кода библиотеки :-(
Чтобы алгоритм термокомпенсации заработал, надо ПОСЛЕ вызова BLE_LibInit() поместить в поле gTmosPara код АЦП температуры (ненулевое значение). После этого алгоритм термокомпенсации начинает нормально работать - вызывать tsCB каждую секунду (не всегда, см. ниже), а при изменении температуры на 7 градусов - вызывать rcCB для выполнения термокомпенсации.
Для включения алгоритма термокомпенсации я после BLE_LibInit() использую такой код:
Для CH57X:
extern uint16_t gTmosPara[]; // BLE Library internal variable, use 3 element (16-bit) for store temperature callback result (see bleConfig_t init structure - pfnTempSampleCB tsCB field)
...
BLE_LibInit(&cfg);
// Workaround for store != 0 value to BLE Library internal variable gTmosPara[3] element (16-bit) - this variable use for store pfnTempSampleCB tsCB callback results
// This element init in BLE_LibInit() by temperature from call pfnTempSampleCB tsCB callback (must return != 0 value) and then internally call TMOS_Init and clear (=0) this value - this is ERROR!!!
// As result, in periodic (1s interval) internal ll_hw_temp_sample() (use for periodic call pfnTempSampleCB tsCB callback) this callback result not processed
// For correct processing temperature samples this gTmosPara[3] elements must contain !=0 value, and pfnTempSampleCB tsCB callback dont return 0!!!
// ll_hw_temp_sample() process temperature meas and call calibration callback pfnLSICalibrationCB rcCB and BLE_RegInit when temperature change by 7grad from previous calibration

gTmosPara[3] = HAL_GetInterTempValue();

Для CH58X и CH59X:
extern uint16_t gTmosPara[]; // BLE Library internal variable, use 4 element (16-bit) for store temperature callback result (see bleConfig_t init structure - pfnTempSampleCB tsCB field)
...
BLE_LibInit(&cfg);
// Workaround for store != 0 value to BLE Library internal variable gTmosPara[4] element (16-bit) - this variable use for store pfnTempSampleCB tsCB callback results
// This element init in BLE_LibInit() by temperature from call pfnTempSampleCB tsCB callback (must return != 0 value) and then internally call TMOS_Init and clear (=0) this value - this is ERROR!!!
// As result, in periodic (1s interval) internal TMOS_TempSample() (use for periodic call pfnTempSampleCB tsCB callback) this callback result not processed
// For correct processing temperature samples this gTmosPara[4] elements must contain !=0 value, and pfnTempSampleCB tsCB callback dont return 0!!!
// TMOS_TempSample process temperature meas and call calibration callback pfnLSICalibrationCB rcCB and BLE_RegInit when temperature change by 7grad from previous calibration

gTmosPara[4] = HAL_GetInterTempValue();

Я привел в коде подробные комментарии, там фигурируют имена функций, которые можно найти в листинге и посмотреть.

Ну и напоследок скажу об еще одной странности алгоритма термокомпенсации. Он вызывается 1 раз в секунду, пока устройство (BLE-Peripheral) находится в состоянии разъединения и вещания. После соединения вызов tsCB начинает выполняться с различными интервалами - от 1 секунды до очень маленьких, т.е. вызовы tsCB могут временами буквально следовать один за другим. Вряд-ли это так задумано - скорее всего это глюк алгоритма. Как понятно из вышенаписанного - это вполне в духе китайских программистов :)

У меня есть в планах отказаться от использования встроенного алгоритма и написать свой, который будет делать то-же самое, но - нормально, без глюков :) Но пока руки не доходят - использую встроенный.

Ну и теперь совсем напоследок - пару лайфхаков использования термокомпенсации:
1. В китайсих примерах функция измерения температуры HAL_GetInterTempValue() выполняет настройку и запуск АЦП, и возвращает код АЦП для канала температуры. Более правильно - чтобы эта функция не запускала АЦП и не ждала окончания преобразования, а просто возвращала бы 2-байтовый код из переменной. А значение этой переменной обновлять отдельно, по событиям TMOS или прерываниям АЦП, не ожидая конца преобразования. Ну и главное - нельзя возвращать 0 значение, иначе встроенный алгоритм термокомпенсации перестанет работать.
2. Если не устраивает диапазон компенсации 7 градусов, можно с помощью нехитрого преобразования сделать любой другой, для этого надо просто отмасщтабировать возвращяемый код АЦП. Я например для получения диапазона 3.5 градуса делаю так:
uint16_t HAL_GetInterTempValue(void)
{
...
adc_data += adc_data - *((uint16_t *)ROM_CFG_TMP_25C); // Increase temperature sensitivity by 2
return (adc_data);

}
т.е. к измеренному коду АЦП добавляю еще дельту и таким образом удваиваю чувствительность
 

pvvx

Активный участник сообщества
По анализу ухода RC генераторов у аналогичных чипов - больший уход счета происходит при переходах Сон - Активность.
Причина банальна - батарейки имеют внутреннее сопротивление (CR2032 к концу - более 100 Ом).
При этом, в активном режиме напряжение питания чипа при передаче падает на 1В составляет 2В.
В режиме сна напряжение поднимается к 2.95В и выше (электрохимия элемента CR2xxx).
Соответственно меняется напряжение питания RC генератора.
В некоторых чипах в режиме сна происходит и отключение DC-DC и переход к LDO, что тоже является изменением напряжения питания RC.
А так-же, в некоторых чипах используется типовая SPI-Flash на 1.8В. Но не все SPI-FLash хорошо работают на 1.8В, и к примеру Telnk для пары марок поднимает внутренне напряжение до 1.9В.
(пп1) Аналогично, для меньшего потребления, если в чипе есть управление питанием, то выходя в сон устанавливают пониженное напряжение для меньшей утечки SRAM, а при пробуждении поднимают до номинала.
Так-же у Telink чипов (и всех других - но в разной степени) есть фича: при включении SoC и работы RF на передачу резко возрастает ток от батареи. Это приводит к хорошему импульсу по всем питаниям чипа и у Telink RC генератор вообще сбивается. Производители всегда любят экономить на конденсаторах в питании, но почему-то не на других элементах :)
Это всё броски питания для RC = сбои и уходы, более чем от температуры.
Для PHY вообще пришлось переписывать алгоритм расчета хода RC. И там стек взят из одной помойки, что и у WCH. Причина - не учтен пп1.
 

pvvx

Активный участник сообщества
Рассчитывать на стабильность питания RC гена нет никакой возможности. Супер LDO имеет обратную связь до 70 дБ, а ток чипа и напряжение колбасит на значительно большее значение...
По этому, во всех чипах при каждом пробуждении производится коррекция RC генератора.
RC генератор для BLE не может тикать менее 32кГц, а чип не может выполнить процедуры инициализации за это время. И у многих чипов есть аппаратный счетчик сколько тиков тактовой частоты между RC тиками.
Даже если такого нет, то после старта основного генератора, по тику RC ставится таймер для определения следующего тика RC, а в это время выполняется другой код, а к событию тика RC он фиксируется... усредняется с прошлыми измерениями...
Всё равно режим активности у WCH не может быть менее 2-х мс - а за это время можно несколько раз произвести учет ухода RC.
И нет никакой нужды измерять напряжения, температуры и т.д.
Но этот алгоритм и колбасит при импульсе провала питания при старте... Но он применен во всех ранее встретившихся чипах, кроме WCH
 

pvvx

Активный участник сообщества
Ну и теперь совсем напоследок - пару лайфхаков использования термокомпенсации:
Во первых требуется удалить вызов компенсации по таймеру (и все другие таймерные события), так как это приводит к отдельному пробуждению SoC для выполнения отдельной тупой задачи. А лишнее пробуждение SoC - это отжирание у батареи лишних более 5 мА на 2..5 мс. Перенести вызов события компенсации RC после или перед передачей маяка, когда SoC уже активен для благих дел. Во время соединения вызов компенсации RC возможен по таймеру, но типично BLE соединения не длятся часами...
И все события должны отрабатываться в период активности SoC только когда BLE стеку необходим процесс приема-передачи. В остальное время все события должны ждать только пробуждения SoC для работы BLE стека.
 

pvvx

Активный участник сообщества
И все события должны отрабатываться в период активности SoC только когда BLE стеку необходим процесс приема-передачи. В остальное время все события должны ждать только пробуждения SoC для работы BLE стека.
Это основной закон для энергоэффективности в BLE и Zigbee, где SoC использует полный sleep, с отключением кварца и части внутренних питаний. Т.к. на пробуждение уходит не менее 1.5 мс и для перехода в сон ещё сотни мкс для самых быстрых вариантов чипов. WCH к таковым не относится. У него время пробуждения SoC больше...
 

pvvx

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

Чтобы не терять 40..60% емкости батареи CR2032 от деградации повышенного тока и просадки напряжения при увеличении внутреннего сопротивления по мере разряда батреи в питание устанавливают расчетный конденсатор с емкостью, рассчитанной для обеспечение работы чипа на десяток мс. Чтобы за время активности чипа в десятку мс напряжение с 3В постепенно падало до 2В.

В итоге активный процесс ограничен временем разряда этого конденсатора. И если этого времени не хватает, то следует отложить действие до следующей зарядки емкости.

Расчеты емкости описаны тут: https://www.ti.com/lit/wp/swra349/swra349.pdf (дубль, т.к. Ti банит РФ)

А так-же следует почитать: Проблемы оборудования и прошивки при использовании микроконтроллеров со сверхнизким энергопотреблением, Джек Гансл
(Но там автор заблуждается в утечках кондеров. Современный нормальный алюминиевый электролитический конденсатор на 16В и 470мкф имеет утечку на 3-х Вольтах не менее сотен наноАмпер, не говоря уже о керамике и танталовых кондерах…)
 

r_o_m_k_a

New member
pvvx, спасибо что выкладываете свои наработки.

По USB с web формой "wso_ina228.htm" отлично работает, красота.

Но, не с мог найти чем подключиться по BLE.
Думал подойдёт "testINA2xx.html" из UBIA.
Но CH582 в BLE как "pp_ch582f" видится, а в UBIA фильтр по "tBLE".

Есть какая-то другая WEB-BLE форма для подключения этого CH582?
 

pvvx

Активный участник сообщества
Есть какая-то другая WEB-BLE форма для подключения этого CH582?
Для Web bluetooth API пока не выкладывал, т.к. всё ещё идет борьба с BLE стеком WCH и имеющиеся решения были пока только для тестов, а не для чего-то другого
 

pvvx

Активный участник сообщества
Есть какая-то другая WEB-BLE форма для подключения этого CH582?
Тест из огрызков от UBIA для CH582F c INA228 c BLE: https://github.com/pvvx/SimplePowerProfiler/tree/main/source/ch583/I2C2BLE/ble_web
Не чищен от ненужных функций и т.д. Как есть, слепил когда тестировал для проверки, что работает с INA228. Но тесты были не в данном html...
 

il-2

New member
По анализу ухода RC генераторов у аналогичных чипов - больший уход счета происходит при переходах Сон - Активность.
Причина банальна - батарейки имеют внутреннее сопротивление (CR2032 к концу - более 100 Ом).
При этом, в активном режиме напряжение питания чипа при передаче падает на 1В составляет 2В.
В режиме сна напряжение поднимается к 2.95В и выше (электрохимия элемента CR2xxx).
Соответственно меняется напряжение питания RC генератора.
В некоторых чипах в режиме сна происходит и отключение DC-DC и переход к LDO, что тоже является изменением напряжения питания RC.
Интересно, это стоит проверить, я как-то не обращал внимание на зависимость от напряжения. Но у меня такой проблемы нет - я не питаюсь от батарейки и не стремлюсь к экономии электроэнергии. Будет случай - посмотрю как зависят коэффициенты калибровки от напряжения (с вкл и выкл DC-DC), и отпишусь.
 

il-2

New member
Рассчитывать на стабильность питания RC гена нет никакой возможности. Супер LDO имеет обратную связь до 70 дБ, а ток чипа и напряжение колбасит на значительно большее значение...
По этому, во всех чипах при каждом пробуждении производится коррекция RC генератора.
RC генератор для BLE не может тикать менее 32кГц, а чип не может выполнить процедуры инициализации за это время. И у многих чипов есть аппаратный счетчик сколько тиков тактовой частоты между RC тиками.
У CH5xx тоже есть счетчик для калибровки LSI, именно он используется в их библиотечной функции калибровки. Только там что-то у них не получилось с аппаратной реализацией, поэтому при калибровке они 1-й результат отбрасывают, и фактически в этой их функции калибровка выполняется 2 раза!!! Я тоже пытался использовать этот счетчик, и тоже без пропуска 1-го результата ничего не получилось. До сути глюка докопаться не удалось, и я просто бросил это дело, стал использовать SysTick.
 

r_o_m_k_a

New member
Тест из огрызков от UBIA для CH582F c INA228 c BLE: https://github.com/pvvx/SimplePowerProfiler/tree/main/source/ch583/I2C2BLE/ble_web
Не чищен от ненужных функций и т.д. Как есть, слепил когда тестировал для проверки, что работает с INA228. Но тесты были не в данном html...
у меня не получается заставить это работать по BLE, хотя по USB всё работает отлично
по BLE получаю графики такого вида (INA228 никуда не подключена, при касании пальцами напряжение немного растёт)

1760295384007.png

смог только посмотреть что принятые данные парсятся одинаково в WEB_USB и ble_web
Код:
test_pp228.html
        if(value.getUint8(1) == 0x3A) {
            for (let i=0;i<len;i+=6) {
                datau.push([cur_idx/smprate, ((value.getInt8(i+4) << 16) | value.getUint16(i+2,true))*kBus+zBus]);
                datai.push([cur_idx/smprate+0.5/smprate, ((value.getUint8(i+7) << 16) | value.getUint16(i+5,true))*kShunt+zShunt]);
                cur_idx++;
                if(cur_idx >= samples) {
                    datau.shift();
                    datai.shift();
                }
            }

//------------------------------------------
pp.js
                } else if (blkid == 0x3A) { // i2c 24bit  data
                    if (typeof this.new_adc_cb == 'function') {
                        if(this.cfg.chnls == 2) {
                            for (var i=0; i<blksz; i+=6) {
                                let du = this.blk[i+2] | (this.blk[i+3]<<8) | (this.blk[i+4]<<16);
                                let di = this.blk[i+5] | (this.blk[i+6]<<8) | (this.blk[i+7]<<16);
                                if(di >= 0x800000)
                                    di -= 0x1000000;
                                this.new_adc_cb(du, di);
                            }

пока не сильно понимаю магию инициализации и запуска ina228 - наверное где-то там надо копать?
Код:
function SendInit(){
    log('Send command #1: StartInit(stop)');
    characteristicCache.writeValue(new Uint8Array([38, 1,
    0, 0, 80, 195, 232, 3, I2CADDR, 0, 255, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, I2CADDR, 1, I2CADDR, 2, I2CADDR, 1, I2CADDR, 2, I2CADDR, 0, 0, 0, 0, 0, 0, 0]))
}   

//--------------------------------------------------
function SendStart(ina_md, ina_id) {
        ........
    if(ina_md == 0x5449 && ina_id == 0x2281) {
        log('INA228 chip registered!');
        ........
        cmd = new Uint8Array([5, 0x38, 1, 3, smprate & 0xff, (smprate>>8)&0xff, 0]);
        log('Send command #1: Set config - Start, I2C CLK 1.5MHz, Read Shunt & Bus, step '+(1000/smprate).toFixed(3)+' ms');
 

pvvx

Активный участник сообщества
Посмотрите лог в UART c CH582F.
И как уже описывал - есть зависимость от BT адаптера.
Но для var smprate = 1851 у меня прокатило на всех адаптерах.
И ещё - в стеке WCH есть бяка - он не реагирует на disсonnect если работает (загружена данными для передачи) функция GATT_Indication().
То есть когда идет поток данных на передачу - отключение невозможно - оно продолжает слать и Web bluetooth API не разрывает соединение ни в какую и никакими командами (и закрытие страницы не поможет).
Только отключение питания CH582F помогает :)
Но если послать команду отключения передачи потока, то CH582F её принимает и отключает передачу. Далее всё работает штатно, включая реакцию на disсonnect.
Т.е. разорвать соединение невозможно, не действуя хитростью :) Стек WCH и Web bluetooth API глух и нем при работе GATT_Indication().
В итоге если происходит сбой связи и переполнение/нарушение внутренних программных FIFO в CH582F - разорвать связь с адаптером возможно только путем отключения ему питания :) :) - смотрите лог UART.
Это ещё предстоит копать и патчить где-то в стеке.
 

pvvx

Активный участник сообщества
А GATT_Notification() использовать в данном стеке невозможно. Оно не сообщает ошибок, даже того, что не смогло переслать, а тупо скипает передачу блока или передает кашу из памяти.
 

pvvx

Активный участник сообщества
Скорее всего приоритет вызова из TMOS задачи GATT_Indication() выше, чем всех других команд стека, кроме приема данных...
И стек WCH рассчитан только на медленные редкие вызовы передачи-приема...
 

pvvx

Активный участник сообщества
у меня не получается заставить это работать по BLE, хотя по USB всё работает отлично
по BLE получаю графики такого вида (INA228 никуда не подключена, при касании пальцами напряжение немного растёт)
По напряжению всё там ок - наводка 50 Гц.
А по току неправильно воспринимает +-значения. Просто не допилен тот пример - требовалось только проверить скорость и что работает с INA228. В остальном там бардак.
---
Пофиксил (был перепутан перевод в значение со знаком для тока и напряжения :) ), обновил git
 
Сверху Снизу