User avatar
John_Spikowski
Posts: 1322
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Fri May 31, 2019 1:00 am

Here is the ScriptBasic code I'm using and THIS is the Python code I'm tying to emulate in ScriptBasic.

gpio.bas

Code: Select all

'GPIO Extension Mondule

GLOBAL CONST SETUP_OK           = 0
GLOBAL CONST SETUP_DEVMEM_FAIL  = 1
GLOBAL CONST SETUP_MALLOC_FAIL  = 2
GLOBAL CONST SETUP_MMAP_FAIL    = 3
GLOBAL CONST SETUP_CPUINFO_FAIL = 4
GLOBAL CONST SETUP_NOT_RPI_FAIL = 5

' Is really 0 for control register!
GLOBAL CONST IN   = 1
' Is really 1 for control register!
GLOBAL CONST OUT  = 0
GLOBAL CONST ALT0 = 4

GLOBAL CONST HIGH    = 1
GLOBAL CONST LOW     = 0

GLOBAL CONST PUD_OFF  = 0
GLOBAL CONST PUD_DOWN = 1
GLOBAL CONST PUD_UP   = 2


MODULE GPIO

DECLARE SUB    ::Setup             ALIAS     "sb_setup"                 LIB "gpio"
DECLARE SUB    ::ClearEventDetect  ALIAS     "sb_clear_event_detect"    LIB "gpio"
DECLARE SUB    ::EventDetected     ALIAS     "sb_eventdetected"         LIB "gpio"
DECLARE SUB    ::SetRisingEvent    ALIAS     "sb_set_rising_event"      LIB "gpio"
DECLARE SUB    ::SetFallingEvent   ALIAS     "sb_set_falling_event"     LIB "gpio"
DECLARE SUB    ::SetHighEvent      ALIAS     "sb_set_high_event"        LIB "gpio"
DECLARE SUB    ::SetLowEvent       ALIAS     "sb_set_low_event"         LIB "gpio"
DECLARE SUB    ::SetPullUpDn       ALIAS     "sb_set_pullupdn"          LIB "gpio"
DECLARE SUB    ::SetupGPIO         ALIAS     "sb_setup_gpio"            LIB "gpio"
DECLARE SUB    ::GPIOFunction      ALIAS     "sb_gpio_function"         LIB "gpio"
DECLARE SUB    ::OutputGPIO        ALIAS     "sb_output_gpio"           LIB "gpio"
DECLARE SUB    ::InputGPIO         ALIAS     "sb_input_gpio"            LIB "gpio"
DECLARE SUB    ::Cleanup           ALIAS     "sb_cleanup"               LIB "gpio"
DECLARE SUB    ::ShortWait         ALIAS     "sb_short_wait"            LIB "gpio"

END MODULE
interface.c

Code: Select all

