Skip to main content
Son, Dong-Seong
Associate III
June 9, 2025
Question

About S2LP with STM32F103VCT

  • June 9, 2025
  • 0 replies
  • 266 views

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
}
 
Schematic is below
SonDongSeong_0-1749466815822.png

I would appreciate it if you could let me know which parts might be incorrect.