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

Ногодрыг на rtl

АндрейМ

New member
Доброго вечера!
Переношу 1wire на rtl, обычный ногодрыг. Но в отличии от esp и обычных ардуинок возникает случайный сбой считывания. Связан он непонятно с чем. Gpio как библиотечный, так и свой volatile - стайл, разница несущественная. Менял пины - не помогло.
В связи с чем вопросы
- как на rtl запретить прерывания?
- для задержек использую wait_us, правильно ли это?
- в примитивном 1wire есть задержки в 2, 10, 70 и 400 мкс, есть ли в rtl возможность настолько короткие таймеры использовать?

Вообще нужны любые идеи
 

Юрий Ботов

Moderator
Команда форума
У автора есть понимание того, что на rtl кроме его программы крутится еще и freertos? Собственно взять и запретить из программы все прерывания... ну как бы не комильфо. Автору придется вникнуть в эту особенность и соответственно скорректировать свою программу, с учетом того факта что wait_us дает результат не совсем корректный, то есть задержка БОЛЬШЕ или равна указанной в функции. Лучше, но сложнее напрямую с таймером. Пардон за поучительный тон. Не хотел.
 

pvvx

Активный участник сообщества
Достаточно было этого. Остальное сообщение "про осень"
Вместо таймера можно использовать любое внутренне устройство, дающее прерывание. Даже UART на передачу символа, при отключенных ножках на GPIO в MIX i/o.
Задержка в wait_us, в неоф.SDK, вычисляется с дискретом в CLK CPU, через счетчик тактов CPU.
https://esp8266.ru/forum/threads/tajmery-rtl8711.1522/#post-24381
Если WiFi включен, то доступен 64-х битный аппаратный счетчик с шагом в 1 us.
Низкочастотное тактирование таймеров в RTL используется для уменьшения потребления, иначе 8 аппаратных таймеров на МГц-ах вызовут дополнительное потребление в несколько мА и режимы wawelock и прочие будет ни к чему.
Задержки у 1wire между стробами ни о чем не говорят, когда надо снимать значение передаваемого бита... Есть аппаратное прерывание по фронту GPIO.
РадиоКот :: Интерфейс 1-Wire.
Для обращения к GPIO на ARM используют Метод "Bit Banding"
RTL00MP3/bitband_io.h at master · pvvx/RTL00MP3 · GitHub
RTL00_WEB/bitband_io.h at master · pvvx/RTL00_WEB · GitHub
Чтобы он заработал с чистого старта, необходимо инициализировать контроллер GPIO (подать на него питание, CLK и установки пина).

Долой Arduin-щиков из RTL-ок!
У Arduino наступает осень со всеми современными WiFi-SoC :) Любимая её пользователями void loop() на них содержит только [inline]return[/inline] или [inline]delay(∞);[/inline]. Т.е. всё заученное и наработанное на ESP8266, как и на 8-ми битных однозадачных MCU далее не применимо.
 
Последнее редактирование:

pvvx

Активный участник сообщества
А что мешает организовать свой цикл в void setup?
Я без подковырки - действительно хочу разобраться...
К примеру нарушение атомарности и многое другое, что присуще многопоточным/многоядерным системам.
По тому у концепций Arduino наступает ядерная Зима. Когда у WiFi SoC появиться возможность содержать виртуальную машину для задач Arduino (дистрибутив SDK будет содержать десятки ГегоБайт), то у неё может опять наступить весна для домочадцев умеющих мыслить только линейно :)
А пока используйте интерпретаторы типа Java, Python и подобные...
Вы можете указать, где в Unix есть аналог Loop()? :) Или в Wind-е - операция вывода в регистр порта для "ногодрыга"? (её можно задать ни нижнем уровне привилегий драйвера CPU, и по обращению к порту в аsm проц x86 будет вызывать "протектед" и после разбора события его вызвавшего, будет перенаправлен со скорректированным запросом к дровам системы и в итоге, перелопатив с десяток уровней защит системы и к сотням МБ кода, это всё вернет в "регистр" CPU значения из виртуального порта. Можете всё это проверить с отмершим LPT портом в виртуальной машине - т.е. она уже работает как интерпретатор устаревших команд CPU :) )
И это всё уже было десятки лет назад, при появлении Wind-ы c WIN32.
Чтобы обратиться к порту LPT напрямую, к примеру для программирования с LPT Pic MCU или карты SmartMedia, требовалось описать драйвер и разрешить привилегии.... При этом если прямо дергать ноги LPT = ничего хорошего и скорость ограничена в стандартные 8 MHz тактирования самой аппаратной части LPT, но у него есть и режим EPP, что дает увеличение скорости его "ногодрыга" :)
Код:
        #define         OUTPORT( p, v )                 _outp( (USHORT)p, (UCHAR)v )
... if defined(_WIN32)
static void _outp(unsigned short p, unsigned char v) {
  asm {
    mov dx, p
    mov al, v
    out dx, al
  }
....
        #if defined(__WINNT__)
                if (wvWINNT == GetWindowsVariant())
                {
                  char driverPath [_MAX_PATH];
                  GetModuleFileName(0, driverPath, sizeof (driverPath));
                  char *lastslash = strrchr (driverPath,'\\');
                  if (lastslash) ++lastslash;
                  else lastslash = driverPath;
                  *lastslash = 0;
                  strcat (driverPath, SSYSNAME );

                  ExtractFile(SSYSNAME);

                  if (InstDrv_StartDriver (driverPath, SDRVNAME ))
                  {
                        DirectNT S_directNT;
                        if (!S_directNT.IsValid()) {
                                LogError( CSMIO_ERROR_IOPRERM, "couldn't open Driver %s", DirectNTDrvName );
                                return TRUE;
                        }
                        if (!S_directNT.GiveIOPermissions (m_iPortBase+0x400, m_iPortBase+0x402)) {
                                LogError( CSMIO_ERROR_IOPRERM, "couldn't get io permissions [0x%X-0x%X]", m_iPortBase+0x400, m_iPortBase+0x402 );
                                return TRUE;
                        }
                        OUTPORT(m_iPortBase+0x402,0x00);
                        UCHAR btest = INPORT(m_iPortBase+0x402);
                        if ((btest&0xE0) != 0x00){
                                LogError( CSMIO_ERROR_IOPRERM, "LPT(0x%03X) port config - Not set Base Mode -> port(0x%03X) = 0x%02X.", m_iPortBase, m_iPortBase+402 , btest );
                                return TRUE;
                                                }
                        if (!S_directNT.GiveIOPermissions (m_iPortBase, m_iPortBase+7)) {
                                LogError( CSMIO_ERROR_IOPRERM, "couldn't get io permissions [0x%X-0x%X]", m_iPortBase, m_iPortBase+7 );
                                return TRUE;
                        }
                        // InstDrv_RemoveDriver (SDRVNAME);
                  }
                  else
                  {
                     // ExtractFile(SSYSNAME);
                      LogError( CSMIO_ERROR_IOPRERM, "couldn't open Driver %s", driverPath );
                      return TRUE;
                  }
                }

        #endif

        PGMOFF();
        OUTPORT(m_iPortControl, 0x00);
        OUTPORT(m_iPortStatus, 0x00);
        PGMOFF();

В итого:
//   Программатор PicPgm (LPT1 Base Mode).
//  Тестовая система:
//   Athlon 1100Meg ABIT KT7A-RAID (default)
//   Max EPP 559388byte/s = 546Kbyte/s
....
//   Программатор SmartMedia (LPT1-EPP).
//  Линейное максимальное:
//   Запись 36 сек 16Meg
//   Чтение 32 сек 16Meg
//   Стирание 4 сек 16Meg
//  Полное итоговое (со всем интерфейсом на один файл):
//   Запись файла 77s (16Meg) 212Kbyte/s
//   Чтение файла 34s (16Meg) 494Kbyte/s
//   Стирание   2.41s (16Meg) 6.6Mbyte/s
//  Тестовая система:
//   Athlon 1100Meg ABIT KT7A-RAID (default)
//   Max EPP 559388byte/s = 546Kbyte/s
На современной Win-де немного по другому, но принцип тот-же... :)
В итого, ногодрыг на MCU Intel 386 EX выходил со скоростью тактирования торчащей из него шины, а на мамках - в сотни и тысячи раз медленнее. Там путь к потрохам LTP = PCI шине и аппаратному эмулятору ISA шины :) и пока туда добирается запрос и вернется ответ, CPU уже перелапатит несколько Гегобайт других задач. А в промежуточной редакции PCI, до появления отложенных транзакций, обращение к LPT вызывало полную остановку "ГегаГерцового" CPU с опустошением всех
его кэшей. :)

Это к тому, что можно всё, но есть в этом смысл?...
 
Последнее редактирование:

АндрейМ

New member
Вы можете указать, где в Unix есть аналог Loop()? :) Или в Wind-е - операция вывода в регистр порта для "ногодрыга"? (её можно задать ни нижнем уровне привилегий драйвера CPU, и по обращению к порту в аsm проц x86 будет вызывать "протектед" и после разбора события его вызвавшего, будет перенаправлен со скорректированным запросом к дровам системы и в итоге, перелопатив с десяток уровней защит системы и к сотням МБ кода, это всё вернет в "регистр" CPU значения из виртуального порта. Можете всё это проверить с отмершим LPT портом :) )
Сумбурно как-то. Я помню те времена, когда в линуховых ядрах небыло NAPI, а еще под досом писал ногодрыг для POCSAG 512 и 1200 бод.
Но сейчас скорости-то совсем другие, все сводится к событийной модели - аппаратка собирает данные, передает в рам, ставит событие в очередь. Потом та-же хрень на уровне драйвера и системы ввода-вывода ядра. А итогом становится эффективность (E)POLL/SELECT механизмов. Но писать поллинг логику чистый мазохизм.
Ногодрыг заработал, причем оказалось достаточно запретить прерывания на чтение на 13 микросекунд и 5/60 мс при записи. Подсмотрел в дровах вайфая.
Задержки у 1wire между стробами ни о чем не говорят, когда надо снимать значение передаваемого бита... Есть аппаратное прерывание по фронту GPIO.
Спасибо, почитаю.
 

sharikov

Active member
Сумбурно как-то. Я помню те времена, когда в линуховых ядрах небыло NAPI, а еще под досом писал ногодрыг для POCSAG 512 и 1200 бод.
Вы бы еще Электронику-60М вспомнили.
Сейчас второе десятилетие XXI века.
Возьмите Winows 10 с многогигагерцовым многоядерным процессором и напишите ногодрыгом обмен 1-wire.
Или возьмите Linux на аналогичном железе и так же ногодрыгом из userspace реализуйте обмен 1-wire.
 

pvvx

Активный участник сообщества
Сумбурно как-то.
А я не имею желания и обучения на степень литератора, излагателя на простой язык сложных вещей. Как раз тут и учусь понемногу как это описывать на "банках", для "домочадцев" не знающих истории и кругов развития электроники... :) Как видим вы поняли смысл, на что и было рассчитано.
Вы бы еще Электронику-60М вспомнили.
Сейчас второе десятилетие XXI века.
Была и такая, и на неё писал :p
Как раз недавно перебирал древние бумажки:
IMG_6946.jpg
А что "второе десятилетие XXI века" изменило? (ввело новые названия старым ?)
Вон вы не в состоянии сами переделать под себя код простого WiFi-SoC и всё нудите, что где-то есть уже готовое и подходящее для решений вашей задачи за большую сумму в $.
А тут обучение и круги ада, т.е. истории :) И для обучения, всегда важна альтернатива.
Вы пока не смогли предоставить альтернативное решение для "начинающих", а я и не собираюсь, только так, что само случайно выпадет и вылезет в ходе хобби с теми-же RTL-ками.

Возможно, по причине того, что “новички” не разбираются в специализированном языке, они и не могут понять смысла и сами реализовать требуемые алгоритмы, что приводит к тупому копированию и развитию недобросовестной рекламы. Я не вижу проблем зашевелить какой торчащей ножкой из PC, хоть на шине разъема CrosFire с ужасной для вас скоростью :)
---
---
---
---
О - пока ещё никто не выкладывал максимальную скорость работы GPIO на RTL-ках через GPIO контроллер. Т.е. можно делать ставки - 10 MHz или ? :)
У ESP8266 - строб контроллера GPIO = кварцу (26 MHz), а у RTL-ок серии "A" = ?
DMA память-память и регистр-память у него есть.
 
Последнее редактирование:

АндрейМ

New member
Сейчас второе десятилетие XXI века.
Возьмите Winows 10 с многогигагерцовым многоядерным процессором и напишите ногодрыгом обмен 1-wire.
Или возьмите Linux на аналогичном железе и так же ногодрыгом из userspace реализуйте обмен 1-wire.
Псст, только ни кому не говорите! Уже есть дрова 1вайр под винду на usb-com ttl. Лет 10 уже.
Были ещё такие страшные люди - советские программисты, у них ракеты стаей летали и спутники на килобайтах ОЗУ. Так и сейчас мало что поменялось.
А в моем посте ключем было napi, все эти юзерспейсы совсем другая тема.
 

АндрейМ

