Радиомикрофоны
October 27

Реверс инжиниринг полурабочего «Простого радиоуправляемого радиомикрофона на MRF49XA» от Blaze 1.0

Реверс инжиниринг прошивки PIC12F675 радиоуправляемого радиомикрофона на MRF49XA от Blaze с сайта vrtp.ru. Исправление ошибок.

Оригинальная схема радиоуправляемого радиомикрофона на MRF49XA и PIC12F675 от Blaze

Источник схемы: vrtp .ru/index.php?act=categories&CODE=article&article=3813

Параметры MRF49XA

  1. Выпуск начат в 2009 году
  2. Диапазоны 433 МГц, 868 МГц, 915 МГц
  3. Приемник с чувствительностью -112 дБмВт (0.5 мкВ) на 433 МГц построен по схеме с прямым преобразованием частоты (привет дедушке Полякову)
  4. Передатчик имеет мощность 7 дБмВт (5 мВт) на частоте 433 МГц при напряжении питания 3.3В
  5. Напряжение питания 2.2-3.8В
  6. Токопотребление 15 мА — передача, 10 мА — прием, 0.3 мкА — сон
  7. Аналог: SI4421

Недостатки

  1. Неправильные номиналы емкостей и индуктивностей — заниженная мощность и плохой КСВ.
  2. Длина идентификатора 1 байт — возможен полный перебор.
  3. После включения передатчика контроллер не засыпает — завышенное потребление тока.

Не будем останавливаться на проблемах НЧ части. Они полностью разобраны в статье о радиомикрофоне серии “R” от Flight на MAX1472. Просто замените ее хорошей схемой с АРУ от Kotu.

Поскольку длина идентификатора всего лишь 1 байт, а частота по умолчанию 439 МГц ровно, можно сделать «мастер пульт», который будет перебирать все значения от 0 до 255 и включать все радиомикрофоны от Blaze в округе.

Сделать идентификатор 32-битным — это будет ваше первое домашнее задание (контрольную сумму 32-битного идентификатора проверять не обязательно).

Для уменьшения энергопотребления контроллер периодически просыпается, включает приемник MRF49XA и пытается принять посылку с пульта. Вполне рабочая стратегия, но MRF49XA умеет это делать и без помощи контроллера, наверняка расходуя при этом еще меньше (1.5 мкА, стр. 80 даташита) заряда батареи:

The MRF49XA can be made to enter into a Low Duty
Cycle mode operation to decrease the average power
consumption in Receive mode. The Low Duty Cycle
mode is normally used in conjunction with the wake-up
timer for its operation. The DCSREG may be config-
ured so that when the wake-up timer brings the device
out of Sleep mode, the receiver is turned on for a short
time to sample for a signal. Then, the device returns to
Sleep and this process repeats.

3.15 Low Duty Cycle Mode (стр. 61)
In Low Duty Cycle mode, the receiver periodically
wakes up for a short period and checks for the valid
FSK transmission in progress.

Гораздо хуже, что все номиналы индуктивностей и емкостей неправильные, неправильная и схема подключения антенны. Правильную схему и номиналы ВЧ части см. в даташите на стр. 76.

Больше всего отличается индуктивность L1 (обозначение по схеме из даташита на стр. 76) — правильное значение в десять раз больше!

В даташите особо оговорено, что подходят только СВЧ индуктивности с малой паразитной емкостью (стр. 75 и 77), например: LQW18ANR39J00D, MLG1608B33NJ и MLG1608B47NJ. Китайские зеленые дроссели не подходят!

Тем не менее, «работать» с этими номиналами радиомикрофон будет, но гораздо хуже (меньше дальность и, возможно, глюки из-за большого КСВ).

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

Конденсаторов по питанию должно быть три (и четвертый — электролит): 2.2u, 10n, 220p. См. стр. 13 даташита.

Во время работы передатчика микроконтроллер гоняет пустые циклы. Лучше бы он засыпал — было бы меньше токопотребление (это второе ваше домашнее задание).

Жаль, что всякие вкусности микросхемы MRF49 типа детектора разряда батареи и автосброса при скачке по питанию (стр. 45) остались незадействованными. Ведь глубокий разряд аккумуляторов очень быстро приводит их в негодность.

Рекомендуемое напряжение питания MRF49XA 2.2...3.8В (стр. 3), а указанное 5В просто не выводит микросхему из строя (стр. 79). MRF49XA нельзя эксплуатировать с таким высоким напряжением питания.

Как сказано в даташите, надежный запуск кварцевого генератора зависит от наличия полезной паразитной емкости, которую нужно создать искусственно, оставив «землю» под кварцем (стр. 48). Если габариты не позволяют, то нужно подключить 1 пф параллельно кварцу:

The crystal oscillator circuit is sensitive to parasitic
capacitance for start-up. A small amount of parasitic
capacitance is needed to facilitate oscillation. To achieve
this, create a ground plane around the crystal and widen
the connection to the MRF49XA. This is to adjust the ref-
erence frequency and to compensate for stray capaci-
tance that might be introduced due to PCB layout. If the
layout is not possible, a 0.5-1 pF capacitor, soldered
across the crystal, will initiate the start-up. Also, see
Section 3.6 “Crystal Selection Guidelines” for
selecting the right crystal.

Кажется, забыли конденсатор 1n с 7 ноги на землю (возможно, он и не используется, см. стр. 57).

Интересно, что на MRF49XA, возможно, получится сделать радиомикрофон с шумоподобным спектром:

The MRF49XA is the best option for Frequency Hopping
Spread Spectrum (FHSS) applications requiring
frequency agility to meet FCC, IC or ETSI requirements.

Частоту легко можно менять 3000 раз в секунду (см. параметр PLL Lock Time на стр. 82).

Перед сборкой этой схемы обязательно прочитайте даташит на MRF49XA от корки до корки. Также см. AN1252. Если найдете исходники на microchip.com, напишите ссылку в комментариях.

Я ее не собирал! Возможно, я что-то понял неправильно. Возможно, в ней есть и другие ошибки.

Контрольный список для исправления ошибок

  1. Заменить УНЧ на схему Kotu с АРУ
  2. ВЧ часть сделать как в даташите на стр. 76
  3. Крепить радиомикрофон магнитом на металлическую поверхность или использовать противовес
  4. Развязать варикап по постоянному току, чтобы напряжение на нем не опускалось ниже 1 В
  5. Не поднимать напряжение питания MRF49XA выше рекомендованных 3.8В
  6. Зашунтировать микрофон конденсатором 100 пф (уже сделано у Kotu)
  7. Увеличить в прошивке длину идентификатора до 24-32 бит, прошить в EEPROM уникальный случайный идентификатор (потребуется и модификация пульта)

Сборка (компилирование) прошивки PIC

apt install gputils
gpasm mrf49.asm -o mrf49.hex

Перекомпилированная прошивка отличается от оригинальной двумя строками (напишите в комментариях, почему):

-:02400E00CC01E3
+:02400E00CC31B3

Чтобы дезассемблировать прошивку пульта, см. команды в статье «Реверс инжиниринг Трёшки от Eddy71».

Исходник прошивки PIC12F675 радиоуправляемого радиомикрофона на MRF49XA от Blaze

Дизассемблированная прошивка с комментариями:

        processor p12f675
        radix dec

        include p12f675.inc

; The recognition of labels and registers is not always good, therefore
; be treated cautiously the results.

        CONFIG  FOSC  = INTRCIO
        CONFIG  WDTE  = ON
        CONFIG  PWRTE = ON
        CONFIG  MCLRE = OFF
        CONFIG  BOREN = ON
        CONFIG  CP    = OFF
        CONFIG  CPD   = OFF

;===============================================================================
; PINS usage definitions

; PIC 7, MRF 6 - данные MRF49XA
#define MRF49_DATA GP0

; PIC 5 - питание УНЧ
#define AMP_POWER GP2

; PIC 2, MRF 1
#define MRF49_SDI GP5

; PIC 6, MRF 3
#define MRF49_CS GP1

; PIC 3, MRF 2
#define MRF_SCK GP4

;===============================================================================
; Макросы

movlf   MACRO value, file
        movlw   (value)
        movwf   (file)
        ENDM

movff   MACRO src, dst
        movf    (src), W
        movwf   (dst)
        ENDM

;===============================================================================
; Определения

; команды для переключения режимов MRF49XA записаны в EEPROM:

#define EEPROM_MRF_CFG_TX 0x00                              ; передача
#define MRF_CFG_ON_LEN 5

#define EEPROM_MRF_CFG_RX 0x10                              ; прием
#define MRF_CFG_OFF_LEN 6

; периодическое выключение приемника для экономии заряда
#define EEPROM_SLEEP 0x1c
#define DUTY_CYCLE 100

#define EEPROM_IDENT 0x20                  ; смещение уникального идентификатора

#define FA1_433 1
#define FA0_433 43

#define FA1_868 2
#define FA0_868 43

#define FA1_915 3
#define FA0_915 30

