Address Traps.... again

General discussion on mikroPascal PRO for dsPIC30/33 and PIC24.
Post Reply
Author
Message
JimKueneman
Posts: 417
Joined: 10 Jan 2009 22:03

Address Traps.... again

#1 Post by JimKueneman » 23 May 2011 02:24

I was not 100% successful on the trap problem until today. ME has explained how mP deals with the software stack enough for me to track down where the problem lies (but I have not spent enough time with the assembly code to understand what is actually happening).

What appears to be happening is I have a few functions that encapsulate some formatting of strings for display on a GLCD. These functions are constantly interrupted in nested interrupts that contain a lot of function calls themselves. I am fairly sure the issues are do to the strings I am manipulating getting corrupted during and interrupt. I have seen the GLCD show a few random characters before the Address Trap was fired. Let me show some of the code that I have removed to solve the problem.

Some string constants:

Code: Select all

const
  COMMANDSTATION_NAME =             'dspDCC';
  COMPANY_NAME =                    'by Mustangpeak';
  
  STR_STATE_DATABASE =              'Database Information';
  STR_STATE_QUEUE =                 'DCC Queue Info';
  STR_STATE_DCC =                   'DCC Information';
  STR_STATE_COMMANDSTATION =        'CommandStation State';
  STR_STATE_ADC =                   'Currents and Voltages';
  
  // STR_STATE_DATABASE parameters
  STR_SLOTS =                       'Slots Used     ';
  STR_SLOTS_LEFT =                  'Slots Open     ';
  STR_TRACK_QUEUE_PEAK =            'Trk Queue Pk   ';
  STR_TRACK_PRIORITY_QUEUE_PEAK =   'Trk PriQueue Pk';
  STR_ACC_QUEUE_PEAK =              'Acc Queue Pk   ';
  
  // STR_STATE_ADC parameters
  STR_3_3 =                         '3.3V           ';
  STR_5_0 =                         '5.0V           ';
  STR_12_0 =                        '12.0V          ';
  STR_BOOSTER1_CURRENT =            'DCC Output 1   ';
  STR_BOOSTER2_CURRENT =            'DCC Output 2   ';
  STR_PROG_BOOSTER_CURRENT =        'Prog Output    ';
  STR_ACC_BOOSTER_CURRENT =         'Accory Output  ';

  // STR_STATE_DCC parameters
  STR_TRACK_PACKET_COUNT =          'Trk Pkts       ';
  STR_TRACK_PRIORITY_PACKET_COUNT = 'Pri Trk Pkts   ';
  STR_ACC_PACKET_COUNT =            'Acc Pkts       ';
  STR_PROG_PACKET_COUNT =           'Prog Pkts      ';
  STR_DCC_TIME =                    'Max DCC Delta ';
  STR_MAINLOOP_TIME =               'Max Loop T ';
  
  // STR_STATE_COMMANDSTATION 1 parameters
  STR_EMERGENCY_SHUTDOWN =          'Emgcy ShutDown    ';
  STR_EMERGENCY_STOP =              'Emgcy Stop        ';
  STR_BAUDRATE =                    'BaudRate       ';
  STR_BOOSTER1 =                    'Boost 1 Out       ';
  STR_BOOSTER2 =                    'Boost 2 Out       ';
  STR_PROGRAMMING =                 'Prog Track Out    ';
  STR_ACCESSORY =                   'Accessory Out     ';
  
  // STR_STATE_COMMANDSTATION 2 parameters
  STR_ACC_TO_TRACK_MAPPING =           'Acc to Track     ';
  STR_PROG_TO_TRACK_MAPPING =          'Prog to Track    ';
  STR_PROG_IN_SERVICEMODE =            'Service Mode     ';
  STR_ACK_IDLE_STATE =                 'Svce Mode Idle   ';
  STR_SERVICEMODE_RESULTREQUEST_COUNT ='SM Rslt        ';
  STR_SERVICEMODE_QUEUE_COUNT =        'SM Queue       ';

  STR_US =                          'us';
  STR_MS =                          'ms';
  STR_115200 =                      '115200';
  STR_38400 =                       '38400';
  STR_57600 =                       '57600';
  STR_19200 =                       '19200' ;
  STR_ON =                          'ON';
  STR_OFF =                         'OFF' ;
