SPI

STM32 programming SPI for Si4432 transceiver

Si4432 transceiver

Using FTDI as power source

Before anything, if you are using STM32 with ST-Link, then MCU and Si4432 is powered by ST-Link. When done with programming, you can use USB FTDI adapter as power source for 3.3V, but first move jumper from 5V to 3.3V (!). Else you can damage both, MCU and SI4432. On block diagram, this wire connection is not shown for reason that some FTDI adapter has voltage selection on bottom side, then you need to solder jumper pads to 3.3V. Here is picture with recommended setting for FTDI for use on your computer and for powering MCU with Si4432:

FTDI

Si4432

To get it working properly, when typing into console, console should be able to send LF and/OR CR symbol (decimal 10 or 13), so rather use HTerm, it is free for Windows and Linux. Do not use both CR and LF (CR-LF), else one of those may be sent over the radio and at receiving site one may notice moving text two rows instead one. Here is screenshot:

HTerm

Default setting in ‘printMsg.c’ is 115200 baud, but you can change to your value, just comment with ‘//’ this one and un-comment (remove ‘//’) one that is the best for you. If you chose less than 9600, then whole thing will be slower than transceiver. In HTerm, there is window with COM port, if it is already open, it will NOT refresh automatically new COM port, you need to click on ‘R’ button next to window with COM port names. Enable “Newline at” and chose LF, you may disable “Show newline characters”.

Codes for remote controller

The codes below is for remote terminal, for communication between two points at fixed frequency and fixer data rate in bauds. For remote controller, the code must be modified. I will do that too, but not sure how soon. If you want it sooner, please buy me a beer. 😀  Just because I have many things to do at once, and sometimes long time may pass between page update. This will kick me to do more.

Codes:

/* This software is provided by https://wildlab.org and
   Milan Karakas from Croatia. This is free program, but 
	 also "beerware". This means if you want this beta test
	 phase to grow into something really great, please buy
	 me a beer :) https://www.paypal.me/milankarakas?locale.x=en_US
	 It is still in beta test phase, and will be upgraded. 
	 BE EXTREMELY CAREFUL WITH FREQUENCY AND POWER !!!
   Your module may be damaged if not made for specific freq
   range. For example, 433 MHz modules from eBay may work
   from say 400 - 440 MHz, but not outside that range. Also
   other modules (315 MHz, 868 Mhz) works with close range. 
   This is because each module has different output low pass
   filter, and phase shifter for the receiver. Transmitter may burn
   if wrong frequency, and receiver may be insensitive due to
   wrong phase on differential inputs. I warned you !!!
   Also, DO NOT use small spring-looking antena that comes
   with the module - this is pure crap. For 433 MHz use for
   example 17 cm wire, or better solder proper coaxial cable
   and proper antenna. Good antenna gives more range than power.	 
	 Later, will ad my own math to do that, but since it is still
	 in beta testing phase... stay tuned.
*/

#include "stm32f10x.h"
#include "printMsg.h"
#include "delayUs.h"
//#include "string.h"
#include "spi.h"
#include "si4432.h"

int len=0;

int main()
{
	usart_1_enable(); //enabling serial protocol
	spiEnable(); //enabling SPI protocol
	
	/* Be careful with the frequency of your module, and power !!! */
	setModule(433.120,0); // (frequency in MHz, power in steps from 0 to 7, or 1.26 mW to 100 mW)
	//enabling and initializating Si4432, setting IRQ for USART, 
	//setting freq (240.001-959.999 MHz), not a Hz outside (!)
  //Output power: 
	/*
	  0 = +1  dBm =  1.26 mW
	  1 = +2  dBm =  1.58 mW
	  2 = +5  dBm =  3.16 mW
	  3 = +8  dBm =  6.31 mW
	  4 = +11 dBm = 12,59 mW
	  5 = +14 dBm = 25.12 mW
	  6 = +17 dBm = 50.12 mW
	  7 = +20 dBm = 100 mW (!)
	(modem baud rate is 9600, I did not finish calculations for that, and other parameters as is type of modulation...)
	(modem currently works in (G)FSK (Gaussian filtered FSK) )
	(USART PC-MCU is 115200, configurable in 'printMsg.c')
	*/
	
	while(1)	listenRadio();
}
/* This software is provided by https://wildlab.org and
   Milan Karakas from Croatia. This is free program, but 
	 also "beerware". This means if you want this beta test
	 phase to grow into something really great, please consider 
	 some donation here: 
	 https://www.paypal.me/milankarakas?locale.x=en_US
	 It is still in beta test phase, and will be upgraded. 
	 So far it works at 433.120 MHz, and you need to change 
	 the frequency if you wish to something else - in library
	 'Si4432.c', there is math and you should to calculate 
	 and change values of the register for other frequencies. 
	 Out there exist also Si4432 - 868 MHz module, and this 
	 program works with this one too, but then you MUST change
	 the frequency, else output TX amplifier may burn. 
	 Later, will ad my own math to do that, but since it is still
	 in beta testing phase... stay tuned.
*/

