v7.1.0 - Exceptions when passing longint var param

Beta Testing discussion on mikroPascal PRO for dsPIC30/33 and PIC24.
Post Reply
Author
Message
VCC
Posts: 463
Joined: 08 Jun 2009 18:31
Location: Romania

v7.1.0 - Exceptions when passing longint var param

#1 Post by VCC » 14 Oct 2019 08:12

Hi,
it seems that passing longint parameter by reference is causing address exceptions when mixed with another longint parameter, which is passed by value. When both types are changed to integer, or both are passed by reference, no exception is generated.
See the OverideItem procedure and notice the Index parameter is passed by value. The procedure is called by the GoToNextVisibleItemFromIndex procedure, which passes a parameter by reference to that index.

MCU: PIC24EP512GU810
Board: mikroMedia for PIC24EP

See also attached project.

Code: Select all

program TestVarParam;

const
  CMaxLoggedTrapAddresses = 10;

type
  TLogAddress = record
    AAddress: DWord;
    Count: Word;
  end;

// TFT module connections
var TFT_DataPort : char  at LATE;
    TFT_RST : sbit  at LATC1_bit;
    TFT_BLED : sbit  at LATD2_bit;
    TFT_RS : sbit  at LATB15_bit;
    TFT_CS : sbit  at LATF12_bit;
    TFT_RD : sbit  at LATD5_bit;
    TFT_WR : sbit  at LATD4_bit;
    TFT_DataPort_Direction : char  at TRISE;
    TFT_RST_Direction : sbit  at TRISC1_bit;
    TFT_BLED_Direction : sbit  at TRISD2_bit;
    TFT_RS_Direction : sbit  at TRISB15_bit;
    TFT_CS_Direction : sbit  at TRISF12_bit;
    TFT_RD_Direction : sbit  at TRISD5_bit;
    TFT_WR_Direction : sbit  at TRISD4_bit;

// End TFT module connections

// Touch Panel module connections
var DriveX_Left : sbit at LATB13_bit;
var DriveX_Right : sbit at LATB11_bit;
var DriveY_Up : sbit at LATB12_bit;
var DriveY_Down : sbit at LATB10_bit;
var DriveX_Left_Direction : sbit at TRISB13_bit;
var DriveX_Right_Direction : sbit at TRISB11_bit;
var DriveY_Up_Direction : sbit at TRISB12_bit;
var DriveY_Down_Direction : sbit at TRISB10_bit;
// End Touch Panel module connections



  LCD_BLED: sbit at LATD.2;
  LCD_BLED_Direction: sbit at TRISD.2;
  BackLightPWMDuty: Word;
  
  Addr1_Base, Addr2_Base: Word;
  Addr1: Word at Addr1_Base; volatile; sfr;
  Addr2: Word at Addr2_Base; volatile; sfr;

  ADebugText: string[20];

  TrapAddresses: array[1..CMaxLoggedTrapAddresses] of TLogAddress;


procedure InitTrapAddresses;
var
  i: Integer;
begin
  for i := 1 to CMaxLoggedTrapAddresses do
  begin
    TrapAddresses[i].AAddress := $AAAAAAAA;
    TrapAddresses[i].Count := 0;
  end;
end;


function TrapAddressExistsInLog(AAddress: DWord): Integer;
var
  i: Integer;
  MaskedAddress: DWord;
begin
  Result := -1;
  MaskedAddress := AAddress and $00FFFFFF;

  for i := 1 to CMaxLoggedTrapAddresses do
    if TrapAddresses[i].AAddress and $00FFFFFF = MaskedAddress then
    begin
      Result := i;
      Exit;
    end;
end;


procedure PushTrapAddress;
var
  i, TrapAddressIndex: Integer;
  NewAddress: DWord;
begin
  NewAddress := (Addr1 shl 16) or Addr2;
  TrapAddressIndex := TrapAddressExistsInLog(NewAddress);
  if TrapAddressIndex > -1 then
  begin
    Inc(TrapAddresses[TrapAddressIndex].Count);
    Exit;
  end;

  for i := CMaxLoggedTrapAddresses downto 2 do
    TrapAddresses[i] := TrapAddresses[i - 1];

  Highest(TrapAddresses[1].AAddress) := Hi(Addr1);
  Higher(TrapAddresses[1].AAddress) := Lo(Addr1);
  Hi(TrapAddresses[1].AAddress) := Hi(Addr2);
  Lo(TrapAddresses[1].AAddress) := Lo(Addr2);
  TrapAddresses[1].Count := 1;
