-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdwhw.c
211 lines (177 loc) · 4.45 KB
/
dwhw.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/*
* libdeca - UWB Library for Qorvo/Decawave DW3000
*
* Copyright (C) 2016 - 2024 Bruno Randolf ([email protected])
*
* This source code is licensed under the GNU Lesser General Public License,
* Version 3. See the file LICENSE.txt for more details.
*/
#include <inttypes.h>
#include <deca_device_api.h>
#include <deca_version.h>
#ifdef DW3000_DRIVER_VERSION // == 0x040000
#include <deca_regs.h>
#endif
#include <dw3000_hw.h>
#include <dw3000_spi.h>
#include "dwhw.h"
#include "dwmac.h"
#include "log.h"
#define DWHW_DEBUG_WAKEUP 0
#ifdef DRIVER_VERSION_HEX // >= 0x060007
extern const struct dwt_probe_s dw3000_probe_interf;
#endif
#ifndef __ZEPHYR__
static const char* LOG_TAG = "DECA";
#endif
static bool dwchip_ready = false;
static float last_calib_temp;
static void dwhw_update_calib_temp(void)
{
uint16_t tv = dwt_readtempvbat();
last_calib_temp = dwt_convertrawtemperature(tv >> 8);
}
bool dwhw_init(void)
{
int ret;
#if DRIVER_VERSION_HEX >= 0x080202
LOG_INF("Decadriver source: " DRIVER_VERSION_STR);
#elif defined(DRIVER_VERSION_HEX)
LOG_INF("Decadriver lib: " DRIVER_VERSION_STR);
#else
LOG_INF("Decadriver source: " DW3000_DEVICE_DRIVER_VER_STRING);
#endif
#ifdef DRIVER_VERSION_HEX // >= 0x060007
ret = dwt_probe((struct dwt_probe_s*)&dw3000_probe_interf);
if (ret < 0) {
LOG_ERR("DWT Probe failed");
return false;
}
#endif
#if DRIVER_VERSION_HEX >= 0x080202
ret = dwt_initialise(DWT_READ_OTP_PID | DWT_READ_OTP_LID | DWT_READ_OTP_BAT
| DWT_READ_OTP_TMP);
#else
ret = dwt_initialise(DWT_DW_INIT)
#endif
if (ret == DWT_ERROR) {
LOG_ERR("INIT failed");
return false;
}
int cnt = 1000;
while (!dwt_checkidlerc() && cnt-- > 0) {
deca_sleep(1);
}
if (cnt <= 0) {
LOG_ERR("Init did not leave IDLE state");
return false;
}
uint32_t dev_id = dwt_readdevid();
ret = dwt_check_dev_id();
if (ret != DWT_SUCCESS) {
LOG_ERR("UNKNOWN DEV ID: %" PRIX32, dev_id);
return false;
} else {
LOG_INF("DEV ID: %" PRIX32, dev_id);
}
// dwt_setleds(DWT_LEDS_ENABLE | DWT_LEDS_INIT_BLINK);
dw3000_spi_speed_fast();
// assume dwphy_init() is run soon!
dwhw_update_calib_temp();
dwchip_ready = true;
return true;
}
void dwhw_configure_sleep(void)
{
/* Sleep configuration:
* - run RX calibration (PGFCAL)
* - restore config
* - wakeup on CS pin
* - wakeup on WAKEUP
* - enable deep sleep */
dwt_configuresleep(DWT_PGFCAL | DWT_CONFIG,
DWT_SLP_EN | DWT_WAKE_CSN | DWT_WAKE_WUP);
}
void dwhw_enable_tx_interrupt(bool on)
{
dwt_setinterrupt(
#ifdef DRIVER_VERSION_HEX // >= 0x060007
DWT_INT_TXFRS_BIT_MASK,
#else
DWT_INT_TFRS,
#endif
0, on ? DWT_ENABLE_INT : DWT_DISABLE_INT);
}
void dwhw_sleep(void)
{
if (!dwchip_ready) {
LOG_ERR("not present or already sleeping");
return;
}
LOG_INF("Sleep");
dwchip_ready = false;
/* pull WAKEUP line low, later we will use it for waking up */
dw3000_hw_wakeup_pin_low();
dwt_entersleep(DWT_DW_IDLE);
/* While in DEEPSLEEP power should not be applied to GPIO, SPICLK or
SPIMISO pins as this will cause an increase in leakage current */
dw3000_spi_fini();
}
bool dwhw_wakeup(void)
{
if (dwchip_ready) {
LOG_ERR("Already woke up?");
return false;
}
dw3000_spi_init();
dw3000_hw_wakeup();
#if DRIVER_VERSION_HEX >= 0x080202
dwt_restoreconfig(1);
#else
dwt_restoreconfig();
#endif
int ret = dwt_check_dev_id();
if (ret != DWT_SUCCESS) {
LOG_ERR("Failed to read device ID after wakeup!");
return false;
}
/* Wait for device to become ready (IDLE state) */
int cnt = 1000;
while (!dwt_checkidlerc() && cnt-- > 0) {
deca_sleep(1);
}
if (cnt <= 0) {
LOG_ERR("Wakeup did not leave IDLE state");
return false;
}
dw3000_spi_speed_fast();
dwmac_cleanup_sleep_after_tx();
#if DWHW_DEBUG_WAKEUP
LOG_INF("WAKEUP STATE %" PRIx32 " STATUS %" PRIx32 " ENABLE %" PRIx32,
dwt_read32bitreg(SYS_STATE_LO_ID), dwt_read32bitreg(SYS_STATUS_ID),
dwt_read32bitreg(SYS_ENABLE_LO_ID));
#endif
dwhw_update_calib_temp(); // DWT_PGFCAL was set
dwchip_ready = true;
return true;
}
bool dwhw_is_ready(void)
{
return dwchip_ready;
}
void dwhw_sleep_after_tx(void)
{
dwchip_ready = false;
dw3000_spi_fini();
}
void dwhw_calib_if_temp_change(void)
{
uint16_t tv = dwt_readtempvbat();
float temp = dwt_convertrawtemperature(tv >> 8);
LOG_INF("TEMP %.2f last %.2f", (double)temp, (double)last_calib_temp);
if (temp >= last_calib_temp + 20.0f || temp <= last_calib_temp - 20.0f) {
LOG_WARN("Temperature changed by 20deg, calibrating");
last_calib_temp = temp;
dwt_pgf_cal(1);
}
}