#include "stm32f10x.h"

uint8_t reg=0, cmd=0;


void spiEnable(void)
{
	RCC->APB2ENR |= RCC_APB2ENR_IOPAEN|RCC_APB2ENR_AFIOEN; //already exist, but anyway...
	/* SPI pins */
	/* GPIO pin A4 is NSS ("Not" Slave Sellect), inverted... if low (0), then it is selected */
	GPIOA->CRL |= GPIO_CRL_CNF4_1|GPIO_CRL_MODE4_0|GPIO_CRL_MODE4_1;// 50 MHz - NSS (nSEL on Si4432)
	GPIOA->CRL &= ~GPIO_CRL_CNF4_0; //alternate function PP, this A4 pin must be high with external resistor 3kOhm to 4.7kOhm
	/* GPIO pin A5 is SPI clock SCK */
	GPIOA->CRL |= GPIO_CRL_CNF5_1|GPIO_CRL_MODE5_0|GPIO_CRL_MODE5_1;// 50 mhz - SCK
	GPIOA->CRL &= ~GPIO_CRL_CNF5_0; //alternate function PP
	/* GPIO pin A6 is MISO */
	GPIOA->CRL &= ~(GPIO_CRL_MODE6_0|GPIO_CRL_MODE6_1); // INPUT - MISO
	GPIOA->CRL |= GPIO_CRL_CNF6_0;
	/* GPIO pin A7 is MOSI */
	GPIOA->CRL |= GPIO_CRL_CNF7_1|GPIO_CRL_MODE7_0|GPIO_CRL_MODE7_1;// 50 MHz - MOSI
	GPIOA->CRL &= ~GPIO_CRL_CNF7_0; //alternate function PP
	
	/*  Configuring SPI */
	RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;// SPI enable
	SPI1->CR1 |= SPI_CR1_BR_2;//|SPI_CR1_BR_1;//|SPI_CR1_BR_1|SPI_CR1_BR_0; // 72MHz/?
	SPI1->CR1 &= ~(SPI_CR1_CPOL|SPI_CR1_CPHA|SPI_CR1_DFF); // modes, 0 for polarity, and 0 for iddle clock=0, dff=0 (8 bit), lsbfirst=0 (MSB first), *
	SPI1->CR2 |= SPI_CR2_SSOE; //NSS enabled         
	SPI1->CR1 |= SPI_CR1_MSTR;// master configuration  
}

void spiWrite(int reg, int cmd)
{
  SPI1->CR1 |= SPI_CR1_SPE;
	SPI1->DR = (0x80|reg); //usually 0x80 does not belongs to SPI, but here it is "command mode", specific for Si4432
	while (!(SPI1->SR & SPI_SR_TXE)){}; 
	SPI1->DR = cmd; 
	while (!(SPI1->SR &SPI_SR_TXE)){}; 
	while(SPI1->SR & SPI_SR_BSY);
	while (!(SPI1->SR & SPI_SR_OVR)){}; //if single byte is sent,...
  SPI1->CR1 &= ~SPI_CR1_SPE;
}

int spiRead(int reg)
{
	SPI1->CR1 |= SPI_CR1_SPE;
	SPI1->DR =reg;
	while (!(SPI1->SR & SPI_SR_TXE)){};
	while(SPI1->SR & SPI_SR_BSY){}; //waiting little bit longer between two sendings
  SPI1->DR = 0x00; //dummy byte
	while (!(SPI1->SR & SPI_SR_RXNE)){};
	int rd=SPI1->DR; //dummy read? Whole thing does not working properly without
	while (!(SPI1->SR & SPI_SR_RXNE)){};
  int r=SPI1->DR;
	SPI1->CR1 &= ~SPI_CR1_SPE;
	return r;
}
#ifndef spi_h
#define spi_h

extern void spiEnable(void);
extern void spiWrite(int reg, int cmd);
extern int spiRead(int reg);

#endif
/* This software is provided by https://wildlab.org and
   Milan Karakas from Croatia. This is free program, but 
	 also "beerware". This means if you want this beta test
	 phase to grow into something really great, please consider 
	 some donation here: 
	 https://www.paypal.me/milankarakas?locale.x=en_US
	 It is still in beta test phase, and will be upgraded. 
	 So far it works at 433.120 MHz, and you need to change 
	 the frequency if you wish to something else - in library
	 'Si4432.c', there is math and you should to calculate 
	 and change values of the register for other frequencies. 
	 Out there exist also Si4432 - 868 MHz module, and this 
	 program works with this one too, but then you MUST change
	 the frequency, else output TX amplifier may burn. 
	 Later, will ad my own math to do that, but since it is still
	 in beta testing phase... stay tuned.
*/

#include "stm32f10x.h"
#include "delayUs.h"
#include "spi.h"
#include "si4432.h"
#include "printMsg.h"

int itStatus1=0,itStatus2=0;
int packetLength=0;
char payload[64];

void setModule(float freq, int power)
{
	// freq=433.120;
	int fc,fb,hbsel;
	
	if      (freq >240.00 && freq < 250.00) {fb=0;hbsel=0;}
	else if (freq >250.00 && freq < 260.00) {fb=1;hbsel=0;}
	else if (freq >260.00 && freq < 270.00) {fb=2;hbsel=0;}
	else if (freq >270.00 && freq < 280.00) {fb=3;hbsel=0;}
	else if (freq >280.00 && freq < 290.00) {fb=4;hbsel=0;}
	else if (freq >290.00 && freq < 300.00) {fb=5;hbsel=0;}
	else if (freq >300.00 && freq < 310.00) {fb=6;hbsel=0;}
	else if (freq >310.00 && freq < 320.00) {fb=7;hbsel=0;}
	else if (freq >320.00 && freq < 330.00) {fb=8;hbsel=0;}
	else if (freq >330.00 && freq < 340.00) {fb=9;hbsel=0;}
	else if (freq >340.00 && freq < 350.00) {fb=10;hbsel=0;}
	else if (freq >350.00 && freq < 360.00) {fb=11;hbsel=0;}
	else if (freq >360.00 && freq < 370.00) {fb=12;hbsel=0;}
	else if (freq >370.00 && freq < 380.00) {fb=13;hbsel=0;}
	else if (freq >380.00 && freq < 390.00) {fb=14;hbsel=0;}
	else if (freq >390.00 && freq < 400.00) {fb=15;hbsel=0;}
	else if (freq >400.00 && freq < 410.00) {fb=16;hbsel=0;}
	else if (freq >410.00 && freq < 420.00) {fb=17;hbsel=0;}
	else if (freq >420.00 && freq < 430.00) {fb=18;hbsel=0;}
	else if (freq >430.00 && freq < 440.00) {fb=19;hbsel=0;}
	else if (freq >440.00 && freq < 450.00) {fb=20;hbsel=0;}
	else if (freq >450.00 && freq < 460.00) {fb=21;hbsel=0;}
	else if (freq >460.00 && freq < 470.00) {fb=22;hbsel=0;}
	else if (freq >470.00 && freq < 480.00) {fb=23;hbsel=0;}
	else if (freq >480.00 && freq < 500.00) {fb=0;hbsel=1;}
	else if (freq >500.00 && freq < 520.00) {fb=1;hbsel=1;}
	else if (freq >520.00 && freq < 540.00) {fb=2;hbsel=1;}
	else if (freq >540.00 && freq < 560.00) {fb=3;hbsel=1;}
	else if (freq >560.00 && freq < 580.00) {fb=4;hbsel=1;}
	else if (freq >580.00 && freq < 600.00) {fb=5;hbsel=1;}
	else if (freq >600.00 && freq < 620.00) {fb=6;hbsel=1;}
	else if (freq >620.00 && freq < 640.00) {fb=7;hbsel=1;}
	else if (freq >640.00 && freq < 660.00) {fb=8;hbsel=1;}
	else if (freq >660.00 && freq < 680.00) {fb=9;hbsel=1;}
	else if (freq >680.00 && freq < 700.00) {fb=10;hbsel=1;}
	else if (freq >700.00 && freq < 720.00) {fb=11;hbsel=1;}
	else if (freq >720.00 && freq < 740.00) {fb=12;hbsel=1;}
	else if (freq >740.00 && freq < 760.00) {fb=13;hbsel=1;}
	else if (freq >760.00 && freq < 780.00) {fb=14;hbsel=1;}
	else if (freq >780.00 && freq < 800.00) {fb=15;hbsel=1;}
	else if (freq >800.00 && freq < 820.00) {fb=16;hbsel=1;}
	else if (freq >820.00 && freq < 840.00) {fb=17;hbsel=1;}
	else if (freq >840.00 && freq < 860.00) {fb=18;hbsel=1;}
	else if (freq >860.00 && freq < 880.00) {fb=19;hbsel=1;}
	else if (freq >880.00 && freq < 900.00) {fb=20;hbsel=1;}
	else if (freq >900.00 && freq < 920.00) {fb=21;hbsel=1;}
	else if (freq >920.00 && freq < 940.00) {fb=22;hbsel=1;}
	else if (freq >940.00 && freq < 960.00) {fb=23;hbsel=1;}
	
	fc=((freq*1e6)/(10e6*(hbsel+1))-fb-24)*64000;
	
		/* should be interrupt for usart */
	USART1->CR1 |= USART_CR1_RXNEIE;  //setting only IRQ which 'listen' input of the MCU (message from PC) 
	NVIC_EnableIRQ(USART1_IRQn); //enabling IRQ
	
	RCC->APB2ENR |= RCC_APB2ENR_IOPAEN|RCC_APB2ENR_AFIOEN; //already exist, but anyway...
	/* Setting output GPIO pin A2 for SDN pin on Si4432 */
	GPIOA->CRL |= GPIO_CRL_MODE2_0|GPIO_CRL_MODE2_1; //pin A2 - OUTPUT - 50 MHz - SDN at Si4432
	GPIOA->CRL &= ~(GPIO_CRL_CNF2_1|GPIO_CRL_CNF2_0); //not sure.... leave 00 - general purpose PP
	/* Setting input GPIO pin A3 for nIRQ pin on Si4432 */
	GPIOA->CRL &= ~(GPIO_CRL_CNF3_0|GPIO_CRL_MODE3_0|GPIO_CRL_MODE3_1); //pin A3 - INPUT - nIRQ at Si4432
	GPIOA->CRL |= GPIO_CRL_CNF3_1; //INPUT, floating (!) Si4432 has high level if IRQs are set
		
	/* Configuring radio */
	GPIOA->BSRR = GPIO_BSRR_BS2; //Hardware reset - SDN pin goes up for 5 mS, then remains down at zero
	delay(500000); //watch LEDs on GPIO 2, if there is inproper reset, then GPIO 2 will give default 1 MHz at this pin
	GPIOA->BSRR = GPIO_BSRR_BR2;// pull down SDN pin on Si4432 to turn on radio
	delay(17000);//wait 17 mS or more, Si4432 internal startup
	
	/* Software reset (SW reset) */
	spiWrite(0x07, 0x80); //software reset on Si4432
	delay(30000);//at least 2 mS, leave it at 3 mS, else it may skip next while loop and not working properly

	while((GPIOA->ODR & GPIO_IDR_IDR3)); //Waiting nIRQ to become low
	//printMsg("IRQ received \n"); //debug only
	spiWrite(0x0a, 0b00001111); //GPIO2 gives 32.768 kHz if line below is not included:
	spiWrite(0x0d, 0b00000001); //but, lets turn off GPIO2, no frequency out if reset is properly done
	
	/* Set the physical parameters, example freq.=433.120 MHz*/
	//spiWrite(0x75,0x40|0x13); //frequency band select (0x40= 64, 0x13= 19 total= 0x53 = 83 decimal) (band select+fb value)-old for 433.120
	spiWrite(0x75, ((1<<6)|(hbsel<<5 )|(fb & 0x1F))); //
	// (0x75)        0       1     0    10011  
	// register: |reserved|sbsel|hbsel|fb[4:0]|
	spiWrite(0x76,(fc>>8)); //Nominal carrier frequency 1 (0x4D = 77 decimal), fc[15:8] (fine tuning?)
	//spiWrite(0x76,0x4e); //old fixed value for 433.120 MHz
	spiWrite(0x77,(fc & 0xFF)); //Nominal carrier frequency 2 (0xFF = 255 decimal),  fc[7:0]  (fine tuning?)
	//spiWrite(0x77, 0x00);//old fixed value for 433.120 MHz
	/* F(carrier)= 10e6*(hbsel+1)*(N+F) */
	/* F(TX)= 10e6*(hbsel+1)*(fb[4:0]+24+(fc[15:0]/64000) */
	/* F=(TX) 10e6*(1+1)*(19+24+(19968/64000)= 433.120 MHz */
	/* fc[15:0]=((wanted frequency in MHz/10e6*(hbsel+1))-fb[4:0]-24)*64000 */
	/* Please take look at page 26 with "Frequency Band Selection", Si4432 datasheet for fb[4:0] and N values. */
	
	
	/* Set desired TX data rate (9600 bps) */
	spiWrite(0x6E, 0x4E); //TX data rate 1, txdr[15:8]
	spiWrite(0x6F, 0xA5); //TX data rate 2  txdr[7:0] (together, txdr[15:0]= 0x4EA5, or 20133 decimal
	spiWrite(0x70, 0x2C); //Modulation Mode Control 1 (0x2C= 0b00101100)
	//  (0x70)        0        0         1         0        1        1       0       0
	// register: |reserved|reserved|txdtrtscale|enphpwdn|manppol|enmanihv|enmanch|enwhite|
	/* DR_TX(bps) = (txdr[15:0]*1 MHz)/(2^(16+5*txdrtscale)) */
	/* DR_TX(bps) = 20133*1e6/2^(16+5*1)= 9600.162506...  */
	/* txdr[15:0]= (DR_TX*(2^(16+5*txdtrtscale))/1 MHz */
	/* txdr[15:0]= 9600*(2^(16+5*1)/1e6= 20132.6595, rounded to 20133, hexadecimal= 0x4EA5, 0x4E goes to txdr[15:8], 0xA5 goes to txdr[7:0] */
	
	/* Set TX deviation register (+/- 5 kHz), or deltaF= 10 Khz, registers 0x71 and 0x72, but if fd[8] is zero, we can skip that register */
	spiWrite(0x72,0x10); //for 9600 bps, 625 kHz*16= 10 kHz, part of 9 bites (!), fd[7:0], MSB bit is in register 0x71 (fd[8])
	/* deltaF= fd[8=0]*625 Hz */
	/* deltaF= 16*625= 10000 Hz */
	/* fd[8:0]= deltaF/625 Hz */
	/* fd[8:0]= 10e3/625= 16 decimal, or 0x10 hexadecimal goes to txdr[8:0] */
	
	/* Set modem parameters according to the excel calculator for 9600 bps, deviation 45 kHz, channel filter BW: 102.2 kHz */
	spiWrite(0x1C, 0x12); //IF filter bandwidth (probably the same math as with TX deviation, or maybe slightly higher value?)
	spiWrite(0x20, 0xD0); //Clock recovery oversampling (?) (no any explanation in the datasheet for all things below)
	spiWrite(0x21, 0x00); //Clock recovery offset 2 (?)
	spiWrite(0x22, 0x9D); //Clock recovery offset 1 (?)
	spiWrite(0x23, 0x49); //Clock recovery offset 0 (?)
	spiWrite(0x24, 0x00); //Clock recovery timing loop gain (?)
	spiWrite(0x25, 0x24); //Clock recovery timing loop gain (?)
	spiWrite(0x1D, 0x40); //AFC loop gearshift override (?)
	spiWrite(0x1E, 0x0A); //AFC timing control register (?)
	spiWrite(0x2A, 0x20); //AFC limiter register (?)
	
	/* Set packet structure and modulation type, set preamble length to 5 bytes */
	spiWrite(0x34, 0x20); //Preamble length register, 0xA = 10 decimal, probably 1010101010 (10 bits)
	spiWrite(0x35, 0x14); //Preable detection control (threshold 42 bits for (G)FSK with AFC enabled)
	spiWrite(0x33, 0x02); //disalbe header bytes, Header control 2 
	spiWrite(0x36, 0x2D); //2D is sync word 3 (0b00101101)
	spiWrite(0x37, 0xD4); //D4 is sync word 2 (0b11010100), sync word 0 not used, so register 0x38 is omitted
	
	/* Enable TX & RX packet handler and CRC-16 (IBM) check */
	spiWrite(0x30, 0x8D); //Data access control register
	// (0x30)        1        0       0        0       1      1      01
	// register: |enpacrx|lsbfirst|crcdonly|skip2ph|enpactx|encrc|crc[1:0]|
	spiWrite(0x32, 0x00); //Header control 1 (disabling receive header filters)
	spiWrite(0x71, 0x63); //Modulation mode control 2
	// (0x71)          01         10       0     0       11
	// register: |trclk[1:0]|dtmod[1:0]|eninv|fd[8]|modtyp[1:0]|, fd[8] is MSB for fd[8:0] that can be found in reg. 0x72
	spiWrite(0x0B, 0b00010010 ); //GPIO 1 (set TX state) was 0x12
	spiWrite(0x0C, 0b00010101); //GPIO 2 (set RX state) was 0x15
	
	/* Non default Si443x registers */
	spiWrite(0x09, 0xA9); //Crystal oscillator load (Leave it as-is. Or, you can fine tune 30 MHz oscillator if you have precise freq.meter)0xAA
	spiWrite(0x69, 0x60); //Override 1 register (?)
	// (0x69)         0     1    1      0      0000
	// register: |reserved|sgi|agcen|lnagain|pga[3:0]|
	
	/* Enable receiver chain */
	spiWrite(0x07, 0x05); //Operating function control 1 reg.
	// (0x07)       0     0     0     0      0    1    0    1
	// register: |swres|enlbd|enwt|x32ksel|txon|rxon|pllon|xton|, enabling only RX and Xtall (30 MHz crystal)
	spiWrite(0x05, 0x03); //Interrupt enable 1 ('ipkval', and 'encrcerror') valid packet received
	// (0x05)        0         0          0          0        0      0          1        1
	// register: |enfferr|entxffafull|entxffaem|enrxffafull|enext|enpksent|enpkvalid|encrcerror|
	spiWrite(0x06, 0x00); //Interrupt enable 2 (actually not enabling anything, just in case you need RSSI, then use 'enrssi')
	// (0x06)        0        0          0        0     0     0       0       0
	// register: |enswdet|enpreaval|enpreinval|enrssi|enwut|enlbd|enchiprdy|enpor|
	
	/* Read interrupt status registers */
	itStatus1=spiRead(0x03);; //read Interrupt status 1
	itStatus2=spiRead(0x04);; //read Interrupt status 2
  //printMsg("itStatus1= %d, itStatus2= %d\n",itStatus1,itStatus2);
	
	/* Power settinigs */
	spiWrite(0x6D, (power&0x07)); //Power, from 0 to 7, max power is 100 mW 
	// (0x6D)         0        0        0       0        0      000
	// register: |reserved|reserved|reserved|reserved|lna_sw|txpow[2:0]|
}

