마지막 프로젝트로 7segment를 이용한 간단한 전자시계를 만들었다.

사용된 기능은 GPIO, Timer interrupt, Switch interrupt, ADC 기능이다.

 

NXP S32K144 PinMap

 

7segment schematic

 

 

먼저 7segment 핀 이용을 위한 정의이다.

#define DIG1 1
#define DIG2 2
#define DIG3 6
#define DIG4 8

#define SEG1 14
#define SEG2 4
#define SEG3 13
#define SEG4 3
#define SEG5 5
#define SEG6 11
#define SEG7 10
#define SEG8 7 //dot

#define DOT 17

#define PTC12 12
#define PTC13 13
#define PTD15 15
#define PTD16 16
#define PTD0 0

volatile int timer = 0;
volatile int setmode = 0;
int digpin[4] = {DIG1,DIG2,DIG3,DIG4};
int segpin[8] = {SEG1,SEG2,SEG3,SEG4,SEG5,SEG6,SEG7,SEG8};

 

 

가장 기본적인 port초기화에 대한 내용이다.

사용하고자 하는 pin들을 모두 GPIO설정 해주었다.

void PORT_init(void){

   PCC -> PCCn[PCC_PORTC_INDEX] = PCC_PCCn_CGC_MASK;
   PORTC ->PCR[12] = PORT_PCR_MUX(1);
   PTC ->PDDR &= ~(1<<PTC12);
   PORTC->PCR[12] |= (9<<16);

   PCC->PCCn[PCC_PORTD_INDEX] |=PCC_PCCn_CGC_MASK;

	for(int i=0;i<4;i++){
			PORTD->PCR[digpin[i]] &= ~PORT_PCR_MUX_MASK;
			PORTD->PCR[digpin[i]]|= PORT_PCR_MUX(1);
			PTD->PDDR |= 1<<digpin[i];
		}

	for(int i=0;i<8;i++){
			PORTD->PCR[segpin[i]] &= ~PORT_PCR_MUX_MASK;
			PORTD->PCR[segpin[i]]|= PORT_PCR_MUX(1);
			PTD->PDDR |= 1<<segpin[i];
		}

		PORTD->PCR[17] &= ~PORT_PCR_MUX_MASK;
		PORTD->PCR[17]|= PORT_PCR_MUX(1);
		PTD->PDDR |= 1<<DOT;

		PORTD->PCR[0] &= ~PORT_PCR_MUX_MASK;
		PORTD->PCR[0] |= PORT_PCR_MUX(1);
		PTD->PDDR |= 1<<PTD0; /////Blue
}

 

 

setTime 함수는 앞으로 타이머 인터럽트가 들어올때마다 계속해서 호출될것이다.

7segment의 원리상 4개의 digit을 가지고있고, 이를 모두 동시에 켤순는 없다.

자리수마다 한개씩 매우 빠르게 번갈아 숫자를 갱신하는 원리이므로, setTime은 그때마다 호출되게된다.

void setTime(int dig_num, int n){
	for(int i=0;i<8;i++){
		PTD->PSOR |= 1<<segpin[i]; //pin clear
	}

	PTD-> PSOR |= 1<<digpin[dig_num];

	switch(n){
	case 0:
		PTD->PCOR |= 1<<SEG1;
		PTD->PCOR |= 1<<SEG2;
		PTD->PCOR |= 1<<SEG3;
		PTD->PCOR |= 1<<SEG4;
		PTD->PCOR |= 1<<SEG5;
		PTD->PCOR |= 1<<SEG6;
		break;
	case 1:
		PTD->PCOR |= 1<<SEG2;
		PTD->PCOR |= 1<<SEG3;
		break;
	case 2:
		PTD->PCOR |= 1<<SEG1;
		PTD->PCOR |= 1<<SEG2;
		PTD->PCOR |= 1<<SEG4;
		PTD->PCOR |= 1<<SEG5;
		PTD->PCOR |= 1<<SEG7;
		break;
	case 3:
		PTD->PCOR |= 1<<SEG1;
		PTD->PCOR |= 1<<SEG2;
		PTD->PCOR |= 1<<SEG3;
		PTD->PCOR |= 1<<SEG4;
		PTD->PCOR |= 1<<SEG7;
		break;
	case 4:
		PTD->PCOR |= 1<<SEG2;
		PTD->PCOR |= 1<<SEG3;
		PTD->PCOR |= 1<<SEG6;
		PTD->PCOR |= 1<<SEG7;
		break;
	case 5:
		PTD->PCOR |= 1<<SEG1;
		PTD->PCOR |= 1<<SEG3;
		PTD->PCOR |= 1<<SEG4;
		PTD->PCOR |= 1<<SEG6;
		PTD->PCOR |= 1<<SEG7;
		break;
	case 6:
		PTD->PCOR |= 1<<SEG1;
		PTD->PCOR |= 1<<SEG3;
		PTD->PCOR |= 1<<SEG4;
		PTD->PCOR |= 1<<SEG5;
		PTD->PCOR |= 1<<SEG6;
		PTD->PCOR |= 1<<SEG7;
		break;
	case 7:
		PTD->PCOR |= 1<<SEG1;
		PTD->PCOR |= 1<<SEG2;
		PTD->PCOR |= 1<<SEG3;
		PTD->PCOR |= 1<<SEG6;
		break;
	case 8:
		PTD->PCOR |= 1<<SEG1;
		PTD->PCOR |= 1<<SEG2;
		PTD->PCOR |= 1<<SEG3;
		PTD->PCOR |= 1<<SEG4;
		PTD->PCOR |= 1<<SEG5;
		PTD->PCOR |= 1<<SEG6;
		PTD->PCOR |= 1<<SEG7;
		break;
	case 9:
		PTD->PCOR |= 1<<SEG1;
		PTD->PCOR |= 1<<SEG2;
		PTD->PCOR |= 1<<SEG3;
		PTD->PCOR |= 1<<SEG4;
		PTD->PCOR |= 1<<SEG6;
		PTD->PCOR |= 1<<SEG7;
		break;
	}
	PTD-> PCOR |= 1<<digpin[dig_num];
}

 

 

main에서는 기본적으로 무한루프내에서 시간의 최대, 즉 24:00을 넘어가게 되면 0으로 초기화되게 된다.

초로 환산하면 86400초이다.

또한 ADC기능을 추가한부분, timer가 홀수와 짝수일때로 나누어 시계의 : 부분이 깜빡이도록 하는 부분까지 확인할 수 있다.

int main(void){
	PORT_init();
	SOSC_init_8MHz();
	SPLL_init_160MHz();
	NormalRUNmode_80MHz();
	NVIC_init_IRQs();
	ADC_init();
	LPIT0_init();
	int hour, min, sec, adc_num;
		for(int i=0;i<8;i++){
			PTD->PSOR |= 1<<segpin[i]; //pin clear
		}

		for(;;){


		convertAdcChan(12);
		if(setmode){
			while(adc_complete()==0){}
			timer = read_adc_chx()*(17.28);
		}
		if(timer == 86400)
			timer = 0;

		if(((timer >=0) && (timer <5) )|| ((timer >= 43200) && (timer < 43205)))
			PTD-> PCOR |= 1<<PTD0;
		else PTD-> PSOR |= 1<<PTD0;

		if((timer % 2) == 0)
			PTD->PCOR |= 1<<DOT;
		else PTD->PSOR |= 1<<DOT;


		hour = timer/3600;
		min = (timer%3600)/60;
		sec = ((timer%3600)%60)%60;


		setTime(0,hour/10);
		setTime(1,hour%10);
		setTime(2,min/10);
		setTime(3,min%10);
		}


}

 

 

실행 영상

 

 

 

 

 

포스팅내 모든 소스코드는 아래사이트에서 확인할 수 있습니다.

github.com/MinkiJo/NXP-S32DesignStudio-Project/tree/main

 

MinkiJo/NXP-S32DesignStudio-Project

마이크로프로세서 설계실험 NXP보드를 이용한 시계만들기입니다. Contribute to MinkiJo/NXP-S32DesignStudio-Project development by creating an account on GitHub.

github.com

 

'NXP&S32DesignStudio' 카테고리의 다른 글

PWM  (0) 2021.01.17
ADC  (0) 2021.01.17
Timer Interrupt  (0) 2021.01.17
GPIO & Switch  (0) 2021.01.17

