• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Таймеры RTL8711

Seeker

New member
Согласно имеющейся здесь документации, минимальный интервал времени таймера 32 микросекунды? Что есть 31.25 кГц, а это мало. Поправьте если не так.
 

Вложения

pvvx

Активный участник сообщества
Согласно имеющейся здесь документации, минимальный интервал времени таймера 32 микросекунды? Что есть 31.25 кГц, а это мало. Поправьте если не так.
У GTimer 32,768 кГц (30.5 us) (hal_timer.h):
[HASHTAG]#define[/HASHTAG] GTIMER_CLK_HZ (32768)
[HASHTAG]#define[/HASHTAG] GTIMER_TICK_US (1000000/GTIMER_CLK_HZ)
 

Seeker

New member
Спасибо за более полный ответ. К сожалению 32кГц это всё же детский сад для создания ик NEC сигналов. Необходимо было ровно 76кГц.
 

pvvx

Активный участник сообщества
Спасибо за более полный ответ. К сожалению 32кГц это всё же детский сад для создания ик NEC сигналов. Необходимо было ровно 76кГц.
Есть ещё _LONG_CALL_ u32 HalDelayUs(u32 us) в ROM.
Но модуля пока нет и не разбирался к кому он привязан...
 

pvvx

Активный участник сообщества
@Seeker - HalDelayUs() тоже обращается к gtimer :( :
Код:
00000898 <HalDelayUs>:
     898:    f241 0385     movw    r3, #4229    ; 0x1085
     89c:    b570         push    {r4, r5, r6, lr}
     89e:    f240 3518     movw    r5, #792    ; 0x318
     8a2:    f6c0 0342     movt    r3, #2114    ; 0x842
     8a6:    f2c1 0500     movt    r5, #4096    ; 0x1000 -> 0x10000318 -> структура HalTimerOp
     8aa:    fba3 2300     umull    r2, r3, r3, r0
     8ae:    1ac6         subs    r6, r0, r3
     8b0:    eb03 0656     add.w    r6, r3, r6, lsr #1
     8b4:    0936         lsrs    r6, r6, #4
     8b6:    f04f 0001     mov.w    r0, #1
     8ba:    68ab         ldr    r3, [r5, #8]; HalTimerOp->HalTimerReadCount
     8bc:    bf08         it    eq
     8be:    4606         moveq    r6, r0
     8c0:    4798         blx    r3
     8c2:    4604         mov    r4, r0
     8c4:    68ab         ldr    r3, [r5, #8]; HalTimerOp->HalTimerReadCount 
     8c6:    2001         movs    r0, #1
     8c8:    4798         blx    r3;  gtimer_read_tick(1)
     8ca:    4284         cmp    r4, r0
     8cc:    eba4 0300     sub.w    r3, r4, r0
     8d0:    bf34         ite    cc
     8d2:    f103 30ff     addcc.w    r0, r3, #4294967295
     8d6:    1a20         subcs    r0, r4, r0
     8d8:    42b0         cmp    r0, r6
     8da:    d9f3         bls.n    8c4 <HalDelayUs+0x2c>
     8dc:    2000         movs    r0, #0
     8de:    bd70         pop    {r4, r5, r6, pc}
[code][/SPOILER]
 

Olegator

New member
Выглядит как грусть печаль, из PWM больше 16Khz не выжать.
Код:
#define MAX_PWM_CTRL_PIN        4
// the minimum tick time for G-timer is 61 us (clock source = 32768Hz, reload value=1 and reload takes extra 1T)
//#define GTIMER_TICK_US            31   // micro-second, 1000000/32768 ~= 30.5
#define MIN_GTIMER_TIMEOUT    61  // in micro-sec, use this value to set the g-timer to generate tick for PWM. 61=(1000000/32768)*2
#define PWM_GTIMER_TICK_TIME    61  // in micro-sec, use this value to set the g-timer to generate tick for PWM. 61=(1000000/32768)*2
Как вариант - юзай UART, они в HAL кажется обмазали драйвер UART возможностью передавать IR коды, вот кусок hal_uart.c

Код:
// Pre-Defined Supported Baud Rate Table for CPU 166 MHz
const u32 DEF_BAUDRATE_TABLE[] = {
        110,     300,     600,    1200,
       2400,    4800,    9600,   14400,
      19200,   28800,   38400,   57600,
      76800,  115200,  128000,  153600,
     230400,  380400,  460800,  500000,
     921600, 1000000, 1382400, 1444400,
    1500000, 1843200, 2000000, 2100000,
    2764800, 3000000, 3250000, 3692300,
    3750000, 4000000, 6000000,

      56000,  256000,

    // For UART to IR Carrier
      66000,   72000,   73400,   76000,
      80000,  112000,

    // End of the table
    0xffffffff
};
 

pvvx

Активный участник сообщества
Выглядит как грусть печаль, из PWM больше 16Khz не выжать.
Пишут, что переферия по регистрам совпадает с описанием от http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/quark-d2000-datasheet.pdf :)
Но там эти таймеры тактируются от CLK_CPU - 32 MHz.
Скорее всего у RTL есть переключатель тактирования таймеров на CLK_CPU... Но будет больше жрать и надо переписать пару файлов в SDK...

Есть ещё бяка - тактирование от OSC32K содержит какую-то калибровку (
[HASHTAG]#ifdef[/HASHTAG] CONFIG_TIMER_MODULE ... VOID En32KCalibration(VOID) ), т.е. таймер может 'плыть', если в чипе используется простой генератор, а не кварц... :(
 
Последнее редактирование:

Olegator

New member
Пишут, что переферия по регистрам совпадает с описанием от http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/quark-d2000-datasheet.pdf :)
Но там эти таймеры тактируются от CLK_CPU - 32 MHz.
Скорее всего у RTL есть переключатель тактирования таймеров на CLK_CPU... Но будет больше жрать и надо переписать пару файлов в SDK...
32Mhz больше похоже на правду, согласен - давно уже не видел MCU с таким огромным тиком таймера.
 

pvvx

Активный участник сообщества
32Mhz больше похоже на правду, согласен - давно уже не видел MCU с таким огромным тиком таймера.
В 'Амёбе' могли привязать такт таймера и к RTC источнику... SDK позволяет менять тактовую CPU и всякие PLL (что необходимо для WiFi), а тогда при изменении CLK_CPU возможна завязка с таймерами, да чип будет горячее и выбрали такт от 32K :(
Пока не нашел и счетчика тиков CPU... В данной модели ARM он обычно не штатный...
 

Olegator

New member
Неужели они ARM-овский SysTick из ядра выпилили?

Уже не терпится получить посылку с модулями, что бы руками пощупать, что они там накрутили :)
 

pvvx

Активный участник сообщества
Неужели они ARM-овский SysTick из ядра выпилили?
Да, sdk-ameba1-v3.4b3_without_NDA\component\soc\realtek\8195a\fwlib\rtl8195a\rtl8195a.h:
Код:
#define __Vendor_SysTickConfig         1         /**< Vendor specific implementation of SysTickConfig is defined */
-> в sdk-ameba1-v3.4b3_without_NDA\component\soc\realtek\8195a\cmsis\core_cm3.h
отключен [inline]__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)[/inline]
 
Последнее редактирование:

pvvx

Активный участник сообщества
Есть 32-х битный счетчик тактов CPU в +.
Без включенной отладки [0хe0001004] он выключен:
Код:
#ATSD=E0001000
[ATSD]: _AT_SYSTEM_DUMP_REGISTER_
E0001000:    40000000    40000000    40000000    40000000
Инициализируем:
Код:
             CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; // открыть доступ
            if(!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) { // уже включен?
                DWT->CYCCNT = 0; // обнулить и запустить
                DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; // запустить счет
            }
            // Сравнение с HalDelayUs(10000);
                uint32_t t0 = DWT->CYCCNT;
                HalDelayUs(10000);
                printf("t = %u\r\n", DWT->CYCCNT-t0);
 

shangdawei

New member
tutorials:f401_f429_disco:cycle_counter:implementation [EmBlocks]

Код:
/*
**
**                           CycleCounter.c
**
**
**********************************************************************/
/*
   Last committed:      Rev 1.0
   Last changed by:     Olavi Kamppari
   Last changed date:   Feb 17, 2014
   Platform:            STM32F4
   Processor:           F429 and F401
   Board:               STM32F429I/STM32F401C Discovery
   Description:         Provide access to core debugger cycle counter.
                        the counter is incremented at CPU clock speed
                        - 180 MHz with F429
                        - 84 MHz with F401
   Note:                This counter is not used with EmBlocks GDB, but
                        could be used in some other M4 IDE.
**********************************************************************/
#include "common.h"
#include "CycleCounter.h"
uint32_t    prevCount;
void        inline initCycleCounter() {
    prevCount           = 0;
    CoreDebug->DEMCR   |= CoreDebug_DEMCR_TRCENA_Msk;   // Enable core debugger for tracing
    DWT->CYCCNT         = 0;                            // Reset debugger trace counter
    DWT->CTRL          |= DWT_CTRL_CYCCNTENA_Msk;       // Enable cycle counter
}
uint32_t    inline currentCount() {
    prevCount           = DWT->CYCCNT;
    return prevCount;
}
uint32_t    inline deltaCount() {
    return DWT->CYCCNT-prevCount;
}
uint32_t    inline deltaMicros() {
    return (DWT->CYCCNT-prevCount)/clockFreqMHz;
}
uint32_t    inline measureMicros(uint32_t startCount, uint32_t endCount) {
    return (endCount-startCount)/clockFreqMHz;
}
uint32_t    inline measureNanos(uint32_t startCount, uint32_t endCount) {
    return (TenTo3*(endCount-startCount))/clockFreqMHz;
}
void        busyWaitMicros(uint32_t micros) {
    assert_check(micros<=MAX_MICROS,"Too large delay in microseconds");
    currentCount();
    while (deltaMicros()<micros);
}
void        busyWaitMillis(uint32_t millis) {
    assert_check(millis<=MAX_MILLIS,"Too large delay in milliseconds");
    busyWaitMicros(millis*TenTo3);
}
void        busyWaitSeconds(uint32_t seconds) {
    assert_check(seconds<=MAX_SECONDS,"Too large delay in seconds");
    busyWaitMicros(seconds*TenTo6);
}
 

shangdawei

New member
Код:
extern uint32_t SystemCoreClock;
void CycleCounterInit( void )
{
  if ( !( CoreDebug->DEMCR &CoreDebug_DEMCR_TRCENA_Msk ))
  {
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    DWT->CYCCNT = 0;
    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
  }
}
void CycleCounterDelayUs( uint32_t Us )
{
  int32_t Done = DWT->CYCCNT + Us * ( SystemCoreClock / 1000000 );
  while ( ( ( int32_t )DWT->CYCCNT - Done ) < 0 )
    ;
}
 

pvvx

Активный участник сообщества
Неужели они ARM-овский SysTick из ядра выпилили?
Он работает на тактирование RTOS и корректируется на режимы Sleep. Но там нашлись странности:
Все загружаемые счетчики и коррекции в RTOS (счет тиков) рассчитаны только на 166 MHz CLK CPU, а модуль RTL00 при загрузке с Flash в sdk-ameba-rtl8710af-v3.5a_without_NDA_GCC_V1.0 от PADI IoT Stamp Resources – PINE64 запускает код с 83MHz CLK CPU. При этом при перезагрузке после разных sleep и загрузке с RAM (отладка) стартует с 166MHz. Короче у pine64 в SDK ошибки... но они корректируемы, т.к. уже "реверс" основных закрытых частей библиотек у меня завершен (кроме низкого уровня библиотеки wifi - изменения её пока не требуются).
Часть с разными CLK CPU уже переписал для всех HAL и т.д.
У меня оно теперь устанавливается в platform_autoconf.h:
#define CONFIG_CPU_CLK 1
#define CONFIG_CPU_166_6MHZ 1 // RUN/IDLE ~62/21 mA
//#define CONFIG_CPU_83_3MHZ 1 // RUN/IDLE ~55/15 mA
//#define CONFIG_CPU_41_6MHZ 1 // RUN/IDLE ~51/11 mA
...
//#define CONFIG_CPU_4MHZ // IDLE ~8 mA
(Замеры питания даны при включенном приеме WiFi в режиме Station)
При 10MHz модуль как-то ещё работает c WiFi :)
 
