--- /dev/null
+/**************************************************************************/
+/*!
+ @file tea5767.c
+ @author K. Townsend
+
+ @brief Driver for the TEA5767 FM receiver.
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2012, K. Townsend
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the copyright holders nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/**************************************************************************/
+#include "tea5767.h"
+#include "core/i2c/i2c.h"
+#include "core/systick/systick.h"
+
+extern volatile uint8_t I2CMasterBuffer[I2C_BUFSIZE];
+extern volatile uint8_t I2CSlaveBuffer[I2C_BUFSIZE];
+
+static bool _tea5767Initialised = false;
+
+/**************************************************************************/
+/*!
+ @brief Sends 5 bytes over I2C
+*/
+/**************************************************************************/
+void tea5767SendData(uint8_t * bytes)
+{
+ // Clear write buffers
+ uint32_t i;
+ for ( i = 0; i < I2C_BUFSIZE; i++ )
+ {
+ I2CMasterBuffer[i] = 0x00;
+ }
+
+ I2CWriteLength = 6;
+ I2CReadLength = 0;
+ I2CMasterBuffer[0] = TEA5767_ADDRESS;
+ I2CMasterBuffer[1] = bytes[0];
+ I2CMasterBuffer[2] = bytes[1];
+ I2CMasterBuffer[3] = bytes[2];
+ I2CMasterBuffer[4] = bytes[3];
+ I2CMasterBuffer[5] = bytes[4];
+ i2cEngine();
+}
+
+/**************************************************************************/
+/*!
+ @brief Reads 5 bytes over I2C
+*/
+/**************************************************************************/
+void tea5767ReadData(uint8_t * bytes)
+{
+ // Clear buffers
+ uint32_t i;
+ for ( i = 0; i < I2C_BUFSIZE; i++ )
+ {
+ I2CMasterBuffer[i] = 0x00;
+ I2CSlaveBuffer[i] = 0x00;
+ }
+
+ I2CWriteLength = 1;
+ I2CReadLength = 5;
+ I2CMasterBuffer[0] = TEA5767_ADDRESS | TEA5767_READ;
+ i2cEngine();
+
+ bytes[0] = I2CSlaveBuffer[0];
+ bytes[1] = I2CSlaveBuffer[1];
+ bytes[2] = I2CSlaveBuffer[2];
+ bytes[3] = I2CSlaveBuffer[3];
+ bytes[4] = I2CSlaveBuffer[4];
+}
+
+/**************************************************************************/
+/*!
+ @brief This is a test function to evaluate the quality of crystals
+ used on 3rd party modules. Most modules use cheap 32.768kHz
+ crystals which are prone to de-tuning. Checking the IF bits
+ at 81.4MHz can check if the crystal is problematic or not.
+
+ @returns True (1) if the IF bits are equal to 0x37 (good), otherwise
+ false (0). The device may still function if the IF values
+ are slightly off, but auto-scan and tuning will likely be
+ less reliable.
+*/
+/**************************************************************************/
+bool tea5767CheckCrystal(void)
+{
+ /* AN10133 (p.38) states:
+
+ The choice of 32768Hz reference frequency makes it possible to use a
+ cheap 32.768kHz watch crystal. A drawback of these clocks is that they
+ have a very high second order temperature coefficient. This may result
+ in de-tuning the radio or a search action may fail.
+
+ Care should be taken when using this crystal. The accuracy of the
+ 32768Hz crystal can be checked by tuning the radio to 81.4 MHz
+ with high/low side injection and reading the IF via the bus. The IF
+ must be 37Hex.
+
+ An other issue when using this crystal is the grid position. It is
+ not possible to create a 100kHz grid position, but 98.304kHz
+ (3*32768Hz). This should not be a problem if this is resolved in
+ software.
+
+ The motional capacitance of the 32768Hz crystal should be between
+ 1.5fF and 3fF. Shunt capacitance must be max 3.5pF. The series
+ resistance should not exceed 75KOhm.
+
+ Further, the frequency accuracy of this crystal must not exceed ±20
+ ppm, while the temperature drift should be in the order of ±50 ppm
+ over a temperature range of –10oC to +60oC.
+ */
+
+ uint8_t ifValue = 0;
+ uint8_t buffer[5] = { 0, 0, 0, 0, 0 };
+
+ // Set the frequency to 81.4MHz
+ tea5767SetFrequency(81400000);
+ systickDelay(100);
+
+ // Read back the IF bits
+ tea5767ReadData(&buffer[0]);
+ ifValue = buffer[2] & 0x7F;
+
+ // Reconfigure the chip to a known frequency to avoid user problems
+ // tea5767SetFrequency(TEA5767_FMBANDSTART_JAPAN);
+ tea5767SetFrequency(TEA5767_FMBANDSTART_US_EUROPE);
+
+ // Return true if the crystal is OK (IF = 0x37 @ 81.4MHz),
+ // false if it's something else
+ if (0x37 == ifValue)
+ return true;
+ else
+ return false;
+}
+
+/**************************************************************************/
+/*!
+ @brief Initialises I2C for the TEA5767.
+*/
+/**************************************************************************/
+uint32_t tea5767Init()
+{
+ // Initialise I2C
+ if (i2cInit(I2CMASTER) == false)
+ {
+ /* Fatal error */
+ return -1;
+ }
+
+ /* Set initialisation flag */
+ _tea5767Initialised = true;
+
+ // Set the frequency to a known value to make sure the PLL is properly configured
+ // tea5767SetFrequency(TEA5767_FMBANDSTART_JAPAN);
+ tea5767SetFrequency(TEA5767_FMBANDSTART_US_EUROPE);
+
+ return 0;
+}
+
+/**************************************************************************/
+/*!
+ @brief Sets the frequency to the specified value in Hz
+
+ @param[in] frequency
+ The frequency in Hz, meaning that 95.7MHz = 97,500,000
+ 101.4 MHz = 101,400,000 etc.
+*/
+/**************************************************************************/
+void tea5767SetFrequency( uint32_t frequency )
+{
+ uint32_t pllValue;
+ uint8_t buffer[5] = { 0, 0, 0, 0, 0 };
+
+ // Make sure I2C is initialised
+ if (!_tea5767Initialised) tea5767Init();
+
+ // Calculate PLL word for high side injection mode
+ // NDEC = (4*(FRF + FIF)) / FREFS
+ // where:
+ // FRF = Desired tuning frequency in Hz
+ // FIF = Intermediate frequency in Hz (225kHz)
+ // FREFS = Reference frequency in Hz (32.768kHz)
+ pllValue = (4 * (frequency + 225000)) / 32768;
+
+ buffer[0] = (pllValue >> 8) & 0x3F; // Upper 6 PLL bits (also turns mute and search mode off!)
+ buffer[1] = (pllValue & 0xFF); // Lower 8 PLL bits
+ buffer[2] = TEA5767_WBYTE3_HLSI; // High side injection mode
+ buffer[3] = TEA5767_WBYTE4_XTAL; // XTAL bit = 1 for 32.768kHz crystal
+ buffer[4] = 0; // PLLREF bit = 0 for 32.768kHz crystal
+
+ // Send data over I2C
+ tea5767SendData(buffer);
+}
+
+/**************************************************************************/
+/*!
+ @brief Returns the current frequency in Hz (meaning 97.5MHz will be
+ returned as 97,500,000 etc.
+*/
+/**************************************************************************/
+uint32_t tea5767GetFrequency( void )
+{
+ uint32_t frequency = 0;
+ uint8_t buffer[5] = { 0, 0, 0, 0, 0 };
+
+ if (!_tea5767Initialised) tea5767Init();
+
+ tea5767ReadData(&buffer[0]);
+
+ // Retrieve the raw 14-bit PLL value from word 1 and 2
+ frequency = ((buffer[0] & 0x3F) << 8) + buffer[1];
+ // Determine the current frequency using the same high side formula as above
+ frequency = frequency * 32768 / 4 - 225000;
+
+ return frequency;
+}
+
+/**************************************************************************/
+/*!
+ @brief Starts the auto-scan process from the current frequency
+
+ @param[in] scanDirection
+ Set this to 0 to scan down, or one to scan up, starting
+ at the current frequency.
+*/
+/**************************************************************************/
+void tea5767Scan( uint8_t scanDirection )
+{
+ uint8_t rbuffer[5] = { 0, 0, 0, 0, 0 };
+ uint8_t wbuffer[5] = { 0, 0, 0, 0, 0 };
+
+ // Make sure I2C is initialised
+ if (!_tea5767Initialised) tea5767Init();
+
+ // First we need to get the current PLL word to know where to start from
+ tea5767ReadData(&rbuffer[0]);
+
+ // Set the PLL value again and append the search enable bu
+ wbuffer[0] = TEA5767_WBYTE1_SEARCHMODE + // Search mode enabled
+ (rbuffer[0] & 0x3F); // Upper PLL bits
+ wbuffer[1] = rbuffer[1]; // Lower PLL bits
+ wbuffer[2] = TEA5767_WBYTE3_SEARCHSTOPLEVEL_MID | // Mid level ADC for search steps
+ TEA5767_WBYTE3_HLSI; // HLSI (must be 1 for PLL)
+ wbuffer[3] = TEA5767_WBYTE4_XTAL; // Must be 1 for 32.768kHz crystal
+ wbuffer[4] = 0x00;
+
+ // Set the scan direction bit to 1 (scan up) if scanDirection is non-zero
+ if (scanDirection) wbuffer[2] |= TEA5767_WBYTE3_SEARCHUPDOWN;
+
+ // Send data over I2C
+ tea5767SendData(wbuffer);
+}
--- /dev/null
+/**************************************************************************/
+/*!
+ @file tea5767.h
+ @author K. Townsend
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2012, K. Townsend.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the copyright holders nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/**************************************************************************/
+
+#ifndef _TEA5767_H_
+#define _TEA5767_H_
+
+#include "projectconfig.h"
+
+#define TEA5767_FMBANDSTART_US_EUROPE (87500000) // 87.5 MHz to 108 MHz
+#define TEA5767_FMBANDSTART_JAPAN (76000000) // 76 MHz to 91 MHz plus TV audio at 108 MHz
+
+/*=========================================================================
+ I2C ADDRESS/BITS
+ -----------------------------------------------------------------------*/
+ #define TEA5767_ADDRESS (0xC0) // 1100000x
+ #define TEA5767_READ (0x01)
+/*=========================================================================*/
+
+/*=========================================================================
+ WRITE BYTE 1
+ MUTE | SEARCHMODE | PLL13 | PLL12 | PLL11 | PLL10 | PLL9 | PLL8
+ -----------------------------------------------------------------------*/
+ #define TEA5767_WBYTE1_MUTE (1<<7) // 1 = mute, 0 = output enabled (mute enabled after reset)
+ #define TEA5767_WBYTE1_SEARCHMODE (1<<6) // 1 = Search mode enabled
+/*=========================================================================*/
+
+/*=========================================================================
+ WRITE BYTE 2
+ PLL7 | PLL6 | PLL5 | PLL4 | PLL3 | PLL2 | PLL1 | PLL0
+ -----------------------------------------------------------------------*/
+
+/*=========================================================================*/
+
+/*=========================================================================
+ WRITE BYTE 3
+ SUD | SSL1 | SSL0 | HLSI | MS | MR | ML | SWP1
+ -----------------------------------------------------------------------*/
+ #define TEA5767_WBYTE3_SEARCHUPDOWN (1<<7) // 1 = search up, 0 = search down
+ #define TEA5767_WBYTE3_SEARCHSTOPLEVEL1 (1<<6) // 10 = mid level (ADC = 7), 11 = high level (ADC = 10)
+ #define TEA5767_WBYTE3_SEARCHSTOPLEVEL0 (1<<5) // 00 = invalid, 01 = low level (ADC = 5)
+ #define TEA5767_WBYTE3_SEARCHSTOPLEVELMASK (3<<5)
+ #define TEA5767_WBYTE3_HLSI (1<<4) // 1 = high side LO injection, 0 = low side LO injection
+ #define TEA5767_WBYTE3_MONOTOSTEREO (1<<3) // 1 = force mono, 0 = stereo on
+ #define TEA5767_WBYTE3_MUTERIGHT (1<<2) // 1 = mute right audio, 0 = enabled
+ #define TEA5767_WBYTE3_MUTELEFT (1<<1) // 1 = mute left audio, 0 = enabled
+ /*---------------------------------------------------------------------*/
+ #define TEA5767_WBYTE3_SEARCHSTOPLEVEL_LOW (0x20) // ADC output = 5 (bit: 01)
+ #define TEA5767_WBYTE3_SEARCHSTOPLEVEL_MID (0x40) // ADC output = 7 (bit: 10)
+ #define TEA5767_WBYTE3_SEARCHSTOPLEVEL_HIGH (0x60) // ADC output = 10 (bit: 11)
+/*=========================================================================*/
+
+/*=========================================================================
+ WRITE BYTE 4
+ SWP2 | STBY | BL | XTAL | SMUTE | HCC | SNC | SI
+ -----------------------------------------------------------------------*/
+ #define TEA5767_WBYTE4_STANDBY (1<<6) // 1 = standby mode
+ #define TEA5767_WBYTE4_BANDLIMITS (1<<5) // 1 = Japanese FM band, 0 = US/Europe
+ #define TEA5767_WBYTE4_XTAL (1<<4) // Combined with PLLREF in byte 5 (set to 1 for 32.768kHz crystal)
+ #define TEA5767_WBYTE4_SOFTMUTE (1<<3) // 1 = soft mute enabled
+ #define TEA5767_WBYTE4_HIGHCUTCONTROL (1<<2) // 1 = HCC enabled
+ #define TEA5767_WBYTE4_STEREONOISECANCEL (1<<1) // 1 = stereo noise cancelling enabled
+/*=========================================================================*/
+
+/*=========================================================================
+ WRITE BYTE 5
+ PLLREF | DTC | - | - | - | - | - | -
+ -----------------------------------------------------------------------*/
+ #define TEA5767_WBYTE5_PLLREF (1<<7) // 1 = 6.5MHz PLL ref freq. enabled (set to 0 for 32.768kHz crystal)
+ #define TEA5767_WBYTE5_DEEMPHASISTIMECONST (1<<6) // 1 = DTC is 75µs, 0 = 50µs
+/*=========================================================================*/
+
+
+/*=========================================================================
+ READ BYTE 1
+ RF | BLF | PLL13 | PLL12 | PLL11 | PLL 10 | PLL9 | PLL8
+ -----------------------------------------------------------------------*/
+ #define TEA5767_RBYTE1_READYFLAG (1<<7) // 1 = station found or band-limit reached, 0 = no station found
+ #define TEA5767_RBYTE1_BANDLIMITFLAG (1<<6) // 1 = band limit has been reached, 0 = band limit not reached
+/*=========================================================================*/
+
+/*=========================================================================
+ READ BYTE 2
+ PLL7 | PLL6 | PLL5 | PLL4 | PLL3 | PLL2 | PLL1 | PLL0
+ -----------------------------------------------------------------------*/
+
+/*=========================================================================*/
+
+/*=========================================================================
+ READ BYTE 3
+ STEREO | IF6 | IF5 | IF4 | IF3 | IF2 | IF1 | IF0
+ -----------------------------------------------------------------------*/
+ #define TEA5767_RBYTE3_STEREOINDICATOR (1<<7) // 1 = stereo reception, 0 = mono reception
+/*=========================================================================*/
+
+/*=========================================================================
+ READ BYTE 4
+ LEV3 | LEV2 | LEV1 | LEV0 | CI3 | CI2 | CI1 | -
+ -----------------------------------------------------------------------*/
+ #define TEA5767_RBYTE4_ADCLEVELOUTPUTMASK (0xF0) // ADC output level
+ #define TEA5767_RBYTE4_CHIPIDMASK (0x0F) // These bits must be set to 0!
+/*=========================================================================*/
+
+/*=========================================================================
+ READ BYTE 5
+ - | - | - | - | - | - | - | -
+ -----------------------------------------------------------------------*/
+
+/*=========================================================================*/
+
+uint32_t tea5767Init( void );
+void tea5767SetFrequency( uint32_t );
+uint32_t tea5767GetFrequency( void );
+void tea5767Scan( uint8_t );
+void tea5767Mute( bool );
+
+#endif
\ No newline at end of file