PWM

 

 

클럭생성 및 클럭설정, 시스템이 동작하기 위한 System Clock/Bus Clock/Flash Clock을 생성하는 부분이다.

void SOSC_init_8Mhz(void){
   SCG->SOSCDIV = SCG_SOSCDIV_SOSCDIV1(1)|SCG_SOSCDIV_SOSCDIV2(1);

   SCG->SOSCCFG = SCG_SOSCCFG_RANGE(2)|SCG_SOSCCFG_EREFS_MASK;

   while(SCG->SOSCCSR & SCG_SOSCCSR_LK_MASK);
   SCG->SOSCCSR = SCG_SOSCCSR_SOSCEN_MASK;

   while(!(SCG->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK));
}

void SPLL_init_160Mhz(void){
   while(SCG->SPLLCSR & SCG_SPLLCSR_LK_MASK);
   SCG->SPLLCSR &= ~SCG_SPLLCSR_SPLLEN_MASK;

   SCG->SPLLDIV |= SCG_SPLLDIV_SPLLDIV1(2)|SCG_SPLLDIV_SPLLDIV2(3);
   SCG->SPLLCFG = SCG_SPLLCFG_MULT(24);

   while(SCG->SPLLCSR & SCG_SPLLCSR_LK_MASK);
   SCG->SPLLCSR |= SCG_SPLLCSR_SPLLEN_MASK;

   while(!(SCG->SPLLCSR & SCG_SPLLCSR_SPLLVLD_MASK));
}

void NormalRUNMode_80Mhz(void){
   SCG->SIRCDIV = SCG_SIRCDIV_SIRCDIV1(1)|SCG_SIRCDIV_SIRCDIV2(1);

   SCG->RCCR = SCG_RCCR_SCS(6)
         |SCG_RCCR_DIVCORE(0b01)
         |SCG_RCCR_DIVBUS(0b01)
         |SCG_RCCR_DIVSLOW(0b10);

   while(((SCG->CSR & SCG_CSR_SCS_MASK) >> SCG_CSR_SCS_SHIFT) != 6){}
}

 

 

 

FTM의 PWM을 사용하기 위한 설정을 한다. 

void FTM0_CH1_PWM(void){
	PCC->PCCn[PCC_FTM0_INDEX] &= ~PCC_PCCn_CGC_MASK;
	PCC->PCCn[PCC_FTM0_INDEX] |= PCC_PCCn_PCS(0b010)
							| PCC_PCCn_CGC_MASK;

	FTM0->SC = FTM_SC_PWMEN1_MASK
			|FTM_SC_PS(1);

	FTM0->MOD = 16000 - 1;

	FTM0->CNTIN = FTM_CNTIN_INIT(0);

	FTM0->CONTROLS[1].CnSC |= FTM_CnSC_MSB_MASK;
	FTM0->CONTROLS[1].CnSC |= FTM_CnSC_ELSA_MASK;

	FTM0->CONTROLS[1].CnV = 2048;
	FTM0->SC |= FTM_SC_CLKS(3);
}

 

 

 

실행결과

 

'NXP&S32DesignStudio' 카테고리의 다른 글

전자시계 만들기  (0) 2021.01.17
ADC  (0) 2021.01.17
Timer Interrupt  (0) 2021.01.17
GPIO & Switch  (0) 2021.01.17

보드의 ADC기능을 확인하기위해 가변저항을 사용해 변화되는 전압값에따른 LED의 밝기 차이를 확인할 것이다.

 

 

먼저 타이머 코드에서 사용한 클럭설정과 관련된 함수들을 가져오자.