Последнее редактирование:

KomX

Member
Где можно почерпнуть информацию о таймерах (TIMERx)?
В частности интересует информация о доступе к регистрам, их назначению, структуре и незанятостью операционкой.
 
Последнее редактирование:

pvvx

Активный участник сообщества
Где можно почерпнуть информацию о таймерах (TIMERx)?
В частности интересует информация о доступе к регистрам, их назначению, структуре и незанятостью операционкой.
Описание регистров таймеров смотрите тут:
http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/quark-d2000-datasheet.pdf
Базовый адрес в RTL00MP3/hal_platform.h at master · pvvx/RTL00MP3 · GitHub
описание остальных регистров в RTL00MP3/rtl8195a_timer.h at master · pvvx/RTL00MP3 · GitHub
ОС использует всего один таймер. Mbed api другой...

Если включен блок WiFi, то работает 64-битный аппаратный счетчик микросекунд TSF:
Код:
#include "hal_com_reg.h"

#define ReadTSF_Lo32() (*((volatile unsigned int *)(WIFI_REG_BASE + REG_TSFTR)))
#define ReadTSF_Hi32() (*((volatile unsigned int *)(WIFI_REG_BASE + REG_TSFTR1)))

LOCAL uint64_t get_tsf(void)
{
    return *((uint64_t *)(WIFI_REG_BASE + REG_TSFTR));
}
 