Some common functions to format a string for display:

Code: Select all

function ADC_Channel_To_String(Channel: Byte; var S: string[15]): string[39];
var
  _FloatStr: string[23];
  _Units: string[1];
begin
  Result := '';
  SetADCSPIClock;
  FloatToStr(real( SPI_Read_ADC_Channel(Channel)) * ADC_SCALING[Channel], _FloatStr);
  TruncFloat(@_FloatStr, 2, 23);
  SetPortExtenderSPIClock;
  strcat2(Result, S, _FloatStr);
  _Units := ADC_UNITS[Channel];
  strcat2(Result, Result, _Units);
end;

function ComparisonToString(Comparison: Boolean; var S: string[15]): string[39];
begin
  Result := '';
  if Comparison then
    strcat2(Result, S, STR_ON)
  else
    strcat2(Result, S, STR_OFF)
end;
Before I was not using strcat2 to build the strings, I was using the "+" operator. When using the "+" operator the error was hard to repeat, but when it did I traced the stack back to the "___cs2s" assembler function that is part of the code generated with a "+" operator. When I went to strcat2 it was much easier to get an error and tracing the stack took me right to the code within the strcat2 "magic" in line function. Once I commented out all calls to these two functions and just display a generic string I have run my code for the last 5 hours trouble free (never could get past 10 minutes before). So here is how I was using the function:

Code: Select all

var
  Str: string[39];             // Be careful that is long enough
  Str2: string[5];
  FloatStr: string[23];
  
procedure GUI_StateMachine;
var

  Mask: Byte;
