feat(stm32h7s78-dk): sound support

This commit is contained in:
raphaelcoeffic
2025-01-18 11:31:07 +01:00
committed by Malte Langermann
parent 1b0cde96ed
commit c00ee1e9dd
7 changed files with 213 additions and 76 deletions
@@ -46,6 +46,7 @@ add_definitions(
-DSTM32H7S7xx -DCORE_CM7 -DFIRMWARE_QSPI
-DSDRAM -DCOLORLCD -DLIBOPENUI -DPCBHORUS -DPCBX10 -DPCBFRSKY
-DHARDWARE_TOUCH -DSOFTWARE_KEYBOARD
-DAUDIO -DVOICE -DSOFTWARE_VOLUME
)
# Make malloc() thread-safe
@@ -96,9 +97,12 @@ set(BOOTLOADER_SRC ${BOOTLOADER_SRC} $<TARGET_OBJECTS:board_bl>)
add_library(board OBJECT EXCLUDE_FROM_ALL
${BOARD_COMMON_SRC}
${TARGET_SRC_DIR}/tp_gt911.cpp
${TARGET_SRC_DIR}/audio_driver.cpp
drivers/wm8904.cpp
targets/common/arm/stm32/lsm6ds_driver.cpp
targets/common/arm/stm32/mixer_scheduler_driver.cpp
targets/common/arm/stm32/stm32_switch_driver.cpp
targets/common/arm/stm32/stm32_i2s.cpp
)
set(FIRMWARE_SRC ${FIRMWARE_SRC} $<TARGET_OBJECTS:board>)
@@ -0,0 +1,181 @@
#include "audio.h"
#include "delays_driver.h"
#include "drivers/wm8904.h"
#include "hal/gpio.h"
#include "stm32_dma.h"
#include "stm32_i2s.h"
#include "stm32_i2c_driver.h"
#include "stm32_hal_ll.h"
#include "debug.h"
#include "timers_driver.h"
static wm8904_t _wm8904 = {0};
//
// STM32H7S78-DK pinout
//
// Pin MCU WM8904
// ---------------------------------
// PA3 (I2S2_MCK): MCLK <-> MCLK
// PA4 (I2S2_WS): WCLK <-> WCLK
// PA5 (I2S2_CK): BCLK <-> BCLK
// PB5 (I2S2_SDO): DOUT <-> DIN
// PG12 (I2S2_SDI): DIN <-> DOUT
#define I2S_DMA GPDMA1
#define I2S_DMA_Stream LL_DMA_CHANNEL_2
#define I2S_DMA_Stream_Request LL_GPDMA1_REQUEST_SPI6_TX
#define I2S_DMA_Stream_IRQn GPDMA1_Channel2_IRQn
#define I2S_DMA_Stream_IRQHandler GPDMA1_Channel2_IRQHandler
const stm32_i2s_t _i2s_dev = {
.SPIx = AUDIO_SPI,
.MCK = {GPIO_PIN(GPIOA, 3), GPIO_AF5},
.WS = {GPIO_PIN(GPIOA, 4), GPIO_AF8},
.CK = {GPIO_PIN(GPIOA, 5), GPIO_AF8},
.SDO = {GPIO_PIN(GPIOB, 5), GPIO_AF8},
.SDI = {GPIO_PIN(GPIOG, 12), GPIO_AF5},
.DMA = I2S_DMA,
.DMA_Stream = I2S_DMA_Stream,
.DMA_PeriphRequest = I2S_DMA_Stream_Request,
};
// 16 bit, 2 channels
#define DMA_BUFFER_HALF_LEN AUDIO_BUFFER_SIZE
// 2 buffers
#define DMA_BUFFER_LEN (DMA_BUFFER_HALF_LEN * 2)
static uint32_t _dma_buffer[DMA_BUFFER_LEN] __DMA_NO_CACHE;
static uintptr_t _ll_addr_reset __DMA_NO_CACHE;
static inline uint32_t _conv_sample(int16_t sample)
{
return ((uint32_t)(uint16_t)sample << 16) | (uint16_t)sample;
}
#define PI 3.14159265358979323846f
static void generate_sine_wave(const uint32_t num_samples)
{
const uint32_t sample_rate = 32000;
const float amplitude = 0.8f;
const float frequency = 440.0f;
// Generate and write samples
for (uint32_t i = 0; i < num_samples; i++) {
float time = (float)i / sample_rate;
// Calculate sample value (-32768 to 32767)
int16_t sample = (int16_t)(amplitude * 32767.0f *
sinf(2.0f * PI * frequency * time));
// write into dma buffer
_dma_buffer[i] = _conv_sample(sample);
}
}
static int enable_dma_irqs()
{
// enable DMA channel IRQ
LL_DMA_EnableIT_HT(I2S_DMA, I2S_DMA_Stream);
LL_DMA_EnableIT_TC(I2S_DMA, I2S_DMA_Stream);
NVIC_SetPriority(GPDMA1_Channel2_IRQn, 7);
NVIC_EnableIRQ(GPDMA1_Channel2_IRQn);
return 0;
}
int audioInit()
{
memset(_dma_buffer, 0, sizeof(_dma_buffer));
if (wm8904_probe(&_wm8904, 0, 0x34 >> 1) < 0) {
return -1;
}
if (stm32_i2s_init(&_i2s_dev)) {
return -1;
}
if (wm8904_init(&_wm8904) < 0) {
return -1;
}
enable_dma_irqs();
return 0;
}
static volatile uint32_t _dma_buffer_offset = 0;
static void copy_into_dma_buffer(const AudioBuffer* buffer)
{
unsigned idx = 0;
uint32_t offset = _dma_buffer_offset;
if (buffer) {
while (idx < buffer->size) {
_dma_buffer[offset++] = _conv_sample(buffer->data[idx++]);
}
audioQueue.buffersFifo.freeNextFilledBuffer();
}
for (;idx < DMA_BUFFER_HALF_LEN; idx++) {
_dma_buffer[offset++] = 0;
}
}
void audioConsumeCurrentBuffer()
{
if (!stm32_i2s_is_xfer_started(&_i2s_dev)) {
auto buffer = audioQueue.buffersFifo.getNextFilledBuffer();
if (!buffer) return;
copy_into_dma_buffer(buffer);
// basic DMA configuration
stm32_i2s_config_dma_stream(&_i2s_dev, _dma_buffer, DMA_BUFFER_LEN * 2);
// configure source address reset (circular buffer)
_ll_addr_reset = (uintptr_t)_dma_buffer;
LL_DMA_SetLinkedListBaseAddr(_i2s_dev.DMA, _i2s_dev.DMA_Stream,
(uintptr_t)&_ll_addr_reset & 0xFFFF0000);
LL_DMA_ConfigLinkUpdate(_i2s_dev.DMA, _i2s_dev.DMA_Stream,
LL_DMA_UPDATE_CSAR,
(uintptr_t)&_ll_addr_reset & 0xFFFF);
// and finally start it!
stm32_i2s_start_dma_stream(&_i2s_dev);
}
}
static inline uint32_t _calc_offset(uint8_t tc)
{
return tc * DMA_BUFFER_HALF_LEN;
}
static void audio_update_dma_buffer(uint8_t tc)
{
_dma_buffer_offset = _calc_offset(tc);
copy_into_dma_buffer(audioQueue.buffersFifo.getNextFilledBuffer());
}
extern "C" void GPDMA1_Channel2_IRQHandler()
{
if (stm32_dma_check_ht_flag(GPDMA1, LL_DMA_CHANNEL_2)) {
audio_update_dma_buffer(0);
}
if (stm32_dma_check_tc_flag(GPDMA1, LL_DMA_CHANNEL_2)) {
audio_update_dma_buffer(1);
}
}
+1 -1
View File
@@ -112,7 +112,7 @@ void boardInit()
keysInit();
switchInit();
// audioInit();
audioInit();
adcInit(&_adc_driver);
setAnalogValue(adcGetInputOffset(ADC_INPUT_VBAT), 840 * 2);
+1 -32
View File
@@ -181,39 +181,8 @@ bool isBacklightEnabled();
#endif
// Audio driver
void audioInit();
int audioInit();
void audioConsumeCurrentBuffer();
void audioSpiWriteBuffer(const uint8_t * buffer, uint32_t size);
void audioSpiSetSpeed(uint8_t speed);
uint8_t audioHardReset();
uint8_t audioSoftReset();
void audioSendRiffHeader();
void audioOn();
void audioOff();
bool isAudioReady();
bool audioChipReset();
#define SPI_SPEED_2 0
#define SPI_SPEED_4 1
#define SPI_SPEED_8 2
#define SPI_SPEED_16 3
#define SPI_SPEED_32 4
#define SPI_SPEED_64 5
#define SPI_SPEED_128 6
#define SPI_SPEED_256 7
#define audioDisableIrq() // interrupts must stay enabled on Horus
#define audioEnableIrq() // interrupts must stay enabled on Horus
#if defined(PCBNV14)
#define setSampleRate(freq)
#else
void setSampleRate(uint32_t frequency);
#endif
void setScaledVolume(uint8_t volume);
void setVolume(uint8_t volume);
static inline int32_t getVolume() { return 0; }
#define VOLUME_LEVEL_MAX 23
#define VOLUME_LEVEL_DEF 12
// Telemetry driver
#define INTMODULE_FIFO_SIZE 512
+2
View File
@@ -227,6 +227,8 @@
// #define AUDIO_TIMER TIM6
// #define AUDIO_DMA DMA1
#define AUDIO_SPI SPI6
// I2C Bus
#define I2C_B1 I2C1
#define I2C_B1_SDA_GPIO GPIO_PIN(GPIOB, 9) // PB.09
+1 -27
View File
@@ -214,30 +214,6 @@ static void LTDC_MspInit()
__HAL_RCC_LTDC_RELEASE_RESET();
}
/**
* @brief LTDC Clock Config for LCD TFT display.
* @param hltdc LTDC Handle
* Being __weak it can be overwritten by the application
* @retval HAL_status
*/
static HAL_StatusTypeDef LTDC_ClockConfig(LTDC_HandleTypeDef *hltdc)
{
LL_RCC_PLL3R_Enable();
LL_RCC_PLL3FRACN_Disable();
LL_RCC_PLL3_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_4_8);
LL_RCC_PLL3_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE);
LL_RCC_PLL3_SetM(2);
LL_RCC_PLL3_SetN(50);
LL_RCC_PLL3_SetP(2);
LL_RCC_PLL3_SetQ(2);
LL_RCC_PLL3_SetR(24);
LL_RCC_PLL3_Enable();
while (LL_RCC_PLL3_IsReady() != 1) {
}
return HAL_OK;
}
/**
* @brief Initializes the LTDC.
* @param hltdc LTDC handle
@@ -340,9 +316,7 @@ static int32_t LCD_InitEx(uint32_t Orientation, uint32_t PixelFormat,
/* Assert display enable LCD_DISP_CTRL pin */
HAL_GPIO_WritePin(LCD_DISP_EN_GPIO_PORT, LCD_DISP_EN_PIN, GPIO_PIN_SET);
if (LTDC_ClockConfig(&hlcd_ltdc) != HAL_OK) {
ret = LCD_ERROR_PERIPH_FAILURE;
} else if (LTDC_Init(&hlcd_ltdc, Width, Height) != HAL_OK) {
if (LTDC_Init(&hlcd_ltdc, Width, Height) != HAL_OK) {
ret = LCD_ERROR_PERIPH_FAILURE;
}
@@ -98,31 +98,34 @@ void SystemClock_Config()
}
/* PLL2 configuration and activation */
// LL_RCC_PLL2P_Enable();
// LL_RCC_PLL2Q_Enable();
// LL_RCC_PLL2R_Enable();
LL_RCC_PLL2S_Enable();
LL_RCC_PLL2Q_Enable();
LL_RCC_PLL2FRACN_Disable();
LL_RCC_PLL2_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_2_4);
LL_RCC_PLL2_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE);
LL_RCC_PLL2_SetM(2);
LL_RCC_PLL2_SetN(50);
// LL_RCC_PLL2_SetP(1);
// LL_RCC_PLL2_SetQ(2);
// LL_RCC_PLL2_SetR(2);
LL_RCC_PLL2_SetS(3);
LL_RCC_PLL2_SetN(64);
LL_RCC_PLL2_SetP(2); // disabled
LL_RCC_PLL2_SetQ(47); // 16.340 MHz
LL_RCC_PLL2_SetR(2); // disabled
LL_RCC_PLL2_SetS(4); // 192 MHz
LL_RCC_PLL2_Enable();
while (LL_RCC_PLL2_IsReady() != 1) {
}
/* Enable SRAM1, SRAM2 & SRAM3 */
// LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_D2SRAM1 |
// LL_AHB2_GRP1_PERIPH_D2SRAM2 |
// LL_AHB2_GRP1_PERIPH_D2SRAM3);
/* Set periph clock sources */
// LL_RCC_SetFMCClockSource(LL_RCC_FMC_CLKSOURCE_HCLK);
// LL_RCC_SetSPIClockSource(LL_RCC_SPI123_CLKSOURCE_PLL3P);
/* PLL2 configuration and activation */
LL_RCC_PLL3R_Enable();
LL_RCC_PLL3FRACN_Disable();
LL_RCC_PLL3_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_4_8);
LL_RCC_PLL3_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE);
LL_RCC_PLL3_SetM(2);
LL_RCC_PLL3_SetN(50);
LL_RCC_PLL3_SetP(2);
LL_RCC_PLL3_SetQ(2);
LL_RCC_PLL3_SetR(24);
LL_RCC_PLL3_Enable();
while (LL_RCC_PLL3_IsReady() != 1) {
}
#if defined(USE_USB_HS)
LL_RCC_SetUSBPHYCClockSource(LL_RCC_USBPHYC_CLKSOURCE_HSE);
@@ -134,9 +137,13 @@ void SystemClock_Config()
LL_RCC_SetOTGFSClockSource(LL_RCC_OTGFS_CLKSOURCE_HSI48);
#endif
// 192 MHz
LL_RCC_SetXSPIClockSource(LL_RCC_XSPI1_CLKSOURCE_PLL2S);
LL_RCC_SetXSPIClockSource(LL_RCC_XSPI2_CLKSOURCE_PLL2S);
// 16.340 MHz
LL_RCC_SetSPIClockSource(LL_RCC_SPI6_CLKSOURCE_PLL2Q);
// Only required if using Async ADC clock ???
LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_CLKP);
}