/* GPIO Extension Module
UXLIBS: -lc
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "c_gpio.h"
#include "../../basext.h"

#define BCM2708_PERI_BASE_DEFAULT   0x20000000
#define BCM2709_PERI_BASE_DEFAULT   0x3f000000
#define GPIO_BASE_OFFSET            0x200000
#define FSEL_OFFSET                 0   // 0x0000
#define SET_OFFSET                  7   // 0x001c / 4
#define CLR_OFFSET                  10  // 0x0028 / 4
#define PINLEVEL_OFFSET             13  // 0x0034 / 4
#define EVENT_DETECT_OFFSET         16  // 0x0040 / 4
#define RISING_ED_OFFSET            19  // 0x004c / 4
#define FALLING_ED_OFFSET           22  // 0x0058 / 4
#define HIGH_DETECT_OFFSET          25  // 0x0064 / 4
#define LOW_DETECT_OFFSET           28  // 0x0070 / 4
#define PULLUPDN_OFFSET             37  // 0x0094 / 4
#define PULLUPDNCLK_OFFSET          38  // 0x0098 / 4

#define PAGE_SIZE  (4*1024)
#define BLOCK_SIZE (4*1024)

static volatile uint32_t *gpio_map;

static void short_wait(void)
{
    int i;

    for (i=0; i<150; i++) {    // wait 150 cycles
        asm volatile("nop");
    }
}

static void clear_event_detect(int gpio)
{
    int offset = EVENT_DETECT_OFFSET + (gpio/32);
    int shift = (gpio%32);

    *(gpio_map+offset) |= (1 << shift);
    short_wait();
    *(gpio_map+offset) = 0;
}

static void set_pullupdn(int gpio, int pud)
{
    int clk_offset = PULLUPDNCLK_OFFSET + (gpio/32);
    int shift = (gpio%32);

    if (pud == PUD_DOWN)
        *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_DOWN;
    else if (pud == PUD_UP)
        *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_UP;
    else  // pud == PUD_OFF
        *(gpio_map+PULLUPDN_OFFSET) &= ~3;

    short_wait();
    *(gpio_map+clk_offset) = 1 << shift;
    short_wait();
    *(gpio_map+PULLUPDN_OFFSET) &= ~3;
    *(gpio_map+clk_offset) = 0;
}

/**************************
 Extension Module Functions
**************************/

typedef struct _ModuleObject {
  void *HandleArray;
}ModuleObject,*pModuleObject;


besVERSION_NEGOTIATE
  return (int)INTERFACE_VERSION;
besEND


besSUB_START
  pModuleObject p;

  besMODULEPOINTER = besALLOC(sizeof(ModuleObject));
  if( besMODULEPOINTER == NULL )return 0;

  p = (pModuleObject)besMODULEPOINTER;
  return 0;
besEND


besSUB_FINISH
  pModuleObject p;

  p = (pModuleObject)besMODULEPOINTER;
  if( p == NULL )return 0;
  return 0;
besEND



/***************
 GPIO Functions
***************/


besFUNCTION(sb_short_wait)
    int i;

    for (i=0; i<150; i++) {    // wait 150 cycles
        asm volatile("nop");
    }
besEND



besFUNCTION(sb_setup)
    int mem_fd;
    uint8_t *gpio_mem;
    uint32_t peri_base = 0;
    uint32_t gpio_base;
    unsigned char buf[4];
    FILE *fp;
    char buffer[1024];
    char hardware[1024];
    int found = 0;

    // try /dev/gpiomem first - this does not require root privs
    if ((mem_fd = open("/dev/gpiomem", O_RDWR|O_SYNC)) > 0)
    {
        if ((gpio_map = (uint32_t *)mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0)) == MAP_FAILED) {
            besRETURN_LONG(SETUP_MMAP_FAIL);
        } else {
            besRETURN_LONG(SETUP_OK);
        }
    }
    // revert to /dev/mem method - requires root

    // determine peri_base
    if ((fp = fopen("/proc/device-tree/soc/ranges", "rb")) != NULL) {
        // get peri base from device tree
        fseek(fp, 4, SEEK_SET);
        if (fread(buf, 1, sizeof buf, fp) == sizeof buf) {
            peri_base = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
        }
        fclose(fp);
    } else {
        // guess peri base based on /proc/cpuinfo hardware field
        if ((fp = fopen("/proc/cpuinfo", "r")) == NULL)
            besRETURN_LONG(SETUP_CPUINFO_FAIL);

        while(!feof(fp) && !found && fgets(buffer, sizeof(buffer), fp)) {
            sscanf(buffer, "Hardware	: %s", hardware);
            if (strcmp(hardware, "BCM2708") == 0 || strcmp(hardware, "BCM2835") == 0) {
                // pi 1 hardware
                peri_base = BCM2708_PERI_BASE_DEFAULT;
                found = 1;
            } else if (strcmp(hardware, "BCM2709") == 0 || strcmp(hardware, "BCM2836") == 0) {
                // pi 2 hardware
                peri_base = BCM2709_PERI_BASE_DEFAULT;
                found = 1;
            }
        }
        fclose(fp);
        if (!found)
            besRETURN_LONG(SETUP_NOT_RPI_FAIL);
    }

    if (!peri_base)
        besRETURN_LONG(SETUP_NOT_RPI_FAIL);
    gpio_base = peri_base + GPIO_BASE_OFFSET;

    // mmap the GPIO memory registers
    if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0)
        besRETURN_LONG(SETUP_DEVMEM_FAIL);

    if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
        besRETURN_LONG(SETUP_MALLOC_FAIL);

    if ((uint32_t)gpio_mem % PAGE_SIZE)
        gpio_mem += PAGE_SIZE - ((uint32_t)gpio_mem % PAGE_SIZE);

    if ((gpio_map = (uint32_t *)mmap( (void *)gpio_mem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, mem_fd, gpio_base)) == MAP_FAILED)
        besRETURN_LONG(SETUP_MMAP_FAIL);

    besRETURN_LONG(SETUP_OK);
