You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by GitBox <gi...@apache.org> on 2021/01/08 13:07:03 UTC

[GitHub] [mynewt-core] kasjer commented on a change in pull request #2405: hw/drivers/i2s: Add I2S driver for DA1469x family

kasjer commented on a change in pull request #2405:
URL: https://github.com/apache/mynewt-core/pull/2405#discussion_r553932832



##########
File path: hw/drivers/i2s/i2s_da1469x/src/i2s_da1469x.c
##########
@@ -0,0 +1,430 @@
+/*
+ * 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 <bsp/bsp.h>
+#include <i2s/i2s.h>
+#include <i2s/i2s_driver.h>
+#include <i2s_da1469x/i2s_da1469x.h>
+#include <mcu/da1469x_dma.h>
+#include <mcu/da1469x_pd.h>
+
+struct da1469x_i2s {
+    struct i2s_cfg cfg;
+
+    /* DMA register pairs 0,2 RX, 1,3 TX */
+    struct da1469x_dma_regs *dma_regs[4];
+    /* Currently active DMA buffer half. */
+    uint8_t active_half;
+    /* Number of buffers that driver has data from. */
+    uint8_t full_buffer_count;
+
+    bool running;
+
+    struct i2s *i2s;
+};
+
+static struct da1469x_i2s da1469x_i2s;
+
+static int
+da1469x_i2s_init(struct i2s *i2s, const struct i2s_cfg *cfg)
+{
+    int rc;
+
+    da1469x_i2s.i2s = i2s;
+    da1469x_i2s.cfg = *cfg;
+
+    mcu_gpio_set_pin_function(cfg->bclk_pin, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_PCM_CLK);
+    mcu_gpio_set_pin_function(cfg->lrcl_pin, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_PCM_FSC);
+    i2s->direction = I2S_INVALID;
+    if (cfg->sdout_pin >= 0) {
+        mcu_gpio_set_pin_function(cfg->sdout_pin, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_PCM_DO);
+        i2s->direction = I2S_OUT;
+    }
+    if (cfg->sdin_pin >= 0) {
+        mcu_gpio_set_pin_function(cfg->sdin_pin, MCU_GPIO_MODE_INPUT, MCU_GPIO_FUNC_PCM_DI);
+        i2s->direction |= I2S_IN;
+    }
+    i2s->sample_size_in_bytes = cfg->sample_bits / 8;
+
+    rc = i2s_init(i2s, cfg->pool);
+
+    if (rc != OS_OK) {
+        goto end;
+    }
+
+    i2s->sample_rate = cfg->sample_rate;
+    i2s->driver_data = &da1469x_i2s;
+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)da1469x_i2s_init, (void *)cfg);
+}
+
+int
+i2s_driver_stop(struct i2s *i2s)
+{
+    struct da1469x_i2s *i2s_data = (struct da1469x_i2s *)i2s->driver_data;
+    struct i2s_sample_buffer *buffer;
+
+    if (i2s_data->running) {
+        da1469x_i2s.dma_regs[0]->DMA_CTRL_REG &= ~DMA_DMA0_CTRL_REG_DMA_ON_Msk;
+        da1469x_i2s.dma_regs[1]->DMA_CTRL_REG &= ~DMA_DMA0_CTRL_REG_DMA_ON_Msk;
+
+        i2s_data->full_buffer_count = 0;
+        while ((buffer = i2s_driver_buffer_get(i2s)) != NULL) {
+            i2s_driver_buffer_put(i2s, buffer);
+        }
+        da1469x_pd_release_nowait(MCU_PD_DOMAIN_PER);
+    }
+
+    return 0;
+}
+
+struct pcm_div {
+    uint16_t div;
+    uint16_t fdiv;
+};
+
+static void
+copy_and_swap_channels_16(const int16_t *lr, int16_t *rl, uint32_t count)
+{
+    const int16_t *limit = lr + count;
+    while (lr < limit) {
+        *rl++ = lr[1];
+        *rl++ = lr[0];
+        lr += 2;
+    }
+}
+
+/* Split 16 bit samples to left and right data for DMA. */
+static void
+split_channels_16(const int16_t *lr, int16_t *l, int16_t *r, uint32_t count)
+{
+    const int16_t *limit = lr + count;
+
+    while (lr < limit) {
+        *l++ = *lr++;
+        *r++ = *lr++;
+    }
+}
+
+/* Split 16 bit samples to left and right data for DMA, extend to 32 bits left aligned. */
+static void
+split_channels_16_32(const int16_t *lr, int32_t *l, int32_t *r, uint32_t count)
+{
+    const int16_t *limit = lr + count;
+
+    while (lr < limit) {
+        *l++ = (*lr++) << 16;
+        *r++ = (*lr++) << 16;
+    }
+}
+
+/* Split 32 bit samples to left and right data for DMA. */
+static void
+split_channels_32_32(const int32_t *lr, int32_t *l, int32_t *r, uint32_t count)
+{
+    const int32_t *limit = lr + count;
+
+    while (lr < limit) {
+        *l++ = *lr++;
+        *r++ = *lr++;
+    }
+}
+
+static inline bool
+tx_dma_is_active(void)
+{
+    return (da1469x_i2s.dma_regs[1]->DMA_CTRL_REG & DMA_DMA0_CTRL_REG_DMA_ON_Msk) != 0;
+}
+
+static void
+da1469x_i2s_fill_dma_buffer(const void *buffer, uint32_t sample_count, uint32_t sample_size_in_bytes)
+{
+    uint32_t offset = 0;
+    const int16_t *src = (const int16_t *)buffer;
+    struct da1469x_dma_buffer *dma_mem = da1469x_i2s.cfg.dma_memory;
+    uint8_t inactive_half = tx_dma_is_active() ? (da1469x_i2s.active_half ^ 1) : da1469x_i2s.full_buffer_count;
+
+    if (da1469x_i2s.cfg.data_format == I2S_DATA_FRAME_16_16) {
+
+        assert(sample_size_in_bytes == 2);
+        assert(sample_count * sample_size_in_bytes == dma_mem->size);
+
+        if (inactive_half != 0) {
+            offset = dma_mem->size;
+        }
+        copy_and_swap_channels_16(src, (int16_t *)(dma_mem->buffer + offset), sample_count);
+    } else if (da1469x_i2s.cfg.data_format == I2S_DATA_FRAME_16_32) {
+
+        assert(sample_size_in_bytes == 2);
+        assert(sample_count * sample_size_in_bytes == dma_mem->size);
+
+        if (inactive_half != 0) {
+            offset = dma_mem->size / 2;
+        }
+        split_channels_16(src, (int16_t *)(dma_mem->buffer + offset),
+                          (int16_t *)(dma_mem->buffer + offset + dma_mem->size),
+                          sample_count);
+    } else if (da1469x_i2s.cfg.data_format == I2S_DATA_FRAME_32_32) {
+
+        if (inactive_half != 0) {
+            offset = dma_mem->size / 2;
+        }
+        if (sample_size_in_bytes == 2) {
+            assert(sample_count * 4 == dma_mem->size);
+            split_channels_16_32((const int16_t *)buffer, (int32_t *)(dma_mem->buffer + offset),
+                                 (int32_t *)(dma_mem->buffer + offset + dma_mem->size),
+                                 sample_count);
+        } else {
+            assert(sample_count * sample_size_in_bytes == dma_mem->size);
+
+            split_channels_32_32((const int32_t *)buffer, (int32_t *)(dma_mem->buffer + offset),
+                                 (int32_t *)(dma_mem->buffer + offset + dma_mem->size),
+                                 sample_count);
+        }
+    }
+    da1469x_i2s.full_buffer_count++;
+}
+
+static void
+da1469x_i2s_dma_tx_start(void)
+{
+    uint32_t number_of_transfers;
+    struct da1469x_dma_regs *lregs = da1469x_i2s.dma_regs[1];
+    struct da1469x_dma_regs *rregs = da1469x_i2s.dma_regs[3];
+    struct da1469x_dma_buffer *dma_mem = da1469x_i2s.cfg.dma_memory;
+
+    da1469x_i2s.active_half = 0;
+
+    if (da1469x_i2s.cfg.data_format == I2S_DATA_FRAME_32_32) {
+        /* Left and right channels data are not interleaved, DMA transfer size 4B */
+        number_of_transfers = (dma_mem->size >> 2) - 1;
+    } else {
+        /* Number of transferred valid for I2S_DATA_FRAME_16_16 and I2S_DATA_FRAME_16_32 */
+        number_of_transfers = (dma_mem->size >> 1) - 1;
+    }
+
+    /* First interrupt at half buffer */
+    lregs->DMA_INT_REG = number_of_transfers / 2;
+    lregs->DMA_LEN_REG = number_of_transfers;
+    if (rregs) {
+        /* DMA is handled in one interrupt, not need for right channel int */
+        rregs->DMA_INT_REG = 0xFFFF;
+        rregs->DMA_LEN_REG = number_of_transfers;
+        rregs->DMA_CTRL_REG |= DMA_DMA0_CTRL_REG_DMA_ON_Msk;
+    }
+    lregs->DMA_CTRL_REG |= DMA_DMA0_CTRL_REG_DMA_ON_Msk;
+}
+
+struct pcm_div {
+    uint16_t div;
+    uint16_t fdiv;
+};

Review comment:
       fixed




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org