New member
Для обращения к GPIO на ARM используют Метод "Bit Banding"
Код:
        // paddr = 0x42000000 + (0x40001000 + 0x0c * (ippin >> 5) - 0x40000000) * 32 + ((ippin & 0x1f) * 4);
        paddr =  BitBandPeriAddr((void *)(GPIO_REG_BASE + GPIO_PORTB_DR * (ippin >> 5)),  ippin & 0x1f);
Это стеб такой?
-----
RTL00_WEB/bitband_io.c at 3e8794a4a369a11ca940d26cbf2a28c053428908 · pvvx/RTL00_WEB · GitHub
Тут вместо GPIO_PORTB_DR нужен GPIO_PORTB_DDR, и переименовать val в direction
 
Последнее редактирование:

pvvx

Активный участник сообщества
Код:
        // paddr = 0x42000000 + (0x40001000 + 0x0c * (ippin >> 5) - 0x40000000) * 32 + ((ippin & 0x1f) * 4);
        paddr =  BitBandPeriAddr((void *)(GPIO_REG_BASE + GPIO_PORTB_DR * (ippin >> 5)),  ippin & 0x1f);
Это стеб такой?
-----
RTL00_WEB/bitband_io.c at 3e8794a4a369a11ca940d26cbf2a28c053428908 · pvvx/RTL00_WEB · GitHub
Тут вместо GPIO_PORTB_DR нужен GPIO_PORTB_DDR, и переименовать val в direction
Вы думаете, что я помню, что хотел там написать и как применить? :)
Данная функция была написана для неопубликованного драйвера RS-485 к Modbus для переключалки направления внешнего аппаратного драйвера :p
rs485cfg.bitband_dir = HardSetPin(PC_0, PIN_OUTPUT, PullNone, 1);
А в указанном на git остался какой-то другой вариант для чего-то другого...
Есть и такой вариант, в моих тестах:
Код:
volatile u8 * HardSetPin(PinName pin, PinDirection pdir, PinMode pmode, u8 val)
{
    volatile u8 *paddr = NULL;
    u32 ippin = HAL_GPIO_GetIPPinName_8195a(pin);
    if(ippin != 0xff) {
        // paddr = 0x42000000 + (0x40001000 + 0x0c * (ippin >> 5) - 0x40000000) * 32 + ((ippin & 0x1f) * 4);
        paddr = BitBandPeriAddr((void *)(GPIO_REG_BASE + GPIO_PORTB_DR * (ippin >> 5)),  ippin & 0x1f);
    }
    if(paddr && _pHAL_Gpio_Adapter) {
        if (_pHAL_Gpio_Adapter->Gpio_Func_En == 0)  GPIO_FuncOn_8195a();
        paddr[0] = val;                        // data register
        paddr[(GPIO_PORTB_DDR - GPIO_PORTB_DR) * 32] = pdir;    // data direction
#if 1 // if use HAL_Gpio_Adapter
        uint32 * p = &_pHAL_Gpio_Adapter->Local_Gpio_Dir[ippin >> 5];
        if(pdir) *p |= 1 << (ippin & 0x1f);
        else *p &= ~(1 << (ippin & 0x1f));
#endif
        paddr[(GPIO_PORTB_CTRL - GPIO_PORTB_DR) * 32] = 0;        // data source control, we should keep it as default: data source from software
        HAL_GPIO_PullCtrl_8195a(pin, pmode);                // set GPIO_PULL_CTRLx
    }
    return paddr;
}
По мере отладки и проверок на разные потребности он ещё будет меняться и дополняться...
В моих примерах кинутых на git данная функция пока не используется.

А что там вам там не понравилось?
GPIO_PORTX_DR -> 0x40001000 и в него задается значение, а установка direction - это другой порт, используется через ROM-BIOS функцию, для связи переменных ROM-BIOS.
И HardSetPin() в моем варианте не должен управлять direction для всех случаев.
Пример с открытым коллектором. Направлением direction пина и производится переключение "0" и "1" на выводе...
Может вы попутали всё с Arduino? Это только в Arduino пин в режиме "открытый коллектор" инвертируется в больную и нереальную для работающих с электроникой ситуацию, но заученную "домочадцами" на основании виртуального, а не физического значения на пине. :p При выводе "1" на пине будет "0" :)
При выводе и чтении в Arduino в порт с OK соответствия с тестером нет, как есть и неопределенность - что даст их любимая функция получения напряжения с пина, имеющего 3 состояния :)

