28X2, 40X2, Multiple Slots and Interrupts

inglewoodpete

Senior Member
A couple of my programs have "hit the limits" of Slot 0 of their respective X2 program memories.

I am now in the process of dissecting my program and spreading it over 2 slots. I have Timer interrupts enabled and need them operational when code is running in both slots. This is a complicated communication package and I need to avoid lockups should something go wrong between chips.

My question: Has anyone had experience with interrupts where more than 1 slot is used?

I have read the description under the Run command: "1. No gosubs (including the interrupt) can be shared between program slots"

I was wondering if I could just duplicate the Interrupt code on each Slot or are there some hidden 'gotchas'. (Oh for the #include directive;))
 

BeanieBots

Moderator
Played with quite a few multi-slot programs and there ARE some gotchas waiting in the wings.
The obvious one which I'm sure you know is that ALL memory is shared.
The not so obvious one is that all the 'special' variables are reset to zero. This means that you cannot have a timer which is common to more than one slot. (but you can use timer in any slot)
Commands such as 'settimer' must be initialised in each and every slot.
The same is true for interrupts.

I have not had any issues using identical interrupt initialisation or routines when switching between slots.
The only pain is the inability to 'carry over' the timer value. It can be preserved in a variable but you might miss one or more 'ticks' during the transition and setup.
 

inglewoodpete

Senior Member
Commands such as 'settimer' must be initialised in each and every slot.
The same is true for interrupts.

I have not had any issues using identical interrupt initialisation or routines when switching between slots.
The only pain is the inability to 'carry over' the timer value. It can be preserved in a variable but you might miss one or more 'ticks' during the transition and setup.
Thanks for the insights. You've probably saved me several hours of debugging. I think I can restructure my code so that I keep comms timeout handling within 1 slot. If I have to hand the timer value from one slot to another, a few minor ticks here or there should not matter.

Sharing variables and memory is a good thing. My code is quite modular and I peek/get and poke/put for each routine sequence.
 

greencardigan

Senior Member
A couple of my programs have "hit the limits" of Slot 0 of their respective X2 program memories.
How do you know when you have reached the memory limit for each slot?

Manual 1 says X2 have 4 slots of 1000 lines each.
But Manual 1 also says X2 have 2000 to 3200 lines over 4 slots.

How many bytes per slot?
 

hippy

Technical Support
Staff member
There are 4096 bytes per slot.

When you do a Syntax Check ( and after download if not launching the Terminal or Debug window ) the Programming Editor reports how many bytes have been used in the slot. You'll get an error message if the program code is too large.
 

inglewoodpete

Senior Member
You'll get an error message if the program code is too large.
Better (or worse:rolleyes:) still, the compiler tells you how many bytes over the limit your program is.

My need was accelerated: I decided to upgrade some X1s to X2s before they hit their limits. The catch was that, when I converted the programs from X1 to X2, they grew in size. Perhaps 3-5% as a guess. And then they wouldn't fit without pruning. I wanted to get the programs running before disecting then into 2 slots each. A bit awkward but I had to comment out a couple of non-essential subroutines.
 

inglewoodpete

Senior Member
The outcome

Some feedback on my experiences with converting a program from single slot to dual slot.

Background: I am upgrading an internet-connected 40x1 which drives 4 x 28x1 i2c bus masters. The upgrade was to replace the existing PICAXEs with a 40x2 and 28x2s to utilise the greater speed and program space.

The communication between the 40x2 and 28x2s is a parallel bus arrangement. Timer 0 is used to supervise communication between the chips. If the other end of the bus should fail to respond, I need the other chips to continue communicating and functioning normally. During the idle time, I use the same background timer to initiate polling of slaves on the i2c busses.

In the end, I broke the code into two blocks according to the supervising timer functions and the associate interupts. All code used for communicating over the parallel bus was moved to Slot 1 with Timer 0 used to supervise communication. Administration and i2c polling code remained in Slot 0 with Timer 0 operating as a task scheduler.

For those of you that are interested, the code in the next post is a very much cut-down version. Slot 0 sends execution to subroutine-like calls which identify functions in Slot 1 via a variable. Once complete, slot 1 returns execution to slot 0 with the same variable indicating to slot 0 that the PICAXE is not booting up.

I have kept the code for both slots in one file and used conditional compiling to switch between slots. I'm looking forward to the #Include directive being completed, making a more flexible approach possible.

Code appears in the next post due to size limitations.
 

inglewoodpete

Senior Member
Refer to the previous post for details.

Code:
'Symbol Version = 5 'v1.5  14-May-2011      4022 bytes Revision prior to splitting code into 2 slots
Symbol Version = 6 'v1.6   28-May-2011 1825/2322 bytes Split into 2 slots. Functionality tested.
'
Symbol MajorRevision = 1  'Revision for production
'
#define LoadSlot0         'Allow loading of 2 different slots from 1 source file
'
#IfDef LoadSlot0
#Slot 0                'Slot 0 handles Serial I/O with MAX and cmd analysis and administration
#Else
#Slot 1                'Slot 1 handles comms between the Serial master and the 4 i2c controllers
#EndIf
'
#Picaxe 40x2
' 
#Terminal 38400         'Open PE Terminal immediately
'#No_Data               'Don't overwrite EEPROM
'#No_Table              'Don't download Table (Flash) or Overwrite EEPROM
'
'--------- Variable Definitions ---------------------------------
'
Symbol bInpStatus    = b0    'w0 Temp use: indicate status of incoming signal lines
Symbol bTemp         = b2    'w1  any local temp use
Symbol bSlotControl  = b27   'w13 Handshake between slots
'
'   b0 - bInpStatus
Symbol tSelcdState   = bit2  'b0/w0
Symbol tTaskTmrOn    = bit4  'b0/w0
Symbol tTaskTmrExp   = bit5  'b0/w0
Symbol tIOTmrOn      = bit6  'b0/w0
Symbol tIOTmrExp     = bit7  'b0/w0
'
'---------- I/O Pins --------------------------------------------
'
Symbol oStatus       = C.2   'Leg 13 Output. Status indication to front panel
Symbol oHndShk       = C.6   'Leg 17 Output.Handshake to master
'
'--------- RAM definitions --------------------------------------
'
Symbol IOStatus      = $6E   'IO Timer status + PortA and PortC pin conditions
Symbol B0Int         = $6F   'Temp storage of b0 during Interrupt routine
'
'----------- Constants ------------------------------------------
'
'Generic Constants
Symbol False         = 0
Symbol True          = 1
Symbol Lo            = 0
Symbol Hi            = 1
'
Symbol cPause100mS_32   = 400
Symbol cPause500mS_32   = 2000
'
'Timer values
Symbol tmrIntOn4thTick  = $FFFC   'Interrupt to be caused by roll over on forth major tick
'
Symbol tmr400mS_8x4     = 53036
Symbol tmr1200mS_8x4    = 28036
'
Symbol mskTimer0Int     = %10000000 'For the SetInt command
'
'Constants for Handshaking between Slots
Symbol cBootup          = 0
Symbol cReceiveData     = 1   'Call to Subprogramme cReceiveData
Symbol cMasterCommand   = 2   'Call to Subprogramme cMasterCommand
'
#IfDef LoadSlot0
'
' =====  P R O G R A M    I N I T I A L I S A T I O N =====
'
Initialise:
      If bSlotControl = cBootup Then 'Is PICAXE Booting Up?
         dirsA = %00000000           'All Input (0 is input; 1 is output)
         dirsB = %11111111           'All Output
         dirsC = %00000111
         dirsD = %00000000           'All Input
         Pause cPause500mS_32
         SerTxd (CR, LF, "Boot")
         For bTemp = 1 to 15         'Indicate bootup: 15 flashes
            High oStatus
            Pause cPause100mS_32
            Low oStatus
            Pause cPause100mS_32
         Next bTemp
         '
         SerTxd (" i2c bus Controller Vers ", #MajorRevision, ".", #Version, CR, LF)
         '
      Else   'Reentering from Slot 1
         'do any reentrant stuff here
         SerTxd("---Re entered Slot 0 ", CR, LF)
      EndIf
      SerTxd("Enter main loop.", CR, LF)
      '
      ' =====   I n i t i a l i s a t i o n   C o m p l e t e   =====
      '
      Do
         If tSelcdState = Hi Then
            'Serial master has tSelected me to transfer data to:
            'Receive the data fron the master
            Poke IOStatus, bInpStatus 
            SerTxd("Slctd; ", CR, LF)
            GoSub ReceiveData                'Go receive data (and place in RAM at IOBuffer)
            '(If received bHeader is 0 then data at spData4SerMaster is uploaded to SerialMaster)
         EndIf
         '
         'Set task timer if not set: Task timer periodically gets data from slave scratchpad
         Peek IOStatus, bInpStatus
         If tTaskTmrOn = False Then
            tTaskTmrOn = True
            tTaskTmrExp = False              'Note: Task Timer (not I/O Timer)
            Poke IOStatus, bInpStatus
            Timer = tmrIntOn4thTick
            SetIntFlags mskTimer0Int, mskTimer0Int   'Set timer 0 to interrupt
            SetTimer tmr400mS_8x4            'Start the firmware timer  Changed from 200mS v0.1.8
            SerTxd("TaskTmrStart ")          'debugging only
         EndIf
            '
         'Task timer periodically initiates the fetching of data from slaves' scratchpads
         Peek IOStatus, bInpStatus
         If tTaskTmrExp = True Then
            If @Ptr = 0 Then                  'Time to do task but only if buffer is empty
               SerTxd("TaskStt ")
               SetTimer Off
               Poke IOStatus, 0               'Clear it
               GoSub PollNextSlave
            EndIf
         EndIf
         '
      Loop
'
' -----  S U B R O U T I N E S    f o r   S L O T   0  -----
'
' ----- Calls for entry to Slot 1 ------
'
'  Program arrives here as subroutine calls
'  The "Run 1" command clears the return stack, so there are no "Return" Statements.
'
ReceiveData:         bSlotControl = cReceiveData
                     Run 1
                     '
HandleCmdFromMaster: bSlotControl = cMasterCommand
                     Run 1
'
' ----- PollNextSlave: Periodic update of local cache of slave S/Pad data
'
'   Note:      Initiated by Task Timer
PollNextSlave:
            Return
'
' ====== Interrupt Handler: Slot 0 =========================================
'
Interrupt:  Poke B0Int, b0                 'Preserve
            Peek IOStatus, bInpStatus      'Get stored IO status (includes timer status)
            If tTaskTmrOn = True Then      'Task is to get the s/pad data from 1 Pole
               SerTxd(" -Tsk0- ")
               tTaskTmrExp = True
               Poke IOStatus, bInpStatus
               SetTimer Off
            EndIf
            Timer = tmrIntOn4thTick        'Set to re-interrupt on first (major) tick
            TOFlag = 0                     'Reset TimeOut flag
            SetIntFlags mskTimer0Int,mskTimer0Int'Set Timer 0 to interrupt
            Peek B0Int, b0                 'Restore
            Return
'
' --------------------------------------------------------------------------
'
#Else      'Entry Routine for Slot 1 (The second slot contains )
'
EntrySlot1: SerTxd("---Slot 1, Call=", #bSlotControl)
            '
            'Disable Task Timer, if running
            Peek IOStatus, bInpStatus
            If tTaskTmrOn = True Then
               SerTxd(" TaskTmrStop ")
            EndIf
            bInpStatus = 0                 'Reset and initialise all timer flags
            tIOTmrOn = True
            Poke IOStatus, bInpStatus
            SetTimer Off                   'Reinitiate Timer
            SetIntFlags mskTimer0Int, mskTimer0Int   'Set timer 0 to interrupt
            Timer = tmrIntOn4thTick        'A major tick occurs on the forth minor tick
            '
            Select Case bSlotControl
            Case cReceiveData
               GoSub ReceiveData
            Case cMasterCommand
               GoSub HandleCmdFromMaster
            Else
               SerTxd ("--->>Handshake not recognised<<", CR, LF)
            EndSelect
            '
            'Disable IO timer (may possibly have timed out too) - must be done in slot 1
            Peek IOStatus, bInpStatus
            If tIOTmrOn = True Then     'IO session with Serial Master is over: reset everything
               Low oHndShk              'Don't Alert Master low: send data still required
               SetTimer Off
               Poke IOStatus, 0         'Clear all bits
            EndIf
            Run 0                       'Return control to slot 0 (bSlotControl must be non-zero)
'
' =========  S U B R O U T I N E S    F O R   S L O T   1  ===========================
'
' ----- ReceiveData: Receive Data from Serial Master ---------------------
'
ReceiveData:Timer = tmrIntOn4thTick
            SetIntFlags mskTimer0Int, mskTimer0Int   'Set timer 0 to interrupt
            SetTimer tmr1200mS_8x4                   'Start the firmware timer
            High oHndShk                             'Initial response
            'other code
            Return
'
' ----- HandleCmdFromMaster: Process Instructions from Serial Master -------
'
' Entry: Valid command from SerialMaster identified in receive buffer at IOBuffer
'
HandleCmdFromMaster:
            'other code
            Return
'
' ====== Interrupt Handler: Slot 1 =========================================
'
Interrupt:  Poke B0Int, b0                 'Preserve
            Peek IOStatus, bInpStatus      'Get stored IO status (includes timer status)
            If tIOTmrOn = True Then        'Don't reset IO timer
               SerTxd(" -Int1- ")
               tIOTmrExp = True
               Poke IOStatus, bInpStatus
               SetTimer Off
            ElseIf tTaskTmrOn = True Then  'Task is to get the s/pad data from 1 Pole
               SerTxd(" -Tsk1- ")
               tTaskTmrExp = True
               Poke IOStatus, bInpStatus
               SetTimer Off
            EndIf
            Timer = tmrIntOn4thTick        'Set to re-interrupt on forth (major) tick
            TOFlag = 0                     'Reset TimeOut flag
            SetIntFlags mskTimer0Int,mskTimer0Int'Set Timer 0 to interrupt
            Peek B0Int, b0                 'Restore
            Return
'
#EndIf   'End of slot 1 code (comms for i2cControllers)
'
'--------    S H A R E D    S U B R O U T I N E S    ---------
'
'Subroutines common to both slots
 
Top