Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Sep 10, 2024. It is now read-only.

Commit c993a7f

Browse files
committed
support wake from accelerometer (v16)
lots of changes inside: - use LAT instead of PORT from writing - refactor write_byte(), read_byte(), write_bit(), read_bit() - check usb product ID in init() - remove "wake_int" which is only for Pysense1 (RA5) - refactor "wake_int_pin", which is for RC1 - add attempt to wake PIC from RC1 if it is not available in init() - rewrite go_to_sleep() and add support for new CMD_GO_NAP command - require FW v16 in init()
1 parent a28c43e commit c993a7f

File tree

2 files changed

+249
-83
lines changed

2 files changed

+249
-83
lines changed

pysense-2/lib/pycoproc.py

Lines changed: 128 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,21 @@ class Pycoproc:
3232
CMD_POKE = const(0x01)
3333
CMD_MAGIC = const(0x02)
3434
CMD_HW_VER = const(0x10)
35-
CMD_FW_VER = const(0x11)
36-
CMD_PROD_ID = const(0x12)
35+
CMD_FW_VER = const(0x11) #define SW_VERSION (15)
36+
CMD_PROD_ID = const(0x12) #USB product ID, e.g. PYSENSE (0xF012)
3737
CMD_SETUP_SLEEP = const(0x20)
3838
CMD_GO_SLEEP = const(0x21)
3939
CMD_CALIBRATE = const(0x22)
40+
CMD_GO_NAP = const(0x23)
4041
CMD_BAUD_CHANGE = const(0x30)
4142
CMD_DFU = const(0x31)
4243
CMD_RESET = const(0x40)
44+
# CMD_GO_NAP options
45+
SD_CARD_OFF = const(0x1)
46+
SENSORS_OFF = const(0x2)
47+
ACCELEROMETER_OFF = const(0x4)
48+
FIPY_OFF = const(0x8)
49+
4350

4451
REG_CMD = const(0)
4552
REG_ADDRL = const(1)
@@ -62,17 +69,26 @@ class Pycoproc:
6269
OPTION_REG_ADDR = const(0x95)
6370

6471
_ADCON0_CHS_POSN = const(0x02)
72+
_ADCON0_CHS_AN5 = const(0x5) # AN5 / RC1
73+
_ADCON0_CHS_AN6 = const(0x6) # AN6 / RC2
6574
_ADCON0_ADON_MASK = const(0x01)
66-
_ADCON1_ADCS_POSN = const(0x04)
75+
_ADCON0_ADCS_F_OSC_64 = const(0x6) # A/D Conversion Clock
6776
_ADCON0_GO_nDONE_MASK = const(0x02)
77+
_ADCON1_ADCS_POSN = const(0x04)
6878

6979
ADRESL_ADDR = const(0x09B)
7080
ADRESH_ADDR = const(0x09C)
7181

7282
TRISA_ADDR = const(0x08C)
83+
TRISB_ADDR = const(0x08D)
7384
TRISC_ADDR = const(0x08E)
7485

86+
LATA_ADDR = const(0x10C)
87+
LATB_ADDR = const(0x10D)
88+
LATC_ADDR = const(0x10E)
89+
7590
PORTA_ADDR = const(0x00C)
91+
PORTB_ADDR = const(0x00C)
7692
PORTC_ADDR = const(0x00E)
7793

7894
WPUA_ADDR = const(0x20C)
@@ -85,6 +101,16 @@ class Pycoproc:
85101

86102
EXP_RTC_PERIOD = const(7000)
87103

104+
@staticmethod
105+
def wake_up():
106+
# P9 is connected to RC1, make P9 an output
107+
p9 = Pin("P9", mode=Pin.OUT)
108+
# toggle rc1 to trigger wake up
109+
p9(1)
110+
time.sleep(0.1)
111+
p9(0)
112+
time.sleep(0.1)
113+
88114
def __init__(self, i2c=None, sda='P22', scl='P21'):
89115
if i2c is not None:
90116
self.i2c = i2c
@@ -95,37 +121,52 @@ def __init__(self, i2c=None, sda='P22', scl='P21'):
95121
self.scl = scl
96122
self.clk_cal_factor = 1
97123
self.reg = bytearray(6)
98-
self.wake_int = False
99-
self.wake_int_pin = False
100-
self.wake_int_pin_rising_edge = True
101124

