AA32 RADIO FM DUT GEII TOURS
Diff: Si4735.cpp
- Revision:
- 0:f5a073ecafa6
--- /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