blob: 9543a796aebb4459e1bf468612faf48186c74c28 [file] [log] [blame]
/*
* 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 <i2s/i2s.h>
#include <i2s/i2s_driver.h>
#include <i2s_stm32f1/stm32_pin_cfg.h>
#include <i2s_stm32f1/i2s_stm32f1.h>
static struct stm32_i2s stm32_i2s2;
static struct stm32_i2s stm32_i2s3;
void
i2s2_irq_handler(void)
{
HAL_I2S_IRQHandler(&stm32_i2s2.hi2s);
}
void
i2s3_irq_handler(void)
{
HAL_I2S_IRQHandler(&stm32_i2s3.hi2s);
}
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
}
void
HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s)
{
struct stm32_i2s *i2s_data = (struct stm32_i2s *)hi2s;
struct i2s *i2s = i2s_data->i2s;
struct i2s_sample_buffer *processed_buffer = i2s_data->active_buffer;
i2s_data->active_buffer = i2s_driver_buffer_get(i2s);
if (i2s_data->active_buffer) {
HAL_I2S_Transmit_DMA(&i2s_data->hi2s,
i2s_data->active_buffer->sample_data,
i2s_data->active_buffer->sample_count);
} else {
i2s_driver_state_changed(i2s, I2S_STATE_OUT_OF_BUFFERS);
}
i2s_driver_buffer_put(i2s, processed_buffer);
}
void
HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)
{
struct stm32_i2s *i2s_data = (struct stm32_i2s *)hi2s;
struct i2s *i2s = i2s_data->i2s;
struct i2s_sample_buffer *processed_buffer = i2s_data->active_buffer;
i2s_data->active_buffer = i2s_driver_buffer_get(i2s);
if (i2s_data->active_buffer) {
HAL_I2S_Receive_DMA(&i2s_data->hi2s,
i2s_data->active_buffer->sample_data,
i2s_data->active_buffer->capacity);
} else {
i2s_driver_state_changed(i2s, I2S_STATE_OUT_OF_BUFFERS);
}
processed_buffer->sample_count = processed_buffer->capacity;
i2s_driver_buffer_put(i2s, processed_buffer);
}
static void
i2s2_dma_stream_irq_handler(void)
{
HAL_DMA_IRQHandler(&stm32_i2s2.hdma_spi);
}
static void
i2s3_dma_stream_irq_handler(void)
{
HAL_DMA_IRQHandler(&stm32_i2s3.hdma_spi);
}
static void
dma1_enable_clock(bool enable)
{
if (enable) {
__HAL_RCC_DMA1_CLK_ENABLE();
} else {
__HAL_RCC_DMA1_CLK_DISABLE();
}
}
static void
dma2_enable_clock(bool enable)
{
#ifdef __HAL_RCC_DMA2_CLK_DISABLE
if (enable) {
__HAL_RCC_DMA2_CLK_ENABLE();
} else {
__HAL_RCC_DMA2_CLK_DISABLE();
}
#endif
}
static void
i2s_init_interrupts(const struct i2s_cfg *cfg)
{
NVIC_SetVector(cfg->hw_cfg->dma_channel_irq, (uint32_t)cfg->hw_cfg->dma_irq_handler);
HAL_NVIC_SetPriority(cfg->hw_cfg->dma_channel_irq, 5, 0);
HAL_NVIC_EnableIRQ(cfg->hw_cfg->dma_channel_irq);
/* I2S interrupt Init */
NVIC_SetVector(cfg->hw_cfg->i2s_irq, (uint32_t)cfg->hw_cfg->i2s_irq_handler);
HAL_NVIC_SetPriority(cfg->hw_cfg->i2s_irq, 5, 0);
HAL_NVIC_EnableIRQ(cfg->hw_cfg->i2s_irq);
}
static void
i2s_init_pins(const struct stm32_i2s_pins *pins)
{
GPIO_InitTypeDef gpio_init;
gpio_init = pins->ck_pin->hal_init;
hal_gpio_init_stm(pins->ck_pin->pin, &gpio_init);
gpio_init = pins->ws_pin->hal_init;
hal_gpio_init_stm(pins->ws_pin->pin, &gpio_init);
gpio_init = pins->sd_pin->hal_init;
hal_gpio_init_stm(pins->sd_pin->pin, &gpio_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->hw_cfg->driver_data;
stm32_i2s->i2s = i2s;
i2s->sample_rate = cfg->sample_rate;
i2s->driver_data = stm32_i2s;
i2s_init_pins((struct stm32_i2s_pins *)&cfg->hw_cfg->pins);
cfg->hw_cfg->i2s_enable_clock(true);
stm32_i2s->hi2s.Instance = cfg->hw_cfg->i2s_base;
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 = I2S_MCLKOUTPUT_DISABLE;
stm32_i2s->hi2s.Init.AudioFreq = cfg->sample_rate;
stm32_i2s->hi2s.Init.CPOL = I2S_CPOL_LOW;
if (HAL_I2S_Init(&stm32_i2s->hi2s) != HAL_OK) {
rc = SYS_EUNKNOWN;
goto end;
}
cfg->hw_cfg->dma_enable_clock(true);
stm32_i2s->hdma_spi.Instance = cfg->hw_cfg->dma_channel_base;
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;
if (HAL_DMA_Init(&stm32_i2s->hdma_spi) != HAL_OK) {
rc = SYS_EUNKNOWN;
goto end;
}
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);
buffer = i2s_data->active_buffer;
if (buffer) {
i2s_data->active_buffer = NULL;
i2s_driver_buffer_put(i2s, buffer);
}
return 0;
}
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_READY:
assert(i2s_data->active_buffer == NULL);
i2s_data->active_buffer = i2s_driver_buffer_get(i2s);
assert(i2s_data->active_buffer);
if (i2s_data->active_buffer == NULL) {
i2s->state = I2S_STATE_OUT_OF_BUFFERS;
rc = I2S_ERR_NO_BUFFER;
break;
}
i2s->state = I2S_STATE_RUNNING;
if (i2s->direction == I2S_IN) {
i2s_data->active_buffer->sample_count = i2s_data->active_buffer->capacity;
HAL_I2S_Receive_DMA(&i2s_data->hi2s,
i2s_data->active_buffer->sample_data,
i2s_data->active_buffer->sample_count);
} else if (i2s->direction == I2S_OUT) {
HAL_I2S_Transmit_DMA(&i2s_data->hi2s,
i2s_data->active_buffer->sample_data,
i2s_data->active_buffer->sample_count);
}
break;
case HAL_I2S_STATE_BUSY:
case HAL_I2S_STATE_BUSY_RX:
case HAL_I2S_STATE_BUSY_TX:
case HAL_I2S_STATE_BUSY_TX_RX:
break;
default:
rc = I2S_ERR_INTERNAL;
}
return rc;
}
void
i2s_driver_buffer_queued(struct i2s *i2s)
{
}
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) \
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, \
} \
}
#define I2S_CK_PIN_DEFINE(n, po, pi) \
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, \
} \
}
#define I2S_WS_PIN_DEFINE(n, po, pi) \
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, \
} \
}
#define I2S_SD_PIN_DEFINE(n, po, pi) \
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, \
} \
}
const struct stm32f1_i2s_hw_cfg i2s2_tx = {
.dma_num = 1,
.dma_channel_irq = DMA1_Channel5_IRQn,
.dma_channel_base = DMA1_Channel5,
.dma_base = DMA1,
.dma_irq_handler = i2s2_dma_stream_irq_handler,
.dma_enable_clock = dma1_enable_clock,
.i2s_irq_handler = i2s2_irq_handler,
.i2s_enable_clock = i2s2_clock_enable,
.pins = {
.ck_pin = I2S_CK_PIN(2, B, 13),
.ws_pin = I2S_WS_PIN(2, B, 12),
.sd_pin = I2S_SD_PIN(2, B, 15),
},
.driver_data = &stm32_i2s2,
.i2s_base = SPI2,
};
const struct stm32f1_i2s_hw_cfg i2s2_rx = {
.dma_num = 1,
.dma_channel_irq = DMA1_Channel4_IRQn,
.dma_channel_base = DMA1_Channel4,
.dma_base = DMA1,
.dma_irq_handler = i2s2_dma_stream_irq_handler,
.dma_enable_clock = dma1_enable_clock,
.i2s_irq_handler = i2s2_irq_handler,
.i2s_enable_clock = i2s2_clock_enable,
.pins = {
.ck_pin = I2S_CK_PIN(2, B, 13),
.ws_pin = I2S_WS_PIN(2, B, 12),
.sd_pin = I2S_SD_PIN(2, B, 15),
},
.driver_data = &stm32_i2s2,
.i2s_base = SPI2,
};
const struct stm32f1_i2s_hw_cfg i2s3_tx = {
.dma_num = 2,
.dma_channel_irq = DMA2_Channel2_IRQn,
.dma_channel_base = DMA2_Channel2,
.dma_base = DMA2,
.dma_irq_handler = i2s3_dma_stream_irq_handler,
.dma_enable_clock = dma2_enable_clock,
.i2s_irq_handler = i2s3_irq_handler,
.i2s_enable_clock = i2s3_clock_enable,
.pins = {
.ck_pin = I2S_CK_PIN(3, B, 3),
.ws_pin = I2S_WS_PIN(3, A, 15),
.sd_pin = I2S_SD_PIN(3, B, 5),
},
.driver_data = &stm32_i2s3,
.i2s_base = SPI3,
};
const struct stm32f1_i2s_hw_cfg i2s3_rx = {
.dma_num = 2,
.dma_channel_irq = DMA2_Channel1_IRQn,
.dma_channel_base = DMA2_Channel1,
.dma_base = DMA2,
.dma_irq_handler = i2s3_dma_stream_irq_handler,
.dma_enable_clock = dma2_enable_clock,
.i2s_irq_handler = i2s3_irq_handler,
.i2s_enable_clock = i2s3_clock_enable,
.pins = {
.ck_pin = I2S_CK_PIN(3, B, 3),
.ws_pin = I2S_WS_PIN(3, A, 15),
.sd_pin = I2S_SD_PIN(3, B, 5),
},
.driver_data = &stm32_i2s3,
.i2s_base = SPI3,
};
/* I2S2 Possible CK pins */
I2S_CK_PIN_DEFINE(2, B, 13);
/* I2S2 possible WS pins */
I2S_WS_PIN_DEFINE(2, B, 12);
/* I2S2 possible SD pins */
I2S_SD_PIN_DEFINE(2, B, 15);
/* I2S2 Possible MCK pins */
I2S_PIN_DEFINE(2, C, 6);
/* I2S3 possible CK pins */
I2S_CK_PIN_DEFINE(3, B, 3);
/* I2S3 possible WS pins */
I2S_WS_PIN_DEFINE(3, A, 15);
/* I2S3 possible SD pins */
I2S_SD_PIN_DEFINE(3, B, 5);
/* I2S3 possible MCK pins */
I2S_PIN_DEFINE(3, C, 7);