#define FVAL_433(freq) ((((freq)/FA1_433) - FA0_433*10000000) / 2500)
#define FVAL_868(freq) ((((freq)/FA1_868) - FA0_868*10000000) / 2500)
#define FVAL_915(freq) ((((freq)/FA1_915) - FA0_915*10000000) / 2500)

; см. стр. 28 даташита

#define RX_FVAL FVAL_433(439000000)     ; частота приемника (шаг 2.5 кГц)
#define RX_BAND MRF_FBS_434

#define TX_FVAL FVAL_433(439000000)     ; частота передатчика (шаг 2.5 кГц)
#define TX_BAND MRF_FBS_434

; проверка границ установки частоты
if (RX_FVAL < 96) || (RX_FVAL > 3903)
        error "Receiver frequency out of range"
endif

if (TX_FVAL < 96) || (TX_FVAL > 3903)
        error "Transmitter frequency out of range"
endif

; скорость передачи данных 407296 бит/с и полоса 400 кГц -
; явно бредовая комбинация, см. формулу на стр. 56 и далее параграф
; 3.10.2 DIGITAL FILTERING MODE на стр. 57

#define REMOTE_CONTROL_RATE 407296
#define SELECTED_MRF_BW MRF_RXBW_400K

;===============================================================================
; MRF49XA
; https://raw.githubusercontent.com/dvdfreitag/MRF49XA-Library/refs/heads/master/MRF49XA_definitions.h
; Created by William Dillon on 11/2/10.
; Copyright 2010 Oregon State University. All rights reserved.
; Modified by David Freitag on 1/13/15

; General Configuration Register
#define MRF_GENCREG		0x8000		; General configuration register addres
#define MRF_TXDEN		0x0080		; TX Data Register enable bit
#define MRF_FIFOEN		0x0040		; FIFO enable bit
#define MRF_FBS_MASK	0x0030		; Mask for the band selection
#define MRF_LCS_MASK	0x000F		; Mask for the crystal load capactiance

; 10pF Crystal load capacitance
#define MRF_LCS			3			; Crystal Load capactiance

; Frequency band settings
#define MRF_FBS_434		0x0010		; 434 mHz band
#define MRF_FBS_868		0x0020		; 868 mHz band
#define MRF_FBS_915		0x0030		; 915 mHz band

; Power Management Configuration Register
#define MRF_PMCREG		0x8200		; Power Mgmt. Config. Register address
#define MRF_RXCEN		0x0080		; Receiver chain enable
#define MRF_BBCEN		0x0040		; Baseband chain enable
#define MRF_TXCEN		0x0020		; Transmitter chain enable
#define MRF_SYNEN		0x0010		; Synthesier enable
#define MRF_OSCEN		0x0008		; Oscillator enable
#define MRF_LBDEN		0x0004		; Low Battery Detector Enable
#define	MRF_WUTEN		0x0002		; Wakeup timer enable
#define MRF_CLKODIS		0x0001		; Clock output disable

#define MRF_RXCREG		0x9000		; Receive control register address
#define MRF_FINTDIO		0x0400		; Function interrupt/dio output
#define MRF_DIORT_MASK	0x0300		; Data indicator response time
#define MRF_RXBW_MASK	0x00E0		; Receiver baseband bandwidth
#define MRF_RXLNA_MASK	0x0018		; Receiver LNA gain
#define MRF_DRSSIT_MASK 0x0007		; Digital RSSI threshold

; Data indicator output response time
#define MRF_DIORT_CONT	0x0300		; Continuous
#define MRF_DIORT_SLOW	0x0200		; Slow
#define MRF_DIORT_MED	0x0100		; Medium
#define MRF_DIORT_FAST	0x0000		; Fast

; Receiver Baseband bandwidth
#define MRF_RXBW_67K	0x00C0		; Receiver Bandwidth 67 khz
#define MRF_RXBW_134K	0x00A0		; Receiver Bandwidth 134 khz
#define MRF_RXBW_200K	0x0080		; Receiver Bandwidth 200 khz
#define MRF_RXBW_270K	0x0060		; Receiver Bandwidth 270 khz
#define MRF_RXBW_340K	0x0040		; Receiver Bandwidth 340 khz
#define MRF_RXBW_400K	0x0020		; Receiver Bandwidth 400 khz

; Receiver LNA Gain
#define MRF_RXLNA_20DB	0x0018		; LNA Gain -20dB
#define MRF_RXLNA_14DB	0x0010		; LNA Gain -14dB
#define MRF_RXLNA_6DB	0x0008		; LNA Gain -6dB
#define MRF_RXLNA_0DB	0x0000		; LNA Gain  0dB

