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 2020/04/25 07:58:06 UTC

[mynewt-core] branch master updated: hw/drivers/i2s: Add I2S driver for NRF52 family

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


The following commit(s) were added to refs/heads/master by this push:
     new fd33ea1  hw/drivers/i2s: Add I2S driver for NRF52 family
fd33ea1 is described below

commit fd33ea1c98c2bc1d658254c7a9fbc4aa7264374f
Author: Jerzy Kasenberg <je...@codecoup.pl>
AuthorDate: Fri Apr 10 16:25:40 2020 +0200

    hw/drivers/i2s: Add I2S driver for NRF52 family
    
    I2S driver implementation for NRF52 MCUs.
---
 .../i2s/i2s_nrf52/include/i2s_nrf52/i2s_nrf52.h    |  37 ++++
 hw/drivers/i2s/i2s_nrf52/pkg.yml                   |  29 +++
 hw/drivers/i2s/i2s_nrf52/src/i2s_nrf52.c           | 235 +++++++++++++++++++++
 hw/drivers/i2s/i2s_nrf52/syscfg.yml                |  19 ++
 4 files changed, 320 insertions(+)

diff --git a/hw/drivers/i2s/i2s_nrf52/include/i2s_nrf52/i2s_nrf52.h b/hw/drivers/i2s/i2s_nrf52/include/i2s_nrf52/i2s_nrf52.h
new file mode 100644
index 0000000..2e5f3d6
--- /dev/null
+++ b/hw/drivers/i2s/i2s_nrf52/include/i2s_nrf52/i2s_nrf52.h
@@ -0,0 +1,37 @@
+/*
+ * 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_NRF52_H
+#define _I2S_NRF52_H
+
+#include <stdint.h>
+#include <nrfx/nrfx.h>
+#include <nrfx/drivers/include/nrfx_i2s.h>
+
+struct i2s;
+
+struct i2s_cfg {
+    nrfx_i2s_config_t nrfx_i2s_cfg;
+
+    uint32_t sample_rate;
+
+    struct i2s_buffer_pool *pool;
+};
+
+#endif /* _I2S_NRF52_H */
diff --git a/hw/drivers/i2s/i2s_nrf52/pkg.yml b/hw/drivers/i2s/i2s_nrf52/pkg.yml
new file mode 100644
index 0000000..14bae07
--- /dev/null
+++ b/hw/drivers/i2s/i2s_nrf52/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_nrf52
+pkg.description: I2S driver for NRF52
+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_nrf52/src/i2s_nrf52.c b/hw/drivers/i2s/i2s_nrf52/src/i2s_nrf52.c
new file mode 100644
index 0000000..ea39f81
--- /dev/null
+++ b/hw/drivers/i2s/i2s_nrf52/src/i2s_nrf52.c
@@ -0,0 +1,235 @@
+/*
+ * 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_nrf52/i2s_nrf52.h>
+#include <nrfx/drivers/include/nrfx_i2s.h>
+
+struct nrf52_i2s {
+    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 nrf52_i2s nrf52_i2s;
+
+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(nrf52_i2s.nrfx_queued_count < 2);
+    assert(nrf52_i2s.nrfx_buffers[nrf52_i2s.nrfx_queued_count] == NULL);
+
+    nrf52_i2s.nrfx_buffers[nrf52_i2s.nrfx_queued_count] = buffer;
+    nrf52_i2s.nrfx_queued_count++;
+    if (nrf52_i2s.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(nrf52_i2s.i2s);
+    nrfx_add_buffer(nrf52_i2s.i2s, buffer);
+}
+
+static void
+nrf52_i2s_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)) {
+        nrf52_i2s.nrfx_queued_count--;
+        assert(nrf52_i2s.nrfx_queued_count >= 0);
+        buffer = nrf52_i2s.nrfx_buffers[0];
+        assert(buffer->sample_data == p_released->p_tx_buffer || buffer->sample_data == p_released->p_rx_buffer);
+        nrf52_i2s.nrfx_buffers[0] = nrf52_i2s.nrfx_buffers[1];
+        nrf52_i2s.nrfx_buffers[1] = NULL;
+        i2s_driver_buffer_put(nrf52_i2s.i2s, buffer);
+    }
+    if (nrf52_i2s.running && nrf52_i2s.nrfx_queued_count < 2) {
+        assert(nrf52_i2s.nrfx_buffers[1] == NULL);
+        feed_nrfx();
+    }
+    if (status == NRFX_I2S_STATUS_TRANSFER_STOPPED) {
+        i2s_driver_state_changed(nrf52_i2s.i2s, I2S_STATE_STOPPED);
+    }
+}
+
+static int
+nrf52_i2s_init(struct i2s *i2s, const struct i2s_cfg *cfg)
+{
+    int rc;
+
+    nrf52_i2s.i2s = i2s;
+
+    NVIC_SetVector(nrfx_get_irq_number(NRF_I2S), (uint32_t) nrfx_i2s_irq_handler);
+
+    nrf52_i2s.nrfx_i2s_cfg = cfg->nrfx_i2s_cfg;
+    switch (cfg->nrfx_i2s_cfg.sample_width) {
+    case NRF_I2S_SWIDTH_8BIT:
+        i2s->sample_size_in_bytes = 1;
+        break;
+    case NRF_I2S_SWIDTH_16BIT:
+        i2s->sample_size_in_bytes = 2;
+        break;
+    case NRF_I2S_SWIDTH_24BIT:
+        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 = &nrf52_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)nrf52_i2s_init, (void *)cfg);
+}
+
+int
+i2s_driver_stop(struct i2s *i2s)
+{
+    struct i2s_sample_buffer *buffer;
+
+    nrf52_i2s.running = false;
+    nrfx_i2s_stop();
+
+    assert(nrf52_i2s.i2s->state == I2S_STATE_STOPPED);
+
+    while (NULL != (buffer = i2s_driver_buffer_get(i2s))) {
+        i2s_driver_buffer_put(i2s, buffer);
+    }
+
+    return 0;
+}
+
+static void
+nrf52_select_i2s_clock_cfg(nrfx_i2s_config_t *cfg, uint32_t sample_rate)
+{
+    cfg->ratio = NRF_I2S_RATIO_32X;
+    switch (sample_rate) {
+    case 16000:
+        cfg->mck_setup = NRF_I2S_MCK_32MDIV63;
+        break;
+    case 22500:
+        cfg->mck_setup = NRF_I2S_MCK_32MDIV42;
+        break;
+    case 32000:
+        cfg->mck_setup = NRF_I2S_MCK_32MDIV31;
+        break;
+    case 441000:
+        cfg->mck_setup = NRF_I2S_MCK_32MDIV23;
+        break;
+    case 48000:
+        cfg->ratio = NRF_I2S_RATIO_48X;
+        cfg->mck_setup = NRF_I2S_MCK_32MDIV21;
+        break;
+    default:
+        assert(0);
+        cfg->mck_setup = NRF_I2S_MCK_32MDIV63;
+    }
+}
+
+int
+i2s_driver_start(struct i2s *i2s)
+{
+    int rc = 0;
+
+    if (!nrf52_i2s.running) {
+        nrf52_i2s.running = true;
+        nrf52_select_i2s_clock_cfg(&nrf52_i2s.nrfx_i2s_cfg, i2s->sample_rate);
+        nrfx_i2s_init(&nrf52_i2s.nrfx_i2s_cfg, nrf52_i2s_data_handler);
+
+        assert(nrf52_i2s.nrfx_buffers[0] == NULL);
+        assert(nrf52_i2s.nrfx_buffers[1] == NULL);
+        assert(!STAILQ_EMPTY(&i2s->driver_queue));
+
+        nrf52_i2s.nrfx_queued_count = 0;
+        feed_nrfx();
+    }
+    return rc;
+}
+
+void
+i2s_driver_buffer_queued(struct i2s *i2s)
+{
+    if (nrf52_i2s.nrfx_queued_count < 2 && nrf52_i2s.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;
+}
diff --git a/hw/drivers/i2s/i2s_nrf52/syscfg.yml b/hw/drivers/i2s/i2s_nrf52/syscfg.yml
new file mode 100644
index 0000000..2cdd574
--- /dev/null
+++ b/hw/drivers/i2s/i2s_nrf52/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: