First commit
authorKevin Townsend <kevin@ktownsend.com>
Fri, 4 May 2012 14:53:11 +0000 (16:53 +0200)
committerKevin Townsend <kevin@ktownsend.com>
Fri, 4 May 2012 14:53:11 +0000 (16:53 +0200)
drivers/audio/tea5767/tea5767.c [new file with mode: 0644]
drivers/audio/tea5767/tea5767.h [new file with mode: 0644]

diff --git a/drivers/audio/tea5767/tea5767.c b/drivers/audio/tea5767/tea5767.c
new file mode 100644 (file)
index 0000000..4e141bf
--- /dev/null
@@ -0,0 +1,279 @@
+/**************************************************************************/
+/*! 
+    @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);
+}
diff --git a/drivers/audio/tea5767/tea5767.h b/drivers/audio/tea5767/tea5767.h
new file mode 100644 (file)
index 0000000..f2a4869
--- /dev/null
@@ -0,0 +1,149 @@
+/**************************************************************************/
+/*! 
+    @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
This page took 0.035555 seconds and 4 git commands to generate.