Various fixes around Companion trainer mode (#7116)
[opentx.git] / radio / src / targets / horus / audio_spi_driver.cpp
blob32ef0f90636e74c689ba6af0e3856bb0db0d1d91
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "opentx.h"
23 #if !defined(SIMU)
25 #define VS_WRITE_COMMAND 0x02
26 #define VS_READ_COMMAND 0x03
28 #define SPI_MODE 0x00
29 #define SPI_STATUS 0x01
30 #define SPI_BASS 0x02
31 #define SPI_CLOCKF 0x03
32 #define SPI_DECODE_TIME 0x04
33 #define SPI_AUDATA 0x05
34 #define SPI_WRAM 0x06
35 #define SPI_WRAMADDR 0x07
36 #define SPI_HDAT0 0x08
37 #define SPI_HDAT1 0x09
38 #define SPI_AIADDR 0x0a
39 #define SPI_VOL 0x0b
40 #define SPI_AICTRL0 0x0c
41 #define SPI_AICTRL1 0x0d
42 #define SPI_AICTRL2 0x0e
43 #define SPI_AICTRL3 0x0f
45 #define SM_DIFF 0x01
46 #define SM_LAYER12 0x02
47 #define SM_RESET 0x04
48 #define SM_CANCEL 0x08
49 #define SM_EARSPEAKER_LO 0x10
50 #define SM_TESTS 0x20
51 #define SM_STREAM 0x40
52 #define SM_EARSPEAKER_HI 0x80
53 #define SM_DACT 0x100
54 #define SM_SDIORD 0x200
55 #define SM_SDISHARE 0x400
56 #define SM_SDINEW 0x800
57 #define SM_ADPCM 0x1000
58 #define SM_LINE1 0x4000
59 #define SM_CLK_RANGE 0x8000
61 #define SPI_SPEED_2 0
62 #define SPI_SPEED_4 1
63 #define SPI_SPEED_8 2
64 #define SPI_SPEED_16 3
65 #define SPI_SPEED_32 4
66 #define SPI_SPEED_64 5
67 #define SPI_SPEED_128 6
68 #define SPI_SPEED_256 7
70 #define MP3_BUFFER_SIZE 32
72 #define CS_HIGH() do { AUDIO_CS_GPIO->BSRRL = AUDIO_CS_GPIO_PIN; } while (0)
73 #define CS_LOW() do { AUDIO_CS_GPIO->BSRRH = AUDIO_CS_GPIO_PIN; } while (0)
74 #define XDCS_HIGH() do { AUDIO_XDCS_GPIO->BSRRL = AUDIO_XDCS_GPIO_PIN; } while (0)
75 #define XDCS_LOW() do { AUDIO_XDCS_GPIO->BSRRH = AUDIO_XDCS_GPIO_PIN; } while (0)
76 #define RST_HIGH() do { AUDIO_RST_GPIO->BSRRL = AUDIO_RST_GPIO_PIN; } while (0)
77 #define RST_LOW() do { AUDIO_RST_GPIO->BSRRH = AUDIO_RST_GPIO_PIN; } while (0)
79 #define READ_DREQ() (GPIO_ReadInputDataBit(AUDIO_DREQ_GPIO, AUDIO_DREQ_GPIO_PIN))
81 void audioSpiInit(void)
83 GPIO_InitTypeDef GPIO_InitStructure;
84 SPI_InitTypeDef SPI_InitStructure;
86 GPIO_InitStructure.GPIO_Pin = AUDIO_SPI_MISO_GPIO_PIN;
87 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
88 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
89 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
90 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
91 GPIO_Init(AUDIO_SPI_MISO_GPIO, &GPIO_InitStructure);
93 GPIO_InitStructure.GPIO_Pin = AUDIO_SPI_SCK_GPIO_PIN;
94 GPIO_Init(AUDIO_SPI_SCK_GPIO, &GPIO_InitStructure);
96 GPIO_InitStructure.GPIO_Pin = AUDIO_SPI_MOSI_GPIO_PIN;
97 GPIO_Init(AUDIO_SPI_MOSI_GPIO, &GPIO_InitStructure);
99 GPIO_InitStructure.GPIO_Pin = AUDIO_CS_GPIO_PIN;
100 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
101 GPIO_Init(AUDIO_CS_GPIO, &GPIO_InitStructure);
103 GPIO_InitStructure.GPIO_Pin = AUDIO_XDCS_GPIO_PIN;
104 GPIO_Init(AUDIO_XDCS_GPIO, &GPIO_InitStructure);
106 GPIO_InitStructure.GPIO_Pin = AUDIO_RST_GPIO_PIN;
107 GPIO_Init(AUDIO_RST_GPIO, &GPIO_InitStructure);
109 GPIO_InitStructure.GPIO_Pin = AUDIO_DREQ_GPIO_PIN;
110 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
111 GPIO_Init(AUDIO_DREQ_GPIO, &GPIO_InitStructure);
113 GPIO_PinAFConfig(AUDIO_SPI_SCK_GPIO, AUDIO_SPI_SCK_GPIO_PinSource, AUDIO_SPI_GPIO_AF);
114 GPIO_PinAFConfig(AUDIO_SPI_MISO_GPIO, AUDIO_SPI_MISO_GPIO_PinSource, AUDIO_SPI_GPIO_AF);
115 GPIO_PinAFConfig(AUDIO_SPI_MOSI_GPIO, AUDIO_SPI_MOSI_GPIO_PinSource, AUDIO_SPI_GPIO_AF);
117 RCC_ClocksTypeDef RCC_Clocks;
118 RCC_GetClocksFreq(&RCC_Clocks);
120 SPI_I2S_DeInit(AUDIO_SPI);
121 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
122 SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
123 SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
124 SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
125 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
126 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
127 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
128 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
129 SPI_InitStructure.SPI_CRCPolynomial = 7;
130 SPI_Init(AUDIO_SPI, &SPI_InitStructure);
131 SPI_Cmd(AUDIO_SPI, ENABLE);
133 SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_RXNE);
134 SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_TXE);
137 void audioSpiSetSpeed(uint8_t speed)
139 AUDIO_SPI->CR1 &= 0xFFC7; // Fsck=Fcpu/256
140 switch (speed) {
141 case SPI_SPEED_2:
142 AUDIO_SPI->CR1 |= 0x00 << 3; // Fsck=Fpclk/2=36Mhz
143 break;
144 case SPI_SPEED_4:
145 AUDIO_SPI->CR1 |= 0x01 << 3; // Fsck=Fpclk/4=18Mhz
146 break;
147 case SPI_SPEED_8:
148 AUDIO_SPI->CR1 |= 0x02 << 3; // Fsck=Fpclk/8=9Mhz
149 break;
150 case SPI_SPEED_16:
151 AUDIO_SPI->CR1 |= 0x03 << 3; // Fsck=Fpclk/16=4.5Mhz
152 break;
153 case SPI_SPEED_32:
154 AUDIO_SPI->CR1 |= 0x04 << 3; // Fsck=Fpclk/32=2.25Mhz
155 break;
156 case SPI_SPEED_64:
157 AUDIO_SPI->CR1 |= 0x05 << 3; // Fsck=Fpclk/16=1.125Mhz
158 break;
159 case SPI_SPEED_128:
160 AUDIO_SPI->CR1 |= 0x06 << 3; // Fsck=Fpclk/16=562.5Khz
161 break;
162 case SPI_SPEED_256:
163 AUDIO_SPI->CR1 |= 0x07 << 3; // Fsck=Fpclk/16=281.25Khz
164 break;
166 AUDIO_SPI->CR1 |= 0x01 << 6;
169 uint8_t audioSpiReadWriteByte(uint8_t value)
171 uint16_t time_out = 0x0FFF;
172 while (SPI_I2S_GetFlagStatus(AUDIO_SPI, SPI_I2S_FLAG_TXE) == RESET) {
173 if (--time_out == 0) {
174 // reset SPI
175 SPI_Cmd(AUDIO_SPI, DISABLE);
176 SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_OVR);
177 SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_BSY);
178 SPI_I2S_ClearFlag(AUDIO_SPI, I2S_FLAG_UDR);
179 SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_TIFRFE);
180 SPI_Cmd(AUDIO_SPI, ENABLE);
181 break;
184 SPI_I2S_SendData(AUDIO_SPI, value);
186 time_out = 0x0FFF;
187 while (SPI_I2S_GetFlagStatus(AUDIO_SPI, SPI_I2S_FLAG_RXNE) == RESET) {
188 if (--time_out == 0) {
189 // reset SPI
190 SPI_Cmd(AUDIO_SPI, DISABLE);
191 SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_OVR);
192 SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_BSY);
193 SPI_I2S_ClearFlag(AUDIO_SPI, I2S_FLAG_UDR);
194 SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_TIFRFE);
195 SPI_Cmd(AUDIO_SPI, ENABLE);
196 break;
199 return SPI_I2S_ReceiveData(AUDIO_SPI);
202 uint8_t audioWaitDreq(int32_t delay_us)
204 while (READ_DREQ() == 0) {
205 if (delay_us-- == 0) return 0;
206 delay_01us(10);
208 return 1;
211 uint16_t audioSpiReadReg(uint8_t address)
213 if (!audioWaitDreq(100))
214 return 0;
216 audioSpiSetSpeed(SPI_SPEED_64);
217 XDCS_HIGH();
218 CS_LOW();
219 audioSpiReadWriteByte(VS_READ_COMMAND);
220 audioSpiReadWriteByte(address);
221 uint16_t result = audioSpiReadWriteByte(0xff) << 8;
222 result += audioSpiReadWriteByte(0xff);
223 delay_01us(100); // 10us
224 CS_HIGH();
225 audioSpiSetSpeed(SPI_SPEED_8);
226 return result;
229 uint16_t audioSpiReadCmd(uint8_t address)
231 if (!audioWaitDreq(100))
232 return 0;
234 audioSpiSetSpeed(SPI_SPEED_64);
235 XDCS_HIGH();
236 CS_LOW();
237 audioSpiReadWriteByte(VS_READ_COMMAND);
238 audioSpiReadWriteByte(address);
239 uint16_t result = audioSpiReadWriteByte(0) << 8;
240 result |= audioSpiReadWriteByte(0);
241 delay_01us(50); // 5us
242 CS_HIGH();
243 audioSpiSetSpeed(SPI_SPEED_8);
244 return result;
247 uint8_t audioSpiWriteCmd(uint8_t address, uint16_t data)
249 if (!audioWaitDreq(100))
250 return 0;
252 audioSpiSetSpeed(SPI_SPEED_64);
253 XDCS_HIGH();
254 CS_LOW();
255 audioSpiReadWriteByte(VS_WRITE_COMMAND);
256 audioSpiReadWriteByte(address);
257 audioSpiReadWriteByte(data >> 8);
258 audioSpiReadWriteByte(data);
259 delay_01us(50); // 5us
260 CS_HIGH();
261 audioSpiSetSpeed(SPI_SPEED_8);
262 return 1;
265 void audioResetDecodeTime(void)
267 audioSpiWriteCmd(SPI_DECODE_TIME, 0x0000);
268 audioSpiWriteCmd(SPI_DECODE_TIME, 0x0000);
271 uint8_t audioHardReset(void)
273 XDCS_HIGH();
274 CS_HIGH();
275 RST_LOW();
276 delay_ms(100); // 100ms
277 RST_HIGH();
279 if (!audioWaitDreq(100))
280 return 0;
282 delay_ms(20); // 20ms
283 return 1;
286 uint8_t audioSoftReset(void)
288 audioSpiSetSpeed(SPI_SPEED_64);
289 if (!audioWaitDreq(100))
290 return 0;
292 audioSpiReadWriteByte(0x00); // start the transfer
294 audioSpiWriteCmd(SPI_MODE, 0x0816); // SOFT RESET, new model
295 if (!audioWaitDreq(100))
296 return 0;
298 // wait for set up successful
299 uint8_t retry = 0;
300 while (audioSpiReadReg(SPI_CLOCKF) != 0x9800 && retry < 100) {
301 retry++;
302 audioSpiWriteCmd(SPI_CLOCKF, 0x9800);
305 audioResetDecodeTime(); // reset the decoding time
306 audioSpiSetSpeed(SPI_SPEED_8);
307 XDCS_LOW();
308 audioSpiReadWriteByte(0X0);
309 audioSpiReadWriteByte(0X0);
310 audioSpiReadWriteByte(0X0);
311 audioSpiReadWriteByte(0X0);
312 delay_01us(100); // 10us
313 XDCS_HIGH();
314 return 1;
317 uint32_t audioSpiWriteData(const uint8_t * buffer, uint32_t size)
319 XDCS_LOW();
321 uint32_t index = 0;
322 while (index < size && READ_DREQ() != 0) {
323 for (int i=0; i<MP3_BUFFER_SIZE && index<size; i++) {
324 audioSpiReadWriteByte(buffer[index++]);
327 return index;
330 void audioSpiWriteBuffer(const uint8_t * buffer, uint32_t size)
332 const uint8_t * p = buffer;
333 while (size > 0) {
334 uint32_t written = audioSpiWriteData(p, size);
335 p += written;
336 size -= written;
340 const uint8_t RiffHeader[] = {
341 0x52, 0x49, 0x46, 0x46, 0xff, 0xff, 0xff, 0xff, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20,
342 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00,
343 0x02, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
344 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 void audioSendRiffHeader()
349 audioSpiWriteBuffer(RiffHeader, sizeof(RiffHeader));
352 #if defined(PCBX12S)
353 void audioShutdownInit()
355 GPIO_InitTypeDef GPIO_InitStructure;
356 GPIO_InitStructure.GPIO_Pin = AUDIO_SHUTDOWN_GPIO_PIN;
357 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
358 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
359 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
360 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
361 GPIO_Init(AUDIO_SHUTDOWN_GPIO, &GPIO_InitStructure);
362 GPIO_SetBits(AUDIO_SHUTDOWN_GPIO, AUDIO_SHUTDOWN_GPIO_PIN); // we never RESET it, there is a 2s delay on STARTUP
364 #endif
366 void audioInit()
368 #if defined(PCBX12S)
369 audioShutdownInit();
370 // TODO X10 code missing
371 #endif
373 audioSpiInit();
374 audioHardReset();
375 audioSoftReset();
376 audioSpiSetSpeed(SPI_SPEED_8);
377 delay_ms(1); // 1ms
378 audioSendRiffHeader();
381 uint8_t * currentBuffer = nullptr;
382 uint32_t currentSize = 0;
383 int16_t newVolume = -1;
385 void audioSetCurrentBuffer(const AudioBuffer * buffer)
387 if (buffer) {
388 currentBuffer = (uint8_t *)buffer->data;
389 currentSize = buffer->size * 2;
391 else {
392 currentBuffer = nullptr;
393 currentSize = 0;
397 void audioConsumeCurrentBuffer()
399 if (newVolume >= 0) {
400 uint8_t value = newVolume;
401 audioSpiWriteCmd(SPI_VOL, (value << 8) + value);
402 // audioSendRiffHeader();
403 newVolume = -1;
406 if (!currentBuffer) {
407 audioSetCurrentBuffer(audioQueue.buffersFifo.getNextFilledBuffer());
410 if (currentBuffer) {
411 uint32_t written = audioSpiWriteData(currentBuffer, currentSize);
412 currentBuffer += written;
413 currentSize -= written;
414 if (currentSize == 0) {
415 audioQueue.buffersFifo.freeNextFilledBuffer();
416 currentBuffer = nullptr;
417 currentSize = 0;
422 // adjust this value for a volume level just above the silence
423 // values is attenuation in dB, higher value - less volume
424 // max value is 126
425 #define VOLUME_MIN_DB 40
427 void setScaledVolume(uint8_t volume)
429 if (volume > VOLUME_LEVEL_MAX) {
430 volume = VOLUME_LEVEL_MAX;
432 // maximum volume is 0x00 and total silence is 0xFE
433 if (volume == 0) {
434 setVolume(0xFE); // silence
436 else {
437 uint32_t vol = (VOLUME_MIN_DB * 2) - ((uint32_t)volume * (VOLUME_MIN_DB * 2)) / VOLUME_LEVEL_MAX;
438 setVolume(vol);
442 void setVolume(uint8_t volume)
444 newVolume = volume;
447 int32_t getVolume()
449 return -1; // TODO
452 #endif