Question about scope and recycling of vars

Discuss the Firewing language

Question about scope and recycling of vars

Postby Timbo » Mon Jun 01, 2015 12:32 pm

Hi,

I have a load of code and variables that are used in an interrupt routine. To make them accessible to code outside I'm using declaring them as Public. But what happens to the contents of the other variables in the sub? Are they getting reused?

BTW the vars are declared outside the event handler sub because inside is an issue.

I ask as I'm getting a flag corrupted. Its not happening on the 18 series pic in a VSM. The boolean var was inside a structure, I moved it outside and it was fine.

Thanks

Tim
Timbo
 
Posts: 93
Joined: Fri May 03, 2013 7:51 pm

Re: Question about scope and recycling of vars

Postby Jerry Messina » Mon Jun 01, 2015 1:17 pm

In general, variables declared local to a subroutine only exist for the lifetime of the subroutine and are recycled when the sub exits.

If you have variables that need to exist outside of the ISR, or between modules, it's best to declare them at the module-level.
That way they exist all the time, and are never shared.

It might be best to show a short example of how you're declaring/using things. If vars are getting corrupted there are a number of things that can be going wrong.
Jerry Messina
 
Posts: 280
Joined: Thu Feb 14, 2013 10:16 am

Re: Question about scope and recycling of vars

Postby Timbo » Mon Jun 01, 2015 2:25 pm

This my "work in progress messy code" not very much commenting yet.

I will try to make it a module, which it is supposed to be. It might resolve the other issues I have had.

Code: Select all
'*****************************************************************************
'*  Name    : UNTITLED.1                                                     *
'*  Author  : [select VIEW...EDITOR OPTIONS]                                 *
'*  Notice  : Copyright (c) 2015 [select VIEW...EDITOR OPTIONS]              *
'*          : All Rights Reserved                                            *
'*  Date    : 10/05/2015                                                     *
'*  Version : 1.0                                                            *
'*  Notes   :                                                                *
'*          :                                                                *
'*****************************************************************************

' Imports section...

imports Tick

// A/D port defs
Dim WLevel as A0
DIm WCPress as A1
Dim WLLow as A2
Dim WLHigh as A3
Dim BSen as A4
Dim TempSensor as A5



// Main Vars exposed to the outside world

Public Structure AllaisingArray_t                                                // All these read only
   VarArray(20) as byte
   WaterLevel as VarArray(0).AsUshort                                            // Water level as % 0-100
   CondenceFlow1hz as VarArray(2).AsUshort                                       // Volume of Gas over last 1 hz
   BubbleFlow1hz as VarArray(4).AsUshort                                         // Volume of water over last 1 hz
   NCTrueValue as VarArray(6).AsUshort                                          // Last proper NC value following a full cycle
   CurrentRawLevel as VarArray(8).AsUshort                                      // Raw value of the level
   BottomOptoRaw as VarArray(10).AsUshort                                        // Last raw value of bottom opto
   TopOptoRaw as VarArray(12).AsUshort                                           // Last raw value of top opto 
   CurrentStage as VarArray(14)                                                  // Current Stage Need to add values
   Flags as VarArray(18)   
   BottomOpto as Flags.Booleans(0)                                                // True or False value of the status of the bottom opto 1 = water is seen
   TopOpto as Flags.Booleans(1)                                                   // True or False value of the status of the top opto 1 = water is seen 
   //Hz1TickUpdated as Flags.Booleans(7)
End Structure                                                                   

Public dim Hz1TickUpdated as boolean
Public Dim DrainState as Byte
Public Dim MainValveState as Byte

Public Dim NC_Status as AllaisingArray_t   

dim MainHzCounter as Byte = 0                                                    // 1000hz tick to 100hz counter

// Water detection levels

Const WaterTransitionLevel = 1000   // Level that trips between a seeing water and no water

//Dim TempByte as Byte
Dim TempUshort1 as Ushort
Dim TempUlong as Ulong

Dim WLevelRawAverageing as Ulong

// Pressure sensor inputs
Dim WLevelRaw as Ushort
Dim PreCapPressureRaw as Ushort


