반응형

 

SysTick Timer

SysTick은 Coretex-M3 Core 프로세서에 장착된 24bit 타이머 이다. (2^24 = 16777216만큼 숫자를 셀 수 있다.)

주로 RTOS의 tick 발생용으로 사용되거나 범용 타이머로 사용된다.

up count, down count로 나뉘는데, 24비트 down counter이다. (숫자가 하나씩 내려가는것이다. 0이 되면 reload 동작이 발생)

 

SysTick : LOAD : timer 초기값을 지정, timeout 되면 타이머로 reload 된다.

SysTick : VAL : timer의 현재값을 표시, timer 시작할 때 LOAD값을 가져온다. 

VAL에 임의의 값을 쓰면 0으로 초기화가 된다. 

Systick : CTRL : SysRick Timer의 설정 및 제어를 담당한다. 

 

 

STM32F10x 시리즈에는 1 ~14까지의 타이머가 내장되어 있고 그룹별로 기능이 다르다. 

 

TIM6,7 : 가장 기본 타이머, DAC의 트리거용으로 사용 간으, 별도 채널 없음

TIM10,11,13,14 : 타이머 당 1개 채널 보유

TIM:2, 5 : 16bit 범용 타이머, 각 타이머 별로 4개씩의 독립적인 채널을 가진다.

16비트 프리스케일러 내장하고 있다. 다양한 인터럽트/ DMA동작 지원 

 

반응형
반응형

 

UART

Universal asynchronous receiver & transmitter. 비동기 직렬 통신을 의미한다. 

usart는 동기 직렬통신도 지원하는 것이다. uart4, uart5는 비동기 통신만 사용가능하다.

여러 에러에 대해서 인터럽트 설정, dma transfer 지원 가능하다.

 

usart1~3, uart4, uart5 이렇게 다섯가지 usart modes가 존재한다.

 

전송 비트에 따른 파형 : 8b, 9b, 7b+parity, 8b+parity 선택 가능

full duplex : rx, tx 별도로 두고 사용하는걸 의미함. 

일반적으로 데이터 프로토콜은 start bit + data + stop bit 로 구성됨. (data는 8bit일지, parity가 포함될지는 옵션에 따라 다름). 가장 포멀한건 start bit + 8bit + parity + stop bit

 

가장 큰 특징은 공유하는 clock이 없다는 것이다. 그렇기 때문에 타이밍 이슈가 존재하게 되는데, baud rate를 사용해서 서로간의 타이밍을 맞춘다. 즉 uart 통신 시 baud rate speed는 두 기기가 동일하게 설정되어야 하는 것이다. (비동기 통신이니까!)

 

반대로 동기 통신이면 공통의 clock line이 있어서 동일한 타이밍에 데이터를 주고 받아야 한다. 

비동기 통신, 특히 uart 통신은 사실 에러가 날 확률이 높다. uart string을 주고 받을 때, 종종 에러 메시지가 포함되기도 한다. (꽤 빈번하게 일어난다.)

 

 

uart 통신은 ttl이라서 원거리 통신이 어렵다. 이를 위해서 RS232 통신 방식을 많이 쓴다.

 

RS232

가장 일반적인 근거리 저속 비동기 직렬통신에 사용됨. DTE-DCE간 통신 규약이다. 터미널과 모뎀간의 통신 규약으로 사용됐다. xmodem, ymodem, zmodem 시절이다. 

 

즉, PC <-> modem 간의 통신에 사용됐던 것이고 위 처럼 9개 통신선이 사용된다. 많이 사용되는 조합은 USI를 통해서 RS232로 uart, spi, i2c 통신을 지원하는 조합이 SOC개발에서 많이 사용됨.

 

일반적으로 DTE-DTE 결선 방식으로 사용하고 있는 것이다. DTE-DCE 결선은 PC랑 MODEM이랑 연결할 때 사용하는방식이다. 

RS422

고속 원거리 방식으로 많이 사용됨. Tx, Rx가 각각 2핀씩 사용된다. 

 

RS485

위 두 방식은 1대1 통신이 기본이다. Rx, Tx 가 각각 서로의 Rx, Tx에 연결되기 때문이다. 

사실 생각해보면 하나의 Tx를 여러 Rx에 엮는건 문제가 안된다. 하지만 하나의 Rx에 여러 Tx가 물리면 문제가 된다. (쇼트나겠지...)

485는 1대N의 통신을 지원하는 방식으로 진화한 것이다. 일종의 ID를 가지게 되고 사회자 처럼 브로드캐스트를 하는 방식이라고 하는데,,,,,, 쓸일 없지 않을까 싶다. 

 

 

 

 

 

반응형
반응형

system clock 설정

CPU는 clock을 기준으로 동작하므로 반드시 Clock 인가가 필요하다. 

주파수 생성 회로는 용도, 정밀도, 주파수 범위 등에 따라서 매위 많은 회로가 있다.

CPU에서는 흔히 사용하는 주파수 발생 방법은 다음 3가지

Resonator : RLC 회로를 이용하여 만드는 저가 발전기 -> 저정밀, 저주파

