You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by je...@apache.org on 2021/05/13 10:50:41 UTC

[mynewt-core] branch master updated (671fd92 -> 7bfcd2b)

This is an automated email from the ASF dual-hosted git repository.

jerzy pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git.


    from 671fd92  kernel/os: Remove min/max macros for C++
     new 956bba7  hw/drivers/i2s: Add I2S driver for NRF5x families
     new 7bfcd2b  mcu/nrf5340: Enable I2S support in NRFX

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../include/i2s_nrfx/i2s_nrfx.h}                   |  6 +-
 hw/drivers/i2s/{i2s_da1469x => i2s_nrfx}/pkg.yml   |  4 +-
 .../src/i2s_nrf52.c => i2s_nrfx/src/i2s_nrfx.c}    | 99 ++++++++++++----------
 hw/mcu/nordic/nrf5340/include/nrfx_config.h        |  2 +-
 4 files changed, 61 insertions(+), 50 deletions(-)
 copy hw/drivers/i2s/{i2s_nrf52/include/i2s_nrf52/i2s_nrf52.h => i2s_nrfx/include/i2s_nrfx/i2s_nrfx.h} (94%)
 copy hw/drivers/i2s/{i2s_da1469x => i2s_nrfx}/pkg.yml (90%)
 copy hw/drivers/i2s/{i2s_nrf52/src/i2s_nrf52.c => i2s_nrfx/src/i2s_nrfx.c} (71%)

[mynewt-core] 02/02: mcu/nrf5340: Enable I2S support in NRFX

Posted by je...@apache.org.
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 7bfcd2bc5491399145c63ced08c086e832731e6b
Author: Jerzy Kasenberg <je...@codecoup.pl>
AuthorDate: Thu May 13 10:44:34 2021 +0200

    mcu/nrf5340: Enable I2S support in NRFX
---
 hw/mcu/nordic/nrf5340/include/nrfx_config.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/mcu/nordic/nrf5340/include/nrfx_config.h b/hw/mcu/nordic/nrf5340/include/nrfx_config.h
index 5f98fb9..87fa001 100644
--- a/hw/mcu/nordic/nrf5340/include/nrfx_config.h
+++ b/hw/mcu/nordic/nrf5340/include/nrfx_config.h
@@ -525,7 +525,7 @@
 // <e> NRFX_I2S_ENABLED - nrfx_i2s - I2S peripheral driver.
 //==========================================================
 #ifndef NRFX_I2S_ENABLED
-#define NRFX_I2S_ENABLED 0
+#define NRFX_I2S_ENABLED 1
 #endif
 
 // <o> NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY  - Interrupt priority.

[mynewt-core] 01/02: hw/drivers/i2s: Add I2S driver for NRF5x families

Posted by je...@apache.org.
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 956bba732eb167bdac304bea3ba0463518c0f642
Author: Jerzy Kasenberg <je...@codecoup.pl>
AuthorDate: Tue May 11 10:00:38 2021 +0200

    hw/drivers/i2s: Add I2S driver for NRF5x families
    
    This is based on NRF52 but incorporates changes needed
    to handle NRF5340 MCU.
    Name of driver implies that it used Nordic provided NRFX code.
    This driver can be used in NRF52 MCUs as well.
---
 .../i2s/i2s_nrfx/include/i2s_nrfx/i2s_nrfx.h       |  45 ++++
 hw/drivers/i2s/i2s_nrfx/pkg.yml                    |  29 +++
 hw/drivers/i2s/i2s_nrfx/src/i2s_nrfx.c             | 274 +++++++++++++++++++++
 3 files changed, 348 insertions(+)

