AA32 RADIO FM DUT GEII TOURS
Si4735.cpp
- Committer:
- jlpadiolleau
- Date:
- 2019-12-16
- Revision:
- 0:f5a073ecafa6
File content as of revision 0:f5a073ecafa6:
//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); }