libpruio  0.6.6
Fast and easy Digital/Analog Input/Output for Beaglebones
pruio.bas
Go to the documentation of this file.
1 
10 
11 
12 
13 #DEFINE __PRUIO_COMPILING__
14 
15 ' uio driver header file
16 #INCLUDE ONCE "pruio_prussdrv.bi"
17 ' driver header file
18 #INCLUDE ONCE "pruio.bi"
19 ' Header file with convenience macros.
20 #INCLUDE ONCE "pruio_pins.bi"
21 ' Header file with Pru_Init instructions.
22 #INCLUDE ONCE "pasm_init.bi"
23 ' Header file with Pru_Run instructions.
24 #INCLUDE ONCE "pasm_run.bi"
25 ' FB include
26 #INCLUDE ONCE "dir.bi"
27 
28 
29 #DEFINE PMUX_NAME "pruio-"
30 
31 #DEFINE PMUX_ERRR 258
32 
33 #DEFINE ArrayBytes(_A_) (UBOUND(_A_) + 1) * SIZEOF(_A_(0))
34 
35 
36 DECLARE FUNCTION memcpy CDECL ALIAS "memcpy"(BYVAL AS ANY PTR, BYVAL AS ANY PTR, BYVAL AS ULONG /'size_t'/) AS ANY PTR
37 
38 ' private functions from pruio_prussdrv.bas
39 DECLARE FUNCTION setPin_save CDECL( _
40  BYVAL AS Pruio_ PTR _
41  , BYVAL AS UInt8 _
42  , BYVAL AS UInt8) AS ZSTRING PTR
43 DECLARE FUNCTION setPin_lkm_bb CDECL( _
44  BYVAL AS Pruio_ PTR _
45  , BYVAL AS UInt8 _
46  , BYVAL AS UInt8) AS ZSTRING PTR
47 DECLARE FUNCTION setPin_lkm CDECL( _
48  BYVAL AS Pruio_ PTR _
49  , BYVAL AS UInt8 _
50  , BYVAL AS UInt8) AS ZSTRING PTR
51 DECLARE FUNCTION setPin_dtbo CDECL( _
52  BYVAL AS Pruio_ PTR _
53  , BYVAL AS UInt8 _
54  , BYVAL AS UInt8) AS ZSTRING PTR
55 DECLARE FUNCTION setPin_nogo CDECL( _
56  BYVAL AS Pruio_ PTR _
57  , BYVAL AS UInt8 _
58  , BYVAL AS UInt8) AS ZSTRING PTR
59 
60 
140 CONSTRUCTOR PruIo( _
141  BYVAL Act AS UInt16 = PRUIO_DEF_ACTIVE _
142  , BYVAL Av AS UInt8 = PRUIO_DEF_AVRAGE _
143  , BYVAL OpD AS UInt32 = PRUIO_DEF_ODELAY _
144  , BYVAL SaD AS UInt8 = PRUIO_DEF_SDELAY)
145  VAR fnr = FREEFILE ' test interrupt access
146  IF OPEN("/dev/uio5" FOR OUTPUT AS fnr) THEN _
147  Errr = @"cannot open /dev/uio5" : EXIT CONSTRUCTOR
148  CLOSE #fnr
149 
150  STATIC AS STRING mux, bbb ' check for BB type and pinmuxing features
151  IF 0 = OPEN("/proc/device-tree/model" FOR INPUT AS fnr) THEN
152  LINE INPUT #fnr, bbb
153  'IF bbb = "TI_AM335x_PocketBeagle" THEN BbType = 1
154  'IF bbb = "TI AM335x BeagleBone Blue" THEN BbType = 2
155  IF INSTR(bbb, "Pocket") THEN BbType = 1
156  IF INSTR(bbb, "Blue") THEN BbType = 2
157  CLOSE #fnr
158  END IF
159 
160  IF 0 = OPEN("/sys/devices/platform/libpruio/state" FOR OUTPUT AS fnr) THEN
161  IF Act AND PRUIO_ACT_FREMUX THEN
162  setPin = IIF(BbType, @setPin_lkm(), @setPin_lkm_bb())
163  ELSE
164  setPin = @setPin_save()
165  Errr = setPin(@THIS, 255, 0)
166  IF Errr THEN CLOSE #fnr : setPin = @setPin_nogo() : fnr = 0
167  END IF : MuxFnr = fnr
168  END IF
169  IF 0 = MuxFnr THEN ' no LKM, test old style device tree overlays
170  VAR p = "/sys/devices/" _
171  , n = DIR(p & "ocp.*", fbDirectory)
172  IF LEN(n) THEN ' old kernel 3.x
173  mux = p & n & "/" & PMUX_NAME : MuxFnr = 256
174  ELSE ' new kernel 4.x
175  p &= "platform/ocp/ocp:"
176  IF LEN(DIR(p & "pruio-*", fbDirectory)) THEN mux = p & PMUX_NAME : MuxFnr = 257
177  END IF
178  IF MuxFnr THEN setPin = @setPin_dtbo() : MuxAcc = SADD(mux) : Errr = 0 _
179  ELSE setPin = @setPin_nogo()
180  END IF
181 
182  IF Act AND PRUIO_ACT_PRU1 THEN
183  PruIntNo = ARM_PRU1_INTERRUPT
184  PruIRam = PRUSS0_PRU1_IRAM
185  PruDRam = PRUSS0_PRU1_DRAM
186  PruNo = PRU1
187  ELSE
188  PruIntNo = ARM_PRU1_INTERRUPT
189  PruIRam = PRUSS0_PRU0_IRAM
190  PruDRam = PRUSS0_PRU0_DRAM
191  PruNo = PRU0
192  END IF
193  IF prussdrv_open(PRUIO_EVNT) THEN _ ' open PRU Interrupt
194  Errr = @"failed opening prussdrv library" : EXIT CONSTRUCTOR
195 
196  prussdrv_map_prumem(PruDRam, CAST(ANY PTR, @DRam))
197  prussdrv_map_extmem(@ERam)
198  ESize = prussdrv_extmem_sIze()
199  EAddr = prussdrv_get_phys_addr(ERam)
200 
201  prussdrv_pru_disable(PruNo) ' disable PRU (if running before)
202  DRam[0] = 0
203  DRam[1] = PRUIO_DAT_ALL ' start of data block
204  ParOffs = 1
205  DevAct = Act
206 
207 ' order must match the order in
208 ' pruio_init.p xxx_Init and in
209 ' pruio_run.p xxx_Config macro calls
210 '& AdcUdt::AdcUdt(); GpioUdt::GpioUdt(); PwmssUdt::PwmssUdt(); TimerUdt::TimerUdt(); /*
211  Adc = NEW AdcUdt(@THIS)
212  Gpio = NEW GpioUdt(@THIS)
213 
214  VAR offs = ParOffs
215  ParOffs += 1 : DRam[ParOffs] = &h44E10800 ' pinmux registers
216 
217  PwmSS = NEW PwmssUdt(@THIS)
218  TimSS = NEW TimerUdt(@THIS)
219 
220  ASSERT(ParOffs < DRam[1] SHR 4)
221  VAR l = ArrayBytes(Pru_Init)
222  IF 0 >= prussdrv_pru_write_memory(PruIRam, 0, @Pru_Init(0), l) THEN _
223  Errr = @"failed loading Pru_Init instructions" : EXIT CONSTRUCTOR
224  prussdrv_pruintc_init(@IntcInit) ' get interrupts initialized
225  prussdrv_pru_enable(PruNo)
226 
227  Pwm = NEW PwmMod(@THIS)
228  Cap = NEW CapMod(@THIS)
229  Qep = NEW QepMod(@THIS)
230 '& */ PwmMod::PwmMod(); CapMod::CapMod(); QepMod::QepMod();
231  Tim = TimSS ' redundant, but consistent API for the user
232 
233  prussdrv_pru_wait_event(PRUIO_EVNT)
234  IF DRam[0] <> PRUIO_MSG_INIT_OK THEN _
235  Errr = @"failed executing Pru_Init instructions" : EXIT CONSTRUCTOR
236 
237  DSize = DRam[ParOffs] - DRam[1]
238  DInit = ALLOCATE(DSize * 2)
239  IF 0 = DInit THEN Errr = @"out of memory" : EXIT CONSTRUCTOR
240 
241  MOffs = DInit - DRam[1]
242  DConf = DInit + DSize
243  VAR p0 = CAST(ANY PTR, DRam) + DRam[1]
244  memcpy(DInit, p0, DSize)
245  memcpy(DConf, p0, DSize)
246 
247  Init = MOffs + DRam[offs]
248  Conf = CAST(ANY PTR, Init) + DSize
249  BallInit = CAST(ANY PTR, Init) + OFFSETOF(BallSet, Value(0))
250  BallConf = BallInit + DSize ' initialize invalid:
251  FOR b AS INTEGER = 0 TO PRUIO_AZ_BALL : BallConf[b] OR= &b11000 : NEXT
252 
253  IF Adc->initialize(Av, OpD, SaD) THEN EXIT CONSTRUCTOR
254  IF Gpio->initialize() THEN EXIT CONSTRUCTOR
255  IF PwmSS->initialize() THEN EXIT CONSTRUCTOR
256  IF TimSS->initialize() THEN EXIT CONSTRUCTOR
257  '& AdcUdt::initialize(); GpioUdt::initialize(); PwmssUdt::initialize(); TimerUdt::initialize();
258 END CONSTRUCTOR
259 
260 
261 
277 DESTRUCTOR PruIo()
278  VAR mux = "" : Errr = 0
279  IF DRam THEN
280  IF DInit THEN
281  IF MuxFnr THEN ' pinmuxing active
282  IF BallInit <> BallConf THEN ' reset pinmuxing
283  FOR i AS INTEGER = 0 TO PRUIO_AZ_BALL
284  IF (BallConf[i] AND &b11000) = &b11000 THEN CONTINUE FOR ' untouched
285  IF (BallConf[i] XOR BallInit[i]) AND &b1111111 THEN _ ' re-mux
286  IF setPin(@THIS, i, BallInit[i]) THEN mux &= _ ' error
287  !"\nre-mux " _
288  & BIN(BallConf[i], 7) & " -> " & BIN(BallInit[i], 7) _
289  & " failed (" & *Errr & ")"
290  NEXT
291  END IF : Errr = 0
292  IF MuxFnr < 256 THEN CLOSE #MuxFnr ' close MuxFile
293  END IF
294  prussdrv_pru_disable(PruNo)
295 
296  DRam[2] = 0
297  DRam[1] = PRUIO_DAT_ALL ' reset subsystems configuration
298  memcpy(CAST(ANY PTR, DRam) + DRam[1], DInit, DSize)
299  DEALLOCATE(DInit)
300 
301  VAR l = ArrayBytes(Pru_Run)
302  IF 0 >= prussdrv_pru_write_memory(PruIRam, 0, @Pru_Run(0), l) THEN
303  Errr = @"failed loading Pru_Exit instructions"
304  ELSE
305  prussdrv_pruintc_init(@IntcInit) ' get interrupt initialized
306  prussdrv_pru_enable(PruNo)
307  prussdrv_pru_wait_event(PRUIO_EVNT)
308  IF DRam[0] <> PRUIO_MSG_CONF_OK THEN _
309  Errr = @"failed executing Pru_Exit instructions"
310  END IF
311  ELSE
312  Errr = @"destructor warning: subsystems are NOT restored"
313  END IF
314  prussdrv_pru_disable(PruNo)
315  prussdrv_exit() ' power down PRU
316  ELSE
317  Errr = @"destructor warning: constructor failed"
318  END IF
319 
320  IF Errr THEN mux &= !"\n" & *Errr
321  IF LEN(mux) THEN _
322  VAR fnr = FREEFILE : OPEN ERR AS fnr : PRINT #fnr, MID(mux, 2) : CLOSE #fnr
323 END DESTRUCTOR
324 
325 
326 
445 FUNCTION PruIo.config CDECL( _
446  BYVAL Samp AS UInt32 = PRUIO_DEF_SAMPLS _
447  , BYVAL Mask AS UInt32 = PRUIO_DEF_STPMSK _
448  , BYVAL Tmr AS UInt32 = PRUIO_DEF_TIMERV _
449  , BYVAL Mds AS UInt16 = PRUIO_DEF_LSLMOD) AS ZSTRING PTR
450 
451  prussdrv_pru_disable(PruNo) ' disable PRU
452  IF Adc->configure(Samp, Mask, Tmr, Mds) THEN RETURN Errr
453 
454  DRam[1] = PRUIO_DAT_ALL
455  memcpy(CAST(ANY PTR, DRam) + DRam[1], DConf, DSize)
456 
457  VAR l = ArrayBytes(Pru_Run)
458  IF 0 >= prussdrv_pru_write_memory(PruIRam, 0, @Pru_Run(0), l) THEN _
459  Errr = @"failed loading Pru_Run instructions" : RETURN Errr
460  prussdrv_pruintc_init(@IntcInit) ' get interrupt initialized
461  prussdrv_pru_enable(PruNo)
462  prussdrv_pru_wait_event(PRUIO_EVNT)
463  SELECT CASE AS CONST Samp
464  CASE 0 : l = DRam[0] <> PRUIO_MSG_CONF_OK
465  CASE 1 : l = DRam[0] <> PRUIO_MSG_IO_OK
466  CASE ELSE : l = DRam[0] <> PRUIO_MSG_MM_WAIT
467  END SELECT
468  IF l THEN Errr = @"failed executing Pru_Run instructions" : RETURN Errr
469  IF Samp < 2 THEN RETURN 0
470 
471  prussdrv_pru_clear_event(PRUIO_EVNT, PRUIO_IRPT)
472  prussdrv_pru_send_event(PruIntNo) ' prepare fast MM start
473  RETURN 0
474 END FUNCTION
475 
476 
477 
499 FUNCTION PruIo.Pin CDECL( _
500  BYVAL Ball AS UInt8, _
501  BYVAL Mo AS UInt8 = 1) AS ZSTRING PTR
502  STATIC AS STRING*50 t
503 
504  VAR x = nameBall(Ball)
505  IF x THEN
506  t = *x
507  ELSE
508  IF Ball > PRUIO_AZ_BALL THEN Errr = @"unknown pin number" : RETURN Errr
509  t = "b " & RIGHT("00" & Ball, 3)
510  END IF
511 
512  VAR r = IIF(Mo, BallConf[Ball], BallInit[Ball]) _
513  , m = r AND &b111
514  IF m = 7 THEN
515  VAR i = BallGpio(Ball) SHR 5 _
516  , n = BallGpio(Ball) AND 31 _
517  , m = 1 SHL n
518  t &= ", GPIO " & i & "/" & RIGHT("0" & n, 2)
519  IF BIT(r, 5) THEN
520  t &= ": input"
521  ELSE
522  WITH *IIF(Mo, Gpio->Conf(i), Gpio->Init(i))
523  t &= ": output-" & *IIF((.DATAOUT OR .SETDATAOUT) AND m, @"1", @"0")
524  END WITH
525  END IF
526  ELSE
527  t &= ", mode " & m _
528  & ": input " & *IIF(BIT(r, 5), @"enabled", @"disabled")
529  END IF
530 
531  IF BIT(r, 3) THEN
532  t &= ", nopull"
533  ELSE
534  IF BIT(r, 4) THEN t &= ", pullup" ELSE t &= ", pulldown"
535  END IF : RETURN SADD(t)
536 END FUNCTION
537 
538 
539 
552 FUNCTION PruIo.nameBall CDECL(BYVAL Ball AS UInt8) AS ZSTRING PTR
553  SELECT CASE AS CONST Ball ' find name
554  CASE P8_03 : RETURN @"P8_03"
555  CASE P8_04 : RETURN @"P8_04"
556  CASE P8_05 : RETURN @"P8_05"
557  CASE P8_06 : RETURN @"P8_06"
558  CASE P8_07 : RETURN @"P8_07"
559  CASE P8_08 : RETURN @"P8_08"
560  CASE P8_09 : RETURN @"P8_09"
561  CASE P8_10 : RETURN @"P8_10"
562  CASE P8_11 : RETURN @"P8_11"
563  CASE P8_12 : RETURN @"P8_12"
564  CASE P8_13 : RETURN @"P8_13"
565  CASE P8_14 : RETURN @"P8_14"
566  CASE P8_15 : RETURN @"P8_15"
567  CASE P8_16 : RETURN @"P8_16"
568  CASE P8_17 : RETURN @"P8_17"
569  CASE P8_18 : RETURN @"P8_18"
570  CASE P8_19 : RETURN @"P8_19"
571  CASE P8_20 : RETURN @"P8_20"
572  CASE P8_21 : RETURN @"P8_21"
573  CASE P8_22 : RETURN @"P8_22"
574  CASE P8_23 : RETURN @"P8_23"
575  CASE P8_24 : RETURN @"P8_24"
576  CASE P8_25 : RETURN @"P8_25"
577  CASE P8_26 : RETURN @"P8_26"
578  CASE P8_27 : RETURN @"P8_27"
579  CASE P8_28 : RETURN @"P8_28"
580  CASE P8_29 : RETURN @"P8_29"
581  CASE P8_30 : RETURN @"P8_30"
582  CASE P8_31 : RETURN @"P8_31"
583  CASE P8_32 : RETURN @"P8_32"
584  CASE P8_33 : RETURN @"P8_33"
585  CASE P8_34 : RETURN @"P8_34"
586  CASE P8_35 : RETURN @"P8_35"
587  CASE P8_36 : RETURN @"P8_36"
588  CASE P8_37 : RETURN @"P8_37"
589  CASE P8_38 : RETURN @"P8_38"
590  CASE P8_39 : RETURN @"P8_39"
591  CASE P8_40 : RETURN @"P8_40"
592  CASE P8_41 : RETURN @"P8_41"
593  CASE P8_42 : RETURN @"P8_42"
594  CASE P8_43 : RETURN @"P8_43"
595  CASE P8_44 : RETURN @"P8_44"
596  CASE P8_45 : RETURN @"P8_45"
597  CASE P8_46 : RETURN @"P8_46"
598  CASE P9_11 : RETURN @"P9_11"
599  CASE P9_12 : RETURN @"P9_12"
600  CASE P9_13 : RETURN @"P9_13"
601  CASE P9_14 : RETURN @"P9_14"
602  CASE P9_15 : RETURN @"P9_15"
603  CASE P9_16 : RETURN @"P9_16"
604  CASE P9_17 : RETURN @"P9_17"
605  CASE P9_18 : RETURN @"P9_18"
606  CASE P9_19 : RETURN @"P9_19"
607  CASE P9_20 : RETURN @"P9_20"
608  CASE P9_21 : RETURN @"P9_21"
609  CASE P9_22 : RETURN @"P9_22"
610  CASE P9_23 : RETURN @"P9_23"
611  CASE P9_24 : RETURN @"P9_24"
612  CASE P9_25 : RETURN @"P9_25"
613  CASE P9_26 : RETURN @"P9_26"
614  CASE P9_27 : RETURN @"P9_27"
615  CASE P9_28 : RETURN @"P9_28"
616  CASE P9_29 : RETURN @"P9_29"
617  CASE P9_30 : RETURN @"P9_30"
618  CASE P9_31 : RETURN @"P9_31"
619  CASE P9_41 : RETURN @"P9_41"
620  CASE 106 : RETURN @"P9_41"
621  CASE P9_42 : RETURN @"P9_42"
622  CASE 104 : RETURN @"P9_42"
623  CASE JT_04 : RETURN @"JT_04"
624  CASE JT_05 : RETURN @"JT_05"
625  CASE SD_01 : RETURN @"SD_01"
626  CASE SD_02 : RETURN @"SD_02"
627  CASE SD_03 : RETURN @"SD_03"
628  CASE SD_05 : RETURN @"SD_05"
629  CASE SD_07 : RETURN @"SD_07"
630  CASE SD_08 : RETURN @"SD_08"
631  CASE SD_10 : RETURN @"SD_10"
632  END SELECT : RETURN 0
633 END FUNCTION
634 
635 
636 
655 FUNCTION PruIo.rb_start CDECL() AS ZSTRING PTR
656  IF DRam[0] <> PRUIO_MSG_MM_WAIT THEN _
657  Errr = @"ring buffer mode not ready" : RETURN Errr
658 
659  DRam[1] = Adc->Samples SHL 1 ' size of ring buffer
660  DRam[2] = EAddr
661  DRam[3] = 0
662  DRam[4] = 1 SHL 4
663 
664  prussdrv_pru_clear_event(PRUIO_EVNT, PruIntNo) ' off we go
665  RETURN 0
666 END FUNCTION
667 
668 
669 
701 FUNCTION PruIo.mm_start CDECL( _
702  BYVAL Trg1 AS UInt32 = 0 _
703  , BYVAL Trg2 AS UInt32 = 0 _
704  , BYVAL Trg3 AS UInt32 = 0 _
705  , BYVAL Trg4 AS UInt32 = 0) AS ZSTRING PTR
706 
707  IF DRam[0] <> PRUIO_MSG_MM_WAIT THEN _
708  Errr = @"measurement mode not ready" : RETURN Errr
709 
710  STATIC AS UInt32 tmin = (1 SHL 22), t_pin
711  DRam[3] = 0
712 
713 #DEFINE PRUIO_PRE_TRIG(_T_) Trg##_T_ >= tmin ANDALSO (Trg##_T_ AND (1 SHL 4)) THEN : _
714  IF BIT(Trg##_T_, 5) ORELSE BIT(Adc->Conf->STEPENABLE, (Trg##_T_ AND &b1111) + 1) THEN : _
715  VAR n = (Trg##_T_ SHR 22) * Adc->ChAz : _
716  IF n < Adc->Samples THEN : DRam[3] = n SHL 1 : _
717  ELSE : Errr = @"Trg" #_T_ ": too much pre-trigger samples" : RETURN Errr : _
718  END IF : _
719  ELSE : Errr = @"Trg" #_T_ ": pre-trigger step must be active" : RETURN Errr : _
720  END IF
721 
722 #DEFINE PRUIO_GPIO_TRIG(_T_) BIT(Trg##_T_, 21) THEN : _
723  t_pin = (Trg##_T_ SHR 8) AND &b1111111 : _
724  IF t_pin > PRUIO_AZ_BALL THEN _
725  Errr = @"Trg" #_T_ ": unknown trigger pin number" : RETURN Errr : _
726  END IF : _
727  IF &b111 <> (BallConf[t_pin] AND &b111) THEN _
728  Errr = @"Trg" #_T_ ": trigger pin must be in mode 7 (GPIO)" : RETURN Errr : _
729  ELSE Trg##_T_ AND= &b11111111111100000000000011111111uL : _
730  Trg##_T_ OR= BallGpio(t_pin) SHL 8 : _
731  END IF : _
732  END IF
733 
734  IF Trg1 THEN
735  IF PRUIO_PRE_TRIG(1)
736  ELSE
737  IF PRUIO_GPIO_TRIG(1)
738  IF Trg2 THEN
739  IF PRUIO_PRE_TRIG(2)
740  ELSE
741  IF PRUIO_GPIO_TRIG(2)
742  IF Trg3 THEN
743  IF PRUIO_PRE_TRIG(3)
744  ELSE
745  IF PRUIO_GPIO_TRIG(3)
746  IF Trg4 THEN
747  IF PRUIO_PRE_TRIG(4)
748  ELSE
749  IF PRUIO_GPIO_TRIG(4)
750  END IF
751  END IF
752  END IF
753  END IF
754  END IF
755  END IF
756  END IF
757  END IF
758 
759  DRam[1] = ESize
760  DRam[2] = EAddr
761  DRam[4] = Trg1
762  DRam[5] = Trg2
763  DRam[6] = Trg3
764  DRam[7] = Trg4
765 
766  prussdrv_pru_clear_event(PRUIO_EVNT, PruIntNo) ' off we go
767 
768  prussdrv_pru_wait_event(PRUIO_EVNT) ' wait for end of measurement
769  prussdrv_pru_clear_event(PRUIO_EVNT, PRUIO_IRPT) ' clear interrupt
770  prussdrv_pru_send_event(PruIntNo) ' prepare next start
771  RETURN 0
772 END FUNCTION
773