X-TAL 발진기: Crystal을 이용하여 만드는 발진기 -> 고정밀,고주파 (크리스탈을 깎은건데 전류를 보내면 전류가 진동한다고 한다. 단점은 강한 충격을 가하면 쉽게 망가질 수 있다는 단점) 

Oscillator : X-TAL과 특정은 유사하나 X-TAL과 달리 부가 회로가 불필요하다. 크리스탈에 발진회로까지 넣은 것이다. 전원만 넣어주면 주파수가 생성된다.

 

X-TAL은 크리스탈 가공의 한계로 인해 원하는 주파수를 얻을 수 없다. 고주파로 갈수록 얇게 가공해야 해서 생산이 어렵다. 

일반적으로 80MHz 이상은 수율이 떨어지게 되고 가격도 비싸지게 된다. 

프로세서에 내장된 내부 PLL 회로로 주파수를 증폭시켜서 사용하고 있는 것이다. 

낮은 주파수를 이용하여 원하는 고주파를 얻기 위하여 PLL회로를 사용하는 것이다. 주파수를 원하는 높은 주파수로 합성해 낼 수 있는 장치이다. 사실 원래 PLL은 주파수의 틀어짐을 보정하여 정확한 주파수가 유지될 수 있도록 해주는 장치이다. 대게 마이크로 프로세서들은 내부 PLL을 내장하고 있다.  

 

PLL은 대신에 안정된 주파수가 출력될 때까지 시간이 필요하다. -->> LOCK Time이라 한다. 

 

즉, X-TAL -> OSC회로와 연계되서 clock이 발생하는 것이다. 이것이 PLL을 거쳐서 내가 원하는 고주파 신호로 변환 될 수 있는 것이다. 경우에 따라서 OSC를 그대로 사용해도 되고, PLL을 통해 변환된 고주파를 사용해도 되는 것이다. (ex) PLL_SHARED0)

 

clock 회로를 보면 nominal이라고 해서 최대 output으로 줄 수 있는 Clock이 정해져 있다. 이부분 주의 해야 한다. 

Clock을 사용하는 시퀀스는 HSI, HSE(X-TAL의 일종, 내부클럭인지 외부클럭인지의 차이) ON -> PLL ON -> PLL LOCK 대기 순으로 사용된다. 

최종적으로 Clock enable sfr을 확인해서 사용이 가능한지 확인하는 과정이 필요할 것이다. 

 

 

CPU의 메모리 AccessTime

 

cpu 메모리 버스의 타이밍은 cpu 클럭을 기준으로 동작한다. 

access time은 메모리 읽기 요청시간부터 실제 데이터 출력까지 긴 시간이 소요되는 데 이것을 의미한다. 일반적으로 메모리마다 시간이 다 다르다. 따라서 CPU가 제대로 메모리를 접근하려면 CPU 타이밍을 조절해야한다. 

 

메모리 속도를 맞추기 위한 Wait 신호가 있다. CPU버스는 WAIT 라는 입력신호를 두고 있고, 이 신호로 메모리 속도를 조절한다. 즉, 느린 메모리를 접속할 때는 외부의 회로가 접속하는 메모리를 인지하고 WAIT를 제어한다. 

 

일반적으로 SRAM은 빠르지만 ROM memory가 느려서 wait 신호가 발생한다고 한다. 

 

 

GPIO 입력 제어

0도 아니고 1도 아닌 애매한 상태를 3-state 상태라고 한다. 디지털은 인식하지 못한다. (0일수도 1일수도 있다.)

다른 이름으로는 하이 임피던스상태이다. 따라서 이런 상태를 만들면 프로세서가 외부 입력 상태를 정확히 판단할 수가 없게 된다. 

 

하이임피던스때문에 저항을 연결하여 안정된 레벨로 만든다.  (다이렉트로 그라운드, 3.3v를 만들면 스위치를 눌렀을 때, short가 발생하게 된다.)

pull down, up 으로 이를 해결할 수 있다. 0V을 연결했음 pull up, 3.3v를 연결했으면 풀다운 저항이 필요한 것이다. 

 

 

 

chattering

스위치는 스프링의 기계적인 동작에 의하여 접점이 붙거나 떨어진다.

이로 인해 스위치를 누르거나 뗄 때 많은 기계적 진동이 발생한다.

이런 상태가 디지털회로에 입력되면 빠르게 0,1이 변화하는 것으로 인식된다. 

 

Chattering을 제거하기 위한 H/W적인 방법: Low Pass Filter를 설치해서 고주파 진동을 제거하는 방법이 있다. 

PCB 면적 증가, 비용 증가 -> 고주파 진동만 제거가 가능하고 저주파는 불가능하다.

 

S/W적인 방법 : 비용은 절감되나 소프트웨어의 부하가 증가한다. 입력신호를 여러 번 읽어서 계속 같은 값일 때 정확한 논리 값을 판단하는 방법 사용 판정 횟수는 노이즈 환경이나 스위치 종류, 소프트웨어 특성에 따라 달라진다.

 

 

디바운스 회로 :  대표적으로 RC 필터가 있다. RC회로의 충방전 곡선을 이용한 회로로 R, C값이 클수록 제거효과는 커진다. 다만 R, C가 너무 크면 늘어지게 되기 때문에 적절한 값을 찾아야 한다. 

 

 

 

