ESP32: система команд сопроцессора ULP |
![]() |
Добавил(а) microsin |
У сопроцессора ULPFSM имеется 4 регистра общего назначения, каждый разрядности 16-бит: R0, R1, R2, R3. У него также есть 8-битный регистр счетчика (stage_cnt), который может использоваться для реализации циклов. К регистру stage_cnt осуществляется доступ с помощью специальных инструкций. Сопроцессор ULP может обращаться к 8 килобайтам области памяти RTC_SLOW_MEM. Память адресуется 32-битными словами. Сопроцессор также может обращаться к регистрам периферийных устройств RTC_CNTL, RTC_IO и SENS. Все инструкции сопроцессора 32-разрядные. Инструкции перехода (Jump), арифметических операций (ALU), доступа к регистрам периферийных устройств и памяти выполняются за 1 такт. Инструкции, которые работают с периферийными устройствами (TSENS, ADC, I2C) выполняются переменное количество тактов, в зависимости от операции периферийного устройства. Синтаксис инструкций не чувствителен к регистру символов. Большие и маленькие буквы могут использоваться произвольным образом, в том числе и вперемежку. Это верно как для имен регистров, так и для имен инструкций. Адресация. Инструкции JUMP, ST, LD ожидают аргумент адреса, выраженный следующим способом, в зависимости от типа адреса аргумента: • Когда аргумент адреса представлен как метка, то инструкция ожидает адрес, выраженный как 32-битное слово. Рассмотрим следующий пример программы: entry:
NOP
NOP
NOP
NOP
loop:
MOVE R1, loop
JUMP R1
Когда эта программа ассемблируется и линкуется, адрес метки цикла будет равен 16 (в байтах). Однако инструкция JUMP ожидает, что адрес, сохраненный в R1, выражен в 32-битном слове. Чтобы учесть такой общий случай, ассемблер преобразует байтовый адрес метки цикла в номер слова, затем генерирует инструкцию MOVE. Генерируемый код будет эквивалентен следующему: 0000 NOP
0004 NOP
0008 NOP
000c NOP
0010 MOVE R1, 4 0014 JUMP R1
• Другой случай - когда аргумент инструкции MOVE не метка, а константа. В этом случае ассемблер будет использовать значение как есть, без преобразования: .set val, 0x10
MOVE R1, val
В этом случае в регистр R1 будет загружено значение 0x10. Однако когда непосредственное значение используется как смещение в инструкциях LD и ST, ассемблер считает аргумент адреса в байтах, и преобразует его в 32-битное слово перед выполнением инструкции: ST R1, R2, 4 // смещение = 4 байта; Mem[R2 + 4 / 4] = R1 В этом случае значение R1 сохраняется в ячейку памяти, указанную как [R2 + смещение / 4]. Рассмотрим следующий код: .global array array: .long 0 .long 0 .long 0 .long 0 MOVE R1, array MOVE R2, 0x1234 ST R2, R1, 0 // запись значения R2 в первый элемент массива, // т. е. в array[0] ST R2, R1, 4 // запись значения R2 во второй элемент массива, // со смещением 4 байта, т. е. в array[1] ADD R1, R1, 2 // эта команда инкрементирует адрес на 2 слова // (8 байт) ST R2, R1, 0 // запись значения R2 во третий элемент массива, // т. е. в array[2] Время выполнения инструкции. Сопроцессор ULP тактируется с частотой RTC_FAST_CLK, которая обычно получается из внутреннего RC-генератора 8 МГц. Приложения, которым нужно знать точную частоту ULP, могут откалибровать её по частоте основных тактов XTAL: // Калибровка тактов 8M/256 по частоте XTAL, получение 8M/256 периодов тактов
uint32_t rtc_8md256_period = rtc_clk_cal(RTC_CAL_8MD256, 100); uint32_t rtc_fast_freq_hz = 1000000ULL * (1 << RTC_CLK_CAL_FRACT) * 256 / rtc_8md256_period; Для выборки каждой инструкции сопроцессору ULP требуется определенное количество тактов, плюс некоторое количество тактов для её выполнения, в зависимости от инструкции. Конкретное время выполнения можно узнать далее в описании каждой инструкции. Время выборки инструкции равно: 2 периода тактов — для инструкций, которые идут за инструкцией ALU и инструкции ветвления. Обратите внимание, что когда осуществляется доступ к ячейкам памяти RTC и регистрам RTC, у сопроцессора ULP приоритет ниже, чем у ядер CPU. Это значит, что выполнение инструкций сопроцессора ULP может быть приостановлено, когда основной CPU обращается к тому же самому региону памяти, что и ULP. [Справочник по системе команд ULP] Синтаксис: NOP Операнды: отсутствуют. Время выполнения: 2 такта на выполнение, 4 такта для выборки следующей инструкции. Пример: NOP Синтаксис: ADD Rdst, Rsrc1, Rsrc2 Операнды: Rdst - регистр R[0..3] Время выполнения: 2 такта на выполнение, 4 такта для выборки следующей инструкции. Инструкция добавляет регистр источника к другому регистру источника, или к 16-битному значению со знаком, и сохраняет результат в регистр назначения. Пример1: ADD R1, R2, R3 // R1 = R2 + R3
Пример 2: Add R1, R2, 0x1234 // R1 = R2 + 0x1234 Пример 3: .set value1, 0x03 // константа value1=0x03 Add R1, R2, value1 // R1 = R2 + value1 Пример 4: .global label // декларация переменной label add R1, R2, label // R1 = R2 + label ... label: nop // определение переменной label Синтаксис: SUB Rdst, Rsrc1, Rsrc2 Операнды: Rdst - регистр R[0..3] Время выполнения: 2 такта на выполнение, 4 такта для выборки следующей инструкции. Инструкция вычитает регистр источника из другого регистра источника, или вычитает 16-битное значение со знаком из регистра источника, и сохраняет результат в регистр назначения. Пример 1: SUB R1, R2, R3 // R1 = R2 - R3
Пример 2: sub R1, R2, 0x1234 // R1 = R2 - 0x1234 Пример 3: .set value1, 0x03 // константа value1=0x03 SUB R1, R2, value1 // R1 = R2 - value1 Пример 4: .global label // декларация переменной label SUB R1, R2, label // R1 = R2 - label ...label: nop // определение переменной label Синтаксис: AND Rdst, Rsrc1, Rsrc2 Операнды: Rdst - регистр R[0..3] Время выполнения: 2 такта на выполнение, 4 такта для выборки следующей инструкции. Инструкция выполнит логическое И исходного регистра и другого исходного регистра, или 16-битного значения со знаком, и результат сохраняет в регистр назначения. Пример 1: AND R1, R2, R3 // R1 = R2 & R3
Пример 2: AND R1, R2, 0x1234 // R1 = R2 & 0x1234 Пример 3: .set value1, 0x03 // константа value1=0x03 AND R1, R2, value1 //R1 = R2 & value1 Пример 4: .global label // декларация переменной label AND R1, R2, label // R1 = R2 & label ... label: nop // определение переменной label Синтаксис: OR Rdst, Rsrc1, Rsrc2 Операнды: Rdst - регистр R[0..3] Время выполнения: 2 такта на выполнение, 4 такта для выборки следующей инструкции. Инструкция выполняет логическое ИЛИ исходного регистра и другого исходного регистра, или 16-битного значения со знаком, и результат сохраняет в регистр назначения. Пример 1: OR R1, R2, R3 // R1 = R2 | R3
Пример 2: OR R1, R2, 0x1234 // R1 = R2 | 0x1234 Пример 3: .set value1, 0x03 // константа value1=0x03 OR R1, R2, value1 // R1 = R2 | value1 Пример 4: .global label // декларация переменной label OR R1, R2, label // R1 = R2 |label ... label: nop // определение переменной label Синтаксис: LSH Rdst, Rsrc1, Rsrc2 Операнды: Rdst - регистр R[0..3] Время выполнения: 2 такта на выполнение, 4 такта для выборки следующей инструкции. Инструкция делает логический сдвиг влево исходного регистра на указанное количество бит в другом исходном регистре или 16-битном значении со знаком, и сохраняет результат в регистр назначения. Пример 1: LSH R1, R2, R3 // R1 = R2 << R3
Пример 2: LSH R1, R2, 0x03 // R1 = R2 << 0x03 Пример 3: .set value1, 0x03 // константа value1=0x03 LSH R1, R2, value1 // R1 = R2 << value1 Пример 4: .global label // декларация переменной label LSH R1, R2, label // R1 = R2 << label ... label: nop // определение переменной label Синтаксис: RSH Rdst, Rsrc1, Rsrc2 Операнды: Rdst - регистр R[0..3] Время выполнения: 2 такта на выполнение, 4 такта для выборки следующей инструкции. Инструкция делает логический сдвиг вправо исходного регистра на указанное количество бит в другом исходном регистре или 16-битном значении со знаком, и сохраняет результат в регистр назначения. Пример 1: RSH R1, R2, R3 // R1 = R2 >> R3
Пример 2: RSH R1, R2, 0x03 // R1 = R2 >> 0x03 Пример 3: .set value1, 0x03 // константа value1=0x03 RSH R1, R2, value1 // R1 = R2 >> value1 Пример 4: .global label // декларация переменной label RSH R1, R2, label // R1 = R2 >> label label: nop // определение переменной label Синтаксис: MOVE Rdst, Rsrc Операнды: Время выполнения: 2 такта на выполнение, 4 такта для выборки следующей инструкции. Инструкция перемещает значение из регистра источника или из 16-битного значения со знаком в регистр назначения. Обратите внимание, что когда метка используется для непосредственного значения, адрес метки будет преобразован из байтов в слова. Это потому, что инструкции LD, ST и JUMP ожидают значение адреса регистра, выраженное в словах, а не в байтах. Чтобы избежать этого, используйте дополнительную инструкцию. Пример 1: MOVE R1, R2 // R1 = R2
Пример 2: MOVE R1, 0x03 // R1 = 0x03 Пример 3: .set value1, 0x03 // константа value1=0x03 MOVE R1, value1 // R1 = value1 Пример 4: .global label // декларация label MOVE R1, label // R1 = адрес(label) / 4 ... label: nop // определение label Синтаксис: ST Rsrc, Rdst, offset Операнды: Rsrc – R[0..3], хранит 16-битное значение для сохранения Время выполнения: 4 такта на выполнение, 4 такта для выборки следующей инструкции. Инструкция сохранит 16-битное значение Rsrc в младшую половину слова в памяти по адресу Rdst+offset. Старшая половина слова записывается текущим значением программного счетчика (PC), выраженным в словах, сдвинутым влево на 5 бит: Mem[Rdst + offset / 4]{31:0} = {PC[10:0], 5'b0, Rsrc[15:0]} Приложение может использовать старшие 16 бит, чтобы определить, какая инструкция в программе ULP записала какое-либо определенное слово в память. Пример 1: ST R1, R2, 0x12 // MEM[R2+0x12] = R1 Пример 2: .data // определение секции данных
Addr1: .word 123 // определение метки Addr1 16 бит .set offs, 0x00 // определение константы смещения .text // определение секции кода MOVE R1, 1 // R1 = 1 MOVE R2, Addr1 // R2 = Addr1 ST R1, R2, offs // MEM[R2 + 0] = R1 // MEM[Addr1 + 0] будет 32'h600001 Синтаксис: LD Rdst, Rsrc, offset Операнды: Rdst – R[0..3], место назначения Время выполнения: 4 такта на выполнение, 4 такта для выборки следующей инструкции. Инструкция загрузит младшую 16-битную половину слова из памяти по адресу Rsrc+offset в регистр назначения Rdst: Rdst[15:0] = Mem[Rsrc + offset / 4][15:0] Пример 1: LD R1, R2, 0x12 // R1 = MEM[R2+0x12] Пример 2: .data // определение секции данных
Addr1: .word 123 // определение метки Addr1 16 бит .set offs, 0x00 // определение константы смещения .text // определение секции кода MOVE R1, 1 // R1 = 1 MOVE R2, Addr1 // R2 = Addr1 / 4 (байтовый адрес метки // преобразуется в адрес слова) LD R1, R2, offs // R1 = MEM[R2 + 0] // R1 будет 123 Синтаксис: JUMP Rdst Операнды: Rdst – R[0..3], содержащий адрес для перехода (выраженный в 32-битных словах) Время выполнения: 2 такта на выполнение, 2 такта для выборки следующей инструкции. Инструкция делает переход по указанному адресу. Это может быть либо безусловный переход, либо ветвление, основанное на флагах операции ALU. Пример 1: JUMP R1 // Переход по адресу в R1 (адрес в R1 // выражен в 32-битных словах) Пример 2: JUMP 0x120, EQ // Переход по адресу 0x120 (значение // в байтах) если результат ALU ноль Пример 3: JUMP label // Переход по метке
...
label: nop // Определение метки Пример 4: .global label // Декларация глобальной метки MOVE R1, label // R1 = label (значение, загруженное в R1 выраженное в словах) JUMP R1 // Переход по метке label ... label: nop // Определение метки Синтаксис: JUMPR Step, Threshold, Condition Операнды: Step – относительное смещение от текущей позиции, в байтах Время выполнения: Условия LT, GE, LE и GT: 2 цикла на выполнение, 2 цикла на выборку следующей инструкции. // JUMPR target, threshold, GT реализовано как: JUMPR target, threshold+1, GE // JUMPR target, threshold, LE реализовано как: JUMPR target, threshold + 1, LT Условие EQ реализовано в ассемблере с использованием двух инструкций JUMPR: // JUMPR target, threshold, EQ реализовано как: JUMPR next, threshold + 1, GE JUMPR target, threshold, GE next:
Таким образом, время выполнения будет зависеть от того, какое происходит ветвление: либо 2 такта на выполнение + 2 такта на выборку инструкции, или 4 такта на выполнение + 4 такта на выборку. Инструкция делает переход по относительному адресу, если условие true. Условие это результат сравнения R0 и значения threshold. Пример 1: pos: JUMPR 16, 20, GE // переход по адресу (позиция + 16 байт), // если значение в R0 >= 20 Пример 2: // Цикл с декрементируемым счетчиком на основе регистра R0 MOVE R0, 16 // загрузка 16 в R0 label: SUB R0, R0, 1 // R0-- NOP // какие-либо действия JUMPR label, 1, GE // переход по метке label, если R0 >= 1 Синтаксис: JUMPS Step, Threshold, Condition Операнды: Step – относительное смещение от текущей позиции, в байтах Время выполнения: Условия LE, LT, GE: 2 цикла на выполнение, 2 цикла на выборку следующей инструкции. // JUMPS target, threshold, EQ реализован как:
JUMPS next, threshold, LT
JUMPS target, threshold, LE
next:
// JUMPS target, threshold, GT реализован как:
JUMPS next, threshold, LE
JUMPS target, threshold, GE
next:
Таким образом, время выполнения будет зависеть от того, какое происходит ветвление: либо 2 такта на выполнение + 2 такта на выборку инструкции, или 4 такта на выполнение + 4 такта на выборку. Инструкция делает переход по относительному адресу, если условие true. Условие это результат сравнения регистра счетчика и значения threshold. Пример 1: pos: JUMPS 16, 20, EQ // переход на (позиция + 16 байт), // если stage_cnt == 20 Пример 2: // Цикл, основанный на инкрементируемом счетчике в регистре stage_cnt STAGE_RST // stage_cnt = 0 label: STAGE_INC 1 // stage_cnt++ NOP // какие-либо действия JUMPS label, 16, LT // переход по метке label, если stage_cnt < 16 Синтаксис: STAGE_RST Операнды: отсутствуют. Время выполнения: 2 такта на выполнение, 4 такта для выборки следующей инструкции. Инструкция установит в 0 регистр stage count. Пример: STAGE_RST // Сброс регистра stage count
Синтаксис: STAGE_INC Value Операнды: Value – 8-разрядное значение Время выполнения: 2 такта на выполнение, 4 такта для выборки следующей инструкции. Инструкция инкрементирует регистр stage count на указанное значение. Пример 1: STAGE_INC 10 // stage_cnt += 10 Пример 2: // Пример цикла со счетчиком, считающим вверх: STAGE_RST // установка stage_cnt в 0 label: STAGE_INC 1 // stage_cnt++ NOP // какие-либо действия JUMPS label, 16, LT // переход по метке label, если stage_cnt < 16 Синтаксис: STAGE_DEC Value Операнды: Value – 8-разрядное значение Время выполнения: 2 такта на выполнение, 4 такта для выборки следующей инструкции. Инструкция декрементирует регистр stage count на указанное значение. Пример 1: STAGE_DEC 10 // stage_cnt -= 10 Пример 2: // Пример цикла со счетчиком, считающим вниз: STAGE_RST // установка stage_cnt в 0 STAGE_INC 16 // инкремент stage_cnt на 16 label: STAGE_DECC 1 // stage_cnt-- NOP // какие-либо действия JUMPS label, 0, LT // переход по метке label, если stage_cnt > 0 Синтаксис: HALT Операнды: отсутствуют. Время выполнения: 2 такта. Инструкция вешает сопроцессор ULP и перезапускает таймер пробуждения ULP (wake up timer), если он разрешен. Пример: HALT // остановка сопроцессора
Синтаксис: WAKE Операнды: отсутствуют. Время выполнения: 2 такта на выполнение, 4 такта для выборки следующей инструкции. Инструкция посылает прерывание от ULP контроллеру RTC. Если SoC находится в режиме глубокого сна (deep sleep mode), и разрешено ULP wakeup, то это разбудит SoC. Если SoC не в deep sleep mode, и бит прерывания ULP (RTC_CNTL_ULP_CP_INT_ENA) установлен в регистре RTC_CNTL_INT_ENA_REG, то произойдет прерывание RTC. Обратите внимание, что перед использованием инструкции WAKE программе ULP может понадобиться подождать, пока контроллер RTC не будет готов тому, чтобы разбудить основной процессор. Это показывается битом RTC_CNTL_RDY_FOR_WAKEUP регистра RTC_CNTL_LOW_POWER_ST_REG. Если инструкция WAKE выполняется, когда RTC_CNTL_RDY_FOR_WAKEUP равен 0, то она не не дает эффекта (пробуждение не произойдет). Пример: is_rdy_for_wakeup: // Чтение бита RTC_CNTL_RDY_FOR_WAKEUP READ_RTC_FIELD(RTC_CNTL_LOW_POWER_ST_REG, RTC_CNTL_RDY_FOR_WAKEUP) AND r0, r0, 1 JUMP is_rdy_for_wakeup, eq // Повтор, пока этот бит не установится WAKE // Запуск пробуждения REG_WR 0x006, 24, 24, 0 // Остановка таймера ULP (очистка // RTC_CNTL_ULP_CP_SLP_TIMER_EN) HALT // Остановка программы ULP // После этой инструкции SoC выйдет из сна, и ULP не заработает опять, // пока не будет запущен основной программой. Синтаксис: SLEEP sleep_reg Операнды: sleep_reg – 0..4, выбор одного из регистров SENS_ULP_CP_SLEEP_CYCx_REG. Время выполнения: 2 такта на выполнение, 4 такта для выборки следующей инструкции. Инструкция выберет, значение в каком из регистров SENS_ULP_CP_SLEEP_CYCx_REG (x = 0..4) будет использоваться для периода таймера пробуждения ULP. По умолчанию используется значение из SENS_ULP_CP_SLEEP_CYC0_REG. Пример 1: SLEEP 1 // Используется период, установленный в SENS_ULP_CP_SLEEP_CYC1_REG Пример 2: .set sleep_reg, 4 // Определение константы SLEEP sleep_reg // Используется период, установленный в SENS_ULP_CP_SLEEP_CYC4_REG Синтаксис: WAIT Cycles Операнды: Cycles – количество тактов для ожидания. Время выполнения: 2 + Cycles тактов на выполнение, 4 такта для выборки следующей инструкции. Инструкция задерживает выполнение кода на указанное количество тактов. Пример 1: WAIT 10 // Ничего не делать в течение 10 тактов Пример 2: .set wait_cnt, 10 // Установка константы WAIT wait_cnt // Подождать 10 тактов Синтаксис: TSENS Rdst, Wait_Delay Операнды: Rdst – регистр назначения R[0..3], куда будет сохранен результат. Время выполнения: 2 + Wait_Delay + 3 * TSENS_CLK тактов на выполнение, 4 такта для выборки следующей инструкции. Инструкция производит измерение температуры с использованием TSENS и сохранит результат в регистр общего назначения. Пример: TSENS R1, 1000 // Измерение температуры в течение 1000 тактов // и сохранение результата в R1 Синтаксис: ADC Rdst, Sar_sel, Mux Операнды: Rdst – регистр назначения R[0..3], куда сохраняется измерение. Время выполнения: 23 + max(1, SAR_AMP_WAIT1) + max(1, SAR_AMP_WAIT2) + max(1, SAR_AMP_WAIT3) + SARx_SAMPLE_CYCLE + SARx_SAMPLE_BIT тактов на выполнение, 4 такта для выборки следующей инструкции. Инструкция делает измерение уровня напряжения на входе ADC. Пример: ADC R1, 0, 1 // изменение значения с использованием ADC1 pad 2 // и сохранение результата в R1 Синтаксис: I2C_RD Sub_addr, High, Low, Slave_sel Операнды: Sub_addr – адрес подчиненного (slave) устройства I2C. Время выполнения: время выполнения инструкции зависит главным образом от времени обмена I2C. 4 такта уходит на выборку следующей инструкции. Инструкция I2C_RD считывает 1 байт из устройства I2C slave с индексом Slave_sel. Адрес (в 7-битном формате) должен быть предварительно установлен в поле регистра SENS_I2C_SLAVE_ADDRx, где x == Slave_sel. 8 бит результата чтения сохраняются в регистр R0. Пример: I2C_RD 0x10, 7, 0, 0 // Чтение байта из подчиненного устройства // с адресом 0x10, с индексом адреса, // установленным в SENS_I2C_SLAVE_ADDR0 Синтаксис: I2C_WR Sub_addr, Value, High, Low, Slave_sel Операнды: Sub_addr – адрес подчиненного (slave) устройства I2C. Время выполнения: время выполнения инструкции зависит главным образом от времени обмена I2C. 4 такта уходит на выборку следующей инструкции. Инструкция I2C_WR запишет 1 байт в I2C с индексом Slave_sel. Адрес (в 7-битном формате) должен быть предварительно установлен в поле регистра SENS_I2C_SLAVE_ADDRx, где x == Slave_sel. Пример: I2C_WR 0x20, 0x33, 7, 0, 1 // Запись байта 0x33 в подчиненное устройство // с адресом 0x20, с индексом адреса, // установленным в SENS_I2C_SLAVE_ADDR1. Синтаксис: REG_RD Addr, High, Low Операнды: Addr – адрес регистра в 32-битных словах. Время выполнения: 4 такта на выполнение, 4 такта для выборки следующей инструкции. Инструкция читает до 16 бит из регистра периферийного устройства в регистр общего назначнения R0 = REG[Addr][High:Low]. Эта инструкция может обращаться к регистрам периферийных устройств RTC_CNTL, RTC_IO, SENS и RTC_I2C. Адрес регистра, как он видится ULP, может быть вычислен из адреса того же регистра на шине DPORT следующим образом: addr_ulp = (addr_dport - DR_REG_RTCCNTL_BASE) / 4 Пример: REG_RD 0x120, 7, 4 // загрузка 4 бит: R0 = {12'b0, REG[0x120][7:4]} Синтаксис: REG_WR Addr, High, Low, Data Операнды: Addr – адрес регистра в 32-битных словах. Время выполнения: 8 тактов на выполнение, 4 такта для выборки следующей инструкции. Инструкция запишет до 8 из непосредственного значения данных в регистр периферийного устройства REG[Addr][High:Low] = данные. Эта инструкция может обращаться к регистрам периферийных устройств RTC_CNTL, RTC_IO, SENS и RTC_I2C. Адрес регистра, как он видится ULP, может быть вычислен из адреса того же регистра на шине DPORT следующим образом: addr_ulp = (addr_dport - DR_REG_RTCCNTL_BASE) / 4 Пример: REG_WR 0x120, 7, 0, 0x10 // установка 8 бит: REG[0x120][7:0] = 0x10 [Макросы для доступа к регистрам периферийного устройства] Перед тем, как исходный код для ULP попадет ассемблеру, он сначала проходит через препроцессор C. Это позволяет использовать определенные макросы для упрощения доступа к регистрам периферийных устройств. Некоторые готовые макросы определены в заголовке soc/soc_ulp.h. Эти макросы позволяют получать доступ к полям регистра периферийного устройства по их именам. Имена регистров периферийных устройств, которые могут использоваться с этими макросами, определены в soc/rtc_cntl_reg.h, soc/rtc_io_reg.h, soc/sens_reg.h и soc/rtc_i2c_reg.h. Чтение до 16 бит из rtc_reg[low_bit + bit_width - 1 : low_bit] в регистр R0. Пример: #include "soc/soc_ulp.h"
#include "soc/rtc_cntl_reg.h"
/* Чтение младших 16 бит RTC_CNTL_TIME0_REG в R0 */ READ_RTC_REG(RTC_CNTL_TIME0_REG, 0, 16) Чтение до 16 бит из поля в регистре rtc_reg и размещение результата чтения в R0. Пример: #include "soc/soc_ulp.h"
#include "soc/sens_reg.h"
/* Чтение 8-битного поля SENS_TSENS_OUT из SENS_SAR_SLAVE_ADDR3_REG в R0 */
READ_RTC_FIELD(SENS_SAR_SLAVE_ADDR3_REG, SENS_TSENS_OUT)
Запись непосредственного значения в rtc_reg[low_bit + bit_width - 1 : low_bit], bit_width < = 8. Пример: #include "soc/soc_ulp.h"
#include "soc/rtc_io_reg.h"
/* Установит BIT(2) RTC_GPIO_OUT_DATA_W1TS field в регистре RTC_GPIO_OUT_W1TS_REG */ WRITE_RTC_REG(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS_S + 2, 1, 1) Запись непосредственного значения в поле rtc_reg, до 8 бит. Пример: #include "soc/soc_ulp.h"
#include "soc/rtc_cntl_reg.h"
/* Установит поле RTC_CNTL_ULP_CP_SLP_TIMER_EN регистра RTC_CNTL_STATE0_REG в 0 */ WRITE_RTC_FIELD(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN, 0) [Ссылки] 1. ESP32 ULP coprocessor instruction set site:docs.espressif.com. |