AA32 RADIO FM DUT GEII TOURS
Revision 0:f5a073ecafa6, committed 2019-12-16
- Comitter:
- jlpadiolleau
- Date:
- Mon Dec 16 07:37:25 2019 +0000
- Commit message:
- Si4735 GEII TOURS
Changed in this revision
Si4735.cpp | Show annotated file Show diff for this revision Revisions of this file |
Si4735.h | Show annotated file Show diff for this revision Revisions of this file |
--- /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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Si4735.h Mon Dec 16 07:37:25 2019 +0000 @@ -0,0 +1,243 @@ +/* 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 example sketches to learn how to use the library in your code. +*/ + +//Modifié par VG pour fonctionner sous MBED +//14 Decembre 2017 +#include "mbed.h" + +#ifndef __SI4735_H +#define __SI4735_H + + +//#include <string.h> +//#include <stdio.h> +#include <ctype.h> //toupper + +//Ajouter par VG pour redéfinir les constantes Arduino INPUT, OUTPUT, LOW et HIGH +//#define INPUT 0 +//#define OUTPUT 1 +//#define LOW 0 +//#define HIGH 1 + + +#define READ_DELAY 10 +//Comment out these 'defines' to strip down the Si4735 library features. +//This will help you save memory space at the cost of features. +#define USE_SI4735_REV +#define USE_SI4735_RDS +#define USE_SI4735_CALLSIGN +#define USE_SI4735_PTY +#define USE_SI4735_RADIOTEXT +#define USE_SI4735_DATE_TIME +#define USE_SI4735_RSQ + +//List of possible modes for the Si4735 Radio +#define AM 0 +#define FM 1 +#define SW 2 +#define LW 3 + +//Define the Locale options +#define NA 0 +#define EU 1 + +#define ON true +#define OFF false + +#define MAKEINT(msb, lsb) (((msb) << 8) | (lsb)) + +struct Metrics { + uint8_t STBLEND; + uint8_t RSSI; + uint8_t SNR; + uint8_t MULT; + uint8_t FREQOFF; +}; + + +class Si4735// : public SPIClass +{ + public: + //This is just a constructor. + Si4735(); + /* + * Description: + * Initializes the Si4735, powers up the radio in the desired mode and limits the bandwidth appropriately. + * This function must be called before any other radio command. + * The bands are set as follows: + * FM - 87.5 - 107.9 MHz + * AM - 520 - 1710 kHz + * SW - 2300 - 23000 khz + * LW - 152 - 279 kHz + * Parameters: + * mode - The desired radio mode. Use AM(0), FM(1), SW(2) or LW(3). + */ + void begin(char mode); + + /* + * Description: + * Acquires certain revision parameters from the Si4735 chip + * Parameters: + * 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 + */ + #if defined(USE_SI4735_REV) + void getREV(char*FW,char*CMP,char *REV); + #endif + + /* + * Description: + * Used to to tune the radio to a desired frequency. The library uses the mode indicated in the + * begin() function to determine how to set the frequency. + * Parameters: + * frequency - The frequency to tune to, in kHz (or in 10kHz if using FM mode). + */ + void tuneFrequency(uint16_t frequency); + + //Gets the frequency of the currently tuned station + uint16_t getFrequency(); + + + // Commands the radio to seek up to the next valid channel. If the top of the band is reached, the seek + // will continue from the bottom of the band. + void seekUp(void); + + // Commands the radio to seek down to the next valid channel. If the bottom of the band is reached, the seek + // will continue from the top of the band. + void seekDown(void); + + /* + * Description: + * Adjust the threshold levels of the seek function. + * FM Ranges: + * SNR=[0-127], FM_default=3 dB + * RSSI=[0-127], FM_default=20 dBuV + * AM Ranges: + * SNR=[0-63], AM_default=5 dB + * RSSI=[0-63], AM_default=19 dBuV + */ + void seekThresholds(uint8_t SNR, uint8_t RSSI); + + // Retreives the Received Signal Quality Parameters/Metrics. + #if defined(USE_SI4735_RSQ) + void getRSQ(Metrics * RSQ); + #endif + + // Sets the volume. If of of the 0 - 63 range, no change will be made. + uint8_t setVolume(uint8_t value); + + // Gets the current volume. + uint8_t getVolume(void); + + // Increasese the volume by 1. If the maximum volume has been reached, no increase will take place. + uint8_t volumeUp(void); + + // Decreases the volume by 1. If the minimum volume has been reached, no decrease will take place. + uint8_t volumeDown(void); + + + // Coupe la sortie audio + void mute(void); + + // Disables the mute. + void unmute(void); + + /* + * Description: + * Gets the current status of the radio. Learn more about the status in the Si4735 datasheet. + * Returns: + * The status of the radio. + */ + char getStatus(void); + + /* + * Description: + * Gets the long response (16 characters) from the radio. Learn more about the long response in the Si4735 datasheet. + * Parameters: + * response - A string for the response from the radio to be stored in. + */ + void getResponse(char * response); + + // Powers down the radio + void end(void); + + // Sets the Locale. This determines what Lookup Table (LUT) to use for the pyt_LUT. + void setLocale(uint8_t locale); + + // Gets the Locale. + uint8_t getLocale(void); + + // Gets the Mode of the radio [AM,FM,SW,LW] + char getMode(void); + + /* + * Description: + * Sets the Mode of the radio [AM,FM,SW,LW]. This also performs a powerdown operation. + * The user is responsible for reissuing the begin method after this method has been called. + */ + void setMode(char mode); + + // Sets a property value + void setProperty(uint16_t address, uint16_t value); + + /* + * Description: + * Gets a property value. + * Returns: + * The value stored in address. + */ + uint16_t getProperty(uint16_t address); + + private: + SPI *busspi;//(DATAOUT, DATAIN, SPICLOCK); // mosi, miso, sclk + DigitalOut *SPISS; + DigitalInOut *GPO2;//D2 + DigitalInOut *GPO1;//D12 + DigitalOut *POWER_PIN;//D8 + DigitalOut *RADIO_RESET_PIN;//D9 + + + char _mode; //Contains the Current Radio mode [AM,FM,SW,LW] + char _volume; //Current Volume + uint16_t _frequency; //Current Frequency + uint8_t _locale; //Contains the locale [NA, EU] + + /* + * Command string that holds the binary command string to be sent to the Si4735. + */ + char command[9]; + + /* + * Description: + * Sends a binary command string to the Si4735. + * Parameters: + * command - Binary command to be sent to the radio. + * length - The number of characters in the command string (since it can't be null terminated!) + * TODO: + * Make the command wait for a valid CTS response from the radio before releasing control of the CPU. + */ + void sendCommand(char * command, int length); + + /* + * Description: + * Sends/Receives a character from the SPI bus. + * Parameters: + * value - The character to be sent to the SPI bus. + * Returns: + * The character read from the SPI bus during the transfer. + */ + char spiTransfer(char value); + +}; + +#endif