슈미트 트리거 input :  0V ~ 0.5V를 0으로 인식, 2.5V ~ 5V를 1로 인식한다. 슈미트 트리거는 L->H, H->L로 변화되는 시점을 다르게 설정한다. chattering에 덜 민감하게 값을 조정하는 것이다. 즉, 1v 이하로 확실하게 떨어지기 전까진 계속 high로 유지해주는 기법 같은 것이다. 즉, 하이 임피던스 상태를 위한 접근 방식이다. 

 

 

반응형
반응형

GPIO pin의 역할

 

프로세서 원하는 논리 레벨을 출력하거나입력 상태를 읽을 수있는 pin

Gernal Purpose Input & Output

즉, 범용적으로 입력 혹은 출력으로 사용할 수 있는 개별 핀이다. 

 

port : 다수의 개별 GPIO핀을 그룹으로 관리

제조사 스펙마다 다르겠지만 STM은 포트별로 그룹에 속한 GPIO핀의 수는 최대 16개까지 존재

프로세서에서는 한 핀, 한 핀 개별적으로 on, off제어가 가능하다. 

 

GPIO는 하나의 용도로만 절대 사용하지 않는다. (핀이 늘어나니까)

ex) SPMI, Timer, UART, GPIO 등을 다 묶어서 하나를 선택해서 사용하게 한다. Boot0와 같은 중요한 핀만 전용 핀을 할당해주고 다른 것들은 다 묶여있다. 

 

그리고 GPIO 포트에서도 모드 설정을 해야함 

입력 모드: 버퍼로 구성. 읽는 순간 외부 핀의 Low, High 상태를 알 수 있다.

출력 모드: 1bit 메모리로 구성. 한번 값을 기록하면 계속 출력 값을 유지

특수 모드: 프로세서 pin 절약을 위해 특수모듈과 공통으로 사용. (uart, timerl, spmi) 

 

 

STM32의 입출력 pin구조

input : floating, pull-up, pull-down, analog

output : open-drain, push-pull

alternate function : push-pull, open-drain

 

Push-Pull은 가장 보편적인 출력형태로 항상 0 아니면 1의 상태로 출력된다.

Open-drain : p-ch를 제거한 형태라서 Floating, 0으로 생성 

즉, push-pull은 전류가 고정인데 open-drain은 외부 저항으로 조정할 수 있다.

만약에 push-pull 방식의 여러 출력을 하나로 묶으면, 출력이 상이한 경우 쇼트가 날 것이다.

 

IAP 프로그램

IAP: in application programming, 양산되어 필드에서 사용중인 장치의 rom에 프로그램 변경

ISP: rom이나 프로세서를 보드에 탑재하여 양산후 jtag장비 등으로 writing

주로 개발중엔 ISP가 사용되나 IAP도 종종 사용된다. 

 

IAP는 두가지 기능을 가진다.

 

app실행 : 플래시 메모리에 들어있는 응용프로그램을 직접 실행

app교체: 새로운 app을 sd, lan, 시리얼 포트등으로 다운받아 flash에 writing한다. 

 

 

 

Heap 메모리 할당 문제

 

표준 함수 사용을 위해서는 꼭 heap메모리도 할당해주어야 한다. 근데 이건 컴파일러에 종속적이라서 gcc 컴파일러 문서를 확인해서 할당 방법은 알아야 한다. 

 

어셈블리에서 ZI_LIMIT을 사용할 땐, 그냥 주소 참조를 하면 되지만, c에서는 변수로 지정해준 다음에 사용해야 된다고 함. 

char * _sbrk(int inc)
{
	extern unsigned char __ZI_LIMIT__;
	static char * heap = (char *)0;

	char * prevHeap;
	char * nextHeap;

	if(heap == (char *)0) heap = (char *)HEAP_BASE;

	prevHeap = heap;
	nextHeap = (char *)((((unsigned int)heap + inc) + 0x7) & ~0x7);

	if((unsigned int)nextHeap >= HEAP_LIMIT) return (char *)0;

	heap = nextHeap;
	return prevHeap;
}
#define HEAP_BASE   (((unsigned int)&__ZI_LIMIT__ + 0x7) & ~0x7)

 

위 처럼 0x7을 해주는 이유는 0x8 단위로 힙이나 스택을 지정해주어야 해서 ~0x7 = b1000 을 비트 and 옵션으로 넣어주고 있는 것이다.

 

 

컴파일러 마다 다르겠지만,,, 아래처럼 init.s에서 word로 첫번째 위치에 배치해주는 주소를 stack으로 인식하는 모양

	.syntax unified
	.thumb

	.text

	.word	0x20005000
	.word	__start

 

 

아래 처럼 지정해주고 있다고 했을 때,,,

#define SYSCLK	8000000
#define HCLK	SYSCLK
#define PCLK2	HCLK
#define PCLK1	HCLK

#define RAM_START	0x20000000
#define RAM_END		0x20004FFF
#define HEAP_BASE	(((unsigned int)&__ZI_LIMIT__ + 0x7) & ~0x7)
#define HEAP_SIZE	(4*1024)
#define HEAP_LIMIT	(HEAP_BASE + HEAP_SIZE)
#define STACK_LIMIT	(HEAP_LIMIT + 8)
#define STACK_BASE	(RAM_END + 1)
#define STACK_SIZE	(STACK_BASE - STACK_LIMIT)

 