void USART1_IRQHandler(void)
{
	USART1->CR1 &= ~USART_CR1_RXNEIE; //as soon as it enters IRQ, forbid re-triggering IRQ
	len=readMsg()+1;
  int fraction;
	/* Sending message just received over USART - lets disable receiver first and clear TX buffer */
	spiWrite(0x07, 0x01); //disabling receiver
	fraction = ((len)%64); //we should to know how how many packets of 64 + the rest of bytes...
  if ((len)<65)
  {
		 spiWrite(0x08, 0x01); //clearing TX FIFO buffer
	   spiWrite(0x08, 0x00); //removing clearing bit
	   for (int s=0;s<(len);s++)
    {
	    spiWrite(0x7F, buff[s]);
    }
		spiWrite(0x3E, (len));
    spiWrite(0x05, 0x04); //interrupt 1 enable ('enpktsent')
    spiWrite(0x06, 0x00); //interrupt 2 enable (actually nothing enabled)
    spiWrite(0x07, 0x09); //Sending packet of 64 bytes
    while((GPIOA->IDR & GPIO_IDR_IDR3)){}; // waiting for confirmation that packet is sent, nIRQ goes low if done
    //printMsg("small packet sent %d\n", len);
	}
 	else
	{			
   	for (int p=0;p<(len-fraction);p+=64)
		{
			spiWrite(0x08, 0x01); //clearing TX FIFO buffer
			spiWrite(0x08, 0x00); //removing clearing bit
			for (int b=0;b<64;b++)
				{
					spiWrite(0x7F, buff[b+p]);
				}
				spiWrite(0x3E, 64); // If it gets here, packet length will be always 64 bytes long, so no need to put calculation or anything else
				spiWrite(0x05, 0x04); //interrupt 1 enable ('enpktsent')
				spiWrite(0x06, 0x00); //interrupt 2 enable (actually nothing enabled)
				spiWrite(0x07, 0x09); //Sending packet of 64 bytes
				while((GPIOA->IDR & GPIO_IDR_IDR3)){}; // waiting for confirmation that packet is sent, nIRQ goes low if done
				itStatus1=spiRead(0x03);; //read Interrupt status 1
	      itStatus2=spiRead(0x04);; //read Interrupt status 2
				//printMsg("Part of the packet sent= %d num= %d\n",(temp+1), p);
		}
		spiWrite(0x08, 0x01); //clearing TX FIFO buffer
		spiWrite(0x08, 0x00); //removing clearing bit
		for (int f=0;f<fraction;f++)
			{
			spiWrite(0x7F, buff[((len)-fraction)+f]);
			}
			spiWrite(0x3E, fraction);
			spiWrite(0x05, 0x04); //interrupt 1 enable ('enpktsent')
			spiWrite(0x06, 0x00); //interrupt 2 enable (actually nothing enabled)
			spiWrite(0x07, 0x09); //Sending packet of 64 bytes
			while((GPIOA->IDR & GPIO_IDR_IDR3)){}; // waiting for confirmation that packet is sent, nIRQ goes low if done
			//printMsg("remaining packet sent %d\n",fraction);
	}		
	USART1->CR1 |= USART_CR1_RXNEIE; //after everything done here, re-enable IRQ
}
			