// Optical Sensors and levels
Dim LowWLevelSense as Ushort
Dim HighWLevelSense as Ushort
Dim BubbleRaw as Ushort
Dim WaterOptoTransitionLevel as Ushort  = 600 /// temp setting <<<<<<<<<<<<<<<<<

// Boolean status of the water seen across sensor
Dim WaterLevelHigh as Boolean   = False
dim WaterLevelLow as Boolean    = False
Dim BubbleSeen as Boolean       = False

// Declare all the main state machine variables

dim ChangeState as boolean                                                       // Flag to say we can change state now

public enum MState as byte
  Off = 0                                                                        // This State has the unit in Off mode
  StartUp                                                                        // Starting up
  Cycle                                                                          // Cycling state
  Sample                                                                         // One Shot sample
  ShutDown                                                                       // Shutting down
end enum
Dim MainState as MState = MState.Off                                             // Decalre the staemachine var and set it to off

public enum SMStateCycle as byte                                                 // Sub State machine inside The Main cycleing state
   Filling = 0                                                                    // In filling phase
   Emptying                                                                       // In Emptying Phase
   TimedEmptying                                                                  // In timed delay before closing the valve
   Calibration                                                                   // Calibration mode were you do not go in one direction and do not dump to drain when it hits the high opto
end enum
Dim  SubStateMCycle as SMStateCycle = SMStateCycle.Filling   

Public Enum SMStateDrian as byte
   Emptying = 0                                                                   // In Emptying Phase
   TimedEmptying                                                                  // In timed delay before closing the valve
   ShutDown
End enum

Dim SubStateMDrain as SMStateDrian = SMStateDrian.Emptying                                                 

// Flow rate const and vars
const TubeVolume = 3000000 // Volume in 1,000,000th of a ml
Const TimedEmptingVolume = 20000000  // Volume
dim MlPerStep as Ushort 
Dim CurrentFlowRate as ULong                                                   // Flowrate in 10,000 th of a ml
Dim CurrentFlowRateDown as ULong   
Dim FloWRateCalcTimer as Ushort
Public Dim FlowDownTimer as Ushort
Dim RawLevelChange as Ushort 
Dim LastWLevelRaw as Ushort
Public Dim TimedEmptyPeriod as Ushort
Public dim UpdateTimer1Hz as byte
Dim Condence1HzTallyCount as Byte
Dim Bubble1HzTallyCount as Byte


Dim BubbleCountTimer as Byte
Dim BubbleTotal as Ulong = 0                                                     // Current Bubble total Volume in 10,000 ml ths

// Temperature Sensor
Dim TempSensorRaw as Ushort


// Solinods
Dim InletSolinoid as D0
Dim DrainSolinoid As D2


// Dims for the Raw Level values

   Dim SampleLevelToBuffer as bit
   Dim RawUpperBufferCounter as byte          // The element in the array pointer
   Const RawUpperBufferNo = 4                  // We are only going to sample 4 to make the maths easier to divide
   Dim RawUpperLevelArray(RawUpperBufferNo) as Ushort         // The Array used
   Dim LowLevelFlag as Boolean                      // Flag used to watch for an up ward going water level to save the raw


   // Volume and flow level D
   Dim RawLevelStart as Ushort
//   Dim RawLevelTop as Ushort
   Dim RawVolumeRange as Ushort
   
   Dim AverageTopSensor as ushort                                                // Holds the current esimated top value so it can be used for the maths
   dim AverageBottomSensor as Ushort
   
   Dim BottomOptoMin as ushort                                                   // Values that the raw value has to be within before Otpo will be detected
   Dim BottomOptoMax as Ushort                                                   // This is to prevent bubbles in the opto tube being read premeturly
   DIm TopOptoMin as Ushort
   
   dim BubbleCondenceTotal as ulong 

   
   Inline Sub OpenDrain()                                                       // Valve control subs
      High(DrainSolinoid)
      DrainState = 1
   end sub
   
   Inline Sub CloseDrain()
      Low(DrainSolinoid)
      DrainState = 0
   End Sub
   
   Inline Sub OpenInlet()
      High(InletSolinoid)
      MainValveState = 1
   End Sub
   
   Inline Sub CloseInlet()
      Low(InletSolinoid)
      MainValveState = 0
   End Sub                 
   
   Inline Function IsThereWater(InputSensor as ushort) as boolean
      If InputSensor < WaterOptoTransitionLevel then
         Return True
      Else
         Return False
      End if
   End Function
   
   function RoundedDiv(ValueNum as ULong, ValueDivisor as Ushort) as Ulong
      RoundedDiv = ValueDivisor / 2
      RoundedDiv = RoundedDiv + ValueNum
      RoundedDiv = RoundedDiv/ValueDivisor
   end function   
                       
     
               