RUNTIME ENVIRONMENT TEST
RO_BASE => 0X08009500
RO_LIMIT => 0X08009828
RW_BASE => 0X20000000
RW_LIMIT => 0X20000580
ZI_BASE => 0X20000580
ZI_LIMIT => 0X200005C8
HEAP_BASE => 0X200005C8
HEAP_LIMIT => 0X200015C8
HEAP_SIZE => 0X00001000
STACK_LIMIT => 0X200015D0
STACK_BASE => 0X20005000
STACK_SIZE => 0X00003A30
p=0X200005D0
q=0X200005E0
[001]q=0X200005D0
[002]q=0X20000658
[003]q=0X200006E0
[004]q=0X20000768
[005]q=0X200007F0
[006]q=0X20000878
[007]q=0X20000900
[008]q=0X20000988
[009]q=0X20000A10
[010]q=0X20000A98
[011]q=0X20000B20
[012]q=0X20000BA8
[013]q=0X20000C30
[014]q=0X20000CB8
[015]q=0X20000D40
[016]q=0X20000DC8
[017]q=0X20000E50
[018]q=0X20000ED8
[019]q=0X20000F60
[020]q=00000000
Heap Over

p와q가 16byte만큼 할당되는 이유

8의 배수로 할당되어야 하기 때문인데, heap이라는 영역은 할당, 할당 해제(free)도 진행되어야 하기 떄문에 8 + 8byte = 16byte 만큼 할당 되어진다고 한다. 즉 8바이트 관리 테이블, 4바이트 메모리 공간, 4바이트 reserved 이렇게 하나씩 할당해주면서 추가가 되고 있는 것이다. 관리테이블에 대한 관리가 수월하지 않고, 메모리 누수가 발생하는 형태이다.

 

임베디드에서는 malloc, calloc 등은 위 이유처럼 메모리 누수가 많이 발생해서 사용 안하는 경우도 많다.

 

 

Volatile의 필요성

 

아래는 gpio toggling 함수이다.

void Main(void)
{
	volatile int i;
	volatile int j;
	Uart_Init(115200);
	Uart_Printf("LED Toggling Test #1\n");
	RCC_APB2ENR |= (1<<3); //b port clock on

	GPIOB_CRH = 0x66 << 0;

	for(;;j++)
	{
		GPIOB_ODR = 0x0 << 8;
		for(i=0; i<0x40000; i++);
		GPIOB_ODR = 0x3 << 8;
		for(i=0; i<0x40000; i++);
	}
}

 

 

CFLAGS          = -mcpu=cortex-m3 -c -g -O3 -Wall -mthumb -msoft-float -fno-builtin -funsigned-char

 

만약에 volatile이 아니라면,

최적화 레벨에 따라서 위 코드가 정상 동작하지 않을 수 있다. 기본적으로 컴파일러는 본인이 직접 최적화를 통해서 효율적인 바이너리를 생성한다. 

이때 volatile을 지정해주면 매번 매모리에 접근해서 그대로 동작을 수행하라고 요청하는 것이다. 

 

만약 최적화 레벨을 낮춰주고 싶으면 -O0와 같은 값으로 변경해주면 된다. 

하지만 최적화를 해주지 않으면 바이너리의 크기가 커질 수 있다. 그래서 위 처럼 필요한 경우에는 volatile 형태로 변경해주는 과정이 필요하다. 

 

 

define에 사용되는 매크로들도 volatile 붙여주는 것을 잊지말자.. 당장은 될지 몰라도 컴파일러, 상황에 따라서 비정상 동작을 야기할 수 있다. 무조건 메모리 맵 I/O는 무조건 volatile을 사용하자! 

#define RCC_APB2ENR   (*(volatile unsigned long*)0x40021018)

#define GPIOB_CRH      (*(volatile unsigned long*)0x40010C04)
#define GPIOB_ODR      (*(volatile unsigned long*)0x40010C0C)

 

 

volatile main()으로 선언하면 안되나요? 

answer : 함수앞에 volatile은 의미 없는 행동이다. 만약 함수앞에 붙이면 함수를 호출할 때, 의미한다. 함수내부에서의 최적화는 그대로 진행된다.

 

아래는 최적화 레벨에 대한 정리

최적화 옵션:
-O0: 최적화를 수행하지 않습니다. 디버깅에 유용합니다.
-O1: 기본적인 최적화를 수행합니다.
-O2: -O1보다 더 많은 최적화를 수행합니다.
-O3: 가능한 가장 높은 수준의 최적화를 수행합니다. 
-Os: 코드 크기를 최소화하는 최적화를 수행합니다.
-Og: 디버깅에 유용한 최적화를 수행합니다. 
-Ofast: 더 공격적인 최적화를 수행하며, 일부 IEEE 표준을 위반할 수 있습니다. 

 

하지만 컴파일러 마다 다를테니 꼭 공식 문서를 보고 확인해야 한다.

 

 

volatile 붙여야 할 때

1. memory mapped I/O