end;


procedure DisplayTrapAddresses;
var
  i: Word;
begin
  TFT_Set_Font(@TFT_defaultFont, CL_RED, FO_HORIZONTAL);
  TFT_Write_Text('TrapAddress    Count', 15, 0);

  TFT_Set_Brush(1, CL_WHITE, 0, 0, 0, 0);
  TFT_Rectangle(10, 20, 140, 220);

  TFT_Set_Pen(CL_BLUE, 1);

  for i := 1 to CMaxLoggedTrapAddresses do
  begin
    LongWordToHex(TrapAddresses[i].AAddress, ADebugText);
    TFT_Write_Text(ADebugText, 15, i * 20);
    
    WordToStr(TrapAddresses[i].Count, ADebugText);
    TFT_Write_Text(ADebugText, 110, i * 20);
  end;
end;


procedure AddressTrap; org 0x06; //if the addressing mode is wrong, the code jumps here  IVT_ADDR_ADDRESSERROR
begin
  INTCON1.3 := 0;

  asm
    MOV [w15-34], w13       //upper 8 bits of the address
    MOV w13, Addr1

    MOV [w15-32], w13       //lower 16 bits of the address
    MOV w13, Addr2
  end;

  PushTrapAddress;
  DisplayTrapAddresses;
end;


procedure Init_MCU;
begin
  // Setting output frequency to 140MHz
  PLLFBD := 68;            // PLL multiplier M=70
  CLKDIV := 0x0000;        // PLL prescaler N1=2, PLL postscaler N2=2

  ANSELA := 0x00;          // Convert all I/O pins to digital
  ANSELB := 0x00;
  ANSELC := 0x00;
  ANSELD := 0x00;
  ANSELE := 0x00;
  ANSELG := 0x00;
  //Mmc_Chip_Select_Direction := 0;
  LCD_BLED_Direction := 0;  //RP66
  BackLightPWMDuty := $FFFF;

  Addr1 := 0;
  Addr2 := 0;

  PPS_Mapping(67, _INPUT,  _U1RX);              // Sets pin RP98 to be Input, and maps U1RX to it
  PPS_Mapping(65, _OUTPUT, _U1TX);              // Sets pin RP104 to be Output, and maps U1TX to it

  PPS_Mapping(66, _OUTPUT, _OC1);

  Delay_ms(150);
  TFT_Set_Default_Mode;

  InitTrapAddresses;
end;


procedure InitPWMOnOC;
begin
  OC1CON1.OCSIDL := 0; //0 = Output Compare x continues to operate in CPU Idle mode
  OC1CON1.OCTSEL_2 := 1; //111 = Peripheral clock (FCY)
  OC1CON1.OCTSEL_1 := 1;
  OC1CON1.OCTSEL_0 := 1;
  OC1CON1.ENFLTC := 0; //0 = Fault inputs are disabled
  OC1CON1.ENFLTB := 0; //0 = Fault inputs are disabled
  OC1CON1.ENFLTA := 0; //0 = Fault inputs are disabled
  OC1CON1.OCFLTC := 0; //0 = PWM Fault condition has not occurred
  OC1CON1.OCFLTB := 0; //0 = PWM Fault condition has not occurred
  OC1CON1.OCFLTA := 0; //0 = PWM Fault condition has not occurred
  OC1CON1.TRIGMODE := 0; //0 = TRIGSTAT (OCxCON2<6>) bit is cleared only by software
  OC1CON1.OCM_2 := 1;  //110 = Edge-Aligned PWM mode: Output is set high when OCxTMR = 0 and is set low when OCxTMR = OCxR
  OC1CON1.OCM_1 := 1;
  OC1CON1.OCM_0 := 0;

  OC1CON2.FLTMD := 0; //0 = Fault mode is maintained until the Fault source is removed and a new PWM period starts
  OC1CON2.FLTOUT := 1; //1 = PWM output is driven high on a Fault
  OC1CON2.FLTTRIEN := 1; //1 = OCx pin is tri-stated on a Fault condition
  OC1CON2.OCINV := 0; //0 = OCx output is not inverted
  //OC1CON2.11 to 9 are not implemented
  OC1CON2.OC32 := 0;  //0 = Cascade module operation is disabled
  OC1CON2.OCTRIG := 0;  //0 = Synchronizes OCx with source designated by SYNCSELx bits
  OC1CON2.TRIGSTAT := 1;  //1 = Timer source has been triggered and is running
  OC1CON2.OCTRIS := 0; //0 = Output compare module drives the OCx pin
  {OC1CON2.SYNCSEL_4 := 0; //01100 = Timer2 synchronizes or triggers OCx (default)
  OC1CON2.SYNCSEL_3 := 1;
  OC1CON2.SYNCSEL_2 := 1;
  OC1CON2.SYNCSEL_1 := 0;
  OC1CON2.SYNCSEL_0 := 0;}
  OC1CON2.SYNCSEL_4 := 1; //11111 = free running
  OC1CON2.SYNCSEL_3 := 1;
  OC1CON2.SYNCSEL_2 := 1;
  OC1CON2.SYNCSEL_1 := 1;
  OC1CON2.SYNCSEL_0 := 1;

  OC1R := $FFFF;
  OC1RS := $FFFF;  //set to max   The OCxRS register can be made to determine the period by setting the SYNCSEL<4:0> bits (OCxCON2<4:0>) = 0x1F
