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.