SI4432 module just not transmitting #11570
-
Hey! I've got a RPi Pico connected to a SI4432 module for which I tried porting this library but I just can't get it to transmit. Nothing comes up on an SDR and I don't even get the packet sent interrupt. I've got no clue as to what's wrong at this point. Can someone point me in the right direction here? Thanks in advance. si4432.py import math
import utime
class SI4432:
REG_DEV_TYPE = 0x00
REG_DEV_VERSION = 0x01
REG_DEV_STATUS = 0x02
REG_INT_STATUS1 = 0x03
REG_INT_STATUS2 = 0x04
REG_INT_ENABLE1 = 0x05
REG_INT_ENABLE2 = 0x06
REG_STATE = 0x07
REG_OPERATION_CONTROL = 0x08
REG_GPIO0_CONF = 0x0B
REG_GPIO1_CONF = 0x0C
REG_GPIO2_CONF = 0x0D
REG_IOPORT_CONF = 0x0E
REG_IF_FILTER_BW = 0x1C
REG_AFC_LOOP_GEARSHIFT_OVERRIDE = 0x1D
REG_AFC_TIMING_CONTROL = 0x1E
REG_CLOCK_RECOVERY_GEARSHIFT = 0x1F
REG_CLOCK_RECOVERY_OVERSAMPLING = 0x20
REG_CLOCK_RECOVERY_OFFSET2 = 0x21
REG_CLOCK_RECOVERY_OFFSET1 = 0x22
REG_CLOCK_RECOVERY_OFFSET0 = 0x23
REG_CLOCK_RECOVERY_TIMING_GAIN1 = 0x24
REG_CLOCK_RECOVERY_TIMING_GAIN0 = 0x25
REG_RSSI = 0x26
REG_RSSI_THRESHOLD = 0x27
REG_AFC_LIMITER = 0x2A
REG_AFC_CORRECTION_READ = 0x2B
REG_DATAACCESS_CONTROL = 0x30
REG_EZMAC_STATUS = 0x31
REG_HEADER_CONTROL1 = 0x32
REG_HEADER_CONTROL2 = 0x33
REG_PREAMBLE_LENGTH = 0x34
REG_PREAMBLE_DETECTION = 0x35
REG_SYNC_WORD3 = 0x36
REG_SYNC_WORD2 = 0x37
REG_SYNC_WORD1 = 0x38
REG_SYNC_WORD0 = 0x39
REG_TRANSMIT_HEADER3 = 0x3A
REG_TRANSMIT_HEADER2 = 0x3B
REG_TRANSMIT_HEADER1 = 0x3C
REG_TRANSMIT_HEADER0 = 0x3D
REG_PKG_LEN = 0x3E
REG_CHECK_HEADER3 = 0x3F
REG_CHECK_HEADER2 = 0x40
REG_CHECK_HEADER1 = 0x41
REG_CHECK_HEADER0 = 0x42
REG_RECEIVED_HEADER3 = 0x47
REG_RECEIVED_HEADER2 = 0x48
REG_RECEIVED_HEADER1 = 0x49
REG_RECEIVED_HEADER0 = 0x4A
REG_RECEIVED_LENGTH = 0x4B
REG_CHARGEPUMP_OVERRIDE = 0x58
REG_DIVIDER_CURRENT_TRIM = 0x59
REG_VCO_CURRENT_TRIM = 0x5A
REG_AGC_OVERRIDE = 0x69
REG_TX_POWER = 0x6D
REG_TX_DATARATE1 = 0x6E
REG_TX_DATARATE0 = 0x6F
REG_MODULATION_MODE1 = 0x70
REG_MODULATION_MODE2 = 0x71
REG_FREQ_DEVIATION = 0x72
REG_FREQ_OFFSET1 = 0x73
REG_FREQ_OFFSET2 = 0x74
REG_FREQBAND = 0x75
REG_FREQCARRIER_H = 0x76
REG_FREQCARRIER_L = 0x77
REG_FREQCHANNEL = 0x79
REG_CHANNEL_STEPSIZE = 0x7A
REG_FIFO = 0x7F
IF_FILTER_TABLE = [[322, 0x26], [3355, 0x88], [3618, 0x89], [4202, 0x8A], [4684, 0x8B], [5188, 0x8C], [5770, 0x8D],
[6207, 0x8E]]
RXMode = 0x04
TXMode = 0x08
Ready = 0x01
TuneMode = 0x02
MAX_TRANSMIT_TIMEOUT = 200
def __init__(self, spi, cs):
self.spi = spi
self.cs = cs # machine.Pin
self.freq_carrier = 433
self.kbps = 100
self.package_sign = 0xDEAD
# Set chip select to high to indicate no active communication.
self.cs.value(1)
# Check sync word.
sw3 = self.read_register(self.REG_SYNC_WORD3)
sw2 = self.read_register(self.REG_SYNC_WORD2)
sw1 = self.read_register(self.REG_SYNC_WORD1)
sw0 = self.read_register(self.REG_SYNC_WORD0)
if sw3 == 0x2D and sw2 == 0xD4:
print("Sync word OK")
else:
raise Exception("Sync word does not match")
self.boot()
def boot(self):
# Rewritten from https://github.com/nopnop2002/Arduino-SI4432/blob/main/si4432.cpp
self.change_register(self.REG_AFC_TIMING_CONTROL, 0x02) # ?? // refer to AN440 for reasons
self.change_register(self.REG_AFC_LIMITER, 0xFF) # write max value - excel file did that
self.change_register(self.REG_AGC_OVERRIDE, 0x60) # max gain control
self.change_register(self.REG_AFC_LOOP_GEARSHIFT_OVERRIDE, 0x3C) # turn off afc
self.change_register(self.REG_DATAACCESS_CONTROL,
0xAD) # enable crc, enable tx packet handler, enable rx packet handler
self.change_register(self.REG_HEADER_CONTROL1,
0x0C) # no broadcast address, enable check headers for bytes 3, 2
self.change_register(self.REG_HEADER_CONTROL2,
0x22) # enable headers byte 3, 2, no fixed packet length, sync word 3, 2
self.change_register(self.REG_PREAMBLE_LENGTH, 0x08) # 8 * 4 bits = 32 bits (4 bytes) preamble length
self.change_register(self.REG_PREAMBLE_DETECTION, 0x3A) # validate 7 * 4 bytes preamble in a packet
self.change_register(self.REG_SYNC_WORD3, 0x2D) # sync word 3
self.change_register(self.REG_SYNC_WORD2, 0xD4) # sync word 2
self.change_register(self.REG_TX_POWER, 0x1F) # max power
self.change_register(self.REG_CHANNEL_STEPSIZE, 0x64) # each channel is 1 mhz apart
self.set_frequency(433) # 433 mhz
self.set_baud_rate(70) # 100 kbps
self.set_channel(0) # channel 0
self.set_comms_signature(0xDEAD) # signature
self.switch_mode(self.Ready)
def start_listening(self):
self.clear_rx_fifo()
self.change_register(self.REG_INT_ENABLE1, 0x03) # enable packet received and crc error interrupts
self.change_register(self.REG_INT_ENABLE2, 0x00) # disable all other interrupts
self.read_register(self.REG_INT_STATUS1) # clear interrupt flags
self.read_register(self.REG_INT_STATUS2)
self.switch_mode(self.RXMode | self.Ready)
def get_packet_received(self):
length = self.read_register(self.REG_RECEIVED_LENGTH)
print("Length: ", length)
data = self.burst_read(self.REG_FIFO, length)
self.clear_rx_fifo()
return data
def is_packet_received(self):
int_stat = self.read_register(self.REG_INT_STATUS1)
self.read_register(self.REG_INT_STATUS2)
if int_stat & 0x02:
self.switch_mode(self.Ready | self.TuneMode)
return True
elif int_stat & 0x01:
self.switch_mode(self.Ready)
print("CRC ERR")
self.clear_rx_fifo()
self.switch_mode(self.RXMode | self.Ready)
return False
def clear_rx_fifo(self):
self.change_register(self.REG_OPERATION_CONTROL, 0x02)
self.change_register(self.REG_OPERATION_CONTROL, 0x00)
def clear_tx_fifo(self):
self.change_register(self.REG_OPERATION_CONTROL, 0x01)
self.change_register(self.REG_OPERATION_CONTROL, 0x00)
def soft_reset(self):
self.change_register(self.REG_STATE, 0x01)
self.change_register(self.REG_STATE, 0x80)
reg = self.read_register(self.REG_INT_STATUS2)
while (reg & 0x02) != 0x02:
utime.sleep_ms(1)
reg = self.read_register(self.REG_INT_STATUS2)
self.boot()
def send_packet(self, data):
self.clear_tx_fifo()
self.change_register(self.REG_PKG_LEN, len(data))
# Convert list of bytes to list of bytearray where [0] is the byte.
for i in range(len(data)):
x = bytearray(1)
x[0] = data[i]
data[i] = x
print(data)
self.burst_write(self.REG_FIFO, data, len(data))
self.change_register(self.REG_INT_ENABLE1, 0x04)
self.change_register(self.REG_INT_ENABLE2, 0x00)
self.read_register(self.REG_INT_STATUS1)
self.read_register(self.REG_INT_STATUS2)
self.switch_mode(self.TXMode | self.Ready)
enter_millis = int(utime.ticks_ms())
while (int(utime.ticks_ms()) - enter_millis) < self.MAX_TRANSMIT_TIMEOUT:
int_status = self.read_register(self.REG_INT_STATUS1)
dev_status = self.read_register(self.REG_DEV_STATUS)
ezmac = self.read_register(self.REG_EZMAC_STATUS)
print("int_status: " + str(hex(int_status)))
print("dev_status: " + str(hex(dev_status)))
print("ezmac: " + str(hex(ezmac)))
if (int_status & 0x04) == 0x04: # or (int_status & 0x20) == 0x20:
self.soft_reset()
return True
print("Transmit timeout")
self.soft_reset()
return False
def set_frequency(self, freq):
if freq < 240 or freq > 930:
raise Exception("Frequency out of range")
self.freq_carrier = freq
high_band = False
if freq >= 480:
high_band = True
f_part = (freq / (10 * (2 if high_band else 1))) - 24
freq_band = int(f_part)
freq_carrier = math.floor((f_part - freq_band) * 64000)
values = bytearray(1)
values1 = bytearray(1)
values2 = bytearray(1)
values[0] = 0x40 | ((1 if high_band else 0) << 5) | (freq_band & 0x3F)
values1[0] = freq_carrier >> 8
values2[0] = freq_carrier & 0xFF
self.burst_write(self.REG_FREQBAND, [values, values1, values2], 3)
def set_baud_rate(self, kbps):
if kbps > 256 or kbps < 1:
raise Exception("Baud rate out of range")
self.kbps = kbps
freq_dev = 15 if kbps <= 10 else 150
modulation_value = 0x4c if kbps < 30 else 0x0c
modulation_vals = bytearray(1)
modulation_vals1 = bytearray(1)
modulation_vals2 = bytearray(1)
modulation_vals[0] = modulation_value
modulation_vals1[0] = 0x23
modulation_vals2[0] = round((freq_dev * 1000) / 625.0)
self.burst_write(self.REG_MODULATION_MODE1, [modulation_vals, modulation_vals1, modulation_vals2], 3)
bps_reg_val = round((kbps * (2097152 if kbps < 30 else 65536.0)) / 1000.0)
datarate_vals = bytearray(1)
datarate_vals1 = bytearray(1)
datarate_vals[0] = bps_reg_val >> 8
datarate_vals1[0] = bps_reg_val & 0xFF
self.burst_write(self.REG_TX_DATARATE1, [datarate_vals, datarate_vals1], 2)
min_bandwidth = (2 * freq_dev) + kbps
if_value = 0xff
for i in range(8):
if self.IF_FILTER_TABLE[i][0] >= min_bandwidth * 10:
if_value = self.IF_FILTER_TABLE[i][1]
break
self.change_register(self.REG_IF_FILTER_BW, if_value)
dwn3_bypass = 1 if if_value & 0x80 else 0
ndec_exp = (if_value >> 4) & 0x07
rx_oversampling = round((500.0 * (1 + 2 * dwn3_bypass)) / ((pow(2, ndec_exp - 3)) * kbps))
nc_offset = math.ceil((kbps * (pow(2, ndec_exp + 20))) / (500.0 * (1 + 2 * dwn3_bypass)))
cr_gain = math.floor(2 + ((65535 * kbps) / (rx_oversampling * freq_dev)))
cr_multiplier = 0x00
if cr_gain > 0x7ff:
cr_gain = 0x7ff
timing_vals = bytearray(1)
timing_vals1 = bytearray(1)
timing_vals2 = bytearray(1)
timing_vals3 = bytearray(1)
timing_vals4 = bytearray(1)
timing_vals5 = bytearray(1)
timing_vals[0] = rx_oversampling & 0x00ff
timing_vals1[0] = (rx_oversampling & 0x7000) >> 3 | (nc_offset >> 16) & 0x0f
timing_vals2[0] = (nc_offset >> 8) & 0xff
timing_vals3[0] = nc_offset & 0xff
timing_vals4[0] = ((cr_gain & 0x0700) >> 8) | cr_multiplier
timing_vals5[0] = cr_gain & 0xff
self.burst_write(self.REG_CLOCK_RECOVERY_OVERSAMPLING,
[timing_vals, timing_vals1, timing_vals2, timing_vals3, timing_vals4, timing_vals5], 6)
def set_channel(self, channel):
self.change_register(self.REG_FREQCHANNEL, channel)
def set_comms_signature(self, signature):
self.package_sign = signature
self.change_register(self.REG_TRANSMIT_HEADER3, signature >> 8)
self.change_register(self.REG_TRANSMIT_HEADER2, signature & 0xFF)
self.change_register(self.REG_CHECK_HEADER3, signature >> 8)
self.change_register(self.REG_CHECK_HEADER2, signature & 0xFF)
def switch_mode(self, mode):
self.change_register(self.REG_STATE, mode)
def read_register(self, address):
return self.burst_read(address)
def change_register(self, address, value):
b = bytearray(1)
b[0] = value
self.burst_write(address, [b])
def burst_read(self, address, length=1):
# Burst read
buf = bytearray(1)
buf[0] = address & 0x7F
self.cs.value(0)
self.spi.write(buf)
# for i in range(1):
values = [0] * length
for i in range(length):
values[i] = list(self.spi.read(1, 0xFF))[0]
self.cs.value(1)
if length == 1:
return values[0]
return values
def burst_write(self, address, values, length=1):
# Burst write
buf = bytearray(1) # 1 byte for address
buf[0] = address | 0x80
self.cs.value(0)
self.spi.write(buf)
for i in range(len(values)):
self.spi.write(values[i])
self.cs.value(1) |
Beta Was this translation helpful? Give feedback.
Answered by
xE1H
May 20, 2023
Replies: 1 comment
-
I tried dumping all of the registers and saw that it was basically writing jibberish everywhere. Upon further inspection, my 3v3 power wire was barely holding on... Fixed. |
Beta Was this translation helpful? Give feedback.
0 replies
Answer selected by
xE1H
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I tried dumping all of the registers and saw that it was basically writing jibberish everywhere. Upon further inspection, my 3v3 power wire was barely holding on... Fixed.