Skip to content

Commit

Permalink
nRF52: Add E.setComparator to enable interrupts from LPCOMP
Browse files Browse the repository at this point in the history
  • Loading branch information
gfwilliams committed Nov 15, 2024
1 parent 9573bb3 commit ad27875
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 1 deletion.
1 change: 1 addition & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
Bangle.js: .setUI now only clears back widget if it hasn't been hidden by widget_utils
Fix UtilTimer timings when new task added infront of existing tasks (fix #2575)
Graphics: Fix issue where drawLine for 2px horizontal lines only drew a 1px dot
nRF52: Add E.setComparator to enable interrupts from LPCOMP

2v24 : Bangle.js2: Add 'Bangle.touchRd()', 'Bangle.touchWr()'
Bangle.js2: After Bangle.showTestScreen, put Bangle.js into a hard off state (not soft off)
Expand Down
10 changes: 10 additions & 0 deletions src/jsdevices.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ typedef enum {
EV_NONE,
EV_EXTI0, ///< External Interrupt
EV_EXTI_MAX = EV_EXTI0 + ESPR_EXTI_COUNT - 1,
EV_CUSTOM, ///< Custom event (See IOCustomEventFlags)
EV_SERIAL_START,
EV_LOOPBACKA = EV_SERIAL_START,
EV_LOOPBACKB,
Expand Down Expand Up @@ -129,6 +130,15 @@ typedef enum {

#define DEVICE_SANITY_CHECK() if (EV_TYPE_MASK>63) jsError("DEVICE_SANITY_CHECK failed")

/** Event types for EV_CUSTOM */
typedef enum {
EVC_NONE,
#ifdef NRF52_SERIES
EVC_LPCOMP,
#endif
EVC_TYPE_MASK = 255,
EVC_DATA_LPCOMP_UP = 256
} PACKED_FLAGS IOCustomEventFlags;

/// True is the device is a serial device (could be a USART, Bluetooth, USB, etc)
#define DEVICE_IS_SERIAL(X) (((X)>=EV_SERIAL_START) && ((X)<=EV_SERIAL_MAX))
Expand Down
2 changes: 2 additions & 0 deletions src/jshardware.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,8 @@ void jshClearUSBIdleTimeout();
#if defined(NRF51_SERIES) || defined(NRF52_SERIES)
/// Called when we have had an event that means we should execute JS
extern void jshHadEvent();
/// Enable/disable(if level==NAN) the LPCOMP comparator
bool jshSetComparator(Pin pin, JsVarFloat level);
#else
#define jshHadEvent() /* We should ensure we exit idle mode */
#endif
Expand Down
14 changes: 14 additions & 0 deletions src/jsinteractive.c
Original file line number Diff line number Diff line change
Expand Up @@ -2152,6 +2152,20 @@ void jsiIdle() {
jsiExecuteEventCallbackName(usartClass, JS_EVENT_PREFIX"parity", 0, 0);
}
jsvUnLock(usartClass);
#endif
} else if (eventType == EV_CUSTOM) {
// TODO: maybe we should handle this with jswrapper.c?
#if defined(NRF52_SERIES) && !defined(SAVE_ON_FLASH)
// see jshSetComparator / E.setComparator
int type = event.data.time & EVC_TYPE_MASK;
if (type == EVC_LPCOMP) {
JsVar *arg = jsvNewFromInteger((event.data.time & EVC_DATA_LPCOMP_UP) ? 1 : -1);
jsiExecuteEventCallbackOn("E",JS_EVENT_PREFIX"comparator",1,&arg);
jsvUnLock(arg);
}
#endif
#ifdef NRF52_SERIES
jsiConsolePrintf("EV_CUSTOM %d\n", event.data.time);
#endif
#ifdef BLUETOOTH
} else if ((eventType == EV_BLUETOOTH_PENDING) || (eventType == EV_BLUETOOTH_PENDING_DATA)) {
Expand Down
35 changes: 35 additions & 0 deletions src/jswrap_espruino.c
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,7 @@ void jswrap_espruino_FFT(JsVar *arrReal, JsVar *arrImag, bool inverse) {
}

#endif //!ESP8266

/*JSON{
"type" : "staticmethod",
"ifndef" : "SAVE_ON_FLASH",
Expand Down Expand Up @@ -683,6 +684,40 @@ void jswrap_espruino_kickWatchdog() {
jshKickWatchDog();
}

/*JSON{
"type" : "staticmethod",
"#if" : "defined(NRF52) && !defined(SAVE_ON_FLASH)",
"class" : "E",
"name" : "setComparator",
"generate" : "jswrap_espruino_setComparator",
"params" : [
["pin","pin","The `Pin` to enable the comparator on"],
["level","float","The level to trigger on, or `undefined` to disable. (see below for [Jolt.js](https://www.espruino.com/Jolt.js))"]
]
}
(Added 2v25) Enable the nRF52 chip's `LPCOMP` hardware. When enabled, it creates an `E.on("comparator", ...)`
event whenever the pin supplied rises or falls past the setpoint given.
```JS
E.setComparator(D28, 8/16); // compare with VDD/2
E.on("comparator", e => {
print(e); // 1 for up, or -1 for down
});
```
**Note:** There is just one LPCOMP, so you can only enable the comparator on one pin.
**On [Jolt.js](https://www.espruino.com/Jolt.js):** when using `E.setComparator` on the analog pins on the
Terminal block (`H0`/`H2`/`H4`/`H8`), the `level` you give needs to be in volts. Because the comparator only
works in 16 steps, you can only detect multiples of 1.37v (1.37/2.74/4.11/etc)
*/
void jswrap_espruino_setComparator(Pin pin, JsVarFloat level) {
#if defined(NRF52_SERIES) && !defined(SAVE_ON_FLASH)
jshSetComparator(pin, level);
#endif
}

/// Return an array of errors based on the current flags
JsVar *jswrap_espruino_getErrorFlagArray(JsErrorFlags flags) {
JsVar *arr = jsvNewEmptyArray();
Expand Down
1 change: 1 addition & 0 deletions src/jswrap_espruino.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ void jswrap_espruino_FFT(JsVar *arrReal, JsVar *arrImag, bool inverse);

void jswrap_espruino_enableWatchdog(JsVarFloat time, JsVar *isAuto);
void jswrap_espruino_kickWatchdog();
void jswrap_espruino_setComparator(Pin pin, JsVarFloat level);
/// Return an array of errors based on the current flags
JsVar *jswrap_espruino_getErrorFlagArray(JsErrorFlags flags);
JsVar *jswrap_espruino_getErrorFlags();
Expand Down
80 changes: 79 additions & 1 deletion targets/nrf5x/jshardware.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) {
#include "jswrap_microbit.h"
#endif

#if defined(NRF52_SERIES) && !defined(SAVE_ON_FLASH)
#include "nrf_lpcomp.h"
#endif

#ifndef SAVE_ON_FLASH
// Enable 7 bit UART (this must be done in software)
#define ESPR_UART_7BIT 1
Expand Down Expand Up @@ -2911,4 +2915,78 @@ void jsvGetProcessorPowerUsage(JsVar *devices) {
pwmOn = true;
if (pwmOn)
jsvObjectSetChildAndUnLock(devices, "PWM", jsvNewFromInteger(200));
}
}


#if defined(NRF52_SERIES) && !defined(SAVE_ON_FLASH)


void COMP_LPCOMP_IRQHandler() {
if (nrf_lpcomp_event_check(NRF_LPCOMP_EVENT_UP) && nrf_lpcomp_int_enable_check(LPCOMP_INTENSET_UP_Msk)) {
nrf_lpcomp_event_clear(NRF_LPCOMP_EVENT_UP);
jshPushIOEvent(EV_CUSTOM, EVC_LPCOMP | EVC_DATA_LPCOMP_UP);
jshHadEvent();
}
if (nrf_lpcomp_event_check(NRF_LPCOMP_EVENT_DOWN) && nrf_lpcomp_int_enable_check(LPCOMP_INTENSET_DOWN_Msk)) {
nrf_lpcomp_event_clear(NRF_LPCOMP_EVENT_DOWN);
jshPushIOEvent(EV_CUSTOM, EVC_LPCOMP);
jshHadEvent();
}
}

/// Enable/disable(if level==NAN) the LPCOMP comparator
bool jshSetComparator(Pin pin, JsVarFloat level) {
if (!isfinite(level)) {
NVIC_DisableIRQ(LPCOMP_IRQn);
nrf_lpcomp_disable();
nrf_lpcomp_task_trigger(NRF_LPCOMP_TASK_STOP);
return true;
}
if (!jshIsPinValid(pin) || pinInfo[pin].analog==JSH_ANALOG_NONE) {
jsExceptionHere(JSET_ERROR, "Pin for LPCOMP must be an analog pin");
return false;
}

#ifdef JOLTJS
// Bit of a hack for Jolt.js where we have a 39k + 220k potential divider
// Multiply up so we return the actual voltage -> 3.3*(220+39)/39 = 21.915
if ((pinInfo[pin].port & JSH_PORT_MASK)==JSH_PORTH)
level = level / 21.915;
#endif
int ilevel = (int)((level*16)+0.5);
if (ilevel<1) ilevel=1;
if (ilevel>15) ilevel=15;
// allow LPCOMP_REFSEL_REFSEL_ARef?
const nrf_lpcomp_ref_t refs[] = {0,
LPCOMP_REFSEL_REFSEL_Ref1_16Vdd,
LPCOMP_REFSEL_REFSEL_Ref1_8Vdd,
LPCOMP_REFSEL_REFSEL_Ref3_16Vdd,
LPCOMP_REFSEL_REFSEL_Ref2_8Vdd,
LPCOMP_REFSEL_REFSEL_Ref5_16Vdd,
LPCOMP_REFSEL_REFSEL_Ref3_8Vdd,
LPCOMP_REFSEL_REFSEL_Ref7_16Vdd,
LPCOMP_REFSEL_REFSEL_Ref4_8Vdd,
LPCOMP_REFSEL_REFSEL_Ref9_16Vdd,
LPCOMP_REFSEL_REFSEL_Ref5_8Vdd,
LPCOMP_REFSEL_REFSEL_Ref11_16Vdd,
LPCOMP_REFSEL_REFSEL_Ref6_8Vdd,
LPCOMP_REFSEL_REFSEL_Ref13_16Vdd,
LPCOMP_REFSEL_REFSEL_Ref7_8Vdd,
LPCOMP_REFSEL_REFSEL_Ref15_16Vdd
};
nrf_lpcomp_config_t config;
config.reference = refs[ilevel];
config.detection = NRF_LPCOMP_DETECT_CROSS;
config.hyst = NRF_LPCOMP_HYST_50mV;
nrf_lpcomp_configure(&config);
nrf_lpcomp_input_select(pinInfo[pin].analog & JSH_MASK_ANALOG_CH);
nrf_lpcomp_int_enable(LPCOMP_INTENSET_UP_Msk|LPCOMP_INTENSET_DOWN_Msk);
nrf_lpcomp_shorts_enable(NRF_LPCOMP_SHORT_READY_SAMPLE_MASK);
NVIC_SetPriority(LPCOMP_IRQn, 3); // low - don't mess with BLE
NVIC_ClearPendingIRQ(LPCOMP_IRQn);
NVIC_EnableIRQ(LPCOMP_IRQn);
nrf_lpcomp_enable();
nrf_lpcomp_task_trigger(NRF_LPCOMP_TASK_START);
return true;
}
#endif

0 comments on commit ad27875

Please sign in to comment.