fix(st16): audio chip init and data transfer (#6299)

This commit is contained in:
Raphael Coeffic
2025-05-27 07:40:48 +10:00
committed by GitHub
parent 7977e8e694
commit 96a1ca5653
4 changed files with 201 additions and 163 deletions
@@ -151,8 +151,6 @@ static void _init_gpios(const stm32_spi_t* spi)
static void _config_dma_streams(const stm32_spi_t* spi)
{
stm32_dma_enable_clock(spi->DMA);
LL_DMA_DeInit(spi->DMA, spi->rxDMA_Stream);
LL_DMA_DeInit(spi->DMA, spi->txDMA_Stream);
LL_DMA_InitTypeDef dmaInit;
LL_DMA_StructInit(&dmaInit);
@@ -160,42 +158,77 @@ static void _config_dma_streams(const stm32_spi_t* spi)
#if defined(STM32H7)
dmaInit.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
dmaInit.Priority = LL_DMA_PRIORITY_VERYHIGH;
dmaInit.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD;
dmaInit.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD;
dmaInit.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_BYTE;
dmaInit.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_BYTE;
#elif defined(STM32H7RS)
dmaInit.Priority = LL_DMA_LOW_PRIORITY_HIGH_WEIGHT;
#endif
#if defined(STM32H7)
dmaInit.PeriphRequest = spi->rxDMA_PeriphRequest;
dmaInit.PeriphOrM2MSrcAddress = LL_SPI_DMA_GetRxRegAddr(spi->SPIx);
#elif defined(STM32H7RS)
dmaInit.Request = spi->rxDMA_PeriphRequest;
dmaInit.SrcAddress = LL_SPI_DMA_GetRxRegAddr(spi->SPIx);
dmaInit.SrcIncMode = LL_DMA_SRC_FIXED;
dmaInit.DestIncMode = LL_DMA_DEST_INCREMENT;
dmaInit.SrcDataWidth = LL_DMA_DEST_DATAWIDTH_HALFWORD;
dmaInit.DestDataWidth = LL_DMA_DEST_DATAWIDTH_HALFWORD;
#endif
dmaInit.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
LL_DMA_Init(spi->DMA, spi->rxDMA_Stream, &dmaInit);
if (spi->rxDMA_PeriphRequest) {
LL_DMA_DeInit(spi->DMA, spi->rxDMA_Stream);
#if defined(STM32H7)
dmaInit.PeriphRequest = spi->txDMA_PeriphRequest;
dmaInit.PeriphOrM2MSrcAddress = LL_SPI_DMA_GetTxRegAddr(spi->SPIx);
dmaInit.PeriphRequest = spi->rxDMA_PeriphRequest;
dmaInit.PeriphOrM2MSrcAddress = LL_SPI_DMA_GetRxRegAddr(spi->SPIx);
#elif defined(STM32H7RS)
dmaInit.Request = spi->rxDMA_PeriphRequest;
dmaInit.DestAddress = LL_SPI_DMA_GetTxRegAddr(spi->SPIx);
dmaInit.SrcIncMode = LL_DMA_SRC_INCREMENT;
dmaInit.DestIncMode = LL_DMA_DEST_FIXED;
dmaInit.SrcDataWidth = LL_DMA_SRC_DATAWIDTH_HALFWORD;
dmaInit.DestDataWidth = LL_DMA_SRC_DATAWIDTH_HALFWORD;
dmaInit.Request = spi->rxDMA_PeriphRequest;
dmaInit.SrcAddress = LL_SPI_DMA_GetRxRegAddr(spi->SPIx);
dmaInit.SrcIncMode = LL_DMA_SRC_FIXED;
dmaInit.DestIncMode = LL_DMA_DEST_INCREMENT;
dmaInit.SrcDataWidth = LL_DMA_SRC_DATAWIDTH_BYTE;
dmaInit.DestDataWidth = LL_DMA_DEST_DATAWIDTH_BYTE;
#endif
dmaInit.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
LL_DMA_Init(spi->DMA, spi->txDMA_Stream, &dmaInit);
dmaInit.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
LL_DMA_Init(spi->DMA, spi->rxDMA_Stream, &dmaInit);
}
if (spi->txDMA_PeriphRequest) {
LL_DMA_DeInit(spi->DMA, spi->txDMA_Stream);
#if defined(STM32H7)
dmaInit.PeriphRequest = spi->txDMA_PeriphRequest;
dmaInit.PeriphOrM2MSrcAddress = LL_SPI_DMA_GetTxRegAddr(spi->SPIx);
#elif defined(STM32H7RS)
dmaInit.Request = spi->txDMA_PeriphRequest;
dmaInit.DestAddress = LL_SPI_DMA_GetTxRegAddr(spi->SPIx);
dmaInit.SrcIncMode = LL_DMA_SRC_INCREMENT;
dmaInit.DestIncMode = LL_DMA_DEST_FIXED;
dmaInit.SrcDataWidth = LL_DMA_SRC_DATAWIDTH_BYTE;
dmaInit.DestDataWidth = LL_DMA_DEST_DATAWIDTH_BYTE;
#endif
dmaInit.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
LL_DMA_Init(spi->DMA, spi->txDMA_Stream, &dmaInit);
}
}
#if defined(STM32H7)
static void _config_tx_dma_data_width(const stm32_spi_t* spi, uint32_t data_width)
{
uint32_t periph_size = LL_DMA_PDATAALIGN_BYTE;
uint32_t memory_size = LL_DMA_MDATAALIGN_BYTE;
if (data_width == sizeof(uint16_t)) {
periph_size = LL_DMA_PDATAALIGN_HALFWORD;
memory_size = LL_DMA_MDATAALIGN_HALFWORD;
}
LL_DMA_SetPeriphSize(spi->DMA, spi->txDMA_Stream, periph_size);
LL_DMA_SetMemorySize(spi->DMA, spi->txDMA_Stream, memory_size);
}
#elif defined(STM32H7RS)
static void _config_tx_dma_data_width(const stm32_spi_t* spi, uint32_t data_width)
{
uint32_t src_width = LL_DMA_SRC_DATAWIDTH_BYTE;
uint32_t dest_width = LL_DMA_DEST_DATAWIDTH_BYTE;
if (data_width == sizeof(uint16_t)) {
src_width = LL_DMA_SRC_DATAWIDTH_HALFWORD;
memory_size = LL_DMA_DEST_DATAWIDTH_HALFWORD;
}
LL_DMA_SetSrcDataWidth(spi->DMA, spi->txDMA_Stream, src_width);
LL_DMA_SetDestDataWidth(spi->DMA, spi->txDMA_Stream, dest_width);
}
#endif
#endif
void stm32_spi_init(const stm32_spi_t* spi, uint32_t data_width)
@@ -427,13 +460,13 @@ uint32_t stm32_spi_dma_receive_bytes(const stm32_spi_t* spi, uint8_t* data,
#if !defined(USE_SPI_DMA)
return stm32_spi_transfer_bytes(spi, nullptr, data, length);
#else
uint32_t xfer_len = length / 2;
uint32_t xfer_len = length;
while (xfer_len > 0) {
uint16_t single_xfer_len =
xfer_len > SPI_MAX_XFER_SIZE ? SPI_MAX_XFER_SIZE : xfer_len;
spi_receive_dma(spi, data, single_xfer_len);
xfer_len -= single_xfer_len;
data += single_xfer_len * 2;
data += single_xfer_len;
}
return length;
@@ -460,25 +493,29 @@ uint32_t stm32_spi_dma_transmit_bytes(const stm32_spi_t* spi,
#if !defined(USE_SPI_DMA)
return stm32_spi_transfer_bytes(spi, data, nullptr, length);
#else
uint32_t xfer_len = length / 2;
_config_tx_dma_data_width(spi, sizeof(uint8_t));
uint32_t xfer_len = length;
while (xfer_len > 0) {
uint16_t single_xfer_len =
xfer_len > SPI_MAX_XFER_SIZE ? SPI_MAX_XFER_SIZE : xfer_len;
spi_transmit_dma(spi, data, single_xfer_len);
xfer_len -= single_xfer_len;
data += single_xfer_len * 2;
data += single_xfer_len;
}
return length;
#endif
}
uint32_t stm32_spi_dma_transmit_words(const stm32_spi_t* spi,
const uint16_t* data, uint32_t length)
{
#if !defined(USE_SPI_DMA)
return stm32_spi_transfer_words(spi, data, nullptr, length);
#else
_config_tx_dma_data_width(spi, sizeof(uint16_t));
return length;
#endif
}
uint32_t stm32_spi_dma_transmit_words(const stm32_spi_t* spi,
const uint16_t* data, uint32_t length)
{
#if !defined(USE_SPI_DMA)
return stm32_spi_transfer_words(spi, data, nullptr, length);
#else
uint32_t xfer_len = length;
while (xfer_len > 0) {
uint16_t single_xfer_len =
+100 -121
View File
@@ -33,46 +33,48 @@
#include "edgetx.h"
#include "timers_driver.h"
#define VS_WRITE_COMMAND 0x02
#define VS_READ_COMMAND 0x03
#define VS_WRITE_COMMAND 0x02
#define VS_READ_COMMAND 0x03
#define SPI_MODE 0x00
#define SPI_STATUS 0x01
#define SPI_BASS 0x02
#define SPI_CLOCKF 0x03
#define SPI_DECODE_TIME 0x04
#define SPI_AUDATA 0x05
#define SPI_WRAM 0x06
#define SPI_WRAMADDR 0x07
#define SPI_HDAT0 0x08
#define SPI_HDAT1 0x09
#define SPI_AIADDR 0x0a
#define SPI_VOL 0x0b
#define SPI_AICTRL0 0x0c
#define SPI_AICTRL1 0x0d
#define SPI_AICTRL2 0x0e
#define SPI_AICTRL3 0x0f
#define SPI_MODE 0x00
#define SPI_STATUS 0x01
#define SPI_BASS 0x02
#define SPI_CLOCKF 0x03
#define SPI_DECODE_TIME 0x04
#define SPI_AUDATA 0x05
#define SPI_WRAM 0x06
#define SPI_WRAMADDR 0x07
#define SPI_HDAT0 0x08
#define SPI_HDAT1 0x09
#define SPI_AIADDR 0x0a
#define SPI_VOL 0x0b
#define SPI_AICTRL0 0x0c
#define SPI_AICTRL1 0x0d
#define SPI_AICTRL2 0x0e
#define SPI_AICTRL3 0x0f
#define SM_DIFF 0x01
#define SM_LAYER12 0x02
#define SM_RESET 0x04
#define SM_CANCEL 0x08
#define SM_EARSPEAKER_LO 0x10
#define SM_TESTS 0x20
#define SM_STREAM 0x40
#define SM_EARSPEAKER_HI 0x80
#define SM_DACT 0x100
#define SM_SDIORD 0x200
#define SM_SDISHARE 0x400
#define SM_SDINEW 0x800
#define SM_ADPCM 0x1000
#define SM_LINE1 0x4000
#define SM_CLK_RANGE 0x8000
#define SM_DIFF 0x01
#define SM_LAYER12 0x02
#define SM_RESET 0x04
#define SM_CANCEL 0x08
#define SM_EARSPEAKER_LO 0x10
#define SM_TESTS 0x20
#define SM_STREAM 0x40
#define SM_EARSPEAKER_HI 0x80
#define SM_DACT 0x100
#define SM_SDIORD 0x200
#define SM_SDISHARE 0x400
#define SM_SDINEW 0x800
#define SM_ADPCM 0x1000
#define SM_LINE1 0x4000
#define SM_CLK_RANGE 0x8000
#define SPI_LOW_SPEED 1500000
#define SPI_HIGH_SPEED 12000000
#define SPI_LOW_SPEED 1500000
#define SPI_HIGH_SPEED 12000000
#define VS1053_BUFFER_SIZE 32
#define VS1053_BUFFER_SIZE 32
#define DEFAULT_VOLUME 0xFEFE
#define XDCS_HIGH() _xdcs_high()
#define XDCS_LOW() _xdcs_low()
@@ -87,11 +89,13 @@ static uint32_t _last_play_ts = 0;
static uint8_t* _audio_buffer = nullptr;
static uint32_t _audio_buffer_len = 0;
static void(*_spi_transmit_data)(const uint8_t*, uint32_t) = nullptr;
// volume is set asynchronously:
// - first saved in _async_volume
// - then vs1053b_update_volume() is called periodically
// to actually send the new setting to the device.
static int16_t _async_volume = -1;
static int16_t _async_volume;
static inline void _xdcs_high() { gpio_set(_instance->XDCS); }
static inline void _xdcs_low() { gpio_clear(_instance->XDCS); }
@@ -127,6 +131,7 @@ static void vs1053b_gpio_init(void)
_set_mute_pin(true);
stm32_spi_init(_instance->spi, LL_SPI_DATAWIDTH_8BIT);
stm32_spi_set_max_baudrate(_instance->spi, SPI_LOW_SPEED);
}
static uint8_t vs1053b_spi_rw_byte(uint8_t value)
@@ -134,122 +139,85 @@ static uint8_t vs1053b_spi_rw_byte(uint8_t value)
return stm32_spi_transfer_byte(_instance->spi, value);
}
static uint8_t vs1053b_wait_dreq(int32_t delay_us)
static void vs1053b_spi_transmit_bytes(const uint8_t* data, uint32_t length)
{
stm32_spi_transfer_bytes(_instance->spi, data, nullptr, length);
}
static void vs1053b_spi_dma_transmit_bytes(const uint8_t* data, uint32_t length)
{
#if __CORTEX_M >= 0x07
SCB_CleanDCache_by_Addr((void*)data, length);
#endif
stm32_spi_dma_transmit_bytes(_instance->spi, data, length);
}
static uint8_t vs1053b_wait_dreq(uint32_t timeout_us)
{
uint32_t start = timersGetUsTick();
while (READ_DREQ() == 0) {
if (delay_us-- == 0) return 0;
delay_01us(10);
if (timersGetUsTick() - start >= timeout_us) return 0;
}
return 1;
}
static uint16_t vs1053b_read_reg(uint8_t address)
static void _wait_us(uint32_t delay_us)
{
if (!vs1053b_wait_dreq(100))
return 0;
uint32_t start = timersGetUsTick();
while (timersGetUsTick() - start < delay_us) {}
}
stm32_spi_set_max_baudrate(_instance->spi, SPI_LOW_SPEED);
XDCS_HIGH();
stm32_spi_select(_instance->spi);
vs1053b_spi_rw_byte(VS_READ_COMMAND);
vs1053b_spi_rw_byte(address);
volatile uint16_t result = vs1053b_spi_rw_byte(0xff) << 8;
result += vs1053b_spi_rw_byte(0xff);
delay_01us(100); // 10us
stm32_spi_unselect(_instance->spi);
stm32_spi_set_max_baudrate(_instance->spi, SPI_HIGH_SPEED);
return result;
static void _wait_ms(uint32_t delay_ms)
{
uint32_t start = timersGetMsTick();
while (timersGetMsTick() - start < delay_ms) {}
}
static uint8_t vs1053b_write_cmd(uint8_t address, uint16_t data)
{
if (!vs1053b_wait_dreq(100))
return 0;
stm32_spi_set_max_baudrate(_instance->spi, SPI_LOW_SPEED);
XDCS_HIGH();
stm32_spi_select(_instance->spi);
vs1053b_spi_rw_byte(VS_WRITE_COMMAND);
vs1053b_spi_rw_byte(address);
vs1053b_spi_rw_byte(data >> 8);
vs1053b_spi_rw_byte(data);
delay_01us(50); // 5us
stm32_spi_unselect(_instance->spi);
// wait for command to be processed
_wait_us(20);
vs1053b_wait_dreq(100);
stm32_spi_set_max_baudrate(_instance->spi, SPI_HIGH_SPEED);
return 1;
}
static void vs1053b_reset_decode_time()
{
vs1053b_write_cmd(SPI_DECODE_TIME, 0x0000);
vs1053b_write_cmd(SPI_DECODE_TIME, 0x0000);
}
static uint8_t vs1053b_hard_reset()
static void vs1053b_hard_reset()
{
XDCS_HIGH();
stm32_spi_unselect(_instance->spi);
_reset_low();
delay_ms(100); // 100ms
_wait_ms(100);
_reset_high();
if (!vs1053b_wait_dreq(5000))
return 0;
delay_ms(20); // 20ms
return 1;
}
static uint8_t vs1053b_soft_reset()
{
stm32_spi_set_max_baudrate(_instance->spi, SPI_LOW_SPEED);
if (!vs1053b_wait_dreq(100))
return 0;
vs1053b_spi_rw_byte(0x00); // start the transfer
uint8_t retry = 0;
uint16_t mode = SM_SDINEW;
while (vs1053b_read_reg(SPI_MODE) != mode && retry < 100) {
retry++;
vs1053b_write_cmd(SPI_MODE, mode | SM_RESET);
delay_ms(2);
}
// wait for set up successful
retry = 0;
while (vs1053b_read_reg(SPI_CLOCKF) != 0x9800 && retry < 100) {
retry++;
vs1053b_write_cmd(SPI_CLOCKF, 0x9800);
}
vs1053b_reset_decode_time(); // reset the decoding time
stm32_spi_set_max_baudrate(_instance->spi, SPI_HIGH_SPEED);
XDCS_LOW();
vs1053b_spi_rw_byte(0X0);
vs1053b_spi_rw_byte(0X0);
vs1053b_spi_rw_byte(0X0);
vs1053b_spi_rw_byte(0X0);
delay_01us(100); // 10us
XDCS_HIGH();
return 1;
// datasheet says 1.8ms at default clock speed
vs1053b_wait_dreq(3000);
}
static uint32_t vs1053b_send_data(const uint8_t * buffer, uint32_t size)
{
XDCS_LOW();
uint32_t index = 0;
while (index < size && READ_DREQ() != 0) {
for (int i = 0; i < VS1053_BUFFER_SIZE && index < size; i++) {
vs1053b_spi_rw_byte(buffer[index++]);
}
const uint8_t* data = buffer;
while (size > 0 && READ_DREQ() != 0) {
uint32_t xfer_size = size > VS1053_BUFFER_SIZE ? VS1053_BUFFER_SIZE : size;
XDCS_LOW();
_spi_transmit_data(data, xfer_size);
XDCS_HIGH();
size -= xfer_size;
data += xfer_size;
}
return index;
return data - buffer;
}
static void vs1053b_send_buffer(const uint8_t * buffer, uint32_t size)
@@ -341,13 +309,24 @@ void vs1053b_init(const vs1053b_t* dev)
{
_instance = dev;
if (_instance->spi->DMA) {
_spi_transmit_data = vs1053b_spi_dma_transmit_bytes;
} else {
_spi_transmit_data = vs1053b_spi_transmit_bytes;
}
vs1053b_gpio_init();
vs1053b_hard_reset();
vs1053b_soft_reset();
vs1053b_write_cmd(SPI_MODE, SM_SDINEW);
_async_volume = DEFAULT_VOLUME;
vs1053b_update_volume();
vs1053b_write_cmd(SPI_CLOCKF, 0x9800);
vs1053b_wait_dreq(1000);
stm32_spi_set_max_baudrate(_instance->spi, SPI_HIGH_SPEED);
delay_ms(1); // 1ms
vs1053b_send_riff_header();
}
+3
View File
@@ -102,6 +102,9 @@ static stm32_spi_t audioSpi =
.MISO = AUDIO_SPI_MISO_GPIO,
.MOSI = AUDIO_SPI_MOSI_GPIO,
.CS = AUDIO_CS_GPIO,
.DMA = AUDIO_SPI_DMA,
.txDMA_PeriphRequest = AUDIO_SPI_DMA_REQ,
.txDMA_Stream = AUDIO_SPI_DMA_STREAM,
};
static void audio_set_rst_pin(bool set)
+19
View File
@@ -21,6 +21,22 @@
#pragma once
// DMA streams:
//
// - LEDs TIM2_UP: DMA1 stream 0
// - Audio SPI1_TX: DMA1 stream 1
// - Gimbals USART2_RX: DMA1 stream 2
// - Telemytry UART5_RX: DMA1 stream 3
// - Telemetry UART5_TX: DMA1 stream 7
//
// - ADC3: DMA2 stream 0
// - ADC1: DMA2 stream 4
// - Ext. Mod. UART4_RX: DMA2 stream 4 (!)
// - Ext. Mod. UART4_TX: DMA2 stream 6
// - Ext. Mod. TIM4_UP: DMA2 stream 6
//
#define CPU_FREQ 400000000
#define PERI1_FREQUENCY 100000000
@@ -342,6 +358,9 @@
#define AUDIO_SPI_SCK_GPIO GPIO_PIN(GPIOA, 5) // PA.05
#define AUDIO_SPI_MISO_GPIO GPIO_PIN(GPIOG, 9) // PG.09
#define AUDIO_SPI_MOSI_GPIO GPIO_PIN(GPIOD, 7) // PD.07
#define AUDIO_SPI_DMA DMA1
#define AUDIO_SPI_DMA_REQ LL_DMAMUX1_REQ_SPI1_TX
#define AUDIO_SPI_DMA_STREAM LL_DMA_STREAM_1
#define AUDIO_MUTE_GPIO 0
#define AUDIO_UNMUTE_DELAY 180 // ms
#define AUDIO_MUTE_DELAY 200 // ms