begin     
  if GUI_Info._840msTicks >= GUI_Info.Max_GUI_UpdateCount then
  begin
    SetPortExtenderSPIClock;
    case GUI_Info.StateMachineIndex of
      GUI_STATE_0 :       // Database Information
        begin
           .....
        end;
      GUI_STATE_1 :     // DCC Information
        begin
          ......
        end;
      GUI_STATE_2 :    // Commandstation Information
        begin
          case GUI_Info.SubStateMachineIndex of
            GUI_SUBSTATE_0 :
              begin
                SPI_Glcd_Fill(0);
                GUI_Info.Max_GUI_UpdateCount := 1;
                SPI_Glcd_Write_Text(STR_STATE_COMMANDSTATION, 2, 0, 1);
                Str := ComparisonToString(CommandStation.Flags.COMMANDSTATION_FLAGS_EMERGENCY_SHUTDOWN_BIT = 1, STR_EMERGENCY_SHUTDOWN);             
                SPI_Glcd_Write_Text(Str, 2, 1, 1);
                Inc(GUI_Info.SubStateMachineIndex);
              end;
            GUI_SUBSTATE_1 :
              begin
                Inc(GUI_Info.SubStateMachineIndex);
                Str := ComparisonToString(CommandStation.Flags.COMMANDSTATION_FLAGS_EMERGENCY_STOP_BIT = 1, STR_EMERGENCY_STOP);       
                SPI_Glcd_Write_Text(Str, 2, 2, 1);

                Str := STR_BAUDRATE;
                if CommandStation.Flags and COMMANDSTATION_FLAGS_BAUD_RATE_115200 = COMMANDSTATION_FLAGS_BAUD_RATE_115200 then Str := Str + STR_115200 else
                if CommandStation.Flags and COMMANDSTATION_FLAGS_BAUD_RATE_38400 = COMMANDSTATION_FLAGS_BAUD_RATE_38400 then Str := Str + STR_38400 else
                if CommandStation.Flags and COMMANDSTATION_FLAGS_BAUD_RATE_57600 = COMMANDSTATION_FLAGS_BAUD_RATE_57600 then Str := Str + STR_57600 else Str := Str + STR_19200;
                SPI_Glcd_Write_Text(Str, 2, 3, 1);
              end;
            GUI_SUBSTATE_2 :
              begin
              
                Mask := CommandStation_DCC_Booster_Enabled_To_Mask;
                Str := ComparisonToString(Mask and MASK_BOOSTER_ID_BOOSTER_1 <> 0, STR_BOOSTER1);
                SPI_Glcd_Write_Text(Str, 2, 4, 1);
                Str := ComparisonToString(Mask and MASK_BOOSTER_ID_BOOSTER_2 <> 0, STR_BOOSTER2);
                SPI_Glcd_Write_Text(Str, 2, 5, 1);
                Str := ComparisonToString(Mask and MASK_BOOSTER_ID_PROGRAMMING <> 0, STR_PROGRAMMING);
                SPI_Glcd_Write_Text(Str, 2, 6, 1);
                Str := ComparisonToString(Mask and MASK_BOOSTER_ID_ACCESSORY <> 0, STR_ACCESSORY);
                SPI_Glcd_Write_Text(Str, 2, 7, 1);

                Inc(GUI_Info.StateMachineIndex);
                GUI_Info.SubStateMachineIndex := GUI_SUBSTATE_0;
                GUI_Info.Max_GUI_UpdateCount := 5
              end;
          end;
        end;
      GUI_STATE_3 :     // Commandstation Information
        begin
          case GUI_Info.SubStateMachineIndex of
            GUI_SUBSTATE_0 :
              begin
                SPI_Glcd_Fill(0);
                GUI_Info.Max_GUI_UpdateCount := 1;
                SPI_Glcd_Write_Text(STR_STATE_COMMANDSTATION, 2, 0, 1);
                Str := ComparisonToString(CommandStation.FlagsEx.COMMANDSTATION_FLAGSEX_MAP_ACC_TO_TRACK_BIT = 1, STR_ACC_TO_TRACK_MAPPING);
                SPI_Glcd_Write_Text(Str, 2, 1, 1);
                Inc(GUI_Info.SubStateMachineIndex);
              end;
            GUI_SUBSTATE_1 :
              begin
                Str := ComparisonToString(CommandStation.FlagsEx.COMMANDSTATION_FLAGSEX_MAP_PROG_TO_TRACK_BIT = 1, STR_PROG_TO_TRACK_MAPPING);
                SPI_Glcd_Write_Text(Str, 2, 2, 1);
                Str := ComparisonToString(ServiceModeInfo.Flags.PROGRAMMING_ACK_STATE_IN_SERVICEMODE_BIT = 1, STR_PROG_IN_SERVICEMODE);
                SPI_Glcd_Write_Text(Str, 2, 3, 1);
                Str := ComparisonToString(ServiceModeInfo.Flags.PROGRAMMING_ACK_STATE_IDLE_BIT = 1, STR_ACK_IDLE_STATE);
                SPI_Glcd_Write_Text(Str, 2, 4, 1);
                Inc(GUI_Info.SubStateMachineIndex);
              end;
            GUI_SUBSTATE_2 :
              begin
                .....
              end;
          end;
        end;
      GUI_STATE_4 :    // Voltage and Current
        begin
          case GUI_Info.SubStateMachineIndex of
            GUI_SUBSTATE_0 :
              begin
                SPI_Glcd_Fill(0);
                GUI_Info.Max_GUI_UpdateCount := 1;
                SPI_Glcd_Write_Text(STR_STATE_ADC, 2, 0, 1);
                Str := ADC_Channel_To_String(4, STR_3_3);
                SPI_Glcd_Write_Text(Str, 2, 1, 1);
                Inc(GUI_Info.SubStateMachineIndex);
              end;
            GUI_SUBSTATE_1 :
              begin
                Str := ADC_Channel_To_String(5, STR_5_0);
                SPI_Glcd_Write_Text(Str, 2, 2, 1);
                Str := ADC_Channel_To_String(6, STR_12_0);
                SPI_Glcd_Write_Text(Str, 2, 3, 1);
                Inc(GUI_Info.SubStateMachineIndex);
              end;
            GUI_SUBSTATE_2 :
              begin
                Str := ADC_Channel_To_String(0, STR_BOOSTER1_CURRENT);
                SPI_Glcd_Write_Text(Str, 2, 4, 1);
                Str := ADC_Channel_To_String(1, STR_BOOSTER2_CURRENT);
                SPI_Glcd_Write_Text(Str, 2, 5, 1);
                Inc(GUI_Info.SubStateMachineIndex);
              end;
            GUI_SUBSTATE_3 :
              begin
               Str := ADC_Channel_To_String(2, STR_PROG_BOOSTER_CURRENT);
                SPI_Glcd_Write_Text(Str, 2, 6, 1);
                Str := ADC_Channel_To_String(3, STR_ACC_BOOSTER_CURRENT);
                SPI_Glcd_Write_Text(Str, 2, 7, 1);
                GUI_Info.StateMachineIndex := GUI_STATE_0;
                GUI_Info.SubStateMachineIndex := GUI_SUBSTATE_0;
                GUI_Info.Max_GUI_UpdateCount := 5
              end;
          end;
        end;
    end;
    GUI_Info._840msTicks := 0;
  end;