void SOSC_init_8MHz(void)
{
	SCG->SOSCDIV = SCG_SOSCDIV_SOSCDIV1(1) |
			SCG_SOSCDIV_SOSCDIV2(1);
	SCG->SOSCCFG = SCG_SOSCCFG_RANGE(2)|SCG_SOSCCFG_EREFS_MASK;

	while(SCG->SOSCCSR & SCG_SOSCCSR_LK_MASK);
	SCG->SOSCCSR = SCG_SOSCCSR_SOSCEN_MASK;




	while(!(SCG->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK));
}
void SPLL_init_160MHz(void){
	while(SCG->SPLLCSR & SCG_SPLLCSR_LK_MASK);
	SCG->SPLLCSR &= ~SCG_SPLLCSR_SPLLEN_MASK;
	SCG->SPLLDIV |= SCG_SPLLDIV_SPLLDIV1(2)|
					SCG_SPLLDIV_SPLLDIV2(3);

	SCG->SPLLCFG = SCG_SPLLCFG_MULT(24);

	while(SCG->SPLLCSR & SCG_SPLLCSR_LK_MASK);
	SCG->SPLLCSR &= ~SCG_SPLLCSR_SPLLEN_MASK;

	while(!(SCG->SPLLCSR & SCG_SPLLCSR_SPLLVLD_MASK));
}
void NormalRUNmode_80MHz(void){
	SCG->SIRCDIV = SCG_SIRCDIV_SIRCDIV1(1) | SCG_SIRCDIV_SIRCDIV2(1);


	SCG->RCCR = SCG_RCCR_SCS(6)
			|SCG_RCCR_DIVCORE(0b01)
			|SCG_RCCR_DIVBUS(0b01)
			|SCG_RCCR_DIVSLOW(0b10);

	while(((SCG->CSR & SCG_CSR_SCS_MASK)>> SCG_CSR_SCS_SHIFT) != 6) {}
}

 

 

 

포트 설정에 관한 부분에서는

ADC 출력 값에 따라 LED 색이 바뀌는 예제이므로 Blue, Red, Green LED 모두를 사용한다.

void PORT_init(void){
   PCC->PCCn[PCC_PORTD_INDEX] |= PCC_PCCn_CGC_MASK;
   PORTD->PCR[PTD0] = PORT_PCR_MUX(1);
   PORTD->PCR[PTD15] = PORT_PCR_MUX(1);
   PORTD->PCR[PTD16] = PORT_PCR_MUX(1);

   PTD->PDDR |= 1<<PTD0
            |1<<PTD15
            |1<<PTD16;
}

 

 

본 ADC구현과 관련된 함수들이다.

더보기

ADC초기설정과 관련된 순서는 다음과 같다.

 

① PCC_ADC0 레지스터를 통해 ADC의 클럭을 선택하고 Enable한다.

② SC1[0] 레지스터를 통해 모듈의 conversion과 interrupt를 Disable한다.

③ CFG1 레지스터를 통해 ADC 입력 클럭과 해상도를 설정한다.

④ CFG2 레지스터를 통해 ADC의 sample time을 설정한다.

⑤ SW Trigger이고, Compare function은 사용하지 않으므로 SC2 레지스터를 0으로 세팅한다.

⑥ Calibration을 하지 않고 One conversion 모드이므로 SC3 레지스터를 0으로 세팅한다.

void ADC_init(void){
   PCC->PCCn[PCC_ADC0_INDEX] &= ~PCC_PCCn_CGC_MASK;
   PCC->PCCn[PCC_ADC0_INDEX] |= PCC_PCCn_PCS(1);
   PCC->PCCn[PCC_ADC0_INDEX] |= PCC_PCCn_CGC_MASK;

   ADC0->SC1[0] |= ADC_SC1_ADCH_MASK;

   ADC0->CFG1 &= ~ADC_CFG1_ADIV_MASK;

   ADC0->CFG1 |= ADC_CFG1_MODE(1);

   ADC0->CFG2 = ADC_CFG2_SMPLTS(12);

   ADC0->SC2 = 0x00000000;
   ADC0->SC3 = 0x00000000;
}

void convertAdcChan(uint16_t adcChan){
   ADC0->SC1[0] &= ~ADC_SC1_ADCH_MASK;
   ADC0->SC1[0] |= ADC_SC1_ADCH(adcChan);
}

uint8_t adc_complete(void){
   return ((ADC0->SC1[0] & ADC_SC1_COCO_MASK) >>ADC_SC1_COCO_SHIFT);
}

uint32_t read_adc_chx(void){
   uint16_t adc_result = 0;
   adc_result = ADC0->R[0];

   return (uint32_t)((5000*adc_result)/0xFFF);
}

 

 

 

가변저항값에 따른 LED색의 변화확인

 

'NXP&S32DesignStudio' 카테고리의 다른 글