Sub DrainingMode()
     
         

      // Every second Workout the flow rate down but only if there is no bubble
   if BubbleSeen = False  then
      if FloWRateCalcTimer < 99 then
         FloWRateCalcTimer += 1                                                  // Inc timer
      Else 
         FloWRateCalcTimer = 0                                                   // Reset the timer                                       
         RawLevelChange = LastWLevelRaw - WLevelRaw                              // Work out the raw level change since last time
         LastWLevelRaw = WLevelRaw
         CurrentFlowRateDown = MlPerStep * RawLevelChange                        // We can work out the flow rate in ML now   
      End if 
   End if
                 
   if WaterLevelLow = True then
      ChangeState = True
      FlowDownTimer = 0
      FloWRateCalcTimer = 0       
      // Work out how long it will take to remove an extra x ml
      TempUlong = TimedEmptingVolume / CurrentFlowRateDown     
      TimedEmptyPeriod = TempUlong     
   End if   
   
End Sub
     
     
Sub TimedDrainMode()
   /*
   if FloWRateCalcTimer < 99 then
      FloWRateCalcTimer += 1                                                     // Inc down flow rate timer even while doing the timed drain
   Else 
      FloWRateCalcTimer = 0                                                      // Reset the timer
   End if
   */

   if FlowDownTimer <= TimedEmptyPeriod then                                      // We keep going until the time we worked out before hits
      FlowDownTimer += 1                                                         // Inc timer
   Else
      ChangeState = True
      CloseDrain()
      LastWLevelRaw = WLevelRaw                                                  // Get it ready to do so
   end if 
End Sub
       

Sub FillingMode()
               
   // Every second Workout the flow rate out
   if BubbleSeen = False  then   
      if FloWRateCalcTimer < 99 then
         FloWRateCalcTimer += 1                                                  // Inc timer
      Else                                         
         RawLevelChange =  WLevelRaw - LastWLevelRaw                             // Work out the flow rate over the last 2 seconds
         LastWLevelRaw = WLevelRaw                                         
         CurrentFlowRate = MlPerStep * RawLevelChange                            // We can work out the flow rate in ML now
         FloWRateCalcTimer = 0                                                   // Reset the timer
      End if                                                                                                                 
   End If         
               
   if WaterLevelHigh = true then
      ChangeState = True
      OpenDrain()
      FloWRateCalcTimer = 0     
      LastWLevelRaw = WLevelRaw                                                  // Record this value for the next stage         
   End if
     
End Sub

Sub CalcLevelPercentage()
   TempUshort1 = WLevelRaw - RawLevelStart
   TempUlong = (TempUshort1 * 100)     
   NC_Status.WaterLevel = TempUlong / RawVolumeRange
End Sub         