; Digital RSSI threshold
#define MRF_DRSSIT_73db	0x0005		; -73dB Threshold
#define MRF_DRSSIT_79db	0x0004		; -79dB Threshold
#define MRF_DRSSIT_85db	0x0003		; -85dB Threshold
#define MRF_DRSSIT_91db	0x0002		; -91dB Threshold
#define MRF_DRSSIT_97db	0x0001		; -97dB Threshold
#define MRF_DRSSIT_103db 0x0000		; -103dB Threshold

; *******************************************************************************
; * Convenience definitions for transmitter control register
; *
; * These defines are provided for use configuring the MRF49XA module.
; * Select the modulation bandwidth and output power by bit-wise oring them
; * with the register address.
; *
; * Use the MRF_TXCREG_SET for Microchip defaults
; *
; *******************************************************************************
; Transmit Configuration register
#define MRF_TXCREG		0x9800		; Transmit configuration register address
#define MRF_MODPLY		0x0100		; Modulation polarity
#define MRF_MODBW_MASK	0x00F0		; Modulation bandwidth
#define MRF_OTXPWR_MASK 0x0007		; Output transmit power

; Modulation bandwidth settings
#define MRF_MODBW_240K	0x00F0		; 240kHz modulation bandwidth
#define MRF_MODBW_225K	0x00E0		; 225kHz modulation bandwidth
#define MRF_MODBW_210K	0x00D0		; 210kHz modulation bandwidth
#define MRF_MODBW_195K	0x00C0		; 195kHz modulation bandwidth
#define MRF_MODBW_180K	0x00B0		; 180kHz modulation bandwidth
#define MRF_MODBW_165K	0x00A0		; 165kHz modulation bandwidth
#define MRF_MODBW_150K	0x0090		; 150kHz modulation bandwidth
#define MRF_MODBW_135K	0x0080		; 135kHz modulation bandwidth
#define MRF_MODBW_120K	0x0070		; 120kHz modulation bandwidth
#define MRF_MODBW_105K	0x0060		; 105kHz modulation bandwidth
#define MRF_MODBW_90K	0x0050		;  90kHz modulation bandwidth
#define MRF_MODBW_75K	0x0040		;  75kHz modulation bandwidth
#define MRF_MODBW_60K	0x0030		;  60kHz modulation bandwidth
#define MRF_MODBW_45K	0x0020		;  45kHz modulation bandwidth
#define MRF_MODBW_30K	0x0010		;  30kHz modulation bandwidth
#define MRF_MODBW_15K	0x0000		;  15kHz modulation bandwidth

; Output power settings
#define MRF_OTXPWR_17D5	0x0007		; -17.5dB Transmit Output Power
#define MRF_OTXPWR_15D0	0x0006		; -15.0dB Transmit Output Power
#define MRF_OTXPWR_12D5	0x0005		; -12.5dB Transmit Output Power
#define MRF_OTXPWR_10D5	0x0004		; -10.5dB Transmit Output Power
#define MRF_OTXPWR_7D5	0x0003		; - 7.5dB Transmit Output Power
#define MRF_OTXPWR_5D0	0x0002		; - 5.0dB Transmit Output Power
#define MRF_OTXPWR_2D5	0x0001		; - 2.5dB Transmit Output Power
#define MRF_OTXPWR_0	0x0000		;   0.0dB Transmit Output Power

#define MRF_CFSREG		0xA000		; Center Frequency value register address

#define MRF_AFCCREG		0xC400		; AFC configuration register address

; Automatic frequency mode selection
#define MRF_AUTOMS_INDP	0x00C0		; Offset independent for state of DIO sig.
#define MRF_AUTOMS_RECV	0x0080		; Offset only during receive
#define MRF_AUTOMS_ONCE	0x0040		; Offset once after power-cycle
#define MRF_AUTOMS_OFF	0x0000		; Auto mode off

; Allowable tuning range selection
#define MRF_ARFO_3to4	0x0030		; +3 to -4 Fres (tuning bits)
#define MRF_ARFO_7to8	0x0020		; +7 to -8 Fres
#define MRF_ARFO_15to16	0x0010		; +15 to -16 Fres
#define MRF_ARFO_unlim	0x0000		; Unlimited

; Data Rate Value set register
#define MRF_DRSREG		0xC600		; Data rate value set register address
#define MRF_DRPE		0x0080		; Data rate prescaler enable
#define MRF_DRPV_MASK	0x007F		; Data rate value mask

;===============================================================================
; DATA address definitions

Common_RAM      equ     0x0020                              ; size: 64 bytes

i               equ     (Common_RAM + 1)
j               equ     (Common_RAM + 2)
k               equ     (Common_RAM + 3)