102125
# Make sure we are inserted into the
103126
# correct board and can talk to the PIC
104-
try:
105-
self.read_fw_version()
106-
except Exception as e:
107-
raise Exception('Board not detected: {}'.format(e))
127+
retry = 0
128+
while True:
129+
try:
130+
self.read_fw_version()
131+
break
132+
except Exception as e:
133+
if retry > 10:
134+
raise Exception('Board not detected: {}'.format(e))
135+
print("Couldn't init Pycoproc. Maybe the PIC is still napping. Try to wake it. ({}, {})".format(retry, e))
136+
Pycoproc.wake_up()
137+
# # p9 is connected to RC1, toggle it to wake PIC
138+
# p9 = Pin("P9", mode=Pin.OUT)
139+
# p9(1)
140+
# time.sleep(0.1)
141+
# p9(0)
142+
# time.sleep(0.1)
143+
# Pin("P9", mode=Pin.IN)
144+
retry += 1
108145

109146
# init the ADC for the battery measurements
110-
self.poke_memory(ANSELC_ADDR, 1 << 2)
111-
self.poke_memory(ADCON0_ADDR, (0x06 << _ADCON0_CHS_POSN) | _ADCON0_ADON_MASK)
112-
self.poke_memory(ADCON1_ADDR, (0x06 << _ADCON1_ADCS_POSN))
113-
# enable the pull-up on RA3
114-
self.poke_memory(WPUA_ADDR, (1 << 3))
147+
self.write_byte(ANSELC_ADDR, 1 << 2) # RC2 analog input
148+
self.write_byte(ADCON0_ADDR, (_ADCON0_CHS_AN6 << _ADCON0_CHS_POSN) | _ADCON0_ADON_MASK) # select analog channel and enable ADC
149+
self.write_byte(ADCON1_ADDR, (_ADCON0_ADCS_F_OSC_64 << _ADCON1_ADCS_POSN)) # ADC conversion clock
115150

116-
# set RC6 and RC7 as outputs and enable power to the sensors and the GPS
117-
self.mask_bits_in_memory(TRISC_ADDR, ~(1 << 6))
118-
self.mask_bits_in_memory(TRISC_ADDR, ~(1 << 7))
151+
# enable the pull-up on RA3
152+
self.write_byte(WPUA_ADDR, (1 << 3))
119153

154+
# set RC6 and RC7 as outputs
155+
self.write_bit(TRISC_ADDR, 6, 0) # 3V3SENSOR_A, power to Accelerometer
156+
self.write_bit(TRISC_ADDR, 7, 0) # PWR_CTRL power to other sensors
120157

121-
self.gps_standby(False)
122-
self.sensor_power()
123-
self.sd_power()
158+
# enable power to the sensors and the GPS
159+
self.gps_standby(False) # GPS, RC4
160+
self.sensor_power() # PWR_CTRL, RC7
161+
self.sd_power() # LP_CTRL, RA5
124162

163+
usb_pid=self.read_product_id()
164+
if usb_pid != 0xf012:
165+
raise ValueError('Not a Pysense2/Pytrack2 ({})'.format(usb_pid))
125166
# for Pysense/Pytrack 2.0, the minimum firmware version is 15
126-
if self.read_fw_version() < 15:
127-
raise ValueError('Firmware out of date')
128-
167+
fw = self.read_fw_version()
168+
if fw < 15:
169+
raise ValueError('Firmware out of date', fw)
129170

130171
def _write(self, data, wait=True):
131172
self.i2c.writeto(I2C_SLAVE_ADDR, data)
@@ -162,11 +203,11 @@ def read_product_id(self):
162203
d = self._read(2)
163204
return (d[1] << 8) + d[0]
164205

165-
def peek_memory(self, addr):
206+
def read_byte(self, addr):
166207
self._write(bytes([CMD_PEEK, addr & 0xFF, (addr >> 8) & 0xFF]))
167208
return self._read(1)[0]
168209

169-
def poke_memory(self, addr, value):
210+
def write_byte(self, addr, value):
170211
self._write(bytes([CMD_POKE, addr & 0xFF, (addr >> 8) & 0xFF, value & 0xFF]))
171212

172213
def magic_write_read(self, addr, _and=0xFF, _or=0, _xor=0):
@@ -182,6 +223,25 @@ def mask_bits_in_memory(self, addr, mask):
182223
def set_bits_in_memory(self, addr, bits):
183224
self.magic_write_read(addr, _or=bits)
184225