Так-же, перед тем как менять direction порта, надо-бы установить выводимое значение, а не устраивать неопределенности и выплески на пине c неизвестным предыдущим записанным туда значением :p А HardSetPin - это всего инициализация порта, без установки direction. После неё будет пин в input.
 
Последнее редактирование:

АндрейМ

New member
А что там вам там не понравилось?
С точки зрения драйвера есть три функции с указателями: *in *out *hardSet. Первые две возвращают то, что хотелось, а последняя почему-то повторно *out. Получается, что не хватает *dir, вот я и предположил, что хард сет собирался его возвращать. А так нужна еще функция.

"GPIO_PORTB_DR" =0x12; С точки зрения расчета bitband-а это просто отвлеченная константа, которая сильно усложняет реверс


**** ковырнул лед с хардсетом, логику понял.

Код:
volatile uint8_t * HardSetPin(PinName pin, HAL_GPIO_PIN_MODE pmode, uint8_t val)
{
    volatile uint8_t *paddr = NULL;
    uint32_t ippin = HAL_GPIO_GetIPPinName_8195a(pin);
    if(ippin < 0xff) {
        if(_pHAL_Gpio_Adapter == NULL) {
            extern HAL_GPIO_ADAPTER gBoot_Gpio_Adapter;
            _pHAL_Gpio_Adapter = &gBoot_Gpio_Adapter;
        }
        if(_pHAL_Gpio_Adapter->Gpio_Func_En == 0) GPIO_FuncOn_8195a();
        wait_us(100);
        // delayMicroseconds(100);
        // paddr = 0x42000000 + (0x40001000 + 0x0c * (ippin >> 5) - 0x40000000) * 32 + ((ippin & 0x1f) * 4);
#if CONFIG_DEBUG_LOG > 3       
        GpioFunctionChk(ippin, ENABLE);
#endif       
        GPIO_PullCtrl_8195a(ippin, HAL_GPIO_HIGHZ); // Make the pin pull control default as High-Z
        paddr = BitBandPeriAddr((void *)(GPIO_REG_BASE + GPIO_PORTB_DDR * (ippin >> 5)),  ippin & 0x1f);
        *paddr = val;                        // data register
        HAL_GPIO_PIN gpio;
        gpio.pin_name = ippin;
        gpio.pin_mode = pmode;
        HAL_GPIO_Init_8195a(&gpio);
        *paddr = val;                        // data register
        paddr[(GPIO_PORTB_DDR - GPIO_PORTB_DR) * 32] = pmode == DOUT_PUSH_PULL;    // data direction
//        GPIO_PullCtrl_8195a(ippin, pmode);                    // set GPIO_PULL_CTRLx
//        paddr[(GPIO_PORTB_CTRL - GPIO_PORTB_DR) * 32] = 0;        // data source control, we should keep it as default: data source from software
    }
    return paddr;
}
почему бы не так?
 
Последнее редактирование:

АндрейМ

New member
Продолжаем. GPIO_MUX + IRQ

Где бы посмотреть, как настраиваются GPIO на прерывания без mbed. Сейчас воткнулся в странную ситуацию:

Инициализация:
Код:
#define OW_READ() (*ow.in)
#define OW_SET_HIGH()    *ow.out=1
#define OW_SET_LOW()    *ow.out=0
#define OW_OUTPUT()        *ow.dir=1
#define OW_INPUT()        *ow.dir=0

 ow.in = GetInPinBitBandAddr(pin);
    ow.out = GetOutPinBitBandAddr(pin);
    ow.dir = ow.out + (GPIO_PORTB_DDR - GPIO_PORTB_DR) * 32;
    HardSetPin(pin, DIN_PULL_HIGH, 0);

uint32_t ippin = HAL_GPIO_GetIPPinName_8195a(pin);
    ow.hal_pin.pin_name = ippin;
    ow.hal_pin.pin_mode = INT_RISING;
    //
    HAL_GPIO_Irq_Init(&ow.hal_pin);
    HAL_GPIO_UserRegIrq(&ow.hal_pin, ow_state_handler, 0);
    HAL_GPIO_IntCtrl(&ow.hal_pin,1); // enable IRQ
//    HAL_GPIO_MaskIrq(&ow.hal_pin);
    HAL_GPIO_UnMaskIrq(&ow.hal_pin);
обработчик прерывания TIMER0
Код:
        crBegin
//        __disable_irq();
        OW_SET_LOW();
        OW_OUTPUT();
        os_delay_us(OW_LOW_PULSE_TIME);
        OW_INPUT();