전자시계 만들기  (0) 2021.01.17
PWM  (0) 2021.01.17
Timer Interrupt  (0) 2021.01.17
GPIO & Switch  (0) 2021.01.17

클럭생성 및 클럭설정, 시스템이 동작하기 위한 System Clock/Bus Clock/Flash Clock을 생성하는 부분이다.

void SOSC_init_8MHz(void){
	SCG->SOSCDIV=SCG_SOSCDIV_SOSCDIV1(1)|
			SCG_SOSCDIV_SOSCDIV2(1);
	SCG->SOSCCFG = SCG_SOSCCFG_RANGE(2)|
			SCG_SOSCCFG_EREFS_MASK;

	while(SCG->SOSCCSR&SCG_SOSCCSR_LK_MASK);
	SCG->SOSCCSR=SCG_SOSCCSR_SOSCEN_MASK;

	while(!(SCG->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK));

}

void SPLL_init_160MHz(void){
	while(SCG->SPLLCSR &SCG_SPLLCSR_LK_MASK);
	SCG->SPLLCSR &= ~SCG_SPLLCSR_SPLLEN_MASK;
	SCG->SPLLDIV |= SCG_SPLLDIV_SPLLDIV1(2)|
			SCG_SPLLDIV_SPLLDIV2(3);
	SCG->SPLLCFG = SCG_SPLLCFG_MULT(24);

	while(SCG->SPLLCSR & SCG_SPLLCSR_LK_MASK);
	SCG->SPLLCSR |=SCG_SPLLCSR_SPLLEN_MASK;

	while(!(SCG->SPLLCSR &SCG_SPLLCSR_SPLLVLD_MASK));
}


void NormalRUNmode_80MHz(void){
	SCG->SIRCDIV = SCG_SIRCDIV_SIRCDIV1(1)
			| SCG_SIRCDIV_SIRCDIV2(1);

	SCG->RCCR=SCG_RCCR_SCS(6)
			|SCG_RCCR_DIVCORE(0b01)
			|SCG_RCCR_DIVBUS(0b01)
			|SCG_RCCR_DIVSLOW(0b10);

	while(((SCG->CSR & SCG_CSR_SCS_MASK) >>SCG_CSR_SCS_SHIFT) != 6){}
}

 

 

48번째 interrupt인 LPIT Channel 0 interrupt에 대한 NVIC설정을 한다.

void NVIC_init_IRQs(void){
	S32_NVIC->ICPR[1] |= 1 << (48 % 32);
	S32_NVIC->ISER[1] |= 1 << (48 % 32);
	S32_NVIC->IP[48] = 0xA;

}

 

 

LPIT Channel 0 Interrupt를 사용하기 위한 설정을 한다.

더보기

<관련 순서 참고>

① PCC_LPIT 레지스터를 통해 Source Clock을 SPLLDIV2_CLK로 설정하고, Clock enable을 한다.

② MCR 레지스터를 통해 모듈의 Clock enable을 한다.

③ MIER 레지스터를 통해 Channel 0에 대한 Interrupt를 Enable 한다.

④ 1초마다 Interrupt가 발생하도록 TVAL 레지스터를 설정한다 ( TVAL = 40000000 )

⑤ TCTRLn 레지스터를 통해 모드를 32-bit periodic counter 모드로 설정하고, LPIT를 동작시킨다 (TCTRLn 레지스터의 Reset value가 0이기 때문에 MODE/TSOT/TSOI/TROT/TRG_SRC/TRG_SEL은 따로 설정하지 않는다).

void LPIT0_init(void){
	PCC->PCCn[PCC_LPIT_INDEX] &= ~PCC_PCCn_PCS_MASK;
	PCC->PCCn[PCC_LPIT_INDEX]|=PCC_PCCn_PCS(6);
	PCC->PCCn[PCC_LPIT_INDEX] |= PCC_PCCn_CGC_MASK;

	LPIT0->MCR |= LPIT_MCR_M_CEN_MASK;

	LPIT0->MIER |=LPIT_MIER_TIE0_MASK;
	LPIT0->TMR[0].TVAL =40000000;
	LPIT0->TMR[0].TCTRL |=LPIT_TMR_TCTRL_T_EN_MASK;
}