226+
def read_bit(self, address, bit):
227+
b = self.read_byte(address)
228+
# print("{0:08b}".format(b))
229+
mask = (1<<bit)
230+
# print("{0:08b}".format(mask))
231+
# print("{0:08b}".format(b & mask))
232+
if b & mask:
233+
return 1
234+
else:
235+
return 0
236+
237+
def write_bit(self, address, bit, level):
238+
if level == 1:
239+
self.set_bits_in_memory(address, (1<<bit) )
240+
elif level == 0:
241+
self.mask_bits_in_memory(address, ~(1<<bit) )
242+
else:
243+
raise Exception("level", level)
244+
185245
def setup_sleep(self, time_s):
186246
try:
187247
self.calibrate_rtc()
@@ -192,38 +252,45 @@ def setup_sleep(self, time_s):
192252
time_s = 2**(8*3)-1
193253
self._write(bytes([CMD_SETUP_SLEEP, time_s & 0xFF, (time_s >> 8) & 0xFF, (time_s >> 16) & 0xFF]))
194254

195-
def go_to_sleep(self, gps=True):
255+
def go_to_sleep(self, gps=True, pycom_module_off=True, accelerometer_off=True, wake_interrupt=False):
196256
# enable or disable back-up power to the GPS receiver
197257
self.gps_standby(gps)
198-
self.sensor_power(False)
199-
self.sd_power(False)
200258

201259
# disable the ADC
202-
self.poke_memory(ADCON0_ADDR, 0)
260+
self.write_byte(ADCON0_ADDR, 0)
203261

204-
if self.wake_int:
205-
# Don't touch RA3, RA5 or RC1 so that interrupt wake-up works
206-
self.poke_memory(ANSELA_ADDR, ~(1 << 3))
207-
self.poke_memory(ANSELC_ADDR, ~((1 << 6) | (1 << 7) | (1 << 1)))
208-
else:
209-
# disable power to the accelerometer, and don't touch RA3 so that button wake-up works
210-
self.poke_memory(ANSELA_ADDR, ~(1 << 3))
211-
self.poke_memory(ANSELC_ADDR, ~(0))
212-
213-
self.poke_memory(ANSELB_ADDR, 0xFF)
214-
215-
# check if INT pin (PIC RC1), should be used for wakeup
216-
if self.wake_int_pin:
217-
if self.wake_int_pin_rising_edge:
218-
self.set_bits_in_memory(OPTION_REG_ADDR, 1 << 6) # rising edge of INT pin
219-
else:
220-
self.mask_bits_in_memory(OPTION_REG_ADDR, ~(1 << 6)) # falling edge of INT pin
262+
# RC0, RC1, RC2, analog input
263+
self.set_bits_in_memory(TRISC_ADDR, (1<<2) | (1<<1) | (1<<0) )
264+
self.set_bits_in_memory(ANSELC_ADDR, (1<<2) | (1<<1) | (1<<0) )
265+
266+
# RA4 analog input
267+
self.set_bits_in_memory(TRISA_ADDR, (1<<4) )
268+
self.set_bits_in_memory(ANSELA_ADDR, (1<<4) )
269+
270+
# RB4, RB5 analog input
271+
self.set_bits_in_memory(TRISB_ADDR, (1<<5) | (1<<4) )
272+
self.set_bits_in_memory(ANSELB_ADDR, (1<<5) | (1<<4) )
273+
274+
# actually only B4 and B5
275+
# todo: tris=1?
276+
self.write_byte(ANSELB_ADDR, 0xff)
277+
278+
if wake_interrupt:
279+
# print("enable wake up PIC from RC1")
280+
self.set_bits_in_memory(OPTION_REG_ADDR, 1 << 6) # rising edge of INT pin
221281
self.mask_bits_in_memory(ANSELC_ADDR, ~(1 << 1)) # disable analog function for RC1 pin
222282
self.set_bits_in_memory(TRISC_ADDR, 1 << 1) # make RC1 input pin
223283
self.mask_bits_in_memory(INTCON_ADDR, ~(1 << 1)) # clear INTF
224284
self.set_bits_in_memory(INTCON_ADDR, 1 << 4) # enable interrupt; set INTE)
225285

226-
self._write(bytes([CMD_GO_SLEEP]), wait=False)
286+
nap_options = SD_CARD_OFF | SENSORS_OFF
287+
if pycom_module_off:
288+
nap_options |= FIPY_OFF
289+
if accelerometer_off:
290+
nap_options |= ACCELEROMETER_OFF
291+
292+
# print("CMD_GO_NAP {0:08b}".format(nap_options))
293+
self._write(bytes([CMD_GO_NAP, nap_options]), wait=False)
227294

