unit PIC32MX_CAN; // ****************************************************************************** // // * Copyright: // (c) Mustangpeak Software 2012. // // The contents of this file are subject to the GNU GPL v3 licence/ you maynot use // this file except in compliance with the License. You may obtain a copy of the // License at http://www.gnu.org/licenses/gpl.html // // * Revision History: // 2012-04-01: 1.0.0.0 Created // 2012-10-07: Version 1.0 // // * Description: // Implements an easy to use interface into the dsPIC33 ECAN Module Registers // It is fast, no. Is it efficient, no. Is it easy to experiment with to try to // understand how this module works, YES // // ****************************************************************************** {$I Options.inc} {$DEFINE PRINT_CAN_REGISTERS} {.$DEFINE TRACE_CAN} {.$DEFINE TRACE_INTERRUPTS} {$DEFINE TRACE_INTERRUPTS_OVERFLOW} uses helperfunctions, opstackdefines, PIC32MX_CAN_RawBuffers; const ICODE_INVALID_MESSAGE = $48; // (IVRIF} ICODE_MODULE_MODE_CHANGE = $47; // (MODIF} ICODE_TIMESTAMP_TIMER = $46; // (CTMRIF) ICODE_BUS_BANDWIDTH_ERROR = $45; // (SERRIF) ICODE_ADDRESS_ERROR = $44; // (SERRIF) ICODE_RX_OVERFLOW = $43; // (RBOVIF) ICODE_WAKEUP = $42; // (WAKIF) ICODE_ERROR = $41; // (CERRIF) ICODE_NO_INTERRUPT = $40; ICODE_FIFO0 = 0; ICODE_FIFO1 = 1; ICODE_FIFO2 = 2; ICODE_FIFO3 = 3; ICODE_FIFO4 = 4; ICODE_FIFO5 = 5; ICODE_FIFO6 = 6; ICODE_FIFO7 = 7; ICODE_FIFO8 = 8; ICODE_FIFO9 = 9; ICODE_FIFO10 = 10; ICODE_FIFO11 = 11; ICODE_FIFO12 = 12; ICODE_FIFO13 = 13; ICODE_FIFO14 = 14; ICODE_FIFO15 = 15; ICODE_FIFO16 = 16; ICODE_FIFO17 = 17; ICODE_FIFO18 = 18; ICODE_FIFO19 = 19; ICODE_FIFO20 = 20; ICODE_FIFO21 = 21; ICODE_FIFO22 = 22; ICODE_FIFO23 = 23; ICODE_FIFO24 = 24; ICODE_FIFO25 = 25; ICODE_FIFO26 = 26; ICODE_FIFO27 = 27; ICODE_FIFO28 = 28; ICODE_FIFO29 = 29; ICODE_FIFO30 = 30; ICODE_FIFO31 = 31; {$IFDEF PRINT_CAN_REGISTERS} procedure PIC32MX_CAN_PrintRegisters(Channel: Byte); {$ENDIF} procedure PIC32MX_CAN_Initialize; procedure PIC32MX_StartTransmission(Buffer: PNMRAnetCanBuffer; IsExtended: Boolean); procedure PIC32MX_StartCANHighPriorityMessageEngine(Buffer: PNMRAnetCanBuffer; IsExtended: Boolean); // ***************************************************************************** // Initialization Functions // ***************************************************************************** procedure PIC32MX_CAN_Enable(Channel: Byte; Enable: Boolean); procedure PIC32MX_CAN_EnterConfigMode(Channel: Byte); procedure PIC32MX_CAN_EnterNormalMode(Channel: Byte); procedure PIC32MX_CAN_AbortPendingTransmissions(Channel: Byte); procedure PIC32MX_CAN_SetBaud(Channel: Byte; SJW, BRP, SEG2PH, SEG1PH, PRSEG: DWord; Sample3Times: Boolean); procedure PIC32MX_CAN_RequestTransmit(Channel, FIFONumber: Byte); // ***************************************************************************** // ***************************************************************************** // Receive Filter and Mask Functions // ***************************************************************************** // Filter Creation procedure PIC32MX_CAN_EnableRXFilters(Channel: Byte; FilterNumber: Byte; Enable: Boolean); procedure PIC32MX_CAN_SetFilter(Channel: Byte; FilterNumber: Byte; Filter: DWord; ExtendedOnly: Boolean); // Mask Creation procedure PIC32MX_CAN_SetMask(Channel: Byte; MaskNumber: Byte; Mask: DWord; ExtendedOnly: Boolean); // Filter to Mask Assignments procedure PIC32MX_CAN_AssociateFilterAndMaskAndFIFO(Channel: Byte; FilterNumber, MaskNumber: Word; FIFO: Byte); // ***************************************************************************** // ***************************************************************************** // FIFO Functions // ***************************************************************************** // FIFO Assignment procedure PIC32MX_CAN_SetFIFO(Channel: Byte; FIFONumber: Byte; Size: Byte; IsTransmitter: Boolean; TxPriority: Byte); // Assign a memory area to the FIFO buffers procedure PIC32MX_CAN_SetFIFOBaseAddress(Channel: Byte; FIFOBufferAddress: ^DWord); // function PIC32MX_CAN_FIFO_IsTransmiter(Channel: Byte; FIFONumber: Byte): Boolean; // ***************************************************************************** // ***************************************************************************** // Interrupt Functions // ***************************************************************************** function PIC32MX_CAN_InterruptCode(Channel: Byte): Byte; // Low level FIFO Tx Interrupt options, these flags are not clearable, the condition that caused them must be cleared procedure PIC32MX_CAN_Tx_Interrupt_NotFull_Enable(Channel, FIFONumber: Byte; DoEnable: Boolean); procedure PIC32MX_CAN_Tx_Interrupt_HalfFull_Enable(Channel, FIFONumber: Byte; DoEnable: Boolean); procedure PIC32MX_CAN_Tx_Interrupt_Empty_Enable(Channel, FIFONumber: Byte; DoEnable: Boolean); function PIC32MX_CAN_Tx_Interrupt_NotFull_FlagSet(Channel, FIFONumber: Byte): Boolean; function PIC32MX_CAN_Tx_Interrupt_HalfFull_FlagSet(Channel, FIFONumber: Byte): Boolean; function PIC32MX_CAN_Tx_Interrupt_Empty_FlagSet(Channel, FIFONumber: Byte): Boolean; // Low level FIFO Rx Interrupt options, these flags are not clearable, the condition that caused them must be cleared procedure PIC32MX_CAN_Rx_Interrupt_Overflow_Enable(Channel, FIFONumber: Byte; DoEnable: Boolean); procedure PIC32MX_CAN_Rx_Interrupt_Full_Enable(Channel, FIFONumber: Byte; DoEnable: Boolean); procedure PIC32MX_CAN_Rx_Interrupt_HalfFull_Enable(Channel, FIFONumber: Byte; DoEnable: Boolean); procedure PIC32MX_CAN_Rx_Interrupt_NotEmpty_Enable(Channel, FIFONumber: Byte; DoEnable: Boolean); function PIC32MX_CAN_Rx_Interrupt_Overflow_FlagSet(Channel, FIFONumber: Byte): Boolean; function PIC32MX_CAN_Rx_Interrupt_Full_FlagSet(Channel, FIFONumber: Byte): Boolean; function PIC32MX_CAN_Rx_Interrupt_HalfFull_FlagSet(Channel, FIFONumber: Byte): Boolean; function PIC32MX_CAN_Rx_Interrupt_NotEmpty_FlagSet(Channel, FIFONumber: Byte): Boolean; // Low level Rx Overflow Interrupt Options, these flags are not clearable, the next level up (module) is cleared that covers multiple FIFOs function PIC32MX_CAN_InterruptRxOverflowFIFOAny(Channel: Byte; DoClear: Boolean): Boolean; // Test the all at once function PIC32MX_CAN_InterruptRxOverflowFIFO(Channel: Byte; FIFONumber: Byte; DoClear: Boolean): Boolean; // CAN Module level Interrupt options, , these flags are clearable, the next level down (FIFO) is is not these are the superset of the FIFOs procedure PIC32MX_CAN_EnableInterrupts(Channel: Byte; InvalidMessage, WakeOnBus, CanBusError, SystemError, RxBufferOverflow, ModeChange, TimestampTimer, RxBuffer, TxBuffer: Boolean); function PIC32MX_CAN_InterruptValidMessageFlag(Channel: Byte; DoClear: Boolean): Boolean; function PIC32MX_CAN_InterruptWakeOnBusFlag(Channel: Byte; DoClear: Boolean): Boolean; function PIC32MX_CAN_InterruptBusErrorFlag(Channel: Byte; DoClear: Boolean): Boolean; function PIC32MX_CAN_InterruptSystemErrorFlag(Channel: Byte; DoClear: Boolean): Boolean; function PIC32MX_CAN_InterruptRxBufferOverflowFlag(Channel: Byte; DoClear: Boolean): Boolean; function PIC32MX_CAN_InterruptModeChangeFlag(Channel: Byte; DoClear: Boolean): Boolean; function PIC32MX_CAN_InterruptTimestampTimerFlag(Channel: Byte; DoClear: Boolean): Boolean; function PIC32MX_CAN_InterruptRxBufferFlag(Channel: Byte; DoClear: Boolean): Boolean; function PIC32MX_CAN_InterruptTxBufferFlag(Channel: Byte; DoClear: Boolean): Boolean; // CPU level Interrupt options procedure PIC32MX_CAN_GlobalInterrupt(Channel: byte; Enable: Boolean); function PIC32MX_CAN_GlobalInterruptFlag(Channel: byte; DoReset: Boolean): Boolean; procedure PIC32MX_CAN_GlobalInterrupt_EventPriority(Channel, Priority, SubPriority: Byte); // ***************************************************************************** // ***************************************************************************** // FIFO State Functions // ***************************************************************************** function PIC32MX_CAN_Next_Buffer_Address(Channel: Byte; FIFONumber: Byte): PCANRawBuffer; function PIC32MX_CAN_Next_Buffer_Index(Channel: Byte; FIFONumber: Byte): Byte; procedure PIC32MX_CAN_Inc_Buffer_Index(Channel: Byte; FIFONumber: Byte); // ***************************************************************************** procedure ReceivedOnFilter0(Buffer: PNMRAnetCanBuffer); external; procedure ReceivedOnFilter1(Buffer: PNMRAnetCanBuffer); external; procedure ReceivedOnFilter2(Buffer: PNMRAnetCanBuffer); external; procedure ReceivedOnFilter3(Buffer: PNMRAnetCanBuffer); external; procedure ReceivedOnFilter4(Buffer: PNMRAnetCanBuffer); external; procedure ReceivedOnFilter5(Buffer: PNMRAnetCanBuffer); external; procedure ReceivedOnFilter6(Buffer: PNMRAnetCanBuffer); external; var PIC32MX_CAN_Transmitting, PIC32MX_CAN_HighPriorityTransmitting: Boolean; var LocalCAN_Channel: Byte; external; implementation procedure PIC32MX_DMA_Style_Buffer(var Buffer: TNMRAnetCanBuffer; var IsExtended: Boolean; Direction: Byte; CANPtr: ^Byte); forward; type PByte = ^Byte; {$IFDEF PRINT_CAN_REGISTERS} procedure PIC32MX_CAN_PrintRegisters(Channel: Byte); var i: Integer; Ptr: ^DWord; s2: string[6]; begin case Channel of 1 : begin UART2_Write_Text('Interrupt and Status Registers' + LF); LongWordToHex(C1CON, s1); UART2_Write_Text('C1CON: 0x' + s1 + LF); LongWordToHex(C1CFG, s1); UART2_Write_Text('C1CFG: 0x' + s1 + LF); LongWordToHex(C1INT, s1); UART2_Write_Text('C1INT: 0x' + s1 + LF); LongWordToHex(C1VEC, s1); UART2_Write_Text('C1VEC: 0x' + s1 + LF); LongWordToHex(C1TREC, s1); UART2_Write_Text('C1TREC: 0x' + s1 + LF); LongWordToHex(C1FSTAT, s1); UART2_Write_Text('C1FSTAT: 0x' + s1 + LF); LongWordToHex(C1RXOVF, s1); UART2_Write_Text('C1RXOVF: 0x' + s1 + LF); LongWordToHex(C1TMR, s1); UART2_Write_Text('C1TMR: 0x' + s1 + LF); UART2_Write_Text('Mask and Filter Configuration Registers' + LF); LongWordToHex(C1RXM0, s1); UART2_Write_Text('C1RXM0: 0x' + s1 + LF); LongWordToHex(C1RXM1, s1); UART2_Write_Text('C1RXM1: 0x' + s1 + LF); LongWordToHex(C1RXM2, s1); UART2_Write_Text('C1RXM2: 0x' + s1 + LF); LongWordToHex(C1RXM3, s1); UART2_Write_Text('C1RXM3: 0x' + s1 + LF); Ptr := @C1FLTCON0; for i := 0 to 7 do begin LongWordToHex(Ptr^, s1); IntToStr(i, s2); UART2_Write_Text(s2 + ' C1FLTCONn: 0x' + s1 + LF); Ptr := Ptr + 4 end; Ptr := @C1RXF0; for i := 0 to 31 do begin LongWordToHex(Ptr^, s1); IntToStr(i, s2); UART2_Write_Text(s2 + ' C1RXFn: 0x' + s1 + LF); Ptr := Ptr + 4 end; UART2_Write_Text('CAN Module Control Registers' + LF); LongWordToHex(C1FIFOBA, s1); UART2_Write_Text('C1FIFOBA: 0x' + s1 + LF); Ptr := @C1FIFOCON0; for i := 0 to 31 do begin LongWordToHex(Ptr^, s1); IntToStr(i, s2); UART2_Write_Text(s2 + ' C1FIFOCONn: 0x' + s1 + LF); Ptr := Ptr + 16 end; Ptr := @C1FIFOINT0; for i := 0 to 31 do begin LongWordToHex(Ptr^, s1); IntToStr(i, s2); UART2_Write_Text(s2 + ' C1FIFOINTn: 0x' + s1 + LF); Ptr := Ptr + 16 end; Ptr := @C1FIFOUA0; for i := 0 to 31 do begin LongWordToHex(Ptr^, s1); IntToStr(i, s2); UART2_Write_Text(s2 + ' C1FIFOUAn: 0x' + s1 + LF); Ptr := Ptr + 16 end; Ptr := @C1FIFOCI0; for i := 0 to 31 do begin LongWordToHex(Ptr^, s1); IntToStr(i, s2); UART2_Write_Text(s2 + ' C1FIFOCIn: 0x' + s1 + LF); Ptr := Ptr + 16 end; if CAN1IE_bit = 1 then UART2_Write_Text('CAN1IE_bit = 1'+ LF) else UART2_Write_Text('CAN1IE_bit = 0'+ LF); if CAN1IF_bit = 1 then UART2_Write_Text('CAN1IF_bit = 1'+ LF) else UART2_Write_Text('CAN1IF_bit = 0'+ LF); UART2_Write_Text('CAN1 Priority: '); if CAN1IP2_bit = 1 then UART2_Write_Text('1') else UART2_Write_Text('0'); if CAN1IP1_bit = 1 then UART2_Write_Text('1') else UART2_Write_Text('0'); if CAN1IP0_bit = 1 then UART2_Write_Text('1') else UART2_Write_Text('0'); UART2_Write_Text(LF); UART2_Write_Text('CAN1 SubPriority: '); if CAN1IS1_bit = 1 then UART2_Write_Text('1') else UART2_Write_Text('0'); if CAN1IS0_bit = 1 then UART2_Write_Text('1') else UART2_Write_Text('0'); UART2_Write_Text(LF); end; 2 : begin UART2_Write_Text('Interrupt and Status Registers' + LF); LongWordToHex(C2CON, s1); UART2_Write_Text('C2CON: 0x' + s1 + LF); LongWordToHex(C2CFG, s1); UART2_Write_Text('C2CFG: 0x' + s1 + LF); LongWordToHex(C2INT, s1); UART2_Write_Text('C2INT: 0x' + s1 + LF); LongWordToHex(C2VEC, s1); UART2_Write_Text('C2VEC: 0x' + s1 + LF); LongWordToHex(C2TREC, s1); UART2_Write_Text('C2TREC: 0x' + s1 + LF); LongWordToHex(C2FSTAT, s1); UART2_Write_Text('C2FSTAT: 0x' + s1 + LF); LongWordToHex(C2RXOVF, s1); UART2_Write_Text('C2RXOVF: 0x' + s1 + LF); LongWordToHex(C2TMR, s1); UART2_Write_Text('C2TMR: 0x' + s1 + LF); UART2_Write_Text('Mask and Filter Configuration Registers' + LF); LongWordToHex(C2RXM0, s1); UART2_Write_Text('C2RXM0: 0x' + s1 + LF); LongWordToHex(C2RXM1, s1); UART2_Write_Text('C2RXM1: 0x' + s1 + LF); LongWordToHex(C2RXM2, s1); UART2_Write_Text('C2RXM2: 0x' + s1 + LF); LongWordToHex(C2RXM3, s1); UART2_Write_Text('C2RXM3: 0x' + s1 + LF); Ptr := @C2FLTCON0; for i := 0 to 7 do begin LongWordToHex(Ptr^, s1); IntToStr(i, s2); UART2_Write_Text(s2 + ' C2FLTCONn: 0x' + s1 + LF); Ptr := Ptr + 4 end; Ptr := @C2RXF0; for i := 0 to 31 do begin LongWordToHex(Ptr^, s1); IntToStr(i, s2); UART2_Write_Text(s2 + ' C2RXFn: 0x' + s1 + LF); Ptr := Ptr + 4 end; UART2_Write_Text('CAN Module Control Registers' + LF); LongWordToHex(C2FIFOBA, s1); UART2_Write_Text('C2FIFOBA: 0x' + s1 + LF); Ptr := @C2FIFOCON0; for i := 0 to 31 do begin LongWordToHex(Ptr^, s1); IntToStr(i, s2); UART2_Write_Text(s2 + ' C2FIFOCONn: 0x' + s1 + LF); Ptr := Ptr + 16 end; Ptr := @C2FIFOINT0; for i := 0 to 31 do begin LongWordToHex(Ptr^, s1); IntToStr(i, s2); UART2_Write_Text(s2 + ' C1FIFOINTn: 0x' + s1 + LF); Ptr := Ptr + 16 end; Ptr := @C2FIFOUA0; for i := 0 to 31 do begin LongWordToHex(Ptr^, s1); IntToStr(i, s2); UART2_Write_Text(s2 + ' C2FIFOUAn: 0x' + s1 + LF); Ptr := Ptr + 16 end; Ptr := @C2FIFOCI0; for i := 0 to 31 do begin LongWordToHex(Ptr^, s1); IntToStr(i, s2); UART2_Write_Text(s2 + ' C2FIFOCIn: 0x' + s1 + LF); Ptr := Ptr + 16 end; if CAN2IE_bit = 1 then UART2_Write_Text('CAN2IE_bit = 1'+ LF) else UART2_Write_Text('CAN2IE_bit = 0'+ LF); if CAN2IF_bit = 1 then UART2_Write_Text('CAN2IF_bit = 1'+ LF) else UART2_Write_Text('CAN2IF_bit = 0'+ LF); UART2_Write_Text('CAN2 Priority: '); if CAN2IP2_bit = 1 then UART2_Write_Text('1') else UART2_Write_Text('0'); if CAN2IP1_bit = 1 then UART2_Write_Text('1') else UART2_Write_Text('0'); if CAN2IP0_bit = 1 then UART2_Write_Text('1') else UART2_Write_Text('0'); UART2_Write_Text(LF); UART2_Write_Text('CAN2 SubPriority: '); if CAN2IS1_bit = 1 then UART2_Write_Text('1') else UART2_Write_Text('0'); if CAN2IS0_bit = 1 then UART2_Write_Text('1') else UART2_Write_Text('0'); UART2_Write_Text(LF); end; end; end; {$ENDIF} // **************************************************************************** // function PIC32MX_StartTransmission: Boolean; // // Starts the transmission if there are no current transmits in procress // // **************************************************************************** procedure PIC32MX_StartTransmission(Buffer: PNMRAnetCanBuffer; IsExtended: Boolean); var Next: PCANRawBuffer; begin if Buffer <> nil then // If there is something to send then send it begin {$IFDEF TRACE_INTERRUPTS}UART2_Write_Text('PIC32MX_StartTransmission' +LF); {$ENDIF} PIC32MX_CAN_Transmitting := True; Next := Map_Physical_To_KSEG0( PIC32MX_CAN_Next_Buffer_Address(LocalCAN_Channel, FIFO_TX_LO_PRIORITY)); // Get where the next buffer to transmit is PIC32MX_DMA_Style_Buffer(Buffer^, IsExtended, CAN_DIRECTION_WRITE, Next); // Convert it into a version that matches the registers PIC32MX_CAN_Inc_Buffer_Index(LocalCAN_Channel, FIFO_TX_LO_PRIORITY); // Message is loaded move to the next one PIC32MX_CAN_Tx_Interrupt_Empty_Enable(LocalCAN_Channel, FIFO_TX_LO_PRIORITY, True); // Fire the interrupt when the buffer is empty PIC32MX_CAN_RequestTransmit(LocalCAN_Channel, FIFO_TX_LO_PRIORITY); // Set the Flag to start the transmission end end; // **************************************************************************** // procedure PIC32MX_StartCANHighPriorityMessageEngine; // // Starts the transmitter engine if there are no current transmits in procress // // THIS MUST ONLY BE CALLED IN THE CAN RECEIVE INTERRUPT >>>>>>>>>>>>> // // **************************************************************************** procedure PIC32MX_StartCANHighPriorityMessageEngine(Buffer: PNMRAnetCanBuffer; IsExtended: Boolean); var Next: PCANRawBuffer; begin if Buffer <> nil then // If there is something to send then send it begin {$IFDEF TRACE_INTERRUPTS}UART2_Write_Text('PIC32MX_StartCANHighPriorityMessageEngine' +LF); {$ENDIF} PIC32MX_CAN_Transmitting := True; Next := Map_Physical_To_KSEG0( PIC32MX_CAN_Next_Buffer_Address(LocalCAN_Channel, FIFO_TX_HI_PRIORITY)); // Get where the next buffer to transmit is PIC32MX_DMA_Style_Buffer(Buffer^, IsExtended, CAN_DIRECTION_WRITE, Next); // Convert it into a version that matches the registers PIC32MX_CAN_Inc_Buffer_Index(LocalCAN_Channel, FIFO_TX_HI_PRIORITY); // Message is loaded move to the next one PIC32MX_CAN_Tx_Interrupt_Empty_Enable(LocalCAN_Channel, FIFO_TX_HI_PRIORITY, True); // Fire the interrupt when the buffer is empty PIC32MX_CAN_RequestTransmit(LocalCAN_Channel, FIFO_TX_HI_PRIORITY); // Set the Flag to start the transmission end end; procedure CAN_2(); iv IVT_CAN_2; //ics ICS_SOFT; var IntCode: Word; Buffer: TNMRAnetCanBuffer; IsExtended: Boolean; Next: PCANRawBuffer; begin PIC32MX_CAN_GlobalInterruptFlag(LocalCAN_Channel, True); // Reset the Global CAN Event Interrupt Flag IntCode := PIC32MX_CAN_InterruptCode(LocalCAN_Channel); while IntCode <> ICODE_NO_INTERRUPT do // Use the Interrupt Code to decode the Events that are both Enabled and Flags are set begin case IntCode of ICODE_FIFO0 : // Tx Rx Buffer 0 begin {$IFDEF TRACE_INTERRUPTS}UART2_Write_Text('TX0' +LF);{$ENDIF} PIC32MX_CAN_Tx_Interrupt_Empty_Enable(LocalCAN_Channel, 0, False); PIC32MX_CAN_Transmitting := False; end; ICODE_FIFO1 : // Tx Rx Buffer 0 begin {$IFDEF TRACE_INTERRUPTS}UART2_Write_Text('TX1' +LF);{$ENDIF} PIC32MX_CAN_Tx_Interrupt_Empty_Enable(LocalCAN_Channel, 1, False); PIC32MX_CAN_HighPriorityTransmitting := False; end; ICODE_FIFO2 : // Tx Rx Buffer 0 begin {$IFDEF TRACE_INTERRUPTS}UART2_Write_Text('RX0' +LF); {$ENDIF} IsExtended := True; Next := Map_Physical_To_KSEG0( PIC32MX_CAN_Next_Buffer_Address(LocalCAN_Channel, FIFO_RX_FIFO_CAN)); PIC32MX_DMA_Style_Buffer(Buffer, IsExtended, CAN_DIRECTION_READ, Next); // Convert it into a version that matches the registers PIC32MX_CAN_Inc_Buffer_Index(LocalCAN_Channel, FIFO_RX_FIFO_CAN); ReceivedOnFilter1(@Buffer); end; ICODE_FIFO3 : // Tx Rx Buffer 0 begin {$IFDEF TRACE_INTERRUPTS}UART2_Write_Text('RX1' +LF); {$ENDIF} IsExtended := True; Next := Map_Physical_To_KSEG0( PIC32MX_CAN_Next_Buffer_Address(LocalCAN_Channel, FIFO_RX_FIFO_OLCB)); PIC32MX_DMA_Style_Buffer(Buffer, IsExtended, CAN_DIRECTION_READ, Next); // Convert it into a version that matches the registers PIC32MX_CAN_Inc_Buffer_Index(LocalCAN_Channel, FIFO_RX_FIFO_OLCB); ReceivedOnFilter0(@Buffer); end; ICODE_RX_OVERFLOW : begin {$IFDEF TRACE_INTERRUPTS_OVERFLOW}UART2_Write_Text('RxOVR'+LF);{$ENDIF} PIC32MX_CAN_InterruptRxOverflowFIFOAny(LocalCAN_Channel, True); // Clear them all end else begin {$IFDEF TRACE_INTERRUPTS}UART2_Write_Text('9' +LF);{$ENDIF} end; end; // case IntCode := PIC32MX_CAN_InterruptCode(LocalCAN_Channel); // Get the next code (or no code) flag end; end; procedure PIC32MX_CAN_Initialize; var i: Integer; begin PIC32MX_CAN_Transmitting := False; PIC32MX_CAN_HighPriorityTransmitting := False; for i := 0 to FIFO_BUFFER_TOTAL - 1 do begin FIFOBufferArray[i].Byte0 := 0; // Allow the compiler to account for this ram FIFOBufferArray[i].Byte1 := 0; FIFOBufferArray[i].Byte2 := 0; FIFOBufferArray[i].Byte3 := 0; // Allow the compiler to account for this ram FIFOBufferArray[i].Byte4 := 0; FIFOBufferArray[i].Byte5 := 0; FIFOBufferArray[i].Byte6 := 0; // Allow the compiler to account for this ram FIFOBufferArray[i].Byte7 := 0; FIFOBufferArray[i].Byte8 := 0; FIFOBufferArray[i].Byte9 := 0; // Allow the compiler to account for this ram FIFOBufferArray[i].Byte10 := 0; FIFOBufferArray[i].Byte11 := 0; FIFOBufferArray[i].Byte12 := 0; // Allow the compiler to account for this ram FIFOBufferArray[i].Byte13 := 0; FIFOBufferArray[i].Byte14 := 0; FIFOBufferArray[i].Byte15 := 0; // Allow the compiler to account for this ram end; end; procedure PIC32MX_CAN_GlobalInterrupt(Channel: Byte; Enable: Boolean); begin case Channel of 1 : begin if Enable then CAN1IE_bit := 1 else CAN1IE_bit := 0; end; 2 : begin if Enable then CAN2IE_bit := 1 else CAN2IE_bit := 0; end; end; end; // ***************************************************************************** // procedure PIC32MX_DMA_Style_Buffer // Parameters: // // Returns: None // // Description: // ***************************************************************************** procedure PIC32MX_DMA_Style_Buffer(var Buffer: TNMRAnetCanBuffer; var IsExtended: Boolean; Direction: Byte; CANPtr: ^Byte); var Temp: DWord; SID, EID: DWord; begin if Direction = CAN_DIRECTION_WRITE then begin // Direction = 0 means Parameters to Buffer (Load TX Buffer) EID := Buffer.MTI and $0003FFFF; SID := (Buffer.MTI shr 18) and $000007FF; CANPtr^ := SID and $000000FF; Inc(CANPtr); CANPtr^ := (SID shr 8) and $00000007; Inc(CANPtr); CANPtr^ := 0; Inc(CANPtr); CANPtr^ := 0; Inc(CANPtr); CANPtr^ := Buffer.PayloadCount and $0F; Inc(CANPtr); CANPtr^ := EID shl 2; Inc(CANPtr); CANPtr^ := EID shr 6; Inc(CANPtr); CANPtr^ := (EID shr 14) and $0F; CANPtr^ := CANPtr^ or $20; // Set SRR if IsExtended then CANPtr^ := CANPtr^ or $10; Inc(CANPtr); CANPtr^ := Buffer.Payload[0]; Inc(CANPtr); CANPtr^ := Buffer.Payload[1]; Inc(CANPtr); CANPtr^ := Buffer.Payload[2]; Inc(CANPtr); CANPtr^ := Buffer.Payload[3]; Inc(CANPtr); CANPtr^ := Buffer.Payload[4]; Inc(CANPtr); CANPtr^ := Buffer.Payload[5]; Inc(CANPtr); CANPtr^ := Buffer.Payload[6]; Inc(CANPtr); CANPtr^ := Buffer.Payload[7]; end else begin Temp := CANPtr^; SID := Temp; Inc(CANPtr); Temp := CANPtr^ and $07; SID := SID or (Temp shl 8); Inc(CANPtr); // CMGTS<7:0> Inc(CANPtr); // CMGTS<15:8> Inc(CANPtr); Buffer.PayloadCount := CANPtr^ and $0F; Inc(CANPtr); Temp := CANPtr^ shr 2; EID := Temp; Inc(CANPtr); Temp := CANPtr^; EID := EID or (Temp shl 6); Inc(CANPtr); Temp := CANPtr^ and $0F; EID := EID or (Temp shl 14); if CANPtr^ and $10 <> 0 then begin IsExtended := True; Buffer.MTI := EID or (SID shl 18); end else begin IsExtended := False; Buffer.MTI := EID; end; Inc(CANPtr); Buffer.Payload[0] := CANPtr^; Inc(CANPtr); Buffer.Payload[1] := CANPtr^; Inc(CANPtr); Buffer.Payload[2] := CANPtr^; Inc(CANPtr); Buffer.Payload[3] := CANPtr^; Inc(CANPtr); Buffer.Payload[4] := CANPtr^; Inc(CANPtr); Buffer.Payload[5] := CANPtr^; Inc(CANPtr); Buffer.Payload[6] := CANPtr^; Inc(CANPtr); Buffer.Payload[7] := CANPtr^; Inc(CANPtr); end end; // ***************************************************************************** // procedure PIC32MX_CAN_RequestTransmit; // // Parameters: BufferNumber: The Buffer Index that is to be used as a Transmitter (0..7) // // Result: // // Description: // ***************************************************************************** procedure PIC32MX_CAN_RequestTransmit(Channel, FIFONumber: Byte); var FIFOControlPtr: ^DWord; begin case Channel of 1 : FIFOControlPtr := @C1FIFOCON0; 2 : FIFOControlPtr := @C2FIFOCON0 else Exit; end; if FIFONumber < 32 then begin FIFOControlPtr := FIFOControlPtr + (FIFONumber * 16); // Account for REG, INV, SET, CLEAR for [CmFIFOCONn, CmFIFOINTn, CnFIFOUAm, CmFIFOCIn] FIFOControlPtr^ := FIFOControlPtr^ or $00000008; end; end; // ***************************************************************************** // procedure PIC32MX_CAN_GlobalInterruptFlag_Event; // // Parameters: DoReset: Resets the flag it true // // Result: // // Description: Checks for the Interrupt Flag associated with the // IVT_ADDR_CxINTERRUPT // ***************************************************************************** function PIC32MX_CAN_GlobalInterruptFlag(Channel: Byte; DoReset: Boolean): Boolean; begin Result := False; case Channel of 1 : begin Result := CAN1IF_bit = 1; if DoReset then CAN1IF_bit := 0; end; 2 : begin Result := CAN2IF_bit = 1; if DoReset then CAN2IF_bit := 0; end; end; end; // ***************************************************************************** // procedure PIC32MX_CAN_GlobalInterrupt_EventPriority; // // Parameters: Priority: Interrupt Priority (0..7) // // Result: // // Description: Set the Interrupt Priority associated with IVT_ADDR_CxINTERRUPT. // ***************************************************************************** procedure PIC32MX_CAN_GlobalInterrupt_EventPriority(Channel, Priority, SubPriority: Byte); begin case Channel of 1 : begin CAN1IP0_bit := Priority.0; CAN1IP1_bit := Priority.1; CAN1IP2_bit := Priority.2; CAN1IS0_bit := SubPriority.0; CAN1IS1_bit := SubPriority.1; end; 2 : begin CAN2IP0_bit := Priority.0; CAN2IP1_bit := Priority.1; CAN2IP2_bit := Priority.2; CAN2IS0_bit := SubPriority.0; CAN2IS1_bit := SubPriority.1; end; end; end; // ***************************************************************************** // function PIC32MX_CAN_InterruptCode; // // Parameters: // // Result: The Interrupt Code // // Description: When using the IVT_ADDR_CxINTERRUPT interrupt this code is a // prioritized reading of the set Flags and Enabled Bits. During the interrupt // keep reading this value to get what interrupt occured, clear that flag, do what // needs to be done, read this value again and repeat until it returns ICODE_NO_INTERRUPT // See the ICODE_XXXXX flag for return values // ***************************************************************************** function PIC32MX_CAN_InterruptCode(Channel: Byte): Byte; begin case Channel of 1 : Result := Lo( C1VEC) and $7F; 2 : Result := Lo( C2VEC) and $7F else Result := 0; end end; // ***************************************************************************** // procedure PIC32MX_CAN_AssociateFilterAndMaskAndFIFO; // // Parameters: FilterNumber: The number Filter (0..15) // MaskNumer: The number Mask to associate with the Filter (0..2) // // Result: // // Description: Filter Number = 0..15, Filter are the Bits that much match // Mask Number = 0..2, Filter are the Bits that much match // ***************************************************************************** procedure PIC32MX_CAN_AssociateFilterAndMaskAndFIFO(Channel: Byte; FilterNumber, MaskNumber: Word; FIFO: Byte); var FilterPtr: ^Byte; begin case Channel of 1 : FilterPtr := @C1FLTCON0; 2 : FilterPtr := @C2FLTCON0 else Exit; end; if (FilterNumber < 16) and (MaskNumber < 3) then begin // Get into the right 32 bit boundry including REG, INV, SET, CLEAR FilterPtr := FilterPtr + ((FilterNumber div 4) * 16); // Increase in Bytes, including REG, INV, SET, CLEAR // Get into the right 8 bit offset in the 32 bit boundry FilterPtr := FilterPtr + (FilterNumber mod 4); FilterPtr^ := FilterPtr^ and $8000; // don't disturb the enable bit FilterPtr^ := FilterPtr^ or (MaskNumber shl 5) or FIFO; end end; // ***************************************************************************** // procedure PIC32MX_CAN_EnableRXFilters; // // Parameters: FilterMask: Set bit to "1" to enable Filter (0..15) // // Result: // // Description: Bits 0..15 = Filters 0..15, Set to "1" to enable "0" to disable // ***************************************************************************** procedure PIC32MX_CAN_EnableRXFilters(Channel: Byte; FilterNumber: Byte; Enable: Boolean); var FilterPtr: ^Byte; begin case Channel of 1 : FilterPtr := @C1FLTCON0; 2 : FilterPtr := @C2FLTCON0 else Exit; end; if (FilterNumber < 16) then begin // Get into the right 32 bit boundry including REG, INV, SET, CLEAR FilterPtr := FilterPtr + ((FilterNumber div 4) * 16); // Increase in Bytes, including REG, INV, SET, CLEAR // Get into the right 8 bit offset in the 32 bit boundry FilterPtr := FilterPtr + (FilterNumber mod 4); if Enable then FilterPtr^ := FilterPtr^ or $80 else FilterPtr^ := FilterPtr^ and not $80; end end; procedure PIC32MX_CAN_SetFIFO(Channel: Byte; FIFONumber: Byte; Size: Byte; IsTransmitter: Boolean; TxPriority: Byte); var FIFOControlPtr: ^DWord; begin case Channel of 1 : FIFOControlPtr := @C1FIFOCON0; 2 : FIFOControlPtr := @C2FIFOCON0 else Exit; end; if (FIFONumber < 32) and (TxPriority < 4) then begin FIFOControlPtr := FIFOControlPtr + (FIFONumber * 16); // Account for REG, INV, SET, CLEAR for [CmFIFOCONn, CmFIFOINTn, CnFIFOUAm, CmFIFOCIn] FIFOControlPtr^ := FIFOControlPtr^ and $FFFFFFF8; FIFOControlPtr^ := FIFOControlPtr^ or TxPriority; FIFOControlPtr^ := FIFOControlPtr^ and $FFE0FFFF; FIFOControlPtr^ := FIFOControlPtr^ or (((Size-1) and $0000001F) shl 16); if IsTransmitter then FIFOControlPtr^ := FIFOControlPtr^ or $000000080 else FIFOControlPtr^ := FIFOControlPtr^ and $FFFFFF7F; end; end; procedure PIC32MX_CAN_SetFIFOBaseAddress(Channel: Byte; FIFOBufferAddress: ^DWord); var FIFOAddress: ^DWord; begin case Channel of 1 : FIFOAddress := @C1FIFOBA; 2 : FIFOAddress := @C2FIFOBA else Exit; end; FIFOAddress^ := Map_KSEG_To_Physical( FIFOBufferAddress); end; function PIC32MX_CAN_FIFO_IsTransmiter(Channel: Byte; FIFONumber: Byte): Boolean; var FIFOControlPtr: ^DWord; begin Result := False; case Channel of 1 : FIFOControlPtr := @C1FIFOCON0; 2 : FIFOControlPtr := @C2FIFOCON0 else Exit; end; if FIFONumber < 32 then begin FIFOControlPtr := FIFOControlPtr + (FIFONumber * 16); // Account for REG, INV, SET, CLEAR for [CmFIFOCONn, CmFIFOINTn, CnFIFOUAm, CmFIFOCIn] Result := FIFOControlPtr^ and $00000080 <> 0 end; end; procedure PIC32MX_CAN_Tx_Interrupt_NotFull_Enable(Channel, FIFONumber: Byte; DoEnable: Boolean); var InterruptPtr: ^DWord; begin case Channel of 1 : InterruptPtr := @C1FIFOINT0; 2 : InterruptPtr := @C2FIFOINT0 else Exit; end; if (FIFONumber < 32) then begin // Get into the right 32 bit boundry including REG, INV, SET, CLEAR InterruptPtr := InterruptPtr + (FIFONumber * 16); // Increase in Bytes, including REG, INV, SET, CLEAR if DoEnable then InterruptPtr^ := InterruptPtr^ or $04000000 else InterruptPtr^ := InterruptPtr^ and not $04000000; end end; procedure PIC32MX_CAN_Tx_Interrupt_HalfFull_Enable(Channel, FIFONumber: Byte; DoEnable: Boolean); var InterruptPtr: ^DWord; begin case Channel of 1 : InterruptPtr := @C1FIFOINT0; 2 : InterruptPtr := @C2FIFOINT0 else Exit; end; if (FIFONumber < 32) then begin // Get into the right 32 bit boundry including REG, INV, SET, CLEAR InterruptPtr := InterruptPtr + (FIFONumber * 16); // Increase in Bytes, including REG, INV, SET, CLEAR if DoEnable then InterruptPtr^ := InterruptPtr^ or $02000000 else InterruptPtr^ := InterruptPtr^ and not $02000000; end end; procedure PIC32MX_CAN_Tx_Interrupt_Empty_Enable(Channel, FIFONumber: Byte; DoEnable: Boolean); var InterruptPtr: ^DWord; begin case Channel of 1 : InterruptPtr := @C1FIFOINT0; 2 : InterruptPtr := @C2FIFOINT0 else Exit; end; if (FIFONumber < 32) then begin // Get into the right 32 bit boundry including REG, INV, SET, CLEAR InterruptPtr := InterruptPtr + (FIFONumber * 16); // Increase in Bytes, including REG, INV, SET, CLEAR if DoEnable then InterruptPtr^ := InterruptPtr^ or $01000000 else InterruptPtr^ := InterruptPtr^ and not $01000000; end end; procedure PIC32MX_CAN_Rx_Interrupt_Overflow_Enable(Channel, FIFONumber: Byte; DoEnable: Boolean); var InterruptPtr: ^DWord; begin case Channel of 1 : InterruptPtr := @C1FIFOINT0; 2 : InterruptPtr := @C2FIFOINT0 else Exit; end; if (FIFONumber < 32) then begin // Get into the right 32 bit boundry including REG, INV, SET, CLEAR InterruptPtr := InterruptPtr + (FIFONumber * 16); // Increase in Bytes, including REG, INV, SET, CLEAR if DoEnable then InterruptPtr^ := InterruptPtr^ or $00080000 else InterruptPtr^ := InterruptPtr^ and not $00080000; end; end; procedure PIC32MX_CAN_Rx_Interrupt_Full_Enable(Channel, FIFONumber: Byte; DoEnable: Boolean); var InterruptPtr: ^DWord; begin case Channel of 1 : InterruptPtr := @C1FIFOINT0; 2 : InterruptPtr := @C2FIFOINT0 else Exit; end; if (FIFONumber < 32) then begin // Get into the right 32 bit boundry including REG, INV, SET, CLEAR InterruptPtr := InterruptPtr + (FIFONumber * 16); // Increase in Bytes, including REG, INV, SET, CLEAR if DoEnable then InterruptPtr^ := InterruptPtr^ or $00040000 else InterruptPtr^ := InterruptPtr^ and not $00040000; end; end; procedure PIC32MX_CAN_Rx_Interrupt_HalfFull_Enable(Channel, FIFONumber: Byte; DoEnable: Boolean); var InterruptPtr: ^DWord; begin case Channel of 1 : InterruptPtr := @C1FIFOINT0; 2 : InterruptPtr := @C2FIFOINT0 else Exit; end; if (FIFONumber < 32) then begin // Get into the right 32 bit boundry including REG, INV, SET, CLEAR InterruptPtr := InterruptPtr + (FIFONumber * 16); // Increase in Bytes, including REG, INV, SET, CLEAR if DoEnable then InterruptPtr^ := InterruptPtr^ or $00020000 else InterruptPtr^ := InterruptPtr^ and not $00020000; end; end; procedure PIC32MX_CAN_Rx_Interrupt_NotEmpty_Enable(Channel, FIFONumber: Byte; DoEnable: Boolean); var InterruptPtr: ^DWord; begin case Channel of 1 : InterruptPtr := @C1FIFOINT0; 2 : InterruptPtr := @C2FIFOINT0 else Exit; end; if (FIFONumber < 32) then begin // Get into the right 32 bit boundry including REG, INV, SET, CLEAR InterruptPtr := InterruptPtr + (FIFONumber * 16); // Increase in Bytes, including REG, INV, SET, CLEAR if DoEnable then InterruptPtr^ := InterruptPtr^ or $00010000 else InterruptPtr^ := InterruptPtr^ and not $00010000; end; end; procedure PIC32MX_CAN_EnableInterrupts(Channel: Byte; InvalidMessage, WakeOnBus, CanBusError, SystemError, RxBufferOverflow, ModeChange, TimestampTimer, RxBuffer, TxBuffer: Boolean); var InterruptPtr: ^DWord; begin case Channel of 1 : InterruptPtr := @C1INT; 2 : InterruptPtr := @C2INT else Exit; end; if InvalidMessage then InterruptPtr^.31 := 1 else InterruptPtr^.31 := 0; if WakeOnBus then InterruptPtr^.30 := 1 else InterruptPtr^.30 := 0; if CanBusError then InterruptPtr^.29 := 1 else InterruptPtr^.29 := 0; if SystemError then InterruptPtr^.28 := 1 else InterruptPtr^.28 := 0; if RxBufferOverflow then InterruptPtr^.27 := 1 else InterruptPtr^.27 := 0; if ModeChange then InterruptPtr^.3 := 19 else InterruptPtr^.19 := 0; if TimestampTimer then InterruptPtr^.18 := 1 else InterruptPtr^.18 := 0; if RxBuffer then InterruptPtr^.17 := 1 else InterruptPtr^.17 := 0; if TxBuffer then InterruptPtr^.16 := 1 else InterruptPtr^.16 := 0; end; function PIC32MX_CAN_InterruptValidMessageFlag(Channel: Byte; DoClear: Boolean): Boolean; var InterruptPtr: ^DWord; begin Result := False; case Channel of 1 : InterruptPtr := @C1INT; 2 : InterruptPtr := @C2INT else Exit; end; Result := InterruptPtr^.15 = 1; if DoClear then InterruptPtr^.15 := 0; end; function PIC32MX_CAN_InterruptWakeOnBusFlag(Channel: Byte; DoClear: Boolean): Boolean; var InterruptPtr: ^DWord; begin Result := False; case Channel of 1 : InterruptPtr := @C1INT; 2 : InterruptPtr := @C2INT else Exit; end; Result := InterruptPtr^.14 = 1; if DoClear then InterruptPtr^.14 := 0; end; function PIC32MX_CAN_InterruptBusErrorFlag(Channel: Byte; DoClear: Boolean): Boolean; var InterruptPtr: ^DWord; begin Result := False; case Channel of 1 : InterruptPtr := @C1INT; 2 : InterruptPtr := @C2INT else Exit; end; Result := InterruptPtr^.13 = 1; if DoClear then InterruptPtr^.13 := 0; end; function PIC32MX_CAN_InterruptSystemErrorFlag(Channel: Byte; DoClear: Boolean): Boolean; var InterruptPtr, ControlPtr: ^DWord; begin Result := False; case Channel of 1 : InterruptPtr := @C1INT; 2 : InterruptPtr := @C2INT else Exit; end; Result := InterruptPtr^.12 = 1; if DoClear then begin case Channel of 1 : ControlPtr := @C1CON; 2 : ControlPtr := @C2CON else Exit; end; // The only way to reset this error is the turn the module on and off ControlPtr^.15 := 0; while ControlPtr^.11 = 1 do; // Wait till CANBUSY is 0 to ensure it was disabled ControlPtr^.15 := 1; end; end; function PIC32MX_CAN_InterruptRxBufferOverflowFlag(Channel: Byte; DoClear: Boolean): Boolean; begin Result := PIC32MX_CAN_InterruptRxOverflowFIFOAny(Channel, DoClear); end; function PIC32MX_CAN_InterruptModeChangeFlag(Channel: Byte; DoClear: Boolean): Boolean; var InterruptPtr: ^DWord; begin Result := False; case Channel of 1 : InterruptPtr := @C1INT; 2 : InterruptPtr := @C2INT else Exit; end; Result := InterruptPtr^.3 = 1; if DoClear then InterruptPtr^.3 := 0; end; function PIC32MX_CAN_InterruptTimestampTimerFlag(Channel: Byte; DoClear: Boolean): Boolean; var InterruptPtr: ^DWord; begin Result := False; case Channel of 1 : InterruptPtr := @C1INT; 2 : InterruptPtr := @C2INT else Exit; end; Result := InterruptPtr^.2 = 1; if DoClear then InterruptPtr^.2 := 0; end; function PIC32MX_CAN_InterruptRxBufferFlag(Channel: Byte; DoClear: Boolean): Boolean; var InterruptPtr: ^DWord; begin Result := False; case Channel of 1 : InterruptPtr := @C1INT; 2 : InterruptPtr := @C2INT else Exit; end; Result := InterruptPtr^.1 = 1; if DoClear then InterruptPtr^.1 := 0; end; function PIC32MX_CAN_InterruptTxBufferFlag(Channel: Byte; DoClear: Boolean): Boolean; var InterruptPtr: ^DWord; begin Result := False; case Channel of 1 : InterruptPtr := @C1INT; 2 : InterruptPtr := @C2INT else Exit; end; Result := InterruptPtr^.0 = 1; if DoClear then InterruptPtr^.0 := 0; end; function PIC32MX_CAN_Tx_Interrupt_NotFull_FlagSet(Channel, FIFONumber: Byte): Boolean; var InterruptPtr: ^DWord; begin Result := False; case Channel of 1 : InterruptPtr := @C1FIFOINT0; 2 : InterruptPtr := @C2FIFOINT0 else Exit; end; if FIFONumber < 32 then begin InterruptPtr := InterruptPtr + (FIFONumber * 16); // Account for REG, INV, SET, CLEAR for [CmFIFOCONn, CmFIFOINTn, CnFIFOUAm, CmFIFOCIn] Result := InterruptPtr^ and $00000400 <> 0 end; end; function PIC32MX_CAN_Tx_Interrupt_HalfFull_FlagSet(Channel, FIFONumber: Byte): Boolean; var InterruptPtr: ^DWord; begin Result := False; case Channel of 1 : InterruptPtr := @C1FIFOINT0; 2 : InterruptPtr := @C2FIFOINT0 else Exit; end; if FIFONumber < 32 then begin InterruptPtr := InterruptPtr + (FIFONumber * 16); // Account for REG, INV, SET, CLEAR for [CmFIFOCONn, CmFIFOINTn, CnFIFOUAm, CmFIFOCIn] Result := InterruptPtr^ and $00000200 <> 0 end end; function PIC32MX_CAN_Tx_Interrupt_Empty_FlagSet(Channel, FIFONumber: Byte): Boolean; var InterruptPtr: ^DWord; begin Result := False; case Channel of 1 : InterruptPtr := @C1FIFOINT0; 2 : InterruptPtr := @C2FIFOINT0 else Exit; end; if FIFONumber < 32 then begin InterruptPtr := InterruptPtr + (FIFONumber * 16); // Account for REG, INV, SET, CLEAR for [CmFIFOCONn, CmFIFOINTn, CnFIFOUAm, CmFIFOCIn] Result := InterruptPtr^ and $00000100 <> 0 end end; function PIC32MX_CAN_Rx_Interrupt_Overflow_FlagSet(Channel, FIFONumber: Byte): Boolean; var InterruptPtr: ^DWord; begin Result := False; case Channel of 1 : InterruptPtr := @C1FIFOINT0; 2 : InterruptPtr := @C2FIFOINT0 else Exit; end; if FIFONumber < 32 then begin InterruptPtr := InterruptPtr + (FIFONumber * 16); // Account for REG, INV, SET, CLEAR for [CmFIFOCONn, CmFIFOINTn, CnFIFOUAm, CmFIFOCIn] Result := InterruptPtr^ and $00000008 <> 0 end end; function PIC32MX_CAN_Rx_Interrupt_Full_FlagSet(Channel, FIFONumber: Byte): Boolean; var InterruptPtr: ^DWord; begin Result := False; case Channel of 1 : InterruptPtr := @C1FIFOINT0; 2 : InterruptPtr := @C2FIFOINT0 else Exit; end; if FIFONumber < 32 then begin InterruptPtr := InterruptPtr + (FIFONumber * 16); // Account for REG, INV, SET, CLEAR for [CmFIFOCONn, CmFIFOINTn, CnFIFOUAm, CmFIFOCIn] Result := InterruptPtr^ and $00000004 <> 0 end end; function PIC32MX_CAN_Rx_Interrupt_HalfFull_FlagSet(Channel, FIFONumber: Byte): Boolean; var InterruptPtr: ^DWord; begin Result := False; case Channel of 1 : InterruptPtr := @C1FIFOINT0; 2 : InterruptPtr := @C2FIFOINT0 else Exit; end; if FIFONumber < 32 then begin InterruptPtr := InterruptPtr + (FIFONumber * 16); // Account for REG, INV, SET, CLEAR for [CmFIFOCONn, CmFIFOINTn, CnFIFOUAm, CmFIFOCIn] Result := InterruptPtr^ and $00000002 <> 0 end end; function PIC32MX_CAN_Rx_Interrupt_NotEmpty_FlagSet(Channel, FIFONumber: Byte): Boolean; var InterruptPtr: ^DWord; begin Result := False; case Channel of 1 : InterruptPtr := @C1FIFOINT0; 2 : InterruptPtr := @C2FIFOINT0 else Exit; end; if FIFONumber < 32 then begin InterruptPtr := InterruptPtr + (FIFONumber * 16); // Account for REG, INV, SET, CLEAR for [CmFIFOCONn, CmFIFOINTn, CnFIFOUAm, CmFIFOCIn] Result := InterruptPtr^ and $00000001 <> 0 end end; function PIC32MX_CAN_InterruptRxOverflowFIFOAny(Channel: Byte; DoClear: Boolean): Boolean; var InterruptOverFlowPtr: ^DWord; i: Integer; begin Result := False; case Channel of 1 : InterruptOverFlowPtr := @C1RXOVF; 2 : InterruptOverFlowPtr := @C2RXOVF else Exit; end; Result := InterruptOverFlowPtr^ <> 0; if DoClear then begin case Channel of 1 : InterruptOverFlowPtr := @C1FIFOINT0; 2 : InterruptOverFlowPtr := @C2FIFOINT0 else Exit; end; for i := 0 to 31 do // Be careful this is a mass clearing of all FIFOs begin InterruptOverFlowPtr^.3 := 0; InterruptOverFlowPtr := InterruptOverFlowPtr + 16 end end; end; function PIC32MX_CAN_InterruptRxOverflowFIFO(Channel: Byte; FIFONumber: Byte; DoClear: Boolean): Boolean; var InterruptOverFlowPtr: ^DWord; begin Result := False; case Channel of 1 : InterruptOverFlowPtr := @C1FIFOINT0; 2 : InterruptOverFlowPtr := @C2FIFOINT0 else Exit; end; Result := InterruptOverFlowPtr^.3 = 1; if DoClear then InterruptOverFlowPtr^.3 := 0 end; function PIC32MX_CAN_Next_Buffer_Address(Channel: Byte; FIFONumber: Byte): PCANRawBuffer; var HeadTailPtr: ^DWord; begin Result := nil; case Channel of 1 : HeadTailPtr := @C1FIFOUA0; 2 : HeadTailPtr := @C2FIFOUA0 else Exit; end; if FIFONumber < 32 then begin HeadTailPtr := HeadTailPtr + (FIFONumber * 16); // Account for REG, INV, SET, CLEAR for [CmFIFOCONn, CmFIFOINTn, CnFIFOUAm, CmFIFOCIn] Result := HeadTailPtr^ end; end; function PIC32MX_CAN_Next_Buffer_Index(Channel: Byte; FIFONumber: Byte): Byte; var IndexPtr: ^DWord; begin Result := nil; case Channel of 1 : IndexPtr := @C1FIFOCI0; 2 : IndexPtr := @C2FIFOCI0 else Exit; end; if FIFONumber < 32 then begin IndexPtr := IndexPtr + (FIFONumber * 16); // Account for REG, INV, SET, CLEAR for [CmFIFOCONn, CmFIFOINTn, CnFIFOUAm, CmFIFOCIn] Result := Lo(IndexPtr^); end end; procedure PIC32MX_CAN_Inc_Buffer_Index(Channel: Byte; FIFONumber: Byte); var FIFOControl: ^DWord; begin case Channel of 1 : FIFOControl := @C1FIFOCON0SET; 2 : FIFOControl := @C2FIFOCON0SET // Need to use this, I think for UINC else Exit; end; if FIFONumber < 32 then begin FIFOControl := FIFOControl + (FIFONumber * 16); // Account for REG, INV, SET, CLEAR for [CmFIFOCONn, CmFIFOINTn, CnFIFOUAm, CmFIFOCIn] FIFOControl^.UINC := 1; end; end; // ***************************************************************************** // procedure PIC32MX_CAN_SetFilter; // // Parameters: FilterNumber: The Filter to set the bits of (0..15) // Filter : The Filter filter (all 27 continuous bits) // ExtendedOnly: If to only look at Extended Messages // // Result: // // Description: Filter Number = 0..15, Filter are the Bits that much match // (as defined by the mask associated with this filter) // ***************************************************************************** procedure PIC32MX_CAN_SetFilter(Channel: Byte; FilterNumber: Byte; Filter: DWord; ExtendedOnly: Boolean); var FilterPtr: ^DWord; begin case Channel of 1 : FilterPtr := @C1RXF0; 2 : FilterPtr := @C2RXF0 else Exit; end; if FilterNumber < 16 then begin FilterPtr := FilterPtr + (FilterNumber * 4); // Account for REG, INV, SET, CLEAR FilterPtr^ := Filter shr 11; FilterPtr^ := FilterPtr^ or ((LoWord(Filter) and $07FF) shl 21); FilterPtr^ := FilterPtr^ and $FFE3FFFF; if ExtendedOnly then FilterPtr^ := FilterPtr^ or $00080000; // Match only Extended end; end; // ***************************************************************************** // procedure PIC32MX_CAN_SetMask; // // Parameters: MaskNumber : The Mask to set the bits of (0..15) // Mask : The Mask filter (all 27 continuous bits) // ExtendedOnly: If to only look at Extended Messages // // Result: // // Description: Mask Number = 0..2, Filter are the Bits that much match // ***************************************************************************** procedure PIC32MX_CAN_SetMask(Channel: Byte; MaskNumber: Byte; Mask: DWord; ExtendedOnly: Boolean); var MaskPtr: ^DWord; begin case Channel of 1 : MaskPtr := @C1RXM0; 2 : MaskPtr := @C2RXM0 else Exit; end; if MaskNumber < 3 then begin MaskPtr := MaskPtr + (MaskNumber * 4); // Account for REG, INV, SET, CLEAR MaskPtr^ := Mask shr 11; MaskPtr^ := MaskPtr^ or ((LoWord(Mask) and $07FF) shl 21); MaskPtr^ := MaskPtr^ and $FFE3FFFF; if ExtendedOnly then MaskPtr^ := MaskPtr^ or $00080000; // Match only Extended end; end; // ***************************************************************************** // procedure PIC32MX_CAN_SetBaud; // // Parameters: SWJ : See Data Sheet // BRP : See Data Sheet // SEG2PH: See Data Sheet // SEG1PH: See Data Sheet // PRSEG : See Data Sheet // Sample3Times: Set module to sample signal 3 time for a majority vote // // Result: // // Description: // ***************************************************************************** procedure PIC32MX_CAN_SetBaud(Channel: Byte; SJW, BRP, SEG2PH, SEG1PH, PRSEG: DWord; Sample3Times: Boolean); var Config: ^DWord; begin case Channel of 1 : Config := @C1CFG; 2 : Config := @C2CFG else Exit; end; if BRP = 0 then BRP := 1; if SJW = 0 then SJW := 1; if SEG1PH = 0 then SEG1PH := 1; if SEG2PH = 0 then SEG2PH := 1; if PRSEG = 0 then PRSEG := 1; Config^ := BRP-1; Config^ := Config^ or ((SJW-1) shl 6); Config^ := Config^ or ((PRSEG-1) shl 8); Config^ := Config^ or ((SEG1PH-1) shl 11); if Sample3Times then Config^ := Config^ or $00004000; // Sample 3 times Config^ := Config^ or ((SEG2PH-1) shl 16); Config^ := Config^ or $00008000; // Programmable SEG2PH case Channel of 1 : Config := @C1CON; 2 : Config := @C2CON else Exit; end; Config^ := $00000000; end; procedure PIC32MX_CAN_Enable(Channel: Byte; Enable: Boolean); begin case Channel of 1 : begin if Enable then ON__C1CON_bit := 1 else ON__C1CON_bit := 0 end; 2 : begin if Enable then ON__C2CON_bit := 1 else ON__C2CON_bit := 0 end; end; end; // ***************************************************************************** // procedure PIC32MX_CAN_EnterConfigMode; // // Parameters: // // Result: // // Description: Places the ECAN module in Configuration Mode and waits for // it to enter the mode // ***************************************************************************** procedure PIC32MX_CAN_EnterConfigMode(Channel: Byte); var Control: ^DWord; begin case Channel of 1 : Control := @C1CON; 2 : Control := @C2CON else Exit; end; Control^ := (Control^ and $F8FFFFFF) or $04000000; // Set REQOP to Config (100) while (Control^ and $00E00000) <> $00800000 do; // Poll OPMODE until it equals (100) end; // ***************************************************************************** // procedure PIC32MX_CAN_EnterNormalMode; // // Parameters: // // Result: // // Description: Places the ECAN module in Normal Mode and waits for // it to enter the mode // ***************************************************************************** procedure PIC32MX_CAN_EnterNormalMode(Channel: Byte); var Control: ^DWord; begin case Channel of 1 : Control := @C1CON; 2 : Control := @C2CON else Exit; end; Control^ := Control^ and $F8FFFFFF; // Set REQOP to Normal (000) while (Control^ and $00E00000) <> $00000000 do; // Poll OPMODE until it equals (000) end; // ***************************************************************************** // procedure PIC32MX_CAN_AbortPendingTransmissions; // // Parameters: // // Result: // // Description: Terminates all Transmissions // ***************************************************************************** procedure PIC32MX_CAN_AbortPendingTransmissions(Channel: Byte); begin case Channel of 1 : ABAT_bit := 1; 2 : ABAT_C2CON_bit := 1; end; end; end.