Neue Vögel: Gerade fliegend und gerade fliegend mit Dip.
[hackover2013-badge-firmware.git] / drivers / audio / tea5767 / tea5767.c
1 /**************************************************************************/
2 /*!
3 @file tea5767.c
4 @author K. Townsend
5
6 @brief Driver for the TEA5767 FM receiver.
7
8 @section LICENSE
9
10 Software License Agreement (BSD License)
11
12 Copyright (c) 2012, K. Townsend
13 All rights reserved.
14
15 Redistribution and use in source and binary forms, with or without
16 modification, are permitted provided that the following conditions are met:
17 1. Redistributions of source code must retain the above copyright
18 notice, this list of conditions and the following disclaimer.
19 2. Redistributions in binary form must reproduce the above copyright
20 notice, this list of conditions and the following disclaimer in the
21 documentation and/or other materials provided with the distribution.
22 3. Neither the name of the copyright holders nor the
23 names of its contributors may be used to endorse or promote products
24 derived from this software without specific prior written permission.
25
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
27 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
30 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
33 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37 /**************************************************************************/
38 #include "tea5767.h"
39 #include "core/i2c/i2c.h"
40 #include "core/systick/systick.h"
41
42 extern volatile uint8_t I2CMasterBuffer[I2C_BUFSIZE];
43 extern volatile uint8_t I2CSlaveBuffer[I2C_BUFSIZE];
44
45 static bool _tea5767Initialised = false;
46
47 /**************************************************************************/
48 /*!
49 @brief Sends 5 bytes over I2C
50 */
51 /**************************************************************************/
52 void tea5767SendData(uint8_t * bytes)
53 {
54 // Clear write buffers
55 uint32_t i;
56 for ( i = 0; i < I2C_BUFSIZE; i++ )
57 {
58 I2CMasterBuffer[i] = 0x00;
59 }
60
61 I2CWriteLength = 6;
62 I2CReadLength = 0;
63 I2CMasterBuffer[0] = TEA5767_ADDRESS;
64 I2CMasterBuffer[1] = bytes[0];
65 I2CMasterBuffer[2] = bytes[1];
66 I2CMasterBuffer[3] = bytes[2];
67 I2CMasterBuffer[4] = bytes[3];
68 I2CMasterBuffer[5] = bytes[4];
69 i2cEngine();
70 }
71
72 /**************************************************************************/
73 /*!
74 @brief Reads 5 bytes over I2C
75 */
76 /**************************************************************************/
77 void tea5767ReadData(uint8_t * bytes)
78 {
79 // Clear buffers
80 uint32_t i;
81 for ( i = 0; i < I2C_BUFSIZE; i++ )
82 {
83 I2CMasterBuffer[i] = 0x00;
84 I2CSlaveBuffer[i] = 0x00;
85 }
86
87 I2CWriteLength = 1;
88 I2CReadLength = 5;
89 I2CMasterBuffer[0] = TEA5767_ADDRESS | TEA5767_READ;
90 i2cEngine();
91
92 bytes[0] = I2CSlaveBuffer[0];
93 bytes[1] = I2CSlaveBuffer[1];
94 bytes[2] = I2CSlaveBuffer[2];
95 bytes[3] = I2CSlaveBuffer[3];
96 bytes[4] = I2CSlaveBuffer[4];
97 }
98
99 /**************************************************************************/
100 /*!
101 @brief This is a test function to evaluate the quality of crystals
102 used on 3rd party modules. Most modules use cheap 32.768kHz
103 crystals which are prone to de-tuning. Checking the IF bits
104 at 81.4MHz can check if the crystal is problematic or not.
105
106 @returns True (1) if the IF bits are equal to 0x37 (good), otherwise
107 false (0). The device may still function if the IF values
108 are slightly off, but auto-scan and tuning will likely be
109 less reliable.
110 */
111 /**************************************************************************/
112 bool tea5767CheckCrystal(void)
113 {
114 /* AN10133 (p.38) states:
115
116 The choice of 32768Hz reference frequency makes it possible to use a
117 cheap 32.768kHz watch crystal. A drawback of these clocks is that they
118 have a very high second order temperature coefficient. This may result
119 in de-tuning the radio or a search action may fail.
120
121 Care should be taken when using this crystal. The accuracy of the
122 32768Hz crystal can be checked by tuning the radio to 81.4 MHz
123 with high/low side injection and reading the IF via the bus. The IF
124 must be 37Hex.
125
126 An other issue when using this crystal is the grid position. It is
127 not possible to create a 100kHz grid position, but 98.304kHz
128 (3*32768Hz). This should not be a problem if this is resolved in
129 software.
130
131 The motional capacitance of the 32768Hz crystal should be between
132 1.5fF and 3fF. Shunt capacitance must be max 3.5pF. The series
133 resistance should not exceed 75KOhm.
134
135 Further, the frequency accuracy of this crystal must not exceed ±20
136 ppm, while the temperature drift should be in the order of ±50 ppm
137 over a temperature range of –10oC to +60oC.
138 */
139
140 uint8_t ifValue = 0;
141 uint8_t buffer[5] = { 0, 0, 0, 0, 0 };
142
143 // Set the frequency to 81.4MHz
144 tea5767SetFrequency(81400000);
145 systickDelay(100);
146
147 // Read back the IF bits
148 tea5767ReadData(&buffer[0]);
149 ifValue = buffer[2] & 0x7F;
150
151 // Reconfigure the chip to a known frequency to avoid user problems
152 // tea5767SetFrequency(TEA5767_FMBANDSTART_JAPAN);
153 tea5767SetFrequency(TEA5767_FMBANDSTART_US_EUROPE);
154
155 // Return true if the crystal is OK (IF = 0x37 @ 81.4MHz),
156 // false if it's something else
157 if (0x37 == ifValue)
158 return true;
159 else
160 return false;
161 }
162
163 /**************************************************************************/
164 /*!
165 @brief Initialises I2C for the TEA5767.
166 */
167 /**************************************************************************/
168 uint32_t tea5767Init()
169 {
170 // Initialise I2C
171 if (i2cInit(I2CMASTER) == false)
172 {
173 /* Fatal error */
174 return -1;
175 }
176
177 /* Set initialisation flag */
178 _tea5767Initialised = true;
179
180 // Set the frequency to a known value to make sure the PLL is properly configured
181 // tea5767SetFrequency(TEA5767_FMBANDSTART_JAPAN);
182 tea5767SetFrequency(TEA5767_FMBANDSTART_US_EUROPE);
183
184 return 0;
185 }
186
187 /**************************************************************************/
188 /*!
189 @brief Sets the frequency to the specified value in Hz
190
191 @param[in] frequency
192 The frequency in Hz, meaning that 95.7MHz = 97,500,000
193 101.4 MHz = 101,400,000 etc.
194 */
195 /**************************************************************************/
196 void tea5767SetFrequency( uint32_t frequency )
197 {
198 uint32_t pllValue;
199 uint8_t buffer[5] = { 0, 0, 0, 0, 0 };
200
201 // Make sure I2C is initialised
202 if (!_tea5767Initialised) tea5767Init();
203
204 // Calculate PLL word for high side injection mode
205 // NDEC = (4*(FRF + FIF)) / FREFS
206 // where:
207 // FRF = Desired tuning frequency in Hz
208 // FIF = Intermediate frequency in Hz (225kHz)
209 // FREFS = Reference frequency in Hz (32.768kHz)
210 pllValue = (4 * (frequency + 225000)) / 32768;
211
212 buffer[0] = (pllValue >> 8) & 0x3F; // Upper 6 PLL bits (also turns mute and search mode off!)
213 buffer[1] = (pllValue & 0xFF); // Lower 8 PLL bits
214 buffer[2] = TEA5767_WBYTE3_HLSI; // High side injection mode
215 buffer[3] = TEA5767_WBYTE4_XTAL; // XTAL bit = 1 for 32.768kHz crystal
216 buffer[4] = 0; // PLLREF bit = 0 for 32.768kHz crystal
217
218 // Send data over I2C
219 tea5767SendData(buffer);
220 }
221
222 /**************************************************************************/
223 /*!
224 @brief Returns the current frequency in Hz (meaning 97.5MHz will be
225 returned as 97,500,000 etc.
226 */
227 /**************************************************************************/
228 uint32_t tea5767GetFrequency( void )
229 {
230 uint32_t frequency = 0;
231 uint8_t buffer[5] = { 0, 0, 0, 0, 0 };
232
233 if (!_tea5767Initialised) tea5767Init();
234
235 tea5767ReadData(&buffer[0]);
236
237 // Retrieve the raw 14-bit PLL value from word 1 and 2
238 frequency = ((buffer[0] & 0x3F) << 8) + buffer[1];
239 // Determine the current frequency using the same high side formula as above
240 frequency = frequency * 32768 / 4 - 225000;
241
242 return frequency;
243 }
244
245 /**************************************************************************/
246 /*!
247 @brief Starts the auto-scan process from the current frequency
248
249 @param[in] scanDirection
250 Set this to 0 to scan down, or one to scan up, starting
251 at the current frequency.
252 */
253 /**************************************************************************/
254 void tea5767Scan( uint8_t scanDirection )
255 {
256 uint8_t rbuffer[5] = { 0, 0, 0, 0, 0 };
257 uint8_t wbuffer[5] = { 0, 0, 0, 0, 0 };
258
259 // Make sure I2C is initialised
260 if (!_tea5767Initialised) tea5767Init();
261
262 // First we need to get the current PLL word to know where to start from
263 tea5767ReadData(&rbuffer[0]);
264
265 // Set the PLL value again and append the search enable bu
266 wbuffer[0] = TEA5767_WBYTE1_SEARCHMODE + // Search mode enabled
267 (rbuffer[0] & 0x3F); // Upper PLL bits
268 wbuffer[1] = rbuffer[1]; // Lower PLL bits
269 wbuffer[2] = TEA5767_WBYTE3_SEARCHSTOPLEVEL_MID | // Mid level ADC for search steps
270 TEA5767_WBYTE3_HLSI; // HLSI (must be 1 for PLL)
271 wbuffer[3] = TEA5767_WBYTE4_XTAL; // Must be 1 for 32.768kHz crystal
272 wbuffer[4] = 0x00;
273
274 // Set the scan direction bit to 1 (scan up) if scanDirection is non-zero
275 if (scanDirection) wbuffer[2] |= TEA5767_WBYTE3_SEARCHUPDOWN;
276
277 // Send data over I2C
278 tea5767SendData(wbuffer);
279 }
This page took 0.063466 seconds and 5 git commands to generate.