sub OnTickEvent() handles Tick.OnTick


   TempUshort1 = Adc.Read(WLevel)                                                  // Read the Pressure Levels
   WLevelRawAverageing = WLevelRawAverageing + TempUshort1             
   
   MainHzCounter += 1

   If MainHzCounter > 9 then 
   
      MainHzCounter = 0
               
      Save(0)
                                                                         
      WLevelRaw = WLevelRawAverageing / 10                                      // This pressure reading is averaged every 100hz (sampled at 1000hz)
      WLevelRawAverageing = 0
     
      PreCapPressureRaw = Adc.Read(WCPress)

      LowWLevelSense = Adc.Read(WLLow)                                              // Read the Bubble sense inputs
      HighWLevelSense = Adc.Read(WLHigh)                                           
      BubbleRaw = Adc.Read(BSen) 
         
                                                                                       
      TempSensorRaw = Adc.Read(TempSensor)                                          // Read the Temp sensor
                                         
         
      // Process the Bubble Level inputs
         
         
      // Check the Low Level Opto

      if WLevelRaw > BottomOptoMin and WLevelRaw < BottomOptoMax then
         If IsThereWater(LowWLevelSense) then                                          // If we see water
            WaterLevelLow = False                                                      // Flag it up to say we have water flag is to say water level is not below sensor 
            If LowLevelFlag = False then                                                  // If last time the level was below the sensor
                RawLevelStart = WLevelRaw                                              // Record the level at which we see the water
                LowLevelFlag = True                                                       // Change the level flag
                // Now work out the raw range for the flow calculations later
                RawVolumeRange = AverageTopSensor - RawLevelStart             
                MlPerStep = RoundedDiv(TubeVolume,RawVolumeRange)                   // Work out the volume per step
                LastWLevelRaw = WLevelRaw                                           // We need to load this so the maths works later                                           
                FloWRateCalcTimer = 0                                               // And reset the timer   
            End if
         Else
            WaterLevelLow = True                                                       // Flag to say no water so bottom sensor hit
            SampleLevelToBuffer = 0                                                    // We can set the flag to so we save the top level for the everage next time
            LowLevelFlag = False                                                           // Set this flag as well so we know to catch the upward movement   
         End if
      End if                     
             
         
         
      // Check the High Level Opto
      WaterLevelHigh = False   
      if WLevelRaw > TopOptoMin then
         If IsThereWater(HighWLevelSense) then                                         // If the level indicates there is water sensed   
            WaterLevelHigh = True                                                      // Mark it so   
            If SampleLevelToBuffer = 0 then                                            // First time we see it go high this time we save the value to the buffer
               SampleLevelToBuffer = 1
               RawUpperLevelArray(RawUpperBufferCounter) = WLevelRaw         
               // Inc the counter and roll over if need be
               RawUpperBufferCounter += 1             
               if RawUpperBufferCounter >= RawUpperBufferNo then                       // We take the average off 5 samples taken at the level transisiton
                  RawUpperBufferCounter = 0
               End if   
               dim i as byte
               AverageTopSensor = 0
               for i = 0 to (RawUpperBufferNo -1)                                      // Every time we add to our average buffer we work out the current average
                  AverageTopSensor = AverageTopSensor + RawUpperLevelArray(i)
               next
               AverageTopSensor = AverageTopSensor >> 2                                // Div by 2 quickly
               NC_Status.TopOptoRaw = WLevelRaw
            End if
         End if                   
      End if
       
         
             
      // Check the Bubble opto
      If IsThereWater(BubbleRaw) then
         BubbleSeen = False
      Else
         BubbleSeen = true
      End if
         
      // State Machines controlling the system
         

         
      Select MainState
         Case MState.Off
            CloseDrain()
            CloseDrain()
         case MState.StartUp
            OpenDrain()
            OpenInlet()
               
         Case MState.Cycle
           
            Select SubStateMCycle
               
            Case SMStateCycle.Filling
               CloseDrain()     
                 
               ChangeState = False         
               FillingMode()         
               if ChangeState = True then
                  SubStateMCycle = SMStateCycle.Emptying                            // Move onto the next state in the state machine
               End if
                 
            Case SMStateCycle.Emptying
               OpenDrain()   
                 
               ChangeState = False
               DrainingMode()                                                        // Call the drain system routine
               if ChangeState = True then
                  SubStateMCycle = SMStateCycle.TimedEmptying                       // Move onto the next state in the state machine
               End if
                 
                     
            Case SMStateCycle.TimedEmptying
               OpenDrain()
                 
               ChangeState = False
               TimedDrainMode()
               if ChangeState = True then
                  SubStateMCycle = SMStateCycle.Filling                             // Move onto the next state in the state machine
               End if
         End select                 
                 
                   
         Case  MState.Sample
           
               
         Case  MState.ShutDown
               
            Select SubStateMDrain
               
            Case SMStateDrian.Emptying
               ChangeState = False
               DrainingMode()                                                       // Call the drain system routine
               if ChangeState = True then
                  SubStateMDrain = SMStateDrian.TimedEmptying                             // Move onto the next state in the state machine
               End if
            Case SMStateDrian.TimedEmptying
               ChangeState = False
               TimedDrainMode()                                                     // Call the Timed drain system routine
               if ChangeState = True then
                  SubStateMDrain = SMStateDrian.ShutDown                       // Move onto the next state in the state machine
               End if
            Case SMStateDrian.ShutDown
               CloseInlet()
               CloseDrain()
               
            End Select
                 
                 
               
               
      end select                       
                                                 
         
         
      // Keep a running tally of collected bubbles based on the flow rate
       
      If BubbleSeen = True then                                                     // Bubble!!!
         BubbleCountTimer += 1                                     
         If BubbleCountTimer >=100 then
             BubbleTotal = BubbleTotal + CurrentFlowRate                          // Tally the flow over the last 1hz
             BubbleCountTimer = 0
         End If
      Else                                                                          // Bubble no longer seen
         If BubbleCountTimer > 0 then   
            TempULong = CurrentFlowRate * BubbleCountTimer
            TempUshort1 = TempULong / 100
            BubbleTotal = BubbleTotal + TempUshort1                                  // Tally the flow for the last time for this bubble
            BubbleCountTimer = 0       
         End iF
      End If 
         
      // Do our totals and % etc   
         
         
         
             
         
      // At the end we update all our external info regs
         
           
                   
      If MainState = MState.Cycle then
         If SubStateMCycle = SMStateCycle.Filling Then
            if WaterLevelLow = False then
               CalcLevelPercentage()
            end if
         End if             
         If SubStateMCycle = SMStateCycle.Emptying then
            CalcLevelPercentage()
         end if
      End If             
                       
      // Every 100hz we tally up the bubbles and condence flow and present them as flow in our ml * x value
      If UpdateTimer1Hz < 99 then   
         UpdateTimer1Hz += 1     
         If BubbleSeen = False then
            Condence1HzTallyCount += 1
         Else
            Bubble1HzTallyCount += 1
         End If 
      Else
          UpdateTimer1Hz = 0
          TempUlong = CurrentFlowRate * Condence1HzTallyCount
          NC_Status.CondenceFlow1hz = TempUlong / 1000
          Condence1HzTallyCount = 0
          TempUlong = CurrentFlowRate * Bubble1HzTallyCount
          NC_Status.BubbleFlow1hz = TempUlong / 1000
          Bubble1HzTallyCount = 0       
          BubbleCondenceTotal = NC_Status.CondenceFlow1hz + NC_Status.BubbleFlow1hz 
             
          Hz1TickUpdated = True                                           // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
      End if 
         
         
      NC_Status.CurrentRawLevel = WLevelRaw
      NC_Status.BottomOpto = LowLevelFlag
      NC_Status.TopOpto = WaterLevelHigh
      NC_Status.BottomOptoRaw = RawLevelStart                                           // update vars displayed to the outside

      Restore     
     
   End if
   
   
