2025-06-09 4:05 AM - last edited on 2025-06-09 5:16 AM by Peter BENSCH
Hello everyone,
I’m trying to control an S2-LP QTR via SPI1 on an STM32F103VCT.
I completed the initial setup and configured the radio to 420 MHz.
I then wrote a routine to transmit periodically, but I’m not seeing any RF output on the antenna pin.
Below is the code I’m using for the S2-LP QTR. Any ideas what might be going wrong?
void S2LP_Init(void)
{
// 1 : SDN pin LOW -> Enter operating mode
S2LP_SDN_LOW(); // SDN LOW → 동작모드
HAL_Delay(10);
// 2 : soft reset (SRES)
// S2LP_SoftReset();
S2LP_SetCommand(CMD_SRES);
// 3 : Setting XO/ RCO
// Disable digital clock divider -> digital clock = fxo
S2LP_WriteReg(XO_RCO_CONF1_ADDR, PD_CLKDIV_REGMASK);
S2LP_WriteReg(XO_RCO_CONF0_ADDR, EXT_REF_REGMASK | GM_CONF_REGMASK);
// 4 : SMPS power management configuration
// 4-1 : internal smps
// S2LP_WriteReg(PM_CONF4_ADDR, 0x00);
// PM_CONF0: SET_SMPS_LVL = 011b → 1.4V (HPM), SLEEP_MODE_SEL=0
// S2LP_WriteReg(PM_CONF0_ADDR, SET_SMPS_LVL_REGMASK); // :contentReference[oaicite:3]{index=3}
// PM_CONF1: default (battery level detection enabled, SMPS level mode in TX)
// S2LP_WriteReg(PM_CONF1_ADDR, BATTERY_LVL_EN_REGMASK | SET_BLD_TH_REGMASK); // :contentReference[oaicite:4]{index=4}
// 4-2 : external smps
S2LP_WriteReg(PM_CONF4_ADDR, EXT_SMPS_REGMASK);
// 5 : Setting GPIO
S2LP_WriteReg(S2LP_GPIO0_CONF, (GPIO_Digi_Out_TX_FIFO_Empty<<GPIO_SELECT_BIT) | (GPIO_DigitalOutputLow<<GPIO_MODE)); // GPIO0: TX FIFO Almost Empty
S2LP_WriteReg(S2LP_GPIO1_CONF, (GPIO_Digi_Out_RX_Data_Out<<GPIO_SELECT_BIT) | (GPIO_DigitalOutputLow<<GPIO_MODE)); // GPIO1: RX data ready
S2LP_WriteReg(S2LP_GPIO2_CONF, 0x00); // GPIO2: NIRQ
S2LP_WriteReg(S2LP_GPIO3_CONF, 0x00); // GPIO3: LOW
// 6 : Data rate setting (e.g., datarate in bps)
// mantissa/exponent Calculation : DataRate = fdig * M / 2^E
uint64_t tmp = (uint64_t)datarate << 28;
uint32_t dr_mant = (uint32_t)(tmp / fxo);
uint8_t dr_exp = (dr_mant >> 28) & 0x0F;
uint16_t dr_man = (uint16_t)(dr_mant & 0x0FFF);
S2LP_WriteReg(MOD4_ADDR, (uint8_t)(dr_man >> 8)); // DATARATE_M[15:8] :contentReference[oaicite:5]{index=5}
S2LP_WriteReg(MOD3_ADDR, (uint8_t)(dr_man & 0xFF)); // DATARATE_M[7:0] :contentReference[oaicite:6]{index=6}
// MOD2: upper 4 bits = modulation type (2-GFSK BT=0.5 → 0xA), lower 4 bits = dr_exp
S2LP_WriteReg(MOD2_ADDR, (0xA << 4) | dr_exp);
// 7 : FDEV: frequency deviation setting (e.g., 20 kHz)
uint32_t fdev = 20000;
tmp = (uint64_t)fdev << 18;
uint32_t fdv_mant = (uint32_t)(tmp / fxo);
uint8_t fdv_exp = (fdv_mant >> 8) & 0x0F;
uint8_t fdv_man = (uint8_t)(fdv_mant & 0xFF);
S2LP_WriteReg(MOD0_ADDR, fdv_man); // FDEV_M :contentReference[oaicite:7]{index=7}
// CONST_MAP: default = 0, lower 4 bits = fdv_exp
S2LP_WriteReg(MOD1_ADDR, (0 << 4) | fdv_exp); // CONST_MAP+FDEV_E :contentReference[oaicite:8]{index=8}
HAL_Delay(1);
S2LP_WriteReg(PA_POWER8_ADDR, 80); // +10dBm
S2LP_WriteReg(PA_POWER7_ADDR, 76); // +8dBm
S2LP_WriteReg(PA_POWER6_ADDR, 72); // +6dBm
S2LP_WriteReg(PA_POWER5_ADDR, 68); // +4dBm
S2LP_WriteReg(PA_POWER4_ADDR, 64); // +2dBm
S2LP_WriteReg(PA_POWER3_ADDR, 60); // +0dBm
S2LP_WriteReg(PA_POWER2_ADDR, 56); // -2dBm
S2LP_WriteReg(PA_POWER1_ADDR, 52); // -4dBm
}
void S2LP_SetFrequency(float freqMHz)
{
const float fXO = 25.0f; // 25 MHz crystal
const uint8_t BS = 8; // SYNT3 bit4 = 1 for middle band
const uint8_t BSbit = BS_REGMASK;
// 28-bit N = freqRF × 2^20 / fXO
uint32_t N = (uint32_t)((freqMHz * BS * (1 << 20)) / fXO);
// 분해
uint8_t synt3 = ((N >> 24) & 0x0F) | BSbit;
uint8_t synt2 = (N >> 16) & 0xFF;
uint8_t synt1 = (N >> 8) & 0xFF;
uint8_t synt0 = N & 0xFF;
// 올바른 레지스터에 쓰기
S2LP_WriteReg(SYNT3_ADDR, synt3); // 0x05, SYNT3(PLL_CP_ISEL|BS|N[27:24])
S2LP_WriteReg(SYNT2_ADDR, synt2); // 0x06, N[23:16]
S2LP_WriteReg(SYNT1_ADDR, synt1); // 0x07, N[15:8]
S2LP_WriteReg(SYNT0_ADDR, synt0); // 0x08, N[7:0]
S2LP_SetCommand(CMD_RCO_CALIB); // Start (or re-start) the RCO calibration
S2LP_SetCommand(CMD_LOCKTX);
S2LP_SetCommand(CMD_LOCKRX);
}
void S2LP_SetOutputPower(uint8_t level_index)
{
// 인덱스 범위 체크
if(level_index > 7) {
level_index = 7;
}
// PA_POWER0: HPM(최대 dBm) 모드 + 램핑 사용 + level 인덱스
uint8_t pa0 = PA_MAXDBM_REGMASK // bit6 = 1 → HPM 모드
| PA_RAMP_EN_REGMASK // bit5 = 1 → 램핑 사용
| (level_index & PA_LEVEL_MAX_IDX_REGMASK);
S2LP_WriteReg(PA_POWER0_ADDR, pa0);
// PA_CONFIG1: 선형 모드 + FIR 필터링
uint8_t pa1 = LIN_NLOG_REGMASK // bit4 = 1 → 선형 모드
| FIR_EN_REGMASK; // bit1 = 1 → FIR 사용
S2LP_WriteReg(PA_CONFIG1_ADDR, pa1);
}
void S2LP_SendPacket(uint8_t* data, uint8_t length)
{
S2LP_SetCommand(CMD_READY);
S2LP_SetCommand(CMD_FLUSHTXFIFO);
S2LP_WriteReg(PCKTLEN1_ADDR, (length >> 8) & 0xFF); // PCKTLEN
S2LP_WriteReg(PCKTLEN0_ADDR, length & 0xFF); // SYNC config
// FIFO write
S2LP_CSN_LOW();
uint8_t cmd = CMD_WRITE_FIFO;
HAL_SPI_Transmit(&hspi1, &cmd, 1, HAL_MAX_DELAY);
HAL_SPI_Transmit(&hspi1, data, length, HAL_MAX_DELAY);
S2LP_CSN_HIGH();
// Start TX
S2LP_SetCommand(CMD_TX);
while ((S2LP_ReadReg(MC_STATE1_ADDR) & (1<<7)) == 0) {
HAL_Delay(1);
}
S2LP_SetCommand(CMD_READY);
S2LP_SetCommand(CMD_FLUSHRXFIFO);
S2LP_SetCommand(CMD_RX);
}
void S2LP_StartRx(void) {
S2LP_WriteReg(0x3E, 64); // 예상 최대 수신길이
uint8_t rx_cmd = 0x61; // RX Command
S2LP_CSN_LOW();
HAL_SPI_Transmit(&hspi1, &rx_cmd, 1, HAL_MAX_DELAY);
S2LP_CSN_HIGH();
}
uint8_t S2LP_IsRxReceived(void)
{
// GPIO1을 NIRQ로 설정했다면 해당 핀 인터럽트 확인
return HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET;
}
void S2LP_ReadReceivedData(uint8_t* buffer, uint8_t length) {
uint8_t cmd = 0x77;
S2LP_CSN_LOW();
HAL_SPI_Transmit(&hspi1, &cmd, 1, HAL_MAX_DELAY);
HAL_SPI_Receive(&hspi1, buffer, length, HAL_MAX_DELAY);
S2LP_CSN_HIGH();
}
static uint8_t S2LP_ReadReg(uint8_t addr)
{
uint8_t tx[2] = {0x01, addr};
uint8_t rx[1];
S2LP_CSN_LOW();
HAL_SPI_Transmit(&hspi1, tx, 2, HAL_MAX_DELAY);
HAL_SPI_Receive(&hspi1, rx, 1, HAL_MAX_DELAY);
S2LP_CSN_HIGH();
return rx[0];
}
static void S2LP_WriteReg(uint8_t addr, uint8_t val)
{
uint8_t tx[3] = {0x00, addr, val};
S2LP_CSN_LOW();
HAL_SPI_Transmit(&hspi1, tx, 3, HAL_MAX_DELAY);
S2LP_CSN_HIGH();
}
static void S2LP_SetCommand(uint8_t cmd)
{
S2LP_CSN_LOW(); // CSN low start
HAL_SPI_Transmit(&hspi1, &cmd, 1, HAL_MAX_DELAY);
S2LP_CSN_HIGH(); // CSN high terminate
HAL_Delay(1); // standby reset
}
I would appreciate it if you could let me know which parts might be incorrect.