2. DMA에 의한 전송 (cpu 간섭없이 dma ip를 사용해서 고속 이동하는 방법인데, 말그대로 cpu는 메모리 변화를 알지 못하니까, 무조건 volatile을 지정해주어야 한다.) 

3. 인터럽트 처리 루틴 (인터럽트 처리루틴과 Main루틴의 공유 변수, 컴파일러는 인터럽트 처리함수를 CPU가 호출하는 함수 인지 알지 못함 )

4. 멀티프로세스 또는 멀티 프로세싱에 의한 메모리 공유하는 경우

 

ARM CMSIS 함수 : 제조사 무관하게 호환성을 위한 공통의 함수 제공 목적으로 만들어진 함수

core_cm3.h, core_cm3.c를 참고한다. 

 

아래 같은 함수들이 포함된다. ex) __func 형태

uint32_t __get_PSP(void) __attribute__( ( naked ) );
uint32_t __get_PSP(void)
{
  uint32_t result=0;

  __ASM volatile ("MRS %0, psp\n\t" 
                  "MOV r0, %0 \n\t"
                  "BX  lr     \n\t"  : "=r" (result) );
  return(result);
}

uint32_t __get_MSP(void) __attribute__( ( naked ) );
uint32_t __get_MSP(void)
{
  uint32_t result=0;

  __ASM volatile ("MRS %0, msp\n\t" 
                  "MOV r0, %0 \n\t"
                  "BX  lr     \n\t"  : "=r" (result) );
  return(result);
}

 

구조체 형식으로 접근 할 수 있게 구현해주었고, 이 스타일 대로 제조사에서도 본인들 함수를 같은 형태로 개발하는 추세이다.

 

typedef struct
{
  __IO uint32_t ISER[8];                      /*!< Offset: 0x000  Interrupt Set Enable Register           */
       uint32_t RESERVED0[24];                                   
  __IO uint32_t ICER[8];                      /*!< Offset: 0x080  Interrupt Clear Enable Register         */
       uint32_t RSERVED1[24];                                    
  __IO uint32_t ISPR[8];                      /*!< Offset: 0x100  Interrupt Set Pending Register          */
       uint32_t RESERVED2[24];                                   
  __IO uint32_t ICPR[8];                      /*!< Offset: 0x180  Interrupt Clear Pending Register        */
       uint32_t RESERVED3[24];                                   
  __IO uint32_t IABR[8];                      /*!< Offset: 0x200  Interrupt Active bit Register           */
       uint32_t RESERVED4[56];                                   
  __IO uint8_t  IP[240];                      /*!< Offset: 0x300  Interrupt Priority Register (8Bit wide) */
       uint32_t RESERVED5[644];                                  
  __O  uint32_t STIR;                         /*!< Offset: 0xE00  Software Trigger Interrupt Register     */
}  NVIC_Type;
#define NVIC                ((NVIC_Type *)          NVIC_BASE)        /*!< NVIC configuration struct         */

 

구조체 형태라서 가독성이 좋다는 것도 장점이 될 수 있다. 

 

 

 

비트 마스킹 

& : bit단위 and 연산. 0일 때 clear, 1일 때 유지 -> 원하는 비트를 clear할 때 사용함

| : bit단위 or 연산. 0일 때 유지, 1일 때 set -> 원하는 비트를 set할 때 사용함 

^ : bit단위 exclusive or 연산. 같을 땐 0, 다르면 1이됨 -> 원하는 비트 invert할 때 사용함

~ : 1의 보수 (전체 반전)

<<, >> : 비트 시프트 연산. >> 는 signed와 unsigned 동작이 다름. signed는 부호비트가 생기고, unsigned는 0으로 채워짐 

 

ex) i |= ((1<<0) | (1<<6) | (3<< 24)) :  기존 값 읽어서 추가로 원하는 비트 값을 더 추가해줌. 꼭 복합대입 |= 을 해줘야함. 컴파일 에러도 안남 

i &= ~((1<<0) | (1<<6) | (3<< 24)) : 반전으로 바꿔주고 and 연산 해줘야 clear 되기 때문에 이게 좀 헷갈릴 수 있다. 이렇게 사용되는 걸로 외우고 넘어가자.

 

 

 

 

반응형
반응형

 

ARM (advanced Risc Machine)

영국 Acom사가 1983년 자체 컴퓨터용 프로세서로 개발

slicon이 아닌 license사업으로 진행 (arm core 설계, IP 설계 etc.)

특징 : 고성능 간결성, 저전력 구조

전세계 non-pc 시장에서 가장 널리 사용되는 프로세서

 

CISC(Intel 진형, cpu가 커지고 전력소모가 커짐, 명령어가 많음)

vs

RISC(arm 진형, 명령어가 짧고 단순함, cpu가 작아지고 전력소모가 작아짐)

 

CISC도 많이 변화하여서 RISC처럼 명령어가 짧아지고 있는 추세이지만, 여전히 위와 같은 특징을 가진다.

 

 

Cortex-M 프로세서 

저가 마이컴 시장을 겨냥하여 출시한 마이크로 컨트롤러 제품군

Low Cost & High Performance

 

Thumb