besEND


besFUNCTION(sb_clear_event_detect)
  int gpio;
  besARGUMENTS("i")
    &gpio
  besARGEND
  int offset = EVENT_DETECT_OFFSET + (gpio/32);
  int shift = (gpio%32);
  *(gpio_map+offset) |= (1 << shift);
  short_wait();
  *(gpio_map+offset) = 0;
besEND


besFUNCTION(sb_eventdetected)
  int gpio;
  besARGUMENTS("i")
    &gpio
  besARGEND
  int offset, value, bit;
  offset = EVENT_DETECT_OFFSET + (gpio/32);
  bit = (1 << (gpio%32));
  value = *(gpio_map+offset) & bit;
  if (value)
    clear_event_detect(gpio);
  besRETURN_LONG(value);
besEND


besFUNCTION(sb_set_rising_event)
  int gpio, enable;
  besARGUMENTS("ii")
    &gpio, &enable
  besARGEND
  int offset = RISING_ED_OFFSET + (gpio/32);
  int shift = (gpio%32);
  if (enable)
    *(gpio_map+offset) |= 1 << shift;
  else
    *(gpio_map+offset) &= ~(1 << shift);
  clear_event_detect(gpio);
besEND


besFUNCTION(sb_set_falling_event)
  int gpio, enable;
  besARGUMENTS("ii")
    &gpio, &enable
  besARGEND
  int offset = FALLING_ED_OFFSET + (gpio/32);
  int shift = (gpio%32);
  if (enable) {
    *(gpio_map+offset) |= (1 << shift);
    *(gpio_map+offset) = (1 << shift);
  } else {
    *(gpio_map+offset) &= ~(1 << shift);
  }
  clear_event_detect(gpio);
besEND


besFUNCTION(sb_set_high_event)
  int gpio, enable;
  besARGUMENTS("ii")
    &gpio, &enable
  besARGEND
  int offset = HIGH_DETECT_OFFSET + (gpio/32);
  int shift = (gpio%32);
  if (enable)
    *(gpio_map+offset) |= (1 << shift);
  else
    *(gpio_map+offset) &= ~(1 << shift);
  clear_event_detect(gpio);
besEND


besFUNCTION(sb_set_low_event)
  int gpio, enable;
  besARGUMENTS("ii")
    &gpio, &enable
  besARGEND
  int offset = LOW_DETECT_OFFSET + (gpio/32);
  int shift = (gpio%32);
  if (enable)
    *(gpio_map+offset) |= 1 << shift;
  else
    *(gpio_map+offset) &= ~(1 << shift);
  clear_event_detect(gpio);
besEND


