ruuvi.drivers.c  ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
ruuvi_nrf5_sdk15_i2c.c
Go to the documentation of this file.
1 
41 #include "ruuvi_interface_i2c.h"
42 #if RUUVI_NRF5_SDK15_I2C_ENABLED
43 #include <stdint.h>
44 #include <string.h> //memcpy
45 
46 #include "ruuvi_boards.h"
47 #include "nrf_drv_twi.h"
48 #include "ruuvi_driver_error.h"
49 #include "ruuvi_interface_gpio.h"
50 #include "ruuvi_interface_yield.h"
51 #include "ruuvi_nrf5_sdk15_gpio.h"
52 #include "ruuvi_nrf5_sdk15_error.h"
53 
54 #ifndef NRF_FIX_TWI_ISSUE_219
55 #define NRF_FIX_TWI_ISSUE_219
56 #endif
57 
58 #ifdef NRF_FIX_TWI_ISSUE_219
59 #define NRF_DRV_TWI_FREQ_390K (0x06200000UL)
60 #endif
61 
62 static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE (I2C_INSTANCE);
63 static bool m_i2c_is_init = false;
64 static volatile bool m_tx_in_progress = false;
65 static volatile ret_code_t xfer_status = NRF_SUCCESS;
66 static uint16_t timeout_us_per_byte = 1000;
67 
68 static nrf_drv_twi_frequency_t ruuvi_to_nrf_frequency (const
69  ri_i2c_frequency_t freq)
70 {
71  switch (freq)
72  {
74  return NRF_DRV_TWI_FREQ_100K;
75 
77  return NRF_DRV_TWI_FREQ_250K;
78 
80  default:
81  return NRF_DRV_TWI_FREQ_400K;
82  }
83 }
84 
85 static void byte_timeout_set (const
86  ri_i2c_frequency_t freq)
87 {
88  switch (freq)
89  {
91  timeout_us_per_byte = 1000;
92 
94  timeout_us_per_byte = 400;
95 
97  default:
98  timeout_us_per_byte = 200;
99  }
100 }
101 
102 #ifdef NRF_FIX_TWI_ISSUE_219
103 static void byte_freq_set (nrf_drv_twi_t const * p_instance,
104  const ri_i2c_frequency_t freq)
105 {
106  NRF_TWI_Type * p_reg_twi = p_instance->u.twi.p_twi;
107  NRF_TWIM_Type * p_reg_twim = p_instance->u.twim.p_twim;
108 
109  if (freq == RI_I2C_FREQUENCY_400k)
110  {
111  if (NRF_DRV_TWI_USE_TWIM) { p_reg_twim->FREQUENCY = NRF_DRV_TWI_FREQ_390K; }
112  else { p_reg_twi->FREQUENCY = NRF_DRV_TWI_FREQ_390K; }
113  }
114 }
115 #endif
116 
117 static void on_complete (nrf_drv_twi_evt_t const * p_event, void * p_context)
118 {
119  m_tx_in_progress = false;
120 
121  if (p_event->type == NRF_DRV_TWI_EVT_ADDRESS_NACK) { xfer_status |= NRF_ERROR_NOT_FOUND; }
122  else if (p_event->type == NRF_DRV_TWI_EVT_DATA_NACK) { xfer_status |= NRF_ERROR_DRV_TWI_ERR_DNACK; }
123  else if (p_event->type != NRF_DRV_TWI_EVT_DONE) { xfer_status |= NRF_ERROR_INTERNAL; }
124 }
125 
127  config)
128 {
129  ret_code_t err_code;
130  nrf_drv_twi_frequency_t frequency = ruuvi_to_nrf_frequency (config->frequency);
131  byte_timeout_set (config->frequency);
132  const nrf_drv_twi_config_t twi_config =
133  {
134  .scl = ruuvi_to_nrf_pin_map (config->scl),
135  .sda = ruuvi_to_nrf_pin_map (config->sda),
136  .frequency = frequency,
137  .interrupt_priority = APP_IRQ_PRIORITY_LOW,
138  .clear_bus_init = true
139  };
140  // Verify that lines can be pulled up
145  ri_gpio_state_t state_scl, state_sda;
146  ri_delay_us (1000);
147  ri_gpio_read (config->sda, &state_sda);
148  ri_gpio_read (config->scl, &state_scl);
149 
150  if (RI_GPIO_HIGH != state_sda ||
151  RI_GPIO_HIGH != state_scl)
152  {
153  return RD_ERROR_INTERNAL;
154  }
155 
156  err_code = nrf_drv_twi_init (&m_twi, &twi_config, on_complete, NULL);
157 #ifdef NRF_FIX_TWI_ISSUE_219
158  byte_freq_set (&m_twi, config->frequency);
159 #endif
160  nrf_drv_twi_enable (&m_twi);
161  m_i2c_is_init = true;
162  m_tx_in_progress = false;
163  return ruuvi_nrf5_sdk15_to_ruuvi_error (err_code);
164 }
165 
166 bool ri_i2c_is_init()
167 {
168  return m_i2c_is_init;
169 }
170 
177 {
178  nrf_drv_twi_disable (&m_twi);
179  nrf_drv_twi_uninit (&m_twi);
180  return RD_SUCCESS;
181 }
182 
183 
193 rd_status_t ri_i2c_write_blocking (const uint8_t address,
194  uint8_t * const p_tx, const size_t tx_len, const bool stop)
195 {
196  if (!m_i2c_is_init) { return RD_ERROR_INVALID_STATE; }
197 
198  if (NULL == p_tx) { return RD_ERROR_NULL; }
199 
200  if (m_tx_in_progress) { return RD_ERROR_BUSY; }
201 
202  int32_t err_code = NRF_SUCCESS;
203  m_tx_in_progress = true;
204  err_code |= nrf_drv_twi_tx (&m_twi, address, p_tx, tx_len, !stop);
205  volatile uint32_t timeout = 0;
206 
207  while (m_tx_in_progress && timeout < (timeout_us_per_byte * tx_len))
208  {
209  timeout++;
210  ri_delay_us (1);
211  }
212 
213  if (timeout >= (timeout_us_per_byte * tx_len)) { err_code |= NRF_ERROR_TIMEOUT; }
214 
215  err_code |= xfer_status;
216  xfer_status = NRF_SUCCESS;
217  return ruuvi_nrf5_sdk15_to_ruuvi_error (err_code);
218 }
219 
231 rd_status_t ri_i2c_read_blocking (const uint8_t address,
232  uint8_t * const p_rx, const size_t rx_len)
233 {
234  if (!m_i2c_is_init) { return RD_ERROR_INVALID_STATE; }
235 
236  if (NULL == p_rx) { return RD_ERROR_NULL; }
237 
238  int32_t err_code = NRF_SUCCESS;
239  m_tx_in_progress = true;
240  err_code |= nrf_drv_twi_rx (&m_twi, address, p_rx, rx_len);
241  volatile uint32_t timeout = 0;
242 
243  while (m_tx_in_progress && timeout < (timeout_us_per_byte * rx_len))
244  {
245  timeout++;
246  ri_delay_us (1);
247  }
248 
249  if (timeout >= (timeout_us_per_byte * rx_len)) { err_code |= NRF_ERROR_TIMEOUT; }
250 
251  err_code |= xfer_status;
252  xfer_status = NRF_SUCCESS;
253  return ruuvi_nrf5_sdk15_to_ruuvi_error (err_code);
254 }
255 
256 #endif
#define RD_ERROR_NULL
Null Pointer.
uint32_t rd_status_t
bitfield for representing errors
rd_status_t ruuvi_nrf5_sdk15_to_ruuvi_error(const ret_code_t error)
convert nrf5 sdk15 error code into Ruuvi error code.
#define RD_SUCCESS
Internal Error.
#define RD_ERROR_INVALID_STATE
Invalid state, operation disallowed in this state.
#define RD_ERROR_INTERNAL
Internal Error.
#define RD_ERROR_BUSY
Busy.
rd_status_t ri_gpio_configure(const ri_gpio_id_t pin, const ri_gpio_mode_t mode)
Configure a pin of a port into a mode. If there are several ports the platform driver must implement ...
rd_status_t ri_gpio_read(const ri_gpio_id_t pin, ri_gpio_state_t *const p_state)
Read state of a pin of a port into bool high If there are several ports the platform driver must impl...
rd_status_t ri_gpio_write(const ri_gpio_id_t pin, const ri_gpio_state_t state)
Write a pin of a port into given state If there are several ports the platform driver must implement ...
Header to enable and disable module compilation.
Ruuvi error codes and error check function.
@ RI_GPIO_MODE_INPUT_PULLUP
Input, can be read. Pulled up by internal resistor, value depends on IC.
@ RI_GPIO_MODE_OUTPUT_HIGHDRIVE
Push-pull output, can be written. Higher current drive than standard.
ri_gpio_state_t
States of GPIO pins.
@ RI_GPIO_HIGH
GPIO electrically high.
Interface for I2C operations.
rd_status_t ri_i2c_init(const ri_i2c_init_config_t *const config)
Initialize I2C driver with given settings.
rd_status_t ri_i2c_write_blocking(const uint8_t address, uint8_t *const p_tx, const size_t tx_len, const bool stop)
I2C read function.
bool ri_i2c_is_init()
Check if i2c driver is initialized.
rd_status_t ri_i2c_uninit(void)
Uninitialize I2C.
ri_i2c_frequency_t
@ RI_I2C_FREQUENCY_250k
250 kbps.
@ RI_I2C_FREQUENCY_400k
400 kbps.
@ RI_I2C_FREQUENCY_100k
100 kbps.
rd_status_t ri_i2c_read_blocking(const uint8_t address, uint8_t *const p_rx, const size_t rx_len)
I2C read function.
rd_status_t ri_delay_us(uint32_t time)
Delay a given number of microseconds.
ri_gpio_id_t bus_pwr
Power to pull-ups, UNUSED if fixed.
ri_gpio_id_t sda
pin number of SDA
ri_i2c_frequency_t frequency
Frequency of I2C Bus, see ri_i2c_frequency_t.
ri_gpio_id_t scl
pin number of SCL