You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ma...@apache.org on 2016/11/19 01:55:53 UTC
incubator-mynewt-core git commit: nrf51 i2c;
implement driver without using nordic's SDK.
Repository: incubator-mynewt-core
Updated Branches:
refs/heads/1_0_0_b1_dev e4b6b6819 -> 183dff92c
nrf51 i2c; implement driver without using nordic's SDK.
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/183dff92
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/183dff92
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/183dff92
Branch: refs/heads/1_0_0_b1_dev
Commit: 183dff92ce64817f3b2d53b180fe87a7a4cb609e
Parents: e4b6b68
Author: Marko Kiiskila <ma...@runtime.io>
Authored: Fri Nov 18 17:55:08 2016 -0800
Committer: Marko Kiiskila <ma...@runtime.io>
Committed: Fri Nov 18 17:55:08 2016 -0800
----------------------------------------------------------------------
hw/mcu/nordic/nrf51xxx/src/hal_i2c.c | 388 +++++++++++++++++++++---------
1 file changed, 277 insertions(+), 111 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/183dff92/hw/mcu/nordic/nrf51xxx/src/hal_i2c.c
----------------------------------------------------------------------
diff --git a/hw/mcu/nordic/nrf51xxx/src/hal_i2c.c b/hw/mcu/nordic/nrf51xxx/src/hal_i2c.c
index ed651b2..394a325 100644
--- a/hw/mcu/nordic/nrf51xxx/src/hal_i2c.c
+++ b/hw/mcu/nordic/nrf51xxx/src/hal_i2c.c
@@ -17,89 +17,227 @@
* under the License.
*/
-#include <hal/hal_i2c.h>
#include <string.h>
#include <errno.h>
+#include <limits.h>
+#include <assert.h>
+
+#include <os/os_time.h>
+
#include "syscfg/syscfg.h"
-#include <nrf.h>
-#include <nrf_drv_twi.h>
+#include <hal/hal_i2c.h>
+#include <hal/hal_gpio.h>
#include <mcu/nrf51_hal.h>
-#include <assert.h>
-struct nrf51_hal_i2c {
- nrf_drv_twi_t nhi_nrf_master;
-};
+#include <nrf.h>
#define NRF51_HAL_I2C_MAX (2)
+#define NRF51_SCL_PIN_CONF \
+ ((GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | \
+ (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) | \
+ (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) | \
+ (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | \
+ (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos))
+#define NRF51_SDA_PIN_CONF NRF51_SCL_PIN_CONF
+
+#define NRF51_HAL_I2C_RESOLVE(__n, __v) \
+ if ((__n) >= NRF51_HAL_I2C_MAX) { \
+ rc = EINVAL; \
+ goto err; \
+ } \
+ (__v) = (struct nrf51_hal_i2c *) nrf51_hal_i2cs[(__n)]; \
+ if ((__v) == NULL) { \
+ rc = EINVAL; \
+ goto err; \
+ }
+
+struct nrf51_hal_i2c {
+ NRF_TWI_Type *nhi_regs;
+};
+
#if MYNEWT_VAL(I2C_0)
-struct nrf51_hal_i2c hal_twi_i2c0 = {NRF_DRV_TWI_INSTANCE(0)};
+struct nrf51_hal_i2c hal_twi_i2c0 = {
+ .nhi_regs = NRF_TWI0
+};
#endif
#if MYNEWT_VAL(I2C_1)
-struct nrf51_hal_i2c hal_twi_i2c1 = {NRF_DRV_TWI_INSTANCE(1)};
+struct nrf51_hal_i2c hal_twi_i2c1 = {
+ .nhi_regs = NRF_TWI1
+};
#endif
static const struct nrf51_hal_i2c *nrf51_hal_i2cs[NRF51_HAL_I2C_MAX] = {
#if MYNEWT_VAL(I2C_0)
- &hal_twi_i2c0,
+ &hal_twi_i2c0,
#else
- NULL,
+ NULL,
#endif
#if MYNEWT_VAL(I2C_1)
- &hal_twi_i2c1
+ &hal_twi_i2c1
#else
- NULL
+ NULL
#endif
};
-#define NRF51_HAL_I2C_RESOLVE(__n, __v) \
- if ((__n) >= NRF51_HAL_I2C_MAX) { \
- rc = EINVAL; \
- goto err; \
- } \
- (__v) = (struct nrf51_hal_i2c *) nrf51_hal_i2cs[(__n)]; \
- if ((__v) == NULL) { \
- rc = EINVAL; \
- goto err; \
+static void
+hal_i2c_delay_us(uint32_t number_of_us)
+{
+register uint32_t delay __ASM ("r0") = number_of_us;
+__ASM volatile (
+#ifdef NRF51
+ ".syntax unified\n"
+#endif
+ "1:\n"
+ " SUBS %0, %0, #1\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+#ifdef NRF52
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+ " NOP\n"
+#endif
+ " BNE 1b\n"
+#ifdef NRF51
+ ".syntax divided\n"
+#endif
+ : "+r" (delay));
+}
+
+/*
+ * Clear the bus after reset by clocking 9 bits manually.
+ * This should reset state from (most of) the devices on the other end.
+ */
+static void
+hal_i2c_clear_bus(struct nrf51_hal_i2c_cfg *cfg)
+{
+ int i;
+
+ hal_gpio_init_out(cfg->scl_pin, 1);
+ hal_gpio_init_in(cfg->sda_pin, HAL_GPIO_PULL_UP);
+
+ hal_i2c_delay_us(4);
+
+ for (i = 0; i < 9; i++) {
+ if (hal_gpio_read(cfg->sda_pin)) {
+ if (i == 0) {
+ /*
+ * Nothing to do here.
+ */
+ return;
+ } else {
+ break;
+ }
+ hal_gpio_write(cfg->scl_pin, 0);
+ hal_i2c_delay_us(4);
+ hal_gpio_write(cfg->sda_pin, 1);
+ hal_i2c_delay_us(4);
+ }
}
+ /*
+ * Send STOP.
+ */
+ hal_gpio_write(cfg->sda_pin, 0);
+ hal_i2c_delay_us(4);
+ hal_gpio_write(cfg->sda_pin, 1);
+}
+
int
hal_i2c_init(uint8_t i2c_num, void *usercfg)
{
struct nrf51_hal_i2c *i2c;
- struct nrf51_hal_i2c_cfg *i2c_cfg;
- nrf_drv_twi_config_t cfg;
+ NRF_TWI_Type *regs;
+ struct nrf51_hal_i2c_cfg *cfg;
+ uint32_t freq;
int rc;
assert(usercfg != NULL);
NRF51_HAL_I2C_RESOLVE(i2c_num, i2c);
- i2c_cfg = (struct nrf51_hal_i2c_cfg *) usercfg;
-
- cfg.scl = i2c_cfg->scl_pin;
- cfg.sda = i2c_cfg->sda_pin;
- switch (i2c_cfg->i2c_frequency) {
- case 100:
- cfg.frequency = NRF_TWI_FREQ_100K;
- break;
- case 250:
- cfg.frequency = NRF_TWI_FREQ_250K;
- break;
- case 400:
- cfg.frequency = NRF_TWI_FREQ_400K;
- break;
- default:
- rc = EINVAL;
- goto err;
- }
-
- rc = nrf_drv_twi_init(&i2c->nhi_nrf_master, &cfg, NULL, NULL);
- if (rc != 0) {
+ cfg = (struct nrf51_hal_i2c_cfg *) usercfg;
+ regs = i2c->nhi_regs;
+
+ switch (cfg->i2c_frequency) {
+ case 100:
+ freq = TWI_FREQUENCY_FREQUENCY_K100;
+ break;
+ case 250:
+ freq = TWI_FREQUENCY_FREQUENCY_K250;
+ break;
+ case 400:
+ freq = TWI_FREQUENCY_FREQUENCY_K400;
+ break;
+ default:
+ rc = EINVAL;
goto err;
}
- nrf_drv_twi_enable(&i2c->nhi_nrf_master);
+ NRF_GPIO->PIN_CNF[cfg->scl_pin] = NRF51_SCL_PIN_CONF;
+ NRF_GPIO->PIN_CNF[cfg->sda_pin] = NRF51_SDA_PIN_CONF;
+ hal_i2c_clear_bus(cfg);
+
+ NRF_GPIO->PIN_CNF[cfg->scl_pin] = NRF51_SCL_PIN_CONF;
+ NRF_GPIO->PIN_CNF[cfg->sda_pin] = NRF51_SDA_PIN_CONF;
+
+ regs->PSELSCL = cfg->scl_pin;
+ regs->PSELSDA = cfg->sda_pin;
+ regs->FREQUENCY = freq;
+ regs->ENABLE = TWI_ENABLE_ENABLE_Enabled;
return (0);
err:
@@ -111,26 +249,59 @@ hal_i2c_master_write(uint8_t i2c_num, struct hal_i2c_master_data *pdata,
uint32_t timo, uint8_t last_op)
{
struct nrf51_hal_i2c *i2c;
- bool no_stop;
+ NRF_TWI_Type *regs = NULL;
int rc;
+ int i;
+ uint32_t start;
NRF51_HAL_I2C_RESOLVE(i2c_num, i2c);
-
- /* If last_op is zero it means we dont put a stop at end. */
- if (last_op == 0) {
- no_stop = true;
- } else {
- no_stop = false;
+ regs = i2c->nhi_regs;
+
+ regs->ADDRESS = pdata->address;
+
+ regs->EVENTS_ERROR = 0;
+ regs->EVENTS_STOPPED = 0;
+ regs->EVENTS_SUSPENDED = 0;
+ regs->SHORTS = 0;
+
+ regs->TASKS_STARTTX = 1;
+ regs->TASKS_RESUME = 1;
+
+ start = os_time_get();
+ for (i = 0; i < pdata->len; i++) {
+ regs->EVENTS_TXDSENT = 0;
+ regs->TXD = pdata->buffer[i];
+ while (!regs->EVENTS_TXDSENT && !regs->EVENTS_ERROR) {
+ if (os_time_get() - start > timo) {
+ rc = -1;
+ regs->TASKS_STOP = 1;
+ goto err;
+ }
+ }
+ if (regs->EVENTS_ERROR) {
+ goto err;
+ }
}
-
- rc = nrf_drv_twi_tx(&i2c->nhi_nrf_master, pdata->address, pdata->buffer,
- pdata->len, no_stop);
- if (rc != 0) {
- goto err;
+ /* If last_op is zero it means we dont put a stop at end. */
+ if (last_op) {
+ regs->EVENTS_STOPPED = 0;
+ regs->TASKS_STOP = 1;
+ while (!regs->EVENTS_STOPPED && !regs->EVENTS_ERROR) {
+ if (os_time_get() - start > timo) {
+ rc = -1;
+ goto err;
+ }
+ }
+ if (regs->EVENTS_ERROR) {
+ goto err;
+ }
}
-
return (0);
err:
+ if (regs && regs->EVENTS_ERROR) {
+ rc = regs->ERRORSRC;
+ regs->ERRORSRC = rc;
+ }
return (rc);
}
@@ -139,73 +310,68 @@ hal_i2c_master_read(uint8_t i2c_num, struct hal_i2c_master_data *pdata,
uint32_t timo, uint8_t last_op)
{
struct nrf51_hal_i2c *i2c;
- bool no_stop;
- int rc;
+ NRF_TWI_Type *regs = NULL;
+ int rc = -1;
+ int i;
+ uint32_t start;
NRF51_HAL_I2C_RESOLVE(i2c_num, i2c);
+ regs = i2c->nhi_regs;
- if (last_op) {
- no_stop = false;
- } else {
- no_stop = true;
- }
+ start = os_time_get();
- rc = nrf_drv_twi_rx_ext(&i2c->nhi_nrf_master, pdata->address, pdata->buffer,
- pdata->len, no_stop);
- if (rc != 0) {
- goto err;
- }
+ regs->EVENTS_ERROR = 0;
+ regs->EVENTS_STOPPED = 0;
+ regs->EVENTS_SUSPENDED = 0;
+ regs->EVENTS_RXDREADY = 0;
- return (0);
-err:
- return (rc);
-}
-
-int
-hal_i2c_master_begin(uint8_t i2c_num)
-{
- return (0);
-}
-
-int
-hal_i2c_master_end(uint8_t i2c_num)
-{
- struct nrf51_hal_i2c *i2c;
- int rc;
-
- NRF51_HAL_I2C_RESOLVE(i2c_num, i2c);
-
- /**
- * XXX: Nordic doesn't provide a function for generating the stop
- * character, and I don't trust issue'ing nrf_drv_twi_tx() with NULL
- * data, and 0 length, so directly use the stop task in HAL driver.
- * This is subject to break as NRF SDK is updated, as reg.p_twi is
- * private, however, seems like it will be reasonably easy to spot.
- * Famous last words.
- */
- nrf_twi_task_trigger(i2c->nhi_nrf_master.reg.p_twi, NRF_TWI_TASK_RESUME);
- nrf_twi_task_trigger(i2c->nhi_nrf_master.reg.p_twi, NRF_TWI_TASK_STOP);
+ regs->ADDRESS = pdata->address;
+ if (pdata->len == 1 && last_op) {
+ regs->SHORTS = TWI_SHORTS_BB_STOP_Msk;
+ } else {
+ regs->SHORTS = TWI_SHORTS_BB_SUSPEND_Msk;
+ }
+ regs->TASKS_STARTRX = 1;
+
+ for (i = 0; i < pdata->len; i++) {
+ regs->TASKS_RESUME = 1;
+
+ while (!regs->EVENTS_RXDREADY && !regs->EVENTS_ERROR) {
+ if (os_time_get() - start > timo) {
+ regs->SHORTS = TWI_SHORTS_BB_STOP_Msk;
+ goto err;
+ }
+ }
+ if (regs->EVENTS_ERROR) {
+ goto err;
+ }
+ pdata->buffer[i] = regs->RXD;
+ if (i == pdata->len - 2) {
+ if (last_op) {
+ regs->SHORTS = TWI_SHORTS_BB_STOP_Msk;
+ }
+ }
+ regs->EVENTS_RXDREADY = 0;
+ }
return (0);
err:
+ if (regs && regs->EVENTS_ERROR) {
+ rc = regs->ERRORSRC;
+ regs->ERRORSRC = rc;
+ }
return (rc);
}
int
hal_i2c_master_probe(uint8_t i2c_num, uint8_t address, uint32_t timo)
{
- struct nrf51_hal_i2c *i2c;
+ struct hal_i2c_master_data rx;
uint8_t buf;
- int rc;
-
- NRF51_HAL_I2C_RESOLVE(i2c_num, i2c);
- rc = nrf_drv_twi_rx(&i2c->nhi_nrf_master, address, &buf, 1);
- if (rc != 0) {
- goto err;
- }
+ rx.address = address;
+ rx.buffer = &buf;
+ rx.len = 1;
- return (0);
-err:
- return (rc);
+ return hal_i2c_master_read(i2c_num, &rx, timo, 1);
}