/* * Copyright (c) 2015 - 2016 , Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP * All rights reserved. * * THIS SOFTWARE IS PROVIDED BY NXP "AS IS" AND ANY EXPRESSED OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL NXP OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include "S32K144.h" /* include peripheral declarations S32K144 */ /********************************************************************* * Project Related Defines *********************************************************************/ #define NIBBLENUM 6 #define TICKMULT 3 /********************************************************************* * Global Variables definition *********************************************************************/ uint8_t DataNibble[NIBBLENUM], SENT_Tx_PulseCnt = 0; const uint8_t CRC_4bit [256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 5, 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1, 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12, 9, 8, 11, 10, 13, 12, 15, 14, 1, 0, 3, 2, 5, 4, 7, 6, 4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11, 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14, 12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3, 6, 7, 4, 5, 2, 3, 0, 1, 14, 15, 12, 13, 10, 11, 8, 9, 11, 10, 9, 8, 15, 14, 13, 12, 3, 2, 1, 0, 7, 6, 5, 4, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 5, 4, 7, 6, 1, 0, 3, 2, 13, 12, 15, 14, 9, 8, 11, 10}; /********************************************************************* * Support Functions *********************************************************************/ void Enable_Interrupt(uint8_t vector_number) { S32_NVIC->ISER[(uint32_t)(vector_number) >> 5U] = (uint32_t)(1U << ((uint32_t)(vector_number) & (uint32_t)0x1FU)); } void SystemOSC_setup(void) { SCG->SOSCCSR &= ~SCG_SOSCCSR_SOSCEN_MASK; /* SOSCEN=0: System OSC is disabled */ /* If PLL is used, then oscillator needs to be in high range only, */ /* SCG_SOSCCFG[RANGE] on 3 as used in reference clock. */ SCG->SOSCCFG = SCG_SOSCCFG_RANGE(3) | /* RANGE=3: High frequency range selected for the crystal oscillator of 8 MHz to 40 MHz */ SCG_SOSCCFG_HGO_MASK | /* HGO=1: Configure crystal oscillator for high-gain operation */ SCG_SOSCCFG_EREFS_MASK; /* EREFS=1: Internal oscillator of OSC requested */ SCG->SOSCCSR = SCG_SOSCCSR_SOSCCM_MASK | /* SOSCCM=1: System OSC Clock Monitor is enabled */ SCG_SOSCCSR_SOSCEN_MASK; /* SOSCEN=1: System OSC is enabled to start oscillation. SOSCVLD will become 1 */ /* Wait for valid indication, or return */ while((SCG->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK) == 0){} } void SystemPLL_setup(void) { /* For 320MHz MHz VCO, 8MHz SOSC as source */ SCG->SPLLCSR &= ~SCG_SPLLCSR_SPLLEN_MASK; /* SPLLEN=0: System PLL is disabled */ SCG->SPLLCSR |= SCG_SPLLCSR_SPLLCM_MASK; /* SPLLCM=1: System PLL Clock Monitor is enabled */ /* PLL Reference Frequency Range should be 8MHz ~ 16MHz */ SCG->SPLLCFG = SCG_SPLLCFG_PREDIV(0) | /* PREDIV=0: Divided by 1, thus PLL Reference input is 8MHz */ SCG_SPLLCFG_MULT(0x18); /* VCO_CLK should be 180MHz ~ 320MHz */ /* MULT=0x18: Multiply Factor is 40, thus VCO_CLK = 8 * 40 = 320MHz */ /* SPLL_CLK = 320 / 2 = 160MHz */ /* Wait for SPLL output to be valid */ SCG->SPLLCSR |= SCG_SPLLCSR_SPLLEN_MASK; /* SPLLEN=1: System PLL is enabled */ while((SCG->SPLLCSR & SCG_SPLLCSR_SPLLVLD_MASK) == 0); } void SCG_clock_dividers_setup(void) { SCG->RCCR = SCG_RCCR_SCS(2) | /* SCS=2: System Clock Source is SIRC */ SCG_RCCR_DIVCORE(1) | /* DIVCORE=1: Divided by 2, thus CORE/SYS_CLK frequency is 8 / 1 = 8MHz */ SCG_RCCR_DIVBUS(1) | /* DIVBUS=1: Divided by 2, thus BUS_CLK frequency is 8 / 2 = 4MHz */ SCG_RCCR_DIVSLOW(2); /* DIVSLOW=2: Divided by 3, thus FLASH_CLK is 8 / 3 = 2.67MHz */ SCG->RCCR |= SCG_RCCR_SCS(6); /* SCS=6: System Clock Source is System PLL */ /* DIVCORE=1: Divided by 2, thus CORE/SYS_CLK frequency is 80 / 1 = 80MHz */ /* DIVBUS=1: Divided by 2, thus BUS_CLK frequency is 80 / 2 = 40MHz */ /* DIVSLOW=2: Divided by 3, thus FLASH_CLK is 80 / 3 = 26.6MHz */ } void Platform_setup(void) { /* Flush and enable I/D cache and write buffer */ LMEM->PCCCR = LMEM_PCCCR_GO_MASK | /* Initiate Cache Command */ LMEM_PCCCR_INVW1_MASK | /* Invalidate all lines in way 1 */ LMEM_PCCCR_INVW0_MASK | /* Invalidate all lines in way 0 */ // LMEM_PCCCR_ENWRBUF_MASK | LMEM_PCCCR_ENCACHE_MASK; /* Cache enabled */ } void ADC_setup(void) { /* Enable FIRCDIV2 divider for ADC ALTCLK */ /* Set ADCK (ADC clock) to half the maximum specified frequency for calibration. */ SCG->FIRCDIV &= ~SCG_FIRCDIV_FIRCDIV2_MASK; /* FIRCDIV2=0: Temporarily disabled */ SCG->FIRCDIV |= SCG_FIRCDIV_FIRCDIV2(2); /* FIRCDIV2=2: Divide by 2, thus FIRCDIV2_CLK = 48MHz / 2 = 24MHz */ PCC->PCCn[PCC_ADC0_INDEX] &= ~PCC_PCCn_CGC_MASK; /* Disable clock to change PCS */ PCC->PCCn[PCC_ADC0_INDEX] |= PCC_PCCn_PCS(3); /* PCS=3: Select FIRC */ PCC->PCCn[PCC_ADC0_INDEX] |= PCC_PCCn_CGC_MASK; /* Enable bus clock in ADC */ ADC0->CFG1 = ADC_CFG1_ADICLK(0) | /* Only ALTCLK1 is available */ ADC_CFG1_MODE(0); /* 0b00: 8-bit, 0b01: 12-bit, 0b10: 10-bit */ /* Before starting calibration, the calibration registers (CLPS, */ /* CLP3, CLP2, CLP1, CLP0, CLPX, and CLP9) must be cleared */ /* by writing 0000_0000h into each of them. */ ADC0->CLPS &= ~ADC_CLPS_CLPS_MASK; ADC0->CLP3 &= ~ADC_CLP3_CLP3_MASK; ADC0->CLP2 &= ~ADC_CLP2_CLP2_MASK; ADC0->CLP1 &= ~ADC_CLP1_CLP1_MASK; ADC0->CLP0 &= ~ADC_CLP0_CLP0_MASK; ADC0->CLPX &= ~ADC_CLPX_CLPX_MASK; ADC0->CLP9 &= ~ADC_CLP9_CLP9_MASK; /* Perform ADC Calibration */ ADC0->SC2 &= ~ADC_SC2_ADTRG_MASK; /* Conversion Trigger: 0b0= SW , 0b1 = HW */ ADC0->XOFS = 0x3F; /* Calibration algorithm needs this input to run through without error */ ADC0->SC3 = ADC_SC3_CAL_MASK | /* Begins the calibration sequence */ ADC_SC3_AVGE_MASK | /* Hardware average function enabled */ ADC_SC3_AVGS(3); /* b11: 32 samples averaged */ while( ( ADC0->SC3 & ADC_SC3_CAL_MASK )>>ADC_SC3_CAL_SHIFT==1 ) {} /* Wait until CAL flag cleared at end of calibration */ ADC0->R[0]; ADC0->SC3 = 0; /* Set ADCK (ADC clock) for application use */ SCG->FIRCDIV &= ~SCG_FIRCDIV_FIRCDIV2_MASK; /* FIRCDIV2=0: Temporarily disabled */ SCG->FIRCDIV |= SCG_FIRCDIV_FIRCDIV2(1); /* FIRCDIV2=1: Divide by 1, thus FIRCDIV2_CLK = 48MHz / 1 = 48MHz */ /* Configuration for Potentiometer Conversion */ ADC0->SC2 = 0x00; /* Software Conversion trigger, disable compare function */ } void Flexio_PWM_setup(void) { SCG->SOSCDIV |= SCG_SOSCDIV_SOSCDIV2(4); /* SOSCDIV2=4: Divided by 8, thus 8 / 8 = 1MHz */ PCC->PCCn[PCC_FLEXIO_INDEX] &= ~PCC_PCCn_CGC_MASK; /* Disable clock to change PCS */ PCC->PCCn[PCC_FLEXIO_INDEX] &= ~PCC_PCCn_PCS_MASK; /* Temporarily clear PCS */ PCC->PCCn[PCC_FLEXIO_INDEX] |= PCC_PCCn_PCS(1); /* PCS=1: Select SOSCDIV2_CLK */ PCC->PCCn[PCC_FLEXIO_INDEX] |= PCC_PCCn_CGC_MASK; /* Enable FlexIO Func Clock with SOSCDIV2_CLK */ /************ SHIFTER Data OUT CONFIGURATION *************************************/ FLEXIO->SHIFTCTL[0] = FLEXIO_SHIFTCTL_SMOD(2) | /* 2: Transmit mode. Load SHIFTBUF contents into the Shifter on expiration of the Timer */ FLEXIO_SHIFTCTL_PINPOL(0) | /* 0: Pin is active high */ FLEXIO_SHIFTCTL_PINSEL(0) | /* 1: Select the FXIO_D0 pin */ FLEXIO_SHIFTCTL_PINCFG(0) | /* 0: Shifter pin output disabled */ FLEXIO_SHIFTCTL_TIMPOL(1) | /* 1: Shift on negedge of Shift clock */ FLEXIO_SHIFTCTL_TIMSEL(0); /* 0: Select Timer 0 */ FLEXIO->SHIFTCFG[0] = FLEXIO_SHIFTCFG_SSTART(0) | /* 0: Start bit disabled for transmitter/receiver/match store, transmitter loads data on enable */ FLEXIO_SHIFTCFG_SSTOP(0) | /* 0: Stop bit disabled for transmitter/receiver/match store */ FLEXIO_SHIFTCFG_INSRC(0); /* 0: Pin */ /************* TIMER BitCLK OUT CONFIGURATION *********************************/ /* The Timer Configuration Register (TIMCFGn) should be configured before setting the Timer Mode (TIMOD).*/ FLEXIO->TIMCFG[0] = FLEXIO_TIMCFG_TSTART(0) | /* 0: Start bit disabled */ FLEXIO_TIMCFG_TSTOP(0) | /* 0: Stop bit disabled */ FLEXIO_TIMCFG_TIMENA(2) | /* 2: Timer enabled on Trigger high */ FLEXIO_TIMCFG_TIMDIS(0) | /* 0: Timer never disabled */ FLEXIO_TIMCFG_TIMRST(0) | /* 0: Timer never reset */ FLEXIO_TIMCFG_TIMDEC(0) | /* 0: Decrement counter on FlexIO clock, Shift clock equals Timer output */ FLEXIO_TIMCFG_TIMOUT(2); /* 2: Timer output is logic one when enabled and on timer reset */ FLEXIO->TIMCTL[0] = FLEXIO_TIMCTL_TIMOD(2) | /* 2: Dual 8-bit counters PWM mode */ FLEXIO_TIMCTL_PINPOL(0) | /* 0: Pin is active high */ FLEXIO_TIMCTL_PINSEL(1) | /* 1: Select the FXIO_D1 pin */ FLEXIO_TIMCTL_PINCFG(3) | /* 3: Timer pin output */ FLEXIO_TIMCTL_TRGSRC(1) | /* 1: Internal trigger selected */ FLEXIO_TIMCTL_TRGPOL(1) | /* 1: Trigger active low */ FLEXIO_TIMCTL_TRGSEL(1); /* 1: 4*N+1 - Shifter N(0) status flag */ /* Timer Compare*/ /* The lower 8-bits configure the high period of the output to (CMP[7:0] + 1) */ /* The upper 8-bits configure the low period of the output to (CMP[15:8] + 1) */ /* 1 tick = 4 timer-counts */ FLEXIO->TIMCMP[0] = 0x0FCF; /* Calibration Pulse (low: 4 tick, high 52 tick) by default */ FLEXIO->TIMIEN |= FLEXIO_TIMIEN_TEIE(1); /* Timer Status Flag interrupt is enabled */ FLEXIO->CTRL |= FLEXIO_CTRL_FLEXEN_MASK; /* Enable FlexIO */ FLEXIO->SHIFTBUF[0] = 0; /* Generate trigger for TIMER[0] to start PWM output */ /* Pin Configuration for PTD1 */ PCC->PCCn[PCC_PORTD_INDEX] |= PCC_PCCn_CGC_MASK; /* CGC=1: Clock enabled for PORTD */ PORTD->PCR[1] &= ~PORT_PCR_MUX_MASK; /* Set MUX=0 temporarily */ PORTD->PCR[1] |= PORT_PCR_MUX(6); /* MUX=4: Select FXIO_D1 on PTD1 */ } void FLEXIO_IRQHandler(void) { uint8_t ADCResult, loopcnt; static uint8_t crc; uint16_t TIMCMPval; if( FLEXIO->TIMSTAT & FLEXIO_TIMSTAT_TSF_MASK ) { FLEXIO->TIMSTAT |= FLEXIO_TIMSTAT_TSF(0x1); /* Write 1 to clear TSF flag */ switch( SENT_Tx_PulseCnt ) { case 0: /* Calibration Pulse - Always 56 tick */ TIMCMPval = ( ( ( 4 * TICKMULT ) - 1 )<<8 ) | ( ( 52 * TICKMULT ) - 1 ); /* Always 4 tick for low, 52 tick for high */ FLEXIO->TIMCMP[0] = TIMCMPval; SENT_Tx_PulseCnt++; break; case 1: /* Status Nibble - Always 0 */ TIMCMPval = ( ( ( 4 * TICKMULT ) - 1 )<<8 ) | ( ( 8 * TICKMULT ) - 1 ); /* Always 4 tick for low, 8 tick for high */ FLEXIO->TIMCMP[0] = TIMCMPval; SENT_Tx_PulseCnt++; break; case 2: /* Data 0 Nibble - current potentiometer position */ case 3: /* Data 1 Nibble - current potentiometer position */ case 4: /* Data 2 Nibble - current potentiometer position */ case 5: /* Data 3 Nibble - current potentiometer position */ case 6: /* Data 4 Nibble - current potentiometer position */ case 7: /* Data 5 Nibble - current potentiometer position */ ADC0->SC1[0] = ADC_SC1_ADCH(12); /* Initiate Conversion: AD12 (ADC0_SE12) @PTC14 */ while( !(ADC0->SC1[0] & ADC_SC1_COCO_MASK) ); /* Wait conversion to complete */ ADCResult = ( uint8_t)ADC0->R[0]; /* Read adc value */ DataNibble[SENT_Tx_PulseCnt-2] = ADCResult>>4; TIMCMPval = ( ( ( 4 * TICKMULT ) - 1 )<<8 ) | ( ( ( DataNibble[SENT_Tx_PulseCnt-2] + 8 ) * TICKMULT ) - 1 ); /* Always 4 tick for low */ FLEXIO->TIMCMP[0] = TIMCMPval; if( SENT_Tx_PulseCnt < (NIBBLENUM + 1) ) { SENT_Tx_PulseCnt++; } else { SENT_Tx_PulseCnt = 8; /* End of Data Nibble */ } break; case 8: /* CRC Nibble */ crc = 5; /* SEED_4BIT */ for(loopcnt=0; loopcntTIMCMP[0] = TIMCMPval; SENT_Tx_PulseCnt = 0; break; } } } void main(void) { SystemOSC_setup(); SystemPLL_setup(); SCG_clock_dividers_setup(); Platform_setup(); ADC_setup(); Enable_Interrupt(FLEXIO_IRQn); Flexio_PWM_setup(); while(1); }