timer           equ     (Common_RAM + 4)                    ; счетчик до выкл.

mrf49_word      equ     (Common_RAM + 5)                    ; регистр MRF49XA

rxbit           equ     (Common_RAM + 7)                    ; принятый бит

; принятая 32-битная посылка с пульта

rx_ident        equ     (Common_RAM + 8)                    ; идентификатор
rx_ident_crc    equ     (Common_RAM + 9)
rx_timer        equ     (Common_RAM + 10)                   ; время включения
rx_timer_crc    equ     (Common_RAM + 11)

pulse_len       equ     (Common_RAM + 12)                   ; длина импульса

;===============================================================================
; CODE area

        ; code

        org     __CODE_START                                ; address: 0x0000

vector_reset:                                               ; address: 0x0000

        bsf     STATUS, RP0

        ; что это такое?
        call    0x03ff

        movwf   T1CON
        clrf    ADCON0

vector_int:                                                 ; address: 0x0004

        clrf    GPIO

        movlf   3, TMR0
        bcf     STATUS, RP0
        movlf   0x31, T1CON
        movlf   0x07, CMCON

        clrf    GPIO                                        ; зачем еще раз?

        call    function_shortdelay

        ; если EEPROM пустая,
        ; записать в нее команды для переключения режимов MRF49XA по умолчанию
        call    function_eeprom_init

        ; короткий выход в эфир при включении питания
        call    function_short_on

        ; главный цикл
        ; пытаемся принять посылку, засыпаем, повторяем
forever:

        clrwdt

        btfsc   GPIO, MRF49_DATA
        call    function_receive_command

        btfss   PIR1, T1IF
        goto    forever

        call    function_sleep
        goto    forever


function_decode_bit:

        clrf    rxbit

        ; ожидаем поднятия DATA в течение 200 попугаев
        movlf   200, TMR0
        bcf     INTCON, T0IF

wait_data_high:

        clrwdt

        btfsc   GPIO, MRF49_DATA
        goto    data_high

        ; 1 = TMR0 register has overflowed (must be cleared in software)
        btfss   INTCON, T0IF
        goto    wait_data_high

        ; не дождались
        return

data_high:

        ; теперь измеряем длительность импульса

        clrf    TMR0
        bcf     INTCON, T0IF

wait_data_low:

        btfss   GPIO, MRF49_DATA
        goto    data_low
        btfss   INTCON, T0IF
        goto    wait_data_low

data_low:

        ; запоминаем измеренную длительность
        movff   TMR0, pulse_len

        movlw   20
        subwf   pulse_len, W
        btfsc   STATUS, C
        incf    rxbit, F                                    ; больше 20

        movlw   40
        subwf   pulse_len, W
        btfsc   STATUS, C
        incf    rxbit, F                                    ; больше 40

        movlw   80
        subwf   pulse_len, W
        btfsc   STATUS, C
        clrf    rxbit                                       ; больше 80 - ошибка

        return

function_receive_command:                                   ; address: 0x0036

        ; синхронизация по концу посылки

        ; принять 32 бита
        movlf   32, Common_RAM

decode_next_bit:                                            ; address: 0x0038

        ; 0 - ошибка, 1 - лог. 1, 2 - лог. 0
        call    function_decode_bit

        ; ошибка
        movf    rxbit, F
        btfsc   STATUS, Z
        return

        ; поместить принятый бит в флаг переноса (проще - rrf rxbit)
        btfsc   rxbit, 0
        bsf     STATUS, C
        btfss   rxbit, 0
        bcf     STATUS, C

        ; сдвигаем 4 байта вправо, перенос становится старшим битом посылки
        rrf     rx_timer_crc, F
        rrf     rx_timer, F
        rrf     rx_ident_crc, F
        rrf     rx_ident, F

        decfsz  Common_RAM, F
        goto    decode_next_bit

        ; прием посылки завершен

        ; проверка контрольной суммы идентификатора
        ; (лучше бы у идентификатора было 32 бита)
        movff   rx_ident, (Common_RAM + 1)
        movff   rx_ident_crc, (Common_RAM + 2)
        call    function_check_crc
        btfss   STATUS, Z
        return

        ; проверка контрольной суммы времени включения
        movff   rx_timer, (Common_RAM + 1)
        movff   rx_timer_crc, (Common_RAM + 2)
        call    function_check_crc
        btfss   STATUS, Z
        return

        ; читаем из EEPROM наш идентификатор
        bsf     STATUS, RP0
        movlf   EEPROM_IDENT, EEADR
        bcf     STATUS, RP0
        call    function_eeprom_read_next

        ; принятый идентификатор равен нашему?
        subwf   rx_ident, W
        btfss   STATUS, Z
        return

        ; да - включаем передатчик на rx_timer попугаев
        call    function_transmitter_timer

        return

function_transmitter_timer:                                 ; address: 0x005e

        ; включаем передатчик
        call    function_transmitter_on

        ; запускаем таймер выключения (гоняем пустые циклы, а лучше бы засыпать)
        movff   rx_timer, timer
        call    function_shortdelay228
        decfsz  timer, F
        goto    $-2

        ; выключаем передатчик и включаем приемник
        call    function_receive

        clrf    TMR1L
        clrf    TMR1H
        bcf     PIR1, T1IF

        return

function_check_crc:                                         ; address: 0x0069

        ; [3] = reverse(2)
        ; return [3] - ([1] ^ 0xff)

        clrf    (Common_RAM + 3)
        btfsc   (Common_RAM + 2), 0x7
        bsf     (Common_RAM + 3), 0x0
        btfsc   (Common_RAM + 2), 0x6
        bsf     (Common_RAM + 3), 0x1
        btfsc   (Common_RAM + 2), 0x5
        bsf     (Common_RAM + 3), 0x2
        btfsc   (Common_RAM + 2), 0x4
        bsf     (Common_RAM + 3), 0x3
        btfsc   (Common_RAM + 2), 0x3
        bsf     (Common_RAM + 3), 0x4
        btfsc   (Common_RAM + 2), 0x2
        bsf     (Common_RAM + 3), 0x5
        btfsc   (Common_RAM + 2), 0x1
        bsf     (Common_RAM + 3), 0x6
        btfsc   (Common_RAM + 2), 0x0
        bsf     (Common_RAM + 3), 0x7
        comf    (Common_RAM + 1), W
        subwf   (Common_RAM + 3), W
        return

function_short_on:                                          ; address: 0x007d

        call    function_mrf49_off
        call    function_transmitter_on
        call    function_shortdelay4
        call    function_mrf49_off
        return

function_transmitter_on:                                    ; address: 0x0082

        bsf     GPIO, AMP_POWER                             ; включить УНЧ

        bsf     STATUS, RP0
        clrf    EEADR                                       ; EEPROM_MRF_CFG_TX
        bcf     STATUS, RP0

        ; загрузить в MRF49 конфигурацию из EEPROM
        movlf   MRF_CFG_ON_LEN, i
label_009:                                                  ; address: 0x0088
        call    function_eeprom_read_next
        movwf   mrf49_word + 1
        call    function_eeprom_read_next
        movwf   mrf49_word
        call    function_mrf49_control
        decfsz  i, F
        goto    label_009

        bsf     STATUS, RP0
        bcf     TRISIO, TRISIO0
        bcf     STATUS, RP0
        bcf     GPIO, MRF49_DATA

        return

function_receive:                                           ; address: 0x0094

        bcf     GPIO, AMP_POWER                             ; выключить УНЧ
        bsf     STATUS, RP0
        movlf   EEPROM_MRF_CFG_RX, EEADR
        bcf     STATUS, RP0

        ; загрузить в MRF49 конфигурацию из EEPROM (6 слов)
        movlf   MRF_CFG_OFF_LEN, i
label_010:
        call    function_eeprom_read_next
        movwf   mrf49_word + 1
        call    function_eeprom_read_next
        movwf   mrf49_word
        call    function_mrf49_control
        decfsz  i, F
        goto    label_010

        bsf     STATUS, RP0
        bsf     TRISIO, TRISIO0
        bcf     STATUS, RP0
        return

function_sleep:                                             ; address: 0x00a6

        bcf     GPIO, AMP_POWER                             ; выключить УНЧ

        ; режим низкого энергопотребления (отключены передатчик и приемник)
        call    function_mrf49_off

        ; периодичность включения приемника записана в EEPROM
        bsf     STATUS, RP0
        movlf   EEPROM_SLEEP, EEADR
        bcf     STATUS, RP0
        call    function_eeprom_read_next

        ; засыпаем
        movwf   k
        sleep
        sleep
        decfsz  k, F
        goto    $-3

        ; включаем приемник
        call    function_receive

        clrf    TMR1L
        clrf    TMR1H
        bcf     PIR1, T1IF
        return

function_mrf49_off:                                         ; address: 0x00b7

        movlf   high MRF_PMCREG, mrf49_word + 1             ; стр. 38 даташита
        movlf   MRF_CLKODIS, mrf49_word
        call    function_mrf49_control

        bsf     STATUS, RP0
        bcf     TRISIO, TRISIO0
        bcf     STATUS, RP0
        bsf     GPIO, MRF49_DATA

        return