기존에는 arm이 4byte 명령어 체계를 사용함

Thumb명령 : 2byte 명령어 체계

레지스터 16개를 전부 사용할 수 없어서 8개만 사용할 수 있다.

Thumb명령은 성능은 저하하지만 메모리를 효율적으로 사용할 수 있다는 장점이 있다.

 

SIMD

Single Instruction Multiple Data

 

아키텍처 별 프로세스는 아래 그림 참고

m core는 Thumb-2 only 

 

Cortex-M3

 

결국 M코어는 저전력에 포커싱이 맞춰진 arm core의 일종이다. M3가 일반적으로 사용되고 M4는 조금 더 성능이 좋다고 한다. M3는 Thumb-2 only, 3-stage pipeline, Optional MPU(8-region) (MMU만큼 파워풀하진 않음), 파이프라인 지원(Fetch, decode를 동시에 진행), 분기 예측 지원

Fixed Memory Map이라서 이식성이 좋아짐. 제조사에서 매번 동일한 메모리 맵이니까 쉽게 접근이 가능함. 

 

Fully Programmable in C : 100% C로 작성 가능. 스택영역은? 메모리 맨 위 4 byte에 위치를 지정해줄 수도 있다고 함.

M코어만 인터럽트의 중첩을 지원한다. 인터럽트가 발생한 곳에서 오래 머물지 말고, 빨리 탈출하라는 의미이긴 한데, 저사양이고 마이크로 컨트롤러 특성상 지원한다고 한다. (NVIC, sysTick이 이를 위한 것이다.)

최대 240개 인터럽트 지원, CMSIS도 지원(코드 호환성 증가), sleep & wake 기능 지원 

 

M4는 M3에 DSP 기능을 추가한 프로세서이다. Optional FPU 지원

TRM = 테크니컬 레퍼런스 메뉴얼임. (NVIC, FPU, MPU, systick, cache, SCB etc.)

Cortex_M3_TRM_r2p1

 

주변 장치 포함 문서를 보려면 제조사의 메뉴얼을 참조해야됨.

STM32F10x_Reference_Manual

 

NVIC :

Vectored Interrupt 지원 (1 ~ 240 intterrupt 가능, 우선순위 설정 가능)

중첩 인터럽트를 지원하기 위한 컨트롤러이다. 

콘텍스트 스위칭 시간 절감 기법들을 제공한다.

 

System Timer :os tick time. 타이머로 사용하기 위한 타이머를 내장한다.

 

MPU: 메모리 프로텍션 유닛 옵션 지원 8개의 메모리 영역을 독립적으로 관리

 

즉, Cortex-M3를 사용한 프로세서 설계를 arm에서 팔고 있는 것이다. 

 

 

반응형
반응형

 

1. BeautifulSoup

 

BeautifulSoup 라이브러리에서는 웹사이트에 데이터를 읽어와서 파싱할 수 있는 기능을 제공하고 있다.

import requests
from bs4 import BeautifulSoup

def get_fear_and_greed():
    url = "https://edition.cnn.com/markets/fear-and-greed"
    response = requests.get(url)
    soup = BeautifulSoup(response.text, 'html.parser')
    
    # HTML 구조에 맞는 특정 요소를 찾아 Fear and Greed Index 값을 추출
    index = soup.find("div", class_="fear-and-greed-index").text.strip()
    return index

if __name__ == "__main__":
    index_value = get_fear_and_greed()
    print(f"CNN Fear and Greed Index: {index_value}")

 

 

하지만 아래 코드를 수행해보면 정상적으로 데이터를 파싱하지 못하는 것 처럼 보일 것이다.

(특히 직접 원하는 영역의 div의 class이름을 검색해보면 결과가 포함이 되지 않을 것이다.)

 

2. Selenium

그 이유는 해당 값이 JavaScript로 동적으로 로딩되기 때문이다. requests와 BeautifulSoup은 HTML 소스를 바로 가져오기 때문에 JavaScript로 생성된 콘텐츠는 포함되지 않는다.

 

이 문제를 해결하려면, Selenium과 같은 브라우저 자동화 도구를 사용하여 동적으로 로딩되는 콘텐츠를 포함한 페이지를 가져올 수 있다. Selenium을 사용하면 JavaScript가 로드된 후 페이지에서 데이터를 추출할 수 있다.

 

from selenium import webdriver
from selenium.webdriver.common.by import By

url = "https://edition.cnn.com/markets/fear-and-greed"

# 브라우저를 실행합니다.
driver = webdriver.Chrome()

driver.get(url)

# 원하는 div를 찾습니다.
index_value = driver.find_element(By.CLASS_NAME, "market-fng-gauge__dial-number").text
print(f"CNN Fear and Greed Index: {index_value}")

# 브라우저 종료
driver.quit()

 

 

이때 매 실행마다 url에 해당하는 사이트가 열리고 켜지면서 실행시간이 아주 오래 걸리는 것을 확인할 수 있다.

 

3. 시간 단축

실제로 데이터를 동적로딩해야하기 때문에 이는 어쩔 수 없는 방법이다. 하지만 시간 단축을 위해서 몇가지 추가할 수 있는 옵션이 있다.

 