end;


procedure DisplayBackLightValue;
var
  LocalText: string[20];
begin
  TFT_Set_Pen(CL_WHITE, 1);
  TFT_Set_Brush(1, CL_WHITE, 0, 0, 0, 0);
  TFT_Rectangle(0, 20, 100, 40);

  LongWordToHex(BackLightPWMDuty, LocalText);
  TFT_Write_Text(LocalText, 10, 20);
end;


//////////////////////////////

type
  NewLongInt = LongInt; //Integer; //LongInt;    <-------------------  Changing to integer, does not cause exceptions
  TDummyStructure = record
    SafeCount: NewLongInt;
  end;
  PDummyStructure = ^TDummyStructure;

//when Index is passed by reference, no exception is generated.
procedure OverideItem(AFirstParam: PDummyStructure; {var} Index: NewLongInt; var ItemText: string{[20]}; var IsVisible: Boolean);
begin
  LongWordToHex(Index, ItemText);
  IsVisible := Index > 3;
end;


procedure GoToNextVisibleItemFromIndex(AFirstParam: PDummyStructure; var IndexOfDrawingItem: NewLongInt; var ItemText: string{[20]}; var IsVisible: Boolean);
begin
  repeat
    IsVisible := True;
    OverideItem(AFirstParam, IndexOfDrawingItem, ItemText, IsVisible);

    Inc(IndexOfDrawingItem);
  until IsVisible or (IndexOfDrawingItem >= AFirstParam^.SafeCount);
end;


procedure DisplayItems;
var
  i: NewLongInt;
  IndexOfDrawingItem: NewLongInt;
  ADummyStructure: TDummyStructure;
  ItemText: string[20];
  IsVisible: Boolean;
  LocalText: string[20];
begin
  ADummyStructure.SafeCount := 8;
  IndexOfDrawingItem := 0;
  IsVisible := False;
  
  for i := 0 to 8 do
  begin
    GoToNextVisibleItemFromIndex(@ADummyStructure, IndexOfDrawingItem, ItemText, IsVisible);
    
    LongintToStr(i, LocalText);
    TFT_Set_Font(@TFT_defaultFont, CL_BLUE, FO_HORIZONTAL);
    TFT_Write_Text(LocalText, 150, 40 + i * 20);
    
    TFT_Set_Font(@TFT_defaultFont, CL_GREEN, FO_HORIZONTAL);
    LongintToStr(IndexOfDrawingItem, LocalText);
    TFT_Write_Text(LocalText, 200, 40 + i * 20);
    
    TFT_Set_Font(@TFT_defaultFont, CL_OLIVE, FO_HORIZONTAL);
    ByteToHex(Lo(IsVisible), LocalText);
    TFT_Write_Text(LocalText, 270, 40 + i * 20);
    
    Delay_ms(100);
  end;
end;


begin
  Delay_ms(100);
  Init_MCU();
  InitPWMOnOC;

  BackLightPWMDuty := 2; //max 15 for full backlight
  
  TFT_Init_ILI9341_8bit(320, 240);
  TFT_Set_Pen(CL_WHITE, 1);
  TFT_Set_Brush(1, CL_WHITE, 0, 0, 0, 0);
  TFT_Rectangle(0, 0, 320, 240);

  TFT_Set_Pen(CL_WHITE, 1);
  TFT_Set_Font(@TFT_defaultFont, CL_MAROON, FO_HORIZONTAL);
  TFT_Write_Text('Test data', 200, 0);
  
  DisplayBackLightValue;

  OC1R := BackLightPWMDuty shl 12;
  OC1R := OC1R or $0FFF;
  
  DisplayItems;

  repeat

    OC1R := BackLightPWMDuty shl 12;
    OC1R := OC1R or $0FFF;

  until False;