End sub   
     
   

     



 Public Sub InitialiseNC_Control()
     
   WaterOptoTransitionLevel = 1000        // temp config of water level
   // Read the Stored Value for the current Top water level And load it into the array

   TempUshort1 = 3310     // This would be read from epprom Previous Average top raw
   FOr RawUpperBufferCounter = 0 to RawUpperBufferNo    // cycle through the whole array
      RawUpperLevelArray(RawUpperBufferCounter) = TempUshort1 
   Next
   RawUpperBufferCounter = 0

   AverageTopSensor = TempUshort1
   NC_Status.TopOptoRaw = TempUshort1           
                   
   
           
   TempUshort1 = 1570                // Raw value of last low sensor from previous reading
   AverageBottomSensor = TempUshort1
   
   TempUshort1 = AverageTopSensor - AverageBottomSensor
   TempUshort1 = TempUshort1 / 20                                                // Get 5% of the total
   
   BottomOptoMin = AverageBottomSensor - TempUshort1
   BottomOptoMax = AverageBottomSensor + TempUshort1
   TopOptoMin = AverageTopSensor - TempUshort1 
   
   
                               
   // Shut the valves
   CloseDrain
   OpenInlet
       
   MainState = MState.Cycle
   SubStateMCycle = SMStateCycle.Filling
         
   // Loads of other code to set up here as well 
   
   // Set up 12 bit A/D
   
    AD1CON1.bits(15) = 0   // turn off adc (ADON)
    AD1CON1.bits(10) = 1   // set 12-bit mode (AD12B)
    AD1CON1.bits(15) = 1   // turn module back on   
         
     
 End Sub
 