Последнее редактирование:

KomX

Member
@pvvx, благодарю за информацию.

Структура регистров в rtl8195a_timer.h соответствует описанию 1-го таймера в D2000 (их в доках всего 2).
Обращения из кода к структуре через макросы HAL_TIMER_READ32(addr) и HAL_TIMER_WRITE32(addr, value) в основном происходит через функцию HalTimerInitRtl8195a_Patch(), в которой в качестве адреса используется TIMER_INTERVAL*pHalTimerAdap->TimerId + смещение требуемого регистра.
TIMER_INTERVAL*pHalTimerAdap->TimerId для 8 значений TimerId (0-7) даёт 8 адресов:
0x40002000 для TimerId=0; //RTC
0x40002014 для TimerId=1; //
0x40002028 для TimerId=2; // PWM_3
0x4000203c для TimerId=3; // PWM_0
0x40002050 для TimerId=4; // PWM_1
0x40002064 для TimerId=5; // PWM_2
0x40002078 для TimerId=6; //
0x4000208c для TimerId=7. //
Дамп регистров снятый в JLink при инициализации мною PWM сигнала на PC_2 верно отображает регистры для TimerId=5, а также инициированный с TimerId=1 таймер. При этом вся структура таймерных регистров повторяется с шагом 0x100 (4 блока).

В принципе это всё, что нарыл в SDK. Это ни на грамм не приблизило меня к аппаратному управлению состоянием pwm пина от таймера в режиме PWM Mode.
Поэтому, если это возможно, хотелось бы получить помощь в конфигурации предделителя(-лей) таймеров и как выходы таймеров подключить в пинам?
Очень хочется иметь аппаратную реализацию 2-х выходов с импульсом в 1 мксек следующим с частотой от 50 Гц до 50 кГц.
 
Сверху Снизу