end;

Is there anything obvious that is wrong in this code? It compiles but it clearly is not "thread-safe" from interrupts.

Thanks,
Jim
Last edited by JimKueneman on 23 May 2011 14:57, edited 1 time in total.

jpc
Posts: 1986
Joined: 22 Apr 2005 17:40
Location: France 87

Re: Address Traps.... again

#2 Post by jpc » 23 May 2011 10:47

Jim,

is there any chance that you are working with the same variables inside these ISR's ? This code at first sight looks ok to me but possibly things get messed by accessing the same data from both interrupt and main.
Au royaume des aveugles, les borgnes sont rois.

JimKueneman
Posts: 417
Joined: 10 Jan 2009 22:03

Re: Address Traps.... again

#3 Post by JimKueneman » 23 May 2011 14:56

Hi jpc,

Yes there is no doubt I do not call this from an interrupt. The GUI has always been "use the remaining time". It is a function in a separate unit that is call in the main program loop. The only thing in the GUI unit that gets called from an interrupt is the timer to update the screen. This is all done with a flag so there is no interaction:

Code: Select all

procedure GUI_840ms_TimeTick;
begin
  Inc(GUI_Info._840msTicks);
end;
Then at the beginning of the main state machine for the GUI I have this:

Code: Select all

  if GUI_Info._840msTicks >= GUI_Info.Max_GUI_UpdateCount then
  begin
     ....
    GUI_Info._840msTicks := 0;
  end;
I can think of no way this could cause my problems.

Jim

JimKueneman
Posts: 417
Joined: 10 Jan 2009 22:03

Re: Address Traps.... again

#4 Post by JimKueneman » 26 May 2011 03:35

Well I simply removed the functions and coded the exact function code into the main statemachine function "n" times and I can not get an Address Trap. Either there is something not right with the generated code that is not saving/restoring the state when and interrupt occurs or there is something wrong with my code. I need to move forward so I will live with the extra ram used by not having the functions.

Jim

User avatar
zristic
mikroElektronika team
Posts: 6608
Joined: 03 Aug 2004 12:59
Contact:

Re: Address Traps.... again

#5 Post by zristic » 06 Jul 2011 14:46

Jim, we might need the entire project so we can inspect where the trap occurs. If possible please share it with us (zristic at mikroe.com).
Thanks.

JimKueneman
Posts: 417
Joined: 10 Jan 2009 22:03

Re: Address Traps.... again

#6 Post by JimKueneman » 06 Jul 2011 15:48

Since this post I have found two bugs in parameter passing in the compiler. Once was suppose to have been fixed in version 5 (not verified yet)

http://www.mikroe.com/forum/viewtopic.php?f=106&t=31745

and one that was currently acknowledged and to be fixed:

http://www.mikroe.com/forum/viewtopic.php?f=106&t=35705

My money is on once both of these are fixed my problem will be gone as it felt like it was a problem passing the wrong address in the parameter problem. When I know that the second problem is fixed I will retry these functions.

Thanks,
Jim

Post Reply

Return to “mikroPascal PRO for dsPIC30/33 and PIC24 General”