-
-
Notifications
You must be signed in to change notification settings - Fork 741
/
jshardware.c
1730 lines (1538 loc) · 57.7 KB
/
jshardware.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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* Platform Specific part of Hardware interface Layer
* ----------------------------------------------------------------------------
*/
/* S110_SoftDevice_Specification_2.0.pdf
RTC0 not usable (SoftDevice)
RTC1 used by app_timer.c
TIMER0 (32 bit) not usable (softdevice)
TIMER1 (16 bit on nRF51, 32 bit on nRF52) used by jshardware util timer
TIMER2 (16 bit) free
TIMER4 used for NFCT library on nRF52
SPI0 / TWI0 -> Espruino's SPI1 (only nRF52 - not enough flash on 51)
SPI1 / TWI1 -> Espruino's I2C1
SPI2 -> free
*/
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "jshardware.h"
#include "jstimer.h"
#include "jsutils.h"
#include "jsparse.h"
#include "jsinteractive.h"
#include "jswrap_io.h"
#include "jswrap_date.h" // for non-F1 calendar -> days since 1970 conversion.
#include "jsflags.h"
#include "app_util_platform.h"
#ifdef BLUETOOTH
#include "app_timer.h"
#include "bluetooth.h"
#include "bluetooth_utils.h"
#include "jswrap_bluetooth.h"
#else
#include "nrf_temp.h"
void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) {
}
#endif
#include "nrf_peripherals.h"
#include "nrf_gpio.h"
#include "nrf_gpiote.h"
#include "nrf_timer.h"
#include "nrf_delay.h"
#include "nrf_nvic.h"
#ifdef NRF52
#include "nrf_saadc.h"
#include "nrf_pwm.h"
#else
#include "nrf_adc.h"
#endif
#include "nrf_drv_uart.h"
#include "nrf_drv_twi.h"
#include "nrf_drv_gpiote.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_spi.h"
#include "nrf5x_utils.h"
#if NRF_SD_BLE_API_VERSION<5
#include "softdevice_handler.h"
#endif
void WDT_IRQHandler() {
}
#ifdef NRF_USB
#include "app_usbd_core.h"
#include "app_usbd.h"
#include "app_usbd_string_desc.h"
#include "app_usbd_cdc_acm.h"
#include "app_usbd_serial_num.h"
#include "nrf_drv_clock.h"
#include "nrf_drv_power.h"
/**
* @brief Enable power USB detection
*
* Configure if example supports USB port connection
*/
#ifndef USBD_POWER_DETECTION
#define USBD_POWER_DETECTION false // power detection true doesn't seem to work
#endif
static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst,
app_usbd_cdc_acm_user_event_t event);
#define CDC_ACM_COMM_INTERFACE 0
#define CDC_ACM_COMM_EPIN NRF_DRV_USBD_EPIN2
#define CDC_ACM_DATA_INTERFACE 1
#define CDC_ACM_DATA_EPIN NRF_DRV_USBD_EPIN1
#define CDC_ACM_DATA_EPOUT NRF_DRV_USBD_EPOUT1
/**
* @brief CDC_ACM class instance
* */
APP_USBD_CDC_ACM_GLOBAL_DEF(m_app_cdc_acm,
cdc_acm_user_ev_handler,
CDC_ACM_COMM_INTERFACE,
CDC_ACM_DATA_INTERFACE,
CDC_ACM_COMM_EPIN,
CDC_ACM_DATA_EPIN,
CDC_ACM_DATA_EPOUT,
APP_USBD_CDC_COMM_PROTOCOL_AT_V250
);
static char m_rx_buffer[1]; // only seems to work with 1 at the moment
static char m_tx_buffer[NRF_DRV_USBD_EPSIZE];
/**
* @brief USB connection status
* */
static bool m_usb_connected = false;
static bool m_usb_open = false;
/**
* @brief User event handler @ref app_usbd_cdc_acm_user_ev_handler_t (headphones)
* */
static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst,
app_usbd_cdc_acm_user_event_t event)
{
app_usbd_cdc_acm_t const * p_cdc_acm = app_usbd_cdc_acm_class_get(p_inst);
jshHadEvent();
switch (event)
{
case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN:
{
jsiConsolePrintf("APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN\n");
m_usb_open = true;
/*Setup first transfer*/
ret_code_t ret = app_usbd_cdc_acm_read(&m_app_cdc_acm,
m_rx_buffer,
sizeof(m_rx_buffer));
UNUSED_VARIABLE(ret);
break;
}
case APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE:
jsiConsolePrintf("APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE\n");
m_usb_open = false;
break;
case APP_USBD_CDC_ACM_USER_EVT_TX_DONE:
// TODO: queue extra transmit here
break;
case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
{
ret_code_t ret;
do
{
/*Get amount of data transfered*/
size_t size = app_usbd_cdc_acm_rx_size(p_cdc_acm);
jshPushIOCharEvents(EV_USBSERIAL, m_rx_buffer, size);
/*Setup next transfer*/
ret = app_usbd_cdc_acm_read(&m_app_cdc_acm,
m_rx_buffer,
sizeof(m_rx_buffer));
} while (ret == NRF_SUCCESS);
break;
}
default:
break;
}
}
static void usbd_user_ev_handler(app_usbd_event_type_t event)
{
jshHadEvent();
switch (event)
{
case APP_USBD_EVT_DRV_SUSPEND:
jsiConsolePrintf("APP_USBD_EVT_DRV_SUSPEND\n");
break;
case APP_USBD_EVT_DRV_RESUME:
jsiConsolePrintf("APP_USBD_EVT_DRV_RESUME\n");
break;
case APP_USBD_EVT_STARTED:
jsiConsolePrintf("APP_USBD_EVT_STARTED\n");
break;
case APP_USBD_EVT_STOPPED:
jsiConsolePrintf("APP_USBD_EVT_STOPPED\n");
app_usbd_disable();
break;
case APP_USBD_EVT_POWER_DETECTED:
jsiConsolePrintf("APP_USBD_EVT_POWER_DETECTED\n");
if (!nrf_drv_usbd_is_enabled())
{
app_usbd_enable();
}
break;
case APP_USBD_EVT_POWER_REMOVED:
jsiConsolePrintf("APP_USBD_EVT_POWER_REMOVED\n");
m_usb_connected = false;
app_usbd_stop();
break;
case APP_USBD_EVT_POWER_READY:
jsiConsolePrintf("APP_USBD_EVT_POWER_READY\n");
app_usbd_start();
m_usb_connected = true;
break;
default:
break;
}
}
#endif
#define SYSCLK_FREQ 1048576 // 1 << 20
#define RTC_SHIFT 5 // to get 32768 up to SYSCLK_FREQ
// Whether a pin is being used for soft PWM or not
BITFIELD_DECL(jshPinSoftPWM, JSH_PIN_COUNT);
// Whether a pin is negated of not (based on NRF pins)
BITFIELD_DECL(jshNRFPinNegated, JSH_PIN_COUNT);
// Current values used in PWM channel counters
static uint16_t pwmValues[3][4];
// Current values used in main PWM counters
static uint16_t pwmCounters[3];
/// For flash - whether it is busy or not...
volatile bool flashIsBusy = false;
volatile bool hadEvent = false; // set if we've had an event we need to deal with
unsigned int ticksSinceStart = 0;
JshPinFunction pinStates[JSH_PIN_COUNT];
#if SPI_ENABLED
static const nrf_drv_spi_t spi0 = NRF_DRV_SPI_INSTANCE(0);
bool spi0Initialised = false;
#endif
static const nrf_drv_twi_t TWI1 = NRF_DRV_TWI_INSTANCE(1);
bool twi1Initialised = false;
static const nrf_drv_uart_t UART0 = NRF_DRV_UART_INSTANCE(0);
static uint8_t uart0rxBuffer[2]; // 2 char buffer
static uint8_t uart0txBuffer[1];
bool uartIsSending = false;
bool uartInitialised = false;
void jshUSARTUnSetup(IOEventFlags device);
const nrf_drv_twi_t *jshGetTWI(IOEventFlags device) {
if (device == EV_I2C1) return &TWI1;
return 0;
}
/// Called when we have had an event that means we should execute JS
void jshHadEvent() {
hadEvent = true;
}
void TIMER1_IRQHandler(void) {
nrf_timer_task_trigger(NRF_TIMER1, NRF_TIMER_TASK_CLEAR);
nrf_timer_event_clear(NRF_TIMER1, NRF_TIMER_EVENT_COMPARE0);
jshHadEvent();
jstUtilTimerInterruptHandler();
}
void jsh_sys_evt_handler(uint32_t sys_evt) {
if (sys_evt == NRF_EVT_FLASH_OPERATION_SUCCESS){
flashIsBusy = false;
}
}
/* SysTick interrupt Handler. */
void SysTick_Handler(void) {
// TODO: When using USB it seems this isn't called
/* Handle the delayed Ctrl-C -> interrupt behaviour (see description by EXEC_CTRL_C's definition) */
if (execInfo.execute & EXEC_CTRL_C_WAIT)
execInfo.execute = (execInfo.execute & ~EXEC_CTRL_C_WAIT) | EXEC_INTERRUPTED;
if (execInfo.execute & EXEC_CTRL_C)
execInfo.execute = (execInfo.execute & ~EXEC_CTRL_C) | EXEC_CTRL_C_WAIT;
ticksSinceStart++;
/* One second after start, call jsinteractive. This is used to swap
* to USB (if connected), or the Serial port. */
if (ticksSinceStart == 5) {
jsiOneSecondAfterStartup();
}
}
#ifdef NRF52
NRF_PWM_Type *nrf_get_pwm(JshPinFunction func) {
if ((func&JSH_MASK_TYPE) == JSH_TIMER1) return NRF_PWM0;
else if ((func&JSH_MASK_TYPE) == JSH_TIMER2) return NRF_PWM1;
else if ((func&JSH_MASK_TYPE) == JSH_TIMER3) return NRF_PWM2;
return 0;
}
#endif
static NO_INLINE void jshPinSetFunction_int(JshPinFunction func, uint32_t pin) {
#if JSH_PORTV_COUNT>0
// don't handle virtual ports (eg. pins on an IO Expander)
if ((pinInfo[pin].port & JSH_PORT_MASK)==JSH_PORTV)
return;
#endif
JshPinFunction fType = func&JSH_MASK_TYPE;
JshPinFunction fInfo = func&JSH_MASK_INFO;
switch (fType) {
case JSH_NOTHING: break;
#ifdef NRF52
case JSH_TIMER1:
case JSH_TIMER2:
case JSH_TIMER3: {
NRF_PWM_Type *pwm = nrf_get_pwm(fType);
pwm->PSEL.OUT[fInfo>>JSH_SHIFT_INFO] = pin;
// FIXME: Only disable if nothing else is using it!
if (pin==0xFFFFFFFF) nrf_pwm_disable(pwm);
break;
}
#endif
case JSH_USART1: if (fInfo==JSH_USART_RX) {
NRF_UART0->PSELRXD = pin;
if (pin==0xFFFFFFFF) nrf_drv_uart_rx_disable(&UART0);
} else NRF_UART0->PSELTXD = pin;
// if both pins are disabled, shut down the UART
if (NRF_UART0->PSELRXD==0xFFFFFFFF && NRF_UART0->PSELTXD==0xFFFFFFFF)
jshUSARTUnSetup(EV_SERIAL1);
break;
#if SPI_ENABLED
case JSH_SPI1: if (fInfo==JSH_SPI_MISO) NRF_SPI0->PSELMISO = pin;
else if (fInfo==JSH_SPI_MOSI) NRF_SPI0->PSELMOSI = pin;
else NRF_SPI0->PSELSCK = pin;
break;
#endif
case JSH_I2C1: if (fInfo==JSH_I2C_SDA) NRF_TWI1->PSELSDA = pin;
else NRF_TWI1->PSELSCL = pin;
break;
default: assert(0);
}
}
static NO_INLINE void jshPinSetFunction(Pin pin, JshPinFunction func) {
if (pinStates[pin]==func) return;
// disconnect existing peripheral (if there was one)
if (pinStates[pin])
jshPinSetFunction_int(pinStates[pin], 0xFFFFFFFF);
// connect new peripheral
pinStates[pin] = func;
jshPinSetFunction_int(pinStates[pin], pinInfo[pin].pin);
}
#ifdef BLUETOOTH
APP_TIMER_DEF(m_wakeup_timer_id);
void wakeup_handler() {
// don't do anything - just waking is enough for us
jshHadEvent();
}
#endif
void jshResetPeripherals() {
// Reset all pins to their power-on state (apart from default UART :)
// Set pin state to input disconnected - saves power
Pin i;
BITFIELD_CLEAR(jshNRFPinNegated);
for (i=0;i<JSH_PIN_COUNT;i++) {
#if JSH_PORTV_COUNT>0
// don't reset virtual pins
if ((pinInfo[i].port & JSH_PORT_MASK)==JSH_PORTV)
continue;
#endif
if (pinInfo[i].port & JSH_PIN_NEGATED)
BITFIELD_SET(jshNRFPinNegated, pinInfo[i].pin, true);
#ifdef DEFAULT_CONSOLE_TX_PIN
if (i==DEFAULT_CONSOLE_TX_PIN) continue;
#endif
#ifdef DEFAULT_CONSOLE_RX_PIN
if (i==DEFAULT_CONSOLE_RX_PIN) continue;
#endif
if (!IS_PIN_USED_INTERNALLY(i) && !IS_PIN_A_BUTTON(i)) {
jshPinSetState(i, JSHPINSTATE_UNDEFINED);
}
}
BITFIELD_CLEAR(jshPinSoftPWM);
#if JSH_PORTV_COUNT>0
jshVirtualPinInitialise();
#endif
}
void jshInit() {
ret_code_t err_code;
memset(pinStates, 0, sizeof(pinStates));
jshInitDevices();
jshResetPeripherals();
#ifdef LED1_PININDEX
jshPinOutput(LED1_PININDEX, LED1_ONSTATE);
#endif
nrf_utils_lfclk_config_and_start();
#ifdef DEFAULT_CONSOLE_RX_PIN
// Only init UART if something is connected and RX is pulled up on boot...
/* Some devices (nRF52DK) use a very weak connection to the UART.
* So much so that even turning on the PULLDOWN resistor is enough to
* pull it down to 0. In these cases use the pulldown for a while,
* but then turn it off and wait to see if the value rises back up. */
jshPinSetState(DEFAULT_CONSOLE_RX_PIN, JSHPINSTATE_GPIO_IN_PULLDOWN);
jshDelayMicroseconds(10);
jshPinSetState(DEFAULT_CONSOLE_RX_PIN, JSHPINSTATE_GPIO_IN);
jshDelayMicroseconds(10);
if (jshPinGetValue(DEFAULT_CONSOLE_RX_PIN)) {
JshUSARTInfo inf;
jshUSARTInitInfo(&inf);
inf.pinRX = DEFAULT_CONSOLE_RX_PIN;
inf.pinTX = DEFAULT_CONSOLE_TX_PIN;
inf.baudRate = DEFAULT_CONSOLE_BAUDRATE;
jshUSARTSetup(EV_SERIAL1, &inf); // Initialize UART for communication with Espruino/terminal.
} else {
// If there's no UART, 'disconnect' the IO pin - this saves power when in deep sleep in noisy electrical environments
jshPinSetState(DEFAULT_CONSOLE_RX_PIN, JSHPINSTATE_UNDEFINED);
}
#endif
// Enable and sort out the timer
nrf_timer_mode_set(NRF_TIMER1, NRF_TIMER_MODE_TIMER);
#ifdef NRF52
nrf_timer_bit_width_set(NRF_TIMER1, NRF_TIMER_BIT_WIDTH_32);
nrf_timer_frequency_set(NRF_TIMER1, NRF_TIMER_FREQ_1MHz);
#define NRF_TIMER_FREQ 1000000
#define NRF_TIMER_MAX 0xFFFFFFFF
#else
nrf_timer_bit_width_set(NRF_TIMER1, NRF_TIMER_BIT_WIDTH_16);
nrf_timer_frequency_set(NRF_TIMER1, NRF_TIMER_FREQ_250kHz);
#define NRF_TIMER_FREQ 250000 // only 16 bit, so just run slower
#define NRF_TIMER_MAX 0xFFFF
// TODO: we could dynamically change the frequency...
#endif
// Irq setup
NVIC_SetPriority(TIMER1_IRQn, 3); // low - don't mess with BLE :)
NVIC_ClearPendingIRQ(TIMER1_IRQn);
NVIC_EnableIRQ(TIMER1_IRQn);
nrf_timer_int_enable(NRF_TIMER1, NRF_TIMER_INT_COMPARE0_MASK );
// Pin change
nrf_drv_gpiote_init();
#ifdef BLUETOOTH
#if NRF_SD_BLE_API_VERSION<5
APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false);
#else
err_code = app_timer_init();
APP_ERROR_CHECK(err_code);
#endif
#ifdef NRF_USB
uint32_t ret;
static const app_usbd_config_t usbd_config = {
.ev_state_proc = usbd_user_ev_handler
};
app_usbd_serial_num_generate();
ret = nrf_drv_clock_init();
APP_ERROR_CHECK(ret);
jsiConsolePrintf("USBD init\n");
ret = app_usbd_init(&usbd_config);
APP_ERROR_CHECK(ret);
jsiConsolePrintf("ok\n");
app_usbd_class_inst_t const * class_cdc_acm = app_usbd_cdc_acm_class_inst_get(&m_app_cdc_acm);
ret = app_usbd_class_append(class_cdc_acm);
APP_ERROR_CHECK(ret);
jsiConsolePrintf("cdc ok\n");
#endif
jsble_init();
err_code = app_timer_create(&m_wakeup_timer_id,
APP_TIMER_MODE_SINGLE_SHOT,
wakeup_handler);
if (err_code) jsiConsolePrintf("app_timer_create error %d\n", err_code);
#else
// because the code in bluetooth.c will call jsh_sys_evt_handler for us
// if we were using bluetooth
softdevice_sys_evt_handler_set(jsh_sys_evt_handler);
#endif
// Enable PPI driver
err_code = nrf_drv_ppi_init();
APP_ERROR_CHECK(err_code);
#ifdef NRF52
// Turn on SYSTICK - used for handling Ctrl-C behaviour
SysTick_Config(0xFFFFFF);
#endif
#ifndef SAVE_ON_FLASH
// Get a random seed to put into rand's random number generator
srand(jshGetRandomNumber());
#endif
#ifdef NRF_USB
if (USBD_POWER_DETECTION)
{
jsiConsolePrintf("app_usbd_power_events_enable\n");
ret = app_usbd_power_events_enable();
APP_ERROR_CHECK(ret);
}
else
{
jsiConsolePrintf("No USB power detection enabled\nStarting USB now\n");
app_usbd_enable();
app_usbd_start();
}
jsiConsolePrintf("USB init done\n");
#endif
#ifdef LED1_PININDEX
jshPinOutput(LED1_PININDEX, !LED1_ONSTATE);
#endif
}
// When 'reset' is called - we try and put peripherals back to their power-on state
void jshReset() {
jshResetDevices();
jshResetPeripherals();
}
void jshKill() {
}
// stuff to do on idle
void jshIdle() {
#ifdef NRF_USB
while (app_usbd_event_queue_process()); /* Nothing to do */
int l = 0;
int c;
while ((l<sizeof(m_tx_buffer)) && ((c = jshGetCharToTransmit(EV_USBSERIAL))>=0))
m_tx_buffer[l++] = c;
if (l) {
// TODO: check return value?
// This is asynchronous call. User should wait for @ref APP_USBD_CDC_ACM_USER_EVT_TX_DONE event
uint32_t ret = app_usbd_cdc_acm_write(&m_app_cdc_acm, m_tx_buffer, l);
}
#endif
}
/// Get this IC's serial number. Passed max # of chars and a pointer to write to. Returns # of chars
int jshGetSerialNumber(unsigned char *data, int maxChars) {
memcpy(data, (void*)NRF_FICR->DEVICEID, sizeof(NRF_FICR->DEVICEID));
return sizeof(NRF_FICR->DEVICEID);
}
// is the serial device connected?
bool jshIsUSBSERIALConnected() {
#ifdef NRF_USB
return m_usb_open;
#else
return false;
#endif
}
/// Hack because we *really* don't want to mess with RTC0 :)
volatile JsSysTime baseSystemTime = 0;
volatile uint32_t lastSystemTime = 0;
/// Get the system time (in ticks)
JsSysTime jshGetSystemTime() {
// Detect RTC overflows
uint32_t systemTime = NRF_RTC0->COUNTER;
if ((lastSystemTime & 0x800000) && !(systemTime & 0x800000))
baseSystemTime += (0x1000000 << RTC_SHIFT); // it's a 24 bit counter
lastSystemTime = systemTime;
// Use RTC0 (also used by BLE stack) - as app_timer starts/stops RTC1
return baseSystemTime + (JsSysTime)(systemTime << RTC_SHIFT);
}
/// Set the system time (in ticks) - this should only be called rarely as it could mess up things like jsinteractive's timers!
void jshSetSystemTime(JsSysTime time) {
baseSystemTime = 0;
baseSystemTime = time - jshGetSystemTime();
}
/// Convert a time in Milliseconds to one in ticks.
JsSysTime jshGetTimeFromMilliseconds(JsVarFloat ms) {
return (JsSysTime) ((ms * SYSCLK_FREQ) / 1000);
}
/// Convert ticks to a time in Milliseconds.
JsVarFloat jshGetMillisecondsFromTime(JsSysTime time) {
return (time * 1000.0) / SYSCLK_FREQ;
}
void jshInterruptOff() {
#if defined(BLUETOOTH) && defined(NRF52)
// disable non-softdevice IRQs. This only seems available on Cortex M3 (not the nRF51's M0)
__set_BASEPRI(4<<5); // Disabling interrupts completely is not reasonable when using one of the SoftDevices.
#else
__disable_irq();
#endif
}
void jshInterruptOn() {
#if defined(BLUETOOTH) && defined(NRF52)
__set_BASEPRI(0);
#else
__enable_irq();
#endif
}
/// Are we currently in an interrupt?
bool jshIsInInterrupt() {
return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0;
}
void jshDelayMicroseconds(int microsec) {
if (microsec <= 0) {
return;
}
nrf_delay_us((uint32_t)microsec);
}
void jshPinSetValue(Pin pin, bool value) {
assert(jshIsPinValid(pin));
if (pinInfo[pin].port & JSH_PIN_NEGATED) value=!value;
#if JSH_PORTV_COUNT>0
// handle virtual ports (eg. pins on an IO Expander)
if ((pinInfo[pin].port & JSH_PORT_MASK)==JSH_PORTV)
return jshVirtualPinSetValue(pin, value);
#endif
nrf_gpio_pin_write((uint32_t)pinInfo[pin].pin, value);
}
bool jshPinGetValue(Pin pin) {
assert(jshIsPinValid(pin));
bool value;
#if JSH_PORTV_COUNT>0
// handle virtual ports (eg. pins on an IO Expander)
if ((pinInfo[pin].port & JSH_PORT_MASK)==JSH_PORTV)
value = jshVirtualPinGetValue(pin);
else
#endif
value = nrf_gpio_pin_read((uint32_t)pinInfo[pin].pin);
if (pinInfo[pin].port & JSH_PIN_NEGATED) value=!value;
return value;
}
// Set the pin state
void jshPinSetState(Pin pin, JshPinState state) {
assert(jshIsPinValid(pin));
// If this was set to be some kind of AF (USART, etc), reset it.
jshPinSetFunction(pin, JSH_NOTHING);
/* Make sure we kill software PWM if we set the pin state
* after we've started it */
if (BITFIELD_GET(jshPinSoftPWM, pin)) {
BITFIELD_SET(jshPinSoftPWM, pin, 0);
jstPinPWM(0,0,pin);
}
if (pinInfo[pin].port & JSH_PIN_NEGATED) {
if (state==JSHPINSTATE_GPIO_IN_PULLUP) state=JSHPINSTATE_GPIO_IN_PULLDOWN;
else if (state==JSHPINSTATE_GPIO_IN_PULLDOWN) state=JSHPINSTATE_GPIO_IN_PULLUP;
}
#if JSH_PORTV_COUNT>0
// handle virtual ports (eg. pins on an IO Expander)
if ((pinInfo[pin].port & JSH_PORT_MASK)==JSH_PORTV)
return jshVirtualPinSetState(pin, state);
#endif
uint32_t ipin = (uint32_t)pinInfo[pin].pin;
#if NRF_SD_BLE_API_VERSION>5
NRF_GPIO_Type *reg = nrf_gpio_pin_port_decode(&ipin);
#else
NRF_GPIO_Type *reg = NRF_GPIO;
#endif
switch (state) {
case JSHPINSTATE_UNDEFINED :
case JSHPINSTATE_ADC_IN :
reg->PIN_CNF[ipin] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
| (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
| (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
| (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
| (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos);
break;
case JSHPINSTATE_AF_OUT :
case JSHPINSTATE_GPIO_OUT :
case JSHPINSTATE_USART_OUT :
reg->PIN_CNF[ipin] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
| (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos)
| (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
| (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
| (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
break;
case JSHPINSTATE_AF_OUT_OPENDRAIN :
case JSHPINSTATE_GPIO_OUT_OPENDRAIN :
reg->PIN_CNF[ipin] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
| (GPIO_PIN_CNF_DRIVE_H0D1 << GPIO_PIN_CNF_DRIVE_Pos)
| (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
| (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
| (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
break;
case JSHPINSTATE_I2C :
case JSHPINSTATE_GPIO_OUT_OPENDRAIN_PULLUP:
reg->PIN_CNF[ipin] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
| (GPIO_PIN_CNF_DRIVE_H0D1 << 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_Output << GPIO_PIN_CNF_DIR_Pos);
break;
case JSHPINSTATE_GPIO_IN :
case JSHPINSTATE_USART_IN :
nrf_gpio_cfg_input(ipin, NRF_GPIO_PIN_NOPULL);
break;
case JSHPINSTATE_GPIO_IN_PULLUP :
nrf_gpio_cfg_input(ipin, NRF_GPIO_PIN_PULLUP);
break;
case JSHPINSTATE_GPIO_IN_PULLDOWN :
nrf_gpio_cfg_input(ipin, NRF_GPIO_PIN_PULLDOWN);
break;
default : jsiConsolePrintf("Unimplemented pin state %d\n", state);
break;
}
}
/** Get the pin state (only accurate for simple IO - won't return JSHPINSTATE_USART_OUT for instance).
* Note that you should use JSHPINSTATE_MASK as other flags may have been added */
JshPinState jshPinGetState(Pin pin) {
assert(jshIsPinValid(pin));
#if JSH_PORTV_COUNT>0
// handle virtual ports (eg. pins on an IO Expander)
if ((pinInfo[pin].port & JSH_PORT_MASK)==JSH_PORTV)
return jshVirtualPinGetState(pin);
#endif
uint32_t ipin = (uint32_t)pinInfo[pin].pin;
#if NRF_SD_BLE_API_VERSION>5
NRF_GPIO_Type *reg = nrf_gpio_pin_port_decode(&ipin);
#else
NRF_GPIO_Type *reg = NRF_GPIO;
#endif
uint32_t p = reg->PIN_CNF[ipin];
bool negated = pinInfo[pin].port & JSH_PIN_NEGATED;
if ((p&GPIO_PIN_CNF_DIR_Msk)==(GPIO_PIN_CNF_DIR_Output<<GPIO_PIN_CNF_DIR_Pos)) {
uint32_t pinDrive = (p&GPIO_PIN_CNF_DRIVE_Msk)>>GPIO_PIN_CNF_DRIVE_Pos;
uint32_t pinPull = (p&GPIO_PIN_CNF_PULL_Msk)>>GPIO_PIN_CNF_PULL_Pos;
// Output
bool pinIsHigh = reg->OUT & (1<<ipin);
if (negated) pinIsHigh = !pinIsHigh;
JshPinState hi = pinIsHigh ? JSHPINSTATE_PIN_IS_ON : 0;
if (pinDrive==GPIO_PIN_CNF_DRIVE_S0D1 || pinDrive==GPIO_PIN_CNF_DRIVE_H0D1) {
if (pinPull==GPIO_PIN_CNF_PULL_Pullup)
return JSHPINSTATE_GPIO_OUT_OPENDRAIN_PULLUP|hi;
else {
if (pinStates[pin])
return JSHPINSTATE_AF_OUT_OPENDRAIN|hi;
else
return JSHPINSTATE_GPIO_OUT_OPENDRAIN|hi;
}
} else {
if (pinStates[pin])
return JSHPINSTATE_AF_OUT|hi;
else
return JSHPINSTATE_GPIO_OUT|hi;
}
} else {
bool pinConnected = ((p&GPIO_PIN_CNF_INPUT_Msk)>>GPIO_PIN_CNF_INPUT_Pos) == GPIO_PIN_CNF_INPUT_Connect;
// Input
if ((p&GPIO_PIN_CNF_PULL_Msk)==(GPIO_PIN_CNF_PULL_Pullup<<GPIO_PIN_CNF_PULL_Pos)) {
return negated ? JSHPINSTATE_GPIO_IN_PULLDOWN : JSHPINSTATE_GPIO_IN_PULLUP;
} else if ((p&GPIO_PIN_CNF_PULL_Msk)==(GPIO_PIN_CNF_PULL_Pulldown<<GPIO_PIN_CNF_PULL_Pos)) {
return negated ? JSHPINSTATE_GPIO_IN_PULLUP : JSHPINSTATE_GPIO_IN_PULLDOWN;
} else {
return pinConnected ? JSHPINSTATE_GPIO_IN : JSHPINSTATE_ADC_IN;
}
}
}
#ifdef NRF52
nrf_saadc_value_t nrf_analog_read() {
nrf_saadc_value_t result;
nrf_saadc_buffer_init(&result,1);
nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
while(!nrf_saadc_event_check(NRF_SAADC_EVENT_STARTED));
nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);
nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE);
while(!nrf_saadc_event_check(NRF_SAADC_EVENT_END));
nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP);
while(!nrf_saadc_event_check(NRF_SAADC_EVENT_STOPPED));
nrf_saadc_event_clear(NRF_SAADC_EVENT_STOPPED);
return result;
}
JsVarFloat nrf_analog_read_pin(int channel /*0..7*/) {
// sanity checks for channel
assert(NRF_SAADC_INPUT_AIN0 == 1);
assert(NRF_SAADC_INPUT_AIN1 == 2);
assert(NRF_SAADC_INPUT_AIN2 == 3);
nrf_saadc_input_t ain = channel+1;
nrf_saadc_channel_config_t config;
config.acq_time = NRF_SAADC_ACQTIME_3US;
config.gain = NRF_SAADC_GAIN1_4; // 1/4 of input volts
config.mode = NRF_SAADC_MODE_SINGLE_ENDED;
config.pin_p = ain;
config.pin_n = ain;
config.reference = NRF_SAADC_REFERENCE_VDD4; // VDD/4 as reference.
config.resistor_p = NRF_SAADC_RESISTOR_DISABLED;
config.resistor_n = NRF_SAADC_RESISTOR_DISABLED;
// make reading
nrf_saadc_enable();
nrf_saadc_resolution_set(NRF_SAADC_RESOLUTION_14BIT);
nrf_saadc_channel_init(0, &config);
JsVarFloat f = nrf_analog_read() / 16384.0;
nrf_saadc_channel_input_set(0, NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED); // give us back our pin!
nrf_saadc_disable();
return f;
}
#endif
// Returns an analog value between 0 and 1
JsVarFloat jshPinAnalog(Pin pin) {
#if JSH_PORTV_COUNT>0
// handle virtual ports (eg. pins on an IO Expander)
if ((pinInfo[pin].port & JSH_PORT_MASK)==JSH_PORTV)
return jshVirtualPinGetAnalogValue(pin);
#endif
if (pinInfo[pin].analog == JSH_ANALOG_NONE) return NAN;
if (!jshGetPinStateIsManual(pin))
jshPinSetState(pin, JSHPINSTATE_ADC_IN);
#ifdef NRF52
return nrf_analog_read_pin(pinInfo[pin].analog & JSH_MASK_ANALOG_CH);
#else
const nrf_adc_config_t nrf_adc_config = {
NRF_ADC_CONFIG_RES_10BIT,
NRF_ADC_CONFIG_SCALING_INPUT_FULL_SCALE,
NRF_ADC_CONFIG_REF_VBG }; // internal reference
nrf_adc_configure( (nrf_adc_config_t *)&nrf_adc_config);
// sanity checks for nrf_adc_convert_single...
assert(ADC_CONFIG_PSEL_AnalogInput0 == 1);
assert(ADC_CONFIG_PSEL_AnalogInput1 == 2);
assert(ADC_CONFIG_PSEL_AnalogInput2 == 4);
// make reading
return nrf_adc_convert_single(1 << (pinInfo[pin].analog & JSH_MASK_ANALOG_CH)) / 1024.0;
#endif
}
/// Returns a quickly-read analog value in the range 0-65535
int jshPinAnalogFast(Pin pin) {
if (pinInfo[pin].analog == JSH_ANALOG_NONE) return 0;
#ifdef NRF52
// sanity checks for channel
assert(NRF_SAADC_INPUT_AIN0 == 1);
assert(NRF_SAADC_INPUT_AIN1 == 2);
assert(NRF_SAADC_INPUT_AIN2 == 3);
nrf_saadc_input_t ain = 1 + (pinInfo[pin].analog & JSH_MASK_ANALOG_CH);
nrf_saadc_channel_config_t config;
config.acq_time = NRF_SAADC_ACQTIME_3US;
config.gain = NRF_SAADC_GAIN1_4; // 1/4 of input volts
config.mode = NRF_SAADC_MODE_SINGLE_ENDED;
config.pin_p = ain;
config.pin_n = ain;
config.reference = NRF_SAADC_REFERENCE_VDD4; // VDD/4 as reference.
config.resistor_p = NRF_SAADC_RESISTOR_DISABLED;
config.resistor_n = NRF_SAADC_RESISTOR_DISABLED;
// make reading
nrf_saadc_enable();
nrf_saadc_resolution_set(NRF_SAADC_RESOLUTION_8BIT);
nrf_saadc_channel_init(0, &config);
return nrf_analog_read() << 8;
#else
const nrf_adc_config_t nrf_adc_config = {
NRF_ADC_CONFIG_RES_8BIT, // 8 bit for speed (hopefully!)
NRF_ADC_CONFIG_SCALING_INPUT_FULL_SCALE,
NRF_ADC_CONFIG_REF_VBG }; // internal reference
nrf_adc_configure( (nrf_adc_config_t *)&nrf_adc_config);
// sanity checks for nrf_adc_convert_single...
assert(ADC_CONFIG_PSEL_AnalogInput0 == 1);
assert(ADC_CONFIG_PSEL_AnalogInput1 == 2);
assert(ADC_CONFIG_PSEL_AnalogInput2 == 4);
// make reading
return nrf_adc_convert_single(1 << (pinInfo[pin].analog & JSH_MASK_ANALOG_CH)) << 8;
#endif
}
JshPinFunction jshGetFreeTimer(JsVarFloat freq) {
int timer, channel, pin;
for (timer=0;timer<3;timer++) {
bool timerUsed = false;
JshPinFunction timerFunc = JSH_TIMER1 + (JSH_TIMER2-JSH_TIMER1)*timer;
if (freq>0) {
// TODO: we could see if the frequency matches?
// if frequency specified then if timer is used by
// anything else we'll skip it
for (pin=0;pin<JSH_PIN_COUNT;pin++)
if ((pinStates[pin]&JSH_MASK_TYPE) == timerFunc)
timerUsed = true;
}
if (!timerUsed) {
// now check each channel
for (channel=0;channel<4;channel++) {
JshPinFunction func = timerFunc | (JSH_TIMER_CH1 + (JSH_TIMER_CH2-JSH_TIMER_CH1)*channel);
bool timerUsed = false;
for (pin=0;pin<JSH_PIN_COUNT;pin++)
if ((pinStates[pin]&(JSH_MASK_TYPE|JSH_MASK_TIMER_CH)) == func)
timerUsed = true;
if (!timerUsed)
return func;
}
}
}
return JSH_NOTHING;
}
JshPinFunction jshPinAnalogOutput(Pin pin, JsVarFloat value, JsVarFloat freq, JshAnalogOutputFlags flags) {
if (value>1) value=1;
if (value<0) value=0;
#ifdef NRF52
// Try and use existing pin function
JshPinFunction func = pinStates[pin];
// If it's not a timer, try and find one
if (!JSH_PINFUNCTION_IS_TIMER(func)) {
#if JSH_PORTV_COUNT>0
// don't handle virtual ports (eg. pins on an IO Expander)
if ((pinInfo[pin].port & JSH_PORT_MASK)==JSH_PORTV)
func = 0;
else
#endif
func = jshGetFreeTimer(freq);
}
/* we set the bit field here so that if the user changes the pin state
* later on, we can get rid of the IRQs */
if ((flags & JSAOF_FORCE_SOFTWARE) ||
((flags & JSAOF_ALLOW_SOFTWARE) && !func)) {
#endif
if (!jshGetPinStateIsManual(pin)) {
BITFIELD_SET(jshPinSoftPWM, pin, 0);
jshPinSetState(pin, JSHPINSTATE_GPIO_OUT);
}
BITFIELD_SET(jshPinSoftPWM, pin, 1);
if (freq<=0) freq=50;
jstPinPWM(freq, value, pin);
return JSH_NOTHING;
#ifdef NRF52
}
if (!func) {
jsExceptionHere(JSET_ERROR, "No free Hardware PWMs. Try not specifying a frequency, or using analogWrite(pin, val, {soft:true}) for Software PWM\n");
return 0;
}
/* if negated... No need to invert when doing SW PWM
as the SW output is already negating it! */
if (pinInfo[pin].port & JSH_PIN_NEGATED)
value = 1-value;
NRF_PWM_Type *pwm = nrf_get_pwm(func);
if (!pwm) { assert(0); return 0; };
jshPinSetState(pin, JSHPINSTATE_GPIO_OUT);
jshPinSetFunction(pin, func);
nrf_pwm_enable(pwm);
nrf_pwm_clk_t clk;
if (freq<=0) freq = 1000;
int counter = (int)(16000000.0 / freq);