Seleniumheadless 모드를 사용해 브라우저 창을 열지 않고 백그라운드에서 동작하도록 할 수 있다. 이렇게 하면 화면에 표시되는 부분을 렌더링하지 않아서 속도가 빨라진다.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options

url = "https://edition.cnn.com/markets/fear-and-greed"

# Chrome 옵션 설정 (headless 모드)
chrome_options = Options()
chrome_options.add_argument("--headless")  # 화면을 표시하지 않음

# 브라우저를 headless 모드로 실행
driver = webdriver.Chrome(options=chrome_options)

driver.get(url)

# 원하는 div를 찾습니다.
index_value = driver.find_element(By.CLASS_NAME, "market-fng-gauge__dial-number").text
print(f"CNN Fear and Greed Index: {index_value}")

# 브라우저 종료
driver.quit()

 

 

4. api를 활용하자

그렇지만 실제로 동적으로 데이터를 받아와야 하는 입장이기 때문에 속도저하는 불가피하다.

이를 개선하기 위해서 다양한 api를 활용해야한다.

 

만약에 미국 주식 지수와 관련한 데이터라면 yfinance 라이브러리를 통해서 데이터를 제공받을 수 있다.

pip install yfinance

 

기본 예시 코드

import yfinance as yf

# VIX 지수 티커
vix = yf.Ticker("^VIX")

# 최근 종가 데이터 가져오기
vix_data = vix.history(period="1d")
print("VIX 지수:", vix_data["Close"].iloc[-1])

 

 

웹크롤링과 라이브러리를 함께 사용한 예시 코드

import sys
import requests
import yfinance as yf
import matplotlib.pyplot as plt
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel
from PyQt6.QtCore import Qt
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas

class DataFetcher:
    """데이터를 가져오는 클래스 (웹 크롤링 또는 API)"""

    @staticmethod
    def fetch_fear_greed_index():
        """CNN Fear & Greed Index 크롤링"""
        chrome_options = Options()
        chrome_options.add_argument("--headless")
        chrome_options.add_argument("--ignore-certificate-errors")

        driver = webdriver.Chrome(options=chrome_options)
        driver.get("https://edition.cnn.com/markets/fear-and-greed")

        index_value = driver.find_element(By.CLASS_NAME, "market-fng-gauge__dial-number").text
        driver.quit()

        return f"CNN Fear & Greed Index: {index_value}"

    @staticmethod
    def fetch_vix_data():
        """VIX 지수 데이터 가져오기 (지난 1개월)"""
        vix = yf.Ticker("^VIX")
        vix_data = vix.history(period="1mo")
        return vix_data

class MarketIndexApp(QWidget):
    """GUI를 관리하는 클래스"""

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Market Index Dashboard")
        self.resize(500, 400)

        self.layout = QVBoxLayout()
        
        self.fear_greed_label = QLabel("Loading Fear & Greed Index...", self)
        self.fear_greed_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.layout.addWidget(self.fear_greed_label)

        self.vix_label = QLabel("Loading VIX Index...", self)
        self.vix_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.layout.addWidget(self.vix_label)

        # 그래프 추가
        self.figure, self.ax = plt.subplots(figsize=(5, 3))
        self.canvas = FigureCanvas(self.figure)
        self.layout.addWidget(self.canvas)

        self.setLayout(self.layout)

        self.update_data()

    def update_data(self):
        """데이터를 가져와 UI에 표시"""
        self.fear_greed_label.setText(DataFetcher.fetch_fear_greed_index())

        vix_data = DataFetcher.fetch_vix_data()
        self.vix_label.setText(f"VIX 지수 (최신값): {vix_data['Close'].iloc[-1]:.2f}")

        # 그래프 업데이트
        self.ax.clear()
        self.ax.plot(vix_data.index, vix_data["Close"], marker='o', linestyle='-', color='b', label="VIX Close")
        self.ax.set_title("VIX Index Trend (Last 1 Month)")
        self.ax.set_xlabel("Date")
        self.ax.set_ylabel("VIX Value")
        self.ax.legend()
        self.ax.grid(True)

        self.canvas.draw()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MarketIndexApp()
    window.show()
    sys.exit(app.exec())
반응형
반응형

 

사실 chat gpt 에게 물어보면서 진행하면 더 편하지만, 작업 환경 셋팅을 위한 전반적인 그림이 필요하신 분이 있을 것 같아 글을 남깁니다. ㅎㅎ

 

 

1. python 설치 

 

직접 python 사이트에서 설치해도 되지만, 윈도우 작업 환경이시라면, MS store에서 python을 설치하는 것 만으로 

python 설치 & 환경변수 설정이 한번에 가능합니다.

 

 

여러가지 python 버전이 있는데, 그냥 아무거나 설치하셔도 됩니다.

사용하실 대부분의 기능들은 python3이상이라면 정상 동작 할 것이기 때문에...

 

 

2. VS code 설치 

 

아래 사이트에서 vsc 코드를 다운 받으시고 실행시키면 됩니다.

https://code.visualstudio.com/download

 

Download Visual Studio Code - Mac, Linux, Windows

Visual Studio Code is free and available on your favorite platform - Linux, macOS, and Windows. Download Visual Studio Code to experience a redefined code editor, optimized for building and debugging modern web and cloud applications.