diff --git a/hw/drivers/i2s/i2s_nrfx/include/i2s_nrfx/i2s_nrfx.h b/hw/drivers/i2s/i2s_nrfx/include/i2s_nrfx/i2s_nrfx.h
new file mode 100644
index 0000000..cba26e3
--- /dev/null
+++ b/hw/drivers/i2s/i2s_nrfx/include/i2s_nrfx/i2s_nrfx.h
@@ -0,0 +1,45 @@
+/*
+ * 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_NRFX_H
+#define _I2S_NRFX_H
+
+#include <stdint.h>
+#include <nrfx/nrfx.h>
+#include <nrfx/drivers/include/nrfx_i2s.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct i2s;
+
+struct i2s_cfg {
+    nrfx_i2s_config_t nrfx_i2s_cfg;
+
+    uint32_t sample_rate;
+
+    struct i2s_buffer_pool *pool;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _I2S_NRFX_H */
diff --git a/hw/drivers/i2s/i2s_nrfx/pkg.yml b/hw/drivers/i2s/i2s_nrfx/pkg.yml
new file mode 100644
index 0000000..4eebb65
--- /dev/null
+++ b/hw/drivers/i2s/i2s_nrfx/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_nrfx
+pkg.description: I2S driver for Nordic chips using NRFX library.
+pkg.author: "Apache Mynewt <de...@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_nrfx/src/i2s_nrfx.c b/hw/drivers/i2s/i2s_nrfx/src/i2s_nrfx.c
new file mode 100644
index 0000000..e9284dd
--- /dev/null
+++ b/hw/drivers/i2s/i2s_nrfx/src/i2s_nrfx.c
@@ -0,0 +1,274 @@
+/*
+ * 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_nrfx/i2s_nrfx.h>
+#include <nrfx/drivers/include/nrfx_i2s.h>
+
+struct i2s_nrfx {
+    nrfx_i2s_config_t nrfx_i2s_cfg;
+    bool running;
+    int8_t nrfx_queued_count;
+    struct i2s *i2s;
+    struct i2s_sample_buffer *nrfx_buffers[2];
+};
+
+static struct i2s_nrfx i2s_nrfx;
+
+static void
+nrfx_add_buffer(struct i2s *i2s, struct i2s_sample_buffer *buffer)
+{
+    nrfx_i2s_buffers_t nrfx_buffers = {0};
+    nrfx_err_t err;
+
+    assert(i2s != NULL);
+    if (buffer == NULL) {
+        return;
+    }
+
+    if (i2s->direction == I2S_OUT || i2s->direction == I2S_OUT_IN) {
+        nrfx_buffers.p_tx_buffer = buffer->sample_data;
+    }
+    if (i2s->direction == I2S_IN || i2s->direction == I2S_OUT_IN) {
+        nrfx_buffers.p_rx_buffer = buffer->sample_data;
+    }
+
+    assert(i2s_nrfx.nrfx_queued_count < 2);
+    assert(i2s_nrfx.nrfx_buffers[i2s_nrfx.nrfx_queued_count] == NULL);
+
+    i2s_nrfx.nrfx_buffers[i2s_nrfx.nrfx_queued_count] = buffer;
+    i2s_nrfx.nrfx_queued_count++;
+    if (i2s_nrfx.nrfx_queued_count == 1) {
+        i2s_driver_state_changed (i2s, I2S_STATE_RUNNING);
+        err = nrfx_i2s_start(&nrfx_buffers, buffer->sample_count * i2s->sample_size_in_bytes / 4, 0);
+    } else {
+        err = nrfx_i2s_next_buffers_set(&nrfx_buffers);
+    }
+
+    assert(err == NRFX_SUCCESS);
+}
+
+static void
+feed_nrfx(void)
+{
+    struct i2s_sample_buffer *buffer;
+
+    buffer = i2s_driver_buffer_get(i2s_nrfx.i2s);
+    nrfx_add_buffer(i2s_nrfx.i2s, buffer);
+}
+
+static void
+i2s_nrfx_data_handler(const nrfx_i2s_buffers_t *p_released, uint32_t status)
+{
+    struct i2s_sample_buffer *buffer;
+
+    if (p_released != NULL &&
+        (p_released->p_rx_buffer != NULL || p_released->p_tx_buffer != NULL)) {
+        i2s_nrfx.nrfx_queued_count--;
+        assert(i2s_nrfx.nrfx_queued_count >= 0);
+        buffer = i2s_nrfx.nrfx_buffers[0];
+        assert(buffer->sample_data == p_released->p_tx_buffer || buffer->sample_data == p_released->p_rx_buffer);
+        i2s_nrfx.nrfx_buffers[0] = i2s_nrfx.nrfx_buffers[1];
+        i2s_nrfx.nrfx_buffers[1] = NULL;
+        i2s_driver_buffer_put(i2s_nrfx.i2s, buffer);
+    }
+    if (i2s_nrfx.running && i2s_nrfx.nrfx_queued_count < 2) {
+        assert(i2s_nrfx.nrfx_buffers[1] == NULL);
+        feed_nrfx();
+    }
+    if (status == NRFX_I2S_STATUS_TRANSFER_STOPPED) {
+        i2s_driver_state_changed(i2s_nrfx.i2s, I2S_STATE_STOPPED);
+    }
+}
+
+static int
+i2s_nrfx_init(struct i2s *i2s, const struct i2s_cfg *cfg)
+{
+    int rc;
+
+    i2s_nrfx.i2s = i2s;
+
+    NVIC_SetVector(nrfx_get_irq_number(NRF_I2S), (uint32_t)nrfx_i2s_irq_handler);
+
+    i2s_nrfx.nrfx_i2s_cfg = cfg->nrfx_i2s_cfg;
+    switch (cfg->nrfx_i2s_cfg.sample_width) {
+    case NRF_I2S_SWIDTH_8BIT:
+#if defined(I2S_CONFIG_SWIDTH_SWIDTH_8BitIn16)
+    case NRF_I2S_SWIDTH_8BIT_IN16BIT:
+#endif
+#if defined(I2S_CONFIG_SWIDTH_SWIDTH_8BitIn32)
+    case NRF_I2S_SWIDTH_8BIT_IN32BIT:
+#endif
+        i2s->sample_size_in_bytes = 1;
+        break;
+    case NRF_I2S_SWIDTH_16BIT:
+#if defined(I2S_CONFIG_SWIDTH_SWIDTH_16BitIn32)
+    case NRF_I2S_SWIDTH_16BIT_IN32BIT:
+#endif
+        i2s->sample_size_in_bytes = 2;
+        break;
+    case NRF_I2S_SWIDTH_24BIT:
+#if defined(I2S_CONFIG_SWIDTH_SWIDTH_24BitIn32)
+    case NRF_I2S_SWIDTH_24BIT_IN32BIT:
+#endif
+#if defined(I2S_CONFIG_SWIDTH_SWIDTH_32Bit)
+    case NRF_I2S_SWIDTH_32BIT:
+#endif
+        i2s->sample_size_in_bytes = 4;
+        break;
+    }
+
+    i2s->direction = I2S_INVALID;
+    if (cfg->nrfx_i2s_cfg.sdin_pin != NRFX_I2S_PIN_NOT_USED) {
+        i2s->direction = I2S_IN;
+    }
+    if (cfg->nrfx_i2s_cfg.sdout_pin != NRFX_I2S_PIN_NOT_USED) {
+        i2s->direction |= I2S_OUT;
+    }
+
+    rc = i2s_init(i2s, cfg->pool);
+
+    if (rc != OS_OK) {
+        nrfx_i2s_uninit();
+        goto end;
+    }
+
+    i2s->sample_rate = cfg->sample_rate;
+    i2s->driver_data = &i2s_nrfx;
+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)i2s_nrfx_init, (void *)cfg);
+}
+
+int
+i2s_driver_stop(struct i2s *i2s)
+{
+    struct i2s_sample_buffer *buffer;
+
+    i2s_nrfx.running = false;
+    nrfx_i2s_stop();
+
+    assert(i2s_nrfx.i2s->state == I2S_STATE_STOPPED);
+
+    while (NULL != (buffer = i2s_driver_buffer_get(i2s))) {
+        i2s_driver_buffer_put(i2s, buffer);
+    }
+
+    return 0;
+}
+
+/* Settings are stored for following sampling frequencies:
+ * 8000, 16000, 22050, 32000, 441000, 48000 */
+struct i2s_clock_cfg {
+    nrf_i2s_mck_t mck_setup;
+    nrf_i2s_ratio_t ratio;
+};
+
+static const uint16_t sample_rates[] = { 8000, 16000, 22050, 32000, 44100, 48000 };
+
+static const struct i2s_clock_cfg mck_for_8_16_bit_samples[] = {
+    { NRF_I2S_MCK_32MDIV125, NRF_I2S_RATIO_32X}, /*  8000:  8000     LRCK error  0.0% */
+    { NRF_I2S_MCK_32MDIV63, NRF_I2S_RATIO_32X},  /* 16000: 15873.016 LRCK error -0.8% */
+    { NRF_I2S_MCK_32MDIV15, NRF_I2S_RATIO_96X},  /* 22050: 22222.222 LRCK error  0.8% */
+    { NRF_I2S_MCK_32MDIV31, NRF_I2S_RATIO_32X},  /* 32000: 32258.065 LRCK error  0.8% */
+    { NRF_I2S_MCK_32MDIV23, NRF_I2S_RATIO_32X},  /* 44100: 43478.261 LRCK error -1.4% */
+    { NRF_I2S_MCK_32MDIV21, NRF_I2S_RATIO_32X}   /* 48000: 47619.048 LRCK error -0.8% */
+};
+
+static const struct i2s_clock_cfg mck_for_24_bit_samples[] = {
+    { NRF_I2S_MCK_32MDIV21, NRF_I2S_RATIO_192X}, /*  8000:  7936.508 LRCK error -0.8% */
+    { NRF_I2S_MCK_32MDIV42, NRF_I2S_RATIO_48X},  /* 16000: 15873.016 LRCK error -0.8% */
+    { NRF_I2S_MCK_32MDIV30, NRF_I2S_RATIO_48X},  /* 22050: 22222.222 LRCK error  0.8% */
+    { NRF_I2S_MCK_32MDIV21, NRF_I2S_RATIO_48X},  /* 32000: 31746.032 LRCK error -0.8% */
+    { NRF_I2S_MCK_32MDIV15, NRF_I2S_RATIO_48X},  /* 44100: 44444.444 LRCK error  0.8% */
+    { NRF_I2S_MCK_32MDIV15, NRF_I2S_RATIO_48X}   /* 48000: 44444.444 LRCK error -7.4% */
+};
+
+static void
+i2s_nrfx_select_clock_cfg(nrfx_i2s_config_t *cfg, uint32_t sample_rate)
+{
+    int i;
+
+    if (cfg->ratio != 0 || cfg->mck_setup != 0) {
+        /* User provided custom clock setup, no need to use stock values */
+        return;
+    }
+    for (i = 0; i < ARRAY_SIZE(sample_rates); ++i) {
+        if (sample_rates[i] == sample_rate) {
+            if (cfg->sample_width == NRF_I2S_SWIDTH_24BIT) {
+                cfg->ratio = mck_for_24_bit_samples[i].ratio;
+                cfg->mck_setup = mck_for_24_bit_samples[i].mck_setup;
+            } else {
+                cfg->ratio = mck_for_8_16_bit_samples[i].ratio;
+                cfg->mck_setup = mck_for_8_16_bit_samples[i].mck_setup;
+            }
+            break;
+        }
+    }
+    assert(cfg->mck_setup);
+}
+
+int
+i2s_driver_start(struct i2s *i2s)
+{
+    int rc = 0;
+
+    if (!i2s_nrfx.running) {
+        i2s_nrfx.running = true;
+        i2s_nrfx_select_clock_cfg(&i2s_nrfx.nrfx_i2s_cfg, i2s->sample_rate);
+        nrfx_i2s_init(&i2s_nrfx.nrfx_i2s_cfg, i2s_nrfx_data_handler);
+
+        assert(i2s_nrfx.nrfx_buffers[0] == NULL);
+        assert(i2s_nrfx.nrfx_buffers[1] == NULL);
+        assert(!STAILQ_EMPTY(&i2s->driver_queue));
+
+        i2s_nrfx.nrfx_queued_count = 0;
+        feed_nrfx();
+    }
+    return rc;
+}
+
+void
+i2s_driver_buffer_queued(struct i2s *i2s)
+{
+    if (i2s_nrfx.nrfx_queued_count < 2 && i2s_nrfx.running) {
+        feed_nrfx();
+    }
+}
+
+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;
+}