AA32 RADIO FM DUT GEII TOURS

Dependents:   RadioFM

Revision:
0:f5a073ecafa6
diff -r 000000000000 -r f5a073ecafa6 Si4735.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Si4735.cpp	Mon Dec 16 07:37:25 2019 +0000
@@ -0,0 +1,397 @@
+//Modifié par VG: attention il faut diminuer la vitesse du bus SPI sur la UnoRev3 (sinon gros problème de lecture)
+//Voir ligne dans la méthode begin SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
+//j'ai ajouté 1<<SPR0 pour mettre l'horloge / 16 (Fmax du Si7435=2,5MHz !!!)
+
+
+/* Arduino Si4735 Library
+ * Written by Ryan Owens for SparkFun Electronics 5/17/11
+ * Altered by Wagner Sartori Junior 09/13/11
+ * Actively Being Developed by Jon Carrier
+ *
+ * This library is for use with the SparkFun Si4735 Shield
+ * Released under the 'Buy Me a Beer' license
+ * (If we ever meet, you buy me a beer)
+ *
+ * See the header file for better function documentation.
+ *
+ * See the example sketches to learn how to use the library in your code.
+*/
+
+/*
+
+SPCR
+| 7    | 6    | 5    | 4    | 3    | 2    | 1    | 0    |
+| SPIE | SPE  | DORD | MSTR | CPOL | CPHA | SPR1 | SPR0 |
+
+SPIE - Enables the SPI interrupt when 1
+SPE - Enables the SPI when 1
+DORD - Sends data least Significant Bit First when 1, most Significant Bit first when 0
+MSTR - Sets the Arduino in master mode when 1, slave mode when 0
+CPOL - Sets the data clock to be idle when high if set to 1, idle when low if set to 0
+CPHA - Samples data on the falling edge of the data clock when 1, rising edge when 0
+SPR1 and SPR0 - Sets the SPI speed, 00 is fastest (4MHz) 11 is slowest (250KHz)
+
+*/
+#include "Si4735.h"
+
+
+//This is just a constructor.
+//Default values are assigned to various private variables
+Si4735::Si4735()
+{
+	//busspi = new SPI(D11,D12,D13);//mosi,miso,sck
+	SPISS = new DigitalOut(D10);
+	GPO2 = new DigitalInOut(D2);//D2
+	GPO1 = new DigitalInOut(D12);//D12
+	POWER_PIN = new	DigitalOut(D8);//D8
+	RADIO_RESET_PIN = new DigitalOut(D9);//D9
+	
+	_mode		= FM;//FM par défaut
+	_locale	= EU;//europe de l'ouest
+	_volume	= 63;//volume à fond
+}
+
+void Si4735::begin(char mode)
+{
+	_mode = mode;//FM par défaut
+	//Etat RESET de l'ordinogramme
+	//On configure les broches en sorties, positionne GPO1 et GPO2 à 1 pendant le reset du Si4735
+	//pour se mettre en mode de communication SPI
+	GPO2->output();//On force pour l'instant GPO2 en sortie
+	GPO1->output();//On force pour l'instant GPO1 en sortie
+	
+	//On active la séquence reset du Si4735
+	RADIO_RESET_PIN->write(0);
+	POWER_PIN->write(0);
+	//wait_ms(20);
+	//On met un niveau 1 sur les GPO (mode SPI)
+	GPO1->write(1);
+	GPO2->write(1);
+	wait_ms(20);
+	//On alimente le Si4735
+	POWER_PIN->write(1);
+	wait_ms(20);
+	//front montant sur la broche reset du Si4735 
+	RADIO_RESET_PIN->write(1);
+	wait_ms(200);//attente pour la prise en compte du mode choisi
+
+	GPO1->input();//On remet GPO1 en entrée pour le bus SPI
+	//broche INT_PIN en entrée
+	GPO2->input();//On remet GPO2 en entrée
+	//SS au niveau haut	
+	SPISS->write(1);
+	delete GPO1;//on détruit GPO1 pour laisser la broche D12 au bus SPI
+	
+	wait(0.2);
+	//Configure le SPI, Maitre, 1MHz Mode 0 à priori pour le Si4735
+	//2,5 MHz max pour l'horloge bus SPI
+	busspi = new SPI(D11,D12,D13);//mosi,miso,sck
+	busspi->format(8,0);//8 bits de données et mode 0
+	busspi->frequency(1000000);//1 MHz
+	wait(0.2);
+	
+	//Emission de la commande POWER_UP (0x01)
+	sprintf(command, "%c%c%c", 0x01, 0x50, 0x05);//Quartz 32768Hz externe validé et sortie GPO2, sortie analogique validé
+	sendCommand(command, 3);
+	wait_ms(200);//Pas vu dans la doc ???
+
+	//Configure GPO lines to maximize stability
+	sprintf(command, "%c%c", 0x80,0x06);//GPO1 et GPO2 en sortie, GPO3 en haute impédance
+	sendCommand(command, 2);
+	wait_ms(10);
+	sprintf(command, "%c%c", 0x81,0x04);//toutes les sorties à zéro sauf GPO1 (pourquoi MISO à 1 ?)
+	sendCommand(command, 2);
+	wait_ms(10);
+
+	//Configure le volume à la valeur courante
+	setVolume(_volume);
+
+	//son sur les sorties audio
+	unmute();
+         
+    setLocale(EU);//désaccentuation Europe = 50µs (filtrage)
+    /*    
+	//Enable RDS
+	setProperty(0x1500, 0x0001);//positionne RDSINT quand la pile FIFO a des données RDS
+	setProperty(0x1501, 0x0004);//Minimum 4 groupes RDS stocké dans la FIFO (A,B,C et D)
+	//setProperty(0x1502, 0xEF01);//Validation RDS et config de la gestion des erreurs sur chaque bloc
+	//Only store good blocks and ones that have been corrected
+	setProperty(0x1502, 0xAA01);	
+	//Only store good blocks
+	//setProperty(0x1502, 0x0001);//Validation RDS et aucune erreur sur les blocs
+	*/
+    seekThresholds(2,14);//on ajuste le seuil pour rechercher plus de stations SNR=2, RSSI=14
+}
+
+
+void Si4735::tuneFrequency(uint16_t frequency)
+{
+	//Split the desired frequency into two character for use in the
+	//set frequency command.
+	uint8_t highByte = frequency >> 8;
+	uint8_t lowByte = frequency & 0x00FF;
+	
+	//set the new frequency. Mode FM uniquement
+	sprintf(command, "%c%c%c%c", 0x20, 0x00, highByte, lowByte);
+	sendCommand(command, 4);
+	wait_ms(100);
+}
+#if defined(USE_SI4735_REV)
+void Si4735::getREV(char*FW,char*CMP,char *REV)
+{
+	//FW = Firmware and it is a 2 character array
+	//CMP = Component Revision and it is a 2 character array
+	//REV = Chip Revision and it is a single character
+	char response [16]={0};
+	sprintf(command, "%c", 0x10);
+	
+	//Send the command
+	sendCommand(command, 1);
+
+	//Now read the response	
+	getResponse(response);	
+
+	FW[0]=response[2];
+	FW[1]=response[3];
+	FW[2]='\0';
+	CMP[0]=response[6];
+	CMP[1]=response[7];
+	CMP[2]='\0';
+	*REV=response[8];	
+}
+#endif //USE_SI4735_REV
+
+uint16_t Si4735::getFrequency()
+{
+	char response [16]={0};
+	uint16_t frequency=0;	
+	uint8_t highByte=0;
+	uint8_t lowByte=0;
+			
+	//The FM_TUNE_STATUS command
+	sprintf(command, "%c%c", 0x22, 0x00);
+	//Send the command
+	sendCommand(command, 2);
+
+	//Now read the response	
+	getResponse(response);
+	
+	lowByte=response[3];
+	highByte=response[2];
+        
+    frequency = (highByte<<8)+lowByte;
+    return frequency;
+}
+
+void Si4735::seekUp(void)
+{
+	//Use the current mode selection to seek up.
+	sprintf(command, "%c%c", 0x21, 0x0C);
+	sendCommand(command, 2);
+	wait_ms(1);
+}
+
+void Si4735::seekDown(void)
+{
+	//Use the current mode selection to seek down.
+	sprintf(command, "%c%c", 0x21, 0x04);
+	sendCommand(command, 2);	
+	wait_ms(1);
+}
+
+void Si4735::seekThresholds(uint8_t SNR, uint8_t RSSI)
+{
+	//Use the current mode selection to set the threshold properties.	
+	if(SNR>127)SNR=127;
+	else if(SNR<1)SNR=0;
+	if(RSSI>127)RSSI=127;
+	else if(RSSI<1)RSSI=0;
+	setProperty(0x1403, (uint16_t)SNR);	
+	setProperty(0x1404, (uint16_t)RSSI);				
+}
+
+#if defined(USE_SI4735_RSQ) 
+void Si4735::getRSQ(Metrics * RSQ)
+{
+	//This function gets the Received Signal Quality Information
+	char response [16]={0};
+				
+	//The FM_RSQ_STATUS command
+	sprintf(command, "%c%c", 0x23, 0x00);
+	//Send the command
+	sendCommand(command, 2);
+
+	//Now read the response	
+	getResponse(response);	
+
+	//Pull the response data into their respecive fields
+	RSQ->RSSI=response[4];
+	RSQ->SNR=response[5];
+
+	RSQ->STBLEND=response[3]&63;
+	RSQ->MULT=response[6];
+	RSQ->FREQOFF=response[7];
+}
+#endif
+
+uint8_t Si4735::volumeUp(void)
+{
+	//63 est le volume maximum
+	if(_volume < 63)
+	{
+		_volume+=1;
+		//Set the volume to the current value.
+		setProperty(0x4000, (uint16_t)_volume);	
+	}
+	return _volume;
+}
+
+uint8_t Si4735::volumeDown(void)
+{
+	//If we're not at the minimum volume yet, decrease the volume
+	if(_volume > 0){
+		_volume-=1;
+		//Set the volume to the current value.
+		setProperty(0x4000, (uint16_t)_volume);	
+	}
+	return _volume;
+}
+
+uint8_t Si4735::setVolume(uint8_t value)
+{
+	if(value <= 63 && value > 0){
+		_volume=value;
+		//Set the volume to the current value.
+		setProperty(0x4000, (uint16_t)_volume);
+	}
+	return _volume;
+}
+
+uint8_t Si4735::getVolume(void)
+{	
+	return _volume;
+}
+
+void Si4735::mute(void)
+{
+	setProperty(0x4001, 0x0003);//coupe le son sur les voies gauche et droite
+}
+
+void Si4735::unmute(void)
+{
+	setProperty(0x4001, 0x0000);//son L et R ok
+}
+
+char Si4735::getStatus(void)
+{
+	char response=0;
+	//SS au niveau bas
+	SPISS->write(0);
+	wait_ms(1);
+	spiTransfer(0xA0);  //Commande de lecture sur GPO1 d'un octet (MISO du SPI)
+	wait_ms(1);
+	response = spiTransfer(0x00);  //Lecture de la réponse
+	//SS au niveau haut, fin de lecture
+	SPISS->write(1);
+	return response;
+}
+
+void Si4735::getResponse(char *response)
+{
+	//char cmd=0xE0;
+	//SS au niveau bas
+	SPISS->write(0);
+	wait_ms(1);
+	busspi->write(0xE0);//Commande de lecture d'une série de 16 octets sur GPO1 (MISO)
+	//spiTransfer(0xE0);  //Commande de lecture d'une série de 16 octets sur GPO1 (MISO)
+	//wait_ms(1);
+	//lecture de 16 octets - le premier est l'octet de contrôle, puis les 15 data
+	//busspi->write(&cmd,1,response,16);
+	for(int i=0; i<16; i++) *response++ = busspi->write(0x00);  //Lecture des 16 octets
+	//SS au niveau haut, fin de lecture
+	SPISS->write(1);
+}
+
+void Si4735::end(void)
+{
+	sprintf(command, "%c", 0x11);//Commande POWER_DOWN
+	sendCommand(command, 1);
+	wait_ms(1);
+}
+
+void Si4735::setLocale(uint8_t locale)
+{
+	_locale=locale;	
+	//Set the deemphasis to match the locale
+	switch(_locale)
+	{
+		case NA:			
+			setProperty(0x1100, 0x0002);		
+			break;
+		case EU:
+			setProperty(0x1100, 0x0001);
+			break;
+		default:
+			break;
+	}
+}
+
+uint8_t Si4735::getLocale(void)
+{
+	return _locale;
+}
+
+
+void Si4735::setMode(char mode)
+{
+	end();
+	begin(mode);
+}
+
+char Si4735::getMode(void)
+{
+	return _mode;
+}
+
+//Envoie la commande 0x12 pour positionner la valeur value du paramètre situé à l'adresse address
+void Si4735::setProperty(uint16_t address, uint16_t value)
+{	
+	sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, (address>>8)&255, address&255, (value>>8)&255, value&255);
+	sendCommand(command, 6);
+	wait_ms(1);
+}
+
+//Envoie la commande 0x13 pour lire la valeur du paramètre situé à l'adresse address.
+uint16_t Si4735::getProperty(uint16_t address)
+{	
+	char response [16]={0};	
+	sprintf(command, "%c%c%c%c", 0x13, 0x00, (address>>8)&255, address&255);
+	sendCommand(command, 4);
+	getResponse(response);
+	return response[2]<<8 | response[3];
+}
+
+/*******************************************
+*
+* Private Functions
+*
+*******************************************/
+//Ecriture ou lecture sur le bus SPI !
+char Si4735::spiTransfer(char value)
+{
+	return busspi->write(value);//Emission d'un octet ou lecture
+}
+
+//Ecriture de données dans le Si4735
+//length=8 octets maximum
+void Si4735::sendCommand(char * command, int length)
+{
+  //SS au niveau bas
+  SPISS->write(0);
+  wait_ms(1);
+  spiTransfer(0x48);  //Octet de contrôle à 0x48 pour signifier une écriture dans le Si4735 (puis envoie de 8 octets de data)
+  for(int i=0; i<length; i++)spiTransfer(command[i]);
+  for(int i=length; i<8; i++)spiTransfer(0x00);  //on compléte avec des 0 si la data est < à 8 octets.
+  //Fin de la séquence par SS au niveau haut
+  SPISS->write(1);
+}
\ No newline at end of file