sub Main()

   Dim CurrentRawLevel as Ushort
   Dim Counter as Byte

    InitialiseNC_Control()

       
   Dim Temp as Ushort = adc.read(A0)

     
     
   'loop forever...   
   while true
   
   If Hz1TickUpdated = true then
      Hz1TickUpdated = False
      CurrentRawLevel = NC_Status.CurrentRawLevel
      Counter = UpdateTimer1Hz
      Console.write("WL = ", CSTR(CurrentRawLevel),32)
      If NC_Status.BottomOpto = true then
         Console.write("B = 1 ")
      Else
         Console.write("B = 0 ")   
      End if
      If NC_Status.TopOpto = true then
         Console.write("T = 1")
      Else
         Console.write("T = 0")   
      End if               
      Console.write(32,cstr(DrainState),32)             
      select MainState 
      case MState.Off
         Console.write("Off")
      Case MState.Startup
         Console.write("SU")
      Case MState.Cycle
         Console.write("Cy")
      end select           
      console.write(32)
     
      select SubStateMCycle
      Case SMStateCycle.Filling 
         Console.write("Fi")
      Case SMStateCycle.Emptying 
         Console.write("E")
      Case SMStateCycle.TimedEmptying 
         Console.write("TE ",cstr(FlowDownTimer))
      End select
     
      Console.write(10)
   
   End if
   
   end while
End Sub
Timbo
 
Posts: 93
Joined: Fri May 03, 2013 7:51 pm

Re: Question about scope and recycling of vars

Postby Jerry Messina » Mon Jun 01, 2015 6:34 pm

There's certainly a lot going on in that ISR! I'd be inclined to move most all of that code into the main loop and just poll for the tick there, but that's just me.

One thing that sticks out is the lack of any addtl context saving in OnTickEvent() other than 'save(0)'.

