unit MCU_Setup_dsPIC33EP64GP502; uses NMRAnetDefinesShared, CANBuffers, dsPIC33_CAN, dsPIC33_DMA; {$I Options.inc} const CAN_SWJ = 0; // Set up for 125Khz Baud Rate with a 8Mhz Crystal CAN_BRP = 7; // Baud Rate Prescaler = 15 Quanta (125000 * 16 = 20Meg) CAN_PHASESEG_1 = 4; // 16 - (1 + 6 + 5) = 4 CAN_PHASESEG_2 = 5; // CAN_PROP_SEG = 3; // DCC_TIMER_58US = 1850; //1792; // Clock ticks every 31.25ns * 1856 = 58us interrupts DCC_TIMER_29US = 928; // Clock ticks every 31.25ns * 928 = 29us interrupts procedure MCU_Setup_Initialize; procedure MCU_Setup_Enable_OlcbBus; implementation procedure MCU_Setup_Enable_OlcbBus; begin dsPIC33_CAN_EnterConfigMode; // Place the module in Configuration Mode // Setup the CAN Baud Rate dsPIC33_CAN_SetBaud(CAN_SWJ, CAN_BRP, CAN_PHASESEG_2, CAN_PHASESEG_1, CAN_PROP_SEG, True); // Setup the Baud Rate for 125kHz with a 64Mhz Clock // Setup the CAN Receive Filters, AN1249 says this should be done in Config Mode dsPIC33_CAN_SetMask(2, $08000000, True); // Mask 2 looks only at bit 27 for the Filters dsPIC33_CAN_SetFilter(0, $00000000, True); // Look for a 0 in bit 27 (CAN Layer Messsage) dsPIC33_CAN_SetFilter(1, $08000000, True); // Look for a 1 in bit 27 (NMRABus Layer Message) dsPIC33_CAN_AssociateFilterWithMask(0, 2); // Link Filter 0 and Mask 2 which looks only at bit 27 = 0 dsPIC33_CAN_AssociateFilterWithMask(1, 2); // Link Filter 1 and Mask 2 which looks only at bit 27 = 1 dsPIC33_CAN_EnableDisableRXFilters($0003); // Enable Filters 0 and 1 dsPIC33_CAN_RegisterBufferWithFilter(0, CAN_RX_0_BUFFER); // Filter 0 to be sent to Buffer dsPIC33_CAN_RegisterBufferWithFilter(1, CAN_RX_0_BUFFER); // Filter 1 to be sent to Buffer dsPIC33_CAN_EnterNormalMode; // Place the module in Normal Mode // Setup the CAN Transmitter dsPIC33_CAN_SetBufferAsTransmitter(CAN_TX_0_BUFFER, True); // Setup Buffer 0 as a Transmit Buffer // Set up Normal Transmit 0 DMA dsPIC33_DMA_Enable(CAN_TX_0_DMA_CHANNEL, False); dsPIC33_DMA_DataSize(CAN_TX_0_DMA_CHANNEL, DATASIZE_WORD); // DMA Data Size is a Word dsPIC33_DMA_Direction(CAN_TX_0_DMA_CHANNEL, DIRECTION_RAM_TO_PERIPHERAL); // Transmit move data from RAM to the Module dsPIC33_DMA_AddressMode(CAN_TX_0_DMA_CHANNEL, ADDRESS_MODE_PERIPHERAL_INDIRECT); // Don't use the buggy Perpherial Addressing Mode dsPIC33_DMA_OperatingMode(CAN_TX_0_DMA_CHANNEL, OPERATING_MODE_CONTINIOUS); // Continious Mode (as apposed to one shot) dsPIC33_DMA_TransferCount(CAN_TX_0_DMA_CHANNEL, 8); // 0...7 dsPIC33_DMA_ManualDMATransfer(CAN_TX_0_DMA_CHANNEL, False); // Automatic DMA Transfers dsPIC33_DMA_PeripheralAddress(CAN_TX_0_DMA_CHANNEL, Word( @C1TXD)); // Assign the DMA Channel to the Transmit Register of the CAN module dsPIC33_DMA_InterruptSelect(CAN_TX_0_DMA_CHANNEL, IRQ_ECAN1_TX_DATA_READY); // Assign the DMA Channel to the ECAN 1 TX to Trigger the Transfer dsPIC33_DMA_AddressOffsetA(CAN_TX_0_DMA_CHANNEL, Word( @TX_Main_RawBufferArray[CAN_TX_0_BUFFER])); // Enable DMA Channel dsPIC33_DMA_Enable(CAN_TX_0_DMA_CHANNEL, True); // Setup the CAN Transmitter dsPIC33_CAN_SetBufferAsTransmitter(CAN_TX_1_BUFFER, True); // Setup Buffer 0 as a Transmit Buffer // Set up Normal Transmit 1 DMA dsPIC33_DMA_Enable(CAN_TX_1_DMA_CHANNEL, False); dsPIC33_DMA_DataSize(CAN_TX_1_DMA_CHANNEL, DATASIZE_WORD); // DMA Data Size is a Word dsPIC33_DMA_Direction(CAN_TX_1_DMA_CHANNEL, DIRECTION_RAM_TO_PERIPHERAL); // Transmit move data from RAM to the Module dsPIC33_DMA_AddressMode(CAN_TX_1_DMA_CHANNEL, ADDRESS_MODE_PERIPHERAL_INDIRECT); // Don't use the buggy Perpherial Addressing Mode dsPIC33_DMA_OperatingMode(CAN_TX_1_DMA_CHANNEL, OPERATING_MODE_CONTINIOUS); // Continious Mode (as apposed to one shot) dsPIC33_DMA_TransferCount(CAN_TX_1_DMA_CHANNEL, 8); // 0...7 dsPIC33_DMA_ManualDMATransfer(CAN_TX_1_DMA_CHANNEL, False); // Automatic DMA Transfers dsPIC33_DMA_PeripheralAddress(CAN_TX_1_DMA_CHANNEL, Word( @C1TXD)); // Assign the DMA Channel to the Transmit Register of the CAN module dsPIC33_DMA_InterruptSelect(CAN_TX_1_DMA_CHANNEL, IRQ_ECAN1_TX_DATA_READY); // Assign the DMA Channel to the ECAN 1 TX to Trigger the Transfer dsPIC33_DMA_AddressOffsetA(CAN_TX_1_DMA_CHANNEL, Word( @TX_Main_RawBufferArray[CAN_TX_1_BUFFER])); // Enable DMA Channel dsPIC33_DMA_Enable(CAN_TX_1_DMA_CHANNEL, True); // Setup the CAN Receiver dsPIC33_CAN_SetBufferAsTransmitter(CAN_RX_0_BUFFER, False); // Setup Buffer 0 as a Receive Buffer // Setup the Receive DMA dsPIC33_DMA_DataSize(CAN_RX_0_DMA_CHANNEL, DATASIZE_WORD); // DMA Data Size is a Word dsPIC33_DMA_Direction(CAN_RX_0_DMA_CHANNEL, DIRECTION_PERIPHERAL_TO_RAM); // Transmit move data from the Module to RAM dsPIC33_DMA_AddressMode(CAN_RX_0_DMA_CHANNEL, ADDRESS_MODE_REG_INDIRECT_POST_INCREMENT); // Don't use the buggy Perpherial Addressing Mode dsPIC33_DMA_OperatingMode(CAN_RX_0_DMA_CHANNEL, OPERATING_MODE_CONTINIOUS); // Continious Mode (as apposed to one shot) dsPIC33_DMA_TransferCount(CAN_RX_0_DMA_CHANNEL, 8); // Transfers 8 Words (0 counts as 1) dsPIC33_DMA_ManualDMATransfer(CAN_RX_0_DMA_CHANNEL, False); // Automatic DMA Transfers dsPIC33_DMA_PeripheralAddress(CAN_RX_0_DMA_CHANNEL, Word( @C1RXD)); // Assign the DMA Channel to the Receive Register of the CAN module dsPIC33_DMA_InterruptSelect(CAN_RX_0_DMA_CHANNEL, IRQ_ECAN1_RX_DATA_READY); // Assign the DMA Channel to the ECAN 1 RX to Trigger the Transfer dsPIC33_DMA_AddressOffsetA(CAN_RX_0_DMA_CHANNEL, Word( @RX_Main_RawBufferArray[0])); // Point the Receive Buffer Offset into the CAN Layer Buffer dsPIC33_DMA_Enable(CAN_RX_0_DMA_CHANNEL, True); // Enable DMA Channel 2 dsPIC33_CAN_InterruptFlagRXBufferOverflow(True); // Clear the flag dsPIC33_CAN_InterruptFlagRXBuffer(True); // RX Interrupt Flag Reset dsPIC33_CAN_InterruptFlagTXBuffer(True); // TX Interrupt Flag Reset dsPIC33_CAN_RXBufferOverflowInterrupt(True); // If we don't enable this and an interrupt occurs then it hangs the loop because you can't clear the Rx Interrupt until this is serviced dsPIC33_CAN_TXBufferInterrupt(True); // Enable the TX Done Event Interrupt dsPIC33_CAN_RXBufferInterrupt(True); // Enable the RX Done Event Interrupt dsPIC33_CAN_GlobalInterruptCAN_EventPriority(6); // CAN Event Interrupt has a priority of 6 out of 7 dsPIC33_CAN_GlobalInterruptCAN_Event(True); // Enable the CAN Event Interrupt end; procedure MCU_Setup_Initialize; var i: Integer; WordPtr: ^Word; begin ANSELA := 0; ANSELB := 0; OSCCON := OSCCON and $F8FF; // Clear NOSC bits (set to FRC mode) OSCCON.0 := 1; // Tell it to change modes while OSCCON.0 = 1 do; // wait for it to take effect CLKDIV := CLKDIV and 0xFFE0; // PLLPRE<4:0> = 0 -> N1 = 2 8MHz / 2 = 4MHz // (must be within 0.8 MHz to 8 MHz range) PLLFBD := 30; // PLLDIV<8:0> = 30 -> M = 32 4MHz * 32 = 128MHz // (must be within 100 MHz to 200 MHz range) PLLPOST_1_bit := 0; PLLPOST_0_bit := 0; // PLLPOST<1:0> = 0 -> N2 = 2 128MHz / 2 = 64MHz OSCCON := OSCCON or $0300; // Set COSC to 011 = XT with PLL OSCCON.0 := 1; // Tell it to change modes while OSCCON.0 = 1 do; // wait for it to take effect while LOCK_bit = 0 do; Delay_ms(10); Unlock_IOLOCK; {$IFDEF UART_ENABLE} PPS_Mapping_NoLock(44, _INPUT, _U1RX); // Set RPI44 to the UART Receive PPS_Mapping_NoLock(42, _OUTPUT, _U1TX); // Set RP42 to the UART Transmit {$ENDIF} PPS_Mapping_NoLock(45, _INPUT, _C1RX); // Set RPI45 to the CAN Receive PPS_Mapping_NoLock(43, _OUTPUT, _C1TX); // Set RP43 to the CAN Transmit Lock_IOLOCK; {$IFDEF UART_ENABLE} // Initialize UART UART1_Init(230400); // Initialize UART module a Delay_ms(100); // Wait for UART module to stabilize {$ENDIF} SPI1_Init(); // Initialize SPI1 module SPIEN_bit := 0; // Disable SPI SPI1CON := SPI1CON and $FFE0; // Clear the prescaler bits SPI1CON := SPI1CON or $0003 or $0018; // Setup for 5 Mhz (with the CAN plug in boards) $10=5Mhz, $14=6.67Mhz, $18 = 10Mhz SPIEN_bit := 1; // Enable the SPI {$IFNDEF DCCTIMER_DISABLE} TCS_T1CON_bit := 0; // internal cycle clock T1IP_0_bit := 1; // Timer 1 Interrupt Priority = 7 (1 means off) T1IP_1_bit := 1; T1IP_2_bit := 1; PR1 := DCC_TIMER_58US; T1IF_bit := 0; // Clear T1IF T1IE_bit := 1; // Enable the Interrupt {$ENDIF} TCS_T2CON_bit := 0; // Disable T2IP_0_bit := 0; // Timer 2 Interrupt Priority = 2 (1 means off) T2IP_1_bit := 1; T2IP_2_bit := 0; TCKPS_0_T2CON_bit := 1; // 256 Prescaler TCKPS_1_T2CON_bit := 1; PR2 := 12500; // Clock ticks every 31.25ns * 256 * 12500 = 100ms interrupts T2IF_bit := 0; // Clear T2IF T2IE_bit := 1; // Enable the Interrupt TON_T2CON_bit := 1; // Turn on TCS_T3CON_bit := 0; // Disable T3IP_0_bit := 0; // Timer 3 Interrupt Priority = 2 (1 means off) T3IP_1_bit := 1; T3IP_2_bit := 0; TCKPS_0_T3CON_bit := 1; // 256 Prescaler TCKPS_1_T3CON_bit := 1; PR3 := 1250; // Clock ticks every 31.25ns * 256 * 1250 = 10ms interrupts T3IF_bit := 0; // Clear T3IF T3IE_bit := 1; // Enable the Interrupt // TON_T3CON_bit := 1; // Turn on TCS_T5CON_bit := 0; // Disable T5IP_0_bit := 1; // Timer 5 Interrupt Priority = 5 (1 means off) T5IP_1_bit := 0; T5IP_2_bit := 1; TCKPS_0_T5CON_bit := 1; // 256 Prescaler TCKPS_1_T5CON_bit := 1; PR5 := 625; // Clock ticks every 31.25ns * 256 * 625 = 5ms interrupts T5IF_bit := 0; // Clear T2IF T5IE_bit := 1; // Enable the Interrupt // Setup of the ADC(s) ANSA0_bit := 1; // Pin RA0 = Analog AD1CON3 := $1FFF; // SAMC = 11111 = 31 * Tad; ADCS = 11111111 (ACDS + 1) = 3 * Tcy = Tad Sample as slow as we can ASAM_bit := 1; // Automatic Sample Bit SSRCG_bit := 0; // Sample Clock Source Group Bit, something other than the PWM SSRC_0_bit := 1; // Sample Clock Source Select Bit, Internal counter ends sampling and starts conversion (auto-convert) SSRC_1_bit := 1; // SSRC_2_bit := 1; // ADDMAEN_bit := 0; // Do not use DMA, store the results in the ADCxBUF0-ADC-xBUFF registers SMPI_0_bit := 1; SMPI_1_bit := 1; SMPI_2_bit := 1; SMPI_3_bit := 1; SMPI_4_bit := 0; // Interrupt every 16 conversions AD1IP_0_bit := 1; AD1IP_1_bit := 1; AD1IP_2_bit := 0; // Interrupt Priority = 3; AD1IF_bit := 0; ADON_bit := 1; // Enable the ADC Module Delay_us(20); end; end.