//        __enable_irq();
        ow_irq_trig=0;
        // todo enable gpio
        ow_timer_result=0;
       (void)OW_READ;
//        HAL_GPIO_UnMaskIrq(&ow.hal_pin);
//        HAL_GPIO_IntCtrl(&ow.hal_pin,1); // enable IRQ
        HAL_GPIO_UnMaskIrq(&ow.hal_pin);

        tsf_st=GET_TSF;
        tsf_e=0;
        crReturn(); // 1 tick
        HAL_GPIO_MaskIrq(&ow.hal_pin);
//        HAL_GPIO_IntCtrl(&ow.hal_pin,0); // enable IRQ

        //        if (tsf_e)
//            rtl_printf("_%lu_",(u32)(tsf_e-tsf_st));

        //        ow_timer_result = ow_irq_trig;

        crFinish
вопрос в том, что прерывание по INT_RISING срабатывает почему-то однократно после ow_reset (там паузы 400+мкс). Видимо, чего-то не донастраивается после переключения in->out->irq
 

pvvx

Активный участник сообщества
вопрос в том, что прерывание по INT_RISING срабатывает почему-то однократно после ow_reset (там паузы 400+мкс). Видимо, чего-то не донастраивается после переключения in->out->irq
Прерывание в базе MBED и по образу и подобию и должно срабатывать однократно. Вы должны заново инициировать разрешение нового прерывания. Это сделано для телепузиков, как защита от дребезга...
Пример GPIO IRQ для моей версии web-свалки (используется её consoleUART)
 

Вложения

AlexeyM

New member
Поздно прочитал, хотел по быстрому запустить rtl00 на ардуине - не полетел :). Использовал RTL_WEB отсюда, и пришлось написать для dht22 библиотечку по быстрому на перываниях. Хотел сначало по спаду-подъёму сделать - но почему то не заработало, пришлось просто по изменению. Может кому для примера пригодиться - там есть немгого лишнего, но это всегда можно выкинуть.
 

Вложения

Последнее редактирование:

pvvx

Активный участник сообщества
BitBand на RTL8710AF (CPU 83.3MHz):
BitBandRTL8710AF.gif
Код:
#include <bitband_io.h>

volatile uint8_t *bitband_dir;
volatile uint8_t *bitband_out;

void setup() {
  sys_info();
  printf("Init GPIO PC_4\n");
  bitband_out = HardSetPin(PC_4, DOUT_PUSH_PULL, 1);
  bitband_dir = bitband_out + (GPIO_PORTB_DDR - GPIO_PORTB_DR) * 32;
  printf("BitBand OUT: 0x%08x, DIR: 0x%08x\n", (unsigned int)bitband_out, (unsigned int)bitband_dir);
  if (!bitband_out) {
    printf("Error!\n");
    while (1);
  }
  printf("Start Test...\n");
  *bitband_dir = 1;
}

void out3pulse(volatile uint8_t *pout) {
  *pout = 0;
  *pout = 1;
  *pout = 0;
  *pout = 1;
  *pout = 0;
  *pout = 1;
}

void loop() {
  while (1) {
    out3pulse(bitband_out);
    delay(10);
}
BitBandRTL8710AF_166MHz.gif
Код:
extern "C" {
void UserPreInit(void)
{
   Init_CPU_CLK_UART(0,38400); // 166.6 MHz
   // 0 - 166666666 Hz, 1 - 83333333 Hz, 2 - 41666666 Hz, 3 - 20833333 Hz, 4 - 10416666 Hz, 5 - 4000000 Hz
   // 6 - 200000000 Hz, 7 - 10000000 Hz, 8 - 50000000 Hz, 9 - 25000000 Hz, 10 - 12500000 Hz, 11 - 4000000 Hz
}
} // extern "C"
На 200 МГц соответственно равно примерно 139.5 + 140.5 нс (3.571 МГц).
Т.е. 28 тактов CPU на вывод через BitBand.
-----------
Direct OUT:
BitBandRTL8710AF_dir.gif
Код:
void direct_pulse_pc_4(void)
{
  volatile uint32_t *port = (volatile uint32_t *)0x40001000;
  uint32_t mask = 1<<8;
  uint32_t data0 = *port & ~mask;
  uint32_t data1 = data0 | mask;
  *port = data0;
  *port = data1;
  *port = data0;
  *port = data1;
  *port = data0;
  *port = data1;
}
Так быстрее :)
 
Последнее редактирование:
Сверху Снизу