Something you might try is to move all of the calculations/subroutine calls currently in OnTickEvent into a sub, and add that sub name to the save list (at this point it's easier than finding and adding each routine individually).

Code: Select all
sub MainHzCalc()
   <code that was in OnTickEvent>
end sub

sub OnTickEvent() handles Tick.OnTick
   TempUshort1 = Adc.Read(WLevel)         // Read the Pressure Levels
   WLevelRawAverageing = WLevelRawAverageing + TempUshort1
   
   MainHzCounter += 1

   If MainHzCounter > 9 then 
      MainHzCounter = 0

      Save(0, MainHzCalc)

      MainHzCalc()

      Restore
   End if
End sub   

I think I mentioned this before, but if not:

Subroutine calls made from inside an ISR are transparent to the compiler. Normally it can see the code that's directly inline and deal with it, but it won't look inside your subroutines and try and figure out what might need to be saved. That's why you have to help it out and put the names of any routines called into the Save list. That lets the compiler know it needs to look at what's going on with them and save any frame variables they might use too.

Try that and see if it clears things up. Just turning it into a module won't change much.
Jerry Messina
 
Posts: 280
Joined: Thu Feb 14, 2013 10:16 am

Re: Question about scope and recycling of vars

Postby Timbo » Mon Jun 01, 2015 7:33 pm

Hi Jerry,

First of all big thanks for all the help you are giving.

Using my other compiler with its flat structure really influenced my coding. I fully understood what was going on at the asm level so if I worried about what was being effected in the interrupt routine I could just look at the asm. Once the basic FSR etc was saved only thing left was maths regs both the compilers and the hardware.

So with this code there really is no option but to do it all in the interrupt routine. I am not in control of what is going to be going on outside of it. The TFT routines will be working hard. My flow rate calculations are based on exact timing, if they start jumping around then they go seriously wrong.

In my routines the only thing that should not really be there is the div routines. The multiply are all hardware so really will not be an issue. Reading your comments about subs. I would have thought that all I needed to do was to specify the area of code that needed context saving and the compiler would look at the vars used and save them.

I can understand that if you're calling a sub that is used by various routines then you will need to save the vars used. But my code uses nothing outside apart from division. The rest is just comparison and multiplication which should just use the hardware and inline code. So really what I need to be sure off is that the div routines are saved.

Actually thinking about it I can see why you recommend putting the maths etc in a sub as then you can specify that section needs to be properly backed saved. Not for its own sake but for anything else using div.

I have moved it all to module but I still had issues with my flags. When compiled for the 18 series I can sim it and look at the asm. Also watch vars being changed. I cannot do it for the 24 series as Labcenter does not have any of the 24H devices. I must try Mplabs...

My main code only has Console.write and CSTR so really done not understand why my simple tick flag was getting corrupted. I moved it out of the structure and it worked. Like I said in the VSM for the 18 series its fine.

Again many thanks.
Timbo
 
Posts: 93
Joined: Fri May 03, 2013 7:51 pm

Re: Question about scope and recycling of vars

Postby Jerry Messina » Mon Jun 01, 2015 9:00 pm

Glad if I can be of any help, Tim

So with this code there really is no option but to do it all in the interrupt routine

So be it then. Sometimes you're stuck with what you're stuck with!

the only thing that should not really be there is the div routines. The multiply are all hardware so really will not be an issue

That's a big assumption. Compiled for the PIC18 almost none of the multiplies invoke the hardware multiplier... they use software routines.

You've broken a lot of the statements up into simple expressions, and that can tend to help a lot, but it's always hard to guess what's going on behind the scenes.

For example, statements like
Code: Select all
AverageTopSensor = AverageTopSensor + RawUpperLevelArray(i)
will almost always require the use of temp frame variables while it calculates the address of the array item and reads it to do the calc.

The compiler does a very good job at tracking subroutine calls and frame variable usage under normal situations. What it can't track is how stuff inside an ISR interacts with the other code since the ISR can occur asynchronously at any time. It leaves it up to you to tell it. If everything was a flat model w/out ram reuse that would be easier, but then you run out of ram pretty quick.

Trying to compile for a PIC24 by debugging code on a PIC18 is not going to work too well. The compilers/chips are just too different. It's always painful learning the tricks and bumps of a different language/implementation, so I feel your pain.

...why my simple tick flag was getting corrupted. I moved it out of the structure and it worked

I'm a bit tied up right now, but I took a quick glance at the difference between having 'Hz1TickUpdated as Flags.Booleans(7)' in the NC_state struct vs on it's own and I didn't see much difference. The other booleans in the program move around and are allocate different bits, but I'd have to take a closer look to see why one works and the other didn't. It wasn't obvious.
Jerry Messina
 
Posts: 280
Joined: Thu Feb 14, 2013 10:16 am

Re: Question about scope and recycling of vars

Postby Timbo » Mon Jun 01, 2015 9:30 pm

All great advice, taking it all in. When you code inside interrupts as much as I end up doing you have to really understand the way the compiler works. So its still very new to me and hence all the basic questions.

The way I normally work is to do 98% in a VSM then just put it in the pic to check it works. So this is what I have been doing here, debugging the logic (it's not going easy I can say) is way easier in a VSM than try and figure what is going in an interrupt routine updating at 100hz.
Timbo
 
Posts: 93
Joined: Fri May 03, 2013 7:51 pm

Re: Question about scope and recycling of vars

Postby Timbo » Tue Jun 09, 2015 10:41 am

Just to say Jerry

I have been thinking hard about your advice and decided to drop using interrupts. It goes against my instinct but I think that as I really do not know enough about what's going on under the skin in Fire Wing, it's too risky. So I'm going to use 2 pic's. The code in my one will just fire out all the data as a TTL rs232 stream.

No interrupts are now needed apart from the tick. I can now be sure I can handle all the data collection at the right time as no other process need to run.

It also allows me to use i2c without worries as well.

Thanks for all the help.
Timbo
 
Posts: 93
Joined: Fri May 03, 2013 7:51 pm

Re: Question about scope and recycling of vars

Postby Jerry Messina » Tue Jun 09, 2015 5:35 pm

That's a drag. Did you ever try the "put everything in a sub and add the sub name to the savelist" method I mentioned?

You ended up using two PIC18's?
Jerry Messina
 
Posts: 280
Joined: Thu Feb 14, 2013 10:16 am

Re: Question about scope and recycling of vars

Postby Timbo » Wed Jun 10, 2015 10:41 am

HI Jerry

To give some background so you can understand it my decision making.

1 I am just dipping my toe in every now and then on this project. I work for myself so fit in the coding around my paid stuff. Ultimately the 2 are linked so while if I could get away with not doing it I would. I have to, just to ensure future employment. I used to code for hours into the night but as I got older the lure of the sofa as overcome the desire to frazel my brain on this one. As you can see by the way every time I code in Firewing I'm asking questions it's not very often. I get gaps in jobs and plan to do a few days of development work but then an order comes in and it takes priority.

2 The project needs to measure very low flow rates of water with high accuracy. I have gone from £60 flow meters to >£250 devices but all fail to provide the required accuracy. I developed a method that while not new as a concept is new in my industry. Its cheap to build (I like that bit as it helps my profits) but its not straightforward and requires a number of relatively precise measurements, a precise mechanical setup with various sensors and a logic system that keeps track of the system in its various cycle stages. Hence the need to have accurate timing, as the period between samples needs to be constant to work out the flowrate etc.

3 The end device will have a GLCD. I could use a EVE board but at £50 apposed to £8 it would be a waste of profits, and the only complex thing it will be doing is generating graphs. As its bit banged I need the high end grunt of a 16 parallel interface and a Pic24. As most of the time the pic will not be doing much I had hoped to just have my code running in an interrupt.

4 I need a pressure sensor with a fair amount of accuracy. I have tried an i2c 14 bit pressure transducer but the pressure side is not water resistant so going for a analog based one with a more robust sensor side interface. Its 0-5v though which makes issues for the 3.3v on a pic. But on one of the transducers it is mechanically very had to induce the pressure to get it to exceed 3.3v. The others I can use a r-r divider to keep it in range.

5 Ref the pressure transducer above I need at least 12 bits on the ADC. If there were an 18 series with a 12bit that had only say 20 pins I would use it. I could go for a external i2c device but as my code was going to run in an interrupt it was out of the question. Even I know its stupid to run i2c in an interrupt. So one Pic24 seemed a good option with its 12bit ADC option.

6 I prefer to VSM and in this case the logic really needs to be tested out in a VSM. I simulate the mechanical side with another pic and a few DAC devices, this enables me to check the maths and logic flow before hand. It helps ironing out bugs and seeing potential issues without the problem of debugging code in real time.

So I hope you see that lot is threaded together. If I spent more time on it I could iron out issues with the interrupt code. Once I drop the idea that it's running in an interrupt it opens up a lot of possibilities like using an 18 series with an i2c a/d converter. But if I did that I would need to build a new board and wait for it to be built.

If I just use the Firewing 24 board I can do my basic VSM'ing compiling for the 18 series board to test the logic then run it for real on the 24 series just using the
appropriate command to test for the device to change constants etc.

Also where as I needed to set up proper methods of letting the main code have access to the data. If it's running full time on the main thread I can at the appropriate time just use the variables it's using and not have to bother with aliasing and turning off interrupts. At the right time I can just fire out the data as a 232 stream to the pic handling the display. The extra pic will cost a few more £ but in the scheme of things it's not much and this kit will sell in the 100's not 1,000's.

As with everything I do if I can make it hard I will do so. Going for one pic means I can code easily, VSM it and not have to worry about syntax so much.

Again thanks for the help.

Tim
Timbo
 
Posts: 93
Joined: Fri May 03, 2013 7:51 pm

Next

Return to Language

Who is online

Users browsing this forum: No registered users and 6 guests

x