void LPIT0_Ch0_IRQHandler(void){
	lpit0_ch0_flag_counter++;
	PTD->PTOR |=1<<0;
	LPIT0->MSR |= LPIT_MSR_TIF0_MASK;
}

 

 

 

포트 설정에관한 부분

void PORT_init(void){
	PCC->PCCn[PCC_PORTD_INDEX] |=PCC_PCCn_CGC_MASK;
	PORTD->PCR[0]&=~PORT_PCR_MUX_MASK;
	PORTD->PCR[0] |= PORT_PCR_MUX(1);
	PTD->PDDR |=1<<0;
}

 

 

 

main 함수

int main(void){
	PORT_init();
	SOSC_init_8MHz();
	SPLL_init_160MHz();
	NormalRUNmode_80MHz();
	NVIC_init_IRQs();
	LPIT0_init();
	for(;;){
		idle_counter++;
	}
}

 

 

 

 

LPIT0_init 에서 설정한대로 1초마다 한번씩 깜빡이는것을 확인할 수 있다.

'NXP&S32DesignStudio' 카테고리의 다른 글

전자시계 만들기  (0) 2021.01.17
PWM  (0) 2021.01.17
ADC  (0) 2021.01.17
GPIO & Switch  (0) 2021.01.17

헤더 선언부분에서 LED 포트로 사용할 PTD15,16,0번포트와 PTC12,13

#include "S32K144.h"
#include "device_registers.h"

#define PTD15 15
#define PTD16 16
#define PTD0 0

#define PTC12 12
#define PTC13 13

 

 

 

 

 

Switch포트의 MUX bits를 설정하여 해당 핀이 GPIO로 사용될 수 있도록 한다.

PCC-> PCCn[PCC_PORTC_INDEX] |= PCC_PCCn_CGC_MASK;

PORTC->PCR[12] &= ~PORT_PCR_MUX_MASK;
PORTC->PCR[12] |= PORT_PCR_MUX(1);
PTC->PDDR &= ~(1<<PTC12);



PORTC->PCR[13] &= ~PORT_PCR_MUX_MASK;
PORTC->PCR[13] |= PORT_PCR_MUX(1);
PTC->PDDR &= ~(1<<PTC13);

 

 

 

 

LED 포트의 MUX bits를 설정하여 해당 핀이 GPIO로 사용될 수 있도록 한다.

PCC-> PCCn[PCC_PORTD_INDEX] |= PCC_PCCn_CGC_MASK;

PORTD->PCR[0] &= ~PORT_PCR_MUX_MASK;
PORTD->PCR[0] |= PORT_PCR_MUX(1);

PTD->PDDR |= 1<<PTD0; /////Blue

PORTD->PCR[15] &= ~PORT_PCR_MUX_MASK;
PORTD->PCR[15] |= PORT_PCR_MUX(1);

PTD->PDDR |= 1<<PTD15; /////Red

PORTD->PCR[16] &= ~PORT_PCR_MUX_MASK;
PORTD->PCR[16] |= PORT_PCR_MUX(1);

PTD->PDDR |= 1<<PTD16;  /////Green

 

 

main 문에서는 해당 스위치가 입력됨에따라 다른 LED 색을 출력하도록 하였다.

for(;;){
	 if((PTC->PDIR & (1<<PTC12)) &&(PTC->PDIR & (1<<PTC13)) ){
				PTD-> PCOR |= 1<<PTD16;
	}else{
		PTD-> PSOR |= 1<<PTD16;

	}

	 if((PTC->PDIR & (1<<PTC12)) && !(PTC->PDIR & (1<<PTC13)) ){

		PTD-> PCOR |= 1<<PTD0;
	}else{
		PTD-> PSOR |= 1<<PTD0;
	}


	if(!(PTC->PDIR & (1<<PTC12)) && (PTC->PDIR & (1<<PTC13)) ){
			PTD-> PCOR |= 1<<PTD15;
		}else{
			PTD-> PSOR |= 1<<PTD15;
		}
}

 

 

 

 

 

실행화면

'NXP&S32DesignStudio' 카테고리의 다른 글

전자시계 만들기  (0) 2021.01.17
PWM  (0) 2021.01.17
ADC  (0) 2021.01.17
Timer Interrupt  (0) 2021.01.17