void listenRadio(void)
	{
		/* Enable receiver chain and listening RX*/
		spiWrite(0x08, 0x02); //operating function control 2 reg. clearing TX and RX FIFO buffer, register bit 'ffclrrx'
		spiWrite(0x08, 0x00); //operating function control 2 reg. not sure why it should go back to zero, but it must be tehere
		
		/* Set interrupts for valid packet ('ipkval'), or CRC error ('encrcerror') */
		spiWrite(0x07, 0x05); // RX on

	  /* Wait for interrupt event */
    while((GPIOA->IDR & GPIO_IDR_IDR3)); //if nothing received, then it will "stuck" here forever
		spiWrite(0x05, 0x03); //interrupt enable 1 'ipkval' and encrcerror'
		spiWrite(0x06, 0x00); //interrupt enable 2, but this time nothing is enabled
		// RSSI value is in register 0x26, and threshold for "clear RSSI" in 0x27 (RSSI is not zero when no signal, there is some noise)
		spiWrite(0x07, 0x01); //disabling receiver during received packed testing, but leave xtall on
		
		/* Checking for errors first */
		itStatus1=spiRead(0x03);; //read Interrupt status 1
	  itStatus2=spiRead(0x04);; //read Interrupt status 2
	  //printMsg("* itStatus1= 0x%X, itStatus2= 0x%X \n",itStatus1,itStatus2); //debug only
			
		/* if CRC error interrupt occured ? : disabled because from time to time some RF noise trigger it without 'real' transmission at the other end.
			if ((itStatus1 & 0x01) ==0x01)  // 0x01 = 'icrcerror' in register 0x03 on Si4432
			{
				printMsg("CRC error \n");
			}
			*/
			/* Valid packet received interrupt occured ? */
			if ((itStatus1 & 0x02) == 0x02)  // 0x02 = 'ipkvalid' in register 0x03 on Si4432
			{
				packetLength=spiRead(0x4B); //read length of the recieved packet
				//printMsg("received packet length= %d \n", packetLength); //debug only
				for (int i=0;i<packetLength;i++)
				{
					payload[i]=spiRead(0x7F); //read FIFO
					printMsg("%c",(char)payload[i]); //print character by character
				}
        //printMsg("\n");	//Line Feed (LF) no needed, since we sending it over the radio
			}
			spiWrite(0x08, 0x02); // clearing TX and RX FIFO buffer, register bit 'ffclrrx'
		  spiWrite(0x08, 0x00); // not sure why it should go back to zero, but it must be tehere
	}
