/* This software is provided by http://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
}