code.visualstudio.com

 

 

vsc에서 python 개발을 위한 플러그인을 설치해야하는데, 아래처럼 python extensions을 설치해주시면 됩니다. 

 

 

3. 가상 환경 설정 

 

작업할 test.py 파일 하나 만드시고 terminal에 가상환경 생성을 위한 명령어를 입력

python -m venv venv  # 가상환경 생성

 

 

그리고 가상환경 활성화를 위해서 아래 명령어를 입력

source venv/bin/activate  # (Mac/Linux) 활성화
venv\Scripts\activate  # (Windows) 활성화

 

간혹 아래 처럼 문제가 발생하는 경우가 있다.

 

단순히 power shell이 관리자 권한이 아니기에 발생하는 문제이기 때문에 아래 명령어를 입력하여 관리자 권한의 terminal로 변경해주면 된다.

 

 Set-ExecutionPolicy Unrestricted -Scope Process

 

 

그러면 아래 사진 처럼 teminal command 창 옆에 (venv)이라고 가상환경이 활성화 된 것을 확인할 수 있다.

 

 

4. PyQt 및 필수 패키지 설치

 

 

pip install PyQt6 pyqt6-tools


PyQt6: PyQt 프레임워크
pyqt6-tools: Qt Designer, uic(코드 변환기) 등 포함

 

5. 코드 작성

 

아래 처럼 기본 코드를 작성

Run - start debuging을 수행하면 창 하나가 나온다.

import sys
from PyQt6.QtWidgets import QApplication, QWidget

class MyApp(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("My PyQt App")  # 창 제목 설정
        self.resize(400, 300)  # 창 크기 설정 (가로x세로)
        self.show()  # 창 표시

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MyApp()
    sys.exit(app.exec())  # 앱 실행

 

 

 

6. 사실 ui 작업이 많아지면 gt designer를 통해서 ui를 만드는게 효율적입니다.

https://jeongbang.tistory.com/3

 

VSCode 에서 PyQt5를 이용한 GUI 만들기

PyQt5를 이용해 파이썬 GUI 프로그래밍을 해보도록 하겠습니다. 파이썬 개발환경이 구성되어 있다는 가정하에 진행하도록 하겠습니다. VSCode에서 Python 개발환경 구성하기 파이썬 IDE에는 여러가지

jeongbang.tistory.com

 

반응형
반응형

 

 


노티드에서 크림 소금빵 이후 신메뉴가 뜸했는데, 마리토쪼라는 신메뉴가 등장했습니다. 

 

마리토쪼? 마리토조? 그게 뭔데...?

 

 

요새 일본에서 대유행인 빵이라고 합니다. 이탈리아의 전통 디저트로, 버터, 설탕, 계란이 많이 사용된 '브리오슈' 라는 빵에 생크림을 듬뿍발라 끼운 것이라고 합니다. 생크림에 견과류나 말린 건포도 같은 것들이 포함되기도 한다고 합니다.

 

 

 

비주얼만 봐도 존맛인데요..?

 

 

 

 

노티드 덕후로서 참지 못하고 바로 구매 완료 : )

 

노티드 인스타 피드에 나와있는 것 처럼 총 6가지 마리토쪼 메뉴가 추가됐습니다.

 

https://www.instagram.com/cafeknotted/

 

 

 

 

역대급 비주얼인데요??..

 

 

실물도 진짜 저럴까요???

저는 메론맛 마리토쪼, 귤 유자맛 마리토쪼 2개를 구입했습니다. 개당 소금빵과 동일한 5200원(24.08.11기준)

 

 

 

 

 

이 정도면 비쥬얼도 합격이네요.

안에 크림도 잔뜩 들어있습니다.

 

 

가장 중요한 맛은....

 

대존맛입니다. 기존에 노티드 크림 소금빵은 크림 도넛에서 사용하던 크림들과 동일한 크림을 사용했다면, 마리토쪼에 들어가는 크림은 맛이 전혀 다른 생크림을 사용하고 있었습니다.

 

 

유자맛 마리토쪼에는 그냥 생크림이 아니라 유자가루같은게 들어가 있어서 상큼한 맛이 났고, 멜론 마리토쪼에는 메론향이 잔뜩 나는 생크림가 멜론맛 커스터드 크림이 들어있었습니다. 

 

 

결론은 대만족!!

 

 

두 제품중에서는 저는 멜론맛 마리토쪼를 강추합니다. 깊은 멜론맛과 향이 잔뜩 느껴집니다. 

크림이 잔뜩 들어있고, 기존에 노티드 도넛과는 차별화되게 다양한 크림, 과일을 사용한다는 점이 인상적이었습니다. 

 

단점은 딱히 없지만 굳이 말하자면, 빵이 생각했던 것 보다 푹신푹신한 느낌은 아니였고, 그냥 일반적인 빵느낌이었던거 같아요.

 

제 기준 종합 평점은

 

맛 : ★ ★ ★ ★☆

비주얼 : ★ ★ ★ ★ ★  

가격 : ★ ★ ★ ★ ☆

 

꼭 한번 드셔보시길 강추드립니다.

반응형

+ Recent posts