#ifndef si4432_h
#define si4432_h

extern int itStatus1,itStatus2;
extern int packetLength;
extern char payload[];

extern void setModule(float freq,int power);
extern void listenRadio(void);

#endif
/* This software is provided by https://wildlab.org and
   Milan Karakas from Croatia. This is free program, but 
	 also "beerware". This means if you want this beta test
	 phase to grow into something really great, please consider 
	 some donation here: 
	 https://www.paypal.me/milankarakas?locale.x=en_US
	 It is still in beta test phase, and will be upgraded. 
	 So far it works at 433.120 MHz, and you need to change 
	 the frequency if you wish to something else - in library
	 'Si4432.c', there is math and you should to calculate 
	 and change values of the register for other frequencies. 
	 Out there exist also Si4432 - 868 MHz module, and this 
	 program works with this one too, but then you MUST change
	 the frequency, else output TX amplifier may burn. 
	 Later, will ad my own math to do that, but since it is still
	 in beta testing phase... stay tuned.
*/

#include "stm32f10x.h"
#include "stdint.h"
#include <stdio.h>
#include "stdarg.h"
#include "string.h"
#include "printMsg.h"

#define buffer 20000
char buff[buffer]; //10000 characters! If you need less, then change this value AND (!) value value below as well

void usart_1_enable(void)
{
  //enabling pin A9 for alternating funct. for uart/usart
  RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN | RCC_APB2ENR_USART1EN; //clock to GPIO A enabled, port A(2), alt.funct.en(0), usart1 clock enabled(14)
	GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9_0 | GPIO_CRH_MODE9_1; //port A9 TX
	GPIOA->CRH &= ~GPIO_CRH_CNF9_0; //port A9
	GPIOA->CRH &= ~(GPIO_CRH_MODE10_0|GPIO_CRH_MODE10_1); //port A10 is RX
	GPIOA->CRH |= GPIO_CRH_CNF10_0; //port A10 is RX
	
	//GPIOA->CRH = 0x444444B4; // A9 is alternate output, 50 MHz, push-pull - not this time short version (!)
	//clkPer/(baudRx_16bit)=72MHZ/9600 = 7500 = 0x1D4C
	/* Remove comment line for speed that you want to use*/
	//USART1->BRR = (0xEA60); //   1200 Baud
	//USART1->BRR = (0x7530); //   2400 Baud
	//USART1->BRR = (0x3A98); //   4800 Baud
	//USART1->BRR = (0x1D4C); //   9600 Baud
	//USART1->BRR = (0x1388); //  14400 Baud
	//USART1->BRR = (0xEA6) ; //  19200 Baud
	//USART1->BRR = (0x9c4) ; //  28800 Baud
	//USART1->BRR = (0x753) ; //  38400 Baud
	//USART1->BRR = (0x505) ; //  56000 Baud
	//USART1->BRR = (0x4E2) ; //  57600 Baud
	USART1->BRR = (0x271) ; // 115200 Baud
	//USART1->BRR = (0x232) ; // 128000 Baud
	//USART1->BRR = (0x119) ; // 256000 Baud
	//USART1->BRR = (0x8C)  ; // 512000 Baud
	//USART1->BRR = (0x46)  ; // 1024000 Baud
	//USART1->BRR = (0x23)  ; // 2048000 Baud
  //USART1->BRR = (0x18)  ; // 3000000 Baud (3 MHz, max speed that HTerm can get, non-standard speed)
	
	
	USART1->CR1 |= USART_CR1_TE; //transmitter enable
	USART1->CR1 |= USART_CR1_RE; //receiver enable
	USART1->CR1 |= USART_CR1_UE; //usart enable
}

void printMsg(char *msg, ...)
{
	//char buff[120]; //was 80
	va_list args;
	va_start(args,msg); 
	vsprintf(buff,msg,args);

	for(int i=0;i<strlen(buff);i++)
	{
	  USART1->DR = buff[i];
	  while(!(USART1->SR & USART_SR_TXE)); //wait for TXE, 1 = data transferred
  }
}

int readMsg(void)
{ 
  
 for( len =0;len<buffer;len++)  //20000 characters! If you need less, then change this value AND (!) buff[] value above as well.
 {
    while(!(USART1->SR & USART_SR_RXNE));
    buff[len]= USART1->DR;
    if (buff[len]==10 || buff[len]==13) break; //if enter is pressed, providing that it is 10 or 0xA (line feed), or 13 (0xD) (carriage return) 
 }
 return len; //just returning number of entered characters, not including line feed nor carriage return (!)
}
#ifndef printMsg_h
#define printMsg_h

extern int len;
extern char buff[];
//char buff[];

void usart_1_enable(void);
void printMsg(char *msg, ...);
int readMsg(void);
void USART1_IRQHandler(void);

#endif

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.