228295
def calibrate_rtc(self):
229296
# the 1.024 factor is because the PIC LF operates at 31 KHz
@@ -248,72 +315,50 @@ def calibrate_rtc(self):
248315
self.clk_cal_factor = (EXP_RTC_PERIOD / period) * (1000 / 1024)
249316
if self.clk_cal_factor > 1.25 or self.clk_cal_factor < 0.75:
250317
self.clk_cal_factor = 1
318+
time.sleep(0.5)
251319

252320
def button_pressed(self):
253-
button = self.peek_memory(PORTA_ADDR) & (1 << 3)
321+
button = self.read_bit(PORTA_ADDR, 3)
254322
return not button
255323

256324
def read_battery_voltage(self):
257325
self.set_bits_in_memory(ADCON0_ADDR, _ADCON0_GO_nDONE_MASK)
258326
time.sleep_us(50)
259-
while self.peek_memory(ADCON0_ADDR) & _ADCON0_GO_nDONE_MASK:
327+
while self.read_byte(ADCON0_ADDR) & _ADCON0_GO_nDONE_MASK:
260328
time.sleep_us(100)
261-
adc_val = (self.peek_memory(ADRESH_ADDR) << 2) + (self.peek_memory(ADRESL_ADDR) >> 6)
329+
adc_val = (self.read_byte(ADRESH_ADDR) << 2) + (self.read_byte(ADRESL_ADDR) >> 6)
262330
return (((adc_val * 3.3 * 280) / 1023) / 180) + 0.01 # add 10mV to compensate for the drop in the FET
263331

264-
def setup_int_wake_up(self, rising, falling):
265-
""" rising is for activity detection, falling for inactivity """
266-
wake_int = False
267-
if rising:
268-
self.set_bits_in_memory(IOCAP_ADDR, 1 << 5)
269-
wake_int = True
270-
else:
271-
self.mask_bits_in_memory(IOCAP_ADDR, ~(1 << 5))
272-
273-
if falling:
274-
self.set_bits_in_memory(IOCAN_ADDR, 1 << 5)
275-
wake_int = True
276-
else:
277-
self.mask_bits_in_memory(IOCAN_ADDR, ~(1 << 5))
278-
self.wake_int = wake_int
279-
280-
def setup_int_pin_wake_up(self, rising_edge = True):
281-
""" allows wakeup to be made by the INT pin (PIC -RC1) """
282-
self.wake_int_pin = True
283-
self.wake_int_pin_rising_edge = rising_edge
284-
285332
def gps_standby(self, enabled=True):
286333
# make RC4 an output
287-
self.mask_bits_in_memory(TRISC_ADDR, ~(1 << 4))
334+
self.write_bit(TRISC_ADDR, 4, 0)
288335
if enabled:
289336
# drive RC4 low
290-
self.mask_bits_in_memory(PORTC_ADDR, ~(1 << 4))
337+
self.write_bit(LATC_ADDR, 4, 0)
291338
else:
292339
# drive RC4 high
293-
self.set_bits_in_memory(PORTC_ADDR, 1 << 4)
340+
self.write_bit(LATC_ADDR, 4, 1)
294341

295342
def sensor_power(self, enabled=True):
296343
# make RC7 an output
297-
self.mask_bits_in_memory(TRISC_ADDR, ~(1 << 7))
344+
self.write_bit(TRISC_ADDR, 7, 0)
298345
if enabled:
299346
# drive RC7 high
300-
self.set_bits_in_memory(PORTC_ADDR, 1 << 7)
347+
self.write_bit(LATC_ADDR, 7, 1)
301348
else:
302349
# drive RC7 low
303-
self.mask_bits_in_memory(PORTC_ADDR, ~(1 << 7))
350+
self.write_bit(LATC_ADDR, 7, 0)
304351

305352
def sd_power(self, enabled=True):
306353
# make RA5 an output
307-
self.mask_bits_in_memory(TRISA_ADDR, ~(1 << 5))
354+
self.write_bit(TRISA_ADDR, 5, 0)
308355
if enabled:
309356
# drive RA5 high
310-
self.set_bits_in_memory(PORTA_ADDR, 1 << 5)
357+
self.write_bit(LATA_ADDR, 5, 1)
311358
else:
312359
# drive RA5 low
313-
self.mask_bits_in_memory(PORTA_ADDR, ~(1 << 5))
314-
360+
self.write_bit(LATA_ADDR, 5, 0)
315361

316-
# at the end:
317362
def reset_cmd(self):
318363
self._send_cmd(CMD_RESET)
319364
return

0 commit comments

Comments
 (0)