function_eeprom_init:                                       ; address: 0x00c1

        ; конфиругация передатчика MRF49
        bsf     STATUS, RP0
        clrf    EEADR                                       ; EEPROM_MRF_CFG_TX
        bcf     STATUS, RP0

        ; GENCREG: GENERAL CONFIGURATION REGISTER (page 22)
        movlw   high MRF_GENCREG
        call    function_eeprom_write_next
        ; bit 5-4FBS<1:0>: Frequency Band Select bits - диапазон
        ; These bits set the frequency band to be used in Sub-GHz range.
        ; 01 = 433 MHz
        ; bit 3-0LCS<3:0>: Load Capacitance Select bits
        ; These bits set and vary the internal load capacitance for the crystal reference.
        ; 1111 = 16.0 pF
        movlw   TX_BAND | MRF_LCS_MASK
        call    function_eeprom_write_next

        ; CFSREG: CENTER FREQUENCY VALUE SET REGISTER (page 28)
        movlw   high MRF_CFSREG | (high TX_FVAL)
        call    function_eeprom_write_next
        ; bit 11-0FREQB<11:0>: Center Frequency Set bits - частота
        ; These bits set the center frequency to be used during transmit or receive. The 12-bit value (FVAL) must
        ; be in a decimal range of 96 to 3903. The value outside this range results in the previous value being
        ; retained and used such that no frequency change occurs
        movlw   low TX_FVAL
        call    function_eeprom_write_next

        ; TXCREG: TRANSMIT CONFIGURATION REGISTER (page 25)
        movlw   high MRF_TXCREG
        call    function_eeprom_write_next
        ; bit 7-4MODBW<3:0>: Modulation Bandwidth bits
        ; These bits set the FSK frequency deviation for transmitting the logic ‘1’ and logic ‘0’.(1)
        ; 0000 = 15 kHz
        ; OTXPWR<2:0>: Output Transmit Power Range bits
        ; 000 = 0 dB (максимальная мощность)
        movlw   MRF_MODBW_15K | MRF_OTXPWR_0
        call    function_eeprom_write_next

        ; AFCCREG: AUTOMATIC FREQUENCY CONTROL CONFIGURATION REGISTER
        movlw   high MRF_AFCCREG
        call    function_eeprom_write_next
        ; отключить автоподстройку частоты (АПЧ)
        ; 00 = Auto mode off (controlled by microcontroller)
        ; These bits select the offset range allowable between transmitter and receiver frequencies.
        ; 00 = No restriction
        ; MFCS: Manual Frequency Control Strobe bit
        ; 0 = Ready for the next sample
        ; HAM: High-Accuracy (Fine) Mode bit
        ; 0 = Frequency Control mode works in regular mode
        ; FOREN: Frequency Offset Register Enable bit
        ; 0 = Denies the addition of the offset value to the frequency control word of the PLL
        ; FOFEN: Frequency Offset Enable bit
        ; 0 = Disables the frequency offset calculation using the AFC circuit
        movlw   MRF_AUTOMS_OFF
        call    function_eeprom_write_next

        ; PMCREG: POWER MANAGEMENT CONFIGURATION REGISTER (page 38)
        movlw   high MRF_PMCREG
        call    function_eeprom_write_next
        ; передатчик включен, приемник выключен, синтезатор включен
        ; индикатор разряда батареи выключен, таймер пробуждения отключен
        movlw   MRF_TXCEN | MRF_SYNEN | MRF_OSCEN | MRF_CLKODIS
        call    function_eeprom_write_next

        bsf     STATUS, RP0

        ; конфиругация приемника MRF49
        movlw   EEPROM_MRF_CFG_RX
        movwf   EEADR
        bcf     STATUS, RP0

        ; GENCREG: GENERAL CONFIGURATION REGISTER (page 22)
        movlw   high MRF_GENCREG
        call    function_eeprom_write_next
        ; см. выше
        movlw   RX_BAND | MRF_LCS_MASK
        call    function_eeprom_write_next

        ; CFSREG: CENTER FREQUENCY VALUE SET REGISTER
        movlw   high MRF_CFSREG | (high RX_FVAL)
        call    function_eeprom_write_next
        ; см. выше
        movlw   low RX_FVAL
        call    function_eeprom_write_next

        ; RXCREG: RECEIVE CONTROL REGISTER (page 29)
        ; bit 9-8DIORT<1:0>: Data Indicator Output Response Time bits
        ; 01 = Medium
        movlw   high MRF_RXCREG | high MRF_DIORT_MED
        call    function_eeprom_write_next
        ; RXBW<2:0>: Receiver Baseband Bandwidth bits
        ; bit 4-3RXLNA<1:0>: Receiver LNA Gain bits
        ; 00 = 0 dB (наибольшая чувствительность)
        ; DRSSIT<2:0>: Digital RSSI Threshold bits
        ; 000 = -103 dB (наибольшая чувствительность)
        movlw   SELECTED_MRF_BW | MRF_RXLNA_0DB | MRF_DRSSIT_103db
        call    function_eeprom_write_next

        ; DRSREG: DATA RATE VALUE SET REGISTER (page 37)
        movlw   high MRF_DRSREG
        call    function_eeprom_write_next
        ; DRPE: Date Rate Prescaler Enable bit
        ; 1 = Enables the prescaler to obtain smaller values of expected data rates.
        ; DRPV<6:0>: Data Rate Parameter Value bits
        ; If the prescaler is not used, the data rates range
        ; from 2.694 kbps to 344.828 kbps
        movlw   (REMOTE_CONTROL_RATE/(10000/29)/8)
        call    function_eeprom_write_next

        ; AFCCREG: AUTOMATIC FREQUENCY CONTROL CONFIGURATION REGISTER (page 23)
        movlw   high MRF_AFCCREG
        call    function_eeprom_write_next
        ; отключить АПЧ
        movlw   MRF_AUTOMS_OFF
        call    function_eeprom_write_next

        ; Power Management Configuration Register
        movlw   high MRF_PMCREG
        call    function_eeprom_write_next
        movlw   MRF_RXCEN | MRF_BBCEN | MRF_SYNEN | MRF_OSCEN | MRF_CLKODIS
        call    function_eeprom_write_next

        ; адрес сейчас равен EEPROM_SLEEP
        movlw   DUTY_CYCLE
        call    function_eeprom_write_next

        return

function_mrf49_control:                                     ; address: 0x00f7

        bcf     GPIO, MRF49_CS
        movlf   16, Common_RAM

label_012:

        btfsc   mrf49_word + 1, 7
        call    function_mrf49_bit1
        btfss   mrf49_word + 1, 7
        call    function_mrf49_bit0

        rlf     mrf49_word, F
        rlf     mrf49_word + 1, F

        decfsz  Common_RAM, F
        goto    label_012

        bsf     GPIO, MRF49_CS

        return

function_mrf49_bit0:                                        ; address: 0x0104

        bcf     GPIO, MRF49_SDI
        goto    label_013

function_mrf49_bit1:                                         ; address: 0x0106

        bsf     GPIO, MRF49_SDI

label_013:

        clrwdt
        bsf     GPIO, MRF_SCK
        clrwdt
        bcf     GPIO, MRF_SCK
        clrwdt
        return

function_shortdelay:                                        ; address: 0x010d

        clrf    i
        clrf    j

        clrwdt
        decfsz  j, F
        goto    $-2
        decfsz  i, F
        goto    $-2

        return

function_shortdelay4:                                       ; address: 0x0115

        movlf   4, k
        call    function_shortdelay
        decfsz  k, F
        goto    $-2
        return

function_shortdelay228:                                     ; address: 0x011b

        movlf   228, k

        call    function_shortdelay
        decfsz  k, F
        goto    $-2

        return

function_eeprom_write_next:                                 ; address: 0x0121

        ; "бережная" запись в EEPROM?

        bsf     STATUS, RP0
        bsf     EECON1, RD
        comf    EEDAT, F                                    ; проверка на 0xff
        btfss   STATUS, Z                                   ; ячейка пустая?
        goto    alredy_written

        movwf   EEDATA
        bsf     EECON1, WREN
        call    function_eeprom_write

alredy_written:                                             ; address: 0x0129

        incf    EEADR, F
        bcf     STATUS, RP0
        return

function_eeprom_write:                                      ; address: 0x012c

        ; Flash programming unlock sequence
        movlf   0x55, EECON2
        movlf   0xaa, EECON2

        bsf     EECON1, WR
        clrwdt
        btfsc   EECON1, WR
        goto    $-2

        bcf     EECON1, WREN
        return

function_eeprom_read_next                                   ; address: 0x0136

        bsf     STATUS, RP0
        bsf     EECON1, RD
        movf    EEDAT, W
        incf    EEADR, F
        bcf     STATUS, RP0
        return
        end

        end

© Copyright 2025 Badradio. All rights reserved.

Все права защищены. Копирование материалов сайта запрещено. При цитировании ставить ссылку на первоисточник.