besFUNCTION(sb_set_pullupdn)
  int gpio, pud;
  besARGUMENTS("ii")
    &gpio, &pud
  besARGEND
  int clk_offset = PULLUPDNCLK_OFFSET + (gpio/32);
  int shift = (gpio%32);
  if (pud == PUD_DOWN)
    *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_DOWN;
  else if (pud == PUD_UP)
    *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_UP;
  else  // pud == PUD_OFF
    *(gpio_map+PULLUPDN_OFFSET) &= ~3;
    short_wait();
    *(gpio_map+clk_offset) = 1 << shift;
    short_wait();
    *(gpio_map+PULLUPDN_OFFSET) &= ~3;
    *(gpio_map+clk_offset) = 0;
besEND


besFUNCTION(sb_setup_gpio)
int gpio, direction, pud;
  besARGUMENTS("iii")
    &gpio, &direction, &pud
  besARGEND
  int offset = FSEL_OFFSET + (gpio/10);
  int shift = (gpio%10)*3;
  set_pullupdn(gpio, pud);
  if (direction == OUTPUT)
    *(gpio_map+offset) = (*(gpio_map+offset) & ~(7<<shift)) | (1<<shift);
  else  // direction == INPUT
    *(gpio_map+offset) = (*(gpio_map+offset) & ~(7<<shift));
besEND


besFUNCTION(sb_gpio_function)
  int gpio;
  besARGUMENTS("i")
    &gpio
  besARGEND
    int offset = FSEL_OFFSET + (gpio/10);
    int shift = (gpio%10)*3;
    int value = *(gpio_map+offset);
    value >>= shift;
    value &= 7;
    besRETURN_LONG(value); // 0=input, 1=output, 4=alt0
besEND


besFUNCTION(sb_output_gpio)
  int gpio, value;
  besARGUMENTS("ii")
    &gpio, &value
  besARGEND
  int offset, shift;
  if (value) // value == HIGH
    offset = SET_OFFSET + (gpio/32);
  else       // value == LOW
    offset = CLR_OFFSET + (gpio/32);
  shift = (gpio%32);
  *(gpio_map+offset) = 1 << shift;
besEND


besFUNCTION(sb_input_gpio)
  int gpio;
  besARGUMENTS("i")
    &gpio
  besARGEND
  int offset, value, mask;
  offset = PINLEVEL_OFFSET + (gpio/32);
  mask = (1 << gpio%32);
  value = *(gpio_map+offset) & mask;
  besRETURN_LONG(value);
besEND


besFUNCTION(sb_cleanup)
  munmap((void *)gpio_map, BLOCK_SIZE);
besEND
Last edited by John_Spikowski on Fri May 31, 2019 1:50 am, edited 1 time in total.

hippy
Posts: 5753
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: ScriptBasic

Fri May 31, 2019 1:22 am

ScriptBasic wrote:
Thu May 30, 2019 8:38 pm
I have been trying to get the ScriptBasic GPIO extension module working with the DHT11 and this is where I'm at.
In your FOR-NEXT loop read of the input; how quickly is it sampling the data ?

I wouldn't know how to determine that other than by replacing the input read with an output high then an output low and looking at the pin with a logic analyser or scope.

User avatar
John_Spikowski
Posts: 1322
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Fri May 31, 2019 1:47 am

I moved the cleanup function to the start of the process. It looks like this function just clears a buffer.

Code: Select all

' Test GPIO

IMPORT gpio.bas
IMPORT sbt.bas

GPIO::Cleanup
status = GPIO::Setup()
GPIO::SetupGPIO(4,0,0)
GPIO::OutputGPIO(4,1)
SB_msSleep(50)
GPIO::OutputGPIO(4,0)
SB_msSleep(20)
GPIO::SetupGPIO(4,1,2)
FOR x = 1 to 100
  PRINT GPIO::InputGPIO(4),"\n"
NEXT
One step I might be missing from the Python version is GPIO.setmode(GPIO.BCM). I don't have a setmode function in the extension module and wonder if this function is Python specific?

User avatar
John_Spikowski
Posts: 1322
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Fri May 31, 2019 1:53 am

hippy wrote:
Fri May 31, 2019 1:22 am
ScriptBasic wrote:
Thu May 30, 2019 8:38 pm
I have been trying to get the ScriptBasic GPIO extension module working with the DHT11 and this is where I'm at.
In your FOR-NEXT loop read of the input; how quickly is it sampling the data ?

I wouldn't know how to determine that other than by replacing the input read with an output high then an output low and looking at the pin with a logic analyser or scope.
ScriptBasic's FOR/NEXT is its fastest loop like function. Much faster than WHILE/WEND. It displays the data a lot faster than Python which works.

I think I'm close as I'm returning a value that changes if the pin number changes. If you own a RPi Astro SenseHAT board, I believe the temperature and humidity sensor is a DHT11. I not sure its usable with the rpi.gpio library. It works great with the SHAT extension module I did that is i2c based.

User avatar
bensimmo
Posts: 4150
Joined: Sun Dec 28, 2014 3:02 pm
Location: East Yorkshire

Re: ScriptBasic

Fri May 31, 2019 8:24 am

GPIO.setmode(GPIO.BCM)
Is just saying which pin naming scheme to use, if I remember correctly


SenseHAT, it uses a LPS25H (pressure/temp) and HTS221 (humid/temp) over i2c.
There is no DHT11.

User avatar
bensimmo
Posts: 4150
Joined: Sun Dec 28, 2014 3:02 pm
Location: East Yorkshire

Re: ScriptBasic

Fri May 31, 2019 8:31 am

For the senseHAT in wonder if waveforms alternate python software (to the official RPi AstroPi one) makes it easier to convert, it has a lot of explanation.
https://github.com/waveform80/pisense
Or this C setup
viewtopic.php?t=197543


And more on the devices on the SenseHAT and where you'll find them
https://pinout.xyz/pinout/sense_hat

hippy
Posts: 5753
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: ScriptBasic

Fri May 31, 2019 12:00 pm

ScriptBasic wrote:
Fri May 31, 2019 1:47 am
I moved the cleanup function to the start of the process. It looks like this function just clears a buffer.
It 'unmaps' the GPIO memory. Presumably that checks if the GPIO memory pointer is NULL and ignores it or it would have caused an exception when used. You shouldn't really be doing the clean up first, before having set the GPIO pointer, and you don't want to unmap it until finished with it.
ScriptBasic wrote:
Fri May 31, 2019 1:53 am
ScriptBasic's FOR/NEXT is its fastest loop like function. Much faster than WHILE/WEND. It displays the data a lot faster than Python which works.
And that's great but it is how fast it executes which matters, though actually it's perhaps how deterministic it is which actually matters.

If one looks at the DHT11 datasheet the data which comes back from the DHT11 arrives as a pulse as follows -

Code: Select all

    ___                    __________
       |__________________|          |_____
"0"   
       |<----- 50us ----->|<- 26us ->|

    ___                    __________________
       |__________________|                  |_____
"1"   
       |<----- 50us ----->|<----- 70us ----->|
The easiest way to read each bit is to wait for the pulse's rising edge, delay 50us and read the line; it will have gone to zero for a "0", will still be high for a "1".

So your code should look something like this, untested, E&OE -

Code: Select all

result = 0
; Prepare to take a reading
SetOutputHigh(dataPin)
PauseMicroseconds(50) ; ? Datasheet doesn't say how long
; Initiate read
SetOutputLow(dataPin)
PauseMilliseconds(20)
SetInputWithPullHigh(dataPin)
; Wait for the response signal
Do : Loop While Input(dataPin) == 1
Do : Loop While Input(dataPin) == 0
; Skip the responding pulse
Do : Loop While Input(dataPin) == 1
; Read data bits
For bitNumber = 0 To 39
  ; Wait for rising edge
  Do : Loop While Input(dataPin) == 0
  ; Start 50us delay
  PauseMicroseconds(50)
  ; Sample bit
  result = ( result << 1 ) | Input(dataPin)
Next
; Terminate the receive
Do : Loop While Input(dataPin) == 1
PauseMicroseconds(50)
SetHigh(dataPin)
; Return the result
return result
So the challenge is to be able to sample the data line faster than every 50us and to have detected the rising edge and sampled the data bit within 76us of that edge and be back to looking for the next rising edge within 126us from the last.

Can ScriptBasic achieve that ? I have no idea. It is possible to un-roll that FOR-NEXT loop to speed things up, take 40 explicit samples, combine those at the end.

At least the data returned includes a checksum, so you can check if the result is correct or not.

In fact, rather than read 40 bits, I would read five sets of 8-bits, as that makes it easier to determine if the checksum matches and it's trivial to create 16-bit humidity and temperature values.

I would still suggest getting your program to work with some simpler to use sensor first, not starting with a device which has onerous timing requirements. Unless you can be sure your library code works you don't know if it's failing because your reading algorithm is flawed, the library code is wrong, ScriptBasic isn't fast enough, or there's an issue with the device.

Have you done the basic tests of setting a pin's Alt-function and checking it is as set ? The same with output levels, and reading input levels ? Checked that a complete dump of pin states matches what "gpio readall" and "gpio allreadall" produces ?

User avatar
John_Spikowski
Posts: 1322
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Fri May 31, 2019 12:33 pm

I'm trying to emulate the Python script and both are using the same C code interface.

Thanks for the clarification about cleanup.

User avatar
John_Spikowski
Posts: 1322
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Fri May 31, 2019 12:47 pm

bensimmo wrote:
Fri May 31, 2019 8:24 am
GPIO.setmode(GPIO.BCM)
Is just saying which pin naming scheme to use, if I remember correctly


SenseHAT, it uses a LPS25H (pressure/temp) and HTS221 (humid/temp) over i2c.
There is no DHT11.
What rpi.gpio C function is used to do the setmode?

User avatar
John_Spikowski
Posts: 1322
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Fri May 31, 2019 12:55 pm

I would still suggest getting your program to work with some simpler to use sensor first, not starting with a device which has onerous timing requirements.
In 2005 I decided it was time to learn C so I picked up the ScriptBasic project and that is how learned C. I find doing the so called impossible more rewarding than just getting by.

Heater
Posts: 13058
Joined: Tue Jul 17, 2012 3:02 pm

Re: ScriptBasic

Fri May 31, 2019 1:43 pm

Interesting. I found it easier to get to C by starting at B then moving to A then skipping ahead to C.

BASIC -> Algol -> C/Coral

Only joking... honest. I'm all for tackling the impossible.

That DHT11 sounds like a bit of a challenge in any language running on an indeterministic operating system like Linux. Unless you are writing a Linux device driver for it that can use interrupts and such.

jahboater
Posts: 4596
Joined: Wed Feb 04, 2015 6:38 pm

Re: ScriptBasic

Fri May 31, 2019 1:53 pm

Heater wrote:
Fri May 31, 2019 1:43 pm
Interesting. I found it easier to get to C by starting at B then moving to A then skipping ahead to C.

BASIC -> Algol -> C/Coral
I started at B then moving to C
B -> C

Obviously with Pascal, Fortran, Algol68 etc etc etc by the way ...

User avatar
John_Spikowski
Posts: 1322
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Fri May 31, 2019 1:54 pm

Facts:

* It works in Python

* I'm using the same C interfaces as Python

*;ScriptBasic is faster than Python at this level


The problem with most of these GPIO functions is there is no returned status if the function worked or not.
Last edited by John_Spikowski on Fri May 31, 2019 1:57 pm, edited 1 time in total.

hippy
Posts: 5753
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: ScriptBasic

Fri May 31, 2019 1:56 pm

ScriptBasic wrote:
Fri May 31, 2019 12:47 pm
What rpi.gpio C function is used to do the setmode?
It's in the Python interfacing layer; lines 513-547 -

https://sourceforge.net/p/raspberry-gpi ... /py_gpio.c

That sets the 'gpio_mode' variable, and I would expect its value is used elsewhere to map the calling parameter to a Broadcom GPIO pin number.

If you aren't supporting anything other than Broadcom GPIO numbers you don't have to worry about it. If you are you will have to translate the parameter value into GPIO numbers somewhere. Either within the extension interfacing or in all the pin using routines themselves.

It is usually best done in the interfacing routines as they can return errors and the lowest-level routines can then be written with the knowledge that everything they get passed to them will be valid -

Code: Select all

ExtensionFunction("SetHigh")
{
  int pin = GetParameter("i");
  if (mapping == MAP_WIRING_PI) {
    pin = MapWiringPiPin(pin);
    if (pin < 0) { return ERROR("Invalid pin used"); }
  }
  if ((pin < 0) || (pin > 53)) { return ERROR("Invalid pin used"); }
  SetHigh(pin);
  return NONE;
}
Mapping a pin and checking its validity can be single function which saves having to do all that in each routine.

Not that mapping a pin will require needing to know which variant of a Pi you have to perform the correct mapping and to determine what exists and doesn't.

User avatar
John_Spikowski
Posts: 1322
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Fri May 31, 2019 2:08 pm

Which of the 16 Kookey sensors do you recommend I start off with to get the GPIO extension module working?

hippy
Posts: 5753
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: ScriptBasic

Fri May 31, 2019 2:12 pm

Heater wrote:
Fri May 31, 2019 1:43 pm
That DHT11 sounds like a bit of a challenge in any language running on an indeterministic operating system like Linux. Unless you are writing a Linux device driver for it that can use interrupts and such.
Yup; it's a nightmare. Unless one can guarantee that one won't be interrupted for more than 50us ( and it's perhaps less ), any interruption can corrupt the data read from a DHT11.

One can lock interrupts out, lock execution to the executing core, but one has to do so for up to 5ms. And it's not always certain one can avoid all stalls, only hope they aren't long enough to have an adverse impact.

Multi-tasking systems really aren't suited to using synchronous I/O. That's why most have dedicated peripheral interfacing and some chips add extra cores to allow for deterministic operation. The RPT will have considered adding deterministic cores for the Pi 4 or later, because I'm told there's no possible suggestion they haven't heard. We'll just have to wait and see if they do provide those.

Code running in the VideoCore should be more deterministic. But as said, my project for attempting that has been on hold.

hippy
Posts: 5753
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: ScriptBasic

Fri May 31, 2019 2:20 pm

ScriptBasic wrote:
Fri May 31, 2019 2:08 pm
Which of the 16 Kookey sensors do you recommend I start off with to get the GPIO extension module working?
"Kookye" I'm guessing -
http://kookye.com/2016/08/01/smart-home ... spberry-pi

Haven't got time to go through them all at present but I would start with digital output LED, then Piezo, digital input button, then things which use SPI or I2C, the simpler the sensor the better.

User avatar
John_Spikowski
Posts: 1322
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Fri May 31, 2019 2:24 pm

It would be great to have any of the C examples work. At this point only the Python examples work.

This GPIO interface is causing me to dig up my hardware past. I haven't touch a logic analyzer / scope in over 25 years.

@hippy,

It would be helpful if you could compare my SB code with the Python code I'm trying to emulate and tell me if I missed a step. The C code is the rpi.gpio library you pointed me to.
Last edited by John_Spikowski on Fri May 31, 2019 2:49 pm, edited 1 time in total.

User avatar
RichardRussell
Posts: 578
Joined: Thu Jun 21, 2012 10:48 am

Re: ScriptBasic

Fri May 31, 2019 2:46 pm

hippy wrote:
Fri May 31, 2019 2:12 pm
Yup; it's a nightmare. Unless one can guarantee that one won't be interrupted for more than 50us ( and it's perhaps less ), any interruption can corrupt the data read from a DHT11.
I think "nightmare" is a bit melodramatic. Yes data can be corrupted, but there's a good chance that this will be caught either by the number of detected transitions being wrong or the checksum not agreeing, in which case the code should retry the operation after a second or so (I believe the DHT11 doesn't like being polled more frequently). In many scenarios this will be an acceptable strategy.

User avatar
John_Spikowski
Posts: 1322
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Fri May 31, 2019 2:54 pm

I agree Richard. Python isn't that much different than SB trying to emulate its functionality. I just need to start seeing 1/0's rather than a stream of sixteens.

Heater
Posts: 13058
Joined: Tue Jul 17, 2012 3:02 pm

Re: ScriptBasic

Fri May 31, 2019 3:08 pm

hippy,
Multi-tasking systems really aren't suited to using synchronous I/O.
They can be. I'm used to using Real-time Operating Systems (RTOS) where one can assign priorities to tasks/processes and for really fast things set up interrupts to handle them, with priorities.

Linux/Unix is not really designed for such things. Now we have the Real-time/Preempt patches integrated into upstream Linux I believe. I have never really looked into how well that works out.

My best efforts were isolating a core from Linux scheduling with the "isolcpus" boot command parameter. Then I could toggle a GPIO output pin almost continuously/reliably at 50MHz. There was still some interrupt happening that caused a 5us jitter every few milliseconds.

Personally I think having to use the Video Core to do this simple GPIO thing sounds kind of nuts.

ScriptBasic,
This GPIO interface is causing me to dig up my hardware past. I haven't touch a logic analyzer / scope in over 25 years.
That's the spirit. We are in the real word now. We need all the tools we can get to see what the hardware is actually doing.

You will be pleased to hear that a cheap Rigol Scope (DS1054Z) is more than enough to deal with this.

RichardRussell,
...data can be corrupted, but there's a good chance that this will be caught either by the number of detected transitions being wrong or the checksum not agreeing, in which case the code should retry the operation after a second or so (I believe the DHT11 doesn't like being polled more frequently).
Yep, sounds like a nightmare. :)

User avatar
John_Spikowski
Posts: 1322
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Fri May 31, 2019 3:26 pm

The way I see it is we have a working model in Python. SB shouldn't have a problem emulating it. A working example in C should be obtainable.

User avatar
RichardRussell
Posts: 578
Joined: Thu Jun 21, 2012 10:48 am

Re: ScriptBasic

Fri May 31, 2019 3:36 pm

Heater wrote:
Fri May 31, 2019 3:08 pm
Yep, sounds like a nightmare. :)
In the 'real world' of digital communication (over the airwaves, or copper wire or fibre etc.) errors and corrupted data are a fact of life. One rarely experiences the luxury of guaranteed perfect data, every time, outside of the realm of a self-contained computer, and even then there may be error detection and correction going on under the hood. So I see nothing scary about having to deal with data corruption.

User avatar
RichardRussell
Posts: 578
Joined: Thu Jun 21, 2012 10:48 am

Re: ScriptBasic

Fri May 31, 2019 3:44 pm

ScriptBasic wrote:
Fri May 31, 2019 2:54 pm
Python isn't that much different than SB trying to emulate its functionality. I just need to start seeing 1/0's rather than a stream of sixteens.
My advice, for what it's worth, is to ignore the existing Python (and C etc.) code and start from scratch coding the required functionality in ScriptBASIC. That's what I intend to do in BBC BASIC, when my DHT11 arrives, so if it doesn't behave how I expect at least I'll know exactly what the code is doing and why.

User avatar
John_Spikowski
Posts: 1322
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Fri May 31, 2019 3:59 pm

I wish I had the knowledge needed to do a start from scratch effort. All I want to do is get a stable GPIO extension module built and able to communicate with common used sensors.

DHT11 Resource

Return to “Other programming languages”