lgpio 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/examples/{i2c_bitbang_search.rb → i2c_bb_search.rb} +2 -3
- data/examples/pwm_hw_bench.rb +20 -0
- data/ext/lgpio/lgpio.c +123 -290
- data/lib/lgpio/version.rb +1 -1
- metadata +26 -27
- data/examples/i2c_bitbang_aht10.rb +0 -40
- data/examples/i2c_bitbang_ssd1306_bench.rb +0 -35
- /data/examples/{bench_in.rb → gpio_bench_in.rb} +0 -0
- /data/examples/{bench_out.rb → gpio_bench_out.rb} +0 -0
- /data/examples/{blink.rb → gpio_blink.rb} +0 -0
- /data/examples/{group_in.rb → gpio_group_in.rb} +0 -0
- /data/examples/{group_out.rb → gpio_group_out.rb} +0 -0
- /data/examples/{momentary.rb → gpio_momentary.rb} +0 -0
- /data/examples/{reports.rb → gpio_reports.rb} +0 -0
- /data/examples/{rotary_encoder.rb → gpio_rotary_encoder.rb} +0 -0
- /data/examples/{rotary_encoder_led.rb → gpio_rotary_encoder_led.rb} +0 -0
- /data/examples/{wave.rb → gpio_wave.rb} +0 -0
- /data/examples/{i2c_bitbang-rb_aht10.rb → i2c_bb_aht10.rb} +0 -0
- /data/examples/{i2c_bitbang-rb_ssd1306_bench.rb → i2c_bb_ssd1306_bench.rb} +0 -0
- /data/examples/{i2c_aht10.rb → i2c_hw_aht10.rb} +0 -0
- /data/examples/{i2c_aht10_zip.rb → i2c_hw_aht10_zip.rb} +0 -0
- /data/examples/{i2c_ssd1306_bench.rb → i2c_hw_ssd1306_bench.rb} +0 -0
- /data/examples/{servo.rb → pwm_hw_servo.rb} +0 -0
- /data/examples/{pwm.rb → pwm_sw.rb} +0 -0
- /data/examples/{spi_bitbang_loopback.rb → spi_bb_loopback.rb} +0 -0
- /data/examples/{spi_bitbang_ssd1306_sim_bench.rb → spi_bb_sim_bench.rb} +0 -0
- /data/examples/{spi_bitbang_ssd1306_bench.rb → spi_bb_ssd1306_bench.rb} +0 -0
- /data/examples/{spi_loopback.rb → spi_hw_loopback.rb} +0 -0
- /data/examples/{spi_ws2812.rb → spi_hw_ws2812.rb} +0 -0
- /data/examples/{spi_ws2812_bounce.rb → spi_hw_ws2812_bounce.rb} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 175af29acc6f0bb362dc017458e1ca9948f5d0c73ac0693f4a06b2e4e64f2842
|
4
|
+
data.tar.gz: c7eebe2b025a40e98c3e7fc7574eb1f7572e7c147a88a32d7b4a9bfdb0cb0882
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e3f5bfc169dfeb319fdfc06c4de1058682e9bee1f547a9eebecc1eb9ad2d50403bda912a67aef171e66b828d22740b04925b83c0e3494204c73c0b32dbbe7931
|
7
|
+
data.tar.gz: f3d17767bf96c7af4631945ac0a7812628698cb483634fc0c1a45513a8ac5107bc613799be32b95b2c4b251e51a4c95c253f107691767d5351b8b1e073f5d965
|
@@ -5,9 +5,8 @@ SCL_PIN = 228
|
|
5
5
|
SDA_PIN = 270
|
6
6
|
|
7
7
|
chip_handle = LGPIO.chip_open(GPIO_CHIP)
|
8
|
-
LGPIO.
|
9
|
-
|
10
|
-
devices = LGPIO.i2c_bb_search(chip_handle, SCL_PIN, SDA_PIN)
|
8
|
+
i2c_bb = LGPIO::I2CBitBang.new(chip_handle, SCL_PIN, SDA_PIN)
|
9
|
+
devices = i2c_bb.search
|
11
10
|
|
12
11
|
if devices.empty?
|
13
12
|
puts "No devices found on I2C bus"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'lgpio'
|
2
|
+
#
|
3
|
+
# Writing directly to a hardware PWM channel.
|
4
|
+
# Arguments in order are:
|
5
|
+
# pwmchip index (X in /sys/class/pwm/pwmchipX/)
|
6
|
+
# PWM channel on the chip (Y in /sys/class/pwm/pwmchipX/pwmY)
|
7
|
+
# period: given in nanoseconds
|
8
|
+
# OR frequency: given in Hz
|
9
|
+
#
|
10
|
+
pwm_out = LGPIO::HardwarePWM.new(0, 1, period: 20_000_000)
|
11
|
+
|
12
|
+
RUNS = 250_000
|
13
|
+
start = Time.now
|
14
|
+
RUNS.times do
|
15
|
+
pwm_out.duty_us = 1000
|
16
|
+
end
|
17
|
+
finish = Time.now
|
18
|
+
|
19
|
+
wps = RUNS / (finish - start)
|
20
|
+
puts "Hardware PWM writes per second: #{wps.round(2)}"
|
data/ext/lgpio/lgpio.c
CHANGED
@@ -3,13 +3,19 @@
|
|
3
3
|
#include <stdio.h>
|
4
4
|
#include <time.h>
|
5
5
|
|
6
|
-
|
6
|
+
/*****************************************************************************/
|
7
|
+
/* GPIO REPORT QUEUE */
|
8
|
+
/*****************************************************************************/
|
7
9
|
static pthread_mutex_t queueLock;
|
10
|
+
// Set up a queue for up to 2**16 GPIO reports.
|
8
11
|
#define QUEUE_LENGTH UINT16_MAX + 1
|
9
12
|
static lgGpioReport_t reportQueue[QUEUE_LENGTH];
|
10
13
|
static uint16_t qWritePos = 1;
|
11
14
|
static uint16_t qReadPos = 0;
|
12
15
|
|
16
|
+
/*****************************************************************************/
|
17
|
+
/* TIMING HELPERS */
|
18
|
+
/*****************************************************************************/
|
13
19
|
static uint64_t nanoDiff(const struct timespec *event2, const struct timespec *event1) {
|
14
20
|
uint64_t event2_ns = (uint64_t)event2->tv_sec * 1000000000LL + event2->tv_nsec;
|
15
21
|
uint64_t event1_ns = (uint64_t)event1->tv_sec * 1000000000LL + event1->tv_nsec;
|
@@ -36,6 +42,9 @@ static void microDelay(uint64_t micros) {
|
|
36
42
|
nanoDelay(micros * 1000);
|
37
43
|
}
|
38
44
|
|
45
|
+
/*****************************************************************************/
|
46
|
+
/* CHIP & GPIO */
|
47
|
+
/*****************************************************************************/
|
39
48
|
static VALUE chip_open(VALUE self, VALUE gpio_dev) {
|
40
49
|
int result = lgGpiochipOpen(NUM2INT(gpio_dev));
|
41
50
|
return INT2NUM(result);
|
@@ -162,103 +171,9 @@ static VALUE gpio_get_report(VALUE self){
|
|
162
171
|
return (popped) ? hash : Qnil;
|
163
172
|
}
|
164
173
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
int echo = NUM2UINT(rbEcho);
|
169
|
-
uint32_t triggerTime = NUM2UINT(rbTriggerTime);
|
170
|
-
struct timespec start;
|
171
|
-
struct timespec now;
|
172
|
-
bool echoSeen = false;
|
173
|
-
|
174
|
-
// Pull down avoids false readings if disconnected.
|
175
|
-
lgGpioClaimInput(handle, LG_SET_PULL_DOWN, echo);
|
176
|
-
|
177
|
-
// Initial pulse on the triger pin.
|
178
|
-
lgGpioClaimOutput(handle, LG_SET_PULL_NONE, trigger, 0);
|
179
|
-
microDelay(5);
|
180
|
-
lgGpioWrite(handle, trigger, 1);
|
181
|
-
microDelay(triggerTime);
|
182
|
-
lgGpioWrite(handle, trigger, 0);
|
183
|
-
|
184
|
-
clock_gettime(CLOCK_MONOTONIC, &start);
|
185
|
-
now = start;
|
186
|
-
|
187
|
-
// Wait for echo to go high, up to 25,000 us after trigger.
|
188
|
-
while(nanoDiff(&now, &start) < 25000000){
|
189
|
-
clock_gettime(CLOCK_MONOTONIC, &now);
|
190
|
-
if (lgGpioRead(handle, echo) == 1) {
|
191
|
-
echoSeen = true;
|
192
|
-
start = now;
|
193
|
-
break;
|
194
|
-
}
|
195
|
-
}
|
196
|
-
if (!echoSeen) return Qnil;
|
197
|
-
|
198
|
-
// Wait for echo to go low again, up to 25,000 us after echo start.
|
199
|
-
while(nanoDiff(&now, &start) < 25000000){
|
200
|
-
clock_gettime(CLOCK_MONOTONIC, &now);
|
201
|
-
if (lgGpioRead(handle, echo) == 0) break;
|
202
|
-
}
|
203
|
-
|
204
|
-
// High pulse time in microseconds.
|
205
|
-
return INT2NUM(round(nanoDiff(&now, &start) / 1000.0));
|
206
|
-
}
|
207
|
-
|
208
|
-
static VALUE gpio_read_pulses_us(VALUE self, VALUE rbHandle, VALUE rbGPIO, VALUE rbReset_us, VALUE rbResetLevel, VALUE rbLimit, VALUE rbTimeout_ms) {
|
209
|
-
// C values
|
210
|
-
int handle = NUM2INT(rbHandle);
|
211
|
-
int gpio = NUM2INT(rbGPIO);
|
212
|
-
uint32_t reset_us = NUM2UINT(rbReset_us);
|
213
|
-
uint8_t resetLevel = NUM2UINT(rbResetLevel);
|
214
|
-
uint32_t limit = NUM2UINT(rbLimit);
|
215
|
-
uint64_t timeout_ns = NUM2UINT(rbTimeout_ms) * 1000000;
|
216
|
-
|
217
|
-
// State setup
|
218
|
-
uint64_t pulses_ns[limit];
|
219
|
-
uint32_t pulseIndex = 0;
|
220
|
-
int gpioState;
|
221
|
-
struct timespec start;
|
222
|
-
struct timespec lastPulse;
|
223
|
-
struct timespec now;
|
224
|
-
|
225
|
-
// Perform reset
|
226
|
-
if (reset_us > 0) {
|
227
|
-
int result = lgGpioClaimOutput(handle, LG_SET_PULL_NONE, gpio, resetLevel);
|
228
|
-
if (result < 0) return NUM2INT(result);
|
229
|
-
microDelay(reset_us);
|
230
|
-
}
|
231
|
-
|
232
|
-
// Initialize timing
|
233
|
-
clock_gettime(CLOCK_MONOTONIC, &start);
|
234
|
-
lastPulse = start;
|
235
|
-
now = start;
|
236
|
-
|
237
|
-
// Switch to input and read initial state
|
238
|
-
lgGpioClaimInput(handle, LG_SET_PULL_NONE, gpio);
|
239
|
-
gpioState = lgGpioRead(handle, gpio);
|
240
|
-
|
241
|
-
// Read pulses in nanoseconds
|
242
|
-
while ((nanoDiff(&now, &start) < timeout_ns) && (pulseIndex < limit)) {
|
243
|
-
clock_gettime(CLOCK_MONOTONIC, &now);
|
244
|
-
if (lgGpioRead(handle, gpio) != gpioState) {
|
245
|
-
pulses_ns[pulseIndex] = nanoDiff(&now, &lastPulse);
|
246
|
-
lastPulse = now;
|
247
|
-
gpioState = gpioState ^ 0b1;
|
248
|
-
pulseIndex++;
|
249
|
-
}
|
250
|
-
}
|
251
|
-
|
252
|
-
// Return Ruby array of pulse as microseconds
|
253
|
-
if (pulseIndex == 0) return Qnil;
|
254
|
-
VALUE retArray = rb_ary_new2(pulseIndex);
|
255
|
-
for(int i=0; i<pulseIndex; i++){
|
256
|
-
uint32_t pulse_us = round(pulses_ns[i] / 1000.0);
|
257
|
-
rb_ary_store(retArray, i, UINT2NUM(pulse_us));
|
258
|
-
}
|
259
|
-
return retArray;
|
260
|
-
}
|
261
|
-
|
174
|
+
/*****************************************************************************/
|
175
|
+
/* SOFTWARE PWM & WAVE */
|
176
|
+
/*****************************************************************************/
|
262
177
|
static VALUE tx_busy(VALUE self, VALUE handle, VALUE gpio, VALUE kind) {
|
263
178
|
int result = lgTxBusy(NUM2INT(handle), NUM2INT(gpio), NUM2INT(kind));
|
264
179
|
return INT2NUM(result);
|
@@ -302,6 +217,9 @@ static VALUE tx_wave(VALUE self, VALUE handle, VALUE lead_gpio, VALUE pulses) {
|
|
302
217
|
return INT2NUM(result);
|
303
218
|
}
|
304
219
|
|
220
|
+
/*****************************************************************************/
|
221
|
+
/* HARDWARE PWM OOK WAVE */
|
222
|
+
/*****************************************************************************/
|
305
223
|
static VALUE tx_wave_ook(VALUE self, VALUE dutyPath, VALUE dutyString, VALUE pulses) {
|
306
224
|
// NOTE: This uses hardware PWM, NOT the lgpio software PWM/wave interface.
|
307
225
|
// The Ruby class LGPIO::HardwarePWM should have already set the PWM carrier frequency.
|
@@ -343,6 +261,9 @@ static VALUE tx_wave_ook(VALUE self, VALUE dutyPath, VALUE dutyString, VALUE pul
|
|
343
261
|
fclose(dutyFile);
|
344
262
|
}
|
345
263
|
|
264
|
+
/*****************************************************************************/
|
265
|
+
/* HARDWARE I2C */
|
266
|
+
/*****************************************************************************/
|
346
267
|
static VALUE i2c_open(VALUE self, VALUE i2cDev, VALUE i2cAddr, VALUE i2cFlags){
|
347
268
|
int handle = lgI2cOpen(NUM2INT(i2cDev), NUM2INT(i2cAddr), NUM2INT(i2cFlags));
|
348
269
|
return INT2NUM(handle);
|
@@ -406,6 +327,9 @@ static VALUE i2c_zip(VALUE self, VALUE handle, VALUE txArray, VALUE rb_rxCount){
|
|
406
327
|
return retArray;
|
407
328
|
}
|
408
329
|
|
330
|
+
/*****************************************************************************/
|
331
|
+
/* HARDWARE SPI */
|
332
|
+
/*****************************************************************************/
|
409
333
|
static VALUE spi_open(VALUE self, VALUE spiDev, VALUE spiChan, VALUE spiBaud, VALUE spiFlags){
|
410
334
|
int handle = lgSpiOpen(NUM2INT(spiDev), NUM2INT(spiChan), NUM2INT(spiBaud), NUM2INT(spiFlags));
|
411
335
|
return INT2NUM(handle);
|
@@ -506,32 +430,108 @@ static VALUE spi_ws2812_write(VALUE self, VALUE handle, VALUE pixelArray){
|
|
506
430
|
}
|
507
431
|
|
508
432
|
/*****************************************************************************/
|
509
|
-
/*
|
433
|
+
/* BIT-BANG PULSE INPUT */
|
510
434
|
/*****************************************************************************/
|
511
|
-
static
|
512
|
-
|
513
|
-
|
435
|
+
static VALUE gpio_read_ultrasonic(VALUE self, VALUE rbHandle, VALUE rbTrigger, VALUE rbEcho, VALUE rbTriggerTime) {
|
436
|
+
int handle = NUM2UINT(rbHandle);
|
437
|
+
int trigger = NUM2UINT(rbTrigger);
|
438
|
+
int echo = NUM2UINT(rbEcho);
|
439
|
+
uint32_t triggerTime = NUM2UINT(rbTriggerTime);
|
440
|
+
struct timespec start;
|
441
|
+
struct timespec now;
|
442
|
+
bool echoSeen = false;
|
514
443
|
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
444
|
+
// Pull down avoids false readings if disconnected.
|
445
|
+
lgGpioClaimInput(handle, LG_SET_PULL_DOWN, echo);
|
446
|
+
|
447
|
+
// Initial pulse on the triger pin.
|
448
|
+
lgGpioClaimOutput(handle, LG_SET_PULL_NONE, trigger, 0);
|
449
|
+
microDelay(5);
|
450
|
+
lgGpioWrite(handle, trigger, 1);
|
451
|
+
microDelay(triggerTime);
|
452
|
+
lgGpioWrite(handle, trigger, 0);
|
453
|
+
|
454
|
+
clock_gettime(CLOCK_MONOTONIC, &start);
|
455
|
+
now = start;
|
456
|
+
|
457
|
+
// Wait for echo to go high, up to 25,000 us after trigger.
|
458
|
+
while(nanoDiff(&now, &start) < 25000000){
|
459
|
+
clock_gettime(CLOCK_MONOTONIC, &now);
|
460
|
+
if (lgGpioRead(handle, echo) == 1) {
|
461
|
+
echoSeen = true;
|
462
|
+
start = now;
|
463
|
+
break;
|
464
|
+
}
|
465
|
+
}
|
466
|
+
if (!echoSeen) return Qnil;
|
467
|
+
|
468
|
+
// Wait for echo to go low again, up to 25,000 us after echo start.
|
469
|
+
while(nanoDiff(&now, &start) < 25000000){
|
470
|
+
clock_gettime(CLOCK_MONOTONIC, &now);
|
471
|
+
if (lgGpioRead(handle, echo) == 0) break;
|
520
472
|
}
|
521
|
-
}
|
522
473
|
|
523
|
-
|
524
|
-
return (
|
474
|
+
// High pulse time in microseconds.
|
475
|
+
return INT2NUM(round(nanoDiff(&now, &start) / 1000.0));
|
525
476
|
}
|
526
477
|
|
527
|
-
static
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
478
|
+
static VALUE gpio_read_pulses_us(VALUE self, VALUE rbHandle, VALUE rbGPIO, VALUE rbReset_us, VALUE rbResetLevel, VALUE rbLimit, VALUE rbTimeout_ms) {
|
479
|
+
// C values
|
480
|
+
int handle = NUM2INT(rbHandle);
|
481
|
+
int gpio = NUM2INT(rbGPIO);
|
482
|
+
uint32_t reset_us = NUM2UINT(rbReset_us);
|
483
|
+
uint8_t resetLevel = NUM2UINT(rbResetLevel);
|
484
|
+
uint32_t limit = NUM2UINT(rbLimit);
|
485
|
+
uint64_t timeout_ns = NUM2UINT(rbTimeout_ms) * 1000000;
|
486
|
+
|
487
|
+
// State setup
|
488
|
+
uint64_t pulses_ns[limit];
|
489
|
+
uint32_t pulseIndex = 0;
|
490
|
+
int gpioState;
|
491
|
+
struct timespec start;
|
492
|
+
struct timespec lastPulse;
|
493
|
+
struct timespec now;
|
494
|
+
|
495
|
+
// Perform reset
|
496
|
+
if (reset_us > 0) {
|
497
|
+
int result = lgGpioClaimOutput(handle, LG_SET_PULL_NONE, gpio, resetLevel);
|
498
|
+
if (result < 0) return NUM2INT(result);
|
499
|
+
microDelay(reset_us);
|
500
|
+
}
|
501
|
+
|
502
|
+
// Initialize timing
|
503
|
+
clock_gettime(CLOCK_MONOTONIC, &start);
|
504
|
+
lastPulse = start;
|
505
|
+
now = start;
|
506
|
+
|
507
|
+
// Switch to input and read initial state
|
508
|
+
lgGpioClaimInput(handle, LG_SET_PULL_NONE, gpio);
|
509
|
+
gpioState = lgGpioRead(handle, gpio);
|
510
|
+
|
511
|
+
// Read pulses in nanoseconds
|
512
|
+
while ((nanoDiff(&now, &start) < timeout_ns) && (pulseIndex < limit)) {
|
513
|
+
clock_gettime(CLOCK_MONOTONIC, &now);
|
514
|
+
if (lgGpioRead(handle, gpio) != gpioState) {
|
515
|
+
pulses_ns[pulseIndex] = nanoDiff(&now, &lastPulse);
|
516
|
+
lastPulse = now;
|
517
|
+
gpioState = gpioState ^ 0b1;
|
518
|
+
pulseIndex++;
|
519
|
+
}
|
532
520
|
}
|
521
|
+
|
522
|
+
// Return Ruby array of pulse as microseconds
|
523
|
+
if (pulseIndex == 0) return Qnil;
|
524
|
+
VALUE retArray = rb_ary_new2(pulseIndex);
|
525
|
+
for(int i=0; i<pulseIndex; i++){
|
526
|
+
uint32_t pulse_us = round(pulses_ns[i] / 1000.0);
|
527
|
+
rb_ary_store(retArray, i, UINT2NUM(pulse_us));
|
528
|
+
}
|
529
|
+
return retArray;
|
533
530
|
}
|
534
531
|
|
532
|
+
/*****************************************************************************/
|
533
|
+
/* BIT BANG 1-WIRE HEPERS */
|
534
|
+
/*****************************************************************************/
|
535
535
|
static VALUE one_wire_bit_read(VALUE self, VALUE rbHandle, VALUE rbGPIO) {
|
536
536
|
int handle = NUM2INT(rbHandle);
|
537
537
|
int gpio = NUM2INT(rbGPIO);
|
@@ -598,167 +598,6 @@ static VALUE one_wire_reset(VALUE self, VALUE rbHandle, VALUE rbGPIO) {
|
|
598
598
|
return UINT2NUM(presence);
|
599
599
|
}
|
600
600
|
|
601
|
-
/*****************************************************************************/
|
602
|
-
/* BIT-BANG I2C */
|
603
|
-
/*****************************************************************************/
|
604
|
-
static uint8_t sdaState = 1;
|
605
|
-
|
606
|
-
static void i2c_bb_set_sda(int handle, int sda, uint8_t level) {
|
607
|
-
if (level == sdaState) return;
|
608
|
-
lgGpioWrite(handle, sda, level);
|
609
|
-
sdaState = level;
|
610
|
-
}
|
611
|
-
|
612
|
-
// Start condition is SDA then SCL going low, from both high.
|
613
|
-
static void i2c_bb_start(int handle, int scl, int sda) {
|
614
|
-
lgGpioWrite(handle, sda, 0);
|
615
|
-
lgGpioWrite(handle, scl, 0);
|
616
|
-
}
|
617
|
-
|
618
|
-
// Stop condition is SDA going high, while SCL is also high.
|
619
|
-
static void i2c_bb_stop(int handle, int scl, int sda) {
|
620
|
-
lgGpioWrite(handle, sda, 0);
|
621
|
-
lgGpioWrite(handle, scl, 1);
|
622
|
-
lgGpioWrite(handle, sda, 1);
|
623
|
-
}
|
624
|
-
|
625
|
-
static uint8_t i2c_bb_read_bit(int handle, int scl, int sda) {
|
626
|
-
uint8_t bit;
|
627
|
-
// Ensure SDA high before we pull SCL high.
|
628
|
-
i2c_bb_set_sda(handle, sda, 1);
|
629
|
-
lgGpioWrite(handle, scl, 1);
|
630
|
-
bit = lgGpioRead(handle, sda);
|
631
|
-
lgGpioWrite(handle, scl, 0);
|
632
|
-
return bit;
|
633
|
-
}
|
634
|
-
|
635
|
-
static void i2c_bb_write_bit(int handle, int scl, int sda, uint8_t bit) {
|
636
|
-
// Set SDA while SCL is low.
|
637
|
-
i2c_bb_set_sda(handle, sda, bit);
|
638
|
-
lgGpioWrite(handle, scl, 1);
|
639
|
-
lgGpioWrite(handle, scl, 0);
|
640
|
-
}
|
641
|
-
|
642
|
-
static uint8_t i2c_bb_read_byte(int handle, int scl, int sda, bool ack) {
|
643
|
-
uint8_t b;
|
644
|
-
|
645
|
-
// Receive MSB first.
|
646
|
-
for (int i=7; i>=0; i--) bitWriteU8(&b, i, i2c_bb_read_bit(handle, scl, sda));
|
647
|
-
|
648
|
-
// Send ACK or NACK and return byte.
|
649
|
-
if (ack) {
|
650
|
-
i2c_bb_write_bit(handle, scl, sda, 0);
|
651
|
-
} else {
|
652
|
-
i2c_bb_write_bit(handle, scl, sda, 1);
|
653
|
-
}
|
654
|
-
return b;
|
655
|
-
}
|
656
|
-
|
657
|
-
static int i2c_bb_write_byte(int handle, int scl, int sda, uint8_t b) {
|
658
|
-
// Send MSB first.
|
659
|
-
for (int i=7; i>=0; i--) i2c_bb_write_bit(handle, scl, sda, bitReadU8(&b, i));
|
660
|
-
|
661
|
-
// Return -1 for NACK, 0 for ACK.
|
662
|
-
return (i2c_bb_read_bit(handle, scl, sda) == 0) ? 0 : -1;
|
663
|
-
}
|
664
|
-
|
665
|
-
static VALUE i2c_bb_claim(VALUE self, VALUE rbHandle, VALUE rbSCL, VALUE rbSDA) {
|
666
|
-
int handle = NUM2INT(rbHandle);
|
667
|
-
int scl = NUM2INT(rbSCL);
|
668
|
-
int sda = NUM2INT(rbSDA);
|
669
|
-
|
670
|
-
// SCL is a driven output. SDA is open drain with pullup enabled.
|
671
|
-
lgGpioClaimOutput(handle, LG_SET_PULL_NONE, scl, 1);
|
672
|
-
lgGpioClaimOutput(handle, LG_SET_OPEN_DRAIN | LG_SET_PULL_UP, sda, 1);
|
673
|
-
}
|
674
|
-
|
675
|
-
static VALUE i2c_bb_search(VALUE self, VALUE rbHandle, VALUE rbSCL, VALUE rbSDA) {
|
676
|
-
int handle = NUM2INT(rbHandle);
|
677
|
-
int scl = NUM2INT(rbSCL);
|
678
|
-
int sda = NUM2INT(rbSDA);
|
679
|
-
int ack;
|
680
|
-
uint8_t present[128];
|
681
|
-
uint8_t presentCount = 0;
|
682
|
-
sdaState = 1;
|
683
|
-
|
684
|
-
// Only addresses from 0x08 to 0x77 are usable (8 to 127).
|
685
|
-
for (uint8_t addr = 0x08; addr < 0x78; addr++) {
|
686
|
-
i2c_bb_start(handle, scl, sda);
|
687
|
-
ack = i2c_bb_write_byte(handle, scl, sda, ((addr << 1) & 0b11111110));
|
688
|
-
i2c_bb_stop(handle, scl, sda);
|
689
|
-
if (ack == 0){
|
690
|
-
present[addr] = 1;
|
691
|
-
presentCount++;
|
692
|
-
} else {
|
693
|
-
present[addr] = 0;
|
694
|
-
}
|
695
|
-
}
|
696
|
-
if (presentCount == 0) return Qnil;
|
697
|
-
|
698
|
-
VALUE retArray = rb_ary_new2(presentCount);
|
699
|
-
uint8_t i = 0;
|
700
|
-
for (uint8_t addr = 0x08; addr < 0x78; addr++) {
|
701
|
-
if (present[addr] == 1) {
|
702
|
-
rb_ary_store(retArray, i, UINT2NUM(addr));
|
703
|
-
i++;
|
704
|
-
}
|
705
|
-
}
|
706
|
-
return retArray;
|
707
|
-
}
|
708
|
-
|
709
|
-
static VALUE i2c_bb_write(VALUE self, VALUE rbHandle, VALUE rbSCL, VALUE rbSDA, VALUE rbAddress, VALUE txArray) {
|
710
|
-
int handle = NUM2INT(rbHandle);
|
711
|
-
int scl = NUM2INT(rbSCL);
|
712
|
-
int sda = NUM2INT(rbSDA);
|
713
|
-
uint8_t address = NUM2CHR(rbAddress);
|
714
|
-
uint8_t writeAddress = (address << 1);
|
715
|
-
sdaState = 1;
|
716
|
-
|
717
|
-
int count = RARRAY_LEN(txArray);
|
718
|
-
uint8_t txBuf[count];
|
719
|
-
VALUE currentByte;
|
720
|
-
for(int i=0; i<count; i++){
|
721
|
-
currentByte = rb_ary_entry(txArray, i);
|
722
|
-
Check_Type(currentByte, T_FIXNUM);
|
723
|
-
txBuf[i] = NUM2CHR(currentByte);
|
724
|
-
}
|
725
|
-
|
726
|
-
i2c_bb_start(handle, scl, sda);
|
727
|
-
i2c_bb_write_byte(handle, scl, sda, writeAddress);
|
728
|
-
for (int i=0; i<count; i++) i2c_bb_write_byte(handle, scl, sda, txBuf[i]);
|
729
|
-
i2c_bb_stop(handle, scl, sda);
|
730
|
-
}
|
731
|
-
|
732
|
-
static VALUE i2c_bb_read(VALUE self, VALUE rbHandle, VALUE rbSCL, VALUE rbSDA, VALUE rbAddress, VALUE rbCount) {
|
733
|
-
int handle = NUM2INT(rbHandle);
|
734
|
-
int scl = NUM2INT(rbSCL);
|
735
|
-
int sda = NUM2INT(rbSDA);
|
736
|
-
uint8_t address = NUM2CHR(rbAddress);
|
737
|
-
uint8_t readAddress = (address << 1) | 0b00000001;
|
738
|
-
sdaState = 1;
|
739
|
-
|
740
|
-
int count = NUM2INT(rbCount);
|
741
|
-
uint8_t rxBuf[count];
|
742
|
-
|
743
|
-
i2c_bb_start(handle, scl, sda);
|
744
|
-
int ack = i2c_bb_write_byte(handle, scl, sda, readAddress);
|
745
|
-
// Device with this address not present on the bus.
|
746
|
-
if (ack != 0) return Qnil;
|
747
|
-
|
748
|
-
// Read and ACK for all but the last byte.
|
749
|
-
int pos = 0;
|
750
|
-
while(pos < count-1) {
|
751
|
-
rxBuf[pos] = i2c_bb_read_byte(handle, scl, sda, true);
|
752
|
-
pos++;
|
753
|
-
}
|
754
|
-
rxBuf[pos] = i2c_bb_read_byte(handle, scl, sda, false);
|
755
|
-
i2c_bb_stop(handle, scl, sda);
|
756
|
-
|
757
|
-
VALUE retArray = rb_ary_new2(count);
|
758
|
-
for(int i=0; i<count; i++) rb_ary_store(retArray, i, UINT2NUM(rxBuf[i]));
|
759
|
-
return retArray;
|
760
|
-
}
|
761
|
-
|
762
601
|
/*****************************************************************************/
|
763
602
|
/* EXTENSION INIT */
|
764
603
|
/*****************************************************************************/
|
@@ -798,10 +637,6 @@ void Init_lgpio(void) {
|
|
798
637
|
rb_define_singleton_method(mLGPIO, "gpio_start_reporting", gpio_start_reporting, 0);
|
799
638
|
rb_define_singleton_method(mLGPIO, "gpio_get_report", gpio_get_report, 0);
|
800
639
|
|
801
|
-
// Pulse Input
|
802
|
-
rb_define_singleton_method(mLGPIO, "gpio_read_ultrasonic", gpio_read_ultrasonic, 4);
|
803
|
-
rb_define_singleton_method(mLGPIO, "gpio_read_pulses_us", gpio_read_pulses_us, 6);
|
804
|
-
|
805
640
|
// Soft PWM / Wave
|
806
641
|
rb_define_const(mLGPIO, "TX_PWM", INT2NUM(LG_TX_PWM));
|
807
642
|
rb_define_const(mLGPIO, "TX_WAVE",INT2NUM(LG_TX_WAVE));
|
@@ -813,6 +648,10 @@ void Init_lgpio(void) {
|
|
813
648
|
// Don't use this. Servo will jitter.
|
814
649
|
rb_define_singleton_method(mLGPIO, "tx_servo", tx_servo, 6);
|
815
650
|
|
651
|
+
// Hardware PWM waves for on-off-keying.
|
652
|
+
VALUE cHardwarePWM = rb_define_class_under(mLGPIO, "HardwarePWM", rb_cObject);
|
653
|
+
rb_define_method(cHardwarePWM, "tx_wave_ook", tx_wave_ook, 3);
|
654
|
+
|
816
655
|
// I2C
|
817
656
|
rb_define_singleton_method(mLGPIO, "i2c_open", i2c_open, 3);
|
818
657
|
rb_define_singleton_method(mLGPIO, "i2c_close", i2c_close, 1);
|
@@ -828,18 +667,12 @@ void Init_lgpio(void) {
|
|
828
667
|
rb_define_singleton_method(mLGPIO, "spi_xfer", spi_xfer, 2);
|
829
668
|
rb_define_singleton_method(mLGPIO, "spi_ws2812_write", spi_ws2812_write, 2);
|
830
669
|
|
831
|
-
//
|
832
|
-
|
833
|
-
|
670
|
+
// Bit-Bang Pulse Input
|
671
|
+
rb_define_singleton_method(mLGPIO, "gpio_read_ultrasonic", gpio_read_ultrasonic, 4);
|
672
|
+
rb_define_singleton_method(mLGPIO, "gpio_read_pulses_us", gpio_read_pulses_us, 6);
|
834
673
|
|
835
|
-
// Bit-
|
674
|
+
// Bit-bang 1-Wire Helpers
|
836
675
|
rb_define_singleton_method(mLGPIO, "one_wire_bit_read", one_wire_bit_read, 2);
|
837
676
|
rb_define_singleton_method(mLGPIO, "one_wire_bit_write", one_wire_bit_write, 3);
|
838
677
|
rb_define_singleton_method(mLGPIO, "one_wire_reset", one_wire_reset, 2);
|
839
|
-
|
840
|
-
// Bit-banged I2C
|
841
|
-
rb_define_singleton_method(mLGPIO, "i2c_bb_claim", i2c_bb_claim, 3);
|
842
|
-
rb_define_singleton_method(mLGPIO, "i2c_bb_search", i2c_bb_search, 3);
|
843
|
-
rb_define_singleton_method(mLGPIO, "i2c_bb_write", i2c_bb_write, 5);
|
844
|
-
rb_define_singleton_method(mLGPIO, "i2c_bb_read", i2c_bb_read, 5);
|
845
678
|
}
|
data/lib/lgpio/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lgpio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- vickash
|
@@ -21,37 +21,36 @@ files:
|
|
21
21
|
- LICENSE
|
22
22
|
- README.md
|
23
23
|
- Rakefile
|
24
|
-
- examples/bench_in.rb
|
25
|
-
- examples/bench_out.rb
|
26
|
-
- examples/blink.rb
|
27
24
|
- examples/dht.rb
|
28
|
-
- examples/
|
29
|
-
- examples/
|
25
|
+
- examples/gpio_bench_in.rb
|
26
|
+
- examples/gpio_bench_out.rb
|
27
|
+
- examples/gpio_blink.rb
|
28
|
+
- examples/gpio_group_in.rb
|
29
|
+
- examples/gpio_group_out.rb
|
30
|
+
- examples/gpio_momentary.rb
|
31
|
+
- examples/gpio_reports.rb
|
32
|
+
- examples/gpio_rotary_encoder.rb
|
33
|
+
- examples/gpio_rotary_encoder_led.rb
|
34
|
+
- examples/gpio_wave.rb
|
30
35
|
- examples/hcsr04.rb
|
31
|
-
- examples/
|
32
|
-
- examples/
|
33
|
-
- examples/
|
34
|
-
- examples/
|
35
|
-
- examples/
|
36
|
-
- examples/
|
37
|
-
- examples/i2c_bitbang_ssd1306_bench.rb
|
38
|
-
- examples/i2c_ssd1306_bench.rb
|
36
|
+
- examples/i2c_bb_aht10.rb
|
37
|
+
- examples/i2c_bb_search.rb
|
38
|
+
- examples/i2c_bb_ssd1306_bench.rb
|
39
|
+
- examples/i2c_hw_aht10.rb
|
40
|
+
- examples/i2c_hw_aht10_zip.rb
|
41
|
+
- examples/i2c_hw_ssd1306_bench.rb
|
39
42
|
- examples/infrared.rb
|
40
|
-
- examples/momentary.rb
|
41
43
|
- examples/one_wire_ds18b20.rb
|
42
44
|
- examples/one_wire_search.rb
|
43
|
-
- examples/
|
44
|
-
- examples/
|
45
|
-
- examples/
|
46
|
-
- examples/
|
47
|
-
- examples/
|
48
|
-
- examples/
|
49
|
-
- examples/
|
50
|
-
- examples/
|
51
|
-
- examples/
|
52
|
-
- examples/spi_ws2812.rb
|
53
|
-
- examples/spi_ws2812_bounce.rb
|
54
|
-
- examples/wave.rb
|
45
|
+
- examples/pwm_hw_bench.rb
|
46
|
+
- examples/pwm_hw_servo.rb
|
47
|
+
- examples/pwm_sw.rb
|
48
|
+
- examples/spi_bb_loopback.rb
|
49
|
+
- examples/spi_bb_sim_bench.rb
|
50
|
+
- examples/spi_bb_ssd1306_bench.rb
|
51
|
+
- examples/spi_hw_loopback.rb
|
52
|
+
- examples/spi_hw_ws2812.rb
|
53
|
+
- examples/spi_hw_ws2812_bounce.rb
|
55
54
|
- ext/lgpio/extconf.rb
|
56
55
|
- ext/lgpio/lgpio.c
|
57
56
|
- lgpio.gemspec
|
@@ -1,40 +0,0 @@
|
|
1
|
-
require 'lgpio'
|
2
|
-
|
3
|
-
POWER_ON_DELAY = 0.100
|
4
|
-
RESET_DELAY = 0.020
|
5
|
-
COMMAND_DELAY = 0.010
|
6
|
-
MEASURE_DELAY = 0.080
|
7
|
-
DATA_LENGTH = 6
|
8
|
-
SOFT_RESET = [0xBA]
|
9
|
-
INIT_AND_CALIBRATE = [0xE1, 0x08, 0x00]
|
10
|
-
START_MEASUREMENT = [0xAC, 0x33, 0x00]
|
11
|
-
|
12
|
-
GPIO_CHIP = 0
|
13
|
-
SCL_PIN = 228
|
14
|
-
SDA_PIN = 270
|
15
|
-
ADDRESS = 0x38
|
16
|
-
|
17
|
-
chip_handle = LGPIO.chip_open(GPIO_CHIP)
|
18
|
-
LGPIO.i2c_bb_claim(chip_handle, SCL_PIN, SDA_PIN)
|
19
|
-
|
20
|
-
# Startup sequence
|
21
|
-
sleep(POWER_ON_DELAY)
|
22
|
-
LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, SOFT_RESET)
|
23
|
-
sleep(RESET_DELAY)
|
24
|
-
LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, INIT_AND_CALIBRATE)
|
25
|
-
sleep(COMMAND_DELAY)
|
26
|
-
|
27
|
-
# Read and close
|
28
|
-
LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, START_MEASUREMENT)
|
29
|
-
sleep(MEASURE_DELAY)
|
30
|
-
bytes = LGPIO.i2c_bb_read(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, DATA_LENGTH)
|
31
|
-
|
32
|
-
# Humidity uses the upper 4 bits of the shared byte as its lowest 4 bits.
|
33
|
-
h_raw = ((bytes[1] << 16) | (bytes[2] << 8) | (bytes[3])) >> 4
|
34
|
-
humidity = (h_raw.to_f / 2**20) * 100
|
35
|
-
|
36
|
-
# Temperature uses the lower 4 bits of the shared byte as its highest 4 bits.
|
37
|
-
t_raw = ((bytes[3] & 0x0F) << 16) | (bytes[4] << 8) | bytes[5]
|
38
|
-
temperature = (t_raw.to_f / 2**20) * 200 - 50
|
39
|
-
|
40
|
-
puts "#{Time.now.strftime '%Y-%m-%d %H:%M:%S'} - Temperature: #{temperature.round(2)} \xC2\xB0C | Humidity: #{humidity.round(2)} %"
|
@@ -1,35 +0,0 @@
|
|
1
|
-
require 'lgpio'
|
2
|
-
|
3
|
-
INIT_ARRAY = [0, 168, 63, 211, 0, 64, 161, 200, 218, 18, 164, 166, 213, 128, 219, 32, 217, 241, 141, 20, 32, 0, 175]
|
4
|
-
START_ARRAY = [0, 33, 0, 127, 34, 0, 7]
|
5
|
-
PATTERN_1 = [64] + Array.new(1024) { 0b00110011 }
|
6
|
-
PATTERN_2 = [64] + Array.new(1024) { 0b11001100 }
|
7
|
-
|
8
|
-
GPIO_CHIP = 0
|
9
|
-
SCL_PIN = 228
|
10
|
-
SDA_PIN = 270
|
11
|
-
ADDRESS = 0x3C
|
12
|
-
|
13
|
-
chip_handle = LGPIO.chip_open(GPIO_CHIP)
|
14
|
-
LGPIO.i2c_bb_claim(chip_handle, SCL_PIN, SDA_PIN)
|
15
|
-
|
16
|
-
LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, INIT_ARRAY)
|
17
|
-
FRAME_COUNT = 400
|
18
|
-
|
19
|
-
start = Time.now
|
20
|
-
(FRAME_COUNT / 2).times do
|
21
|
-
LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, START_ARRAY)
|
22
|
-
LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, PATTERN_1)
|
23
|
-
LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, START_ARRAY)
|
24
|
-
LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, PATTERN_2)
|
25
|
-
end
|
26
|
-
finish = Time.now
|
27
|
-
|
28
|
-
LGPIO.chip_close(chip_handle)
|
29
|
-
|
30
|
-
fps = FRAME_COUNT / (finish - start)
|
31
|
-
# Also calculate C calls per second, using roughly 23 calls per byte written.
|
32
|
-
cps = (START_ARRAY.length + ((PATTERN_1.length + PATTERN_2.length) / 2) + 2) * 23 * fps
|
33
|
-
cps = (cps / 1000.0).round
|
34
|
-
|
35
|
-
puts "SSD1306 benchmark result: #{fps.round(2)} fps | #{cps}k C calls/s"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|