diff --git a/radio/src/targets/common/arm/stm32/stm32_spi_h7.cpp b/radio/src/targets/common/arm/stm32/stm32_spi_h7.cpp index 5e6ad0a06..f2c60a429 100644 --- a/radio/src/targets/common/arm/stm32/stm32_spi_h7.cpp +++ b/radio/src/targets/common/arm/stm32/stm32_spi_h7.cpp @@ -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 = diff --git a/radio/src/targets/common/arm/stm32/vs1053b.cpp b/radio/src/targets/common/arm/stm32/vs1053b.cpp index 829378f0b..24db3ab72 100644 --- a/radio/src/targets/common/arm/stm32/vs1053b.cpp +++ b/radio/src/targets/common/arm/stm32/vs1053b.cpp @@ -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(); } diff --git a/radio/src/targets/st16/board.cpp b/radio/src/targets/st16/board.cpp index 85f5fb841..0c3dfb736 100644 --- a/radio/src/targets/st16/board.cpp +++ b/radio/src/targets/st16/board.cpp @@ -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) diff --git a/radio/src/targets/st16/hal.h b/radio/src/targets/st16/hal.h index dbf645b89..73ea71214 100644 --- a/radio/src/targets/st16/hal.h +++ b/radio/src/targets/st16/hal.h @@ -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