end.
Thank you :|
Attachments
Exceptions.png
Exceptions.png (535.72 KiB) Viewed 2461 times
ExpectedData.png
ExpectedData.png (492.46 KiB) Viewed 2461 times
TestVarParam.zip
Project
(82.82 KiB) Downloaded 78 times

User avatar
stefan.filipovic
mikroElektronika team
Posts: 1135
Joined: 18 Dec 2018 10:30

Re: v7.1.0 - Exceptions when passing longint var param

#2 Post by stefan.filipovic » 22 Nov 2019 14:10

Hi,

I've tested this, and I have not managed to reproduce this issue in passing the long int parameter by reference.
Could you please check and test the project from the attachment?

Kind regards,
Attachments
TestVarParam.zip
(200.62 KiB) Downloaded 83 times
Stefan Filipović

VCC
Posts: 463
Joined: 08 Jun 2009 18:31
Location: Romania

Re: v7.1.0 - Exceptions when passing longint var param

#3 Post by VCC » 02 Dec 2019 13:36

Hi,
it's interesting that you can't reproduce the issue. I retested it again and reproduced it again.
The project you attached has all involved parameters, passed by reference (because they are pointers), so no issue with that. That works as expected. I am already using that workaround.
As I mentioned in the original post, the issue appears when mixing the two types of passing, by value and by reference, for LongInt only.

If you program the board with the hex file I provided, can you see on the screen the table with exception addresses, from posted Exceptions.png?

User avatar
stefan.filipovic
mikroElektronika team
Posts: 1135
Joined: 18 Dec 2018 10:30

Re: v7.1.0 - Exceptions when passing longint var param

#4 Post by stefan.filipovic » 03 Dec 2019 14:38

Hi,

OK, I've reproduced this issue with the hex file from your project. It seems that you need to add var keyword for the Index parameter in the OverideItem procedure.

Code: Select all

procedure OverideItem(AFirstParam: PDummyStructure; var Index: NewLongInt; var ItemText: string{[20]}; var IsVisible: Boolean);
begin
  LongIntToHex(Index, ItemText);
  IsVisible := Index > 3;
end;
Please check the project from the attachment.

Kind regards,
Attachments
TestVarParam.zip
(200.64 KiB) Downloaded 80 times
Stefan Filipović

VCC
Posts: 463
Joined: 08 Jun 2009 18:31
Location: Romania

Re: v7.1.0 - Exceptions when passing longint var param

#5 Post by VCC » 04 Dec 2019 07:31

stefan.filipovic wrote:Hi,

OK, I've reproduced this issue with the hex file from your project. It seems that you need to add var keyword for the Index parameter in the OverideItem procedure.

Code: Select all

procedure OverideItem(AFirstParam: PDummyStructure; var Index: NewLongInt; var ItemText: string{[20]}; var IsVisible: Boolean);
begin
 LongIntToHex(Index, ItemText);
 IsVisible := Index > 3;
end;
Please check the project from the attachment.

Kind regards,
Adding the var keyword is the right way to do it but.. The compiler should properly dereference the Index parameter, when calling the OverrideItem procedure from GoToNextVisibleItemFromIndex, if it's passed by value, mixed with passing by reference, as in original post. Either no dereference is being done, or it is done, but it is faulty.
If it's too hard to fix this, it would be nice at least to have a warning here, saying that mixing the two types of passing, is not supported.

Thank you.

User avatar
stefan.filipovic
mikroElektronika team
Posts: 1135
Joined: 18 Dec 2018 10:30

Re: v7.1.0 - Exceptions when passing longint var param

#6 Post by stefan.filipovic » 04 Dec 2019 11:00

Hi,

I will forward this to our developers.

I apologize for the inconvenience.

Kind regards,
Stefan Filipović

VCC
Posts: 463
Joined: 08 Jun 2009 18:31
Location: Romania

Re: v7.1.0 - Exceptions when passing longint var param

#7 Post by VCC » 05 Dec 2019 15:21

Thank you :)

Post Reply

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