This is an automated email from the ASF dual-hosted git repository. jerzy pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
commit 854699acb5358f37b583192d584106cd8d2b2a58 Author: Jerzy Kasenberg <jerzy.kasenb...@codecoup.pl> AuthorDate: Wed Jan 15 09:58:48 2025 +0100 hw/drivers/i2s: Add I2S driver for STM32F7 family Code implements I2S driver for STM32F7xx MCUs that have it. Signed-off-by: Jerzy Kasenberg <jerzy.kasenb...@codecoup.pl> --- .../i2s_stm32f7/include/i2s_stm32f7/i2s_stm32f7.h | 346 ++++++++ .../include/i2s_stm32f7/stm32_pin_cfg.h | 41 + hw/drivers/i2s/i2s_stm32f7/pkg.yml | 29 + hw/drivers/i2s/i2s_stm32f7/src/i2s_stm32f7.c | 971 +++++++++++++++++++++ hw/drivers/i2s/i2s_stm32f7/syscfg.yml | 19 + 5 files changed, 1406 insertions(+) diff --git a/hw/drivers/i2s/i2s_stm32f7/include/i2s_stm32f7/i2s_stm32f7.h b/hw/drivers/i2s/i2s_stm32f7/include/i2s_stm32f7/i2s_stm32f7.h new file mode 100644 index 000000000..c78636e75 --- /dev/null +++ b/hw/drivers/i2s/i2s_stm32f7/include/i2s_stm32f7/i2s_stm32f7.h @@ -0,0 +1,346 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _I2S_STM32_H +#define _I2S_STM32_H + +#include <stm32f7xx_hal.h> +#include <i2s_stm32f7/stm32_pin_cfg.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct i2s; +struct i2s_cfg; +struct stm32_spi_cfg; + +struct stm32_i2s_pins { + stm32_pin_cfg_t ck_pin; + stm32_pin_cfg_t ws_pin; + stm32_pin_cfg_t sd_pin; + stm32_pin_cfg_t mck_pin; +}; + +#define I2S_PIN(n, port, pin) &(I2S ## n ## _P ## port ## pin) +#define I2S_CK_PIN(n, port, pin) &(I2S ## n ## _CK_P ## port ## pin) +#define I2S_WS_PIN(n, port, pin) &(I2S ## n ## _WS_P ## port ## pin) +#define I2S_SD_PIN(n, port, pin) &(I2S ## n ## _SD_P ## port ## pin) + +struct stm32_dma_cfg { + uint8_t dma_num; + IRQn_Type dma_stream_irq; + DMA_Stream_TypeDef *dma_stream; + uint32_t dma_channel; +}; + +struct i2s_cfg { + uint32_t mode; + uint32_t standard; + uint32_t data_format; + uint32_t sample_rate; + + struct i2s_buffer_pool *pool; + const struct stm32_spi_cfg *spi_cfg; + const struct stm32_dma_cfg *dma_cfg; + struct stm32_i2s_pins pins; +}; + +#define SPI_CFG(n) &(spi ## n ## _cfg) + +struct stm32_i2s { + I2S_HandleTypeDef hi2s; + DMA_HandleTypeDef *hdma_spi; + + struct i2s *i2s; + struct i2s_sample_buffer *dma_buffers[2]; + uint8_t dma_buffer_count; +}; + +#define DMA_CFG(dma, ch, st, name) &(name ## _stream ## st ## _channel ## ch) + +#define DMA_STREAM_DECLARE(dma, ch, st, name) \ + extern const struct stm32_dma_cfg name ## _stream ## st ## _channel ## ch + +DMA_STREAM_DECLARE(1, 0, 0, spi3_rx); +DMA_STREAM_DECLARE(1, 0, 1, spdifrx_dt); +DMA_STREAM_DECLARE(1, 0, 2, spi3_rx); +DMA_STREAM_DECLARE(1, 0, 3, spi2_rx); +DMA_STREAM_DECLARE(1, 0, 4, spi2_tx); +DMA_STREAM_DECLARE(1, 0, 5, spi3_tx); +DMA_STREAM_DECLARE(1, 0, 6, spdifrx_cs); +DMA_STREAM_DECLARE(1, 0, 7, spi3_tx); + +DMA_STREAM_DECLARE(1, 1, 0, i2c1_rx); +DMA_STREAM_DECLARE(1, 1, 1, i2c3_rx); +DMA_STREAM_DECLARE(1, 1, 2, tim7_up); +DMA_STREAM_DECLARE(1, 1, 4, tim7_up); +DMA_STREAM_DECLARE(1, 1, 5, i2c1_rx); +DMA_STREAM_DECLARE(1, 1, 6, i2c1_tx); +DMA_STREAM_DECLARE(1, 1, 7, i2c1_tx); + +DMA_STREAM_DECLARE(1, 2, 0, tim4_ch1); +DMA_STREAM_DECLARE(1, 2, 2, i2c4_rx); +DMA_STREAM_DECLARE(1, 2, 3, tim4_ch2); +DMA_STREAM_DECLARE(1, 2, 5, i2c4_rx); +DMA_STREAM_DECLARE(1, 2, 6, tim4_up); +DMA_STREAM_DECLARE(1, 2, 7, tim4_ch3); + +DMA_STREAM_DECLARE(1, 3, 1, tim2_up); +DMA_STREAM_DECLARE(1, 3, 1, tim2_ch3); +DMA_STREAM_DECLARE(1, 3, 2, i2c3_rx); +DMA_STREAM_DECLARE(1, 3, 4, i2c3_tx); +DMA_STREAM_DECLARE(1, 3, 5, tim2_ch1); +DMA_STREAM_DECLARE(1, 3, 6, tim2_ch2); +DMA_STREAM_DECLARE(1, 3, 6, tim2_ch4); +DMA_STREAM_DECLARE(1, 3, 7, tim2_up); +DMA_STREAM_DECLARE(1, 3, 7, tim2_ch4); + +DMA_STREAM_DECLARE(1, 4, 0, uart5_rx); +DMA_STREAM_DECLARE(1, 4, 1, usart3_rx); +DMA_STREAM_DECLARE(1, 4, 2, uart4_rx); +DMA_STREAM_DECLARE(1, 4, 3, usart3_tx); +DMA_STREAM_DECLARE(1, 4, 4, uart4_tx); +DMA_STREAM_DECLARE(1, 4, 5, usart2_rx); +DMA_STREAM_DECLARE(1, 4, 6, usart2_tx); +DMA_STREAM_DECLARE(1, 4, 7, uart5_tx); + +DMA_STREAM_DECLARE(1, 5, 0, uart8_tx); +DMA_STREAM_DECLARE(1, 5, 1, uart7_tx); +DMA_STREAM_DECLARE(1, 5, 2, tim3_ch4); +DMA_STREAM_DECLARE(1, 5, 2, tim3_up); +DMA_STREAM_DECLARE(1, 5, 3, uart7_rx); +DMA_STREAM_DECLARE(1, 5, 4, tim3_ch1); +DMA_STREAM_DECLARE(1, 5, 4, tim3_trig); +DMA_STREAM_DECLARE(1, 5, 5, tim3_ch2); +DMA_STREAM_DECLARE(1, 5, 6, uart8_rx); +DMA_STREAM_DECLARE(1, 5, 7, tim3_ch3); + +DMA_STREAM_DECLARE(1, 6, 0, tim5_ch3); +DMA_STREAM_DECLARE(1, 6, 0, tim5_up); +DMA_STREAM_DECLARE(1, 6, 1, tim5_ch4); +DMA_STREAM_DECLARE(1, 6, 1, tim5_trig); +DMA_STREAM_DECLARE(1, 6, 2, tim5_ch1); +DMA_STREAM_DECLARE(1, 6, 2, tim3_up); +DMA_STREAM_DECLARE(1, 6, 3, tim5_ch4); +DMA_STREAM_DECLARE(1, 6, 3, tim5_trig); +DMA_STREAM_DECLARE(1, 6, 4, tim5_ch2); +DMA_STREAM_DECLARE(1, 6, 6, tim5_up); + +DMA_STREAM_DECLARE(1, 7, 1, tim6_up); +DMA_STREAM_DECLARE(1, 7, 2, i2c2_rx); +DMA_STREAM_DECLARE(1, 7, 3, i2c2_rx); +DMA_STREAM_DECLARE(1, 7, 4, usart3_tx); +DMA_STREAM_DECLARE(1, 7, 5, dac1); +DMA_STREAM_DECLARE(1, 7, 6, dac2); +DMA_STREAM_DECLARE(1, 7, 7, i2c2_tx); + +DMA_STREAM_DECLARE(1, 8, 0, i2c3_tx); +DMA_STREAM_DECLARE(1, 8, 1, i2c4_rx); +DMA_STREAM_DECLARE(1, 8, 4, i2c2_tx); +DMA_STREAM_DECLARE(1, 8, 6, i2c4_tx); + +DMA_STREAM_DECLARE(1, 9, 1, i2c2_rx); +DMA_STREAM_DECLARE(1, 9, 6, i2c2_tx); + +DMA_STREAM_DECLARE(2, 0, 0, adc1); +DMA_STREAM_DECLARE(2, 0, 1, sai1_a); +DMA_STREAM_DECLARE(2, 0, 2, tim8_ch1); +DMA_STREAM_DECLARE(2, 0, 2, tim8_ch2); +DMA_STREAM_DECLARE(2, 0, 2, tim8_ch3); +DMA_STREAM_DECLARE(2, 0, 3, sai1_a); +DMA_STREAM_DECLARE(2, 0, 4, adc1); +DMA_STREAM_DECLARE(2, 0, 5, sai1_b); +DMA_STREAM_DECLARE(2, 0, 6, tim1_ch1); +DMA_STREAM_DECLARE(2, 0, 6, tim1_ch2); +DMA_STREAM_DECLARE(2, 0, 6, tim1_ch3); +DMA_STREAM_DECLARE(2, 0, 7, sai1_b); + +DMA_STREAM_DECLARE(2, 1, 1, dcmi); +DMA_STREAM_DECLARE(2, 1, 2, adc2); +DMA_STREAM_DECLARE(2, 1, 3, adc2); +DMA_STREAM_DECLARE(2, 1, 4, sai1_b); +DMA_STREAM_DECLARE(2, 1, 5, spi6_tx); +DMA_STREAM_DECLARE(2, 1, 6, spi6_rx); +DMA_STREAM_DECLARE(2, 1, 7, dcmi); + +DMA_STREAM_DECLARE(2, 2, 0, adc3); +DMA_STREAM_DECLARE(2, 2, 1, adc3); +DMA_STREAM_DECLARE(2, 2, 3, spi5_rx); +DMA_STREAM_DECLARE(2, 2, 4, spi5_tx); +DMA_STREAM_DECLARE(2, 2, 5, cryp_out); +DMA_STREAM_DECLARE(2, 2, 6, cryp_in); +DMA_STREAM_DECLARE(2, 2, 7, hash_in); + +DMA_STREAM_DECLARE(2, 3, 0, spi1_rx); +DMA_STREAM_DECLARE(2, 3, 2, spi1_rx); +DMA_STREAM_DECLARE(2, 3, 3, spi1_tx); +DMA_STREAM_DECLARE(2, 3, 4, sai2_a); +DMA_STREAM_DECLARE(2, 3, 5, spi1_tx); +DMA_STREAM_DECLARE(2, 3, 6, sai2_b); +DMA_STREAM_DECLARE(2, 3, 7, quadspi); + +DMA_STREAM_DECLARE(2, 4, 0, spi4_rx); +DMA_STREAM_DECLARE(2, 4, 1, spi4_tx); +DMA_STREAM_DECLARE(2, 4, 2, usart1_rx); +DMA_STREAM_DECLARE(2, 4, 3, sdmmc1); +DMA_STREAM_DECLARE(2, 4, 5, usart1_rx); +DMA_STREAM_DECLARE(2, 4, 6, sdmmc1); +DMA_STREAM_DECLARE(2, 4, 7, usart1_tx); + +DMA_STREAM_DECLARE(2, 5, 1, usart6_rx); +DMA_STREAM_DECLARE(2, 5, 2, usart6_rx); +DMA_STREAM_DECLARE(2, 5, 3, spi4_rx); +DMA_STREAM_DECLARE(2, 5, 4, spi4_tx); +DMA_STREAM_DECLARE(2, 5, 5, spi5_tx); +DMA_STREAM_DECLARE(2, 5, 6, usart6_tx); +DMA_STREAM_DECLARE(2, 5, 7, usart6_tx); + +DMA_STREAM_DECLARE(2, 6, 0, tim1_trig); +DMA_STREAM_DECLARE(2, 6, 1, tim1_ch1); +DMA_STREAM_DECLARE(2, 6, 2, tim1_ch2); +DMA_STREAM_DECLARE(2, 6, 3, tim1_ch1); +DMA_STREAM_DECLARE(2, 6, 4, tim1_ch4); +DMA_STREAM_DECLARE(2, 6, 4, tim1_trig); +DMA_STREAM_DECLARE(2, 6, 4, tim1_com); +DMA_STREAM_DECLARE(2, 6, 5, tim1_up); +DMA_STREAM_DECLARE(2, 6, 6, tim1_ch3); + +DMA_STREAM_DECLARE(2, 7, 1, tim8_up); +DMA_STREAM_DECLARE(2, 7, 2, tim8_ch1); +DMA_STREAM_DECLARE(2, 7, 3, tim8_ch2); +DMA_STREAM_DECLARE(2, 7, 4, tim8_ch3); +DMA_STREAM_DECLARE(2, 7, 5, spi5_rx); +DMA_STREAM_DECLARE(2, 7, 6, spi5_tx); +DMA_STREAM_DECLARE(2, 7, 7, tim8_ch4); +DMA_STREAM_DECLARE(2, 7, 7, tim8_trig); +DMA_STREAM_DECLARE(2, 7, 7, tim8_com); + +DMA_STREAM_DECLARE(2, 8, 0, dfsdm1_flt0); +DMA_STREAM_DECLARE(2, 8, 1, dfsdm1_flt1); +DMA_STREAM_DECLARE(2, 8, 2, dfsdm1_flt2); +DMA_STREAM_DECLARE(2, 8, 3, dfsdm1_flt3); +DMA_STREAM_DECLARE(2, 8, 4, dfsdm1_flt0); +DMA_STREAM_DECLARE(2, 8, 5, dfsdm1_flt1); +DMA_STREAM_DECLARE(2, 8, 6, dfsdm1_flt2); +DMA_STREAM_DECLARE(2, 8, 7, dfsdm1_flt3); + +DMA_STREAM_DECLARE(2, 9, 0, jpeg_in); +DMA_STREAM_DECLARE(2, 9, 1, jpeg_out); +DMA_STREAM_DECLARE(2, 9, 2, spi4_tx); +DMA_STREAM_DECLARE(2, 9, 3, jpeg_in); +DMA_STREAM_DECLARE(2, 9, 4, jpeg_out); +DMA_STREAM_DECLARE(2, 9, 5, spi5_rx); + +DMA_STREAM_DECLARE(2, 10, 0, sai1_b); +DMA_STREAM_DECLARE(2, 10, 1, sai2_b); +DMA_STREAM_DECLARE(2, 10, 2, sai2_a); +DMA_STREAM_DECLARE(2, 10, 6, sai1_a); + +DMA_STREAM_DECLARE(2, 11, 0, sdmmc2); +DMA_STREAM_DECLARE(2, 11, 2, suadspi); +DMA_STREAM_DECLARE(2, 11, 5, sdmmc2); + +#define SPI_CFG_DECLARE(n) \ + extern struct stm32_spi_cfg spi ## n ## _cfg; + +SPI_CFG_DECLARE(1); +SPI_CFG_DECLARE(2); +SPI_CFG_DECLARE(3); +SPI_CFG_DECLARE(4); +SPI_CFG_DECLARE(5); + +#define I2S_PIN_DECLARE(n, port, pin) \ + extern const struct stm32_pin_cfg I2S ## n ## _P ## port ## pin; +#define I2S_CK_PIN_DECLARE(n, port, pin) \ + extern const struct stm32_pin_cfg I2S ## n ## _CK_P ## port ## pin; +#define I2S_WS_PIN_DECLARE(n, port, pin) \ + extern const struct stm32_pin_cfg I2S ## n ## _WS_P ## port ## pin; +#define I2S_SD_PIN_DECLARE(n, port, pin) \ + extern const struct stm32_pin_cfg I2S ## n ## _SD_P ## port ## pin; + + +/* I2S1 Possible CK pins */ +I2S_CK_PIN_DECLARE(1, A, 5); +I2S_CK_PIN_DECLARE(1, B, 3); +I2S_CK_PIN_DECLARE(1, G, 11); + +/* I2S1 possible WS pins */ +I2S_WS_PIN_DECLARE(1, A, 4); +I2S_WS_PIN_DECLARE(1, A, 15); +I2S_WS_PIN_DECLARE(1, G, 10); + +/* I2S1 possible SD pins */ +I2S_SD_PIN_DECLARE(1, B, 5); +I2S_SD_PIN_DECLARE(1, A, 7); +I2S_SD_PIN_DECLARE(1, D, 7); + +/* I2S1 possible MCK pins */ +I2S_SD_PIN_DECLARE(1, C, 4); + +/* I2S2 Possible CKIN pins */ +I2S_PIN_DECLARE(2, C, 9); + +/* I2S2 Possible MCK pins */ +#ifdef GPIO_AF5_SPI2 +I2S_PIN_DECLARE(2, C, 6); +#endif + +/* I2S2 Possible CK pins */ +I2S_CK_PIN_DECLARE(2, A, 9); +I2S_CK_PIN_DECLARE(2, A, 12); +I2S_CK_PIN_DECLARE(2, B, 10); +I2S_CK_PIN_DECLARE(2, B, 13); +I2S_CK_PIN_DECLARE(2, D, 3); +I2S_CK_PIN_DECLARE(2, I, 1); + +/* I2S2 possible WS pins */ +I2S_WS_PIN_DECLARE(2, A, 11); +I2S_WS_PIN_DECLARE(2, B, 4); +I2S_WS_PIN_DECLARE(2, B, 9); +I2S_WS_PIN_DECLARE(2, B, 12); +I2S_WS_PIN_DECLARE(2, I, 0); + +/* I2S2 possible SD pins */ +I2S_SD_PIN_DECLARE(2, B, 15); +I2S_SD_PIN_DECLARE(2, C, 1); +I2S_SD_PIN_DECLARE(2, C, 3); +I2S_SD_PIN_DECLARE(2, I, 3); + +/* I2S3 possible CK pins */ +I2S_CK_PIN_DECLARE(3, B, 3); +I2S_CK_PIN_DECLARE(3, C, 10); + +/* I2S3 possible WS pins */ +I2S_WS_PIN_DECLARE(3, A, 4); +I2S_WS_PIN_DECLARE(3, A, 15); + +/* I2S3 possible SD pins */ +I2S_SD_PIN_DECLARE(3, B, 2); +I2S_SD_PIN_DECLARE(3, B, 5); +I2S_SD_PIN_DECLARE(3, C, 12); +#ifdef GPIO_AF5_SPI3 +I2S_SD_PIN_DECLARE(3, D, 6); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _I2S_STM32_H */ diff --git a/hw/drivers/i2s/i2s_stm32f7/include/i2s_stm32f7/stm32_pin_cfg.h b/hw/drivers/i2s/i2s_stm32f7/include/i2s_stm32f7/stm32_pin_cfg.h new file mode 100644 index 000000000..10823f420 --- /dev/null +++ b/hw/drivers/i2s/i2s_stm32f7/include/i2s_stm32f7/stm32_pin_cfg.h @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _STM32_PIN_CFG_H +#define _STM32_PIN_CFG_H + +#include <stdint.h> +#include <mcu/stm32_hal.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct stm32_pin_cfg { + int8_t pin; + GPIO_InitTypeDef hal_init; +}; + +typedef const struct stm32_pin_cfg *stm32_pin_cfg_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _STM32_PIN_CFG_H */ diff --git a/hw/drivers/i2s/i2s_stm32f7/pkg.yml b/hw/drivers/i2s/i2s_stm32f7/pkg.yml new file mode 100644 index 000000000..e68d1e0cf --- /dev/null +++ b/hw/drivers/i2s/i2s_stm32f7/pkg.yml @@ -0,0 +1,29 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: hw/drivers/i2s/i2s_stm32f7 +pkg.description: I2S driver for STM32 F7xx devices +pkg.author: "Apache Mynewt <d...@mynewt.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.apis: + - I2S_HW_IMPL +pkg.deps: + - "@apache-mynewt-core/hw/drivers/i2s" diff --git a/hw/drivers/i2s/i2s_stm32f7/src/i2s_stm32f7.c b/hw/drivers/i2s/i2s_stm32f7/src/i2s_stm32f7.c new file mode 100644 index 000000000..54ec94883 --- /dev/null +++ b/hw/drivers/i2s/i2s_stm32f7/src/i2s_stm32f7.c @@ -0,0 +1,971 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <os/mynewt.h> +#include <mcu/mcu.h> +#include <mcu/stm32_hal.h> +#include <bsp/bsp.h> +#include <i2s/i2s.h> +#include <i2s/i2s_driver.h> +#include <i2s_stm32f7/i2s_stm32f7.h> + +struct stm32_spi_cfg { + uint8_t spi_num; + SPI_TypeDef *spi; + IRQn_Type i2s_irq; + struct stm32_i2s *driver_data; + DMA_HandleTypeDef *hdma_spi; + void (*irq_handler)(void); + void (*i2s_dma_handler)(void); + void (*enable_clock)(bool enable); +}; + +static struct stm32_i2s stm32_i2s1; +static struct stm32_i2s stm32_i2s2; +static struct stm32_i2s stm32_i2s3; + +void +i2s1_irq_handler(void) +{ + os_trace_isr_enter(); + + HAL_I2S_IRQHandler(&stm32_i2s1.hi2s); + + os_trace_isr_exit(); +} + +void +i2s2_irq_handler(void) +{ + os_trace_isr_enter(); + + HAL_I2S_IRQHandler(&stm32_i2s2.hi2s); + + os_trace_isr_exit(); +} + +void +i2s3_irq_handler(void) +{ + os_trace_isr_enter(); + + HAL_I2S_IRQHandler(&stm32_i2s3.hi2s); + + os_trace_isr_exit(); +} + +static void +i2s1_clock_enable(bool enable) +{ +#ifdef SPI1 + if (enable) { + __HAL_RCC_SPI1_CLK_ENABLE(); + } else { + __HAL_RCC_SPI1_CLK_DISABLE(); + } +#endif +} + +static void +i2s2_clock_enable(bool enable) +{ +#ifdef SPI2 + if (enable) { + __HAL_RCC_SPI2_CLK_ENABLE(); + } else { + __HAL_RCC_SPI2_CLK_DISABLE(); + } +#endif +} + +static void +i2s3_clock_enable(bool enable) +{ +#ifdef SPI3 + if (enable) { + __HAL_RCC_SPI3_CLK_ENABLE(); + } else { + __HAL_RCC_SPI3_CLK_DISABLE(); + } +#endif +} + +static void +i2s1_dma_stream_irq_handler(void) +{ + os_trace_isr_enter(); + + HAL_DMA_IRQHandler(stm32_i2s1.hdma_spi); + + os_trace_isr_exit(); +} + +static void +i2s2_dma_stream_irq_handler(void) +{ + os_trace_isr_enter(); + + HAL_DMA_IRQHandler(stm32_i2s2.hdma_spi); + + os_trace_isr_exit(); +} + +static void +i2s3_dma_stream_irq_handler(void) +{ + os_trace_isr_enter(); + + HAL_DMA_IRQHandler(stm32_i2s3.hdma_spi); + + os_trace_isr_exit(); +} + +static void +i2s_init_interrupts(const struct i2s_cfg *cfg) +{ + NVIC_SetVector(cfg->dma_cfg->dma_stream_irq, (uint32_t)cfg->spi_cfg->i2s_dma_handler); + HAL_NVIC_SetPriority(cfg->dma_cfg->dma_stream_irq, 5, 0); + HAL_NVIC_EnableIRQ(cfg->dma_cfg->dma_stream_irq); + + /* I2S1 interrupt Init */ + NVIC_SetVector(cfg->spi_cfg->i2s_irq, (uint32_t)cfg->spi_cfg->irq_handler); + HAL_NVIC_SetPriority(cfg->spi_cfg->i2s_irq, 5, 0); + HAL_NVIC_EnableIRQ(cfg->spi_cfg->i2s_irq); +} + +static void +i2s_init_pins(struct stm32_i2s_pins *pins) +{ + hal_gpio_init_stm(pins->ck_pin->pin, (GPIO_InitTypeDef *)&pins->ck_pin->hal_init); + hal_gpio_init_stm(pins->ws_pin->pin, (GPIO_InitTypeDef *)&pins->ws_pin->hal_init); + hal_gpio_init_stm(pins->sd_pin->pin, (GPIO_InitTypeDef *)&pins->sd_pin->hal_init); + if (pins->mck_pin) { + hal_gpio_init_stm(pins->mck_pin->pin, (GPIO_InitTypeDef *)&pins->mck_pin->hal_init); + } +} + +static int +stm32_i2s_init(struct i2s *i2s, const struct i2s_cfg *cfg) +{ + int rc = 0; + struct stm32_i2s *stm32_i2s; + + i2s->direction = ((cfg->mode == I2S_MODE_MASTER_TX) || + (cfg->mode == I2S_MODE_SLAVE_TX)) ? I2S_OUT : I2S_IN; + + if (cfg->data_format == I2S_DATAFORMAT_16B_EXTENDED || + cfg->data_format == I2S_DATAFORMAT_16B) { + i2s->sample_size_in_bytes = 2; + } else { + i2s->sample_size_in_bytes = 4; + } + + rc = i2s_init(i2s, cfg->pool); + + if (rc != OS_OK) { + goto end; + } + + stm32_i2s = cfg->spi_cfg->driver_data; + stm32_i2s->i2s = i2s; + stm32_i2s->hdma_spi = cfg->spi_cfg->hdma_spi; + + i2s->sample_rate = cfg->sample_rate; + i2s->driver_data = stm32_i2s; + + i2s_init_pins((struct stm32_i2s_pins *)&cfg->pins); + + cfg->spi_cfg->enable_clock(true); + + stm32_i2s->hi2s.Instance = cfg->spi_cfg->spi; + stm32_i2s->hi2s.Init.Mode = cfg->mode; + stm32_i2s->hi2s.Init.Standard = cfg->standard; + stm32_i2s->hi2s.Init.DataFormat = cfg->data_format; + stm32_i2s->hi2s.Init.MCLKOutput = (cfg->pins.mck_pin) ? I2S_MCLKOUTPUT_ENABLE : I2S_MCLKOUTPUT_DISABLE; + stm32_i2s->hi2s.Init.AudioFreq = cfg->sample_rate; + stm32_i2s->hi2s.Init.CPOL = I2S_CPOL_LOW; + stm32_i2s->hi2s.Init.ClockSource = I2S_CLOCK_PLL; + + if (cfg->dma_cfg->dma_num == 1) { + __HAL_RCC_DMA1_CLK_ENABLE(); + } else { +#ifdef __HAL_RCC_DMA2_CLK_DISABLE + __HAL_RCC_DMA2_CLK_ENABLE(); +#endif + } + + stm32_i2s->hdma_spi->Instance = cfg->dma_cfg->dma_stream; + stm32_i2s->hdma_spi->Init.Channel = cfg->dma_cfg->dma_channel; + if (cfg->mode == I2S_MODE_MASTER_TX || cfg->mode == I2S_MODE_SLAVE_TX) { + stm32_i2s->hdma_spi->Init.Direction = DMA_MEMORY_TO_PERIPH; + } else { + stm32_i2s->hdma_spi->Init.Direction = DMA_PERIPH_TO_MEMORY; + } + stm32_i2s->hdma_spi->Init.PeriphInc = DMA_PINC_DISABLE; + stm32_i2s->hdma_spi->Init.MemInc = DMA_MINC_ENABLE; + stm32_i2s->hdma_spi->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + stm32_i2s->hdma_spi->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; + stm32_i2s->hdma_spi->Init.Mode = DMA_NORMAL; + stm32_i2s->hdma_spi->Init.Priority = DMA_PRIORITY_LOW; + stm32_i2s->hdma_spi->Init.FIFOMode = DMA_FIFOMODE_DISABLE; + + if (cfg->mode == I2S_MODE_MASTER_TX || cfg->mode == I2S_MODE_SLAVE_TX) { + __HAL_LINKDMA(&stm32_i2s->hi2s, hdmatx, *stm32_i2s->hdma_spi); + } else { + __HAL_LINKDMA(&stm32_i2s->hi2s, hdmarx, *stm32_i2s->hdma_spi); + } + + i2s_init_interrupts(cfg); +end: + return rc; +} + +int +i2s_create(struct i2s *i2s, const char *name, const struct i2s_cfg *cfg) +{ + return os_dev_create(&i2s->dev, name, OS_DEV_INIT_PRIMARY, + 100, (os_dev_init_func_t)stm32_i2s_init, (void *)cfg); +} + +int +i2s_driver_stop(struct i2s *i2s) +{ + struct stm32_i2s *i2s_data = (struct stm32_i2s *)i2s->driver_data; + struct i2s_sample_buffer *buffer; + + HAL_I2S_DMAStop(&i2s_data->hi2s); + if (i2s->state == I2S_STATE_RUNNING && i2s->direction == I2S_OUT) { + /* + * When DMA is stopped and then I2S peripheral is stopped, it + * may happen that DMA put some data already in SPI data buffer. + * In that case single sample may be in the I2S output buffer. + * If this happens next transmission will swap channels due to + * one extra sample already present. + * To avoid this just wait till all samples are gone. + */ + if (0 == (i2s_data->hi2s.Instance->SR & SPI_SR_TXE_Msk)) { + __HAL_I2S_ENABLE(&i2s_data->hi2s); + while (0 == (i2s_data->hi2s.Instance->SR & SPI_SR_TXE_Msk)) + ; + __HAL_I2S_DISABLE(&i2s_data->hi2s); + } + } + + assert(i2s_data->hi2s.State == HAL_I2S_STATE_READY); + if (i2s_data->dma_buffer_count > 0) { + buffer = i2s_data->dma_buffers[0]; + i2s_data->dma_buffers[0] = NULL; + i2s_driver_buffer_put(i2s, buffer); + if (i2s_data->dma_buffer_count > 1) { + buffer = i2s_data->dma_buffers[1]; + i2s_driver_buffer_put(i2s, buffer); + } + i2s_data->dma_buffers[1] = NULL; + i2s_data->dma_buffer_count = 0; + } + HAL_I2S_DeInit(&i2s_data->hi2s); + HAL_DMA_DeInit(i2s_data->hdma_spi); + return 0; +} + +static void +i2s_dma_complete(DMA_HandleTypeDef *hdma, HAL_DMA_MemoryTypeDef memory) +{ + I2S_HandleTypeDef *hi2s = (I2S_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 */ + struct stm32_i2s *i2s_data = (struct stm32_i2s *)hi2s; + struct i2s *i2s = i2s_data->i2s; + struct i2s_sample_buffer *processed_buffer = NULL; + const int ix = (int)memory; + + if (i2s_data->dma_buffer_count == 2) { + /* There were already two different memory buffers, one can be returned to the user */ + processed_buffer = i2s_data->dma_buffers[ix]; + i2s_data->dma_buffers[ix] = i2s_driver_buffer_get(i2s); + /* If there are not more waiting buffers, use same buffer again */ + if (i2s_data->dma_buffers[ix] == NULL) { + i2s_data->dma_buffer_count = 1; + i2s_data->dma_buffers[ix] = i2s_data->dma_buffers[ix ^ 1]; + } + HAL_DMAEx_ChangeMemory(hdma, (uint32_t)i2s_data->dma_buffers[ix]->sample_data, memory); + processed_buffer->sample_count = processed_buffer->capacity; + i2s_driver_buffer_put(i2s, processed_buffer); + } +} + +static void +i2s_dma_m0_complete(DMA_HandleTypeDef *hdma) +{ + i2s_dma_complete(hdma, MEMORY0); +} + +static void +i2s_dma_m1_complete(DMA_HandleTypeDef *hdma) +{ + i2s_dma_complete(hdma, MEMORY1); +} + +/* + * Following functions: + * i2s_dma_error(), i2s_receive_start_dma() i2s_transmit_start_dma(), i2s_transmit_receive_dma() + * are close copies of ST HAL functions with exception that they program DMA in double buffering + * mode. Style and naming is in most part unchanged. + */ +static void +i2s_dma_error(DMA_HandleTypeDef *hdma) +{ + I2S_HandleTypeDef *hi2s = (I2S_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 */ + + /* Disable Rx and Tx DMA Request */ + CLEAR_BIT(hi2s->Instance->CR2, (SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN)); + hi2s->TxXferCount = 0U; + hi2s->RxXferCount = 0U; + + hi2s->State = HAL_I2S_STATE_READY; + + /* Set the error code and execute error callback */ + SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_DMA); + /* Call user error callback */ +#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1U) + hi2s->ErrorCallback(hi2s); +#else + HAL_I2S_ErrorCallback(hi2s); +#endif /* USE_HAL_I2S_REGISTER_CALLBACKS */ +} + +static HAL_StatusTypeDef +i2s_receive_start_dma(I2S_HandleTypeDef *hi2s, uint16_t *buf0, uint16_t *buf1, uint16_t sample_count) +{ + uint32_t tmpreg_cfgr; + uint16_t size; + + if ((buf0 == NULL) || (buf1 == NULL) || (sample_count == 0)) { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hi2s); + + if (hi2s->State != HAL_I2S_STATE_READY) { + __HAL_UNLOCK(hi2s); + return HAL_BUSY; + } + + /* Set state and reset error code */ + hi2s->State = HAL_I2S_STATE_BUSY_RX; + hi2s->ErrorCode = HAL_I2S_ERROR_NONE; + hi2s->pRxBuffPtr = buf0; + + tmpreg_cfgr = hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN); + + if ((tmpreg_cfgr == I2S_DATAFORMAT_24B) || (tmpreg_cfgr == I2S_DATAFORMAT_32B)) { + size = sample_count << 1U; + } else { + size = sample_count; + } + + /* Half transfer callback not needed */ + hi2s->hdmarx->XferHalfCpltCallback = NULL; + + /* Set the I2S Rx DMA transfer complete callback */ + hi2s->hdmarx->XferCpltCallback = i2s_dma_m0_complete; + hi2s->hdmarx->XferM1CpltCallback = i2s_dma_m1_complete; + + /* Set the DMA error callback */ + hi2s->hdmarx->XferErrorCallback = i2s_dma_error; + + /* Check if Master Receiver mode is selected */ + if ((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_MASTER_RX) { + /* + * Clear the Overrun Flag by a read operation to the SPI_DR register followed by a read + * access to the SPI_SR register. + */ + __HAL_I2S_CLEAR_OVRFLAG(hi2s); + } + + hi2s->hdmarx->Instance->CR &= ~DMA_SxCR_CT_Msk; + /* Enable the Rx DMA Stream/Channel */ + if (HAL_OK != HAL_DMAEx_MultiBufferStart_IT(hi2s->hdmarx, (uint32_t)&hi2s->Instance->DR, + (uint32_t)buf0, (uint32_t)buf1, size)) { + /* Update SPI error code */ + SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_DMA); + hi2s->State = HAL_I2S_STATE_READY; + + __HAL_UNLOCK(hi2s); + return HAL_ERROR; + } + + /* Check if the I2S is already enabled */ + if (HAL_IS_BIT_CLR(hi2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE)) { + /* Enable I2S peripheral */ + __HAL_I2S_ENABLE(hi2s); + } + + /* Check if the I2S Rx request is already enabled */ + if (HAL_IS_BIT_CLR(hi2s->Instance->CR2, SPI_CR2_RXDMAEN)) { + /* Enable Rx DMA Request */ + SET_BIT(hi2s->Instance->CR2, SPI_CR2_RXDMAEN); + } + + __HAL_UNLOCK(hi2s); + return HAL_OK; +} + +static HAL_StatusTypeDef +i2s_transmit_start_dma(I2S_HandleTypeDef *hi2s, uint16_t *buf0, uint16_t *buf1, uint16_t sample_count) +{ + uint32_t tmpreg_cfgr; + uint16_t size; + + if ((buf0 == NULL) || (buf1 == NULL) || (sample_count == 0)) { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hi2s); + + if (hi2s->State != HAL_I2S_STATE_READY) { + __HAL_UNLOCK(hi2s); + return HAL_BUSY; + } + + /* Set state and reset error code */ + hi2s->State = HAL_I2S_STATE_BUSY_TX; + hi2s->ErrorCode = HAL_I2S_ERROR_NONE; + hi2s->pTxBuffPtr = buf0; + + tmpreg_cfgr = hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN); + + if ((tmpreg_cfgr == I2S_DATAFORMAT_24B) || (tmpreg_cfgr == I2S_DATAFORMAT_32B)) { + size = sample_count << 1U; + } else { + size = sample_count; + } + + /* Set the I2S Tx DMA Half transfer complete callback */ + hi2s->hdmatx->XferHalfCpltCallback = NULL; + + /* Set the I2S Tx DMA transfer complete callback */ + hi2s->hdmatx->XferCpltCallback = i2s_dma_m0_complete; + hi2s->hdmatx->XferM1CpltCallback = i2s_dma_m1_complete; + + /* Set the DMA error callback */ + hi2s->hdmatx->XferErrorCallback = i2s_dma_error; + + hi2s->hdmatx->Instance->CR &= ~DMA_SxCR_CT_Msk; + /* Enable the Tx DMA Stream/Channel */ + if (HAL_OK != HAL_DMAEx_MultiBufferStart_IT(hi2s->hdmatx, (uint32_t)buf0, (uint32_t)&hi2s->Instance->DR, + (uint32_t)buf1, size)) { + /* Update SPI error code */ + SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_DMA); + hi2s->State = HAL_I2S_STATE_READY; + + __HAL_UNLOCK(hi2s); + return HAL_ERROR; + } + + /* Check if the I2S is already enabled */ + if (HAL_IS_BIT_CLR(hi2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE)) { + /* Enable I2S peripheral */ + __HAL_I2S_ENABLE(hi2s); + } + + /* Check if the I2S Rx request is already enabled */ + if (HAL_IS_BIT_CLR(hi2s->Instance->CR2, SPI_CR2_TXDMAEN)) { + /* Enable Rx DMA Request */ + SET_BIT(hi2s->Instance->CR2, SPI_CR2_TXDMAEN); + } + + __HAL_UNLOCK(hi2s); + return HAL_OK; +} + +int +i2s_driver_start(struct i2s *i2s) +{ + int rc = 0; + struct stm32_i2s *i2s_data = (struct stm32_i2s *)i2s->driver_data; + + switch (i2s_data->hi2s.State) { + case HAL_I2S_STATE_RESET: + if (i2s->sample_rate) { + i2s_data->hi2s.Init.AudioFreq = i2s->sample_rate; + } + if (HAL_I2S_Init(&i2s_data->hi2s) != HAL_OK) { + rc = SYS_EUNKNOWN; + break; + } + if (HAL_DMA_Init(i2s_data->hdma_spi) != HAL_OK) { + (void)HAL_I2S_DeInit(&i2s_data->hi2s); + rc = SYS_EUNKNOWN; + break; + } + /* Fallthrough */ + case HAL_I2S_STATE_READY: + assert(i2s_data->dma_buffers[0] == NULL); + assert(i2s_data->dma_buffers[1] == NULL); + assert(i2s_data->dma_buffer_count == 0); + i2s_data->dma_buffers[0] = i2s_driver_buffer_get(i2s); + i2s_data->dma_buffers[1] = i2s_driver_buffer_get(i2s); + if (i2s_data->dma_buffers[0] == NULL) { + i2s->state = I2S_STATE_OUT_OF_BUFFERS; + rc = I2S_ERR_NO_BUFFER; + break; + } + if (i2s_data->dma_buffers[1] == NULL) { + i2s_data->dma_buffers[1] = i2s_data->dma_buffers[0]; + i2s_data->dma_buffer_count = 1; + } else { + i2s_data->dma_buffer_count = 2; + } + i2s->state = I2S_STATE_RUNNING; + if (i2s->direction == I2S_IN) { + i2s_data->dma_buffers[0]->sample_count = i2s_data->dma_buffers[0]->capacity; + assert(i2s_data->dma_buffers[0]->capacity == i2s_data->dma_buffers[1]->capacity); + i2s_receive_start_dma(&i2s_data->hi2s, i2s_data->dma_buffers[0]->sample_data, + i2s_data->dma_buffers[1]->sample_data, i2s_data->dma_buffers[0]->sample_count); + } else if (i2s->direction == I2S_OUT) { + i2s_transmit_start_dma(&i2s_data->hi2s, + i2s_data->dma_buffers[0]->sample_data, + i2s_data->dma_buffers[1]->sample_data, + i2s_data->dma_buffers[0]->sample_count); + } + break; + case HAL_I2S_STATE_BUSY: + case HAL_I2S_STATE_BUSY_RX: + case HAL_I2S_STATE_BUSY_TX: + break; + default: + rc = I2S_ERR_INTERNAL; + } + return rc; +} + +void +i2s_driver_buffer_queued(struct i2s *i2s) +{ + struct stm32_i2s *i2s_data = (struct stm32_i2s *)i2s->driver_data; + struct i2s_sample_buffer *next_buffer; + int sr; + int inactive_memory_buffer_ix; + uint32_t sample_buffer_addr; + + if (i2s->state != I2S_STATE_RUNNING) { + return; + } + OS_ENTER_CRITICAL(sr); + switch (i2s_data->dma_buffer_count) { + case 0: + i2s_data->dma_buffers[0] = i2s_driver_buffer_get(i2s); + i2s_data->dma_buffer_count = 1; + break; + case 1: + next_buffer = i2s_driver_buffer_get(i2s); + if ((i2s_data->hdma_spi->Instance->CR & DMA_SxCR_EN) == 0) { + i2s_data->dma_buffers[1] = next_buffer; + } else { + sample_buffer_addr = (uint32_t)next_buffer->sample_data; + /* DMA is active with just one buffer, inactive buffer needs to be changed. */ + inactive_memory_buffer_ix = (i2s_data->hdma_spi->Instance->CR & DMA_SxCR_CT_Msk) ? 0 : 1; + HAL_DMAEx_ChangeMemory(i2s_data->hdma_spi, sample_buffer_addr, + inactive_memory_buffer_ix ? MEMORY1 : MEMORY0); + if ((i2s_data->hdma_spi->Instance->CR & DMA_SxCR_EN_Msk) == 0) { + /* + * There was race between checking current buffer and settings next. + * In this case M1AR or M0AR was write protected and write did not succeeded, + * Just write the other memory address. + */ + inactive_memory_buffer_ix ^= 1; + HAL_DMAEx_ChangeMemory(i2s_data->hdma_spi, sample_buffer_addr, + inactive_memory_buffer_ix ? MEMORY1 : MEMORY0); + + /* Writing to MxAR that was used stopped transfer with errors, make it continue */ + __HAL_DMA_CLEAR_FLAG(i2s_data->hdma_spi, + (DMA_FLAG_FEIF0_4 | DMA_FLAG_DMEIF0_4 | + DMA_FLAG_TEIF0_4 | DMA_FLAG_HTIF0_4 | + DMA_FLAG_TCIF0_4) << i2s_data->hdma_spi->StreamIndex); + i2s_data->hdma_spi->Instance->CR |= DMA_SxCR_EN; + } + i2s_data->dma_buffers[inactive_memory_buffer_ix] = next_buffer; + } + i2s_data->dma_buffer_count = 2; + break; + default: + break; + } + OS_EXIT_CRITICAL(sr); +} + +int +i2s_driver_suspend(struct i2s *i2s, os_time_t timeout, int arg) +{ + return OS_OK; +} + +int +i2s_driver_resume(struct i2s *i2s) +{ + return OS_OK; +} + +bool +i2s_out_is_active(struct i2s *i2s) +{ + struct stm32_i2s *i2s_data = (struct stm32_i2s *)i2s->driver_data; + return READ_BIT(i2s_data->hi2s.Instance->I2SCFGR, SPI_I2SCFGR_I2SE) != 0; +} + +#define I2S_PIN_DEFINE(n, po, pi, af) \ + const struct stm32_pin_cfg I2S ## n ## _P ## po ## pi = { \ + .pin = MCU_GPIO_PORT ## po(pi), \ + .hal_init = { \ + .Pin = GPIO_PIN_ ## pi, \ + .Mode = GPIO_MODE_AF_PP, \ + .Pull = GPIO_NOPULL, \ + .Speed = GPIO_SPEED_FREQ_LOW, \ + .Alternate = af, \ + } \ + } + +#define I2S_CK_PIN_DEFINE(n, po, pi, af) \ + const struct stm32_pin_cfg I2S ## n ## _CK_P ## po ## pi = { \ + .pin = MCU_GPIO_PORT ## po(pi), \ + .hal_init = { \ + .Pin = GPIO_PIN_ ## pi, \ + .Mode = GPIO_MODE_AF_PP, \ + .Pull = GPIO_NOPULL, \ + .Speed = GPIO_SPEED_FREQ_LOW, \ + .Alternate = af, \ + } \ + } + +#define I2S_WS_PIN_DEFINE(n, po, pi, af) \ + const struct stm32_pin_cfg I2S ## n ## _WS_P ## po ## pi = { \ + .pin = MCU_GPIO_PORT ## po(pi), \ + .hal_init = { \ + .Pin = GPIO_PIN_ ## pi, \ + .Mode = GPIO_MODE_AF_PP, \ + .Pull = GPIO_NOPULL, \ + .Speed = GPIO_SPEED_FREQ_LOW, \ + .Alternate = af, \ + } \ + } + +#define I2S_SD_PIN_DEFINE(n, po, pi, af) \ + const struct stm32_pin_cfg I2S ## n ## _SD_P ## po ## pi = { \ + .pin = MCU_GPIO_PORT ## po(pi), \ + .hal_init = { \ + .Pin = GPIO_PIN_ ## pi, \ + .Mode = GPIO_MODE_AF_PP, \ + .Pull = GPIO_NOPULL, \ + .Speed = GPIO_SPEED_FREQ_LOW, \ + .Alternate = af, \ + } \ + } + +/* I2S1 Possible CK pins */ +I2S_CK_PIN_DEFINE(1, A, 5, GPIO_AF5_SPI1); +I2S_CK_PIN_DEFINE(1, B, 3, GPIO_AF5_SPI1); +I2S_CK_PIN_DEFINE(1, G, 11, GPIO_AF5_SPI1); + +/* I2S1 possible WS pins */ +I2S_WS_PIN_DEFINE(1, A, 4, GPIO_AF5_SPI1); +I2S_WS_PIN_DEFINE(1, A, 15, GPIO_AF5_SPI1); +I2S_WS_PIN_DEFINE(1, G, 10, GPIO_AF5_SPI1); + +/* I2S1 possible SD pins */ +I2S_SD_PIN_DEFINE(1, B, 5, GPIO_AF5_SPI1); +I2S_SD_PIN_DEFINE(1, A, 7, GPIO_AF5_SPI1); +I2S_SD_PIN_DEFINE(1, D, 7, GPIO_AF5_SPI1); + +/* I2S1 possible MCK pins */ +I2S_SD_PIN_DEFINE(1, C, 4, GPIO_AF5_SPI1); + +/* I2S2 Possible CKIN pins */ +I2S_PIN_DEFINE(2, C, 9, GPIO_AF5_SPI2); + +/* I2S2 Possible MCK pins */ +#ifdef GPIO_AF5_SPI2 +I2S_PIN_DEFINE(2, C, 6, GPIO_AF5_SPI2); +#endif + +/* I2S2 Possible CK pins */ +I2S_CK_PIN_DEFINE(2, A, 9, GPIO_AF5_SPI2); +I2S_CK_PIN_DEFINE(2, A, 12, GPIO_AF5_SPI2); +I2S_CK_PIN_DEFINE(2, B, 10, GPIO_AF5_SPI2); +I2S_CK_PIN_DEFINE(2, B, 13, GPIO_AF5_SPI2); +I2S_CK_PIN_DEFINE(2, D, 3, GPIO_AF5_SPI2); +I2S_CK_PIN_DEFINE(2, I, 1, GPIO_AF5_SPI2); + +/* I2S2 possible WS pins */ +I2S_WS_PIN_DEFINE(2, A, 11, GPIO_AF5_SPI2); +I2S_WS_PIN_DEFINE(2, B, 4, GPIO_AF7_SPI2); +I2S_WS_PIN_DEFINE(2, B, 9, GPIO_AF5_SPI2); +I2S_WS_PIN_DEFINE(2, B, 12, GPIO_AF5_SPI2); +I2S_WS_PIN_DEFINE(2, I, 0, GPIO_AF5_SPI2); + +/* I2S2 possible SD pins */ +I2S_SD_PIN_DEFINE(2, B, 15, GPIO_AF5_SPI2); +I2S_SD_PIN_DEFINE(2, C, 1, GPIO_AF5_SPI2); +I2S_SD_PIN_DEFINE(2, C, 3, GPIO_AF5_SPI2); +I2S_SD_PIN_DEFINE(2, I, 3, GPIO_AF5_SPI2); + +/* I2S3 possible CK pins */ +I2S_CK_PIN_DEFINE(3, B, 3, GPIO_AF6_SPI3); +I2S_CK_PIN_DEFINE(3, C, 10, GPIO_AF6_SPI3); + +/* I2S3 possible WS pins */ +I2S_WS_PIN_DEFINE(3, A, 4, GPIO_AF6_SPI3); +I2S_WS_PIN_DEFINE(3, A, 15, GPIO_AF6_SPI3); + +/* I2S3 possible SD pins */ +I2S_SD_PIN_DEFINE(3, B, 2, GPIO_AF6_SPI3); +I2S_SD_PIN_DEFINE(3, B, 5, GPIO_AF6_SPI3); +I2S_SD_PIN_DEFINE(3, C, 12, GPIO_AF6_SPI3); +#ifdef GPIO_AF5_SPI3 +I2S_SD_PIN_DEFINE(3, D, 6, GPIO_AF5_SPI3); +#endif + +/* I2S3 possible MCK pins */ +I2S_PIN_DEFINE(3, C, 7, GPIO_AF6_SPI3); + +#define DMA_STREAM_DEFINE(dma, ch, st, name) \ + const struct stm32_dma_cfg name ## _stream ## st ## _channel ## ch = { \ + dma, \ + DMA ## dma ## _Stream ## st ## _IRQn, \ + DMA ## dma ## _Stream ## st, \ + DMA_CHANNEL_ ## ch, \ + } + +DMA_STREAM_DEFINE(1, 0, 0, spi3_rx); +DMA_STREAM_DEFINE(1, 0, 1, spdifrx_dt); +DMA_STREAM_DEFINE(1, 0, 2, spi3_rx); +DMA_STREAM_DEFINE(1, 0, 3, spi2_rx); +DMA_STREAM_DEFINE(1, 0, 4, spi2_tx); +DMA_STREAM_DEFINE(1, 0, 5, spi3_tx); +DMA_STREAM_DEFINE(1, 0, 6, spdifrx_cs); +DMA_STREAM_DEFINE(1, 0, 7, spi3_tx); + +DMA_STREAM_DEFINE(1, 1, 0, i2c1_rx); +DMA_STREAM_DEFINE(1, 1, 1, i2c3_rx); +DMA_STREAM_DEFINE(1, 1, 2, tim7_up); +DMA_STREAM_DEFINE(1, 1, 4, tim7_up); +DMA_STREAM_DEFINE(1, 1, 5, i2c1_rx); +DMA_STREAM_DEFINE(1, 1, 6, i2c1_tx); +DMA_STREAM_DEFINE(1, 1, 7, i2c1_tx); + +DMA_STREAM_DEFINE(1, 2, 0, tim4_ch1); +DMA_STREAM_DEFINE(1, 2, 2, i2c4_rx); +DMA_STREAM_DEFINE(1, 2, 3, tim4_ch2); +DMA_STREAM_DEFINE(1, 2, 5, i2c4_rx); +DMA_STREAM_DEFINE(1, 2, 6, tim4_up); +DMA_STREAM_DEFINE(1, 2, 7, tim4_ch3); + +DMA_STREAM_DEFINE(1, 3, 1, tim2_up); +DMA_STREAM_DEFINE(1, 3, 1, tim2_ch3); +DMA_STREAM_DEFINE(1, 3, 2, i2c3_rx); +DMA_STREAM_DEFINE(1, 3, 4, i2c3_tx); +DMA_STREAM_DEFINE(1, 3, 5, tim2_ch1); +DMA_STREAM_DEFINE(1, 3, 6, tim2_ch2); +DMA_STREAM_DEFINE(1, 3, 6, tim2_ch4); +DMA_STREAM_DEFINE(1, 3, 7, tim2_up); +DMA_STREAM_DEFINE(1, 3, 7, tim2_ch4); + +DMA_STREAM_DEFINE(1, 4, 0, uart5_rx); +DMA_STREAM_DEFINE(1, 4, 1, usart3_rx); +DMA_STREAM_DEFINE(1, 4, 2, uart4_rx); +DMA_STREAM_DEFINE(1, 4, 3, usart3_tx); +DMA_STREAM_DEFINE(1, 4, 4, uart4_tx); +DMA_STREAM_DEFINE(1, 4, 5, usart2_rx); +DMA_STREAM_DEFINE(1, 4, 6, usart2_tx); +DMA_STREAM_DEFINE(1, 4, 7, uart5_tx); + +DMA_STREAM_DEFINE(1, 5, 0, uart8_tx); +DMA_STREAM_DEFINE(1, 5, 1, uart7_tx); +DMA_STREAM_DEFINE(1, 5, 2, tim3_ch4); +DMA_STREAM_DEFINE(1, 5, 2, tim3_up); +DMA_STREAM_DEFINE(1, 5, 3, uart7_rx); +DMA_STREAM_DEFINE(1, 5, 4, tim3_ch1); +DMA_STREAM_DEFINE(1, 5, 4, tim3_trig); +DMA_STREAM_DEFINE(1, 5, 5, tim3_ch2); +DMA_STREAM_DEFINE(1, 5, 6, uart8_rx); +DMA_STREAM_DEFINE(1, 5, 7, tim3_ch3); + +DMA_STREAM_DEFINE(1, 6, 0, tim5_ch3); +DMA_STREAM_DEFINE(1, 6, 0, tim5_up); +DMA_STREAM_DEFINE(1, 6, 1, tim5_ch4); +DMA_STREAM_DEFINE(1, 6, 1, tim5_trig); +DMA_STREAM_DEFINE(1, 6, 2, tim5_ch1); +DMA_STREAM_DEFINE(1, 6, 2, tim3_up); +DMA_STREAM_DEFINE(1, 6, 3, tim5_ch4); +DMA_STREAM_DEFINE(1, 6, 3, tim5_trig); +DMA_STREAM_DEFINE(1, 6, 4, tim5_ch2); +DMA_STREAM_DEFINE(1, 6, 6, tim5_up); + +DMA_STREAM_DEFINE(1, 7, 1, tim6_up); +DMA_STREAM_DEFINE(1, 7, 2, i2c2_rx); +DMA_STREAM_DEFINE(1, 7, 3, i2c2_rx); +DMA_STREAM_DEFINE(1, 7, 4, usart3_tx); +DMA_STREAM_DEFINE(1, 7, 5, dac1); +DMA_STREAM_DEFINE(1, 7, 6, dac2); +DMA_STREAM_DEFINE(1, 7, 7, i2c2_tx); + +DMA_STREAM_DEFINE(1, 8, 0, i2c3_tx); +DMA_STREAM_DEFINE(1, 8, 1, i2c4_rx); +DMA_STREAM_DEFINE(1, 8, 4, i2c2_tx); +DMA_STREAM_DEFINE(1, 8, 6, i2c4_tx); + +DMA_STREAM_DEFINE(1, 9, 1, i2c2_rx); +DMA_STREAM_DEFINE(1, 9, 6, i2c2_tx); + +DMA_STREAM_DEFINE(2, 0, 0, adc1); +DMA_STREAM_DEFINE(2, 0, 1, sai1_a); +DMA_STREAM_DEFINE(2, 0, 2, tim8_ch1); +DMA_STREAM_DEFINE(2, 0, 2, tim8_ch2); +DMA_STREAM_DEFINE(2, 0, 2, tim8_ch3); +DMA_STREAM_DEFINE(2, 0, 3, sai1_a); +DMA_STREAM_DEFINE(2, 0, 4, adc1); +DMA_STREAM_DEFINE(2, 0, 5, sai1_b); +DMA_STREAM_DEFINE(2, 0, 6, tim1_ch1); +DMA_STREAM_DEFINE(2, 0, 6, tim1_ch2); +DMA_STREAM_DEFINE(2, 0, 6, tim1_ch3); +DMA_STREAM_DEFINE(2, 0, 7, sai1_b); + +DMA_STREAM_DEFINE(2, 1, 1, dcmi); +DMA_STREAM_DEFINE(2, 1, 2, adc2); +DMA_STREAM_DEFINE(2, 1, 3, adc2); +DMA_STREAM_DEFINE(2, 1, 4, sai1_b); +DMA_STREAM_DEFINE(2, 1, 5, spi6_tx); +DMA_STREAM_DEFINE(2, 1, 6, spi6_rx); +DMA_STREAM_DEFINE(2, 1, 7, dcmi); + +DMA_STREAM_DEFINE(2, 2, 0, adc3); +DMA_STREAM_DEFINE(2, 2, 1, adc3); +DMA_STREAM_DEFINE(2, 2, 3, spi5_rx); +DMA_STREAM_DEFINE(2, 2, 4, spi5_tx); +DMA_STREAM_DEFINE(2, 2, 5, cryp_out); +DMA_STREAM_DEFINE(2, 2, 6, cryp_in); +DMA_STREAM_DEFINE(2, 2, 7, hash_in); + +DMA_STREAM_DEFINE(2, 3, 0, spi1_rx); +DMA_STREAM_DEFINE(2, 3, 2, spi1_rx); +DMA_STREAM_DEFINE(2, 3, 3, spi1_tx); +DMA_STREAM_DEFINE(2, 3, 4, sai2_a); +DMA_STREAM_DEFINE(2, 3, 5, spi1_tx); +DMA_STREAM_DEFINE(2, 3, 6, sai2_b); +DMA_STREAM_DEFINE(2, 3, 7, quadspi); + +DMA_STREAM_DEFINE(2, 4, 0, spi4_rx); +DMA_STREAM_DEFINE(2, 4, 1, spi4_tx); +DMA_STREAM_DEFINE(2, 4, 2, usart1_rx); +DMA_STREAM_DEFINE(2, 4, 3, sdmmc1); +DMA_STREAM_DEFINE(2, 4, 5, usart1_rx); +DMA_STREAM_DEFINE(2, 4, 6, sdmmc1); +DMA_STREAM_DEFINE(2, 4, 7, usart1_tx); + +DMA_STREAM_DEFINE(2, 5, 1, usart6_rx); +DMA_STREAM_DEFINE(2, 5, 2, usart6_rx); +DMA_STREAM_DEFINE(2, 5, 3, spi4_rx); +DMA_STREAM_DEFINE(2, 5, 4, spi4_tx); +DMA_STREAM_DEFINE(2, 5, 5, spi5_tx); +DMA_STREAM_DEFINE(2, 5, 6, usart6_tx); +DMA_STREAM_DEFINE(2, 5, 7, usart6_tx); + +DMA_STREAM_DEFINE(2, 6, 0, tim1_trig); +DMA_STREAM_DEFINE(2, 6, 1, tim1_ch1); +DMA_STREAM_DEFINE(2, 6, 2, tim1_ch2); +DMA_STREAM_DEFINE(2, 6, 3, tim1_ch1); +DMA_STREAM_DEFINE(2, 6, 4, tim1_ch4); +DMA_STREAM_DEFINE(2, 6, 4, tim1_trig); +DMA_STREAM_DEFINE(2, 6, 4, tim1_com); +DMA_STREAM_DEFINE(2, 6, 5, tim1_up); +DMA_STREAM_DEFINE(2, 6, 6, tim1_ch3); + +DMA_STREAM_DEFINE(2, 7, 1, tim8_up); +DMA_STREAM_DEFINE(2, 7, 2, tim8_ch1); +DMA_STREAM_DEFINE(2, 7, 3, tim8_ch2); +DMA_STREAM_DEFINE(2, 7, 4, tim8_ch3); +DMA_STREAM_DEFINE(2, 7, 5, spi5_rx); +DMA_STREAM_DEFINE(2, 7, 6, spi5_tx); +DMA_STREAM_DEFINE(2, 7, 7, tim8_ch4); +DMA_STREAM_DEFINE(2, 7, 7, tim8_trig); +DMA_STREAM_DEFINE(2, 7, 7, tim8_com); + +DMA_STREAM_DEFINE(2, 8, 0, dfsdm1_flt0); +DMA_STREAM_DEFINE(2, 8, 1, dfsdm1_flt1); +DMA_STREAM_DEFINE(2, 8, 2, dfsdm1_flt2); +DMA_STREAM_DEFINE(2, 8, 3, dfsdm1_flt3); +DMA_STREAM_DEFINE(2, 8, 4, dfsdm1_flt0); +DMA_STREAM_DEFINE(2, 8, 5, dfsdm1_flt1); +DMA_STREAM_DEFINE(2, 8, 6, dfsdm1_flt2); +DMA_STREAM_DEFINE(2, 8, 7, dfsdm1_flt3); + +DMA_STREAM_DEFINE(2, 9, 0, jpeg_in); +DMA_STREAM_DEFINE(2, 9, 1, jpeg_out); +DMA_STREAM_DEFINE(2, 9, 2, spi4_tx); +DMA_STREAM_DEFINE(2, 9, 3, jpeg_in); +DMA_STREAM_DEFINE(2, 9, 4, jpeg_out); +DMA_STREAM_DEFINE(2, 9, 5, spi5_rx); + +DMA_STREAM_DEFINE(2, 10, 0, sai1_b); +DMA_STREAM_DEFINE(2, 10, 1, sai2_b); +DMA_STREAM_DEFINE(2, 10, 2, sai2_a); +DMA_STREAM_DEFINE(2, 10, 6, sai1_a); + +DMA_STREAM_DEFINE(2, 11, 0, sdmmc2); +DMA_STREAM_DEFINE(2, 11, 2, suadspi); +DMA_STREAM_DEFINE(2, 11, 5, sdmmc2); + +#define SPI_CFG_DEFINE(n) \ + struct stm32_spi_cfg spi ## n ## _cfg = { \ + .spi_num = n, \ + .spi = SPI ## n, \ + .i2s_irq = SPI ## n ## _IRQn, \ + .driver_data = &stm32_i2s ## n, \ + .irq_handler = i2s ## n ## _irq_handler, \ + .i2s_dma_handler = i2s ## n ## _dma_stream_irq_handler, \ + .hdma_spi = &hdma_spi ## n, \ + .enable_clock = i2s ## n ## _clock_enable, \ + } + +#define I2S_CFG_DEFINE(n) \ + struct stm32_spi_cfg spi ## n ## _cfg = { \ + .spi_num = n, \ + .spi = SPI ## n, \ + .i2s_irq = SPI ## n ## _IRQn, \ + .driver_data = &stm32_i2s ## n, \ + .irq_handler = i2s ## n ## _irq_handler, \ + .i2s_dma_handler = i2s ## n ## _dma_stream_irq_handler, \ + .i2sext_dma_handler = i2s ## n ## ext_dma_stream_irq_handler, \ + .hdma_spi = &hdma_spi ## n, \ + .hdma_i2sext = &hdma_i2s ## n ## ext, \ + .enable_clock = i2s ## n ## _clock_enable, \ + } + +#ifdef SPI1 +static DMA_HandleTypeDef hdma_spi1; +SPI_CFG_DEFINE(1); +#endif +#ifdef SPI2 +static DMA_HandleTypeDef hdma_spi2; +SPI_CFG_DEFINE(2); +#endif +#ifdef SPI3 +static DMA_HandleTypeDef hdma_spi3; +SPI_CFG_DEFINE(3); +#endif diff --git a/hw/drivers/i2s/i2s_stm32f7/syscfg.yml b/hw/drivers/i2s/i2s_stm32f7/syscfg.yml new file mode 100644 index 000000000..2cdd57468 --- /dev/null +++ b/hw/drivers/i2s/i2s_stm32f7/syscfg.yml @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: