fastspin Basic CM2302

What I am trying to do is create some fastspin Basic code to read a CM2302 temp/humid module.

In my fastspin basic code below, I am trying to get the correct hi/low sequence for the module to send something. I am not having very much success. I am not sure if I am interpreting the Basic output() = 1/0 command correctly. Or is there a better way to do this.

I also have the dht11/22 spin code below as reference material, that code is like Greek to me, but I am trying. Any assistance for solving this would be appreciated.

Thanks
Ray


My basic code
rem test_temp2.bas
'
'

dim indata%

waitcnt(getcnt() + 10_000_000) 'Wait for terminal screen

pausems 2000 'Wait for sensor to stabilize

direction(2) = output 
output(2) = 1  'Pull high
pausems 1000

output(2) = 0  'Pull low
pausems 0000_0500  'uS
output(2) = 1  'Pull high
direction(2) = input  'Chnge to input
pausems 1000
output(2) = indata%  'Capture incoming

print "Exp Data! "; indata%  'Print out the data captured


spin code
''******************************************
''*  Title: DHTnn_Object                   *
''*  Modified from DHT21_Object -          *
''*  Walter T. Mosscrop 2016               *
''*  Original Author: Gregg Erickson  2012 *
''*  See MIT License for Related Copyright *
''*  See end of file and objects for .     *
''*  related copyrights and terms of use   *
''*  This object draws upon code from other*
''*  OBEX objects such as servoinput.spin  *
''*  and DHT C++  from Adafruit Industries *
''*                                        *
''*  This object reads the temperature and *
''*  humidity from an DHT11 or DHT22       *
''*  using a unique 1-wire serial protocol *
''*  with 5 byte packets where 0s are 26uS *
''*  long and 1s are 70uS.                 *
''*                                        *
''*  The object automatically returns the  *
''*  temperature and humidiy to variables  *
''*  memory every few seconds as Deg C and *
''*  relative percent respectively. It also*
''*  return an error byte where true means *
''*  the data received had correct parity  *
''*                                        *
''*  The read loop has been reworked to    *
''*  stabilize the timing and reduce the   *
''*  number of invalid reads due to timing *
''*  issues                                *
''******************************************
{
   Vcc──────────────Red (Power)
                │
               10K (Pull-Up Resistor)
                │
   Prop Pin ────────Yellow (Data)


   VSS──────────────Black (Ground)

}
CON

  MAX_SAMPLES = 40 ' 40 one-bit samples 

VAR

long APin,Device                  
long MeasurementStack[50]
long clkpermicro, clkminpulse
long measurementCog, measuring
long MeasurementValues[MAX_SAMPLES]
long temperaturePtr, humidityPtr, statusPtr

OBJ
  f       : "FloatMath"

PUB StartDHTnn(devicePin,DeviceModel,TempPtr,HumPtr,StatPtr) : result

  APin := devicePin
  Device := DeviceModel

  measurementCog := -1
  
{{
    This method lauches the Measuring code in a new cog
    to read the DHTnn autonomously with variables updated
    every few seconds
}}

  MeasurementInit(APin, @measuring, @MeasurementValues)

  temperaturePtr := TempPtr
  humidityPtr := HumPtr
  statusPtr := StatPtr

PUB Stop
{{
   stop cog if in use
}}

    if measurementCog => 0
      cogstop(measurementCog)

Pub DHTnn_Read | Data[5], Temp, Humid, ByteCount,BitCount,Pulsewidth,Parity,ptr,tr,hr
{{
    This method reads the DHTnn device autonomously with variables located at
    the pointers updated every few seconds
}}
                      'Apin is data line in from DHTnn
                      'Data[5] bytes received in order from DHTnn
                      'DATA = upper 8 bits of RH data
                      '     + lower 8 bits of RH data
                      '     + upper 8 bits of temperature data
                      '     + lower 8 bits of temperature data
                      '     + 8 bits check-sum (equals other 4 bytes added)

                      'ByteCount   - Index counter for data Bytes
                      'BitCount    - Index counter for bits within data bytes
                      'Pulsewidth  - Width of bits received from DHTnn, 26uS = 0, 70S=1, in clock ticks
                      'parity      - Boolean - parity for data from DHTnn
                      'clkpermicro - number of clock ticks per microsecond
                      'clkminpulse - the number of clock ticks for a pulsewidth value to be considered a 1

  clkpermicro := clkfreq / 1_000_000
  clkminpulse := clkpermicro * 48 ' Minimum 48 us 'high' pulse

  waitcnt(clkfreq*2+cnt)                ' Pause to allow DHTnn to stabilize

  DIRA[Apin]~~                          ' Set selected Pin to output
  OUTA[Apin]~~                          ' Pull Up selected Pin to start sequence

  Repeat ByteCount from 0 to 4
    Data[ByteCount]:=0                  ' Clear Data of Each Byte Before Input
  
  waitcnt(clkfreq/4+cnt)                ' Pause to allow DHTnn to stabilize

  ' Send a low to the DHTnn to request data

  DIRA[Apin]~~                          ' Set selected Pin to output
  OUTA[Apin]~                           ' Pull Down selected Pin for 500 uS to Request Data

  if device == 11
    waitcnt((clkpermicro * 20_000) + cnt) ' hold 20ms
  else
    waitcnt(clkfreq / 2000 + cnt)       ' Pause for 500uS

  OUTA[Apin]~~                          ' Return Pin to High
  DIRA[Apin]~                           ' Set Pin to Input and Release Control to DHTnn
  
  ' DHTnn reponds with a ready signal (80uS low, 80uS high, 40 uS low, before data)

  waitpne(|<Apin,|<Apin,0)              ' Wait for low, high, low sequence
  
  waitpeq(|<Apin,|<Apin,0)
  
  waitpne(|<Apin,|<Apin,0)

  MeasurementStart
  
  ' DHTnn will send 40 high bits where 0 is 26uS and 1 is 70uS

  repeat until measuring == 0
 
  ptr := 0
  
  Repeat ByteCount from 0 to 4          ' Store Data in 5 Bytes
    Repeat BitCount from 7 to 0         ' Receive Data by Bit, MSB to LSB
      pulsewidth := LONG[@MeasurementValues][ptr++]
      if pulsewidth > clkminpulse       ' If Pulse > min pulse then bit is 1 else 0 
        Data[ByteCount]|=|<BitCount     ' Store the bit in byte
  
  ' Check Parity
  parity := ((data[0]+data[1]+data[2]+data[3])& $ff)==(data[4]) 'Last byte equals sum of first four bytes
  
  ' Calculate Temperature

  if parity
    if (Device == 11)
      tr := data[2] & $7f               ' Pull from data2, mask MSB Bit
    else
      tr := data[2]                     ' Pull from data2
    
    tr <<= 8                            ' Put into upper byte
    tr += data[3]                       ' Add lower byte

    Temp := f.FFloat(tr)

    if (Device == 11)
      Temp := f.FDiv(Temp, 256.0)       ' Convert to DHT11 value
    else
      Temp := f.FMul(Temp, 0.1)         ' Convert to DHT22 value    
  
  ' Calculate Humidity

  if parity
    Humid:=data[0]                      ' Pull from data0
    Humid<<=8                           ' Put into upper byte
    Humid+=data[1]                      ' Add lower byte

    Humid := f.FFloat(Humid)

    if (Device == 11)
      Humid := f.FDiv(Humid, 256.0)     ' Convert to DHT11 value
    else
      Humid := f.FMul(Humid, 0.1)       ' Convert to DHT22 value    

  ' Return values to addresses provided in pointers
  
  if parity
    Long[temperaturePtr] := temp        ' Temperature
    Long[humidityPtr] := humid          ' Humidity
    Long[statusPtr] := 1                ' Parity ok
  else
    Long[statusPtr]:= 0                 ' Error

' Cog relies on these arguments, do not remove
pub MeasurementInit(pAPin, pMeasuringStatus, pMeasurementValues) 
 
  measurementCog := cognew(@MeasureCog, @pAPin)

pub MeasurementStart
  Long[statusPtr] := -1                  ' We're updating values    

  LONGFILL(@MeasurementValues, MAX_SAMPLES, 0)

  measuring := 1

DAT
        ORG 0

MeasureCog        
        mov             p1, par                         ' Get data pointer
        rdlong          APinNum, p1                     ' Get APin number

        add             p1, #4                          ' Get next pointer
        
        rdlong          measuringStatusPtr, p1          ' Get pointer to measuring value

        add             p1, #4                          ' Get next pointer
        rdlong          arrayPtrSave, p1                ' Get monitor array pointer

        mov             APinMask, #1                    ' Get pin mask
        shl             APinMask, APinNum 

        ' Used for timing pulses

        movi            ctra, #%11111                   ' Setup counter (always)
        mov             frqa, #1                        ' One count per tick

        ' Used for timeout in case of device failure
        
        movi            ctrb, #%11111                   ' Setup counter (always)
        mov             frqb, #1                        ' One count per tick

wait
        rdlong          t1, measuringStatusPtr wz       ' Check "measuring" value
   if_z jmp             #wait                           ' Wait until "measuring" value nonzero

        ' Prepare for measurement
   
        mov             arrayPtr, arrayPtrSave          ' Set up array pointer

        mov             t2, #0                          ' Reset counter
        mov             phsb, #0                        ' Reset timeout
        
measure

' Handle low-to-high (pulse gap)

        mov             t1, #0 wc                       ' Reset carry for waitpeq

        waitpeq         APinMask, APinMask              ' Wait for high state

        mov             t1, phsb                        ' Have we timed out?
        cmp             t1, timeoutTicks wz, wc         
  if_a  jmp             #done                           ' Yes, set done & start over

        mov             phsa, #0                        ' Reset counter

' Time high-to-low (pulse)

        waitpne         APinMask, APinMask              ' Wait for low state
        mov             t1, phsa                        ' Save counter value in t1, can't write directly to hub
        wrlong          t1, arrayPtr                    ' Save duration value
        add             arrayPtr, #4                    ' Set up for next array value

        mov             t1, phsb                        ' Have we timed out?
        cmp             t1, timeoutTicks wz, wc         
  if_a  jmp             #done                           ' Yes, set done & start over

        add             t2, #1                          ' Count values
        cmp             maxSample, t2 wz                ' Have we reached the limit?
  if_ne jmp             #measure                        ' No, back for more

done    mov             t1, #0                          ' Yes, set status value to zero
        wrlong          t1, measuringStatusPtr          ' Update status value

        jmp             #wait                           ' We're done monitoring
        
APinNum            long              0
maxSample          long              MAX_SAMPLES
measuringStatusPtr long              0
arrayPtr           long              0 
arrayPtrSave       long              0

timeoutTicks       long              5 * 80_000_000 ' Assumes 80 MHz clock; 5 seconds

APinMask      long              0

p1            long              0

t1            long              0
t2            long              0

{{

┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                                   TERMS OF USE: MIT License                                                  │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation    │
│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,    │
│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│
│is furnished to do so, subject to the following conditions:                                                                   │
│                                                                                                                              │
│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│
│                                                                                                                              │
│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE          │
│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR         │
│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,   │
│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                         │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
}}

Comments

  • This line:
    output(2) = indata%  'Capture incoming
    
    does not do what the comment says (capture incoming); instead it outputs a random value (whatever happened to be in the variable "indata%") to pin 2. Did you mean to say:
    indata% = input(2) ' Capture state of pin 2
    

    In general, if the Spin code you have works correctly then you can just use that directly in the BASIC code by doing something like:
    ' create a BASIC Object (class) from the Spin object
    dim dht as class using "DHTnn_Object.spin"
    ' declare some variables to receive output
    dim temperature as single
    dim humidity as single
    dim status as integer
    ...
    ' start the reading process in the background
    dht.StartDHTnn(devicePin, deviceModel, @temperature, @humidity, @status)
    
    ' loop printing temperature and humidity
    do
      pausems 1000
      if status = 1
        print "temperature=", temerature, "humidity=", humidity
      else
        print "error? status=", status
      end if
    loop
    
    (I haven't checked that code and don't have a device to actually test with, so it probably needs some tweaking, but that's the general idea.)
  • Actually what I was trying to do is, or make an attempt to write the dht22 code in fastspin Basic. So, basically I would have a driver for the CM2302 module that was in Basic instead of using the dht22 spin object.

    I was curious to see whether the actual Basic code would make the actual program size smaller than what I am getting when using the spin object code. The same experiment could be used to see what the code sizes look like with the dht22 C code, whenever that becomes available.

    Since fastspin Basic is using LMM mode, it seems that all the program code has to be as small and compact as possible. I think that it would be easier to tweak Basic code then to tweak the spin objects, before using them in the fastspin Basic. Just my thoughts on this.

    Ray
  • Rsadeika wrote: »
    Actually what I was trying to do is, or make an attempt to write the dht22 code in fastspin Basic. So, basically I would have a driver for the CM2302 module that was in Basic instead of using the dht22 spin object.

    I was curious to see whether the actual Basic code would make the actual program size smaller than what I am getting when using the spin object code.
    Well, in general I would expect the code produced by fastspin to be similar size regardless of the language. Internally fastspin translates all 3 languages into the same internal form before compiling to PASM. So if you write the code in the same way in Spin, BASIC, or C it should be compiled into the same result.

    The "in the same way" is an interesting caveat though, because it may be that different languages make slightly different forms of code more "natural". In Spin, for example, it's pretty easy to interface to a PASM driver that runs in another COG, but that's harder in BASIC or C. In BASIC it's easier to use small inline functions than in the other languages. And C code tends not to use objects in the same way as Spin or BASIC.

  • Interesting, so the only way to see program code, in a reduced size, would be by changing over to CMM, I think. Also, I was thinking, using the dhtnn spin object, as an example, if that were written in complete pasm, would that show a reduction in program size when used with Basic?

    I think there needs to be an explanation for why/when you would use the optimization option. I noticed that the dhtnn program, when you use 'no optimization', it runs as expected and the values are correct. But when you use 'Default Optimization', the program runs, but the values that you are printing are wrong, although there is quite a substantial reduction in program code size. I guess it would be some what difficult to find out where the problem lies when you do use the optimization option. Maybe a short summary on how the optimization thing works.

    Ray
  • Using the latest version of fastspin Basic, I cleaned up the CM2302 code, and it seems to be working as expected. I am not including the Spin objects, for that, if you are interested, OBEX is the place to find them.

    Still need to get a handle on how that Optimization works. With that info I guess you can start writing programs with that protocol in mind, I think. Also, what is the best way to have this program copied to EEPROM, so it starts up on power up?

    The next step, I think, will have to be a pair up with a Raspberry Pi, that way I can access a program on the RasPi to get the temperature/humidity readings remotely.

    Ray

    rem test_temp3.bas
    '
    '  April 21, 2019
    rem This uses the CM2302 module for temperature and humidity.
    /'
    For this to work, you need access to the following:
    DHTnn_Object.spin
    FloatMath.spin
    FloatString.spin
    Also, in Options, the selection has to be "No Optimization".
    Program size is 12704 bytes, ~one third of available memory is used.
    '/
    
    ' Setup a Spin object for use with Basic
    dim dht as class using "DHTnn_Object.spin"
    
    let dhtpin = 2  ' Pin number.
    let model = 22  ' Model is dht22.
    
    ' Variable types.
    dim temp as single
    dim humid as single
    dim status as integer
    
    /' Start the dht object code.
     Module is set for pin 2, and model 22.'/
    dht.StartDHTnn(dhtpin,model,@temp,@humid,@status)
    ' Hold for terminal screen access.
    waitcnt(getcnt() + 10_000_000)
    
    do
      dht.DHTnn_Read()  ' Read the dht module.
      if status = 1 then
        print "Temperature - ";(9.0/5.0)*temp + 32.0;" *F" ;"  Humidity - ";humid;" %"
      else
        print "error status= "; status
      end if
      pausems 3000  ' Need at least two seconds for module stabalization.
    loop
    
  • ersmithersmith Posts: 3,385
    edited 2019-04-21 - 15:45:50
    Rsadeika wrote: »
    IAlso, I was thinking, using the dhtnn spin object, as an example, if that were written in complete pasm, would that show a reduction in program size when used with Basic?
    Possibly, depending on how clever your PASM code was.
    I think there needs to be an explanation for why/when you would use the optimization option. I noticed that the dhtnn program, when you use 'no optimization', it runs as expected and the values are correct. But when you use 'Default Optimization', the program runs, but the values that you are printing are wrong, although there is quite a substantial reduction in program code size.
    Well, that's a bug then. Could you describe exactly how it's going wrong? (what kinds of values are being printed, etc.) As I said, I don't have any DHT hardware to test with, but if you could narrow down the problem to which function is producing the wrong result I may be able to figure out what's wrong.

    There are a lot of optimizations that fastspin performs. The ones that most reduce the program size are unused method removal (getting rid of methods that are never called) and dead code removal (getting rid of parts of if statements that are always false). I think all of the optimizations in the "default optimization" level are performed within functions. At "full optimization" (-O2) it also does a few things like automatically inlining functions that are only called once.
  • When you run the program :
    No Optimization
    Temperature : 73.04 *F Humidity : 45.100 %
    Default Optimization
    Temperature : 107.42 *F Humidity : 1.109E+08
    Full Optimization
    error status = 0

    The values are so far apart, not sure what the heck is going on. But, when you compile with Full Optimization, the program code size is 7932 bytes. That is quite a reduction in program code size.

    Ray

  • Rsadeika wrote: »
    Also, what is the best way to have this program copied to EEPROM, so it starts up on power up?
    PropLoader (loader for P1) gets built as part of the spin2gui project.
    $ proploader
    PropLoader v1.0-41 (2019-04-11 14:50:14 g9192230)
    
    usage: proploader [options] [<file>]
    
    options:
        -b <type>       select target board and subtype (default is 'default:default')
        -c              display numeric message codes
        -D var=value    define a board configuration variable
        -e              program eeprom (and halt, unless combined with -r)
    ... many more options available...
    
    The "-e" option allows uploading to the P1 EEPROM.

    dgately
    Livermore, CA (50 miles SE of San Francisco)
  • For debugging something like this I would add output statements to print the temperature and humidity at every step of the calculations from reading the raw data to outputting the final result.
    In science there is no authority. There is only experiment.
    Life is unpredictable. Eat dessert first.
  • I was very curious how the Basic program would compare to the program I have that uses SimpleIDE. The program below comes out too: 9092bytes(9480 total).

    Another thing that I am noticing is the actual code itself. Of course it is a very simple program, but the fastspin Basic is just as readable as the C code, and vice-versa, in this instance. I know that C code can get very difficult to decipher at times.

    I also looked at DHT11_Test.spin, which is similar in function, I sort looked at that code and was scratching my head thinking, what the heck. I am not saying this to start a language war, just my observation.

    I am starting to like fastspin Basic, although I must confess, I have written some programs using FreeBasic, so it is starting to become very familiar.

    Ray
    /*
      cm2302_test.c
      September 13, 2018
    */
    #include "simpletools.h"
    #include "dht22.h"
    
    float temp,humid;  // Decimal point precision.
    
    int main()
    {
      // Add startup code here.
      
     
      while(1)
      {
        // Add main loop code here.
        dht22_read(2);   // CM2302 is connected to pin 16.
        pause(150);
        temp = dht22_getTemp(0);  // (0) Celsius, (1) Fahrenheit, (2) Kelvin.
        temp = ((temp*.100)-.30); 
        print("%.2f Temperature\n",temp);  // Apply decimal point precission.
        humid = dht22_getHumidity();
        humid = (humid*.10);
        print("%.2f Humidity\n",humid);  // Apply decimal point precission.
        pause(2000);  // Pause for two seconds.
      }  
    }
    
  • To get a better feel for how to use Spin objects with fastspin Basic, I tried to use the FFloat() that is available with FloatMath.spin. The results that I am seeing are not what I expected.

    I thought I would see something like 1.111 2.111 … But what I am seeing is 3F800000 40400000 … So, I must be using math.FFloat() incorrectly, right? I also wanted to see how the optimization would work on a program that had a Spin object attached.

    Ray
    rem test4.bas
    
    dim math as class using "FloatMath.spin"
    
    
    dim i as integer
    
    waitcnt(getcnt() + 10_000_000)
    
    for i =  1.111 to 10
      print math.FFloat(i)
      pausems 1000
    next i
    
    FloatMath.spin
    ''***************************************
    ''*  Floating-Point Math                *
    ''*  Single-precision IEEE-754          *
    ''*  Author: Chip Gracey                *
    ''*  Copyright (c) 2006 Parallax, Inc.  *
    ''*  See end of file for terms of use.  *
    ''***************************************
    
    
    PUB FFloat(integer) : single | s, x, m
    
    ''Convert integer to float    
    
      if m := ||integer             'absolutize mantissa, if 0, result 0
        s := integer >> 31          'get sign
        x := >|m - 1                'get exponent
        m <<= 31 - x                'msb-justify mantissa
        m >>= 2                     'bit29-justify mantissa
    
        return Pack(@s)             'pack result
       
    
    PUB FRound(single) : integer
    
    ''Convert float to rounded integer
    
      return FInteger(single, 1)    'use 1/2 to round
    
    
    PUB FTrunc(single) : integer
    
    ''Convert float to truncated integer
    
      return FInteger(single, 0)    'use 0 to round
    
    
    PUB FNeg(singleA) : single
    
    ''Negate singleA
    
      return singleA ^ $8000_0000   'toggle sign bit
      
    
    PUB FAbs(singleA) : single
    
    ''Absolute singleA
    
      return singleA & $7FFF_FFFF   'clear sign bit
      
    
    PUB FSqr(singleA) : single | s, x, m, root
    
    ''Compute square root of singleA
    
      if singleA > 0                'if a =< 0, result 0
    
        Unpack(@s, singleA)         'unpack input
    
        m >>= !x & 1                'if exponent even, shift mantissa down
        x ~>= 1                     'get root exponent
    
        root := $4000_0000          'compute square root of mantissa
        repeat 31
          result |= root
          if result ** result > m
            result ^= root
          root >>= 1
        m := result >> 1
      
        return Pack(@s)             'pack result
    
    
    PUB FAdd(singleA, singleB) : single | sa, xa, ma, sb, xb, mb
    
    ''Add singleA and singleB
    
      Unpack(@sa, singleA)          'unpack inputs
      Unpack(@sb, singleB)
    
      if sa                         'handle mantissa negation
        -ma
      if sb
        -mb
    
      result := ||(xa - xb) <# 31   'get exponent difference
      if xa > xb                    'shift lower-exponent mantissa down
        mb ~>= result
      else
        ma ~>= result
        xa := xb
    
      ma += mb                      'add mantissas
      sa := ma < 0                  'get sign
      ||ma                          'absolutize result
    
      return Pack(@sa)              'pack result
    
    
    PUB FSub(singleA, singleB) : single
    
    ''Subtract singleB from singleA
    
      return FAdd(singleA, FNeg(singleB))
    
                 
    PUB FMul(singleA, singleB) : single | sa, xa, ma, sb, xb, mb
    
    ''Multiply singleA by singleB
    
      Unpack(@sa, singleA)          'unpack inputs
      Unpack(@sb, singleB)
    
      sa ^= sb                      'xor signs
      xa += xb                      'add exponents
      ma := (ma ** mb) << 3         'multiply mantissas and justify
    
      return Pack(@sa)              'pack result
    
    
    PUB FDiv(singleA, singleB) : single | sa, xa, ma, sb, xb, mb
    
    ''Divide singleA by singleB
    
      Unpack(@sa, singleA)          'unpack inputs
      Unpack(@sb, singleB)
    
      sa ^= sb                      'xor signs
      xa -= xb                      'subtract exponents
    
      repeat 30                     'divide mantissas
        result <<= 1
        if ma => mb
          ma -= mb
          result++        
        ma <<= 1
      ma := result
    
      return Pack(@sa)              'pack result
    
    
    PRI FInteger(a, r) : integer | s, x, m
    
    'Convert float to rounded/truncated integer
    
      Unpack(@s, a)                 'unpack input
    
      if x => -1 and x =< 30        'if exponent not -1..30, result 0
        m <<= 2                     'msb-justify mantissa
        m >>= 30 - x                'shift down to 1/2-lsb
        m += r                      'round (1) or truncate (0)
        m >>= 1                     'shift down to lsb
        if s                        'handle negation
          -m
        return m                    'return integer
    
          
    PRI Unpack(pointer, single) | s, x, m
    
    'Unpack floating-point into (sign, exponent, mantissa) at pointer
    
      s := single >> 31             'unpack sign
      x := single << 1 >> 24        'unpack exponent
      m := single & $007F_FFFF      'unpack mantissa
    
      if x                          'if exponent > 0,
        m := m << 6 | $2000_0000    '..bit29-justify mantissa with leading 1
      else
        result := >|m - 23          'else, determine first 1 in mantissa
        x := result                 '..adjust exponent
        m <<= 7 - result            '..bit29-justify mantissa
    
      x -= 127                      'unbias exponent
    
      longmove(pointer, @s, 3)      'write (s,x,m) structure from locals
      
      
    PRI Pack(pointer) : single | s, x, m
    
    'Pack floating-point from (sign, exponent, mantissa) at pointer
    
      longmove(@s, pointer, 3)      'get (s,x,m) structure into locals
    
      if m                          'if mantissa 0, result 0
      
        result := 33 - >|m          'determine magnitude of mantissa
        m <<= result                'msb-justify mantissa without leading 1
        x += 3 - result             'adjust exponent
    
        m += $00000100              'round up mantissa by 1/2 lsb
        if not m & $FFFFFF00        'if rounding overflow,
          x++                       '..increment exponent
        
        x := x + 127 #> -23 <# 255  'bias and limit exponent
    
        if x < 1                    'if exponent < 1,
          m := $8000_0000 +  m >> 1 '..replace leading 1
          m >>= -x                  '..shift mantissa down by exponent
          x~                        '..exponent is now 0
    
        return s << 31 | x << 23 | m >> 9 'pack result
    
    {{
    
    ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
    │                                                   TERMS OF USE: MIT License                                                  │                                                            
    ├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
    │Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation    │ 
    │files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,    │
    │modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│
    │is furnished to do so, subject to the following conditions:                                                                   │
    │                                                                                                                              │
    │The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│
    │                                                                                                                              │
    │THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE          │
    │WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR         │
    │COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,   │
    │ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                         │
    └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
    }}    
    
  • dgatelydgately Posts: 1,109
    edited 2019-04-23 - 01:38:52
    First off... i is an integer... It most likely will not hold a value of '1.111', right?
    Secondly... a For loop would need some form of stepping of non-integers, if it allowed floating point as an index:
    For someFloatValue = 1.111 To 20 Step .5  '' if that works at all
    
    Third... I'm not sure that you can print a floating value directly in this BASIC. You probably need a formatted print statement. I'm a bit fuzzy on this BASIC, but if it's like Spin, it will need a formatted print statement.

    EDIT: Looks like FloatMath.spin uses an integer as basically a pointer to a 32 bit value that it manipulates as if a float. It packs a float into those 32 bits, that would need to be unpacked for use. i.e. you can't just print the integer, as-is.
    ''Convert integer to float
    
      if m := ||integer             'absolutize mantissa, if 0, result 0
        s := integer >> 31          'get sign
        x := >|m - 1                'get exponent
        m <<= 31 - x                'msb-justify mantissa
        m >>= 2                     'bit29-justify mantissa
    

    dgately
    Livermore, CA (50 miles SE of San Francisco)
  • Spin doesn't have any notion of types, so basically every Spin function's return value has the BASIC type "any", which is just a plain 32 bit value with no real interpretation. This won't mix well with BASIC floating point values ("single"). In BASIC you can just use floating point the same way you do in C.

    For loops and print will work with floats, so you can do something like:
    dim x as single  ' declare x as a float
    for x = 1.11 to 10
      print x
    next x
    

    So there's no need for FloatMath.spin in a BASIC program, and it would actually be confusing to try to mix BASIC floating point and a Spin object.
  • OK, since there is no need to use FloatMath.spin object, is it somehow corrupting some values in the DHTnn_Object.spin object since it uses both FloatMath.spin and FloatString.spin objects? I have not tried the FloatString.spin object on its own, so I am not sure if it will have a problem working with fastspin Basic.

    Ray
  • Rsadeika wrote: »
    OK, since there is no need to use FloatMath.spin object, is it somehow corrupting some values in the DHTnn_Object.spin object since it uses both FloatMath.spin and FloatString.spin objects? I have not tried the FloatString.spin object on its own, so I am not sure if it will have a problem working with fastspin Basic.

    I don't think it's a conflict -- you said things work if optimization is disabled, so you've probably encountered a bug in fastspin's optimizer. The Float*.spin files should work, it's just that calling them from BASIC requires some care since Spin does not have floating point as a built in type but BASIC does. (Plus there's not really any need to call them from BASIC, since BASIC has the same functions built in.)

    I'd like to figure out what's going wrong, but I don't have DHTnn hardware to test with. Looking at the code I'd guess that if something's going wrong it may be with the data[] array in the DHTnn_Read function in DHTnn_Object.spin. You could try changing that from a local variable to a method variable (in the VAR block) to see if that helps.
Sign In or Register to comment.